Codex随行助手:基于Win32 API的窗口跟随与置顶工具实践 这次我们来看一个跟 Codex 相关的小项目我做了个会跟着 Codex 走的窗口。简单说它是一个桌面辅助窗口会自动定位到 Codex 窗口旁边Codex 窗口在哪它就跟着去哪拖动、切换屏幕、改变窗口大小时它都会贴过去同时保持置顶显示。为什么做这个东西Codex 本身是终端里的编码代理跑长任务时终端窗口经常被占满想看状态、切输入、贴提示词模板都得来回切窗口。我把常用内容放到一个独立小窗里让它跟着 Codex 走等于给 Codex 加了一块“随身面板”。这个小工具的核心特点可以概括为下面几条窗口跟随按进程名或窗口标题识别 Codex 窗口实时同步位置。置顶显示辅助窗口悬浮在 Codex 旁边不抢焦点不影响终端操作。快捷输入与提示词模板把常用 prompt 放在面板里一键发送到终端。配置化窗口尺寸、偏移量、跟随间隔、匹配规则都在配置文件里不用改代码。资源占用低不调用模型接口不需要显卡普通笔记本就能带得动。本文会带你做三件事第一理解窗口跟随的核心实现原理第二把工具在本地跑起来并完成功能验证第三把 Codex 日常使用中常见的安装、模型配置、接口转发问题一起过一遍。适合读者用 Codex CLI 跑任务、想给终端加辅助面板、对 Windows 窗口编程有兴趣的人。不适合读者想找 Codex 官方全景面板、希望在网页端使用的用户这个工具解决不了那种需求。1. Codex 是什么为什么需要一个会跟着它走的窗口Codex 是 OpenAI 开源的终端编码代理主要工作方式是你在终端里给它一个任务它在本地读取代码、执行命令、调用模型接口然后返回修改建议或直接改文件。它支持用 ChatGPT 账号登录也支持用 API Key 接入还允许通过配置文件切换不同模型服务商。最近社区里讨论比较多的场景包括 codex 接入 DeepSeek、Codex 桌面版、codex CLI 安装、cc-switch 切换配置等。但实际用下来有个很直接的问题Codex 本身是终端程序没有自带一个常驻的面板窗口。跑一个长任务时你会需要看当前任务状态或日志但不能把终端切走。频繁输入类似 prompt不想每次重新打。粘贴多段提示词模板或保存几条常用指令。在 Codex 和编辑器之间来回切换时需要一个稳定的“锚点”。所以这个窗口本质是一个“外挂面板”它不是 Codex 官方功能而是独立的小工具通过系统 API 找到 Codex 窗口跟随它的位置把辅助内容放在旁边。这样做的好处是不改 Codex 源码不动终端行为随时可以关掉不影响主流程。从技术类型上看这属于桌面窗口管理工具核心是 Win32 API 的窗口查找、位置获取、窗口定位和置顶样式处理。模型能力、API 调用这些都不是重点它服务的对象是 Codex 这个编码代理本身。2. 核心能力速览能力项说明项目类型桌面辅助窗口工具目标程序Codex CLI 终端窗口 / Codex 桌面版窗口核心功能窗口跟随、置顶、快捷输入、提示词模板、状态展示跟随实现按进程名或窗口标题识别目标窗口定时轮询位置变化支持平台以 Windows 为主用 Win32 API 实现其他平台需对应适配启动方式命令行启动 / 一键脚本是否需要模型服务不需要窗口本身不调用模型接口资源占用低主要是窗口轮询与重绘具体以本机运行情况为准模板能力支持多条提示词模板一键发送到 Codex 终端配置方式配置文件可调窗口尺寸、偏移、跟随间隔、置顶开关上面这些能力里最值得关注的是“跟随”本身。它看起来简单实际涉及目标窗口识别、位置获取、窗口样式设置、多显示器坐标、最小化恢复等一堆细节。你不需要在 Codex 侧装任何插件只需要目标窗口的标题或进程名能被识别到。需要说明的是因为 Codex 的窗口形态在不同环境里有差异——有人用 Windows Terminal有人用 Codex 桌面版还有人用 VSCode 插件里的集成终端——所以工具的识别规则设计成了可配置的。实际用的时候先确认自己那边 Codex 窗口的进程名和标题格式再填到配置文件里。3. 窗口跟随的实现思路这一节把核心原理讲清楚后面排错会用到。实现方式不唯一这里给的是我在这个项目里采用的方案。3.1 找到 Codex 窗口Windows 下找窗口通常两条路按窗口标题找FindWindowW(None, Codex)最快但标题一变就失效。枚举窗口再按进程名过滤先EnumWindows拿到所有顶层窗口句柄再用GetWindowThreadProcessId拿进程 ID最后拿进程名比对是否为codex.exe或包含 Codex 字样的进程。推荐第二种稳定性更好。条件允许的话把窗口标题和进程名都作为匹配规则谁命中都行。这里给一段参考代码Python pywin32import ctypes import ctypes.wintypes as wintypes user32 ctypes.windll.user32 kernel32 ctypes.windll.kernel32 PROCESS_QUERY_LIMITED_INFORMATION 0x1000 def match_window(hwnd): # 排除不可见窗口 if not user32.IsWindowVisible(hwnd): return False pid wintypes.DWORD() user32.GetWindowThreadProcessId(hwnd, ctypes.byref(pid)) # 打开进程拿进程名 h_process kernel32.OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, False, pid.value) if not h_process: return False name ctypes.create_unicode_buffer(260) size ctypes.c_ulong(260) kernel32.QueryFullProcessImageNameW(h_process, 0, name, ctypes.byref(size)) kernel32.CloseHandle(h_process) return codex in name.value.lower()3.2 拿到目标窗口位置用GetWindowRect拿矩形区域。注意多显示器环境下坐标可能是负数后面SetWindowPos时要直接用虚拟屏幕坐标不能假设坐标从 0 开始。rect wintypes.RECT() user32.GetWindowRect(target_hwnd, ctypes.byref(rect)) left, top, right, bottom rect.left, rect.top, rect.right, rect.bottom width right - left height bottom - top3.3 把自己的窗口贴过去跟随窗口本身用普通窗口创建但样式上要做两件事设置WS_EX_TOOLWINDOW不在任务栏显示额外图标设置WS_EX_TOPMOST置顶。然后每次位置变化时用SetWindowPos把窗口放到目标窗口右侧或左侧。# companion_hwnd 是辅助窗口句柄 # 放到 Codex 窗口右侧右边距 8 像素高度跟随目标窗口 offset_x rect.right 8 offset_y rect.top w 320 h height user32.SetWindowPos( companion_hwnd, -1, # HWND_TOPMOST offset_x, offset_y, w, h, 0x0040 # SWP_SHOWWINDOW )3.4 跟随策略选轮询还是事件监听两种方案定时轮询每 50~100ms 查一次目标窗口位置有变化就移动。实现简单兼容性最好缺点是 CPU 略高。事件监听用SetWinEventHook监听EVENT_OBJECT_LOCATIONCHANGE只有窗口移动时才触发。资源占用低但某些第三方终端窗口不一定会发出标准位置事件可能漏跟。我的建议是先把轮询跑通再换事件监听做优化。轮询间隔不要小于 30ms否则很容易出现窗口抖动如果发现跟随窗口来回跳就加大间隔到 100ms 以上。3.5 窗口最小化和恢复目标窗口最小化后IsIconic会返回 True。这时一般有两种处理跟随窗口也跟着隐藏或者显示成一个小按钮留在屏幕上。我的选择是跟随隐藏等 Codex 恢复后再出现逻辑最简单也不会干扰其它窗口。is_iconic user32.IsIconic(target_hwnd) if is_iconic: user32.ShowWindow(companion_hwnd, 0) # 隐藏 else: user32.ShowWindow(companion_hwnd, 5) # SW_SHOW4. 环境准备与前置条件这个工具的常规运行环境要求如下操作系统Windows 10 / 11。Python3.9 以上。依赖库pywin32操作 Win32 API、pynput可选用于快捷键、PyYAML读配置。不需要显卡不需要 CUDA不会占用显存。磁盘占用很小主要是代码和几个依赖库。如果你还没装 Codex先把它装好因为窗口要跟随的目标就是 Codex。Codex CLI 的常规安装方式是 Node.js 环境 npm 全局安装具体命令以官方文档为准# 确认 node 版本建议 18 及以上 node -v # 全局安装 codex npm install -g openai/codex # 查看版本 codex --version登录环节一般有两种用 ChatGPT 账号走设备认证登录或者配置 API Key 走接口调用。第一次启动 Codex 时会引导你完成也可以直接改配置文件。如果 npm 安装不顺利先检查 Node 版本和网络环境这类问题大多出在这两个地方。5. 安装部署与启动方式工具目录结构大致是这样codex-follow-window/ ├── main.py # 入口创建跟随窗口和主循环 ├── config.yaml # 配置目标窗口规则、窗口尺寸、偏移、轮询间隔 ├── templates.yaml # 提示词模板可选 ├── requirements.txt └── run.bat # 一键启动脚本依赖安装pip install pywin32 pyyaml pynput配置文件示例target: # 按进程名匹配Codex CLI 在 Windows Terminal 里运行时通常是 codex.exe process_names: - codex.exe # 按窗口标题匹配命中任一即可 title_keywords: - codex - Codex companion_window: width: 320 offset_x: 8 # 与目标窗口的横向间距 offset_y: 0 follow_interval_ms: 50 always_on_top: true auto_hide_on_minimize: true启动python main.pyWindows 下也可以直接运行 run.batecho off cd /d %~dp0 python main.py pause启动后先打开一个 Codex 终端窗口再运行工具。正常情况下几秒内右侧会出现一个辅助窗并自动对齐到 Codex 窗口右侧。如果没出现先看控制台日志里有没有输出“未找到目标窗口”。注意这里的路径、依赖版本、脚本需要按你实际仓库情况调整。如果你只是想要一个能跑的版本重点关注main.py里的窗口匹配规则和跟随逻辑。6. 功能测试与效果验证工具装好不是为了看而是为了用。下面给出一套验证流程按顺序跑一遍基本能确认这个跟随窗口是否合格。6.1 跟随测试操作步骤打开 Codex 终端窗口启动跟随工具。用鼠标拖动 Codex 窗口到屏幕不同位置。观察辅助窗口是否始终贴在 Codex 窗口右侧。预期结果辅助窗口和 Codex 窗口的相对位置保持不变拖动过程不闪、不跳、不落后明显。判断标准连续拖动 10 秒辅助窗口始终保持在目标区域。切换不同分辨率或缩放比例后仍然对齐。失败排查先看日志中目标窗口句柄是否为 0如果为 0说明进程名或标题规则没匹配上。其次看轮询间隔是否过大可以临时调到 30ms 测试。6.2 置顶测试操作步骤打开浏览器或编辑器让辅助窗口和 Codex 窗口同时可见再点击其它窗口。预期结果辅助窗口仍然悬浮在其它窗口之上且不抢焦点。判断标准辅助窗口不接收鼠标点击时不会把焦点从 Codex 抢走。这一点实现时要注意不要把辅助窗口设为默认激活窗口否则点一下面板就把 Codex 的输入焦点带走了。6.3 最小化恢复测试操作步骤最小化 Codex 窗口再恢复。预期结果Codex 最小化时辅助窗口隐藏Codex 恢复后辅助窗口回到正确位置。判断标准恢复后辅助窗口重新出现并与 Codex 对齐没有残留位置偏移。6.4 快捷输入与提示词模板测试操作步骤在辅助窗口里选中一条提示词模板单击“发送到终端”。预期结果模板内容自动写入 Codex 终端输入行。判断标准写入后终端光标位置正确没有多余换行。这里有个细节模拟键盘输入时最好用SendInput不要用旧的keybd_event否则在部分终端里会丢字符。6.5 长时间稳定性测试操作步骤让 Codex 跑一个长任务比如 10 分钟以上的代码修改同时保持跟随窗口运行。预期结果辅助窗口不崩、不飘、不占用过多 CPU。判断标准运行过程中任务管理器里主进程 CPU 占用保持低位Codex 窗口在打印日志时位置没有剧烈变化辅助窗口也没有反复跳动。7. Codex 配置与接口接入跟随窗口本身不调模型但它存在的意义是服务 Codex 的日常使用。实际使用中遇到最多的不是窗口问题而是 Codex 的配置和接口接入问题。这里把社区里高频的几个点一起说清楚。7.1 Codex 配置文件在哪Codex CLI 的配置一般在用户目录下~/.codex/config.toml。不同版本字段可能有差异改动前先备份。# 示例最小可用配置字段以官方文档为准 model_provider openai model your-model-name auth { method api-key, env_var OPENAI_API_KEY }7.2 接入 DeepSeek 这类 OpenAI 兼容服务社区里传得比较多的是 codex 接入 DeepSeek。思路其实通用Codex 支持自定义 provider只要服务商提供 OpenAI 兼容接口就能通过修改 config.toml 把模型切过去。model_provider deepseek model deepseek-chat [model_providers.deepseek] name DeepSeek base_url https://api.deepseek.com/v1 env_key DEEPSEEK_API_KEY配置完成后设置环境变量DEEPSEEK_API_KEY再启动 codex。要注意不同服务商的模型列表不一样填错模型名会直接报错。比如最近有人遇到类似the gpt-5.6-sol model is not supported的报错本质就是配置文件里写了一个服务商不支持的模型名。遇到这种问题去服务商官网查一下支持的模型列表改model字段即可。7.3 本地转发服务连不上时怎么排查如果你用 cc-switch 这类工具切换 Codex 配置或者把base_url指向本地的转发服务常见报错是类似handle codex endpoint /responses failed。这种问题通常不是 Codex 本身的问题而是本地转发服务没有启动。服务启动后端口和配置文件里的端口不一致。配置里 base_url 写错路径。服务已启动但日志显示鉴权失败。排查思路可以这样先确认转发服务进程是否在跑再确认端口能否访问最后看 Codex 启动时有没有输出对应的 HTTP 状态码。如果状态码是 401/403优先检查密钥如果是连接拒绝优先检查端口和 base_url。7.4 桌面版 / VSCode 插件场景现在有 Codex 桌面版也有 VSCode 里的 Codex 插件。跟随窗口在这些场景下同样可以用但目标进程名会不同。比如 VSCode 集成终端里跑 codex目标窗口其实是 VSCode 主窗口不是 codex.exe。所以配置文件里的目标规则要按实际场景调整否则窗口识别不到。8. 资源占用与性能观察这里分两部分跟随窗口的占用和 Codex 本身的占用。跟随窗口的资源占用很低它不调用模型接口不读大文件主要开销是轮询时的位置获取和窗口重绘。如果发现 CPU 占用偏高优先检查轮询间隔是不是太短。把follow_interval_ms从 50 调到 100一般能明显下降肉眼几乎感觉不到跟随延迟差别。Codex 本身是文本 Agent核心工作都在远端模型服务或本地命令执行上。它不依赖 GPU不需要大显存普通笔记本就能跑。你观察资源占用时重点看三个指标Codex 进程的 CPU、内存、以及终端窗口刷新频率。如果 Codex 在反复打印日志Windows Terminal 的 CPU 占用会暂时上升这是正常现象不代表跟随窗口有问题。要确认跟随窗口没有异常占用最直接的方法是任务管理器里按 CPU 排序找到两个进程分别观察。也可以这样验证只用跟随窗口但不开 Codex看它单独运行 5 分钟的 CPU 曲线再开 Codex 跑任务看曲线变化。如果两次差别不大说明跟随逻辑没有因为目标窗口活动而做无用功。9. 常见问题与排查方法问题现象可能原因排查方式解决方案启动后没有辅助窗口出现配置的进程名/标题没匹配到 Codex 窗口查看日志是否输出“未找到目标窗口”用任务管理器确认 Codex 的进程名修正 process_names辅助窗口不跟着移动轮询间隔过大或目标窗口句柄已失效检查日志中句柄是否被清空缩短轮询间隔或重新匹配窗口辅助窗口抖动/闪烁轮询间隔过短或目标窗口在持续变化位置观察抖动出现场景加大 follow_interval_ms 到 100ms 以上置顶不生效窗口样式缺少 WS_EX_TOPMOST查看窗口样式在创建窗口时设置 WS_EX_TO