--[[ -- handle key- and mousebindings in a sane and readable way --]] -- needs local awful = require("awful") local gears = require("gears") local notifications = require("strangesome.notifications") local debug = notifications.debug_enabled local debug_msg = notifications.debug_msg local wrequire = require("strangesome.loader").wrequire -- define standard commands local to speed up things a little bit local next = next local setmetatable = setmetatable local tonumber = tonumber -- strangesome.bindings local bindings = { _NAME = "strangesome.bindings" } local gearstable = awful.util.table or gears.table local internalbindings = {} local separator = "+" local keyregex = "([^"..separator.."]+)" -- define named keys with usable aliases local named_keys = { { "Escape", { "esc", "escape" } }, { "Left", {} }, { "Right", {} }, { "Up", {} }, { "Down", {} }, { "Enter", {} }, { "Return", {} }, { "Print", {} }, { "Space", {} }, { "Backspace", {} }, { "Tab", {} }, { "XF86AudioMute", {} }, { "XF86HomePage", {} }, { "XF86Calculator", {} }, { "XF86AudioMedia", {} }, { "XF86AudioPrev", {} }, { "XF86AudioNext", {} }, { "XF86AudioPlay", {} }, { "XF86AudioStop", {} }, { "XF86MyComputer", {} }, { "XF86AudioRaiseVolume", {} }, { "XF86AudioLowerVolume", {} }, -- more to come... } local mod_keys = { { "Control", { "control", "ctrl" } }, { "Shift", {} }, { "Mod1", { "alt", "mod1" } }, { "Mod4", { "super", "meta", "mod4" } }, } local mouse_keys = { { 1, { "left", "mouseleft", "leftkey", "leftclick" } }, { 2, { "middle", "mousemiddle", "middlekey", "middleclick" } }, { 3, { "right", "mouseright", "rightkey", "rightclick" } }, { 4, { "up", "mouseup", "scrollup" } }, { 5, { "down", "mousedown", "scrolldown" } }, -- more to come... } --[[ -- targetmap may be a string or a table with one or two entries -- -- map = { -- { "Ctrl+Alt+Super+L", "Super+LeftClick", description, function() } -- } --]] function bindings.addkeyandmousemap(targetmap, category, map) if type(targetmap) == "string" then targetkey = targetmap.."_key" targetmouse = targetmap.."_mouse" elseif type(targetmap) == "table" then if #targetmap == 1 then targetkey = targetmap[1].."_key" targetmouse = targetmap[1].."_mouse" elseif #targetmap == 2 then targetkey = targetmap[1] targetmouse = targetmap[2] end else return nil end if type(internalbindings[targetkey]) == "nil" then internalbindings[targetkey] = {} end if type(internalbindings[targetmouse]) == "nil" then internalbindings[targetmouse] = {} end for _, mapentry in ipairs(map) do local keys = mapentry[1] local mkeys = mapentry[2] local desc = mapentry[3] local bindfunc = mapentry[4] if keys then internalbindings[targetkey] = gearstable.join(internalbindings[targetkey], awful.key(getmodkeys(keys), getkey(keys), bindfunc, {description = desc, group = category}) ) end if mkeys then internalbindings[targetmouse] = gearstable.join(internalbindings[targetmouse], awful.button(getmodkeys(mkeys), getmousekey(mkeys), bindfunc) ) end end return { keys = internalbindings[targetkey], mouse = internalbindings[targetmouse] } end --[[ -- map = { -- { "Ctrl+Alt+Super+L", description, function() } -- } --]] function bindings.addkeymap(target, category, map) if debug then debug_msg("Type of internalbindings["..target.."]: "..type(internalbindings[target])) end if type(internalbindings[target]) == "nil" then internalbindings[target] = {} end for _, mapentry in ipairs(map) do local keys = mapentry[1] local desc = mapentry[2] local bindfunc = mapentry[3] internalbindings[target] = gearstable.join(internalbindings[target], awful.key(getmodkeys(keys), getkey(keys), bindfunc, {description = desc, group = category}) ) end if debug then debug_msg("Type of internalbindings["..target.."]: "..type(internalbindings[target])) end return internalbindings[target] end function bindings.addmousemap(target, map) if debug then debug_msg("Type of internalbindings["..target.."]: "..type(internalbindings[target])) end if type(internalbindings[target]) == "nil" then internalbindings[target] = {} end for _, mapentry in ipairs(map) do local keys = mapentry[1] local bindfunc = mapentry[2] internalbindings[target] = gearstable.join(internalbindings[target], awful.button(getmodkeys(keys), getmousekey(keys), bindfunc) ) end if debug then debug_msg("Type of internalbindings["..target.."]: "..type(internalbindings[target])) end return internalbindings[target] end function bindings.export(target) if type(internalbindings[target]) == "nil" then return {} end return internalbindings[target] end function getmodkeys(keys) local modkeys = {} local mkey for key in string.gmatch(keys, keyregex) do mkey = ismodkey(key) if mkey then modkeys[#modkeys+1] = mkey end end return modkeys end function getkey(keys) local sepregex = "["..separator.."]["..separator.."]" local key = "" for str in string.gmatch(keys, keyregex) do -- single char, always lower case if string.len(str) == 1 then key = string.lower(str) -- named key, see table named_keys above elseif isnamedkey(str) then key = isnamedkey(str) -- match separator key, e.g in "Alt+Super++" for Alt, Super and "+" elseif string.match(keys, sepregex) then key = string.lower(separator) end end return key end function getmousekey(keys) local keyregex = "([^"..separator.."]+)" local key = 0 local mkey for str in string.gmatch(keys, keyregex) do -- is number and between 1 and 5 if type(str.tonumber) == "number" then local num = str.tonumber if num > 0 and num < 6 then key = num end -- mousekey, see table mouse_keys above (integers 1 to 5) elseif ismousekey(str) then key = ismousekey(str) end end return key end function isnamedkey(key) -- there are no named keys with length 1 if string.len(key) == 1 then return false end return check_keys_table(key, named_keys) end function ismodkey(key) return check_keys_table(key, mod_keys) end function ismousekey(key) return check_keys_table(key, mouse_keys) end function check_keys_table(key, table) for _, entry in ipairs(table) do local tkey = entry[1] local aliases = entry[2] if next(aliases) == nil then --no aliases given, check against tkey if string.lower(key) == string.lower(tkey) then return tkey end else for _, alias in ipairs(aliases) do if string.lower(key) == string.lower(alias) then return tkey end end end end return false end return setmetatable(bindings, { __index = wrequire })