Skip to content

iOS: fix hardware keyboard keys getting stuck - #19441

Open
frees11 wants to merge 1 commit into
libretro:masterfrom
frees11:fix/ios-keyboard-stuck-keys
Open

iOS: fix hardware keyboard keys getting stuck#19441
frees11 wants to merge 1 commit into
libretro:masterfrom
frees11:fix/ios-keyboard-stuck-keys

Conversation

@frees11

@frees11 frees11 commented Aug 19, 2026

Copy link
Copy Markdown

Fixes hardware keyboard keys staying "held" on iOS (#16212).

Three independent causes in the iOS keyboard path:

  1. pressesCancelled:withEvent: was not implemented (App Store build path, HAVE_APPLE_STORE). UIKit delivers pressesCancelled instead of pressesEnded when the system interrupts a press (app switcher, keyboard-shortcut HUD, incoming call, ...). Without a handler the key stays latched in apple_key_state[] until it is pressed again — the emulated character keeps walking after the key was released.

  2. Key-event de-dup was global instead of per-key (non-store build path). handleKeyUIEvent: / _keyCommandForEvent: drop any event carrying the same timestamp as the previous one. Two keys pressed or released within the same frame share a timestamp, so the second key's event was silently discarded — that key stayed stuck (lost key-up) or appeared dead (lost key-down). The de-dup is now keyed on (timestamp, keyCode, isKeyDown).

  3. Keyboard state was not reset on focus loss on iOS. The macOS port calls apple_input_keyboard_reset() in applicationWillResignActive (ui_cocoa.m); the iOS port only cleared stale touches. Keys held while switching away never received their release event. Now mirrored on iOS.

Testing

Built with HAVE_APPLE_STORE (public presses path) from RetroArch_iOS13.xcodeproj and deployed to a physical iPhone 17 Pro Max (iOS 27.0 beta) with a USB-C HID keyboard case (Akko MetaKey). An instrumented run logging the press pipeline recorded 629 keypresses with 629 matching key-down and 629 key-up events — no stuck keys during fast direction mashing, and no keys latched after app switching. Before the patch, the stuck-direction repro of #16212 appeared within seconds of fast direction input.

The non-store handleKeyUIEvent: change is compile-tested only — that path is not built in the configuration I deployed.

- Handle pressesCancelled as key release; UIKit delivers it instead of
  pressesEnded when the system interrupts a press, leaving the key
  latched in apple_key_state (libretro#16212)
- De-dup key events per (timestamp, keycode, direction) instead of
  timestamp alone, which dropped the second of two keys pressed or
  released in the same frame
- Reset keyboard state when the app resigns active, matching the macOS
  port
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant