最近在做一键截图的脚本,这种东西其实10年之前玩过游戏都很熟悉,就类似脚本精灵,读取一些按键/自动执行一些按键。

在Github上官方就有很详细的介绍

https://github.com/boppreh/keyboard?tab=readme-ov-file#keyboard.is_pressed

安装:

pip install keyboard

这次主要还是读取键盘,而且是读取小键盘。

这里涉及到一个问题小键盘和大键盘都是有数字的,在名字属性上一摸一样,所以一般使用ScanCode键盘扫描码或者按键事件中的is_keypad来做判断。

这个库有个很好用的功能,在shell中输入下方代码,就可以直接答应事件信息一目了然,想识别哪个键按下看得很清楚。

python -m keyboard
{"event_type": "down", "scan_code": 29, "name": "ctrl", "time": 1736676278.0122712, "is_keypad": false}
{"event_type": "down", "scan_code": 46, "name": "c", "time": 1736676278.0431879, "is_keypad": false}

使用

首先,在下方官方演示代码中提到,在监听键盘时候,我们添加了一个监听任务(热键),之后程序就会自动关闭,如果我们想要之后没有代码,程序会关闭。这时不要使用while True: pass,这样会占用100%的CPU,所以使用keyboard.wait(),库内代码会执行一个休眠的任务。

Preventing the program from closing防止程序关闭

import keyboard
keyboard.add_hotkey('space', lambda: print('space was pressed!'))
# If the program finishes, the hotkey is not in effect anymore.

# Don't do this! This will use 100% of your CPU.
#while True: pass

# Use this instead
keyboard.wait()

# or this
import time
while True:
    time.sleep(1000000)

当然你也可是使用更简单的监听一次某个按键,下面演示的是空格。与上面不一样的是,上面的代码会持续监听直到你手动关闭程序。

import keyboard

# Don't do this! This will use 100% of your CPU until you press the key.
#
#while not keyboard.is_pressed('space'):
#    continue
#print('space was pressed, continuing...')

# Do this instead
keyboard.wait('space')
print('space was pressed, continuing...')

详细讲下其中的几个我用到的方法。

hook方法主要是启动一个获得所有键盘事件的钩子,只要运行,就完成了注册,这个callback回调函数需要一个形参来接受事件,传递给回调的事件的类型为keyboard.KeyboardEvent,事件类型如右图,而且在后续的使用中发现,即使是在被callback阻塞的情况下,它依旧会捕捉事件,但是不会立刻运行。suppress代表是否抑制按键被其他程序使用,默认就行,on_remove是在被钩子被移除时执行的函数,默认为空。

unhook解除钩子方法有两种一种是全部移除,一种是指定移除。

is_pressed是一种最常见的捕捉方式,提供一种不阻塞的按键监听,只会返回当前按键是否按下,一般用在循环退出的判断。

wait也很易用,阻塞监听,用于退出比较多。

keyboard.hook(callback, suppress=False, on_remove=<lambda>)

keyboard.unhook_all_hotkeys()
keyboard.unhook(remove) # remove = keyboard.hook(callback)

keyboard.is_pressed(hotkey) #hotkey = "q" 
keyboard.wait(hotkey)

下面是一段如何检测小键盘的按键的demo。

import keyboard
import time

def print_5_times():
    for i in range(5):
        print(i)
        time.sleep(0.1)   
def thats_what_I_really_want(keyboard_event):
    scan_code = keyboard_event.scan_code
    name = keyboard_event.name
    event_type = keyboard_event.event_type
    # print(scan_code,name)
    is_keypad = keyboard_event.is_keypad
    if event_type == "down":
        if name == "5" and is_keypad == True:
            print("5被按下了")
            print_5_times()
        elif name == "5" and is_keypad == False:
            print("这不是我要的5")
        else:
            print("5没有被按下")
        

keyboard.hook(lambda e: thats_what_I_really_want(e),suppress=True)
keyboard.wait()