aboutsummaryrefslogtreecommitdiffstats
path: root/sway/input/keyboard.c
diff options
context:
space:
mode:
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