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

Unix环境下Python如何避免将终端鼠标选中文本事件误识别为KeyboardInterrupt

解决Unix环境下Python误将鼠标选中文本识别为Ctrl-C的问题

这个坑我之前也踩过!其实根本不是Python的锅,是你的终端在搞事情——很多Unix系终端(比如GNOME Terminal、xterm)默认会在你用鼠标选中文本时,给前台进程发送SIGINT信号(也就是和Ctrl-C一样的信号),所以你的wrapper.py才会误判成用户要退出。

下面给你几种靠谱的解决办法,按需选择:

方法1:改终端设置(最省心,不用改代码)

直接调整终端的鼠标选中行为,让它别乱发SIGINT:

  • GNOME Terminal:打开终端的「偏好设置」→「快捷键」,找到“选中时自动复制”这类选项,要么关掉,要么改成需要手动触发(比如按Ctrl+C才复制),避免和系统的中断信号冲突。
  • Xterm:编辑你的~/.Xresources文件,添加一行XTerm*selectToClipboard: true,保存后执行xrdb ~/.Xresources生效。这样选中文本只会复制到剪贴板,不会发信号。
  • Konsole:在设置的「编辑」选项卡中,找到鼠标选中的相关设置,关闭“发送中断信号”的选项。

方法2:在代码里禁用终端鼠标事件(适合必须改程序的场景)

如果不想动终端设置,可以在wrapper.py里通过终端控制命令,禁用鼠标操作触发信号的行为。修改后的代码如下:

import subprocess
import signal
import sys
import termios

# 保存原始终端属性,退出时要恢复
original_terminal_attrs = termios.tcgetattr(sys.stdin)

def sig_handler(signum, frame):
    res = input("\nCtrl-C was pressed. Do you really want to exit? y/n ")
    if res.lower() == 'y':
        # 恢复终端原始状态再退出
        termios.tcsetattr(sys.stdin, termios.TCSADRAIN, original_terminal_attrs)
        sys.stdout.write('\033[?1000h')  # 重新开启鼠标跟踪
        sys.stdout.flush()
        sys.exit(1)

def disable_mouse_triggered_signals():
    # 用ANSI转义序列关闭xterm类终端的鼠标跟踪
    sys.stdout.write('\033[?1000l')
    sys.stdout.flush()
    # 确保只有真正的Ctrl-C(ASCII码0x03)能触发SIGINT
    attrs = termios.tcgetattr(sys.stdin)
    attrs[6][termios.VINTR] = b'\x03'
    termios.tcsetattr(sys.stdin, termios.TCSADRAIN, attrs)

try:
    disable_mouse_triggered_signals()
    signal.signal(signal.SIGINT, sig_handler)

    while True:
        p = subprocess.Popen("python run.py", shell=True)
        p.communicate()
finally:
    # 不管程序怎么退出,都要恢复终端属性
    termios.tcsetattr(sys.stdin, termios.TCSADRAIN, original_terminal_attrs)
    sys.stdout.write('\033[?1000h')
    sys.stdout.flush()

代码说明:

  • \033[?1000l是终端的ANSI控制码,用来关闭鼠标跟踪功能,这样终端就不会把鼠标选中文本的操作转换成信号发给Python进程了。
  • 保存并恢复终端属性是为了防止程序退出后,终端的行为变得异常(比如无法正常输入)。
  • 我们明确指定只有Ctrl-C(ASCII 0x03)能触发SIGINT,进一步避免误触发。

方法3:让子进程脱离当前终端会话(辅助方案)

如果不想彻底禁用鼠标事件,还可以让run.py在独立的会话中运行,这样终端的误发信号不会直接终止run.py。修改subprocess.Popen的参数:

p = subprocess.Popen("python run.py", shell=True, start_new_session=True)

不过这个方法只是减少误触发的影响——wrapper.py还是会收到误发的SIGINT,但run.py不会被直接终止,适合你需要保留终端鼠标操作的场景。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.06 06:54:02