Module: awful.keygrabber

A keyboard grabbing and transaction object.

This module allows to grab all keyboard inputs until stopped. It is used to gather input data (such as in awful.prompt), implement VI-like keybindings or multi key transactions such as emulating the Alt+Tab behavior.

Note that this module has been redesigned in Awesome 4.3 to be object oriented and stateful. The use of the older global keygrabbing API is discouraged going forward since it had problem with recursive keygrabbers and required a lot of boiler plate code to get anything done.

Using keygrabber as transactions

The transactional keybindings are keybindings that start with a normal keybindings, but only end when a (mod)key is released. In the classic "Alt+Tab" transaction, first pressing "Alt+Tab" will display a popup listing all windows (clients). This popup will only disappear when "Alt" is released.

awful.keygrabber {
    keybindings = {
        awful.key {
            modifiers = {"Mod1"},
            key       = "Tab",
            on_press  = awful.client.focus.history.select_previous
        },
        awful.key {
            modifiers = {"Mod1", "Shift"},
            key       = "Tab",
            on_press  = awful.client.focus.history.select_next
        },
    },
    -- Note that it is using the key name and not the modifier name.
    stop_key           = "Mod1",
    stop_event         = "release",
    start_callback     = awful.client.focus.history.disable_tracking,
    stop_callback      = awful.client.focus.history.enable_tracking,
    export_keybindings = true,
}

In that example, because export_keybindings is set to true, pressing alt+tab or alt+shift+tab will start the transaction even if the keygrabber is not (yet) running.

Using keygrabber for modal keybindings (VI like)

VI-like modal keybindings are triggered by a key, like Escape, followed by either a number, an adjective (or noun) and closed by a verb. For example <Escape>+2+t+f could mean "focus (f) the second (2) tag (t)". <Escape>+2+h+t+f would "focus (f) two (2) tags (t) to the right (h)".

Here is a basic implementation of such a system. Note that the action functions themselves are not implemented to keep the example size and complexity to a minimum. The implementation is just if/elseif of all action and the code can be found in the normal rc.lua keybindings section:

local map, actions = {
    verbs = {
        m = "move" , f = "focus" , d = "delete" , a = "append",
        w = "swap" , p = "print" , n = "new"    ,
    },
    adjectives = { h = "left"  , j = "down" , k = "up"    , l = "right" , },
    nouns      = { c = "client", t = "tag"  , s = "screen", y = "layout", },
}, {}

function actions.client(action, adj) print("IN CLIENT!") end --luacheck: no unused args
function actions.tag   (action, adj) print("IN TAG!"   ) end --luacheck: no unused args
function actions.screen(action, adj) print("IN SCREEN!") end --luacheck: no unused args
function actions.layout(action, adj) print("IN LAYOUT!") end --luacheck: no unused args

local function parse(_, stop_key, _, sequence)
    local parsed, count = { verbs = "", adjectives = "", nouns = "", }, ""
    sequence = sequence..stop_key

    for i=1, #sequence do
        local char = sequence:sub(i,i)
        if char >= "0" and char <= "9" then
            count = count .. char
        else
            for kind in pairs(parsed) do
                parsed[kind] = map[kind][char] or parsed[kind]
            end
        end
    end

    if parsed.nouns == "" then return end
    for _=1, count == "" and 1 or tonumber(count) do
        actions[parsed.nouns](parsed.verbs, parsed.adjectives)
    end
end

awful.keygrabber {
    stop_callback = parse,
    stop_key   = gears.table.keys(map.verbs),
    root_keybindings = {
        awful.key({"Mod4"}, "v")
    },
}

Using signals

When the keygrabber is running, it will emit signals on each event. The format is "keyname".."::".."pressedor_released". For example, to attach a callback to Escape being pressed, do:

mykeygrabber:connect_signal("Escape::pressed", function(self, modifiers, modset)
    print("Escape called!")
end)

The self argument is the keygrabber instance. The modifiers is a list of all the currently pressed modifiers and the modset is the same table, but with the modifiers as keys instead of value. It allow to save time by checking if modset.Mod4 then ... end instead of looping into the modifiers table or using gears.table.

Info:

Constructors

awful.keygrabber {[args]} A wrapper around the keygrabber to make it easier to add keybindings.

Static module functions

awful.keygrabber.connect_signal (name, callback) Connect to a signal for all keygrabbers at once.
awful.keygrabber.disconnect_signal (name, callback) Disconnect to a signal for all keygrabbers at once.
awful.keygrabber.emit_signal (name, ...) Emit a signal on the keygrabber module itself.

