Add onRelease option to <keybind>

...to make keybind actions fire on the release event rather then when the
key is first pressed. This is useful for binding actions to modifier keys
only. The most likely use-case for this is the binding of a Super key to a
menu, for example:

    <keybind key="Super_L" onRelease="yes">
      <action name="Execute" command="rofi -show drun"/>
    </keybind>

If another keybind is issued between the press and release, the on-release
keybind is cancelled.

Co-authored-by: @johanmalm
This commit is contained in:
Simon Long 2024-04-26 11:05:12 +01:00 committed by Johan Malm
parent f6c91c8d13
commit 84c222a84f
6 changed files with 51 additions and 5 deletions

View file

@ -492,6 +492,23 @@ extending outward from the snapped edge.
If set to "no" (or is absent) the keybind will be layout agnostic.
Default is no.
*<keyboard><keybind key="" onRelease="yes|no">*
*onRelease*, when yes, fires the keybind action when the key or key
combination is released, rather than first pressed. This is useful to
bind actions to only modifier keys, where the action should fire when
the modifier is used without another key. Default is no.
The example below will trigger the launch of rofi when the super key is
pressed & released, without interference from other multi-key
combinations that include the super key:
```
<keybind key="Super_L" onRelease="yes">
<action name="Execute" command="rofi -show drun"/>
</keybind>
```
*<keyboard><keybind key=""><action name="">*
Keybind action. See labwc-actions(5).

View file

@ -20,6 +20,7 @@ struct keybind {
int keycodes_layout;
struct wl_list actions; /* struct action.link */
struct wl_list link; /* struct rcxml.keybinds */
bool on_release;
};
/**

View file

@ -9,6 +9,7 @@ struct seat;
struct keyboard;
struct wlr_keyboard;
void keyboard_reset_current_keybind(void);
void keyboard_configure(struct seat *seat, struct wlr_keyboard *kb,
bool is_virtual);

View file

@ -403,6 +403,8 @@ fill_keybind(char *nodename, char *content)
} else if (!current_keybind) {
wlr_log(WLR_ERROR, "expect <keybind key=\"\"> element first. "
"nodename: '%s' content: '%s'", nodename, content);
} else if (!strcasecmp(nodename, "onRelease")) {
set_bool(content, &current_keybind->on_release);
} else if (!strcasecmp(nodename, "layoutDependent")) {
set_bool(content, &current_keybind->use_syms_only);
} else if (!strcmp(nodename, "name.action")) {

View file

@ -38,6 +38,15 @@ struct keyinfo {
static bool should_cancel_cycling_on_next_key_release;
static struct keybind *cur_keybind;
/* Called on --reconfigure to prevent segfault when handling release keybinds */
void
keyboard_reset_current_keybind(void)
{
cur_keybind = NULL;
}
static void
change_vt(struct server *server, unsigned int vt)
{
@ -407,7 +416,19 @@ handle_compositor_keybindings(struct keyboard *keyboard,
keyinfo.is_modifier);
if (event->state == WL_KEYBOARD_KEY_STATE_RELEASED) {
return handle_key_release(server, event->keycode);
if (cur_keybind && cur_keybind->on_release) {
key_state_bound_key_remove(event->keycode);
if (seat->server->session_lock_manager->locked
|| seat->active_client_while_inhibited) {
cur_keybind = NULL;
return true;
}
actions_run(NULL, server, &cur_keybind->actions, 0);
cur_keybind = NULL;
return true;
} else {
return handle_key_release(server, event->keycode);
}
}
/* Catch C-A-F1 to C-A-F12 to change tty */
@ -443,16 +464,19 @@ handle_compositor_keybindings(struct keyboard *keyboard,
/*
* Handle compositor keybinds
*/
struct keybind *keybind =
match_keybinding(server, &keyinfo, keyboard->is_virtual);
if (keybind) {
cur_keybind = match_keybinding(server, &keyinfo, keyboard->is_virtual);
if (cur_keybind) {
/*
* Update key-state before action_run() because the action
* might lead to seat_focus() in which case we pass the
* 'pressed-sent' keys to the new surface.
*/
key_state_store_pressed_key_as_bound(event->keycode);
actions_run(NULL, server, &keybind->actions, 0);
if (!cur_keybind->on_release) {
actions_run(NULL, server, &cur_keybind->actions, 0);
/* This cancels any pending on-release keybinds */
cur_keybind = NULL;
}
return true;
}

View file

@ -592,6 +592,7 @@ seat_reconfigure(struct server *server)
struct input *input;
cursor_reload(seat);
overlay_reconfigure(seat);
keyboard_reset_current_keybind();
wl_list_for_each(input, &seat->inputs, link) {
switch (input->wlr_input_device->type) {
case WLR_INPUT_DEVICE_KEYBOARD: