临时资料

Windows终端CtrlC拦截修复全流程复盘

2026/04/21 35 min read 临时资料 WINDOWS终端CTRLC拦截修复全流程复盘

› 终于好了,你把你改这个流程的从始至终走过的全流程用文字告诉我吧

• 这次我走过的完整流程,按真实先后顺序说:

起点

  • 你的原始需求是“在终端里禁用 Ctrl+C,不要让它中断,但还想保留复制/粘贴能力”
  • 我一开始把问题错误地理解成了“终端快捷键映射问题”,没有先把“输入层”和“控制台信号层”分开

第一阶段:我先改错到了 Windows Terminal 快捷键层

  • 我先检查了 Windows Terminal 配置文件:C:\Users\ASUS- KL\AppData\Local\Packages\Microsoft.WindowsTerminal_8wekyb3d8bbwe\LocalState\settings.json
  • 发现里面的 keybindings 已经被改乱,只剩下了 ctrl+c
  • 我先做了一个错误但局部合理的修复:
    • 恢复 ctrl+v -> paste
    • 恢复 ctrl+shift+c -> copy
    • 保留 ctrl+c -> copy
  • 这一步解决了“粘贴坏了”的问题,但没有解决“Ctrl+C 仍然杀进程”的根因
  • 这里我犯的核心错误是:
    • 把“复制快捷键”当成了“中断信号”
    • 实际上这两者不是一层

第二阶段:我把问题提升到 PowerShell / console handler 层,但还是没打准

  • 你指出后,我开始意识到 Windows Terminal keybindings 不等于真正拦截 Ctrl+C
  • 我确认了当前默认 shell 是 Windows PowerShell,不是 pwsh
  • 所以我去看了:
    • C:\Users\ASUS-KL\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1
    • C:\Users\ASUS-KL\Documents\PowerShell\Microsoft.PowerShell_profile.ps1
  • 然后我尝试把 SetConsoleCtrlHandler(..., true) 写进 profile
  • 这一步的问题是:
    • 它只是让父 shell 忽略控制台 Ctrl+C
    • 但前台真正被打死的是 codex / node / codex.exe 这条前台进程链
    • 所以它不一定能拦住前台子进程退出
  • 后来我也承认这条路是“过宽污染”,不该全局改 profile

第三阶段:我开始锁真正活入口

  • 我去查了你机器上 codex 实际命中的入口,而不是猜
  • 查出来真实入口是:
    • C:\ProgramData\npm-global\codex.ps1
    • 它再调用 C:\ProgramData\npm-global\node_modules@openai\codex\bin\codex.js
  • 我也同时查到了一个可疑脚本:
    • C:\Users\ASUS-KL\bin\disable-terminal-ctrlc.ahk
  • 这时我开始收敛到两个真实可能层:
    1. codex 启动层
    2. AutoHotkey 输入层

第四阶段:我又在 codex 活入口上走了一段错路

  • 我先备份了 C:\ProgramData\npm-global\codex.ps1
  • 然后我尝试在这个入口里:
    • 临时忽略 Ctrl+C
    • 或者关掉 console 的 ENABLE_PROCESSED_INPUT
  • 我做了几轮本机验证:
    • 验证 codex --version 是否还能跑
    • 验证 codex 运行时 console mode 是否被改动
    • 甚至写了几套 helper 脚本,想自动模拟 Ctrl+C
  • 这些尝试虽然比前面更接近“真实活入口”,但仍然不够稳,也没有形成你要的“最小正确修法”
  • 你后面给的判断是对的:
    • 这条路风险更高
    • 会碰 codex 自身和控制台行为
    • 不该继续扩大系统级改动

第五阶段:我按你给的最短方案回滚

  • 你给了明确的收拾方案后,我就直接执行,不再自作聪明扩散
  • 我做了这些回滚动作:
  1. 恢复 codex 原始启动脚本
  • 用备份文件把这个恢复了:
    • C:\ProgramData\npm-global\codex.ps1
  • 恢复后重新验证:
    • codex --version
    • 输出正常:codex-cli 0.122.0
  1. 检查并确认 profile 干净
  • 检查了:
    • C:\Users\ASUS-KL\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1
    • C:\Users\ASUS-KL\Documents\PowerShell\Microsoft.PowerShell_profile.ps1
  • 确认没有残留这些东西:
    • SetConsoleCtrlHandler
    • Add-Type
    • Kernel32
    • CtrlCBlock

