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

如何限制pynput的keyboard.Listener仅在指定终端窗口生效

解决方案

核心逻辑:pynput.keyboard.Listener 本身是全局监听组件,要实现仅终端窗口激活时响应,需要在按键回调中新增前台活跃窗口匹配校验,仅当当前活跃窗口为程序运行的终端时才执行后续逻辑。

实现步骤

  1. 程序启动时设置唯一的终端窗口标题,避免和其他窗口混淆
  2. 新增跨系统的活跃窗口标题获取函数
  3. 在按键回调逻辑最开头加入窗口匹配校验,不匹配则直接跳过响应

依赖安装

根据你的运行系统安装对应依赖:

  • 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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 13:15:02