Object properties

timeout number or nil The keygrabber timeout.
stop_key string or table or nil The key on which the keygrabber listen to terminate itself.
stop_event string The event on which the keygrabbing will be terminated.
mask_event_callback boolean Whether or not to execute the key press/release callbacks when keybindings are called.
mask_modkeys boolean Do not call the callbacks on modifier keys (like Control or Mod4) events.
export_keybindings boolean Export all keygrabber keybindings as root (global) keybindings.
root_keybindings table The root (global) keybinding to start this keygrabber.
keybindings table The keybindings associated with this keygrabber.
allowed_keys table or nil If any key is pressed that is not in this list, the keygrabber is stopped.
sequence string The sequence of keys recorded since the start of the keygrabber.

Object methods

:start () -> boolean Start the keygrabber.
:stop (stop_key, stop_mods) Stop the keygrabber.
:add_keybinding (key) Add a keybinding to this keygrabber.
:remove_keybinding () -> boolean Remove a keybinding from the keygrabber.
:emit_signal (name, ...) Emit a signal. Inherited from gears.object
:connect_signal (name, func) Connect to a signal. Inherited from gears.object
:weak_connect_signal (name, func) Connect to a signal weakly. Inherited from gears.object

Signals

property::current_instance The global signal used to track the current_instance.
started When the keygrabber starts.
stopped When the keygrabber stops.
keybinding::triggered When an awful.key is pressed.

Deprecated functions

awful.keygrabber.stop (g) Stop grabbing the keyboard for the provided callback. Deprecated
awful.keygrabber.run (g) A lower level API to interact with the keygrabber directly. Deprecated

Callback functions prototype

start_callback (keygrabber) A function called when a keygrabber starts.
stop_callback (self, stop_key, stop_mods, sequence) The callback when the keygrabbing stops.
timeout_callback () The function called when the keygrabber stops because of a timeout.
keypressed_callback (self, mod, key, event) The callback function to call with mod table, key and command as arguments when a key was pressed.
keyreleased_callback (self, mod, key, event) The callback function to call with mod table, key and command as arguments when a key was released.

Fields

awful.keygrabber.current_instance keygrabber The current (running) instance of this keygrabber.
awful.keygrabber.is_running boolean If a keygrabber is currently running.


Constructors

🔗 awful.keygrabber {[args]}
A wrapper around the keygrabber to make it easier to add keybindings.

This is similar to the awful.prompt, but without an actual widget. It can be used to implement custom transactions such as alt+tab or keyboard menu navigation.

Note that the object returned can be used as a client or global keybinding callback without modification. Make sure to set stop_key and stop_event to proper values to avoid permanently locking the keyboard.

Parameters:

Note: This constructors uses named parameters calling convention. It means you call it with {} and omit the parantheses. For example, calling this will all default argument would be awful.keygrabber{}. This is a Lua shortcut syntax equivalent to awful.keygrabber({}). args is only a placeholder name for the "lone table argument" used in named parameters calls.
Name Type(s) Description Default value
args table Not applicable
stop_event Optional string Release event ("press" or "release") "press"
stop_key Optional string or table The key that has to be kept pressed. nil
keybindings table All keybindings. Not applicable
timeout Optional number The maximum inactivity delay. -1
mask_event_callback Optional boolean Do not call keypressed_callback or keyreleased_callback when a hook is called. true
start_callback Optional function Undefined
stop_callback Optional function Undefined
timeout_callback Optional function Undefined
keypressed_callback Optional function Undefined
keyreleased_callback Optional function Undefined
allowed_keys Optional table or nil A table with all keys that won't stop the keygrabber. nil
root_keybindings Optional table The root (global) keybindings. Undefined
export_keybindings Optional boolean Create root (global) keybindings. false
autostart Optional boolean Start the grabbing immediately false
mask_modkeys Optional boolean Do not call the callbacks on modifier keys (like "Control" or "Mod4") events. false

Static module functions

🔗 awful.keygrabber.connect_signal (name, callback)
Connect to a signal for all keygrabbers at once.

Parameters:

Name Type(s) Description
name string The signal name.
callback function The callback.
🔗 awful.keygrabber.disconnect_signal (name, callback)
Disconnect to a signal for all keygrabbers at once.

Parameters:

