mirror of
https://github.com/netbirdio/netbird.git
synced 2026-09-30 18:49:08 +02:00
Emit explicit Fn flagsChanged transitions around macOS navigation keys
This commit is contained in:
@@ -27,6 +27,7 @@ const (
|
|||||||
kCGEventRightMouseDragged int32 = 7
|
kCGEventRightMouseDragged int32 = 7
|
||||||
kCGEventKeyDown int32 = 10
|
kCGEventKeyDown int32 = 10
|
||||||
kCGEventKeyUp int32 = 11
|
kCGEventKeyUp int32 = 11
|
||||||
|
kCGEventFlagsChanged int32 = 12
|
||||||
kCGEventOtherMouseDown int32 = 25
|
kCGEventOtherMouseDown int32 = 25
|
||||||
kCGEventOtherMouseUp int32 = 26
|
kCGEventOtherMouseUp int32 = 26
|
||||||
|
|
||||||
@@ -74,6 +75,8 @@ var (
|
|||||||
cgEventPost func(int32, uintptr)
|
cgEventPost func(int32, uintptr)
|
||||||
cgEventSetIntegerValueField func(uintptr, int32, int64)
|
cgEventSetIntegerValueField func(uintptr, int32, int64)
|
||||||
cgEventSetFlags func(uintptr, uint64)
|
cgEventSetFlags func(uintptr, uint64)
|
||||||
|
cgEventSetType func(uintptr, int32)
|
||||||
|
cgEventCreateForInput func(uintptr) uintptr
|
||||||
|
|
||||||
// CGEventCreateScrollWheelEvent is variadic, call via SyscallN.
|
// CGEventCreateScrollWheelEvent is variadic, call via SyscallN.
|
||||||
cgEventCreateScrollWheelEventAddr uintptr
|
cgEventCreateScrollWheelEventAddr uintptr
|
||||||
@@ -136,6 +139,8 @@ func initDarwinInput() {
|
|||||||
purego.RegisterLibFunc(&cgEventPost, cg, "CGEventPost")
|
purego.RegisterLibFunc(&cgEventPost, cg, "CGEventPost")
|
||||||
purego.RegisterLibFunc(&cgEventSetIntegerValueField, cg, "CGEventSetIntegerValueField")
|
purego.RegisterLibFunc(&cgEventSetIntegerValueField, cg, "CGEventSetIntegerValueField")
|
||||||
purego.RegisterLibFunc(&cgEventSetFlags, cg, "CGEventSetFlags")
|
purego.RegisterLibFunc(&cgEventSetFlags, cg, "CGEventSetFlags")
|
||||||
|
purego.RegisterLibFunc(&cgEventSetType, cg, "CGEventSetType")
|
||||||
|
purego.RegisterLibFunc(&cgEventCreateForInput, cg, "CGEventCreate")
|
||||||
|
|
||||||
sym, err := purego.Dlsym(cg, "CGEventCreateScrollWheelEvent")
|
sym, err := purego.Dlsym(cg, "CGEventCreateScrollWheelEvent")
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@@ -408,18 +413,54 @@ func (m *MacInputInjector) InjectKeyScancode(scancode, keysym uint32, down bool)
|
|||||||
m.postMacKey(src, vk, down)
|
m.postMacKey(src, vk, down)
|
||||||
}
|
}
|
||||||
|
|
||||||
// postMacKey emits a single key down/up event via Core Graphics. The
|
// postMacKey emits a single key down/up event via Core Graphics. For
|
||||||
// Fn flag is attached for keycodes that live in the Fn-shifted region of
|
// keycodes that live in the Fn-shifted region of an Apple keyboard we
|
||||||
// an Apple keyboard so the system doesn't treat the next plain key as
|
// also emit explicit flagsChanged events around the keypress: posting
|
||||||
// Fn-modified.
|
// the Fn flag on the key event alone leaves macOS's modifier state
|
||||||
|
// machine without a matching transition, which manifests as "Fn stays
|
||||||
|
// active" for the next key (e.g. the next letter activates a menu
|
||||||
|
// accelerator).
|
||||||
func (m *MacInputInjector) postMacKey(src uintptr, keycode uint16, down bool) {
|
func (m *MacInputInjector) postMacKey(src uintptr, keycode uint16, down bool) {
|
||||||
|
fnShifted := isFnShiftedKeycode(keycode)
|
||||||
|
if fnShifted && down {
|
||||||
|
postFnFlagsChanged(src, true)
|
||||||
|
}
|
||||||
event := cgEventCreateKeyboardEvent(src, keycode, down)
|
event := cgEventCreateKeyboardEvent(src, keycode, down)
|
||||||
|
if event == 0 {
|
||||||
|
if fnShifted && !down {
|
||||||
|
postFnFlagsChanged(src, false)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if fnShifted && cgEventSetFlags != nil {
|
||||||
|
cgEventSetFlags(event, kCGEventFlagMaskSecondaryFn)
|
||||||
|
}
|
||||||
|
cgEventPost(kCGHIDEventTap, event)
|
||||||
|
cfRelease(event)
|
||||||
|
if fnShifted && !down {
|
||||||
|
postFnFlagsChanged(src, false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// postFnFlagsChanged emits a synthetic Fn modifier transition so the
|
||||||
|
// system updates its global modifier state to match the key events we
|
||||||
|
// post for the navigation cluster. Without this, posting a Fn-flagged
|
||||||
|
// key event leaves macOS thinking Fn is still held after the key is
|
||||||
|
// released.
|
||||||
|
func postFnFlagsChanged(src uintptr, fnOn bool) {
|
||||||
|
if cgEventCreateForInput == nil || cgEventSetType == nil || cgEventSetFlags == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
event := cgEventCreateForInput(src)
|
||||||
if event == 0 {
|
if event == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if isFnShiftedKeycode(keycode) && cgEventSetFlags != nil {
|
cgEventSetType(event, kCGEventFlagsChanged)
|
||||||
cgEventSetFlags(event, kCGEventFlagMaskSecondaryFn)
|
var flags uint64
|
||||||
|
if fnOn {
|
||||||
|
flags = kCGEventFlagMaskSecondaryFn
|
||||||
}
|
}
|
||||||
|
cgEventSetFlags(event, flags)
|
||||||
cgEventPost(kCGHIDEventTap, event)
|
cgEventPost(kCGHIDEventTap, event)
|
||||||
cfRelease(event)
|
cfRelease(event)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user