Skip to content

Commit 56f1410

Browse files
committed
Merge pull request #412 from morinted/osx-mods
osxkeyboardcontrol: explicity remove unwanted mask flags
2 parents 35e3975 + 09b96ac commit 56f1410

File tree

1 file changed

+31
-24
lines changed

1 file changed

+31
-24
lines changed

plover/oslayer/osxkeyboardcontrol.py

+31-24
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,11 @@
3131
kCGHeadInsertEventTap,
3232
kCGKeyboardEventKeycode,
3333
kCGSessionEventTap,
34+
kCGEventSourceStateHIDSystemState,
3435
)
3536
import Foundation
3637
import threading
38+
from time import time
3739
import collections
3840
from plover.oslayer import mac_keycode
3941

@@ -148,10 +150,7 @@ def down_up(seq):
148150
55: kCGEventFlagMaskCommand
149151
}
150152

151-
# kCGEventSourceStatePrivate is -1 but when -1 is passed in here it is
152-
# unmarshalled incorrectly as 10379842816535691263.
153-
MY_EVENT_SOURCE = CGEventSourceCreate(0xFFFFFFFF) # 32 bit -1
154-
MY_EVENT_SOURCE_ID = CGEventSourceGetSourceStateID(MY_EVENT_SOURCE)
153+
OUTPUT_SOURCE = CGEventSourceCreate(kCGEventSourceStateHIDSystemState)
155154

156155
# For the purposes of this class, we're only watching these keys.
157156
# We could calculate the keys, but our default layout would be misleading:
@@ -186,10 +185,6 @@ def callback(proxy, event_type, event, reference):
186185
# Don't pass on meta events meant for this event tap.
187186
if event_type not in self._KEYBOARD_EVENTS:
188187
return None
189-
# Don't intercept events from this module.
190-
if (CGEventGetIntegerValueField(event, kCGEventSourceStateID) ==
191-
MY_EVENT_SOURCE_ID):
192-
return event
193188
# Don't intercept the event if it has modifiers, allow
194189
# Fn and Numeric flags so we can suppress the arrow and
195190
# extended (home, end, etc...) keys.
@@ -261,9 +256,9 @@ def __init__(self):
261256
def send_backspaces(number_of_backspaces):
262257
for _ in xrange(number_of_backspaces):
263258
CGEventPost(kCGSessionEventTap,
264-
CGEventCreateKeyboardEvent(MY_EVENT_SOURCE, BACK_SPACE, True))
259+
CGEventCreateKeyboardEvent(OUTPUT_SOURCE, BACK_SPACE, True))
265260
CGEventPost(kCGSessionEventTap,
266-
CGEventCreateKeyboardEvent(MY_EVENT_SOURCE, BACK_SPACE, False))
261+
CGEventCreateKeyboardEvent(OUTPUT_SOURCE, BACK_SPACE, False))
267262

268263
def send_string(self, s):
269264
"""
@@ -320,10 +315,10 @@ def apply_raw():
320315

321316
@staticmethod
322317
def _send_string_press(c):
323-
event = CGEventCreateKeyboardEvent(MY_EVENT_SOURCE, 0, True)
318+
event = CGEventCreateKeyboardEvent(OUTPUT_SOURCE, 0, True)
324319
KeyboardEmulation._set_event_string(event, c)
325320
CGEventPost(kCGSessionEventTap, event)
326-
event = CGEventCreateKeyboardEvent(MY_EVENT_SOURCE, 0, False)
321+
event = CGEventCreateKeyboardEvent(OUTPUT_SOURCE, 0, False)
327322
KeyboardEmulation._set_event_string(event, c)
328323
CGEventPost(kCGSessionEventTap, event)
329324

@@ -418,30 +413,42 @@ def _set_event_string(event, s):
418413
buf = Foundation.NSString.stringWithString_(s)
419414
CGEventKeyboardSetUnicodeString(event, len(buf), buf)
420415

416+
MODS_MASK = (
417+
kCGEventFlagMaskAlternate |
418+
kCGEventFlagMaskControl |
419+
kCGEventFlagMaskShift |
420+
kCGEventFlagMaskCommand
421+
)
422+
421423
@staticmethod
422424
def _send_sequence(sequence):
423425
# There is a bug in the event system that seems to cause inconsistent
424426
# modifiers on key events:
425427
# http://stackoverflow.com/questions/2008126/cgeventpost-possible-bug-when-simulating-keyboard-events
426428
# My solution is to manage the state myself.
427429
# I'm not sure how to deal with caps lock.
428-
# If event_mask is not zero at the end then bad things might happen.
429-
event_mask = 0
430+
# If mods_flags is not zero at the end then bad things might happen.
431+
mods_flags = 0
432+
430433
for keycode, key_down in sequence:
431434
if not key_down and keycode in MODIFIER_KEYS_TO_MASKS:
432-
event_mask &= ~MODIFIER_KEYS_TO_MASKS[keycode]
435+
mods_flags &= ~MODIFIER_KEYS_TO_MASKS[keycode]
436+
437+
event = CGEventCreateKeyboardEvent(OUTPUT_SOURCE, keycode, key_down)
433438

434-
event = CGEventCreateKeyboardEvent(MY_EVENT_SOURCE, keycode, key_down)
439+
if key_down and keycode not in MODIFIER_KEYS_TO_MASKS:
440+
event_flags = CGEventGetFlags(event)
441+
# Add wanted flags, remove unwanted flags.
442+
goal_flags = (event_flags & ~KeyboardEmulation.MODS_MASK) | mods_flags
443+
if event_flags != goal_flags:
444+
CGEventSetFlags(event, goal_flags)
435445

436-
# The event comes with flags already, check if they contain our own event_mask.
437-
if event_mask and (CGEventGetFlags(event) & event_mask) != event_mask:
438-
# If our event_mask is missing from flags, set it.
439-
CGEventSetFlags(event, event_mask)
440-
elif not event_mask and keycode not in MODIFIER_KEYS_TO_MASKS:
441-
# Always set event_mask when it is zero to force release of modifiers.
442-
CGEventSetFlags(event, event_mask)
446+
# Half millisecond pause after keydown
447+
deadline = time() + 0.0005
448+
while time() < deadline:
449+
pass
443450

444451
CGEventPost(kCGSessionEventTap, event)
445452

446453
if key_down and keycode in MODIFIER_KEYS_TO_MASKS:
447-
event_mask |= MODIFIER_KEYS_TO_MASKS[keycode]
454+
mods_flags |= MODIFIER_KEYS_TO_MASKS[keycode]

0 commit comments

Comments
 (0)