mirror of
https://github.com/priyanshujain/sanderling.git
synced 2026-10-02 19:17:10 +00:00
fix(ioscompanion): replace field content on input so blackout-skipped erase cannot accumulate text
This commit is contained in:
1 parent
d8b6dcaf98
commit
6cc84fcafe
2 files changed
+34
-5
No files matched your search
@@ -831,7 +831,14 @@ func waitForListener(ctx context.Context, address string) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ReplacesTextOnInput reports that InputText replaces the field's content, so
|
||||||
|
// the runner skips its pre-erase. The driver clears the field inside InputText,
|
||||||
|
// which is robust even when a collapsed accessibility bridge would make the
|
||||||
|
// runner read the field length as zero and wrongly skip erasing.
|
||||||
|
func (d *Driver) ReplacesTextOnInput() bool { return true }
|
||||||
|
|
||||||
var (
|
var (
|
||||||
_ driver.DeviceDriver = (*Driver)(nil)
|
_ driver.DeviceDriver = (*Driver)(nil)
|
||||||
_ driver.ForegroundChecker = (*Driver)(nil)
|
_ driver.ForegroundChecker = (*Driver)(nil)
|
||||||
|
_ driver.TextReplacer = (*Driver)(nil)
|
||||||
)
|
)
|
||||||
@@ -103,17 +103,39 @@ func usesPasteboard(text string) bool {
|
|||||||
return len(skipped) > 0
|
return len(skipped) > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// inputText types text into the focused field. Mappable text goes through the
|
// inputText replaces the focused field's content with text. It selects any
|
||||||
// hardware keyboard in one HID stream; anything else falls back to the
|
// existing content and deletes it first, so the result is the typed text alone
|
||||||
// pasteboard. The field target is only consulted on the pasteboard path.
|
// regardless of what the field held. Replacing (rather than relying on the
|
||||||
|
// runner's pre-erase) keeps input correct even when the accessibility bridge is
|
||||||
|
// momentarily collapsed and the runner cannot read the field's length. Mappable
|
||||||
|
// text goes through the hardware keyboard in one HID stream; anything else falls
|
||||||
|
// back to the pasteboard. The field target is only consulted on the pasteboard
|
||||||
|
// path.
|
||||||
func inputText(ctx context.Context, run runner, text string, field fieldTarget) error {
|
func inputText(ctx context.Context, run runner, text string, field fieldTarget) error {
|
||||||
if !usesPasteboard(text) {
|
if !usesPasteboard(text) {
|
||||||
presses, _ := typeString(text)
|
events := append(clearFieldEvents(), keyPressEvents(typeStringPresses(text))...)
|
||||||
return run.sendHID(ctx, keyPressEvents(presses)...)
|
return run.sendHID(ctx, events...)
|
||||||
|
}
|
||||||
|
if err := run.sendHID(ctx, clearFieldEvents()...); err != nil {
|
||||||
|
return fmt.Errorf("clear field: %w", err)
|
||||||
}
|
}
|
||||||
return pasteText(ctx, run, text, field)
|
return pasteText(ctx, run, text, field)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// typeStringPresses is typeString's presses, dropping the skipped runes (the
|
||||||
|
// caller already decided this text is fully mappable).
|
||||||
|
func typeStringPresses(text string) []KeyPress {
|
||||||
|
presses, _ := typeString(text)
|
||||||
|
return presses
|
||||||
|
}
|
||||||
|
|
||||||
|
// clearFieldEvents selects the whole field (command+A) and deletes it, so a
|
||||||
|
// following type or paste lands in an empty field. On an already-empty field
|
||||||
|
// the select selects nothing and the delete is a no-op.
|
||||||
|
func clearFieldEvents() []transport.HIDEvent {
|
||||||
|
return append(selectAllChordEvents(), keyPressEvents(backspaces(1))...)
|
||||||
|
}
|
||||||
|
|
||||||
// pasteText copies the full text to the pasteboard, sends the paste chord
|
// pasteText copies the full text to the pasteboard, sends the paste chord
|
||||||
// once, and polls until the field reflects the text. The chord is re-sent ONLY
|
// once, and polls until the field reflects the text. The chord is re-sent ONLY
|
||||||
// after dismissing a permission dialog (the dialog swallowed that paste);
|
// after dismissing a permission dialog (the dialog swallowed that paste);
|
||||||
|
|||||||
Reference in new issue
Block a user