Add dmenu's Meta (Alt) keybindings - wmenu - 🔧 fork of wmenu
 (HTM) git clone git@git.drkhsh.at/wmenu.git
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit c37c3fe38e77398fba65d169c664f569fbab9760
 (DIR) parent 04dfc063795c56a5fdb3096bf8fe0b4123c3c28d
 (HTM) Author: Amin Bandali <bandali@kelar.org>
       Date:   Tue, 27 Feb 2024 00:49:58 -0500
       
       Add dmenu's Meta (Alt) keybindings
       
       This change adds dmenu's mixture of Emacs+vim-style Meta keybindings.
       
       Also 'Page_Up' and 'Page_Down' were deprecated in upstream xkbcommon,
       so replace them with the new 'Prior' and 'Next' names respectively.
       
       Diffstat:
         M docs/wmenu.1.scd                    |      24 ++++++++++++++++++++++++
         M main.c                              |      80 ++++++++++++++++++++++++-------
       
       2 files changed, 86 insertions(+), 18 deletions(-)
       ---
 (DIR) diff --git a/docs/wmenu.1.scd b/docs/wmenu.1.scd
       @@ -148,3 +148,27 @@ arrow keys, page up, page down, home, and end.
        |[ *C-w*
        :[ Delete word left
        
       +|[ *M-b*
       +:[ Move cursor to the start of the current word.
       +
       +|[ *M-f*
       +:[ Move cursor to the end of the current word.
       +
       +|[ *M-g*
       +:[ Home
       +
       +|[ *M-G*
       +:[ End
       +
       +|[ *M-h*
       +:[ Up
       +
       +|[ *M-j*
       +:[ Page down
       +
       +|[ *M-k*
       +:[ Page up
       +
       +|[ *M-l*
       +:[ Down
       +
 (DIR) diff --git a/main.c b/main.c
       @@ -291,6 +291,27 @@ static size_t nextrune(struct menu *menu, int incr) {
                return n;
        }
        
       +static void movewordedge(struct menu *menu, int dir) {
       +        if (dir < 0) {
       +                // Move to beginning of word
       +                while (menu->cursor > 0 && menu->input[nextrune(menu, -1)] == ' ') {
       +                        menu->cursor = nextrune(menu, -1);
       +                }
       +                while (menu->cursor > 0 && menu->input[nextrune(menu, -1)] != ' ') {
       +                        menu->cursor = nextrune(menu, -1);
       +                }
       +        } else {
       +                // Move to end of word
       +                size_t len = strlen(menu->input);
       +                while (menu->cursor < len && menu->input[menu->cursor] == ' ') {
       +                        menu->cursor = nextrune(menu, +1);
       +                }
       +                while (menu->cursor < len && menu->input[menu->cursor] != ' ') {
       +                        menu->cursor = nextrune(menu, +1);
       +                }
       +        }
       +}
       +
        // Calculate text widths.
        static void calc_widths(struct menu *menu) {
                cairo_t *cairo = menu->current->cairo;
       @@ -573,6 +594,9 @@ static void keypress(struct menu *menu, enum wl_keyboard_key_state key_state,
                bool ctrl = xkb_state_mod_name_is_active(menu->xkb_state,
                                XKB_MOD_NAME_CTRL,
                                XKB_STATE_MODS_DEPRESSED | XKB_STATE_MODS_LATCHED);
       +        bool meta = xkb_state_mod_name_is_active(menu->xkb_state,
       +                        XKB_MOD_NAME_ALT,
       +                        XKB_STATE_MODS_DEPRESSED | XKB_STATE_MODS_LATCHED);
                bool shift = xkb_state_mod_name_is_active(menu->xkb_state,
                                XKB_MOD_NAME_SHIFT,
                                XKB_STATE_MODS_DEPRESSED | XKB_STATE_MODS_LATCHED);
       @@ -682,24 +706,12 @@ static void keypress(struct menu *menu, enum wl_keyboard_key_state key_state,
                                return;
                        case XKB_KEY_Left:
                        case XKB_KEY_KP_Left:
       -                        // Move to beginning of word
       -                        while (menu->cursor > 0 && menu->input[nextrune(menu, -1)] == ' ') {
       -                                menu->cursor = nextrune(menu, -1);
       -                        }
       -                        while (menu->cursor > 0 && menu->input[nextrune(menu, -1)] != ' ') {
       -                                menu->cursor = nextrune(menu, -1);
       -                        }
       +                        movewordedge(menu, -1);
                                render_frame(menu);
                                return;
                        case XKB_KEY_Right:
                        case XKB_KEY_KP_Right:
       -                        // Move to end of word
       -                        while (menu->cursor < len && menu->input[menu->cursor] == ' ') {
       -                                menu->cursor = nextrune(menu, +1);
       -                        }
       -                        while (menu->cursor < len && menu->input[menu->cursor] != ' ') {
       -                                menu->cursor = nextrune(menu, +1);
       -                        }
       +                        movewordedge(menu, +1);
                                render_frame(menu);
                                return;
        
       @@ -709,6 +721,38 @@ static void keypress(struct menu *menu, enum wl_keyboard_key_state key_state,
                        default:
                                return;
                        }
       +        } else if (meta) {
       +                // Emacs-style line editing bindings
       +                switch (sym) {
       +                case XKB_KEY_b:
       +                        movewordedge(menu, -1);
       +                        render_frame(menu);
       +                        return;
       +                case XKB_KEY_f:
       +                        movewordedge(menu, +1);
       +                        render_frame(menu);
       +                        return;
       +                case XKB_KEY_g:
       +                        sym = XKB_KEY_Home;
       +                        break;
       +                case XKB_KEY_G:
       +                        sym = XKB_KEY_End;
       +                        break;
       +                case XKB_KEY_h:
       +                        sym = XKB_KEY_Up;
       +                        break;
       +                case XKB_KEY_j:
       +                        sym = XKB_KEY_Next;
       +                        break;
       +                case XKB_KEY_k:
       +                        sym = XKB_KEY_Prior;
       +                        break;
       +                case XKB_KEY_l:
       +                        sym = XKB_KEY_Down;
       +                        break;
       +                default:
       +                        return;
       +                }
                }
        
                char buf[8];
       @@ -752,15 +796,15 @@ static void keypress(struct menu *menu, enum wl_keyboard_key_state key_state,
                                render_frame(menu);
                        }
                        break;
       -        case XKB_KEY_Page_Up:
       -        case XKB_KEY_KP_Page_Up:
       +        case XKB_KEY_Prior:
       +        case XKB_KEY_KP_Prior:
                        if (menu->sel && menu->sel->page->prev) {
                                menu->sel = menu->sel->page->prev->first;
                                render_frame(menu);
                        }
                        break;
       -        case XKB_KEY_Page_Down:
       -        case XKB_KEY_KP_Page_Down:
       +        case XKB_KEY_Next:
       +        case XKB_KEY_KP_Next:
                        if (menu->sel && menu->sel->page->next) {
                                menu->sel = menu->sel->page->next->first;
                                render_frame(menu);