Skip to content

Commit 151a43c

Browse files
authored
修复远程桌面软件按 modifier key 时产生幽灵 'a' 按键的问题 (#1116)
* Fix ghost 'a' keypress from remote desktop modifier key events Some remote desktop software (e.g. Parsec, older Deskflow) sends flagsChanged events via IOHIDPostEvent without setting event.key.keyCode for modifier keys, causing it to default to 0 (kVK_ANSI_A). The osxKeycodeToRime function then maps keycode 0 to XK_a via additionalCodeMappings, producing a ghost 'a' keypress whenever Shift, CapsLock, or other modifier keys are pressed. This fix validates that event.keyCode corresponds to a known modifier virtual keycode for flagsChanged events. When an invalid keycode is detected (such as 0), the correct modifier keycode is inferred from the changed modifier flags instead. Fixes #825
1 parent 4be026f commit 151a43c

2 files changed

Lines changed: 40 additions & 3 deletions

File tree

sources/MacOSKeyCodes.swift

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,30 @@ struct SquirrelKeycode {
6565
return UInt32(XK_VoidSymbol)
6666
}
6767

68+
static let modifierKeycodes: Set<UInt16> = [
69+
UInt16(kVK_Shift), UInt16(kVK_RightShift),
70+
UInt16(kVK_CapsLock),
71+
UInt16(kVK_Control), UInt16(kVK_RightControl),
72+
UInt16(kVK_Option), UInt16(kVK_RightOption),
73+
UInt16(kVK_Command), UInt16(kVK_RightCommand),
74+
UInt16(kVK_Function)
75+
]
76+
77+
static func inferModifierKeycode(from changes: NSEvent.ModifierFlags) -> UInt16? {
78+
if changes.contains(.capsLock) {
79+
return UInt16(kVK_CapsLock)
80+
} else if changes.contains(.shift) {
81+
return UInt16(kVK_Shift)
82+
} else if changes.contains(.control) {
83+
return UInt16(kVK_Control)
84+
} else if changes.contains(.option) {
85+
return UInt16(kVK_Option)
86+
} else if changes.contains(.command) {
87+
return UInt16(kVK_Command)
88+
}
89+
return nil
90+
}
91+
6892
private static let keycodeMappings: [Int: Int32] = [
6993
// modifiers
7094
kVK_CapsLock: XK_Caps_Lock,

sources/SquirrelInputController.swift

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,22 @@ final class SquirrelInputController: IMKInputController {
6262
}
6363
// print("[DEBUG] FLAGSCHANGED client: \(sender ?? "nil"), modifiers: \(modifiers)")
6464
var rimeModifiers: UInt32 = SquirrelKeycode.osxModifiersToRime(modifiers: modifiers)
65-
// For flags-changed event, keyCode is available since macOS 10.15
66-
// (#715)
67-
let rimeKeycode: UInt32 = SquirrelKeycode.osxKeycodeToRime(keycode: event.keyCode, keychar: nil, shift: false, caps: false)
65+
// For flags-changed event, keyCode is available since macOS 10.15 (#715)
66+
// Some remote desktop software (e.g. Parsec) sends flagsChanged events with
67+
// keyCode defaulting to 0 (kVK_ANSI_A) instead of the actual modifier keycode,
68+
// causing a ghost 'a' keypress. Validate and infer the correct keycode from
69+
// the changed modifier flags when necessary. (#825)
70+
var keyCode = event.keyCode
71+
if !SquirrelKeycode.modifierKeycodes.contains(keyCode) {
72+
guard let inferred = SquirrelKeycode.inferModifierKeycode(from: changes) else {
73+
lastModifiers = modifiers
74+
rimeUpdate()
75+
handled = true
76+
break
77+
}
78+
keyCode = inferred
79+
}
80+
let rimeKeycode: UInt32 = SquirrelKeycode.osxKeycodeToRime(keycode: keyCode, keychar: nil, shift: false, caps: false)
6881

6982
if changes.contains(.capsLock) {
7083
// NOTE: rime assumes XK_Caps_Lock to be sent before modifier changes,

0 commit comments

Comments
 (0)