keygrabber: Do not try to guess the modifiers name

There is no an API to query the correct value

Fixes #2515
This commit is contained in:
Emmanuel Lepage Vallee 2019-01-20 23:04:39 -05:00
parent b466db955f
commit 0d80b3f0e9
2 changed files with 74 additions and 27 deletions

View File

@ -9,15 +9,12 @@
-- Grab environment we need -- Grab environment we need
local setmetatable = setmetatable local setmetatable = setmetatable
local ipairs = ipairs local ipairs = ipairs
local capi = { key = key, root = root } local capi = { key = key, root = root, awesome = awesome }
local gmath = require("gears.math") local gmath = require("gears.math")
local gtable = require("gears.table") local gtable = require("gears.table")
local key = { mt = {}, hotkeys = {} } local key = { mt = {}, hotkeys = {} }
--- Modifiers to ignore. --- Modifiers to ignore.
-- By default this is initialized as { "Lock", "Mod2" } -- By default this is initialized as { "Lock", "Mod2" }
-- so the Caps Lock or Num Lock modifier are not taking into account by awesome -- so the Caps Lock or Num Lock modifier are not taking into account by awesome
@ -27,23 +24,53 @@ local key = { mt = {}, hotkeys = {} }
key.ignore_modifiers = { "Lock", "Mod2" } key.ignore_modifiers = { "Lock", "Mod2" }
--- Convert the modifiers into pc105 key names --- Convert the modifiers into pc105 key names
local conversion = { local conversion = nil
mod4 = "Super_L",
control = "Control_L", local function generate_conversion_map()
shift = "Shift_L", if conversion then return conversion end
mod1 = "Alt_L",
} local mods = capi.awesome._modifiers
assert(mods)
conversion = {}
for mod, keysyms in pairs(mods) do
for _, keysym in ipairs(keysyms) do
assert(keysym.keysym)
conversion[mod] = conversion[mod] or keysym.keysym
conversion[keysym.keysym] = mod
end
end
return conversion
end
capi.awesome.connect_signal("xkb::map_changed" , function() conversion = nil end)
--- Execute a key combination. --- Execute a key combination.
-- If an awesome keybinding is assigned to the combination, it should be -- If an awesome keybinding is assigned to the combination, it should be
-- executed. -- executed.
--
-- To limit the chances of accidentally leaving a modifier key locked when
-- calling this function from a keybinding, make sure is attached to the
-- release event and not the press event.
--
-- @see root.fake_input -- @see root.fake_input
-- @tparam table mod A modified table. Valid modifiers are: Any, Mod1, -- @tparam table mod A modified table. Valid modifiers are: Any, Mod1,
-- Mod2, Mod3, Mod4, Mod5, Shift, Lock and Control. -- Mod2, Mod3, Mod4, Mod5, Shift, Lock and Control.
-- @tparam string k The key -- @tparam string k The key
function key.execute(mod, k) function key.execute(mod, k)
local modmap = generate_conversion_map()
local active = capi.awesome._active_modifiers
-- Release all modifiers
for _, m in ipairs(active) do
assert(modmap[m])
root.fake_input("key_release", modmap[m])
end
for _, v in ipairs(mod) do for _, v in ipairs(mod) do
local m = conversion[v:lower()] local m = modmap[v]
if m then if m then
root.fake_input("key_press", m) root.fake_input("key_press", m)
end end
@ -53,11 +80,18 @@ function key.execute(mod, k)
root.fake_input("key_release", k) root.fake_input("key_release", k)
for _, v in ipairs(mod) do for _, v in ipairs(mod) do
local m = conversion[v:lower()] local m = modmap[v]
if m then if m then
root.fake_input("key_release", m) root.fake_input("key_release", m)
end end
end end
-- Restore the previous modifiers all modifiers. Please note that yes,
-- there is a race condition if the user was fast enough to release the
-- key during this operation.
for _, m in ipairs(active) do
root.fake_input("key_press", modmap[m])
end
end end
--- Create a new key to use as binding. --- Create a new key to use as binding.

View File

@ -72,7 +72,7 @@ local gtable = require("gears.table")
local gobject = require("gears.object") local gobject = require("gears.object")
local gtimer = require("gears.timer") local gtimer = require("gears.timer")
local glib = require("lgi").GLib local glib = require("lgi").GLib
local capi = { keygrabber = keygrabber, root = root } local capi = { keygrabber = keygrabber, root = root, awesome = awesome }
local keygrab = {} local keygrab = {}
@ -85,17 +85,7 @@ local keygrabber = {
} }
-- Instead of checking for every modifiers, check the key directly. -- Instead of checking for every modifiers, check the key directly.
--FIXME This is slightly broken but still good enough for `mask_modkeys` local conversion = nil
local conversion = {
Super_L = "Mod4",
Control_L = "Control",
Shift_L = "Shift",
Alt_L = "Mod1",
Super_R = "Mod4",
Control_R = "Control",
Shift_R = "Shift",
Alt_R = "Mod1",
}
--BEGIN one day create a proper API to add and remove keybindings at runtime. --BEGIN one day create a proper API to add and remove keybindings at runtime.
-- Doing it this way is horrible. -- Doing it this way is horrible.
@ -103,6 +93,27 @@ local conversion = {
-- This list of keybindings to add in the next event loop cycle. -- This list of keybindings to add in the next event loop cycle.
local delay_list = {} local delay_list = {}
-- Read the modifiers name and map their keysyms to the modkeys
local function generate_conversion_map()
if conversion then return conversion end
local mods = capi.awesome._modifiers
assert(mods)
conversion = {}
for mod, keysyms in pairs(mods) do
for _, keysym in ipairs(keysyms) do
assert(keysym.keysym)
conversion[keysym.keysym] = mod
end
end
return conversion
end
capi.awesome.connect_signal("xkb::map_changed" , function() conversion = nil end)
local function add_root_keybindings(self, list) local function add_root_keybindings(self, list)
assert( assert(
list, "`add_root_keybindings` needs to be called with a list of keybindings" list, "`add_root_keybindings` needs to be called with a list of keybindings"
@ -168,8 +179,10 @@ local function grabber(mod, key, event)
end end
local function runner(self, modifiers, key, event) local function runner(self, modifiers, key, event)
local converted = generate_conversion_map()[key]
-- Stop the keygrabber with the `stop_key` -- Stop the keygrabber with the `stop_key`
if key == self.stop_key if (key == self.stop_key or (converted and converted == self.stop_key))
and event == self.stop_event and self.stop_key then and event == self.stop_event and self.stop_key then
self:stop(key, modifiers) self:stop(key, modifiers)
return false return false
@ -191,7 +204,7 @@ local function runner(self, modifiers, key, event)
end end
end end
local is_modifier = conversion[key] ~= nil local is_modifier = converted ~= nil
-- Reset the inactivity timer on each events. -- Reset the inactivity timer on each events.
if self._private.timer and self._private.timer.started then if self._private.timer and self._private.timer.started then