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

macOS启动pynput键盘监听器致Tkinter应用崩溃问题求助

macOS下Tkinter按钮启动pynput键盘监听器崩溃(exit code 133 SIGTRAP)解决方法

问题表现

在macOS系统下,通过Tkinter按钮的command回调函数启动pynput键盘监听器时,应用直接崩溃,控制台输出报错:

Process finished with exit code 133 (interrupted by signal 5: SIGTRAP)

直接通过终端运行脚本时,终端输出:

zsh: trace trap path/to/py/script

相同代码在Windows 11系统下可正常运行,尝试将监听器放到独立新线程中启动,崩溃问题依然存在。

运行环境

  • 系统:macOS Monterey 12.4(M1 PRO芯片)
  • Python版本:3.9
  • pynput版本:1.7.6

复现代码

import tkinter
from tkinter import Tk, Button
from pynput import keyboard

logo = b'iVBORw0KGgoAAAANSUhEUgAAACUAAAAlCAYAAADFniADAAAACXBIWXMAAAsSAAALEgHS3X78AAACOElEQVRYhc2Yy23CQBCG/1jcoYO4ATuc7GPcQdIB3H2hgzgdEMm+Ox2ECmKOvhFXAB1ABURjjdGyLHgX/PqlFcKP3Y+Z3WFmno7HI0zlJv4UQMBjAsAG8MzTrPkzA7ApwvzHdH5tKDfxafE5gIUAoKMDAAJbFmG+aQzKTfyIYcYGMCqtaJ4izLd3Q7GbUgAvD8KIOjBYagzlJn7AZn/UOtf0XYT5XBvKTfxq7+wNFnkFsAMgu6Y6BGvFO3QQFhdXCUocTuxNndjbO7EXyPduDSf2jk7sRYr5IrqneteJvcyJvVS+bkkWmvBRbstlKs3YMydZ0kNpx0CVlm7i2xdQvLHfegACGyKqvoyEG5H6eSPZ/ONE2ZoTkBsjimElFMej1wagZjzuFRlmXrlPGS960DuEPSWbvC+Nyf0Wh4Em/0YeVUCWmg4IiGRbnA8NSfaoK0tx+nNhFdWzI9XFlvShO+3IMBOo02cR5tpB2E38TBUfaU9ppahdymrYUk0osziZPwwIalNF9KxnEFFZBWVcm7WkVRHm+xKKK4shuLA0jph5LvtjKbWryi4ZatcfE05VzQmKfNljXrUSew5nhUMR5nQKvzoG2snGuFaMphzpTaL9L1W9XBHpKuIS/mydW2V7+mC+XSc67YGqEyPXfSdxnd+WK/8oZbrWGqptBXHJlBr2pG6pNpMwaZrNeQ/cC0f7LarrTRlBCXBUBtEgC9YBUpOMTnTKIUdLd/U8BUDK71Xp9FbHIkoB+AdGxhvJUKsuTwAAAABJRU5ErkJggg=='

root = Tk()
root.title("Test window")
root.geometry("400x200")
core_logo_icon = tkinter.PhotoImage(data=logo)


def start_listener():
    def on_press(key):
        print("Key ", key, " pressed")

    def on_release(key):
        print("Key ", key, " released")

    keyboard_listener = keyboard.Listener(on_press=on_press, on_release=on_release)
    keyboard_listener.start()
    print("Keyboard listener ON")


button = Button(root, command=start_listener, image=core_logo_icon, borderwidth=0)
button.pack()
root.mainloop()

问题原因

  1. macOS下pynput的键盘监听器依赖系统辅助功能权限,权限缺失时底层Quartz事件框架会直接触发SIGTRAP信号终止进程,不会抛出Python层可捕获的异常。
  2. pynput的macOS后端基于CFRunLoop实现,监听器实例必须在Tkinter主事件循环(mainloop())启动前、主线程上下文中完成初始化,在按钮回调(运行在Tk事件循环线程中)中创建监听器实例会触发底层断言崩溃,手动开新线程也无法规避——实例创建时的线程上下文不符合要求就会触发trap。

