moses-palmer / pynput

Sends virtual input commands
GNU Lesser General Public License v3.0
1.77k stars 245 forks source link

What is the darwin_intercept equivalent of the command key? #473

Open SpecialCharacter opened 2 years ago

SpecialCharacter commented 2 years ago

Description What is the darwin_intercept (= Mac) equivalent of the command key? I want to suppress it. (Or any control keys, as a matter of principle.)

Platform and pynput version MacOS Catalina 10.15.7 pynput version unknown

To Reproduce The example given in the documentation is chars == 'x', but the command key does not have a character associated with it. I tried exchanging it with virtualKey == 0x37, but it said "virtualKey is not defined".

SpecialCharacter commented 2 years ago

chars == 'cmd' and chars == cmd do not work either.

SpecialCharacter commented 2 years ago

Added virtualKey as third variable, but got an error message (along the lines of "third variable not found"). Does that mean I cannot use Quartz.CGEventKeyboardGetUnicodeString for this at all? But what then? I found CGEventCreateKeyboardEvent, but I want to listen, not create...

SpecialCharacter commented 2 years ago

OK, so apparently modifier keys are handled by CGEventGetFlags instead. Still an example would be nice (maybe the example in the documentation could be updated, as this will be valuable to other users?)... also because I usually don't work with macOS and have no idea how to program this... I guess Quartz.CGEventGetFlags(event) ... but then?

SpecialCharacter commented 2 years ago

To illustrate why: I want to assign some command key combinations (e.g., cmd + Q) new tasks. But so far, cmd + Q still closes programs, so I need to suppress that.

SpecialCharacter commented 2 years ago

OK, so if I use a True/False variable to check if the command key is pressed, I manage with elif cmd == True and length > 0 and chars == 'q': in the darwin_intercept part. The only strange thing is that "command key down, command key up, q" will trigger the behaviour as well (while I want it only for "command key down, q"). Any suggestions?

SpecialCharacter commented 2 years ago

Solved the "command key up" part, now it is triggered when pressing "cmd + Q" two times in sequence.

SpecialCharacter commented 2 years ago

This seems to do the trick:

from pynput import keyboard
from pynput.keyboard import Key, Controller
# --- initialise ---
cmd = False
# ======
def on_press(key):
    global cmd
    try:
        print('alphanumeric key {0} pressed'.format(
            key.char))
        # ...   
    except AttributeError:
        print('special key {0} pressed'.format(
            key))
        if key == Key.cmd:
            cmd = True
            # (modifier) # Windows key / MacOS Command key  
        # ...
# ======
def on_release(key):
    global cmd
    try:
        print('{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
            # (modifier) # Windows key / MacOS Command key
    except AttributeError:
        print('on_release special key {0} released'.format(
            key)) # Am Ende löschen
        # nothing
# ======
def darwin_intercept(event_type, event):                        # pynput-internal definition
    import Quartz
    global cmd
    length, chars = Quartz.CGEventKeyboardGetUnicodeString(
        event, 100, None, None)
    if cmd == True and length > 0 and chars == 'q':             # Apple down + q
        return None
    else:
        return event
# ======
# Collect events until released
with keyboard.Listener(
        on_press=on_press,
        on_release=on_release,
        # Add suppressing events (darwin_intercept):
        darwin_intercept=darwin_intercept) as listener:
    listener.join()

However, when I let go of the q key while still pressing the control key, I get an unwanted second control key event. Any suggestions how to get rid of this?

moses-palmer commented 2 years ago

Thank you for your report, and I apologise for this late reply.

When working with macOS specific functionality, you may want to consult darwin_vks.py for a list of character codes.

For detecting cmd+Q, you may want to have a look on Quartz.CGEventGetFlags and Quartz.kCGEventFlagMaskCommand; I think that will let you drop your internal state.

SpecialCharacter commented 2 years ago

The command key is not listed in [darwin_vks.py] :(

How extract the cmd or AltGr flag from [Quartz.CGEventGetFlags]? I looked for examples, but there are few...