awful.key: Support multiple keys per `awful.key` objects.

This allows to support the arrows, numpad or numrow using a single
object. This will simplify some code, including `rc.lua`.
This commit is contained in:
Emmanuel Lepage Vallee 2019-11-18 02:03:51 -05:00
parent d6568993e2
commit 1f604a73c9
2 changed files with 88 additions and 24 deletions

View File

@ -274,7 +274,9 @@ function widget.new(args)
end end
table.sort( table.sort(
sorted_table, sorted_table,
function(a,b) return (a.mod or '')..a.key<(b.mod or '')..b.key end function(a,b)
local k1, k2 = a.key or a.keys[1][1], b.key or b.keys[1][1]
return (a.mod or '')..k1<(b.mod or '')..k2 end
) )
target[group] = sorted_table target[group] = sorted_table
end end
@ -287,7 +289,9 @@ function widget.new(args)
return return
end end
for _, data in pairs(awful.key.hotkeys) do for _, data in pairs(awful.key.hotkeys) do
self:_add_hotkey(data.key, data, self._cached_awful_keys) for _, key_pair in ipairs(data.keys) do
self:_add_hotkey(key_pair[1], data, self._cached_awful_keys)
end
end end
self:_sort_hotkeys(self._cached_awful_keys) self:_sort_hotkeys(self._cached_awful_keys)
end end

View File

@ -24,6 +24,17 @@ local gobject = require("gears.object")
-- @property key -- @property key
-- @param string -- @param string
--- A group of keys.
--
-- The valid keygroups are:
--
-- * **numrow**: The row above the letters in the US PC-105/PC-104 keyboards
-- and its derivative. This is usually the number 1-9 followed by 0.
-- * **arrows**: The Left/Right/Top/Bottom keys usually located right of the
-- spacebar.
--
-- @property keygroup
--- The table of modifier keys. --- The table of modifier keys.
-- --
-- A modifier, such as `Control` are a predetermined set of keys that can be -- A modifier, such as `Control` are a predetermined set of keys that can be
@ -222,7 +233,7 @@ end
-- @treturn table A table with one or several key objects. -- @treturn table A table with one or several key objects.
-- @constructorfct awful.key -- @constructorfct awful.key
local function new_common(mod, _key, press, release, data) local function new_common(mod, _keys, press, release, data)
if type(release)=='table' then if type(release)=='table' then
data=release data=release
release=nil release=nil
@ -230,38 +241,52 @@ local function new_common(mod, _key, press, release, data)
local ret = {} local ret = {}
local subsets = gmath.subsets(key.ignore_modifiers) local subsets = gmath.subsets(key.ignore_modifiers)
for _, key_pair in ipairs(_keys) do
for _, set in ipairs(subsets) do for _, set in ipairs(subsets) do
local sub_key = capi.key { local sub_key = capi.key {
modifiers = gtable.join(mod, set), modifiers = gtable.join(mod, set),
key = _key key = key_pair[1]
} }
sub_key._private._legacy_convert_to = ret sub_key._private._legacy_convert_to = ret
sub_key:connect_signal("press", function(_, ...) sub_key:connect_signal("press", function(_, ...)
if ret.on_press then if ret.on_press then
if key_pair[2] ~= nil then
ret.on_press(key_pair[2], ...)
else
ret.on_press(...) ret.on_press(...)
end end
end
end) end)
sub_key:connect_signal("release", function(_, ...) sub_key:connect_signal("release", function(_, ...)
if ret.on_release then if ret.on_release then
if key_pair[2] ~= nil then
ret.on_release(key_pair[2], ...)
else
ret.on_release(...) ret.on_release(...)
end end
end
end) end)
ret[#ret + 1] = sub_key ret[#ret + 1] = sub_key
end end
end
-- append custom userdata (like description) to a hotkey -- append custom userdata (like description) to a hotkey
data = data and gtable.clone(data) or {} data = data and gtable.clone(data) or {}
data.mod = mod data.mod = mod
data.key = _key data.keys = _keys
data.on_press = press data.on_press = press
data.on_release = release data.on_release = release
data._is_capi_key = false data._is_capi_key = false
assert((not data.key) or type(data.key) == "string")
table.insert(key.hotkeys, data) table.insert(key.hotkeys, data)
data.execute = function(_) key.execute(mod, _key) end data.execute = function(_)
assert(#_keys == 1, "key:execute() makes no sense for groups")
key.execute(mod, _keys[1])
end
-- Store the private data -- Store the private data
reverse_map[ret] = data reverse_map[ret] = data
@ -273,19 +298,54 @@ local function new_common(mod, _key, press, release, data)
return setmetatable(ret, obj_mt) return setmetatable(ret, obj_mt)
end end
local keygroups = {
numrow = {},
arrows = {
{"Left" , "Left" },
{"Right" , "Right" },
{"Top" , "Top" },
{"Bottom", "Bottom"},
}
}
-- Technically, this isn't very popular, but we have been doing this for 12
-- years and nobody complained too loudly.
for i = 1, 10 do
table.insert(keygroups.numrow, {"#" .. i + 9, i == 10 and 0 or i})
end
-- Allow key objects to provide more than 1 key.
--
-- Some "groups" like arrows, the numpad, F-keys or numrow "belong together"
local function get_keys(args)
if not args.keygroup then return {{args.key}} end
-- Make sure nothing weird happens.
assert(
not args.key,
"Please provide either the `key` or `keygroup` property, not both"
)
assert(keygroups[args.keygroup], "Please provide a valid keygroup")
return keygroups[args.keygroup]
end
function key.new(args, _key, press, release, data) function key.new(args, _key, press, release, data)
-- Assume this is the new constructor. -- Assume this is the new constructor.
if not _key then if not _key then
assert(not (press or release or data), "Calling awful.key() requires a key name") assert(not (press or release or data), "Calling awful.key() requires a key name")
local keys = get_keys(args)
return new_common( return new_common(
args.modifiers, args.modifiers,
args.key, keys,
args.on_press, args.on_press,
args.on_release, args.on_release,
args args
) )
else else
return new_common(args, _key, press, release, data) return new_common(args, {{_key}}, press, release, data)
end end
end end