diff --git a/lib/awful/button.lua b/lib/awful/button.lua index aadf7c7a..c4c05f67 100644 --- a/lib/awful/button.lua +++ b/lib/awful/button.lua @@ -2,6 +2,8 @@ --- Create easily new buttons objects ignoring certain modifiers. -- -- @author Julien Danjou <julien@danjou.info> +-- @author Emmanuel Lepage Vallee <elv1313@gmail.com> +-- @copyright 2018 Emmanuel Lepage Vallee -- @copyright 2009 Julien Danjou -- @inputmodule awful.button --------------------------------------------------------------------------- @@ -15,6 +17,13 @@ local gtable = require("gears.table") local button = { mt = {} } +-- Due to non trivial abuse or `pairs` in older code, the private data cannot +-- be stored in the object itself without creating subtle bugs. This cannot be +-- fixed internally because the default `rc.lua` uses `gears.table.join`, which +-- is affected. +--TODO v6: Drop this +local reverse_map = setmetatable({}, {__mode="k"}) + --- Modifiers to ignore. -- -- By default this is initialized as `{ "Lock", "Mod2" }` @@ -24,19 +33,172 @@ local button = { mt = {} } -- @table ignore_modifiers local ignore_modifiers = { "Lock", "Mod2" } +--- The mouse buttons names. +-- +-- It can be used instead of the button ids. +-- +-- @table names +button.names = { + LEFT = 1,-- The left mouse button. + MIDDLE = 2,-- The scrollwheel button. + RIGHT = 3,-- The context menu button. + SCROLL_UP = 4,-- A scroll up increment. + SCROLL_DOWN = 5,-- A scroll down increment. +} + +--- The table of modifier keys. +-- +-- A modifier, such as `Control` are a predetermined set of keys that can be +-- used to implement keybindings. Note that this list is fix and cannot be +-- extended using random key names, code or characters. +-- +-- Common modifiers are: +-- +-- +-- +-- +-- +-- +-- +-- +-- +-- +-- +--
NameDescription
Mod1Usually called Alt on PCs and Option on Macs
Mod4Also called Super, Windows and Command ⌘
Mod5Also called AltGr or ISO Level 3
ShiftBoth left and right shift keys
ControlAlso called CTRL on some keyboards
+-- +-- Please note that Awesome ignores the status of "Lock" and "Mod2" (Num Lock). +-- +-- @property modifiers + +--- The mouse button identifier. +-- +-- ![Mouse buttons](../images/mouse.svg) +-- +-- @property button +-- @param integer + +--- The button description. +-- +-- @property description +-- @param string + +--- The button name. +-- +-- @property name +-- @param string + +--- The button group. +-- +-- @property group +-- @param string + +--- The callback when this button is pressed. +-- +-- @property on_press +-- @param function + +--- The callback when this button is released. +-- +-- @property on_release +-- @param function + +--- Execute this mousebinding. +-- @function button:trigger + +function button:set_button(b) + for _, v in ipairs(self) do + v.button = b + end +end + +function button:set_modifiers(mod) + local subsets = gmath.subsets(ignore_modifiers) + for k, set in ipairs(subsets) do + self[k].modifiers = gtable.join(mod, set) + end +end + +for _, prop in ipairs { "description", "group", "on_press", "on_release", "name" } do + button["get_"..prop] = function(self) + return reverse_map[self][prop] + end + button["set_"..prop] = function(self, value) + reverse_map[self][prop] = value + end +end + +function button:get_button() + return self[1].button +end + +function button:trigger() + local data = reverse_map[self] + if data.press then + data.press() + end + + if data.release then + data.release() + end +end + +local function index_handler(self, k) + if button["get_"..k] then + return button["get_"..k](self) + end + + if type(button[k]) == "function" then + return button[k] + end + + local data = reverse_map[self] + assert(data) + + return data[k] +end + +local function newindex_handler(self, key, value) + if button["set_"..key] then + return button["set_"..key](self, value) + end + + local data = reverse_map[self] + assert(data) + + data[key] = value +end + +local obj_mt = { + __index = index_handler, + __newindex = newindex_handler +} + --- Create a new button to use as binding. -- --- This function is useful to create several buttons from one, because it will use --- the ignore_modifier variable to create more button with or without the ignored --- modifiers activated. +-- @constructorfct awful.button +-- @tparam table mod A list of modifier keys. Valid modifiers are: +-- `Any`, `Mod1`, Mod2`, `Mod3`, `Mod4`, `Mod5`, `Shift`, `Lock` and `Control`. +-- This argument is (**mandatory**). +-- @tparam number button The mouse button (it is recommended to use the +-- `awful.button.names` constants. +-- @tparam function press Callback for when the button is pressed. +-- @tparam function release Callback for when the button is released. +-- @treturn table An `awful.button` object. + +--- Create a new button to use as binding. -- --- For example if you want to ignore CapsLock in your buttonbinding (which is --- ignored by default by this function), creating button binding with this function --- will return 2 button objects: one with CapsLock on, and the other one with --- CapsLock off. --- --- @treturn table A table with one or several button objects. -function button.new(mod, _button, press, release) +-- @constructorfct2 awful.button +-- @tparam table args +-- @tparam table args.modifiers A list of modifier keys. Valid modifiers are: +-- `Any`, `Mod1`, Mod2`, `Mod3`, `Mod4`, `Mod5`, `Shift`, `Lock` and `Control`. +-- This argument is (**mandatory**). +-- @tparam number args.button The mouse button (it is recommended to use the +-- `awful.button.names` constants. +-- @tparam function args.on_press Callback for when the button is pressed. +-- @tparam function args.on_release Callback for when the button is released. +-- @treturn table An `awful.button` object. + +local function new_common(mod, _button, press, release) local ret = {} local subsets = gmath.subsets(ignore_modifiers) for _, set in ipairs(subsets) do @@ -49,7 +211,25 @@ function button.new(mod, _button, press, release) ret[#ret]:connect_signal("release", function (_, ...) release(...) end) end end - return ret + + reverse_map[ret] = {_is_capi_button = false} + + return setmetatable(ret, obj_mt) +end + +function button.new(args, _button, press, release) + -- Assume this is the new constructor. + if not _button then + assert(not (press or release), "Calling awful.button() requires a button name") + return new_common( + args.modifiers, + args.button, + args.on_press, + args.on_release + ) + else + return new_common(args, _button, press, release) + end end function button.mt:__call(...) diff --git a/spec/awful/keyboardlayout_spec.lua b/spec/awful/keyboardlayout_spec.lua index e2a5c966..4cf8739d 100644 --- a/spec/awful/keyboardlayout_spec.lua +++ b/spec/awful/keyboardlayout_spec.lua @@ -3,6 +3,14 @@ -- @copyright 2015 Uli Schlachter and Kazunobu Kuriyama --------------------------------------------------------------------------- +-- luacheck: globals button +_G.button = setmetatable({ + set_index_miss_handler = function() end, + set_newindex_miss_handler = function() end +}, { + __call = function() return {} end +}) + local kb = require("awful.widget.keyboardlayout") describe("awful.widget.keyboardlayout get_groups_from_group_names", function()