恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
wezterm `window-focus-changed` 事件完全指南:监听窗口焦点状态并联动 Lua 配置
首页
资讯中心
/
wezterm `window-focus-changed` 事件完全指南:监听窗口焦点状态并联动 Lua 配置
wezterm `window-focus-changed` 事件完全指南:监听窗口焦点状态并联动 Lua 配置
发布时间:2026/9/13 6:26:22
weztermwindow-focus-changed事件完全指南监听窗口焦点状态并联动 Lua 配置【免费下载链接】weztermA GPU-accelerated cross-platform terminal emulator and multiplexer written by wez and implemented in Rust项目地址: https://gitcode.com/GitHub_Trending/we/wezterm导读window-focus-changed是 wezterm 在 GUI 窗口焦点状态发生变化时触发的一个 Lua 事件它是窗口级事件Window Event家族的一员通过 wezterm.on 注册回调即可捕获。本文基于 window-focus-changed.md 官方文档结合 wezterm 源码wezterm-gui/src/termwindow/mod.rs 与 wezterm-gui/src/scripting/guiwin.rs深入讲解该事件的触发时机、参数结构、回调写法并给出多个可直接复制的实战示例帮助你实现窗口失焦自动暂停任务、聚焦自动恢复主题、根据焦点状态切换配色等场景。一、事件概述什么时候会触发window-focus-changed事件自版本20221119-145034-49b9839f起引入见 docs/changelog.md 中与该版本同步发布的window:is_focused()方法。该事件在窗口的焦点状态发生变化时发出即窗口从后台切换到前台获得焦点窗口从前台切换到后台失去焦点在多个 wezterm 窗口之间切换时每个受影响窗口都会触发各自的事件。注意这里的焦点指 GUI 窗口级别的输入焦点与某个具体 Pane 是否被选中不是同一概念。焦点变化会影响鼠标事件、光标闪烁等窗口级行为而当前活动 Pane 的变化则与update-status等事件相关。在源码层面焦点变化由TermWindow::focus_changed()处理wezterm-gui/src/termwindow/mod.rs 中可以看到完整调用链fn focus_changed(mut self, focused: bool, window: Window) { log::trace!(Setting focus to {:?}, focused); self.focused if focused { Some(Instant::now()) } else { None }; self.quad_generation 1; self.load_os_parameters(); if self.focused.is_none() { // 失焦时清理鼠标状态 self.last_mouse_click None; self.current_mouse_buttons.clear(); self.current_mouse_capture None; self.is_click_to_focus_window false; } // 重置光标闪烁相位强制重绘光标 self.prev_cursor.bump(); window.invalidate(); // 通知活动 pane 焦点变化 if let Some(pane) self.get_active_pane_or_overlay() { pane.focus_changed(focused); } self.update_title(); self.emit_window_event(window-focus-changed, None); }从这段实现可以看出几个值得注意的细节窗口内部的focused字段被记录为OptionInstantwezterm-gui/src/termwindow/mod.rswindow:is_focused()正是通过判断该字段是否为Some来返回布尔值见 wezterm-gui/src/scripting/guiwin.rs失焦时 wezterm 会主动清理鼠标点击、按键捕获、鼠标终端坐标等状态避免失焦后残留输入状态无论聚焦还是失焦都会触发一次window-focus-changed事件回调中可以通过window:is_focused()区分是哪种状态变化。二、事件参数window对象与pane对象与大多数窗口级事件如 window-resized.md、window-config-reloaded.md一致window-focus-changed的回调携带两个参数参数类型含义windowwindow 对象代表当前触发事件的 GUI 窗口句柄panepane 对象该窗口中当前活动的 pane其中window对象本质上是源码中GuiWin结构体mux_window_id 底层::window::Window在 Lua 层的封装wezterm-gui/src/scripting/guiwin.rs 中定义了它的构造方式。它不能由 Lua 代码主动创建只能通过事件回调传入。pane对象是MuxPane类型mux::pane::PaneId的包装代表当前活动窗格。注意事件触发时若窗口存在 overlay例如复制模式、快速选择、确认关闭对话框等叠加层get_active_pane_or_overlay()返回的可能是 overlay 对应的 pane这在 wezterm-gui/src/termwindow/mod.rs 的schedule_window_event中体现。三、基础用法官方最小示例官方文档给出的最小示例window-focus-changed.md如下local wezterm require wezterm wezterm.on(window-focus-changed, function(window, pane) wezterm.log_info( the focus state of , window:window_id(), changed to , window:is_focused() ) end)将这段代码放进你的~/.wezterm.lua或wezterm.lua配置文件的顶部即可生效。它做了三件事通过wezterm.on(window-focus-changed, ...)注册回调调用window:window_id()获取该窗口在 mux 中的唯一 ID源码见 wezterm-gui/src/scripting/guiwin.rsmethods.add_method(window_id, ...)直接返回mux_window_id调用window:is_focused()判断当前是否持有焦点。wezterm.log_info会输出到 wezterm 的日志层可在运行 wezterm 的终端 stdout 中看到也可以通过ShowDebugOverlay动作ShiftCtrlSpace默认绑定在调试面板中查看。log_info自20210814-124438-54e29167起支持多参数、任意类型见 wezterm/log_info.md。四、事件分发机制fire-and-forget 与并发保护4.1 为什么说是 fire-and-forget官方文档明确说明该事件是fire-and-forget发出即忘语义wezterm 只负责在焦点变化时把事件发出去通知你不会等待回调结果也不依赖回调的返回值做任何后续处理。因此你不能在回调里通过返回值来阻止或修改这次焦点变化本身——它只是通知。这一点在emit_window_event中体现得很清楚焦点变化处理完毕后self.emit_window_event(window-focus-changed, None)只是把事件名投递给调度器wezterm-gui/src/termwindow/mod.rs随后事件在独立异步任务中执行 Lua 回调。4.2 事件执行的并发控制wezterm 对同一窗口的窗口级事件做了单飞single-flight 排队queued保护避免同一事件重入造成状态混乱wezterm-gui/src/termwindow/mod.rs每个事件名对应一个EventStateNone/InProgress/InProgressWithQueued事件正在执行时又发生新触发不会立刻并发执行而是标记为有一个待处理项当前回调执行完毕后finish_window_event会检查是否存在排队项若有则立即调度下一个wezterm-gui/src/termwindow/mod.rs。这意味着即使焦点在极短时间内快速切换多次你的回调也不会被并发重入最多保持1 个在执行 1 个排队的状态逻辑上可以安全地操作共享状态。4.3 事件如何到达 Luaschedule_window_event会在主线程上取回 Lua 配置config::with_lua_config_on_main_thread构造GuiWin与MuxPane参数然后调用config::lua::emit_event分发wezterm-gui/src/termwindow/mod.rs。分发逻辑位于 config/src/lua.rswezterm 会把同名事件的所有处理器按注册顺序依次调用如果某个回调返回false则视为阻止默认行为并停止后续回调返回true或非布尔值时继续。不过如前所述对window-focus-changed而言这个返回值不会被 wezterm 采纳。五、实战示例5.1 失焦时切换配色方案聚焦时恢复这个示例结合了window:is_focused()与window:set_config_overrides()/window:get_config_overrides()源码见 wezterm-gui/src/scripting/guiwin.rs实现窗口失焦时自动变暗、聚焦时恢复明亮配色方便在一屏多窗口时快速定位当前终端local wezterm require wezterm wezterm.on(window-focus-changed, function(window, pane) local overrides window:get_config_overrides() or {} if window:is_focused() then -- 获得焦点恢复明亮主题 overrides.color_scheme nordfox else -- 失去焦点切换为暗色主题 overrides.color_scheme nightfox end window:set_config_overrides(overrides) end)要点get_config_overrides()返回当前窗口的配置覆盖表set_config_overrides()将其应用到该窗口不会影响其他窗口和其他配置文件的用户color_scheme取值必须是 wezterm 内置 scheme 或你的自定义 scheme 名称由于每次焦点切换都会触发事件set_config_overrides在值未变化时应尽量避免调用可先比较再赋值这与 window-config-reloaded.md 中关于避免递归触发window-config-reloaded的提醒同理。5.2 失焦时让 pane 暂停输出配合pane:inject_output之外的机制如果你希望在窗口失焦时自动暂停任务可以使用mux域 API 在失焦时对窗口内的 pane 发送控制字符。例如失焦时向活动 pane 发送CtrlSXON/XOFF 流控的暂停符聚焦时发送CtrlQ恢复local wezterm require wezterm wezterm.on(window-focus-changed, function(window, pane) if window:is_focused() then pane:send_text(\x11) -- CtrlQ恢复输出 else pane:send_text(\x13) -- CtrlS暂停输出 end end)pane:send_text()是 pane 对象 提供的方法会向该 pane 的终端输入流注入文本其底层对应pane:inject_output/终端输入通路详见 pane/send_text.md。注意这只适合可以响应流控的交互式程序对忽略 XON/XOFF 的程序无效。5.3 多窗口环境下只对特定窗口生效因为回调第一个参数带有window:window_id()你可以只关心某个特定窗口的焦点变化local wezterm require wezterm local target_window_id nil wezterm.on(window-focus-changed, function(window, pane) local wid window:window_id() -- 首次触发时记住当前窗口之后只响应它 if target_window_id nil then target_window_id wid end if wid target_window_id then wezterm.log_info(focus of main window changed to .. tostring(window:is_focused())) end end)5.4 组合update-status实现状态栏焦点指示wezterm/window/is_focused.md 中展示了另一种思路不通过window-focus-changed而是利用update-status事件它在焦点变化时同样会被触发刷新状态栏。两者可以组合用window-focus-changed做一次性动作如改配色、暂停任务用update-status做持续显示如状态栏图标local wezterm require wezterm wezterm.on(update-status, function(window, pane) local overrides window:get_config_overrides() or {} if window:is_focused() then overrides.color_scheme nordfox else overrides.color_scheme nightfox end window:set_config_overrides(overrides) end) return {}两种方式的差别在于window-focus-changed只在焦点状态翻转的瞬间触发一次update-status会被更频繁地调用如每 1 秒刷新一次适合需要持续反映状态、但不想维护额外触发源的场景。若在window-focus-changed回调里做较重的工作建议避免在回调内再触发会连锁更新状态栏的写操作防止事件风暴。六、与其他窗口事件的关联与区分window-focus-changed属于 窗口事件Window Events 一族与以下事件共享相同的window/pane双参数结构和相同的并发调度机制事件触发时机典型用途window-focus-changed窗口焦点状态变化焦点感知的配色、暂停/恢复任务window-resized窗口尺寸变化、全屏切换动态调整窗口内边距见 window-resized.mdwindow-config-reloaded配置重载自动重载、ReloadConfiguration、set_config_overrides应用配置覆盖、联动重算update-status周期性刷新默认每 1 秒及焦点等状态变化更新左右状态栏需要区分的是window-focus-changed反映的是窗口级输入焦点状态栏tab bar刷新与活动 pane 变更更多依赖update-status若你在window-config-reloaded中调用set_config_overrides会再次触发window-config-reloaded注意避免死循环window-config-reloaded.mdwindow-focus-changed本身没有这种自触发链路回调中可以相对放心地修改配置覆盖。七、调试与注意事项确认版本window-focus-changed需要 wezterm20221119-145034-49b9839f或更新版本。可以在配置中通过wezterm.versionwezterm/version 相关文档打印当前版本核对。查看日志回调中的wezterm.log_info/wezterm.log_warn/wezterm.log_error输出可通过ShowDebugOverlay调试面板查看若 wezterm 由终端启动也会打印到该终端 stdout。避免重复注册wezterm.on同一个事件名可以注册多个处理器它们按注册顺序依次执行见 config/src/lua.rs。不要在每个回调里再次require wezterm或重复wezterm.on这会导致处理器越积越多。异步开销事件回调运行在独立异步任务中不要在回调里做阻塞主线程的重操作如长时间os.execute、网络请求如需与窗口交互优先使用window对象提供的异步方法如window:get_dimensions()。多窗口/多进程window-focus-changed只在 GUI 前端进程wezterm-gui中触发通过wezterm connect连接的远端 mux 会话中焦点事件仍由本地 GUI 进程负责感知与分发。总结window-focus-changed是 wezterm 面向窗口焦点场景提供的精确、低噪的事件接口触发时机由TermWindow::focus_changed在每次焦点翻转时统一驱动wezterm-gui/src/termwindow/mod.rs回调携带window与pane两个对象配合window:is_focused()、window:set_config_overrides()等方法可以完成从日志记录到焦点感知配色任务暂停恢复等丰富联动。理解其 fire-and-forget 语义与单飞/排队并发机制有助于写出健壮、不产生事件风暴的配置代码。【免费下载链接】weztermA GPU-accelerated cross-platform terminal emulator and multiplexer written by wez and implemented in Rust项目地址: https://gitcode.com/GitHub_Trending/we/wezterm创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考