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

基于xkb-switch实现客户端独立键盘布局切换异常,疑存竞态问题

问题

我想用xkb-switch工具切换键盘布局,实现IBus中「所有应用共享同一输入法 - 禁用」的效果,即每个窗口保留独立的键盘布局,切换窗口时自动切回对应窗口的布局。

我的实现思路:

  • 窗口失去焦点时,保存当前xkb-switch输出的布局(例如us(altgr-intl)、am、ru)
  • 窗口获得焦点时,调用xkb-switch --switch <layout>命令切回该窗口保存的布局

我编写的Lua尝试代码如下:

client.connect_signal("unfocus", function(c)
    awful.spawn.easy_async_with_shell("xkb-switch", function(stdout)
        if c.valid then
            c.keyboard_layout = stdout
        end
    end)
end)

client.connect_signal("focus", function(c)
    c = awful.screen.focused({client = true})
    if c.keyboard_layout == nil then
        c.keyboard_layout = "us(altgr-intl)"
    end
    awful.spawn.with_shell("xkb-switch -s "..c.keyboard_layout)
end)

当前问题:通知弹窗显示的语言符合预期,但实际切换的语言错误,怀疑存在竞态风险?

解决方案

确实存在竞态风险,同时代码还有几处逻辑问题:

  • 竞态问题:unfocus信号中使用的easy_async_with_shell是异步调用,当窗口快速切换时,前一个窗口的异步回调可能在新窗口获得焦点后才执行,导致新窗口的布局被旧窗口的回调覆盖。
  • 焦点客户端逻辑错误:focus信号的参数c已经是当前获得焦点的客户端,重新赋值为awful.screen.focused({client = true})会在多屏幕等场景下获取到错误的客户端。
  • 输出格式问题:xkb-switch的输出自带换行符,直接赋值给c.keyboard_layout会导致切换命令中包含无效的换行字符,引发执行错误。

修改后的代码:

-- 窗口失去焦点时同步保存布局,避免异步竞态
client.connect_signal("unfocus", function(c)
    if c.valid then
        -- 同步执行xkb-switch,读取输出并清理末尾空白(含换行)
        local handle = io.popen("xkb-switch")
        local layout = handle:read("*a"):gsub("%s+$", "")
        handle:close()
        c.keyboard_layout = layout
    end
end)

client.connect_signal("focus", function(c)
    -- 直接使用参数传入的当前焦点客户端
    if not c.keyboard_layout then
        c.keyboard_layout = "us(altgr-intl)"
    end
    -- 清理布局字符串并包裹单引号,避免特殊字符干扰
    local clean_layout = c.keyboard_layout:gsub("%s+$", "")
    awful.spawn.with_shell("xkb-switch -s '" .. clean_layout .. "'")
end)

关键改动说明:

  • 将unfocus中的异步调用替换为同步的io.popen,确保布局保存操作在窗口失去焦点时立即完成,彻底解决竞态问题。
  • 移除focus信号中重新获取客户端的代码,直接使用参数传递的当前焦点窗口,保证操作对象正确。
  • 对xkb-switch的输出进行空白字符清理,并在切换命令中用单引号包裹布局字符串,避免因特殊字符导致命令执行失败。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 01:57:10