Name Type(s) Description
name string The signal name.
callback function The callback.
🔗 awful.keygrabber.emit_signal (name, ...)
Emit a signal on the keygrabber module itself.

Warning, usually don't use this directly, use my_keygrabber:emit_signal(name, ...). This function works on the whole keygrabber module, not one of its instance.

Parameters:

Name Type(s) Description
name string The signal name.
... Other arguments for the callbacks.

Object properties

🔗 timeout number or nil
The keygrabber timeout.

Constraints:

Default value : nil
Type description:
nil : No timeout.
Unit : second
Negative allowed : false

See also:

gears.timer Class to execute code at specific intervals. module
timeout_callback The function called when the keygrabber stops because of a timeout. callback functions prototype

Usage:

    awful.keygrabber {
        autostart      = true,
        timeout        = 1, -- second
        timeout_callback  = function()
            print("The keygrabber has expired")
        end,
    }
🔗 stop_key string or table or nil
The key on which the keygrabber listen to terminate itself.

When this is set, the running keygrabber will quit when [one of] the stop key event occurs.

By default, the event is press. It is common for use case like the awful.prompt where return (enter) will terminate the keygrabbing. Using release as an event is more appropriate when the keygrabber is tied to a modifier key. For example, an Alt+Tab implementation stops when mod1 (Alt) is released.

It can also be a table containing many keys (as values).

Please note that modkeys are not accepted as stop_keys. You have to use their corresponding key names such as Control_L.

Constraints:

Default value : nil
Table content : A list of key names, such as "Control" or "a".
Unit : nil No stop key.

See also:

stop_event The event on which the keygrabbing will be terminated. object properties
🔗 stop_event string
The event on which the keygrabbing will be terminated.

Constraints:

Default value : "press"
Valid values:
"press" : When the keyboard key is first pressed.
"release" : When the keyboard key is released.

See also:

stop_key The key on which the keygrabber listen to terminate itself. object properties
🔗 mask_event_callback boolean
Whether or not to execute the key press/release callbacks when keybindings are called.

When this property is set to false, the keyreleased_callback and keypressed_callback callbacks will be executed even when the event was consumed by a keybinding.

By default, keybindings block those callbacks from being executed.

Constraints:

Default value : true
Valid values : true or false.

See also:

keybindings The keybindings associated with this keygrabber. object properties
keyreleased_callback The callback function to call with mod table, key and command as arguments when a key was released. callback functions prototype
keypressed_callback The callback function to call with mod table, key and command as arguments when a key was pressed. callback functions prototype
🔗 mask_modkeys boolean
Do not call the callbacks on modifier keys (like Control or Mod4) events.

Constraints:

Default value : false
Valid values : true or false.

See also:

mask_event_callback Whether or not to execute the key press/release callbacks when keybindings are called. object properties
🔗 export_keybindings boolean
Export all keygrabber keybindings as root (global) keybindings.

When this is enabled, calling all of the keygrabber object keybindings will will create root awful.key and will automatically starts the grabbing.

Use this with caution. If many keygrabber or "real" root keybindings are set on the same key combination, they are all executed and there is almost no safe way to undo that. Make sure the keygrabber that use this option have a single instance.

Constraints:

Default value : false
Valid values : true or false.
🔗 root_keybindings table

The root (global) keybinding to start this keygrabber.

Instead of adding an entry to root.keys or rc.lua globalkeys section, this property can be used to take care of everything. This way, it becomes easier to package modules using keygrabbers.

Usage example output:

Is now active!  nil
A key was pressed:  a   with    0   modifier!
A key was pressed:  i   with    1   modifier!
Called again!

Constraints:

Default value : {}
Table content : A list of awful.key objects.

See also:

export_keybindings Export all keygrabber keybindings as root (global) keybindings. object properties
keybindings The keybindings associated with this keygrabber. object properties

