监测键盘输入 + 通过多线程解决实际需求

有个需求是这样的:程序运行时一直在跑一个 while 循环,直到检测到键盘按下 p 键,退出 while 循环,继续执行 while 循环之后的代码。

经过查阅发现实时监测键盘有两个第三方库可以使用:pyHook 和 pynput,其中只有 pynput 可以通过 pip 的方式安装,那么果断 pip install pynput。

pypi 页面地址:https://pypi.org/project/pynput/

其中涉及鼠标以及键盘的控制和监测。

键盘监测代码如下:

from pynput import keyboard

def on_press(key):
    try:
        print('alphanumeric key {0} pressed'.format(
            key.char))
    except AttributeError:
        print('special key {0} pressed'.format(
            key))

def on_release(key):
    print('{0} released'.format(
        key))
    if key == keyboard.Key.esc:
        # Stop listener
        return False

# Collect events until released
with keyboard.Listener(
        on_press=on_press,
        on_release=on_release) as listener:
    listener.join()

运行这段代码后只要按下或者松开键盘就会提示按下或是松开了哪些键,但这不能满足开头提到的循环和监测键盘同时运行的需求。

这时候就需要用到多线程了,python 中多线程的原理是计算机不停切换每个线程,因为速度足够快,让人觉得多个线程在同时运行。

多线程主要用到 threading 这个库,下面给出全部代码:

try:
    from pynput import keyboard
except:
    print('please install pynput!')
    raise SystemExit
import threading
    
class Keyboard(object):
    
    def __init__(self):
        self.a = False
        
    def do_sth(self):
        while True:
            if self.a:
                break
            else:
                print('keep running')
        print('end loop')
                
    def press(self, key):
        if str(key) == "'p'":
            self.a = True
            return False
        else:
            return True
            
    def main(self):
        with keyboard.Listener(on_press=self.press) as listener:
            listener.join()
            
    def pool(self):
        t1 = threading.Thread(target=self.do_sth, name='LoopThread1')
        t2 = threading.Thread(target=self.main, name='LoopThread2')
        t1.start()
        t2.start()
        t1.join()
        t2.join()
        
a = Keyboard()
a.pool()

在设计器中运行时由于运行栏限制显示 1000 行,因此需要加延时。