Skip to content

Add Key Mapper interoperability (key event relay service + broadcast input API)#898

Open
MiMoHo wants to merge 1 commit into
openboard-team:masterfrom
MiMoHo:keymapper-interop
Open

Add Key Mapper interoperability (key event relay service + broadcast input API)#898
MiMoHo wants to merge 1 commit into
openboard-team:masterfrom
MiMoHo:keymapper-interop

Conversation

@MiMoHo

@MiMoHo MiMoHo commented Jul 6, 2026

Copy link
Copy Markdown

Summary

This PR ports the Key Mapper interoperability layer from the KeyMapperOpenBoard fork back into OpenBoard — without any of the fork's rebranding. OpenBoard's package name, app name, icons and metadata are untouched.

Key Mapper users currently have to install the "Key Mapper GUI Keyboard" (a rebranded OpenBoard fork) to get remapped keys and macros working inside an IME. With this PR, stock OpenBoard becomes a drop-in interoperable keyboard, and the two projects stop diverging.

What this adds

  • IKeyEventRelayService / IKeyEventRelayServiceCallback AIDL definitions — deliberately kept in the io.github.sds100.keymapper.api package: the Binder interface descriptor must match the Key Mapper app byte-for-byte for cross-app IPC to work.
  • KeyEventRelayServiceWrapper (new Kotlin class in org.dslul.openboard.inputmethod.latin) — binds to the relay service of the Key Mapper release/debug/ci builds, re-binds on ACTION_REBIND_RELAY_SERVICE, and forwards key/motion events. Uses the callback-id API introduced with Key Mapper 2.8.
  • LatinIME integration:
    • hardware key events (onKeyDown/onKeyUp) and generic motion events are offered to Key Mapper first, so remaps keep working while the IME has focus;
    • key events and text arriving from Key Mapper (via relay callback or via the documented broadcast API ACTION_INPUT_DOWN_UP/_DOWN/_UP/_TEXT) are injected into the current InputConnection.
  • <queries> manifest entries for the three Key Mapper package names, so the relay service is resolvable under Android 11+ package-visibility rules.

Why it does not affect existing functionality

  • Without Key Mapper installed, binding fails silently at IME startup (three Bind unsuccessful debug logs) and every relay call is a no-op returning false, so all events take exactly the code paths they take today.
  • No dependency, toolchain or targetSdkVersion changes; the diff is additive (5 files, +465 lines, no deletions).
  • Compared to the fork, the broadcast receiver got additional null-guards (getParcelableExtra results are checked), so malformed intents cannot crash the keyboard.

Testing

Built with the project's stock toolchain configuration (AGP 7.0.4 / Gradle 7.0.2 / JDK 11) and tested on an Android 15 (API 35) emulator:

  1. Baseline behaviour unchanged: typing, auto-capitalisation, suggestions and gesture area all behave as before, with and without Key Mapper installed (screenshots below).
  2. Relay binding: with Key Mapper 4.2.1 installed, logcat shows Bind io.github.sds100.keymapper (and Bind unsuccessful …debug/…ci for the absent build variants); the service connection registers the IME callback without errors.
  3. Broadcast input API: am broadcast -a io.github.sds100.keymapper.inputmethod.ACTION_INPUT_TEXT --es io.github.sds100.keymapper.inputmethod.EXTRA_TEXT " world" commits text into the focused editor through the IME.
  4. Robustness: broadcasting a malformed EXTRA_KEY_EVENT does not crash the IME (null-guard path).
07-06 15:54:13.605  4649  4649 I LatinIME: Hardware accelerated drawing: true
07-06 15:54:13.639  4649  4649 D LatinIME: Bind io.github.sds100.keymapper
07-06 15:54:13.640  4649  4649 D LatinIME: Bind unsuccessful io.github.sds100.keymapper.debug
07-06 15:54:13.640  4649  4649 D LatinIME: Bind unsuccessful io.github.sds100.keymapper.ci
07-06 15:54:14.115  4649  4649 I LatinIME: Starting input. Cursor position = 6,6

Note for macOS/Apple-Silicon contributors (not part of this PR): the pinned NDK 21.3 and build-tools 30.0.2 only ship x86_64 binaries, so local builds there need buildToolsVersion "34.0.0", ndkVersion "23.2.8568313" and -Pandroid.aapt2FromMavenOverride=$ANDROID_HOME/build-tools/34.0.0/aapt2. Linux/CI builds are unaffected.

Context

The KeyMapperOpenBoard fork is only minimally maintained (Key Mapper is moving towards an accessibility-based "expert mode", see keymapperorg/KeyMapper#1981), but the relay protocol remains supported by current Key Mapper releases. Merging the interop here means users don't need a rebranded second keyboard for the remaining use cases, and the fork could eventually be retired in favour of stock OpenBoard.

🤖 Generated with Claude Code

Port the Key Mapper interop layer from the KeyMapperOpenBoard fork
(https://github.com/keymapperorg/KeyMapperOpenBoard) back into OpenBoard,
keeping OpenBoard's package name and branding untouched:

- Add the IKeyEventRelayService/IKeyEventRelayServiceCallback AIDL
  definitions. They intentionally stay in the io.github.sds100.keymapper.api
  package because the Binder interface descriptor must match the Key Mapper
  app for cross-app IPC to work.
- Add KeyEventRelayServiceWrapper, which binds to the relay service of the
  Key Mapper release/debug/ci builds, re-binds on
  ACTION_REBIND_RELAY_SERVICE and relays hardware key/motion events.
- LatinIME: relay hardware key events and generic motion events to Key
  Mapper first so remaps work while this IME has focus, and input key
  events/text received from Key Mapper via the relay callback and the
  broadcast API (ACTION_INPUT_DOWN_UP/_DOWN/_UP/_TEXT).
- AndroidManifest: declare <queries> for the Key Mapper packages so the
  service is visible on Android 11+.

Without Key Mapper installed all added paths are no-ops: binding fails
silently and the relay wrappers return false, so existing behaviour is
unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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