boppreh / keyboard

Hook and simulate global keyboard events on Windows and Linux.
MIT License
3.76k stars 433 forks source link

Can't unhook press and release event map to one key #584

Closed WanliZhong closed 1 year ago

WanliZhong commented 1 year ago

When I run the code below, I can't unhook these two event. I only can unhook one of them, but the another will work still.

import keyboard

def gimbal_control_up(e):
    print("press")
def gimbal_control_stop(e):
    print("release")

up_hook = keyboard.on_press_key("w", gimbal_control_up)
up_stop = keyboard.on_release_key("w", gimbal_control_stop)
keyboard.wait("q")
keyboard.unhook(up_hook)
keyboard.unhook(up_stop)

This is the error thrown by the code:

w
press
release
q
Traceback (most recent call last):
  File "C:/Users/Zoom/Desktop/OpenCV_China/drone/drone/drone.py", line 88, in <module>
    adjust_camera()
  File "C:/Users/Zoom/Desktop/OpenCV_China/drone/drone/drone.py", line 83, in adjust_camera
    keyboard.unhook(up_stop)
  File "C:\Software\miniconda3\envs\drone\lib\site-packages\keyboard\__init__.py", line 523, in unhook
    _hooks[remove]()
  File "C:\Software\miniconda3\envs\drone\lib\site-packages\keyboard\__init__.py", line 499, in remove_
    del _hooks[key]
KeyError: 'w'
WanliZhong commented 1 year ago

I use while true loop and keyboard.read_event() to solve my problem.

monkeyman192 commented 7 months ago

So I had this exact same issue so I did some digging and it's because of how keyboard stores the information internally. The solution in the follow up comment wasn't going to work for me due to how I was using keyboard, but I found another solution which is more robust, but basically requires just using keyboard.hook and not using on_press_key or on_release_key at all and rolling your own as follows:

import keyboard
import time

def press_func():
    print("pressed a key!")

def release_func():
    print("released a key!")

press = keyboard.hook(lambda e: e.name == "space" and e.event_type == "down" and press_func())
release = keyboard.hook(lambda e: e.name == "space" and e.event_type == "up" and release_func())

while True:
    time.sleep(5)
    break

print("UNHOOKING PRESS")
keyboard.unhook_key(press)
print("UNHOOKING RELEASE")
keyboard.unhook_key(release)

while True:
    time.sleep(5)
    break

In the above I am binding both to the space bar key as you can see. This is basically what is happening in the on_press_key except it uses hook_key internally which seems to have issues when you bind two things to the same key (one up, one down)

Anyway, hope this may be useful to anyone else out there who comes across this issue!