Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions sources/MacOSKeyCodes.swift
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,30 @@ struct SquirrelKeycode {
return UInt32(XK_VoidSymbol)
}

static let modifierKeycodes: Set<UInt16> = [
UInt16(kVK_Shift), UInt16(kVK_RightShift),
UInt16(kVK_CapsLock),
UInt16(kVK_Control), UInt16(kVK_RightControl),
UInt16(kVK_Option), UInt16(kVK_RightOption),
UInt16(kVK_Command), UInt16(kVK_RightCommand),
UInt16(kVK_Function)
]

static func inferModifierKeycode(from changes: NSEvent.ModifierFlags) -> UInt16? {
if changes.contains(.capsLock) {
return UInt16(kVK_CapsLock)
} else if changes.contains(.shift) {
return UInt16(kVK_Shift)
} else if changes.contains(.control) {
return UInt16(kVK_Control)
} else if changes.contains(.option) {
return UInt16(kVK_Option)
} else if changes.contains(.command) {
return UInt16(kVK_Command)
}
return nil
}

private static let keycodeMappings: [Int: Int32] = [
// modifiers
kVK_CapsLock: XK_Caps_Lock,
Expand Down
19 changes: 16 additions & 3 deletions sources/SquirrelInputController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,22 @@ final class SquirrelInputController: IMKInputController {
}
// print("[DEBUG] FLAGSCHANGED client: \(sender ?? "nil"), modifiers: \(modifiers)")
var rimeModifiers: UInt32 = SquirrelKeycode.osxModifiersToRime(modifiers: modifiers)
// For flags-changed event, keyCode is available since macOS 10.15
// (#715)
let rimeKeycode: UInt32 = SquirrelKeycode.osxKeycodeToRime(keycode: event.keyCode, keychar: nil, shift: false, caps: false)
// For flags-changed event, keyCode is available since macOS 10.15 (#715)
// Some remote desktop software (e.g. Parsec) sends flagsChanged events with
// keyCode defaulting to 0 (kVK_ANSI_A) instead of the actual modifier keycode,
// causing a ghost 'a' keypress. Validate and infer the correct keycode from
// the changed modifier flags when necessary. (#825)
var keyCode = event.keyCode
if !SquirrelKeycode.modifierKeycodes.contains(keyCode) {
guard let inferred = SquirrelKeycode.inferModifierKeycode(from: changes) else {
lastModifiers = modifiers
rimeUpdate()
handled = true
break
}
keyCode = inferred
}
let rimeKeycode: UInt32 = SquirrelKeycode.osxKeycodeToRime(keycode: keyCode, keychar: nil, shift: false, caps: false)

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