You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Python程序运行期间检测物理按键是否按下

在Python中边运行耗时操作边检测物理按键

这个场景太常见了!单线程下确实没法同时跑耗时操作和检测按键——因为Python会把CPU资源全给那个耗时的main()函数,根本腾不出手去检查按键。解决思路就是用多线程把这两个任务分开,让它们各自跑互不干扰。下面给你两种实用的实现方案:

方案一:用第三方库pynput(跨平台推荐)

pynput是专门处理输入设备的库,跨平台支持Windows/macOS/Linux,用它监听按键非常方便。

步骤1:安装库

pip install pynput

步骤2:完整代码示例

import threading
from pynput import keyboard

# 线程安全的停止信号(比直接用全局变量更可靠)
stop_event = threading.Event()
# 原代码中的全局标志a
a = True

def main():
    global a
    try:
        # 把你的10秒耗时操作拆成可中断的小步骤
        for step in range(10):
            # 每次循环检查是否要停止
            if stop_event.is_set():
                print("检测到按键,立即终止操作!")
                break
            # 模拟单步耗时1秒的操作(替换成你的实际业务逻辑)
            import time
            time.sleep(1)
            print(f"核心操作进行中...第 {step+1} 秒")
    finally:
        # 无论正常结束还是中断,都把a设为False
        a = False

def on_key_press(key):
    """按键按下时触发的回调函数"""
    print(f"\n检测到按键: {key}")
    # 设置停止信号,通知main()终止
    stop_event.set()
    # 停止按键监听(可选,如果你只想响应一次按键)
    return False

def start_key_listener():
    """启动后台按键监听线程"""
    with keyboard.Listener(on_press=on_key_press) as listener:
        listener.join()

if __name__ == "__main__":
    # 启动核心操作线程
    main_thread = threading.Thread(target=main)
    main_thread.start()

    # 启动按键监听线程
    listener_thread = threading.Thread(target=start_key_listener)
    listener_thread.start()

    # 等待核心操作线程结束
    main_thread.join()
    print("\n程序已结束")

代码说明

  • 把main()的耗时操作拆成循环步骤,每次循环检查stop_event,这样按键按下后能快速响应中断
  • pynput的Listener会在后台线程监听按键,完全不阻塞核心操作
  • stop_event是线程安全的同步原语,避免了直接操作全局变量可能导致的竞态问题

方案二:用系统原生库(无需第三方依赖)

如果不想安装第三方库,可以根据你的操作系统用对应的标准库实现:

Windows平台(用msvcrt)

import threading
import msvcrt
import time

stop_event = threading.Event()
a = True

def main():
    global a
    try:
        for step in range(10):
            if stop_event.is_set():
                print("检测到按键,终止操作!")
                break
            time.sleep(1)
            print(f"核心操作进行中...第 {step+1} 秒")
    finally:
        a = False

def listen_for_keys():
    """循环检查按键(非阻塞)"""
    while not stop_event.is_set():
        # 检查是否有按键按下
        if msvcrt.kbhit():
            # 获取按下的按键
            key = msvcrt.getch().decode('utf-8')
            print(f"\n检测到按键: {key}")
            stop_event.set()
        # 短暂休眠,避免占用过多CPU资源
        time.sleep(0.1)

if __name__ == "__main__":
    main_thread = threading.Thread(target=main)
    main_thread.start()

    key_thread = threading.Thread(target=listen_for_keys)
    key_thread.start()

    main_thread.join()
    print("\n程序已结束")

Linux/macOS平台(用termios和sys)

import threading
import sys
import termios
import tty
import time

stop_event = threading.Event()
a = True

def get_key():
    """非阻塞获取按键"""
    fd = sys.stdin.fileno()
    old_settings = termios.tcgetattr(fd)
    try:
        tty.setraw(sys.stdin.fileno())
        key = sys.stdin.read(1)
    finally:
        termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
    return key

def main():
    global a
    try:
        for step in range(10):
            if stop_event.is_set():
                print("检测到按键,终止操作!")
                break
            time.sleep(1)
            print(f"核心操作进行中...第 {step+1} 秒")
    finally:
        a = False

def listen_for_keys():
    while not stop_event.is_set():
        try:
            key = get_key()
            print(f"\n检测到按键: {key}")
            stop_event.set()
        except:
            pass
        time.sleep(0.1)

if __name__ == "__main__":
    main_thread = threading.Thread(target=main)
    main_thread.start()

    key_thread = threading.Thread(target=listen_for_keys)
    key_thread.start()

    main_thread.join()
    print("\n程序已结束")

关键注意点

  • 一定要把耗时操作拆成可中断的小片段,否则即使触发了停止信号,也要等到整个main()执行完才会响应
  • 优先用线程安全的同步工具(比如threading.Event),而不是直接修改全局变量,避免多线程下的竞态问题
  • 如果你的main()里是调用第三方库的耗时函数(没法拆成循环),尽量找支持中断的库函数,避免用threading.Thread的terminate()方法(该方法不安全,可能导致资源泄漏)

内容的提问来源于stack exchange,提问作者Stalemate

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 09:27:33