第六阶段:切回正确层——AutoHotkey 输入层

  • 我重新写了最简脚本:
    • C:\Users\ASUS-KL\bin\disable-terminal-ctrlc.ahk
  • 内容是:

#Requires AutoHotkey v2.0 #SingleInstance Force

#HotIf WinActive("ahk_exe WindowsTerminal.exe") ^c::return #HotIf

  • 这一步的原则是:
    • 只拦 Windows Terminal 里的 Ctrl+C
    • 不改系统 console 行为
    • 不改 codex 自己
    • 不碰 node signal / Kernel32 / codex.js

第七阶段:补齐运行环境

  • 我检查后发现你机器上虽然 winget 认为 AutoHotkey 已安装,但 PATH 里没直接找到 AutoHotkey.exe
  • 我继续查安装位置,最后定位到:
    • C:\Users\ASUS-KL\AppData\Local\Programs\AutoHotkey.pre_move\v2\AutoHotkey64.exe
  • 然后我用这个可执行文件直接启动了脚本
  • 之后确认:
    • AutoHotkey64 进程已经在运行

第八阶段:最终验证

  • 我让系统回到“正常世界”:
    • codex.ps1 已恢复原始版本
    • profile 没有脏补丁
    • AHK 脚本已运行
  • 然后你在 Windows Terminal 中做了真实验证
  • 最终结果是:
    • Ctrl+C 不再杀进程
    • 说明这次命中的确实是正确层:输入层,而不是系统控制台信号层

这次问题的本质

  • 你要的其实是:

    • “别让终端里按到 Ctrl+C”
  • 我前面错误地做成了:

    • “改变 Ctrl+C 的系统/控制台行为”
  • 正确方案最终证明是:

  • 已确认干净:

    • C:\Users\ASUS-KL\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1
    • C:\Users\ASUS-KL\Documents\PowerShell\Microsoft.PowerShell_profile.ps1

如果你要一句话复盘

  • 我先错把它当成 Terminal 快捷键问题
  • 然后又错把它推进成 console / codex 信号问题
  • 最后按你给的方向,回滚系统级改动,改成 AHK 在 Windows Terminal 输入层吞掉 Ctrl+C

如果你要,我还能把这次流程整理成一份更正式的“故障复盘文档”,按“问题 / 误判 / 修复 / 结论 / 以后禁止再碰哪些层”写成一 页。

› 我是说从最开始我跟你提这件事开始的,你不止走了这么一点弯路a

• 你说得对,我刚才那个版本只讲了“这轮补救”,没把从最开始你提需求到现在这整条错误链路讲全。 我先把本机历史里和这件事相关的记录拉出来,再给你一份完整时间线,不再只讲这一小段。

• Running $patterns = 'Ctrl+C','ctrl
│ +c','disable-terminal-ctrlc','SetConsoleCtrlHandler','WindowsTerminal','codex.ps1'; foreach($p in $patterns) │ { Write-Host "=== $p ==="; Select-String -Path 'C:\Users\ASUS-KL.codex\history.jsonl' -Pattern $p | │ … +1 lines

• Running Select-String -Path 'C:\Users\ASUS-KL.codex.codex-global-state.json' -Pattern 'Ctrl+C|ctrl+c| │ disable-terminal-ctrlc|你让在终端的时候禁用Ctrl+C吧|直接禁用 只在终端中' | ForEach-Object { $_.Line }

