]> git.mdlowis.com Git - proto/labwc.git/commitdiff
Add onRelease option to <keybind>
authorSimon Long <simon@raspberrypi.com>
Fri, 26 Apr 2024 10:05:12 +0000 (11:05 +0100)
committerJohan Malm <johanmalm@users.noreply.github.com>
Sun, 9 Jun 2024 20:15:58 +0000 (21:15 +0100)
...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
docs/labwc-config.5.scd
include/config/keybind.h
include/input/keyboard.h
src/config/rcxml.c
src/input/keyboard.c
src/seat.c

index 7d8982dcd59b740b7c9752c2bd488df540c7f30a..4ab1a23ec06e65108c06c81992fc549af7f1cd91 100644 (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).
 
index c61392aa4711888d0541fb1ee7b0614a8be83cf8..fc573316b4b676b2708408bfe972b72b8a878ef1 100644 (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;
 };
 
 /**
index ff4fbe60d35ac09335151c00f1c6e3f73e6355ae..ff2d8500bfc69c793388f7d65ef1e0feec2111f8 100644 (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);
 
index 4f3db549b94ee0e15dd3c3bbdde787eb0bda13eb..0a5d225d5ab7ef725d64d8bc9142497db9845d29 100644 (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")) {
index 1d1467cea4f1a7a0da2cd0741c31a8bde4e1319a..6ba6ab230c0abac33c861cb65a20b7dd46dcee04 100644 (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;
        }
 
index 5b4afe59a12d53fe582b42f01c664948038cb6c1..5eca16a3b1c2f72b7f16ef3fe5ad554cbd632f47 100644 (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: