diff --git a/include/sway/input/keyboard.h b/include/sway/input/keyboard.h index 8ec3eb356..e99a54b17 100644 --- a/include/sway/input/keyboard.h +++ b/include/sway/input/keyboard.h @@ -3,7 +3,26 @@ #include "sway/input/seat.h" -#define SWAY_KEYBOARD_PRESSED_KEYSYMS_CAP 32 +#define SWAY_KEYBOARD_PRESSED_KEYS_CAP 32 + +struct sway_shortcut_state { + /** + * A list of pressed key ids (either keysyms or keycodes), + * including duplicates when different keycodes produce the same key id. + * + * Each key id is associated with the keycode (in `pressed_keycodes`) + * whose press generated it, so that the key id can be removed on + * keycode release without recalculating the transient link between + * keycode and key id at the time of the key press. + */ + uint32_t pressed_keys[SWAY_KEYBOARD_PRESSED_KEYS_CAP]; + /** + * The list of keycodes associated to currently pressed key ids, + * including duplicates when a keycode generates multiple key ids. + */ + uint32_t pressed_keycodes[SWAY_KEYBOARD_PRESSED_KEYS_CAP]; + int last_key_index; +}; struct sway_keyboard { struct sway_seat_device *seat_device; @@ -13,11 +32,11 @@ struct sway_keyboard { struct wl_listener keyboard_key; struct wl_listener keyboard_modifiers; - xkb_keysym_t pressed_keysyms_translated[SWAY_KEYBOARD_PRESSED_KEYSYMS_CAP]; - uint32_t modifiers_translated; - - xkb_keysym_t pressed_keysyms_raw[SWAY_KEYBOARD_PRESSED_KEYSYMS_CAP]; - uint32_t modifiers_raw; + struct sway_shortcut_state state_keysyms_translated; + struct sway_shortcut_state state_keysyms_raw; + struct sway_shortcut_state state_keycodes; + struct sway_binding *held_binding; + uint32_t last_modifiers; }; struct sway_keyboard *sway_keyboard_create(struct sway_seat *seat, diff --git a/sway/commands/bind.c b/sway/commands/bind.c index c6b3368ad..d0e3e22f3 100644 --- a/sway/commands/bind.c +++ b/sway/commands/bind.c @@ -69,22 +69,25 @@ bool binding_key_compare(struct sway_binding *binding_a, return true; } -struct cmd_results *cmd_bindsym(int argc, char **argv) { +static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv, + bool bindcode) { + const char *bindtype = bindcode ? "bindcode" : "bindsym"; + struct cmd_results *error = NULL; - if ((error = checkarg(argc, "bindsym", EXPECTED_MORE_THAN, 1))) { + if ((error = checkarg(argc, bindtype, EXPECTED_MORE_THAN, 1))) { return error; } struct sway_binding *binding = calloc(1, sizeof(struct sway_binding)); if (!binding) { - return cmd_results_new(CMD_FAILURE, "bindsym", + return cmd_results_new(CMD_FAILURE, bindtype, "Unable to allocate binding"); } binding->keys = create_list(); binding->modifiers = 0; binding->release = false; binding->locked = false; - binding->bindcode = false; + binding->bindcode = bindcode; // Handle --release and --locked while (argc > 0) { @@ -100,9 +103,9 @@ struct cmd_results *cmd_bindsym(int argc, char **argv) { } if (argc < 2) { free_sway_binding(binding); - return cmd_results_new(CMD_FAILURE, "bindsym", - "Invalid bindsym command " - "(expected at least 2 non-option arguments, got %d)", argc); + return cmd_results_new(CMD_FAILURE, bindtype, + "Invalid %s command " + "(expected at least 2 non-option arguments, got %d)", bindtype, argc); } binding->command = join_args(argv + 1, argc - 1); @@ -115,36 +118,63 @@ struct cmd_results *cmd_bindsym(int argc, char **argv) { binding->modifiers |= mod; continue; } - // Check for xkb key - xkb_keysym_t sym = xkb_keysym_from_name(split->items[i], - XKB_KEYSYM_CASE_INSENSITIVE); - // Check for mouse binding - if (strncasecmp(split->items[i], "button", strlen("button")) == 0 && - strlen(split->items[i]) == strlen("button0")) { - sym = ((char *)split->items[i])[strlen("button")] - '1' + BTN_LEFT; + xkb_keycode_t keycode; + xkb_keysym_t keysym; + if (bindcode) { + // parse keycode + keycode = (int)strtol(split->items[i], NULL, 10); + if (!xkb_keycode_is_legal_ext(keycode)) { + error = + cmd_results_new(CMD_INVALID, "bindcode", + "Invalid keycode '%s'", (char *)split->items[i]); + free_sway_binding(binding); + list_free(split); + return error; + } + } else { + // Check for xkb key + keysym = xkb_keysym_from_name(split->items[i], + XKB_KEYSYM_CASE_INSENSITIVE); + + // Check for mouse binding + if (strncasecmp(split->items[i], "button", strlen("button")) == 0 && + strlen(split->items[i]) == strlen("button0")) { + keysym = ((char *)split->items[i])[strlen("button")] - '1' + BTN_LEFT; + } + if (!keysym) { + struct cmd_results *ret = cmd_results_new(CMD_INVALID, "bindsym", + "Unknown key '%s'", (char *)split->items[i]); + free_sway_binding(binding); + free_flat_list(split); + return ret; + } } - if (!sym) { - struct cmd_results *ret = cmd_results_new(CMD_INVALID, "bindsym", - "Unknown key '%s'", (char *)split->items[i]); - free_sway_binding(binding); - free_flat_list(split); - return ret; - } - xkb_keysym_t *key = calloc(1, sizeof(xkb_keysym_t)); + uint32_t *key = calloc(1, sizeof(uint32_t)); if (!key) { free_sway_binding(binding); free_flat_list(split); - return cmd_results_new(CMD_FAILURE, "bindsym", + return cmd_results_new(CMD_FAILURE, bindtype, "Unable to allocate binding"); } - *key = sym; + + if (bindcode) { + *key = (uint32_t)keycode; + } else { + *key = (uint32_t)keysym; + } + list_add(binding->keys, key); } free_flat_list(split); binding->order = binding_order++; - list_t *mode_bindings = config->current_mode->keysym_bindings; + list_t *mode_bindings; + if (bindcode) { + mode_bindings = config->current_mode->keycode_bindings; + } else { + mode_bindings = config->current_mode->keysym_bindings; + } // overwrite the binding if it already exists bool overwritten = false; @@ -163,95 +193,16 @@ struct cmd_results *cmd_bindsym(int argc, char **argv) { list_add(mode_bindings, binding); } - wlr_log(L_DEBUG, "bindsym - Bound %s to command %s", - argv[0], binding->command); + wlr_log(L_DEBUG, "%s - Bound %s to command %s", + bindtype, argv[0], binding->command); return cmd_results_new(CMD_SUCCESS, NULL, NULL); + +} + +struct cmd_results *cmd_bindsym(int argc, char **argv) { + return cmd_bindsym_or_bindcode(argc, argv, false); } struct cmd_results *cmd_bindcode(int argc, char **argv) { - struct cmd_results *error = NULL; - if ((error = checkarg(argc, "bindcode", EXPECTED_MORE_THAN, 1))) { - return error; - } - - struct sway_binding *binding = calloc(1, sizeof(struct sway_binding)); - if (!binding) { - return cmd_results_new(CMD_FAILURE, "bindsym", - "Unable to allocate binding"); - } - binding->keys = create_list(); - binding->modifiers = 0; - binding->release = false; - binding->locked = false; - binding->bindcode = true; - - // Handle --release and --locked - while (argc > 0) { - if (strcmp("--release", argv[0]) == 0) { - binding->release = true; - } else if (strcmp("--locked", argv[0]) == 0) { - binding->locked = true; - } else { - break; - } - argv++; - argc--; - } - if (argc < 2) { - free_sway_binding(binding); - return cmd_results_new(CMD_FAILURE, "bindcode", - "Invalid bindcode command " - "(expected at least 2 non-option arguments, got %d)", argc); - } - - binding->command = join_args(argv + 1, argc - 1); - - list_t *split = split_string(argv[0], "+"); - for (int i = 0; i < split->length; ++i) { - // Check for a modifier key - uint32_t mod; - if ((mod = get_modifier_mask_by_name(split->items[i])) > 0) { - binding->modifiers |= mod; - continue; - } - // parse keycode - xkb_keycode_t keycode = (int)strtol(split->items[i], NULL, 10); - if (!xkb_keycode_is_legal_ext(keycode)) { - error = - cmd_results_new(CMD_INVALID, "bindcode", - "Invalid keycode '%s'", (char *)split->items[i]); - free_sway_binding(binding); - list_free(split); - return error; - } - xkb_keycode_t *key = calloc(1, sizeof(xkb_keycode_t)); - *key = keycode - 8; - list_add(binding->keys, key); - } - free_flat_list(split); - - binding->order = binding_order++; - - list_t *mode_bindings = config->current_mode->keycode_bindings; - - // overwrite the binding if it already exists - bool overwritten = false; - for (int i = 0; i < mode_bindings->length; ++i) { - struct sway_binding *config_binding = mode_bindings->items[i]; - if (binding_key_compare(binding, config_binding)) { - wlr_log(L_DEBUG, "overwriting old binding with command '%s'", - config_binding->command); - free_sway_binding(config_binding); - mode_bindings->items[i] = binding; - overwritten = true; - } - } - - if (!overwritten) { - list_add(mode_bindings, binding); - } - - wlr_log(L_DEBUG, "bindcode - Bound %s to command %s", - argv[0], binding->command); - return cmd_results_new(CMD_SUCCESS, NULL, NULL); + return cmd_bindsym_or_bindcode(argc, argv, true); } diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c index e873eea31..420cefa64 100644 --- a/sway/input/keyboard.c +++ b/sway/input/keyboard.c @@ -9,88 +9,91 @@ #include "sway/commands.h" #include "log.h" -static bool keysym_is_modifier(xkb_keysym_t keysym) { - switch (keysym) { - case XKB_KEY_Shift_L: case XKB_KEY_Shift_R: - case XKB_KEY_Control_L: case XKB_KEY_Control_R: - case XKB_KEY_Caps_Lock: - case XKB_KEY_Shift_Lock: - case XKB_KEY_Meta_L: case XKB_KEY_Meta_R: - case XKB_KEY_Alt_L: case XKB_KEY_Alt_R: - case XKB_KEY_Super_L: case XKB_KEY_Super_R: - case XKB_KEY_Hyper_L: case XKB_KEY_Hyper_R: - return true; - default: - return false; - } -} - -static size_t pressed_keysyms_length(xkb_keysym_t *pressed_keysyms) { - size_t n = 0; - for (size_t i = 0; i < SWAY_KEYBOARD_PRESSED_KEYSYMS_CAP; ++i) { - if (pressed_keysyms[i] != XKB_KEY_NoSymbol) { - ++n; +/** + * Update the shortcut model state in response to new input + */ +static void update_shortcut_state(struct sway_shortcut_state *state, + struct wlr_event_keyboard_key *event, uint32_t new_key, + bool last_key_was_a_modifier) { + if (event->state == WLR_KEY_PRESSED) { + if (last_key_was_a_modifier && state->last_key_index >= 0) { + // Last pressed key before this one was a modifier + state->pressed_keycodes[state->last_key_index] = 0; + state->pressed_keys[state->last_key_index] = 0; + state->last_key_index = -1; } - } - return n; -} -static ssize_t pressed_keysyms_index(xkb_keysym_t *pressed_keysyms, - xkb_keysym_t keysym) { - for (size_t i = 0; i < SWAY_KEYBOARD_PRESSED_KEYSYMS_CAP; ++i) { - if (pressed_keysyms[i] == keysym) { - return i; + // Add current key to set; there may be duplicates + for (size_t i = 0; i < SWAY_KEYBOARD_PRESSED_KEYS_CAP; ++i) { + if (!state->pressed_keys[i]) { + state->pressed_keys[i] = new_key; + state->pressed_keycodes[i] = event->keycode; + state->last_key_index = i; + break; + } } - } - return -1; -} - -static void pressed_keysyms_add(xkb_keysym_t *pressed_keysyms, - xkb_keysym_t keysym) { - ssize_t i = pressed_keysyms_index(pressed_keysyms, keysym); - if (i < 0) { - i = pressed_keysyms_index(pressed_keysyms, XKB_KEY_NoSymbol); - if (i >= 0) { - pressed_keysyms[i] = keysym; + } else { + for (size_t i = 0; i < SWAY_KEYBOARD_PRESSED_KEYS_CAP; ++i) { + // The same keycode may match multiple keysyms. + if (state->pressed_keycodes[i] == event->keycode) { + state->pressed_keys[i] = 0; + state->pressed_keycodes[i] = 0; + } } } } -static void pressed_keysyms_remove(xkb_keysym_t *pressed_keysyms, - xkb_keysym_t keysym) { - ssize_t i = pressed_keysyms_index(pressed_keysyms, keysym); - if (i >= 0) { - pressed_keysyms[i] = XKB_KEY_NoSymbol; +/** + * + * Returns a binding which matches the shortcut model state (ignoring the + * `release` flag). + */ +static struct sway_binding *get_active_binding( + struct sway_shortcut_state *state, list_t *bindings, + uint32_t modifiers, bool locked) { + int npressed_keys = 0; + for (size_t i = 0; i < SWAY_KEYBOARD_PRESSED_KEYS_CAP; ++i) { + if (state->pressed_keys[i]) { + ++npressed_keys; + } } -} + for (int i = 0; i < bindings->length; ++i) { + struct sway_binding *binding = bindings->items[i]; -static void pressed_keysyms_update(xkb_keysym_t *pressed_keysyms, - const xkb_keysym_t *keysyms, size_t keysyms_len, - enum wlr_key_state state) { - for (size_t i = 0; i < keysyms_len; ++i) { - if (keysym_is_modifier(keysyms[i])) { + if (modifiers ^ binding->modifiers || + npressed_keys != binding->keys->length || + locked > binding->locked) { continue; } - if (state == WLR_KEY_PRESSED) { - pressed_keysyms_add(pressed_keysyms, keysyms[i]); - } else { // WLR_KEY_RELEASED - pressed_keysyms_remove(pressed_keysyms, keysyms[i]); + + bool match = true; + for (int j = 0; j < binding->keys->length; ++j) { + uint32_t key = *(uint32_t *)binding->keys->items[j]; + + bool key_found = false; + for (int k = 0; k < SWAY_KEYBOARD_PRESSED_KEYS_CAP; ++k) { + if (state->pressed_keys[k] == key) { + key_found = true; + break; + } + } + if (!key_found) { + match = false; + break; + } + } + + if (match) { + return binding; } } + + return NULL; } -static bool binding_matches_key_state(struct sway_binding *binding, - enum wlr_key_state key_state) { - if (key_state == WLR_KEY_PRESSED && !binding->release) { - return true; - } - if (key_state == WLR_KEY_RELEASED && binding->release) { - return true; - } - - return false; -} - +/** + * Execute the command associated to a binding + */ static void keyboard_execute_command(struct sway_keyboard *keyboard, struct sway_binding *binding) { wlr_log(L_DEBUG, "running command for binding: %s", @@ -113,7 +116,7 @@ static void keyboard_execute_command(struct sway_keyboard *keyboard, * should be propagated to clients. */ static bool keyboard_execute_compositor_binding(struct sway_keyboard *keyboard, - xkb_keysym_t *pressed_keysyms, uint32_t modifiers, size_t keysyms_len) { + const xkb_keysym_t *pressed_keysyms, uint32_t modifiers, size_t keysyms_len) { for (size_t i = 0; i < keysyms_len; ++i) { xkb_keysym_t keysym = pressed_keysyms[i]; if (keysym >= XKB_KEY_XF86Switch_VT_1 && @@ -133,157 +136,6 @@ static bool keyboard_execute_compositor_binding(struct sway_keyboard *keyboard, return false; } -/** - * Execute keyboard bindings bound with `bindysm` for the given keyboard state. - * - * Returns true if the keysym was handled by a binding and false if the event - * should be propagated to clients. - */ -static bool keyboard_execute_bindsym(struct sway_keyboard *keyboard, - xkb_keysym_t *pressed_keysyms, uint32_t modifiers, - enum wlr_key_state key_state, bool locked) { - // configured bindings - int n = pressed_keysyms_length(pressed_keysyms); - list_t *keysym_bindings = config->current_mode->keysym_bindings; - for (int i = 0; i < keysym_bindings->length; ++i) { - struct sway_binding *binding = keysym_bindings->items[i]; - if (!binding_matches_key_state(binding, key_state) || - modifiers ^ binding->modifiers || - n != binding->keys->length || locked > binding->locked) { - continue; - } - - bool match = true; - for (int j = 0; j < binding->keys->length; ++j) { - match = - pressed_keysyms_index(pressed_keysyms, - *(int*)binding->keys->items[j]) >= 0; - - if (!match) { - break; - } - } - - if (match) { - keyboard_execute_command(keyboard, binding); - return true; - } - } - - return false; -} - -static bool binding_matches_keycodes(struct wlr_keyboard *keyboard, - struct sway_binding *binding, struct wlr_event_keyboard_key *event, bool locked) { - assert(binding->bindcode); - - uint32_t keycode = event->keycode + 8; - - if (!binding_matches_key_state(binding, event->state)) { - return false; - } - - if (locked > binding->locked) { - return false; - } - - uint32_t modifiers = wlr_keyboard_get_modifiers(keyboard); - if (modifiers ^ binding->modifiers) { - return false; - } - - // on release, the released key must be in the binding - if (event->state == WLR_KEY_RELEASED) { - bool found = false; - for (int i = 0; i < binding->keys->length; ++i) { - uint32_t binding_keycode = *(uint32_t*)binding->keys->items[i] + 8; - if (binding_keycode == keycode) { - found = true; - break; - } - } - if (!found) { - return false; - } - } - - // every keycode in the binding must be present in the pressed keys on the - // keyboard - for (int i = 0; i < binding->keys->length; ++i) { - uint32_t binding_keycode = *(uint32_t*)binding->keys->items[i] + 8; - if (event->state == WLR_KEY_RELEASED && keycode == binding_keycode) { - continue; - } - - bool found = false; - for (size_t j = 0; j < keyboard->num_keycodes; ++j) { - xkb_keycode_t keycode = keyboard->keycodes[j] + 8; - if (keycode == binding_keycode) { - found = true; - break; - } - } - - if (!found) { - return false; - } - } - - // every keycode pressed on the keyboard must be present within the binding - // keys (unless it is a modifier) - for (size_t i = 0; i < keyboard->num_keycodes; ++i) { - xkb_keycode_t keycode = keyboard->keycodes[i] + 8; - bool found = false; - for (int j = 0; j < binding->keys->length; ++j) { - uint32_t binding_keycode = *(uint32_t*)binding->keys->items[j] + 8; - if (binding_keycode == keycode) { - found = true; - break; - } - } - - if (!found) { - if (!binding->modifiers) { - return false; - } - - // check if it is a modifier, which we know matched from the check - // above - const xkb_keysym_t *keysyms; - int num_keysyms = - xkb_state_key_get_syms(keyboard->xkb_state, - keycode, &keysyms); - if (num_keysyms != 1 || !keysym_is_modifier(keysyms[0])) { - return false; - } - } - } - - return true; -} - -/** - * Execute keyboard bindings bound with `bindcode` for the given keyboard state. - * - * Returns true if the keysym was handled by a binding and false if the event - * should be propagated to clients. - */ -static bool keyboard_execute_bindcode(struct sway_keyboard *keyboard, - struct wlr_event_keyboard_key *event, bool locked) { - struct wlr_keyboard *wlr_keyboard = - keyboard->seat_device->input_device->wlr_device->keyboard; - list_t *keycode_bindings = config->current_mode->keycode_bindings; - for (int i = 0; i < keycode_bindings->length; ++i) { - struct sway_binding *binding = keycode_bindings->items[i]; - if (binding_matches_keycodes(wlr_keyboard, binding, event, locked)) { - keyboard_execute_command(keyboard, binding); - return true; - } - } - - return false; -} - /** * Get keysyms and modifiers from the keyboard as xkb sees them. * @@ -339,61 +191,96 @@ static void handle_keyboard_key(struct wl_listener *listener, void *data) { struct wlr_event_keyboard_key *event = data; bool input_inhibited = keyboard->seat_device->sway_seat->exclusive_client != NULL; + // Identify new keycode, raw keysym(s), and translated keysym(s) xkb_keycode_t keycode = event->keycode + 8; - bool handled = false; - // handle keycodes - handled = keyboard_execute_bindcode(keyboard, event, input_inhibited); - - // handle translated keysyms - if (!handled && event->state == WLR_KEY_RELEASED) { - handled = keyboard_execute_bindsym(keyboard, - keyboard->pressed_keysyms_translated, - keyboard->modifiers_translated, - event->state, input_inhibited); - } const xkb_keysym_t *translated_keysyms; + uint32_t translated_modifiers; size_t translated_keysyms_len = keyboard_keysyms_translated(keyboard, keycode, &translated_keysyms, - &keyboard->modifiers_translated); - pressed_keysyms_update(keyboard->pressed_keysyms_translated, - translated_keysyms, translated_keysyms_len, event->state); - if (!handled && event->state == WLR_KEY_PRESSED) { - handled = keyboard_execute_bindsym(keyboard, - keyboard->pressed_keysyms_translated, - keyboard->modifiers_translated, - event->state, input_inhibited); + &translated_modifiers); + + const xkb_keysym_t *raw_keysyms; + uint32_t raw_modifiers; + size_t raw_keysyms_len = + keyboard_keysyms_raw(keyboard, keycode, &raw_keysyms, &raw_modifiers); + + struct wlr_input_device *device = + keyboard->seat_device->input_device->wlr_device; + uint32_t code_modifiers = wlr_keyboard_get_modifiers(device->keyboard); + + bool last_key_was_a_modifier = code_modifiers != keyboard->last_modifiers; + keyboard->last_modifiers = code_modifiers; + + // Update shortcut model state + update_shortcut_state(&keyboard->state_keycodes, event, + (uint32_t)keycode, last_key_was_a_modifier); + for (size_t i = 0; i < translated_keysyms_len; ++i) { + update_shortcut_state(&keyboard->state_keysyms_translated, + event, (uint32_t)translated_keysyms[i], + last_key_was_a_modifier && i == 0); + } + for (size_t i = 0; i < raw_keysyms_len; ++i) { + update_shortcut_state(&keyboard->state_keysyms_raw, + event, (uint32_t)raw_keysyms[i], + last_key_was_a_modifier && i == 0); } - // Handle raw keysyms - if (!handled && event->state == WLR_KEY_RELEASED) { - handled = keyboard_execute_bindsym(keyboard, - keyboard->pressed_keysyms_raw, keyboard->modifiers_raw, - event->state, input_inhibited); + // identify which binding should be executed. + struct sway_binding *binding = get_active_binding( + &keyboard->state_keycodes, + config->current_mode->keycode_bindings, + code_modifiers, input_inhibited); + struct sway_binding *translated_binding = get_active_binding( + &keyboard->state_keysyms_translated, + config->current_mode->keysym_bindings, + translated_modifiers, input_inhibited); + if (translated_binding && !binding) { + binding = translated_binding; + } else if (binding && translated_binding && binding != translated_binding) { + wlr_log(L_DEBUG, "encountered duplicate bindings %d and %d", + binding->order, translated_binding->order); } - const xkb_keysym_t *raw_keysyms; - size_t raw_keysyms_len = - keyboard_keysyms_raw(keyboard, keycode, &raw_keysyms, &keyboard->modifiers_raw); - pressed_keysyms_update(keyboard->pressed_keysyms_raw, raw_keysyms, - raw_keysyms_len, event->state); - if (!handled && event->state == WLR_KEY_PRESSED) { - handled = keyboard_execute_bindsym(keyboard, - keyboard->pressed_keysyms_raw, keyboard->modifiers_raw, - event->state, input_inhibited); + struct sway_binding *raw_binding = get_active_binding( + &keyboard->state_keysyms_raw, + config->current_mode->keysym_bindings, + raw_modifiers, input_inhibited); + if (raw_binding && !binding) { + binding = raw_binding; + } else if (binding && raw_binding && binding != raw_binding) { + wlr_log(L_DEBUG, "encountered duplicate bindings %d and %d", + binding->order, raw_binding->order); + } + + bool handled = false; + + // Execute the identified binding if need be. + if (keyboard->held_binding && binding != keyboard->held_binding && + event->state == WLR_KEY_RELEASED) { + keyboard_execute_command(keyboard, keyboard->held_binding); + handled = true; + } + if (binding != keyboard->held_binding) { + keyboard->held_binding = NULL; + } + if (binding && event->state == WLR_KEY_PRESSED) { + if (binding->release) { + keyboard->held_binding = binding; + } else { + keyboard_execute_command(keyboard, binding); + handled = true; + } } // Compositor bindings if (!handled && event->state == WLR_KEY_PRESSED) { - handled = - keyboard_execute_compositor_binding(keyboard, - keyboard->pressed_keysyms_translated, - keyboard->modifiers_translated, + handled = keyboard_execute_compositor_binding( + keyboard, translated_keysyms, translated_modifiers, translated_keysyms_len); } if (!handled && event->state == WLR_KEY_PRESSED) { - handled = - keyboard_execute_compositor_binding(keyboard, - keyboard->pressed_keysyms_raw, keyboard->modifiers_raw, + handled = keyboard_execute_compositor_binding( + keyboard, raw_keysyms, raw_modifiers, raw_keysyms_len); } @@ -429,6 +316,10 @@ struct sway_keyboard *sway_keyboard_create(struct sway_seat *seat, wl_list_init(&keyboard->keyboard_key.link); wl_list_init(&keyboard->keyboard_modifiers.link); + keyboard->state_keycodes.last_key_index = -1; + keyboard->state_keysyms_raw.last_key_index = -1; + keyboard->state_keysyms_translated.last_key_index = -1; + return keyboard; }