Home > other >  Detect key-presses with Python in macOS
Detect key-presses with Python in macOS

Time:12-31

I wrote a script that use key-presses to record time. It is using the keyboard module that does not work on macOS.

Code

import time
import keyboard
import pyautogui

while True:
    if keyboard.is_pressed('e'):
        #recording
        v = [0]
        z = True
        m = time.time()
        while z == True:
            if keyboard.is_pressed('space'):
                v.append(time.time() - m)
            elif keyboard.is_pressed('e'):
                print("Stopped recording")
                z = False
        print(v)
    elif keyboard.is_pressed('x'):
        #replaying
        pyautogui.click()
        for b in range(len(v)-1):
            time.sleep(v[b   1] - v[b])
            pyautogui.keyDown('space')
    elif x == "q":
        #if key 'q' is pressed, it stops
        break

I tried to use pynput but without success to detect key presses in the second while loop.

How to modify the code so it can work on mac?

CodePudding user response:

Welcome to SO!

That cannot work, since a keypress is an asynchronous operation, which cannoct be collected without asynchronous event handlers.

A simple way to obtain what you want is to use pynput.

In a bunch of lines you can achieve what you tried to do:

from pynput import keyboard

recording = False
v = [0]
m = 0

def start_recording():
    recording = True
    m = time.time()

def stop_recording():
    recording = False
    print("Stopped recording")

def on_press(key):
    if key == 'e':
        if recording:
            stop_recording()
        else:
            start_recording()
    elif key == keyboard.Key.space and recording:
        v.append(time.time() - m)

listener = keyboard.Listener(on_press=on_press)
listener.start()
listener.join() # This will prevent main process to end

Same goes for the x case and the q case, which I'll leave to you as an exercise.

CodePudding user response:

Although Quartz framework is mainly dedicated to imaging, you can try this as an alternative solution.

Your modified code using pyobjc-framework-Quartz instead of "keyboard":

import time

from Quartz import CGEventCreateKeyboardEvent
from Quartz import kCGEventKeyDown
from Quartz import kCGEventKeyUp
from Quartz import CGEventPost
from Quartz import CGEventSourceCreate
from Quartz import CGKeyCode

import pyautogui

def key_down(key_code):
    event = CGEventCreateKeyboardEvent(None, key_code, True)
    CGEventPost(kCGHIDEventTap, event)

def key_up(key_code):
    event = CGEventCreateKeyboardEvent(None, key_code, False)
    CGEventPost(kCGHIDEventTap, event)

while True:
    if keyboard.is_pressed('e'):
        # recording
        v = [0]
        z = True
        m = time.time()
        while z == True:
            if keyboard.is_pressed('space'):
                v.append(time.time() - m)
            elif keyboard.is_pressed('e'):
                print("Stopped recording")
                z = False
        print(v)
    elif keyboard.is_pressed('x'):
        # replaying
        pyautogui.click()
        for b in range(len(v)-1):
            time.sleep(v[b   1] - v[b])
            key_down(CGKeyCode('space'))
            key_up(CGKeyCode('space'))
    elif x == "q":
        # if key 'q' is pressed, it stops
        break
  • Related