解决步骤

  1. 配置系统辅助功能权限
    打开「系统设置」→「隐私与安全性」→「辅助功能」,将你运行脚本使用的终端(Terminal/iTerm2等)或代码IDE加入允许列表,勾选开启权限。如果之前已经添加过对应程序,先删除条目重新添加,权限配置完成后完全重启终端/IDE再运行脚本。
  2. 调整代码逻辑,提前初始化监听器实例
    不要在按钮回调函数中创建keyboard.Listener实例,把实例初始化逻辑移到Tk主循环启动前的主线程中,按钮回调仅负责启动未运行的监听器即可。修正后的代码如下:
import tkinter
from tkinter import Tk, Button
from pynput import keyboard

logo = b'iVBORw0KGgoAAAANSUhEUgAAACUAAAAlCAYAAADFniADAAAACXBIWXMAAAsSAAALEgHS3X78AAACOElEQVRYhc2Yy23CQBCG/1jcoYO4ATuc7GPcQdIB3H2hgzgdEMm+Ox2ECmKOvhFXAB1ABURjjdGyLHgX/PqlFcKP3Y+Z3WFmno7HI0zlJv4UQMBjAsAG8MzTrPkzA7ApwvzHdH5tKDfxafE5gIUAoKMDAAJbFmG+aQzKTfyIYcYGMCqtaJ4izLd3Q7GbUgAvD8KIOjBYagzlJn7AZn/UOtf0XYT5XBvKTfxq7+wNFnkFsAMgu6Y6BGvFO3QQFhdXCUocTuxNndjbO7EXyPduDSf2jk7sRYr5IrqneteJvcyJvVS+bkkWmvBRbstlKs3YMydZ0kNpx0CVlm7i2xdQvLHfegACGyKqvoyEG5H6eSPZ/ONE2ZoTkBsjimElFMej1wagZjzuFRlmXrlPGS960DuEPSWbvC+Nyf0Wh4Em/0YeVUCWmg4IiGRbnA8NSfaoK0tx+nNhFdWzI9XFlvShO+3IMBOo02cR5tpB2E38TBUfaU9ppahdymrYUk0osziZPwwIalNF9KxnEFFZBWVcm7WkVRHm+xKKK4shuLA0jph5LvtjKbWryi4ZatcfE05VzQmKfNljXrUSew5nhUMR5nQKvzoG2snGuFaMphzpTaL9L1W9XBHpKuIS/mydW2V7+mC+XSc67YGqEyPXfSdxnd+WK/8oZbrWGqptBXHJlBr2pG6pNpMwaZrNeQ/cC0f7LarrTRlBCXBUBtEgC9YBUpOMTnTKIUdLd/U8BUDK71Xp9FbHIkoB+AdGxhvJUKsuTwAAAABJRU5ErkJggg=='

# 提前定义回调函数,不要嵌套在按钮回调里
def on_press(key):
    print("Key ", key, " pressed")

def on_release(key):
    print("Key ", key, " released")

root = Tk()
root.title("Test window")
root.geometry("400x200")
core_logo_icon = tkinter.PhotoImage(data=logo)

# 主循环启动前,主线程中初始化监听器实例
keyboard_listener = keyboard.Listener(on_press=on_press, on_release=on_release)

def start_listener():
    # 加判断避免重复启动报错
    if not keyboard_listener.is_alive():
        keyboard_listener.start()
        print("Keyboard listener ON")


button = Button(root, command=start_listener, image=core_logo_icon, borderwidth=0)
button.pack()
root.mainloop()
  1. M1芯片设备额外检查
    确认安装的Python是arm64原生版本,不要通过Rosetta 2转译运行x86版本的Python,转译环境下pynput和Tkinter的事件循环交互存在已知兼容问题,会偶发崩溃。

内容的提问来源于stack exchange,提问作者Tomáš Sýkora

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 06:57:21