RobberFokZ
RobberFokZ

Reputation: 43

Unique keyboard layout per client

I change my layouts with a very primitive xkb-switch utility. I need to imitate the 'Share the same input method among all applications - disabled' behaviour of IBus.

My idea is such:

My attempt:

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)

Here is the behaviour: the notification popup is showing the intended language, but for some reason the switched language is wrong, is there some race hazard? https://youtu.be/juarLneLBAo

Upvotes: 1

Views: 35

Answers (2)

Piterden
Piterden

Reputation: 789

Here is the way which I use:

local layout = require("awful.widget.keyboardlayout")
local menubar = require("menubar")

require("awful.client").property.persist("last_layout", "number")

local kbdlayout = {
  globally_preferred = "us",
  menubar_preferred = "us",
}

local function get_idx_by_name(name)
  if not name then
    return
  end
  for i, v in ipairs(layout.get_groups_from_group_names(awesome.xkb_get_group_names())) do
    if v.file == name then
      return i - 1
    end
  end
end

local oneshot_lock = false

local function on_layout_change()
  if oneshot_lock then
    oneshot_lock = false
    return
  end
  local c = client.focus
  if c then
    c.last_layout = awesome.xkb_get_layout_group()
  end
end

local function on_focus_changed(c)
  local idx = c.last_layout or get_idx_by_name(c.preferred_layout or kbdlayout.globally_preferred)
  if idx and awesome.xkb_get_layout_group() ~= idx then
    awesome.xkb_set_layout_group(idx)
  end
end

awesome.connect_signal("xkb::map_changed", on_layout_change)
awesome.connect_signal("xkb::group_changed", on_layout_change)
client.connect_signal("focus", on_focus_changed)

local menubar_show = menubar.show
local menubar_hide = menubar.hide

function menubar.show(...)
  menubar_show(...)
  local idx = get_idx_by_name(kbdlayout.menubar_preferred)
  if idx then
    oneshot_lock = true
    awesome.xkb_set_layout_group(idx)
  end
end

function menubar.hide(...)
  menubar_hide(...)
  local c = client.focus
  if c then
    on_focus_changed(c)
  end
end

return kbdlayout

Upvotes: 0

RobberFokZ
RobberFokZ

Reputation: 43

In the end I changed 2 lines of code and now this works:

client.connect_signal("unfocus", function(c)
    awful.spawn.easy_async_with_shell("xkb-switch", function(stdout)
        if c.valid then -- To avoid 'Invalid Object' error
            c.keyboard_layout = stdout
        end
    end)
end)

client.connect_signal("focus", function(c)
    if c.keyboard_layout == nil then
        c.keyboard_layout = "us(altgr-intl)"
    end
    awful.spawn("xkb-switch -s "..c.keyboard_layout, false) -- `false` to prevent cursor being stuck in 'loading' state
end)

Upvotes: 0

Related Questions