Repository navigation
Normalize keyboard event for menu dispatch under non-Latin IME #2032
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
49f98c6
7d832ff
60a3f38
d2f1c55
10088a0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -12605,7 +12605,35 @@ private extension NSWindow { | |||||||||||||||||||||||||||||||||||||||||||||||||
| if firstResponderGhosttyView != nil, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| shouldRouteCommandEquivalentDirectlyToMainMenu(event), | ||||||||||||||||||||||||||||||||||||||||||||||||||
| let mainMenu = NSApp.mainMenu { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| let consumedByMenu = mainMenu.performKeyEquivalent(with: event) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| // Normalize event characters for non-Latin IME (Korean, Russian, etc.) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| // so NSMenu.performKeyEquivalent can match ASCII-based shortcuts. | ||||||||||||||||||||||||||||||||||||||||||||||||||
| // When IME is active, event.charactersIgnoringModifiers may return | ||||||||||||||||||||||||||||||||||||||||||||||||||
| // non-ASCII characters (e.g. "ㅅ" instead of "t"), causing menu | ||||||||||||||||||||||||||||||||||||||||||||||||||
| // shortcut matching to fail. | ||||||||||||||||||||||||||||||||||||||||||||||||||
| var menuEvent = event | ||||||||||||||||||||||||||||||||||||||||||||||||||
| let rawChars = event.charactersIgnoringModifiers ?? "" | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if (rawChars.isEmpty || !rawChars.allSatisfy(\.isASCII)), | ||||||||||||||||||||||||||||||||||||||||||||||||||
| let normalized = KeyboardLayout.character(forKeyCode: event.keyCode, modifierFlags: event.modifierFlags), | ||||||||||||||||||||||||||||||||||||||||||||||||||
| !normalized.isEmpty { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| menuEvent = NSEvent.keyEvent( | ||||||||||||||||||||||||||||||||||||||||||||||||||
| with: event.type, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| location: event.locationInWindow, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| modifierFlags: event.modifierFlags, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| timestamp: event.timestamp, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| windowNumber: event.windowNumber, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| context: nil, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| characters: event.characters ?? normalized, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| charactersIgnoringModifiers: normalized, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| isARepeat: event.isARepeat, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| keyCode: event.keyCode | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ) ?? event | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+12618
to
+12629
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Both This is harmless for A safer alternative is to preserve the original
Suggested change
Comment on lines
+12613
to
+12629
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Cover empty-string key equivalents in the new normalization path. This branch only normalizes non-ASCII 🔧 Suggested change var menuEvent = event
- if let chars = event.charactersIgnoringModifiers,
- !chars.allSatisfy({ $0.isASCII }),
- let normalized = KeyboardLayout.character(forKeyCode: event.keyCode, modifierFlags: event.modifierFlags) {
+ let rawChars = event.charactersIgnoringModifiers ?? ""
+ if (rawChars.isEmpty || !rawChars.allSatisfy(\.isASCII)),
+ let normalized = KeyboardLayout.character(forKeyCode: event.keyCode, modifierFlags: event.modifierFlags),
+ !normalized.isEmpty {
menuEvent = NSEvent.keyEvent(
with: event.type,
location: event.locationInWindow,
modifierFlags: event.modifierFlags,🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| #if DEBUG | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if menuEvent !== event { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| dlog(" → normalized menu event chars: \(event.charactersIgnoringModifiers ?? "nil") → \(menuEvent.charactersIgnoringModifiers ?? "nil")") | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| #endif | ||||||||||||||||||||||||||||||||||||||||||||||||||
| let consumedByMenu = mainMenu.performKeyEquivalent(with: menuEvent) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| #if DEBUG | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if browserZoomShortcutTraceCandidate( | ||||||||||||||||||||||||||||||||||||||||||||||||||
| flags: event.modifierFlags, | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🌐 Web query:
According to Apple AppKit documentation, doesNSEvent.charactersIgnoringModifiersignore Command, Option, and Control while preserving only Shift?💡 Result:
Yes, according to the official Apple AppKit documentation, NSEvent.charactersIgnoringModifiers ignores all modifier keys except Shift, preserving the Shift-modified character while ignoring Command (⌘), Option (⌥/Alt), and Control. The documentation states: "The characters generated by a key event as if no modifier key (except for Shift) applies." Examples include Option-e returning "e" (ignoring Option), and it is used alongside modifierFlags to detect combinations like Alt-S by checking for "s" and NSAlternateKeyMask.
Citations:
Use Shift-only modifiers when rebuilding
charactersIgnoringModifiers.Line 12616 derives
charactersIgnoringModifierswith the fullevent.modifierFlags. According to Apple AppKit documentation,NSEvent.charactersIgnoringModifiersignores all modifier keys except Shift. Passing Command, Option, and Control flags toKeyboardLayout.character()will synthesize the wrong character for those key combinations under non-Latin input methods.Suggested fix
🤖 Prompt for AI Agents