I am working on a snippet that requires user interaction: either an Esc
press or a Ctrl+Shift
press.
I am struggling with combining Ctrl+Shift
though. The below code works fine with the Esc
button. However, when pressing Ctrl+Shift
initially (before pressing Esc
) it doesn't print anything, while after having pressed Esc
at least once, it works for Shift
but not for Ctrl
- which is not what I intended. How can I bind Ctrl
and Shift
together?
from pynput import keyboard
COMBINATIONS = [
{ keyboard.Key.shift, keyboard.Key.ctrl },
{ keyboard.Key.esc }
]
# The currently active modifiers
current = set()
def execute():
print ("Pressed!")
def on_press(key):
if any([key in COMBO for COMBO in COMBINATIONS]):
current.add(key)
if any(all(k in current for k in COMBO) for COMBO in COMBINATIONS):
execute()
def on_release(key):
try:
current.remove(key)
except KeyError:
pass
with keyboard.Listener(on_press=on_press, on_release=on_release) as listener:
listener.join()
If you put a print(key)
at the start of on_press
, you'll see that the CTRL key generates either a ctrl_l
or ctrl_r
key (depending on which one you've pressed), not a ctrl
key.
So you either have to handle either of them, ending up with some monstrous any/all/any
code snippet, or just translate at the top:
if key == keyboard.Key.ctrl_l or key == keyboard.Key.ctrl_r:
key = keyboard.Key.ctrl
A version which handles this with a translation function xlate()
(for CTRL and SHIFT keys, since the latter appear to generate shift/shift_r
), as well as detecting releases of keys, can be seen below:
from pynput import keyboard
COMBINATIONS = [
{ keyboard.Key.shift, keyboard.Key.ctrl },
{ keyboard.Key.esc }
]
current = set()
def execute():
print ("Pressed!")
def xlate(key):
if key == keyboard.Key.ctrl_l or key == keyboard.Key.ctrl_r:
return keyboard.Key.ctrl
if key == keyboard.Key.shift_l or key == keyboard.Key.shift_r:
return keyboard.Key.shift
return key
def on_release(key):
key = xlate(key)
if key in current:
current.remove(key)
def on_press(key):
#print(key) # for debugging purposes.
key = xlate(key)
if any([key in COMBO for COMBO in COMBINATIONS]):
current.add(key)
if any(all(k in current for k in COMBO) for COMBO in COMBINATIONS):
execute()
with keyboard.Listener(on_press=on_press, on_release=on_release) as listener:
listener.join()