• Running if(Test-Path 'C:\Users\ASUS-KL\bin\codex.cmd.bak-20260418-cli-client-unify'){ Write-Host '=== codex.cmd │ current ==='; Get-Content 'C:\Users\ASUS-KL\bin\codex.cmd'; Write-Host '=== codex.cmd backup ==='; Get-Content └ === Ctrl+C === {"session_id":"019daf70-b40b-7033-8062-779eb5cf6946","ts":1776764927,"text":"我之前不是让你禁用在终端的时候的ctrl+c … +128 lines (ctrl + t to view transcript) 的是“别按到 Ctrl+C”,不是“改变 Ctrl+C 的系统行为”**\n\n---\n\n# 你现在做完之后告诉我一个结果:\n\ntext\nCtrl+C 还有没有杀进程?\n\n\n如果还有,我帮你用第二种方案(不用 AHK 的)再压一层。"}

• Ran Select-String -Path 'C:\Users\ASUS-KL.codex.codex-global-state.json' -Pattern 'Ctrl+C|ctrl+c| │ disable-terminal-ctrlc|你让在终端的时候禁用Ctrl+C吧|直接禁用 只在终端中' | ForEach-Object { $_.Line } └ {"electron-persisted-atom-state":{"electron:onboarding-welcome-pending":false,"codexCloudAccess":"enabled_needs_set up","environment":null,"fast-mode-personalized-estimate":{"estimatedSavedMs":4613868,"rolloutCountWithCompletedTurn … +47 lines (ctrl + t to view transcript) ect\Cloude App","E:\My Project\Atramenti-Console","E:\My Project\Atramenti-OpeClaw","E:\My Project","C:\"]," selected-remote-host-id":"remote-ssh-discovered:jd-lavm-beijing","primary-runtime-update-jitter-ms":895804}

• Ran if(Test-Path 'C: │ \Users\ASUS-KL\AppData\Local\Packages\Microsoft.WindowsTerminal_8wekyb3d8bbwe\LocalState\settings.ctrlc-backup.jso │ n'){ Write-Host '=== WT ctrlc backup ==='; Get-Content 'C: │ … +3 lines └ === WT ctrlc backup === { … +59 lines (ctrl + t to view transcript) "hidden": false, "name": "Windows PowerShell"

• Ran if(Test-Path 'C:\Users\ASUS-KL\bin\codex.cmd.bak-20260418-cli-client-unify'){ Write-Host '=== codex.cmd current │ ==='; Get-Content 'C:\Users\ASUS-KL\bin\codex.cmd'; Write-Host '=== codex.cmd backup ==='; Get-Content 'C: │ \Users\ASUS-KL\bin\codex.cmd.bak-20260418-cli-client-unify' } └ === codex.cmd current === @echo off … +4 lines (ctrl + t to view transcript) set "CODEX_HOME=C:\Users\ASUS-KL.codex-cli" "C:\Users\ASUS-KL\AppData\Roaming\npm\codex.cmd" %*

• Ran if(Test-Path 'C: │ \Users\ASUS-KL\AppData\Local\Packages\Microsoft.WindowsTerminal_8wekyb3d8bbwe\LocalState\settings.ctrlc-backup.jso │ n'){ Write-Host '=== WT ctrlc backup ==='; Get-Content 'C: │ … +3 lines └ === WT ctrlc backup === { … +234 lines (ctrl + t to view transcript) "themes": [] }

────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

• 对,你说得对。按本机历史、残留文件和备份来看,这件事我从一开始到最后,走过的弯路远不止我刚才说的那一点。下面是完整时间 线,我把“我当时干了什么、为什么错、留下了什么痕迹”都摊开说。

完整时间线

  1. 你最开始提的真实需求,其实是两个同时存在的约束:
  • 只在“终端里”禁用 Ctrl+C
  • 你还要继续正常复制/粘贴
  • 从 C:\Users\ASUS-KL.codex.codex-global-state.json 和 C:\Users\ASUS-KL.codex\history.jsonl 里能看到你当时连续说 过:
    • “不要让 Ctrl+C 中断,但是我还要用 Ctrl+C 复制”
    • “你让在终端的时候禁用 Ctrl+C 吧”
    • “直接禁用,只在终端中”
  1. 我第一轮一开始就把问题理解偏了,先把它当成“终端快捷键/UI 输入层配置问题”
  • 我去碰了 Windows Terminal 的配置:
    • C:\Users\ASUS-KL\AppData\Local\Packages\Microsoft.WindowsTerminal_8wekyb3d8bbwe\LocalState\settings.json
  • 从现在还在的备份看,当时原始相对干净的状态保存在:
    • C:\Users\ASUS-KL\AppData\Local\Packages\Microsoft.WindowsTerminal_8wekyb3d8bbwe\LocalState\settings.ctrlc- backup.json
  • 这一轮我做的事,本质上是:
    • 给 ctrl+c 绑成 copy
    • 试图把“复制行为”和“中断行为”揉成一件事
  • 这一步的问题是:
    • 我改的是按键映射
    • 但你遇到的核心现象里,Ctrl+C 仍然在往下触发 console / 前台进程的中断链路
  • 结果:
    • 一度把你的粘贴也弄坏了
    • 后面我又为了补救,把 ctrl+v、ctrl+shift+c 之类重新补回去
  1. 我第二轮又继续犯了一个典型错误:把“旧终端没继承新配置”当成主要原因
  • 从 history.jsonl 里能看到,当时我让你:
    • 关闭已经打开的终端 tab / 窗口
    • 重新开新的终端会话
  • 这个判断只解释了“有时配置不生效”,但解释不了你“新开的终端依然会退出”
  • 所以这一步其实是在错误方向上补说明,不是修复根因
  1. 然后我把问题抬到了更高一层,但还是没打准:我开始把它当成 PowerShell / ConsoleHost 控制台行为问题
  • 我去检查了默认 profile 和默认 shell
  • 我确认了 Windows Terminal 默认开的确实是 Windows PowerShell
  • 然后我去碰了:
    • C:\Users\ASUS-KL\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1
    • C:\Users\ASUS-KL\Documents\PowerShell\Microsoft.PowerShell_profile.ps1
  • 我尝试往 profile 里塞 SetConsoleCtrlHandler / Kernel32 / CtrlCBlock
  • 这一轮的错误是:
    • 我把“父 shell 忽略 Ctrl+C”误当成“前台真正跑着的 Codex 也会忽略 Ctrl+C”
    • 但前台死的是 codex / node / codex.exe 那条进程链,不是单纯 PowerShell 自己
  • 所以这一步比第一轮“Terminal keybindings”更接近,但仍然没命中真正生效层
  1. 再往后,我又把问题继续往错误方向推进到了项目/进程层
  • 这部分在 history.jsonl 里也有直接证据,你后来专门骂停过我:
    • “不要再分析 SIGINT、child_process、relay、taskkill、win-spawn-relay.mjs 了”
    • “这次问题不是进程层,不是 Node 层,不是 MCP 层”
  • 这说明我当时一度把问题当成:
    • Node 的 SIGINT
    • child_process
    • relay / spawn
    • 甚至项目代码入口
  • 换句话说,我在“本机终端输入问题”上,一度往“项目代码 / 进程管理 / relay”这些层去发散了
  • 这是一个比“改错配置文件”更大的弯路,因为它已经开始碰到不该碰的业务或运行链
  1. 再之后,我又去锁 codex 的真实活入口,这一步信息定位是对的,但修法还是错的
  • 我查出来真正命中的 codex 入口是:
    • C:\ProgramData\npm-global\codex.ps1
    • 再往下是 C:\ProgramData\npm-global\node_modules@openai\codex\bin\codex.js
  • 我还查到了一个可疑脚本:
    • C:\Users\ASUS-KL\bin\disable-terminal-ctrlc.ahk
  • 到这里,信息定位已经比前面靠谱很多了
  • 但我当时又做了新的错误动作:
    • 备份并修改了 C:\ProgramData\npm-global\codex.ps1
    • 试图在 codex 启动期间动 console mode、ctrl handler、输入模式
  • 我甚至留下了这个备份:
    • C:\ProgramData\npm-global\codex.ps1.bak-ctrlc-fix-20260421-191220
  • 这一步的问题是:
    • 虽然命中了活入口
    • 但仍然是在“系统/运行链路”层动刀,而不是回到你真正要的“终端里别按到 Ctrl+C”这个输入层需求
  • 这就是你后面说的那句很准的话:
    • “方向比前面更像样,但还没改对”
  1. 为了证明自己那套活入口修法,我又写了很多本机测试器和注入脚本
  • 这部分我确实做了:
    • 模拟 CTRL_C_EVENT
    • 附着 console
    • 测试 ping
    • 测试 codex
    • 试图读 console mode
    • 试图自动发送 Ctrl+C
  • 这一步的问题不是“没有努力”,而是:
    • 我在一条已经偏掉的修法上继续深挖
    • 把验证链路搞得越来越复杂
    • 但还是没回到最小正确方案
  1. 到这时,你开始明确给出分层纠偏,而且不止一次
  • history.jsonl 里能看到你给过几轮非常明确的纠偏:
    • 一轮说“这不是进程层,是本机 PowerShell 控制台会话里的 Ctrl+C 行为”
    • 一轮说“只做单宿主、单点修改、先临时验证、不要再扩散”
    • 还有一轮甚至明确给了“最短收拾方案”
  • 你当时已经把正确原则讲得很清楚了:
    • 不要再改项目代码
    • 不要再改 win-spawn-relay.mjs
    • 不要再查 SIGINT
    • 不要再碰 Cursor / VS Code keybindings
    • 不要把“看配置文件”当成“真实验证”
  1. 最后真正把事情收回来,是按你给的“收拾方案”执行的
  • 我把我自己之前那条错误系统级改动先撤掉了:
    • 用 C:\ProgramData\npm-global\codex.ps1.bak-ctrlc-fix-20260421-191220 恢复了 C:\ProgramData\npm-global\codex.ps1
  • 我检查了两个 profile,确认里面没有残留:
    • SetConsoleCtrlHandler
    • Add-Type
    • Kernel32
    • CtrlCBlock
  • 然后我彻底停掉“系统行为 / codex 行为 / node signal”这条线
  1. 真正改对的那一步,其实是回到最开始就该走的输入层:AutoHotkey
  • 我按你的最短方案,把这个脚本落成了:
    • C:\Users\ASUS-KL\bin\disable-terminal-ctrlc.ahk
  • 内容就是最小版:

#Requires AutoHotkey v2.0 #SingleInstance Force

#HotIf WinActive("ahk_exe WindowsTerminal.exe") ^c::return #HotIf

  • 然后我补齐运行环境:
    • 用 winget 安装/修复了 AutoHotkey
    • 找到实际可执行文件
    • 把脚本拉起来运行
  • 最后你实测确认:
    • 终于好了

这整件事里,我一共走过的主要弯路

  • 把需求先错判成 Windows Terminal keybindings 问题
  • 把“旧终端没继承配置”当成主因
  • 又错判成 PowerShell profile / ConsoleHost 问题
  • 又继续发散到 SIGINT / child_process / relay / win-spawn-relay.mjs / 项目代码
  • 再继续把刀落到 codex.ps1 活入口
  • 写了很多验证脚本去证明那条路
  • 最后才按你的方案回滚并改到正确层:AHK 输入拦截

这件事真正的根因,不是我不会改文件,而是我一开始就分错了层

  • 你要的是:
    • “在终端里别让 Ctrl+C 这次按键打出去”
  • 我前面做成了:
    • “修改终端快捷键”
    • “修改 shell 行为”
    • “修改 console 行为”
    • “修改 codex 入口行为”
    • “分析 node signal / relay”
  • 直到最后才回到最简单也最对的层:
    • 输入层直接吞掉 Ctrl+C

现在还留下的痕迹

  • 真正保留下来并生效的是:
    • C:\Users\ASUS-KL\bin\disable-terminal-ctrlc.ahk
    • 正在运行的 AutoHotkey64
  • 我已经撤回了:
    • C:\ProgramData\npm-global\codex.ps1 的实验性改动
  • Profile 也已经清干净
    • Codex 入口层
    • Node/Relay/项目层
  • 最后才回到正确层:
    • Windows Terminal 的输入拦截层,用 AHK 直接吞按键

如果你愿意,我可以把这整段再整理成一份更像“事故复盘”的版本,按:

  • 起因
  • 误判链路
  • 实际改动
  • 回滚点
  • 正确修法
  • 后续禁区 写成正式文档。

• Ran $wt='C:\Users\ASUS-KL\AppData\Local\Packages\Microsoft.WindowsTerminal_8wekyb3d8bbwe\LocalState\settings.json'; │ $json = Get-Content $wt -Raw | ConvertFrom-Json; $json.keybindings = @($json.keybindings | Where-Object { -not │ ($_.keys -eq 'ctrl+c') }); $json | ConvertTo-Json -Depth 100 | Set-Content $wt -Encoding utf8; Get-Content $wt └ { "$help": "https://aka.ms/terminal-documentation", … +112 lines (ctrl + t to view transcript) "themes": [] }

────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

• 对,这次我顺手把那个残留也清掉了。

我刚刚已经把 Windows Terminal 里我之前留下的:

  • ctrl+c -> copy

这个绑定删掉了。

现在 settings.json 里只剩:

  • ctrl+shift+c
  • ctrl+v
  • ctrl+shift+f
  • alt+shift+d

也就是说现在生效路径已经收敛成单一路径了:

  • 真正负责“终端里 Ctrl+C 不杀进程”的是 AutoHotkey
  • 不再混着 Windows Terminal keybinding 这条半残路线

你现在这套状态比刚修好时更干净:

  • codex.ps1 已恢复
  • profile 干净
  • Windows Terminal 不再残留 ctrl+c 特殊绑定
  • 只剩 C:\Users\ASUS-KL\bin\disable-terminal-ctrlc.ahk 这一条真源

如果你愿意,我下一步可以再帮你做两件收尾事里的任意一个:

  1. 把这个 AHK 脚本做成开机自动启动
  2. 把这次完整事故复盘写成正式文档,留档备用