如何限制pynput的keyboard.Listener仅在指定终端窗口生效
解决方案
核心逻辑:pynput.keyboard.Listener 本身是全局监听组件,要实现仅终端窗口激活时响应,需要在按键回调中新增前台活跃窗口匹配校验,仅当当前活跃窗口为程序运行的终端时才执行后续逻辑。
实现步骤
- 程序启动时设置唯一的终端窗口标题,避免和其他窗口混淆
- 新增跨系统的活跃窗口标题获取函数
- 在按键回调逻辑最开头加入窗口匹配校验,不匹配则直接跳过响应
依赖安装
根据你的运行系统安装对应依赖:
- Windows:
pip install pywin32 - Linux:
pip install python-xlib - macOS:
pip install pyobjc-framework-AppKit
完整修改后代码
import sys from multiprocessing import Process from pynput.keyboard import Listener, Key # 自定义唯一终端标题,避免和其他窗口冲突 APP_TERMINAL_TITLE = "我的控制台专属程序" def get_active_window_title(): """跨平台获取当前前台活跃窗口的标题""" if sys.platform == "win32": import win32gui hwnd = win32gui.GetForegroundWindow() return win32gui.GetWindowText(hwnd) elif sys.platform == "darwin": from AppKit import NSWorkspace active_app = NSWorkspace.sharedWorkspace().activeApplication() return active_app["NSApplicationName"] elif sys.platform.startswith("linux"): from Xlib import X, display d = display.Display() root = d.screen().root window_id = root.get_full_property(d.intern_atom('_NET_ACTIVE_WINDOW'), X.AnyPropertyType).value[0] window = d.create_resource_object('window', window_id) return window.get_wm_name() else: return "" def recCommand(): # 你的原有业务逻辑 pass def mainloop(debug): # 你的原有业务逻辑 pass def listener(MP: Process): def actions(key): # 新增窗口校验:活跃窗口不是当前程序终端则直接跳过响应 if get_active_window_title() != APP_TERMINAL_TITLE: return # 原有按键逻辑 if key == Key.ctrl_l: print("shutting down ...") MP.terminate() return False if str(key) == "'s'": p = Process(target=recCommand) p.start() def runListener(): listener = Listener(on_press = actions) listener.start() runListener() if __name__ == '__main__': # 启动前先设置终端标题 print(f"\033]0;{APP_TERMINAL_TITLE}\007", end="", flush=True) debug = False # 替换为你的原有参数配置 MP = Process(target=mainloop, args=(debug,)) MP.start() listener(MP=MP)
注意事项
- macOS运行时需要给运行程序的终端/IDE开启「辅助功能权限」,路径为:系统设置→隐私与安全性→辅助功能,勾选对应应用即可
- Linux如果使用Wayland显示服务器,默认会限制窗口信息获取,可切换到X11显示服务器后使用
- 若担心标题冲突,可在程序启动时生成随机唯一字符串作为标题,匹配精度更高
内容的提问来源于stack exchange,提问作者KeMeK
相关产品推荐
相关产品推荐

