2 -- TODO: make xkbion_set understand some simple presets
4 -- (c) Sergey Redin <sergey at redin.info>
6 -- smersh at users.sf.net (author of xkbind) for the original idea
10 -- This script allows you to use independent keyboard layouts for different windows in Anion3.
11 -- It uses a window property to store the XKB groups, so you can restart Ion without losing
12 -- settings for each window.
14 -- Example usage. This is what I have in my cfg_ion.lua:
16 dopath("mod_xkbevents")
19 {name="EN", hint="", action = function() mod_xkbevents.lock_group(0) end},
20 {name="RU", hint="important", action = function() mod_xkbevents.lock_group(1) end},
22 statusname = "xkbion",
25 {name="NUM", command="numlockx on"},
26 {name="---", command="numlockx off"},
29 atomname="XKBION_NUM",
32 {name="----", hint="", action = function() mod_xkbevents.lock_modifiers(2, 0) end},
33 {name="CAPS", hint="critical", action = function() mod_xkbevents.lock_modifiers(2, 2) end},
36 atomname="XKBION_CAPS",
39 -- Edit this to suit your needs.
40 -- Please note, if you want to use Caps_Lock key to change the keyboard groups like I do,
41 -- do not forget to add "grp:caps_toggle" to your XKB settings, just to prevent X from using
42 -- this key also for swiching keyboard registers.
44 -- At least one group definition must be present.
45 -- "name" is only neseccary if you want to use mod_statusbar to indicate current XKB group.
46 -- "hint" is only necessary if you want to highlight your XKB group in statusbar, possible
47 -- values are standard values provided by the mod_statusbar: important, normal, critical
48 -- "command" and "action" are also unneseccary but xkbion.lua is not particulary useful
49 -- without them. :) The same thing for "key".
51 -- The last thing to say about xkbion_set() parameters is that if you call xkbion_set
52 -- more than once (like I do it for XKB groups and NumLock state) you must choose different
53 -- "atomname" values. The default for atomname is XKBION_GROUP.
55 -- The second xkbion_set() call (numlock section) is here mostly for the example. Most users
56 -- will need only one call, for changing XKB group. Please also note that you can define more
57 -- than two groups in call to xkbion_set().
59 -- You can use this line in cfg_statusbar.lua to indicate the current XKB group:
61 -- template="... %xkbion ...",
63 -- If your Ion does not have mod_xkb, you may try the following:
66 -- {name="EN", command="setxkbmap us -option grp:caps_toggle"},
67 -- {name="RU", command="setxkbmap ru winkeys -option grp:caps_toggle"},
69 -- statusname = "xkbion",
74 function xkbion_set (groups
) -- the only global created by xkbion.lua
76 if not groups
or type(groups
) ~= "table" then error("bad args") end
77 if not groups
[1] or type(groups
[1]) ~= "table" then
78 error("default group is undefined")
81 -- window_group_prop(w) - get XKBION_GROUP integer property of window `w' (set it to 1 if it's not yet defined)
82 -- window_group_prop(w, group) - set XKBION_GROUP property of window `w' to integer `group'
83 -- "XKBION_GROUP" is just the default name
84 local window_group_prop
87 local atom
= notioncore
.x_intern_atom( tostring( groups
.atomname
or "XKBION_GROUP" ) )
88 if not atom
or type(atom
) ~= "number" then
89 error("Cannot intern atom " .. atomname
)
91 window_group_prop
= function(w
, gnum
)
92 if not w
or type(w
) ~= "userdata" or not w
.xid
or type(w
.xid
) ~= "function" then return 1 end
93 local xid
= tonumber( w
:xid() )
95 local t
= notioncore
.x_get_window_property( xid
, atom
, XA_INTEGER
, 1, true )
96 if t
and type(t
) == "table" and t
[1] ~= nil then
97 do return tonumber(t
[1]) end
102 gnum
= tonumber(gnum
)
104 -- we're here if the second argument is set or if the window does not have our property yet
105 notioncore
.defer( function()
106 notioncore
.x_change_property( xid
, atom
, XA_INTEGER
, 32, "replace", {gnum
} )
114 local current_gnum
= 1
115 local first_time
= true
116 local statusname
= groups
.statusname
117 if statusname
and type(statusname
) ~= "string" then statusname
= nil end
118 set_group
= function(w
, do_increment
)
121 gnum
= window_group_prop(w
)
125 if do_increment
then gnum
= gnum
+ 1 end
126 local g
= groups
[gnum
]
127 if not g
then gnum
, g
= 1, groups
[1] end
128 if not g
then return end -- error in settings, groups[1] not defined
131 elseif gnum
== current_gnum
then
134 window_group_prop(w
, gnum
) -- it's OK to call it even it `w' is nil
136 notioncore
.exec(g
.command
)
138 if g
.action
then notioncore
.defer(g
.action
) end
140 local group_name
= g
.name
141 local hint_name
= g
.hint
142 if statusname
and group_name
and type(group_name
) == "string" then
143 mod_statusbar
.inform(statusname
, group_name
)
144 mod_statusbar
.inform(statusname
.."_hint", hint_name
)
145 notioncore
.defer(mod_statusbar
.update
)
150 notioncore
.get_hook("region_notify_hook"):add(
151 function(reg
, action
)
152 if (reg
~= nil) and (tostring(reg
.__typename
) == "WClientWin") then
153 if (action
== "activated") or (action
== "pseudoactivated") then
160 local key
= groups
.key
161 if key
and type(key
) == "string" then
162 defbindings("WClientWin", {
163 kpress(key
, function (_
, _sub
) set_group(_
, true) end)
167 set_group() -- initialize