Fix dead keys not working in the editor on desktop#17
Merged
Conversation
The desktop editor never opened a platform input-method session — the desktop TextEditorTextInputService just called awaitCancellation(). Without an AWT input-method context, Linux/XIM had nowhere to deliver composed dead-key / accent text, so the editor only received the base letter (while standard BasicTextFields elsewhere worked because they open the session). Implement a real PlatformTextInputMethodRequest on desktop via startInputMethod: a live TextEditorState adapter, an editText scope, and focusedRectInRoot for IME candidate-window placement. Compose's DesktopTextInputService2 then attaches AWT InputMethodRequests and routes InputMethodEvents (dead keys, CJK, macOS press-and-hold, Windows emoji picker) into editText. Plain KEY_TYPED input is unchanged and coexists as it does in Compose's own BasicTextField. Extract the IME edit operations shared by Android and desktop into a new commonMain ImeEditLogic, and refactor the Android InputConnection to use it so composing/cursor/surrogate semantics stay identical across platforms. Capture the editor canvas layout coordinates so the desktop IME can place the composition window at the cursor. Also wire compose-hot-reload v1.2.0-alpha01 into :sampleApp for hot-reload + MCP-driven verification of the running desktop app. Verified: 429 desktop tests pass (incl. 8 new IME-logic tests covering the dead-key/accent/CJK/surrogate cases); live keypress test on Linux shows ñ/á/è/ü committed as single composed characters with no double-insertion.
- Extract the selection/composition/text mapping used by the desktop and iOS PlatformTextInputMethodRequests into commonMain helpers (selectionAsTextRange, composingAsTextRange, imeSubSequence, imeCharAt). Both platforms' adapters now delegate to one implementation instead of duplicating it. (The adapter class itself stays per-platform: the Compose TextEditorState interface is skiko-only and not in the common API surface.) - IME char/substring queries now read only the requested range via getStringInRange instead of rebuilding the entire document with getAllText() on every call — avoids O(n)-per-access allocation during composition on large documents. - imeCharAt enforces the CharSequence out-of-range contract explicitly. - Fix a misleading comment in ImeEditLogic: the platform "batch" suppresses IME cursor-sync notifications, it does not coalesce undo history. All three targets (desktop, android, iosSimulatorArm64) compile; 429 desktop tests pass.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes the editor dropping dead-key / accent composition on desktop (Linux): reported in Wavesonics/hammer-editor#561, where
´+aproducedainstead ofáin the main editor, even though dead keys worked in every other field.Root cause
The desktop
TextEditorTextInputServicenever opened a platform input-method session — it just calledawaitCancellation(). Without an AWT input-method context attached to the focused editor, Linux/XIM has nowhere to deliver composed text, so only the base letter arrives viaKEY_TYPED. StandardBasicTextFields elsewhere work because they do open the session.Fix
PlatformTextInputMethodRequeston desktop viastartInputMethod: a liveTextEditorStateadapter, aneditTextscope, andfocusedRectInRootfor candidate-window placement. Compose'sDesktopTextInputService2then attachesInputMethodRequestsand routesInputMethodEvents intoeditText. PlainKEY_TYPEDinput is unchanged and coexists exactly as in Compose's ownBasicTextField.ImeEditLogic, and refactor the AndroidInputConnectionto use it — composing/cursor/surrogate semantics stay identical across platforms.Side benefit: the same path should also enable macOS Option-key composition and the Windows emoji picker in the editor (the previous "known limitations" in the desktop input service); only Linux dead keys were tested here.
Tooling
Wires compose-hot-reload v1.2.0-alpha01 into
:sampleAppfor hot-reload + MCP-driven verification of the running desktop app. (Local.mcp.jsonis gitignored.)Verification
:ComposeTextEditor:desktopTest— 429 tests pass, including 8 newImeEditLogicTestcases covering commit / dead-key compose-then-commit / CJK / selection-replace / surrogate-pair delete / cursor-position contract.us+intllayout):ñ,á,è,ücommitted as single composed characters;hellotypes with no double-insertion.