aboutsummaryrefslogtreecommitdiffstats
path: root/sway/input/keyboard.c
diff options
context:
space:
mode:
authorLibravatar frsfnrrg <frsfnrrg@users.noreply.github.com>2018-06-12 11:07:11 -0400
committerLibravatar frsfnrrg <frsfnrrg@users.noreply.github.com>2018-06-12 20:26:57 -0400
commitca061ba8bf94e1d09e1d912871841212778044ed (patch)
tree855a5886f90dd555ae1057049d8d802d0c2b5cfb /sway/input/keyboard.c
parentSort binding key lists (diff)
downloadsway-ca061ba8bf94e1d09e1d912871841212778044ed.tar.gz
sway-ca061ba8bf94e1d09e1d912871841212778044ed.tar.zst
sway-ca061ba8bf94e1d09e1d912871841212778044ed.zip
Fix keyboard shortcut handling inconsistencies
* Ensure that modifier keys are identified even when the next key does not produce a keysym. This requires that modifier change tracking be done for each sway_shortcut_state. * Permit regular and --release shortcuts on the same key combination. Distinct bindings are identified for press and release cases; note that the release binding needs to be identified for both key press and key release events. * Maintain ascending sort order for the shortcut state list, and keep track of the number of pressed key ids, for simpler (and hence faster) searching of the list of key bindings. * Move binding duplicate detection into get_active_binding to avoid duplicating error messages.
Diffstat (limited to 'sway/input/keyboard.c')
-rw-r--r--sway/input/keyboard.c206
1 files changed, 112 insertions, 94 deletions
diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c
index d90655f2..9e093828 100644
--- a/sway/input/keyboard.c
+++ b/sway/input/keyboard.c
@@ -10,85 +10,111 @@
10#include "log.h" 10#include "log.h"
11 11
12/** 12/**
13 * Remove all key ids associated to a keycode from the list of pressed keys
14 */
15static void state_erase_key(struct sway_shortcut_state *state,
16 uint32_t keycode) {
17 size_t j = 0;
18 for (size_t i = 0; i < state->npressed; ++i) {
19 if (i > j) {
20 state->pressed_keys[j] = state->pressed_keys[i];
21 state->pressed_keycodes[j] = state->pressed_keycodes[i];
22 }
23 if (state->pressed_keycodes[i] != keycode) {
24 ++j;
25 }
26 }
27 while(state->npressed > j) {
28 --state->npressed;
29 state->pressed_keys[state->npressed] = 0;
30 state->pressed_keycodes[state->npressed] = 0;
31 }
32}
33
34/**
35 * Add a key id (with associated keycode) to the list of pressed keys,
36 * if the list is not full.
37 */
38static void state_add_key(struct sway_shortcut_state *state,
39 uint32_t keycode, uint32_t key_id) {
40 if (state->npressed >= SWAY_KEYBOARD_PRESSED_KEYS_CAP) {
41 return;
42 }
43 size_t i = 0;
44 while (i < state->npressed && state->pressed_keys[i] < key_id) {
45 ++i;
46 }
47 size_t j = state->npressed;
48 while (j > i) {
49 state->pressed_keys[j] = state->pressed_keys[j - 1];
50 state->pressed_keycodes[j] = state->pressed_keycodes[j - 1];
51 --j;
52 }
53 state->pressed_keys[i] = key_id;
54 state->pressed_keycodes[i] = keycode;
55 state->npressed++;
56}
57
58/**
13 * Update the shortcut model state in response to new input 59 * Update the shortcut model state in response to new input
14 */ 60 */
15static void update_shortcut_state(struct sway_shortcut_state *state, 61static void update_shortcut_state(struct sway_shortcut_state *state,
16 struct wlr_event_keyboard_key *event, uint32_t new_key, 62 struct wlr_event_keyboard_key *event, uint32_t new_key,
17 bool last_key_was_a_modifier) { 63 uint32_t raw_modifiers) {
64 bool last_key_was_a_modifier = raw_modifiers != state->last_raw_modifiers;
65 state->last_raw_modifiers = raw_modifiers;
66
18 if (event->state == WLR_KEY_PRESSED) { 67 if (event->state == WLR_KEY_PRESSED) {
19 if (last_key_was_a_modifier && state->last_key_index >= 0) { 68 if (last_key_was_a_modifier && state->last_keycode) {
20 // Last pressed key before this one was a modifier 69 // Last pressed key before this one was a modifier
21 state->pressed_keycodes[state->last_key_index] = 0; 70 state_erase_key(state, state->last_keycode);
22 state->pressed_keys[state->last_key_index] = 0;
23 state->last_key_index = -1;
24 } 71 }
25 72
26 // Add current key to set; there may be duplicates 73 // Add current key to set; there may be duplicates
27 for (size_t i = 0; i < SWAY_KEYBOARD_PRESSED_KEYS_CAP; ++i) { 74 state_add_key(state, event->keycode, new_key);
28 if (!state->pressed_keys[i]) { 75 state->last_keycode = event->keycode;
29 state->pressed_keys[i] = new_key;
30 state->pressed_keycodes[i] = event->keycode;
31 state->last_key_index = i;
32 break;
33 }
34 }
35 } else { 76 } else {
36 for (size_t i = 0; i < SWAY_KEYBOARD_PRESSED_KEYS_CAP; ++i) { 77 state_erase_key(state, event->keycode);
37 // The same keycode may match multiple keysyms.
38 if (state->pressed_keycodes[i] == event->keycode) {
39 state->pressed_keys[i] = 0;
40 state->pressed_keycodes[i] = 0;
41 }
42 }
43 } 78 }
44} 79}
45 80
46/** 81/**
47 * 82 * If one exists, finds a binding which matches the shortcut model state,
48 * Returns a binding which matches the shortcut model state (ignoring the 83 * current modifiers, release state, and locked state.
49 * `release` flag).
50 */ 84 */
51static struct sway_binding *get_active_binding( 85static void get_active_binding(const struct sway_shortcut_state *state,
52 struct sway_shortcut_state *state, list_t *bindings, 86 list_t *bindings, struct sway_binding **current_binding,
53 uint32_t modifiers, bool locked) { 87 uint32_t modifiers, bool release, bool locked) {
54 int npressed_keys = 0;
55 for (size_t i = 0; i < SWAY_KEYBOARD_PRESSED_KEYS_CAP; ++i) {
56 if (state->pressed_keys[i]) {
57 ++npressed_keys;
58 }
59 }
60 for (int i = 0; i < bindings->length; ++i) { 88 for (int i = 0; i < bindings->length; ++i) {
61 struct sway_binding *binding = bindings->items[i]; 89 struct sway_binding *binding = bindings->items[i];
62 90
63 if (modifiers ^ binding->modifiers || 91 if (modifiers ^ binding->modifiers ||
64 npressed_keys != binding->keys->length || 92 state->npressed != (size_t)binding->keys->length ||
65 locked > binding->locked) { 93 locked > binding->locked ||
94 release != binding->release) {
66 continue; 95 continue;
67 } 96 }
68 97
69 bool match = true; 98 bool match = true;
70 for (int j = 0; j < binding->keys->length; ++j) { 99 for (size_t j = 0; j < state->npressed; j++) {
71 uint32_t key = *(uint32_t *)binding->keys->items[j]; 100 uint32_t key = *(uint32_t *)binding->keys->items[j];
72 101 if (key != state->pressed_keys[j]) {
73 bool key_found = false;
74 for (int k = 0; k < SWAY_KEYBOARD_PRESSED_KEYS_CAP; ++k) {
75 if (state->pressed_keys[k] == key) {
76 key_found = true;
77 break;
78 }
79 }
80 if (!key_found) {
81 match = false; 102 match = false;
82 break; 103 break;
83 } 104 }
84 } 105 }
106 if (!match) {
107 continue;
108 }
85 109
86 if (match) { 110 if (*current_binding && *current_binding != binding) {
87 return binding; 111 wlr_log(L_DEBUG, "encountered duplicate bindings %d and %d",
112 (*current_binding)->order, binding->order);
113 } else {
114 *current_binding = binding;
88 } 115 }
116 return;
89 } 117 }
90
91 return NULL;
92} 118}
93 119
94/** 120/**
@@ -204,69 +230,65 @@ static void handle_keyboard_key(struct wl_listener *listener, void *data) {
204 size_t raw_keysyms_len = 230 size_t raw_keysyms_len =
205 keyboard_keysyms_raw(keyboard, keycode, &raw_keysyms, &raw_modifiers); 231 keyboard_keysyms_raw(keyboard, keycode, &raw_keysyms, &raw_modifiers);
206 232
207 struct wlr_input_device *device = 233 uint32_t code_modifiers = wlr_keyboard_get_modifiers(wlr_device->keyboard);
208 keyboard->seat_device->input_device->wlr_device;
209 uint32_t code_modifiers = wlr_keyboard_get_modifiers(device->keyboard);
210
211 bool last_key_was_a_modifier = code_modifiers != keyboard->last_modifiers;
212 keyboard->last_modifiers = code_modifiers;
213 234
214 // Update shortcut model state 235 // Update shortcut model state
215 update_shortcut_state(&keyboard->state_keycodes, event, 236 update_shortcut_state(&keyboard->state_keycodes, event,
216 (uint32_t)keycode, last_key_was_a_modifier); 237 (uint32_t)keycode, code_modifiers);
217 for (size_t i = 0; i < translated_keysyms_len; ++i) { 238 for (size_t i = 0; i < translated_keysyms_len; ++i) {
218 update_shortcut_state(&keyboard->state_keysyms_translated, 239 update_shortcut_state(&keyboard->state_keysyms_translated,
219 event, (uint32_t)translated_keysyms[i], 240 event, (uint32_t)translated_keysyms[i],
220 last_key_was_a_modifier && i == 0); 241 code_modifiers);
221 } 242 }
222 for (size_t i = 0; i < raw_keysyms_len; ++i) { 243 for (size_t i = 0; i < raw_keysyms_len; ++i) {
223 update_shortcut_state(&keyboard->state_keysyms_raw, 244 update_shortcut_state(&keyboard->state_keysyms_raw,
224 event, (uint32_t)raw_keysyms[i], 245 event, (uint32_t)raw_keysyms[i],
225 last_key_was_a_modifier && i == 0); 246 code_modifiers);
226 } 247 }
227 248
228 // identify which binding should be executed.
229 struct sway_binding *binding = get_active_binding(
230 &keyboard->state_keycodes,
231 config->current_mode->keycode_bindings,
232 code_modifiers, input_inhibited);
233 struct sway_binding *translated_binding = get_active_binding(
234 &keyboard->state_keysyms_translated,
235 config->current_mode->keysym_bindings,
236 translated_modifiers, input_inhibited);
237 if (translated_binding && !binding) {
238 binding = translated_binding;
239 } else if (binding && translated_binding && binding != translated_binding) {
240 wlr_log(L_DEBUG, "encountered duplicate bindings %d and %d",
241 binding->order, translated_binding->order);
242 }
243 struct sway_binding *raw_binding = get_active_binding(
244 &keyboard->state_keysyms_raw,
245 config->current_mode->keysym_bindings,
246 raw_modifiers, input_inhibited);
247 if (raw_binding && !binding) {
248 binding = raw_binding;
249 } else if (binding && raw_binding && binding != raw_binding) {
250 wlr_log(L_DEBUG, "encountered duplicate bindings %d and %d",
251 binding->order, raw_binding->order);
252 }
253 249
254 bool handled = false; 250 bool handled = false;
255 251
256 // Execute the identified binding if need be. 252 // Identify active release binding
257 if (keyboard->held_binding && binding != keyboard->held_binding && 253 struct sway_binding *binding_released = NULL;
254 get_active_binding(&keyboard->state_keycodes,
255 config->current_mode->keycode_bindings, &binding_released,
256 code_modifiers, true, input_inhibited);
257 get_active_binding(&keyboard->state_keysyms_translated,
258 config->current_mode->keysym_bindings, &binding_released,
259 translated_modifiers, true, input_inhibited);
260 get_active_binding(&keyboard->state_keysyms_raw,
261 config->current_mode->keysym_bindings, &binding_released,
262 raw_modifiers, true, input_inhibited);
263
264 // Execute stored release binding once no longer active
265 if (keyboard->held_binding && binding_released != keyboard->held_binding &&
258 event->state == WLR_KEY_RELEASED) { 266 event->state == WLR_KEY_RELEASED) {
259 keyboard_execute_command(keyboard, keyboard->held_binding); 267 keyboard_execute_command(keyboard, keyboard->held_binding);
260 handled = true; 268 handled = true;
261 } 269 }
262 if (binding != keyboard->held_binding) { 270 if (binding_released != keyboard->held_binding) {
263 keyboard->held_binding = NULL; 271 keyboard->held_binding = NULL;
264 } 272 }
265 if (binding && event->state == WLR_KEY_PRESSED) { 273 if (binding_released && event->state == WLR_KEY_PRESSED) {
266 if (binding->release) { 274 keyboard->held_binding = binding_released;
267 keyboard->held_binding = binding; 275 }
268 } else { 276
269 keyboard_execute_command(keyboard, binding); 277 // Identify and execute active pressed binding
278 if (event->state == WLR_KEY_PRESSED) {
279 struct sway_binding *binding_pressed = NULL;
280 get_active_binding(&keyboard->state_keycodes,
281 config->current_mode->keycode_bindings, &binding_pressed,
282 code_modifiers, false, input_inhibited);
283 get_active_binding(&keyboard->state_keysyms_translated,
284 config->current_mode->keysym_bindings, &binding_pressed,
285 translated_modifiers, false, input_inhibited);
286 get_active_binding(&keyboard->state_keysyms_raw,
287 config->current_mode->keysym_bindings, &binding_pressed,
288 raw_modifiers, false, input_inhibited);
289
290 if (binding_pressed) {
291 keyboard_execute_command(keyboard, binding_pressed);
270 handled = true; 292 handled = true;
271 } 293 }
272 } 294 }
@@ -315,10 +337,6 @@ struct sway_keyboard *sway_keyboard_create(struct sway_seat *seat,
315 wl_list_init(&keyboard->keyboard_key.link); 337 wl_list_init(&keyboard->keyboard_key.link);
316 wl_list_init(&keyboard->keyboard_modifiers.link); 338 wl_list_init(&keyboard->keyboard_modifiers.link);
317 339
318 keyboard->state_keycodes.last_key_index = -1;
319 keyboard->state_keysyms_raw.last_key_index = -1;
320 keyboard->state_keysyms_translated.last_key_index = -1;
321
322 return keyboard; 340 return keyboard;
323} 341}
324 342