Keep shortcut repeat through unrelated releases

0a5f86f13dc4bd6c574f216a5850b705168fa632
Alexis Sellier committed ago 1 parent 1ebc9753
swm.c +21 -9
252 252
/* Physical or virtual keyboard group. */
253 253
typedef struct {
254 254
    struct wlr_keyboard_group *wlr_group;
255 255
    bool                       is_virtual;
256 256
    int                        nsyms;
257 -
    const xkb_keysym_t        *keysyms; /* Valid only when nsyms is nonzero. */
258 -
    uint32_t                   mods;    /* Valid only when nsyms is nonzero. */
257 +
    uint32_t                   repeat_keycode; /* Valid only when nsyms is nonzero. */
258 +
    const xkb_keysym_t        *keysyms;        /* Valid only when nsyms is nonzero. */
259 +
    uint32_t                   mods;           /* Valid only when nsyms is nonzero. */
259 260
    struct wl_event_source    *key_repeat_source;
260 261
    uint32_t                   handled_keys[(KEY_CNT + 31) / 32];
261 262
    struct wl_listener         modifiers;
262 263
    struct wl_listener         key;
263 264
    struct wl_listener         destroy;
3844 3845
    }
3845 3846
    return true;
3846 3847
}
3847 3848
/* Arm shortcut repeat after a repeatable compositor binding is pressed. */
3848 3849
static void key_repeat_begin(
3849 -
    keyboard_group_t *group, const xkb_keysym_t *syms, int nsyms, uint32_t mods
3850 +
    keyboard_group_t *group, const xkb_keysym_t *syms, int nsyms, uint32_t mods, uint32_t keycode
3850 3851
) {
3851 -
    group->nsyms   = nsyms;
3852 -
    group->keysyms = syms;
3853 -
    group->mods    = mods;
3852 +
    group->nsyms          = nsyms;
3853 +
    group->keysyms        = syms;
3854 +
    group->mods           = mods;
3855 +
    group->repeat_keycode = keycode;
3854 3856
    wl_event_source_timer_update(
3855 3857
        group->key_repeat_source, group->wlr_group->keyboard.repeat_info.delay
3856 3858
    );
3857 3859
}
3858 3860
3861 +
/* Return whether this event supersedes the active shortcut repeat. */
3862 +
static bool key_repeat_should_stop(
3863 +
    keyboard_group_t *group, const struct wlr_keyboard_key_event *event
3864 +
) {
3865 +
    if (!group->nsyms)
3866 +
        return false;
3867 +
    return event->state == WL_KEYBOARD_KEY_STATE_PRESSED || event->keycode == group->repeat_keycode;
3868 +
}
3869 +
3859 3870
/* Handle shortcuts and forward unhandled key events to the focused application. */
3860 3871
void key_press(struct wl_listener *listener, void *data) {
3861 3872
    int i;
3862 3873
3863 3874
    /* This event is raised when a key is pressed or released. */
3879 3890
    if (!locked && event->state == WL_KEYBOARD_KEY_STATE_PRESSED) {
3880 3891
        for (i = 0; i < nsyms; i++)
3881 3892
            handled |= key_binding(mods, syms[i], 0);
3882 3893
    }
3883 3894
    if ((handled & 2) && group->wlr_group->keyboard.repeat_info.delay > 0)
3884 -
        key_repeat_begin(group, syms, nsyms, mods);
3885 -
    else {
3886 -
        group->nsyms = 0;
3895 +
        key_repeat_begin(group, syms, nsyms, mods, event->keycode);
3896 +
    else if (key_repeat_should_stop(group, event)) {
3897 +
        group->nsyms          = 0;
3898 +
        group->repeat_keycode = 0;
3887 3899
        wl_event_source_timer_update(group->key_repeat_source, 0);
3888 3900
    }
3889 3901
    if (!key_event_should_forward(group, event->keycode, event->state, handled))
3890 3902
        return;
3891 3903
test/unit.c +9 -1
1115 1115
    group.wlr_group                           = &keyboard_group;
1116 1116
    keyboard_group.keyboard.repeat_info.rate  = 25;
1117 1117
    keyboard_group.keyboard.repeat_info.delay = 300;
1118 1118
    group.key_repeat_source                   = wl_event_loop_add_timer(loop, key_repeat, &group);
1119 1119
    assert(group.key_repeat_source);
1120 -
    key_repeat_begin(&group, &symbol, 1, MOD);
1120 +
    key_repeat_begin(&group, &symbol, 1, MOD, KEY_J);
1121 1121
    assert(group.nsyms == 1);
1122 1122
    assert(group.keysyms == &symbol);
1123 1123
    assert(group.mods == MOD);
1124 +
    assert(group.repeat_keycode == KEY_J);
1125 +
    assert(!key_repeat_should_stop(
1126 +
        &group,
1127 +
        &(struct wlr_keyboard_key_event){
1128 +
            .keycode = KEY_K,
1129 +
            .state   = WL_KEYBOARD_KEY_STATE_RELEASED,
1130 +
        }
1131 +
    ));
1124 1132
    assert(key_repeat(&group) == 0);
1125 1133
    wl_event_source_remove(group.key_repeat_source);
1126 1134
    wl_event_loop_destroy(loop);
1127 1135
}
1128 1136