Skip to content

Type idb ui text on the simulator's hardware keyboard layout - #1002

Open
joshuayoes wants to merge 2 commits into
meta:mainfrom
joshuayoes:keyboard-layout-text-idb
Open

joshuayoes wants to merge 2 commits into
meta:mainfrom
joshuayoes:keyboard-layout-text-idb

Conversation

@joshuayoes

@joshuayoes joshuayoes commented Nov 10, 2026 •

Copy link
Copy Markdown

Motivation

idb ui text maps each character to a key position with a US table in the client and sends key presses. On a simulator whose hardware keyboard layout is not US the guest types different characters: idb ui text mobiletest@example.com arrives as ,obiletest2exq,ple:co, on French, and characters off the US keyboard fail with "No keycode found". See #666.

What changes:

  • HIDEvent gains a text event (HIDText: the text and an optional layout name). The companion turns it into key presses for the layout with Simulator.keyboard.typingEvent (added in the framework pull request this depends on).
  • The companion advertises this as CompanionInfo.hid_text (field 13).
  • Client.text(text, layout=None) sends one HIDText event to a companion that advertises it.
  • idb ui text TEXT --layout LAYOUT names a layout to type on, such as US or French. Without it the companion uses the simulator's own.
  • A character the layout has no key for, or a layout the runtime does not have, fails with INVALID_ARGUMENT before anything is typed. The message names the character's offset and the layout.

Compatibility:

  • Old client, new companion: the client still sends key presses, which the companion handles as before.
  • New client, old companion: hid_text is absent, so the client sends the same US key presses it always has. A --layout other than US is refused in the client before any event is sent.
  • --layout US sends the key presses idb ui text sent before this change, on any simulator, for every character the US table has.
  • On a simulator set to US, the default sends the same key presses as before. On any other layout the default now types the text itself, which is a change for callers who pre-mapped their text to US positions; --layout US restores the old behaviour.

Known limit: an app keeps the hardware layout it was launched with. The layout is read from the simulator's keyboard settings, so after changing the simulator's keyboards either relaunch the app or pass --layout.

The hid stream handler now resolves the first event of a stream before taking the HID lease, so reading the simulator's keyboard settings does not hold up other HID streams.

Test Plan

  • ./build.sh test CompanionTests: 225 tests pass. ./build.sh test CompanionLibTests: 163 pass. ./build.sh test FBSimulatorControlUnitTests: 513 pass. ./build.sh build all succeeds.
  • Python, as CI runs it (pip install ., then python -m pytest --pyargs idb -o python_files='*_tests.py' from outside the checkout): 411 passed, 1 skipped. Run on Python 3.14.
  • idb/grpc/tests is not part of the installed package, so CI does not collect it. Run against a copy of the installed package: 216 passed, 1 failed. The failure is repl_contract_tests, which could not load its fixture in that layout and is not touched by this change.
  • End to end: test_ui_text_types_on_the_simulators_keyboard_layout in EndToEndTests/test_accessibility.py passed on fresh iOS 27.2 and iOS 26.2 simulators (run before rebasing onto 60beb1c; the before/after below was rerun after). It sets the simulator to French, types text that AZERTY moves along with option-layer and dead-key characters, checks a refused character types nothing, and checks --layout US sends US positions. It restores the keyboard settings it changes.
  • Manual, iOS 27.2 (and the French and US cases on 26.2), typing into Safari's address bar and reading the field back:
    • French, French via hw=Automatic, German, Canadian French and Devanagari strings typed exactly, including mobiletest@example.com, €, ê, ñ, ß.
    • en_US: all 94 printable ASCII characters typed exactly; café € typed exactly.
    • French with --layout US: azerty arrives as qwerty.
    • abc日def: exit 1, Cannot type the character at offset 3 on the French hardware keyboard layout, field unchanged.
    • --layout Bogus: exit 1, The simulator's runtime has no hardware keyboard layout named "Bogus", field unchanged.
  • Before/after on a French simulator, stock idb 1.7.6 against this change, rerun on the rebased build: stock types ,obiletest2exq,ple:co, for mobiletest@example.com; this change types it exactly. Recording (stock idb first, then this change):
proof.mp4
  • Version skew: this client against a 1.7.6 companion types US key presses as before and refuses --layout French with The companion does not support typing on a keyboard layout; a 1.7.6 client against this companion behaves as before.
  • python -m CI.check_documentation_links passes.

Related PRs

Depends on #1001. Until that lands this branch carries its commit too, so only the second commit is new here. website/docs/idb/ui.mdx and commands.mdx are updated in this pull request.

🤖 Generated with Claude Code

joshuayoes and others added 2 commits November 10, 2026 08:22
…ontrol

SimulatorHIDEvent key presses are USB HID usages, which name key positions.
The helpers that turn text into key presses map characters to positions with
a US table, so on a simulator whose hardware keyboard layout is not US the
guest types different characters: "azerty" arrives as "qwerty" on French.

Add framework support for typing text on a given layout:

- SimulatorHIDEvent.text(_:layout:table:) builds the key presses for a
  string from a layout table, resolving every character before any event is
  built.
- SimulatorUSKeyboardLayoutTable is the US table that was private to the
  REPL's command dispatcher.
- SimulatorUCHRKeyboardLayoutTable reads every other layout from the
  runtime's USBKeyboardLayouts.bundle and confirms the planned key presses
  with UCKeyTranslate.
- Simulator.keyboard.typingEvent(for:layout:) types on a named layout, or on
  the one the simulator's keyboard settings give a newly launched app.

The REPL's text command now goes through this.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
`idb ui text` maps each character to a key position with a US table in the
client, so a simulator whose hardware keyboard layout is not US types
different characters: "mobiletest@example.com" arrives as
",obiletest2exq,ple:co," on French.

HIDEvent gains a text event carrying the text and an optional layout name.
The companion turns it into key presses for the simulator's layout and
advertises support as CompanionInfo.hid_text. The client sends it to
companions that advertise it and falls back to US key presses otherwise.
`idb ui text --layout LAYOUT` names a layout explicitly; `--layout US`
sends the key presses sent before this change.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant