Repository navigation
Fix Korean (and other rewriting IME) input from the on-screen keyboard - #733
Open
ginlimeb-ship-it wants to merge 1 commit into
Open
ginlimeb-ship-it wants to merge 1 commit into
ginlimeb-ship-it wants to merge 1 commit into
Conversation
The on-screen keyboard handler sent each newly typed character and then reset the text field to the sentinel. IMEs that build a character by rewriting the one before it, like the iOS Korean keyboard (ㅎ -> 하 -> 한), lost everything after the first jamo because the character they wanted to rewrite was already gone. Instead, keep the text field contents while typing and send a diff against what was already sent: backspaces for removed characters, then the new text. Marked text from other IMEs (Japanese, Chinese) is held back until it's committed, since it can contain Latin letters. Marked Hangul is sent right away and fixed up by the diff as it changes. The field is reset to the sentinel only at whitespace, punctuation, Return, an empty field, or when the text gets long. Keyboard text events are now sent in order on a serial queue. Before, each key went through a concurrent global queue, so a backspace could be sent after the text meant to replace it. Return commits any marked text and sends it before the Return key. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This was referenced Oct 31, 2026
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 #731
Problem
onKeyboardPressed:sends each newly typed character and then resets the text field to the"0"sentinel. The iOS Korean keyboard builds a syllable by rewriting the character it just typed (ㅎ → 하 → 한). By the time it rewrites, that character has already been sent and removed from the field. As a result only the first jamo reaches the host: typing 되나 sends justㄷ, and 안녕하세요 shows ㅇㄴ. This was confirmed with Sunshine's debug log; details are in #731.Change
markedTextRangeis sent; the rest waits until it's committed, because marked text can contain Latin letters (romaji, pinyin) that shouldn't reach the host as key presses. Marked Hangul is real text that only gets replaced, so it is sent right away and the diff corrects it. Otherwise the syllable being typed wouldn't show on the host until the next one started.textFieldShouldReturn:commits any marked text and sends it before Return.dispatch_get_global_queue, which is concurrent, so a Backspace could reach the host after the text meant to replace it.sendLowLevelEvent:is split so this path can send synchronously on that queue. Other callers are unchanged.Unchanged: hardware keyboard handling, the keyboard toolbar keys, ASCII text being sent as key events (UTF-8 is used only for non-ASCII), and Backspace on an empty field.
The diff logic was also checked with a small simulation against three possible behaviors of the iOS Korean keyboard: plain replacement, a marked syllable, and a plain first jamo that then becomes marked. All the cases below passed in each, plus word-delete and Japanese-style marked input.
Testing
Tested on an iPad mini (6th generation) and an iPhone 15 Pro Max (both on iPadOS/iOS 27.2) with the built-in Korean – Standard (2-set) keyboard, streaming to Sunshine 2026.914 on Windows 11, typing into Notepad.
For comparison, with Moonlight 9.0.2 from the App Store on the same iPad, typing 안녕 hello 안녕 반가워 produced
ㅇㄴ ㅗ디ㅣㅐ ㅇㄴㅂㄱon the host (the Latin part comes from the host being in Hangul mode, which this PR doesn't change).Deleting right after typing removes one jamo at a time, also across earlier syllables. That's what the iOS keyboard itself does (same in Notes), and the host just mirrors it.
Known limitation: when a syllable changes (아 → 안) the host briefly shows the old syllable removed before the new one appears, since the only way to change already-sent text is Backspace followed by new text. Removing the short pause between the two made it worse: Backspace goes over the keyboard channel and text over the UTF-8 channel, which aren't ordered against each other, so the text could arrive first.
🤖 Generated with Claude Code