Usage:

    awful.keygrabber {
        mask_modkeys = true,
        root_keybindings = {
            awful.key {
                modifiers = {"Mod4"},
                key       = "i",
                on_press  = function(self)
                    print("Is now active!", self)
                end
            },
        },
        keybindings = {
            awful.key {
                modifiers = {"Mod4", "Shift"},
                key       = "i",
                on_press  = function(self)
                    print("Called again!")
                    self:stop()
                end
            },
        },
        keypressed_callback  = function(_, modifiers, key)
            print("A key was pressed:", key, "with", #modifiers, "modifier!")
        end,
    }
    
    -- The following will **NOT** trigger the keygrabbing because it isn't exported
    -- to the root (global) keys. Adding export_keybindings would solve that
    root._execute_keybinding({"Mod4", "Shift"}, "i")
    assert(#keybinding_works == 0)
    
    -- But this will start the keygrabber because it is part of the root_keybindings
    root._execute_keybinding({"Mod4"}, "i")
    
    -- Note that that keygrabber is running, all callbacks should work:
    root.fake_input("key_press"  , "a")
    root.fake_input("key_release"  , "a")
    
    -- Calling the root keybindings now wont work because they are not part of
    -- the keygrabber internal (own) keybindings, so keypressed_callback will
    -- be called.
    root._execute_keybinding({"Mod4"}, "i")
    
    -- Now the keygrabber own keybindings will work
    root._execute_keybinding({"Mod4", "Shift"}, "i")
🔗 keybindings table
The keybindings associated with this keygrabber.

This property contains a table of awful.key objects.

Constraints:

Default value : {}
Table content : A list of awful.key objects.

See also:

export_keybindings Export all keygrabber keybindings as root (global) keybindings. object properties
root_keybindings The root (global) keybinding to start this keygrabber. object properties
awful.key Create easily new key objects ignoring certain modifiers. module
🔗 allowed_keys table or nil
If any key is pressed that is not in this list, the keygrabber is stopped.

When defined, this property allows to define an implicit way to release the keygrabber. It helps save some boilerplate code in the handler callbacks.

It is useful when a transaction only handle a limited number of keys. If a key unhandled by the transaction is triggered, the transaction is canceled.

Constraints:

Default value : nil
Type description:
nil : All keys are allowed.
table : Only some keys are allowed.
Table content : A list of key names, such as "Control" or "a".

Usage:

    awful.keygrabber {
        autostart      = true,
        allowed_keys   = {"a", "w", "e", "s", "o", "m", "e"},
    }
🔗 sequence string
The sequence of keys recorded since the start of the keygrabber.

In this example, the stop_callback is used to retrieve the final key sequence.

Please note that backspace will remove elements from the sequence and named keys and modifiers are ignored.

Constraints:

Default value : ""

Usage:

    awful.keygrabber {
        autostart      = true,
        stop_key       = "Return",
        stop_callback  = function(_, _, _, sequence)
            naughty.notification {message="The keys were:"..sequence}
        end,
    }

Object methods

🔗 :start () -> boolean · 2 signals
Start the keygrabber.

Note that only a single keygrabber can be started at any one time. If another keygrabber (or this one) is currently running. This method returns false.

Returns:

    boolean If the keygrabber was successfully started.

Click to display more

Emit signals:

🔗 :stop (stop_key, stop_mods) · 2 signals
Stop the keygrabber.

Also stops any timeout.

Parameters:

Name Type(s) Description
stop_key string or nil Override the key passed to stop_callback DEPRECATED
stop_mods tale or nil Override the modifiers passed to stop_callback DEPRECATED

Click to display more

Emit signals:

🔗 :add_keybinding (key)
Add a keybinding to this keygrabber.

Those keybindings will automatically start the keygrabbing when hit.

Please note that this method previously accepted a mods, keycode, callback, description signature. This is deprecated. Store those values in an awful.key prior to passing it to this function. The previous method signature made it impossible to alter the description and/or enable/disable the keybinding.

Parameters:

Name Type(s) Description
key awful.key The key.

See also:

remove_keybinding Remove a keybinding from the keygrabber. object methods
🔗 :remove_keybinding () -> boolean
Remove a keybinding from the keygrabber.

Returns:

    boolean true if removed, false if not found.

See also:

add_keybinding Add a keybinding to this keygrabber. object methods
🔗 :emit_signal (name, ...) · Inherited from gears.object
Emit a signal.

Parameters:

Name Type(s) Description
name string The name of the signal.
... Extra arguments for the callback functions. Each connected function receives the object as first argument and then any extra arguments that are given to emit_signal().
🔗 :connect_signal (name, func) · Inherited from gears.object
Connect to a signal.

Parameters:

Name Type(s) Description
name string The name of the signal.
func function The callback to call when the signal is emitted.
🔗 :weak_connect_signal (name, func) · Inherited from gears.object
Connect to a signal weakly.

This allows the callback function to be garbage collected and automatically disconnects the signal when that happens.

Warning: Only use this function if you really, really, really know what you are doing.

Parameters:

Name Type(s) Description
name string The name of the signal.
func function The callback to call when the signal is emitted.

Signals

🔗 property::current_instance
The global signal used to track the current_instance.
🔗 started
When the keygrabber starts.
🔗 stopped
When the keygrabber stops.
🔗 keybinding::triggered
When an awful.key is pressed.

Arguments:

Name Type(s) Description
self awful.keybinding
key awful.key The keybinding.
event string Either "press" or "release".

Deprecated functions

🔗 awful.keygrabber.stop (g)
Stop grabbing the keyboard for the provided callback.

When no callback is given, the last grabber gets removed (last one added to the stack).

Parameters:

Name Type(s) Description
g Optional The key grabber that must be removed.
🔗 awful.keygrabber.run (g)
A lower level API to interact with the keygrabber directly.

Grab keyboard input and read pressed keys, calling the least callback function from the stack at each keypress, until the stack is empty.

Calling run with the same callback again will bring the callback to the top of the stack.

The callback function receives three arguments:

  • a table containing modifiers keys
  • a string with the pressed key
  • a string with either "press" or "release" to indicate the event type.

Here is the content of the modifier table:

Modifier name Key name Alternate key name
Mod4 Super_L Super_R
Control Control_L Control_R
Shift Shift_L Shift_R
Mod1 Alt_L Alt_R

A callback can return false to pass the events to the next keygrabber in the stack.

Parameters:

Name Type(s) Description
g The key grabber callback that will get the key events until it will be deleted or a new grabber is added.

Returns:

    the given callback g.

Usage:

    -- The following function can be bound to a key, and be used to resize a
    -- client using the keyboard.
    
    function resize(c)
      local grabber
      grabber = awful.keygrabber.run(function(mod, key, event)
        if event == "release" then return end
    
        if     key == 'Up'    then c:relative_move(0, 0, 0, 5)
        elseif key == 'Down'  then c:relative_move(0, 0, 0, -5)
        elseif key == 'Right' then c:relative_move(0, 0, 5, 0)
        elseif key == 'Left'  then c:relative_move(0, 0, -5, 0)
        else   awful.keygrabber.stop(grabber)
        end
      end)
    end

Callback functions prototype

🔗 start_callback (keygrabber)
A function called when a keygrabber starts.

Parameters:

Name Type(s) Description
keygrabber keygrabber The keygrabber.
🔗 stop_callback (self, stop_key, stop_mods, sequence)
The callback when the keygrabbing stops.

Parameters:

Name Type(s) Description
self table The current transaction object.
stop_key string The key(s) that stop the keygrabbing (if any)
stop_mods table The modifiers key (if any)
sequence string The recorded key sequence.

See also:

sequence The sequence of keys recorded since the start of the keygrabber. object properties
stop Stop grabbing the keyboard for the provided callback. deprecated functions

Usage:

    local function my_done_cb(self, stop_key, stop_mods, sequence)
       -- do something
    end
🔗 timeout_callback ()
The function called when the keygrabber stops because of a timeout.

Note that the stop_callback is also called when the keygrabbers timeout.

See also:

timeout The keygrabber timeout. object properties
🔗 keypressed_callback (self, mod, key, event)
The callback function to call with mod table, key and command as arguments when a key was pressed.

Parameters:

Name Type(s) Description
self table The current transaction object.
mod table The current modifiers (like "Control" or "Shift").
key string The key name.
event string The event ("press" or "release").

Usage:

    local function my_keypressed_cb(self, mod, key, command)
       -- do something
    end
🔗 keyreleased_callback (self, mod, key, event)
The callback function to call with mod table, key and command as arguments when a key was released.

Parameters:

Name Type(s) Description
self table The current transaction object.
mod table The current modifiers (like "Control" or "Shift").
key string The key name.
event string The event ("press" or "release")

Usage:

    local function my_keyreleased_cb(self, mod, key, command)
       -- do something
    end

Fields

🔗 awful.keygrabber.current_instance keygrabber · 1 signal
The current (running) instance of this keygrabber.

The keygrabber instance is created when the keygrabber starts. It is an object mirroring this keygrabber object, but where extra properties can be added. It is useful to keep some contextual data part of the current transaction without polluting the original object of having extra boilerplate code.

Click to display more

Emit signals:

🔗 awful.keygrabber.is_running boolean
If a keygrabber is currently running.
generated by LDoc 1.5.0