pynput
pynput copied to clipboard
Global hotkeys with ctrl and alt don't work on MacOS
keyboard.GlobalHotKeys({"<ctrl>+k": test1, "<alt>+k": test2})
On Mac, hotkeys with the modifiers ctrl or alt simply don't work. The functions don't get called. Hotkeys with the cmd or shift modifiers, or with no modifiers at all, work perfectly fine. But for some reason there's a problem with ctrl and alt.
The same problem occurs if I use keyboard.HotKey, so the following example code shown in the docs doesn't work either:
from pynput import keyboard
def on_activate():
print('Global hotkey activated!')
def for_canonical(f):
return lambda k: f(l.canonical(k))
hotkey = keyboard.HotKey(
keyboard.HotKey.parse('<ctrl>+<alt>+h'),
on_activate)
with keyboard.Listener(
on_press=for_canonical(hotkey.press),
on_release=for_canonical(hotkey.release)) as l:
l.join()
Thank you for your report.
As I have noted in other issues, I no longer have access to a macOS system, so troubleshooting is very difficult. Could you please try to run the script below and post the output when you attempt the hotkey combination?
from pynput.keyboard import Key, Listener
def on_press(key):
print('> {} ({})'.format(str(key), listener.canonical(key)))
def on_release(key):
print('< {} ({})'.format(str(key), listener.canonical(key)))
if key == Key.esc:
return False
with Listener(
on_press=on_press,
on_release=on_release) as listener:
listener.join()
Cmd + K
> Key.cmd (Key.cmd)
> 'k' ('k')
< 'k' ('k')
< Key.cmd (Key.cmd)
Shift + K
> Key.shift (Key.shift)
> 'K' ('k')
< 'K' ('k')
< Key.shift (Key.shift)
Ctrl + K
> Key.ctrl (Key.ctrl)
> '\x0b' ('\x0b')
< '\x0b' ('\x0b')
< Key.ctrl (Key.ctrl)
Alt + K
> Key.alt (Key.alt)
> '˚' ('˚')
< '˚' ('˚')
< Key.alt (Key.alt)
Thank you for the log.
I suspect that CGEventKeyboardGetUnicodeString used here returns something unexpected by pynput. May I ask you to add some logging to Listener._event_to_key? All variables defined within the method are of interest.
I came into the same problem, is it solved? @moses-palmer
Unfortunately not. @wallezhang, can you provide logs?
Hi there. Im having the same problem on a mac. When I use
Key.ctrl_r (Key.ctrl) '\x0e' ('\x0e') < '\x0e' ('\x0e') < Key.ctrl_r (Key.ctrl)
Can you give me an example of the kind of logging you'd like to see for this?
Thanks
Thank you for your offer to debug.
I would like information about the event parameter in this function. Information can be extracted using the methods found here.
They are available under the Quartz module. I think that especially calling CGEventGetIntegerValueField using the constants found here would be helpful.
OK, Below you'll see my debugging program and the output. I only included params that seemed to involve keyboard stuff but if you want more specific ones please let me know which ones and ill add them and run it again. Thanks for the support!
from pynput.keyboard import Key, Listener
import Quartz
class MyListener(Listener):
def _event_to_key(self, event):
my_dict = {}
my_dict['CGEventGetType'] = Quartz.CGEventGetType(event)
my_dict['kCGKeyboardEventAutorepeat'] = Quartz.CGEventGetIntegerValueField(
event, Quartz.kCGKeyboardEventAutorepeat)
my_dict['kCGKeyboardEventKeycode'] = Quartz.CGEventGetIntegerValueField(
event, Quartz.kCGKeyboardEventKeycode)
my_dict['kCGKeyboardEventKeyboardType'] = Quartz.CGEventGetIntegerValueField(
event, Quartz.kCGKeyboardEventKeyboardType)
print('\n')
print("New _event_to_key call:")
print(my_dict)
return Listener._event_to_key(self, event)
def on_press(key):
# print('> {} ({})'.format(str(key), listener.canonical(key)))
pass
def on_release(key):
# print('< {} ({})'.format(str(key), listener.canonical(key)))
# if key == Key.esc:
# return False
pass
with MyListener(
on_press=on_press,
on_release=on_release) as listener:
listener.join()
And here's the output after typing "control" and "control-n" and "n" a few times:
New _event_to_key call: {'CGEventGetType': 12, 'kCGKeyboardEventAutorepeat': 0, 'kCGKeyboardEventKeycode': 62, 'kCGKeyboardEventKeyboardType': 58}
New _event_to_key call: {'CGEventGetType': 14, 'kCGKeyboardEventAutorepeat': 0, 'kCGKeyboardEventKeycode': 0, 'kCGKeyboardEventKeyboardType': 0}
New _event_to_key call: {'CGEventGetType': 12, 'kCGKeyboardEventAutorepeat': 0, 'kCGKeyboardEventKeycode': 62, 'kCGKeyboardEventKeyboardType': 58}
New _event_to_key call: {'CGEventGetType': 14, 'kCGKeyboardEventAutorepeat': 0, 'kCGKeyboardEventKeycode': 0, 'kCGKeyboardEventKeyboardType': 0}
New _event_to_key call: {'CGEventGetType': 12, 'kCGKeyboardEventAutorepeat': 0, 'kCGKeyboardEventKeycode': 62, 'kCGKeyboardEventKeyboardType': 58}
New _event_to_key call: {'CGEventGetType': 10, 'kCGKeyboardEventAutorepeat': 0, 'kCGKeyboardEventKeycode': 45, 'kCGKeyboardEventKeyboardType': 58}
New _event_to_key call: {'CGEventGetType': 14, 'kCGKeyboardEventAutorepeat': 0, 'kCGKeyboardEventKeycode': 0, 'kCGKeyboardEventKeyboardType': 0}
New _event_to_key call: {'CGEventGetType': 12, 'kCGKeyboardEventAutorepeat': 0, 'kCGKeyboardEventKeycode': 62, 'kCGKeyboardEventKeyboardType': 58}
New _event_to_key call: {'CGEventGetType': 11, 'kCGKeyboardEventAutorepeat': 0, 'kCGKeyboardEventKeycode': 45, 'kCGKeyboardEventKeyboardType': 58}
New _event_to_key call: {'CGEventGetType': 10, 'kCGKeyboardEventAutorepeat': 0, 'kCGKeyboardEventKeycode': 45, 'kCGKeyboardEventKeyboardType': 58}
New _event_to_key call: {'CGEventGetType': 11, 'kCGKeyboardEventAutorepeat': 0, 'kCGKeyboardEventKeycode': 45, 'kCGKeyboardEventKeyboardType': 58}
New _event_to_key call: {'CGEventGetType': 14, 'kCGKeyboardEventAutorepeat': 0, 'kCGKeyboardEventKeycode': 0, 'kCGKeyboardEventKeyboardType': 0}
New _event_to_key call: {'CGEventGetType': 12, 'kCGKeyboardEventAutorepeat': 0, 'kCGKeyboardEventKeycode': 62, 'kCGKeyboardEventKeyboardType': 58}
New _event_to_key call: {'CGEventGetType': 10, 'kCGKeyboardEventAutorepeat': 0, 'kCGKeyboardEventKeycode': 45, 'kCGKeyboardEventKeyboardType': 58}
New _event_to_key call: {'CGEventGetType': 11, 'kCGKeyboardEventAutorepeat': 0, 'kCGKeyboardEventKeycode': 45, 'kCGKeyboardEventKeyboardType': 58}
New _event_to_key call: {'CGEventGetType': 14, 'kCGKeyboardEventAutorepeat': 0, 'kCGKeyboardEventKeycode': 0, 'kCGKeyboardEventKeyboardType': 0}
New _event_to_key call: {'CGEventGetType': 12, 'kCGKeyboardEventAutorepeat': 0, 'kCGKeyboardEventKeycode': 62, 'kCGKeyboardEventKeyboardType': 58}
New _event_to_key call: {'CGEventGetType': 14, 'kCGKeyboardEventAutorepeat': 0, 'kCGKeyboardEventKeycode': 0, 'kCGKeyboardEventKeyboardType': 0}
New _event_to_key call: {'CGEventGetType': 14, 'kCGKeyboardEventAutorepeat': 0, 'kCGKeyboardEventKeycode': 0, 'kCGKeyboardEventKeyboardType': 0}
New _event_to_key call: {'CGEventGetType': 14, 'kCGKeyboardEventAutorepeat': 0, 'kCGKeyboardEventKeycode': 0, 'kCGKeyboardEventKeyboardType': 0}
@brettelliot Would you be so kind to take a look at https://stackoverflow.com/questions/64408695/example-for-darwin-intercept-in-pynput ?
I don't know anything about the "grammar" of Mac, but you seem knowledgeable. Any help is appreciated! Do I have to import Quartz?
I have finally been able to acquire access to a system with macOS.
So far I have been able to reproduce the error, and unfortunately found that the simple solution I envisioned---just clearing the alt, ctrl and ⌘ modifiers before passing the event to CGEventKeyboardGetUnicodeString---does not work; the unicode representation appears to be baked into the event.
I did, however, find a rather involved solution here. I remains to be seen whether this works from Python though.
I am having a similar issue, but different, when trying to execute this function in Ubuntu:
from pynput.keyboard import Key, Controller
import time
def open_terminal():
keyboard = Controller()
time.sleep(1)
with keyboard.pressed(Key.ctrl_l, Key.alt_l):
keyboard.press('t')
keyboard.release('t')
time.sleep(1)
when I execute open_terminal() in an interactive console, instead of opening a Terminal (which is expected behaviour if I press those keys myself), the Ctrl, Alt and T keyboard events seem to be sent to the console instead of the OS, so you end up seeing this:
>>> open_terminal()
^[^T>>>
should I open a ticket about this issue, or is it worthless?
I have same issue with ctrl in mac, I just wanted to press ctrl + right key, where it detects the right key but not the ctrl key :( have tried
print('pressing ctrl+right ') with keyboard.pressed(Key.ctrl): keyboard.press(Key.right) keyboard.release(Key.right)
but still not working.
I solved it by toggling a variable "ctrl" from True to False in the on_press(key)/on_release(key), then:
if ctrl == True and key == Key.right
<do xyz>
ctrl = False
Does that help you?
I solved it by toggling a variable "ctrl" from True to False in the on_press(key)/on_release(key), then:
if ctrl == True and key == Key.right <do xyz> ctrl = FalseDoes that help you?
can you elaborate by some more code ?
@savankaneriya savankaneriya Sorry:
` cmd = False alt_gr = False echo = False
def on_press(key): global cmd global alt_gr global echo
try:
print('alphanumeric key {0} pressed'.format(
key.char))
except AttributeError:
print('special key {0} pressed'.format(
key))
if key == Key.cmd: # Win down # Apple down
cmd = True
echo = cmd
elif key == Key.alt_gr: # AltGr down / right Alt down
alt_gr = True
echo = alt_gr
def on_release(key): global cmd global alt_gr global echo
print('[alphanumeric/special] key {0} released'.format(
key))
if key == keyboard.Key.esc: # <--- stop program
# Stop listener
return False
elif key == Key.cmd: # Win up # Apple up
cmd = False
echo = cmd
elif key == Key.alt_gr: # AltGr up / right Alt up
alt_gr = False
echo = alt_gr`