Press cmd_r and release with cmd pressed will produce two presses instead of press + release
tisonkun opened this issue · 3 comments
Description
from dotenv import load_dotenv
from pynput import keyboard
from pynput.keyboard import Key
import logging
import os
import sys
MODIFIERS = {
Key.shift, Key.shift_l, Key.shift_r,
Key.alt, Key.alt_l, Key.alt_r, Key.alt_gr,
Key.ctrl, Key.ctrl_l, Key.ctrl_r,
Key.cmd, Key.cmd_l, Key.cmd_r,
}
TABLE = sqlalchemy.Table(
'keyboard_monitor',
sqlalchemy.MetaData(),
sqlalchemy.Column('hits', sqlalchemy.String),
sqlalchemy.Column('ts', sqlalchemy.DateTime),
)
if __name__ == '__main__':
load_dotenv()
logging.basicConfig(filename='agent.log', encoding='utf-8', level=logging.DEBUG)
logging.getLogger().addHandler(logging.StreamHandler(sys.stdout))
current_modifiers = set()
def record_combos(keys):
hits = '+'.join(keys)
logging.info(f'recoding: {hits}')
def on_press(key):
if key in MODIFIERS:
current_modifiers.add(key)
else:
record_combos(sorted([ str(key) for key in current_modifiers ]) + [ str(key) ])
logging.debug(f'{key} pressed, current_modifiers: {current_modifiers}')
def on_release(key):
if key in MODIFIERS:
try:
current_modifiers.remove(key)
except KeyError:
logging.warn(f'Key {key} not in current_modifiers {current_modifiers}')
logging.debug(f'{key} released, current_modifiers: {current_modifiers}')
with keyboard.Listener(on_press=on_press, on_release=on_release) as listener:
try:
listener.join()
except KeyboardInterrupt:
logging.info("Exiting...")
Platform and pynput version
pynput: 1.7.6
os: Darwin tisondeMacBook-Pro.local 22.5.0 Darwin Kernel Version 22.5.0: Mon Apr 24 20:53:19 PDT 2023; root:xnu-8796.121.2~5/RELEASE_ARM64_T6020 arm64
MacOS Ventura 13.4
To Reproduce
Keep the left command pressed, and press the right command and release it, then release the left command:
Key.cmd pressed, current_modifiers: {<Key.cmd: <55>>}
Key.cmd_r pressed, current_modifiers: {<Key.cmd_r: <54>>, <Key.cmd: <55>>}
Key.cmd_r pressed, current_modifiers: {<Key.cmd_r: <54>>, <Key.cmd: <55>>}
Key.cmd released, current_modifiers: {<Key.cmd_r: <54>>}
As you can see, two "Key.cmd_r pressed" events were emitted instead of a press and a release.
For my use case, I may want only an API to get the current pressed key ..
This bug can be reproduced if I switch the command order, that is:
Key.cmd_r pressed, current_modifiers: {<Key.cmd_r: <54>>}
Key.cmd pressed, current_modifiers: {<Key.cmd: <55>>, <Key.cmd_r: <54>>}
Key.cmd pressed, current_modifiers: {<Key.cmd: <55>>, <Key.cmd_r: <54>>}
Thank you for your report.
Unfortunately I no longer have access to a macOS system, so I cannot test this, but reading through the code here reveals a possible cause; the modifier keys do not emit proper keyboard events, but only flag changed events, and this library uses heuristics to determine whether a key has been pressed or released. shift and ctrl should exhibit the same behaviour.
I am uncertain about how to proceed, as I have trouble finding any reasonable way to determine the pressed state.