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

按键映射软件修改全局控制变量后线程未立即终止仅按键后退出问题求助

问题根源

你遇到的线程无法立刻终止的核心原因是 keyboard.read_key() 是阻塞调用:线程执行到这行代码时会陷入阻塞等待,直到检测到键盘输入才会继续往下执行。所以哪怕你提前把全局变量active改为False,线程还是会卡在读取按键的步骤,必须等用户按下任意按键后才会判断循环条件退出。


可行解决方案

方案1:替换阻塞读取为事件驱动回调(改动最小,性能最优)

把循环内的阻塞读按键逻辑删除,改用keyboard.on_press()注册全局按键回调来接收按键输入,退出时直接卸载回调即可,完全避免阻塞等待。

修改后的代码示例:

import time # 需额外导入time模块
# 声明全局变量存回调钩子,方便后续卸载
key_hook = None

def on_key_press(event):
    # 原有的按键处理逻辑移到这个回调函数里
    global x_cor, y_cor
    key = str(event.name).capitalize()
    
    x = int(str(mouse.get_position()).split('(')[1].split(',')[0])
    y = int(str(mouse.get_position()).split(')')[0].split(', ')[1])
            
    for i in saves[start_range+1:end_range+1]:
        i = str(i).split(" = ")
        if i[0] == key:
            x_cor = int(i[1].split(',')[0])
            y_cor = int(i[1].split(',')[1])
    
    if x_cor and y_cor: 
        mouse.move(x_cor-x,y_cor-y,absolute=False,duration=0.01)
        mouse.click('left')
        x_cor = 0
        y_cor = 0
    else:
        if key == 'F9':
            button_switch()
        elif key == 'enter':
            if tree.selection() != ():
                app.wm_attributes("-topmost", 1)
                tmsg.showerror("Already running",f"'{keymap_name}' is already running.")
                app.wm_attributes("-topmost", 0)

def keymapping():
    global active, keymapping_running, key_hook
    tree.bind('<Return>',func=lambda event=None:())
    
    keymapping_running = True
    # 注册按键回调,替换原来的阻塞读循环
    key_hook = keyboard.on_press(on_key_press)
    
    # 循环只做状态检测,加短休眠降低CPU占用
    while active:
        time.sleep(0.05)
        
    # 退出时卸载按键回调,停止接收按键事件
    keyboard.unhook(key_hook)
    tree.bind('<Return>',func=lambda event=None:button_switch())

    keymapping_running = False
    x_cor = 0
    y_cor = 0
    selected = ''
    selected_iid = ''
    app.wm_attributes("-topmost", 1)
    tmsg.showinfo("Keymapping Deactivated",f"'{keymap_name}' has been deactivated")
    app.wm_attributes("-topmost", 0)
    keymap_name = ''

方案2:带超时的阻塞读(临时兼容方案,无需大改逻辑)

如果不想改动现有代码结构,可以把keyboard.read_key()替换为带超时的实现,每隔固定时间中断一次读取,判断active状态:

while active:
    # 每隔100ms超时一次,检测active状态
    try:
        key = str(keyboard.read_key(timeout=0.1)).capitalize()
    except:
        # 超时没读到按键就跳过,继续下一轮循环检测active
        continue
    
    # 原来的后续按键处理逻辑保持不变

额外优化建议

  • 尽量不要用大量全局变量传递状态,可以用类封装所有状态变量,逻辑更清晰也更易维护
  • 切换active状态时建议加线程锁,避免多线程读写变量时出现竞态条件

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 16:09:00