diff --git a/docs/labwc-config.5.scd b/docs/labwc-config.5.scd index 7d8982dc..4ab1a23e 100644 --- a/docs/labwc-config.5.scd +++ b/docs/labwc-config.5.scd @@ -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. +** + *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 action. See labwc-actions(5). diff --git a/include/config/keybind.h b/include/config/keybind.h index c61392aa..fc573316 100644 --- a/include/config/keybind.h +++ b/include/config/keybind.h @@ -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; }; /** diff --git a/include/input/keyboard.h b/include/input/keyboard.h index ff4fbe60..ff2d8500 100644 --- a/include/input/keyboard.h +++ b/include/input/keyboard.h @@ -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); diff --git a/src/config/rcxml.c b/src/config/rcxml.c index 4f3db549..0a5d225d 100644 --- a/src/config/rcxml.c +++ b/src/config/rcxml.c @@ -403,6 +403,8 @@ fill_keybind(char *nodename, char *content) } else if (!current_keybind) { wlr_log(WLR_ERROR, "expect element first. " "nodename: '%s' content: '%s'", nodename, content); + } else if (!strcasecmp(nodename, "onRelease")) { + set_bool(content, ¤t_keybind->on_release); } else if (!strcasecmp(nodename, "layoutDependent")) { set_bool(content, ¤t_keybind->use_syms_only); } else if (!strcmp(nodename, "name.action")) { diff --git a/src/input/keyboard.c b/src/input/keyboard.c index 1d1467ce..6ba6ab23 100644 --- a/src/input/keyboard.c +++ b/src/input/keyboard.c @@ -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; } diff --git a/src/seat.c b/src/seat.c index 5b4afe59..5eca16a3 100644 --- a/src/seat.c +++ b/src/seat.c @@ -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: