I am writing an application which uses pynput to gather raw keyboard input. I needed a form of key event that could be instantiated, deleted, enabled, and disabled arbitrarily during runtime, so pynput's Global Hotkey system wouldn't work. So, I created my own event class:
keyEvents = []
class keyEvent():
def __init__(self, key, callback, onPress, onRelease):
self.key = key,
self.callback = callback
self.onPress = onPress
self.onRelease = onRelease
self.active = True
self.calls = []
keyEvents.append(self)
# Called from listener thread, do not call callbacks from listener thread because then things happen at unpredictable times
def fire(self, state):
if self.active:
print('{} fired {}({})'.format(self.key, self.callback, state))
if self.onPress and state: self.calls.append(True)
elif self.onRelease and not state: self.calls.append(False)
def _onKeyPress(key):
print(key, key == keyboard.Key.enter)
for event in keyEvents:
if event.key == key: event.fire(True)
else: print('Event did not fire {} != {}'.format(event.key, key))
def _onKeyRelease(key):
for event in keyEvents:
if event.key == key: event.fire(False)
And here I create several events, which are polled by menu.exec
:
class menu():
def __init__(self, name):
self.name = name
self.items = []
self.keyEvents = [
keyEvent(keyboard.Key.left, self._keyLeft, True, False),
keyEvent(keyboard.Key.right, self._keyRight, True, False),
keyEvent(keyboard.Key.up, self._keyUp, True, False),
keyEvent(keyboard.Key.down, self._keyDown, True, False),
keyEvent(keyboard.Key.enter, self._keyEnter, True, False)
]
for event in self.keyEvents: event.active = False
...
def exec(self):
for event in self.keyEvents: event.active = True
self.refresh()
self.active = True
while self.active:
for event in self.keyEvents:
for call in event.calls:
event.callback(call)
time.sleep(0.1)
When I run the app, it gives me this output after I press the enter key:
Key.enter True
Event did not fire (<Key.left: <65361>>,) != Key.enter
Event did not fire (<Key.right: <65363>>,) != Key.enter
Event did not fire (<Key.up: <65362>>,) != Key.enter
Event did not fire (<Key.down: <65364>>,) != Key.enter
Event did not fire (<Key.enter: <65293>>,) != Key.enter
The first line tells me that the key passed to _onKeyPress
is indeed keyboard.Key.enter
. The last 5 lines tell me that _onKeyPress
refused to call event.fire
for all 5 events, including the one that was assigned to keyboard.Key.enter
. Nowhere else in the code does event.key
get modified. It is first set in keyEvent.__init__
and accessed in _onKeyPressed
for the comparison and yet, the enter key that _onKeyPressed
sees in the event
object is different. Why is this?
Solved! In keyEvent.__init__
I had this loose comma:
class keyEvent():
def __init__(self, key, callback, onPress, onRelease):
self.key = key,
...
Loose commas are like loose wires. They get in trouble.