summaryrefslogtreecommitdiffstats
path: root/sway
diff options
context:
space:
mode:
authorLibravatar emersion <contact@emersion.fr>2018-06-02 09:18:07 +0100
committerLibravatar GitHub <noreply@github.com>2018-06-02 09:18:07 +0100
commit2d480e754e8287ba747faf1b21d8ecb927d565a1 (patch)
treecf71dc112c1b4acb944073d93b73f76ee957ceac /sway
parentMerge pull request #2088 from RyanDwyer/fix-floating-border-pixel (diff)
parentStyle fix, redundant entry removal, fix extra keysym delete (diff)
downloadsway-2d480e754e8287ba747faf1b21d8ecb927d565a1.tar.gz
sway-2d480e754e8287ba747faf1b21d8ecb927d565a1.tar.zst
sway-2d480e754e8287ba747faf1b21d8ecb927d565a1.zip
Merge pull request #2080 from frsfnrrg/keyboard-remodeling
Reduce work duplication in keyboard and binding code
Diffstat (limited to 'sway')
-rw-r--r--sway/commands/bind.c173
-rw-r--r--sway/input/keyboard.c405
2 files changed, 210 insertions, 368 deletions
diff --git a/sway/commands/bind.c b/sway/commands/bind.c
index c6b3368a..d0e3e22f 100644
--- a/sway/commands/bind.c
+++ b/sway/commands/bind.c
@@ -69,22 +69,25 @@ bool binding_key_compare(struct sway_binding *binding_a,
69 return true; 69 return true;
70} 70}
71 71
72struct cmd_results *cmd_bindsym(int argc, char **argv) { 72static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv,
73 bool bindcode) {
74 const char *bindtype = bindcode ? "bindcode" : "bindsym";
75
73 struct cmd_results *error = NULL; 76 struct cmd_results *error = NULL;
74 if ((error = checkarg(argc, "bindsym", EXPECTED_MORE_THAN, 1))) { 77 if ((error = checkarg(argc, bindtype, EXPECTED_MORE_THAN, 1))) {
75 return error; 78 return error;
76 } 79 }
77 80
78 struct sway_binding *binding = calloc(1, sizeof(struct sway_binding)); 81 struct sway_binding *binding = calloc(1, sizeof(struct sway_binding));
79 if (!binding) { 82 if (!binding) {
80 return cmd_results_new(CMD_FAILURE, "bindsym", 83 return cmd_results_new(CMD_FAILURE, bindtype,
81 "Unable to allocate binding"); 84 "Unable to allocate binding");
82 } 85 }
83 binding->keys = create_list(); 86 binding->keys = create_list();
84 binding->modifiers = 0; 87 binding->modifiers = 0;
85 binding->release = false; 88 binding->release = false;
86 binding->locked = false; 89 binding->locked = false;
87 binding->bindcode = false; 90 binding->bindcode = bindcode;
88 91
89 // Handle --release and --locked 92 // Handle --release and --locked
90 while (argc > 0) { 93 while (argc > 0) {
@@ -100,9 +103,9 @@ struct cmd_results *cmd_bindsym(int argc, char **argv) {
100 } 103 }
101 if (argc < 2) { 104 if (argc < 2) {
102 free_sway_binding(binding); 105 free_sway_binding(binding);
103 return cmd_results_new(CMD_FAILURE, "bindsym", 106 return cmd_results_new(CMD_FAILURE, bindtype,
104 "Invalid bindsym command " 107 "Invalid %s command "
105 "(expected at least 2 non-option arguments, got %d)", argc); 108 "(expected at least 2 non-option arguments, got %d)", bindtype, argc);
106 } 109 }
107 110
108 binding->command = join_args(argv + 1, argc - 1); 111 binding->command = join_args(argv + 1, argc - 1);
@@ -115,124 +118,63 @@ struct cmd_results *cmd_bindsym(int argc, char **argv) {
115 binding->modifiers |= mod; 118 binding->modifiers |= mod;
116 continue; 119 continue;
117 } 120 }
118 // Check for xkb key
119 xkb_keysym_t sym = xkb_keysym_from_name(split->items[i],
120 XKB_KEYSYM_CASE_INSENSITIVE);
121 121
122 // Check for mouse binding 122 xkb_keycode_t keycode;
123 if (strncasecmp(split->items[i], "button", strlen("button")) == 0 && 123 xkb_keysym_t keysym;
124 strlen(split->items[i]) == strlen("button0")) { 124 if (bindcode) {
125 sym = ((char *)split->items[i])[strlen("button")] - '1' + BTN_LEFT; 125 // parse keycode
126 } 126 keycode = (int)strtol(split->items[i], NULL, 10);
127 if (!sym) { 127 if (!xkb_keycode_is_legal_ext(keycode)) {
128 struct cmd_results *ret = cmd_results_new(CMD_INVALID, "bindsym", 128 error =
129 "Unknown key '%s'", (char *)split->items[i]); 129 cmd_results_new(CMD_INVALID, "bindcode",
130 free_sway_binding(binding); 130 "Invalid keycode '%s'", (char *)split->items[i]);
131 free_flat_list(split); 131 free_sway_binding(binding);
132 return ret; 132 list_free(split);
133 return error;
134 }
135 } else {
136 // Check for xkb key
137 keysym = xkb_keysym_from_name(split->items[i],
138 XKB_KEYSYM_CASE_INSENSITIVE);
139
140 // Check for mouse binding
141 if (strncasecmp(split->items[i], "button", strlen("button")) == 0 &&
142 strlen(split->items[i]) == strlen("button0")) {
143 keysym = ((char *)split->items[i])[strlen("button")] - '1' + BTN_LEFT;
144 }
145 if (!keysym) {
146 struct cmd_results *ret = cmd_results_new(CMD_INVALID, "bindsym",
147 "Unknown key '%s'", (char *)split->items[i]);
148 free_sway_binding(binding);
149 free_flat_list(split);
150 return ret;
151 }
133 } 152 }
134 xkb_keysym_t *key = calloc(1, sizeof(xkb_keysym_t)); 153 uint32_t *key = calloc(1, sizeof(uint32_t));
135 if (!key) { 154 if (!key) {
136 free_sway_binding(binding); 155 free_sway_binding(binding);
137 free_flat_list(split); 156 free_flat_list(split);
138 return cmd_results_new(CMD_FAILURE, "bindsym", 157 return cmd_results_new(CMD_FAILURE, bindtype,
139 "Unable to allocate binding"); 158 "Unable to allocate binding");
140 } 159 }
141 *key = sym;
142 list_add(binding->keys, key);
143 }
144 free_flat_list(split);
145 binding->order = binding_order++;
146
147 list_t *mode_bindings = config->current_mode->keysym_bindings;
148
149 // overwrite the binding if it already exists
150 bool overwritten = false;
151 for (int i = 0; i < mode_bindings->length; ++i) {
152 struct sway_binding *config_binding = mode_bindings->items[i];
153 if (binding_key_compare(binding, config_binding)) {
154 wlr_log(L_DEBUG, "overwriting old binding with command '%s'",
155 config_binding->command);
156 free_sway_binding(config_binding);
157 mode_bindings->items[i] = binding;
158 overwritten = true;
159 }
160 }
161
162 if (!overwritten) {
163 list_add(mode_bindings, binding);
164 }
165
166 wlr_log(L_DEBUG, "bindsym - Bound %s to command %s",
167 argv[0], binding->command);
168 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
169}
170
171struct cmd_results *cmd_bindcode(int argc, char **argv) {
172 struct cmd_results *error = NULL;
173 if ((error = checkarg(argc, "bindcode", EXPECTED_MORE_THAN, 1))) {
174 return error;
175 }
176
177 struct sway_binding *binding = calloc(1, sizeof(struct sway_binding));
178 if (!binding) {
179 return cmd_results_new(CMD_FAILURE, "bindsym",
180 "Unable to allocate binding");
181 }
182 binding->keys = create_list();
183 binding->modifiers = 0;
184 binding->release = false;
185 binding->locked = false;
186 binding->bindcode = true;
187 160
188 // Handle --release and --locked 161 if (bindcode) {
189 while (argc > 0) { 162 *key = (uint32_t)keycode;
190 if (strcmp("--release", argv[0]) == 0) {
191 binding->release = true;
192 } else if (strcmp("--locked", argv[0]) == 0) {
193 binding->locked = true;
194 } else { 163 } else {
195 break; 164 *key = (uint32_t)keysym;
196 } 165 }
197 argv++;
198 argc--;
199 }
200 if (argc < 2) {
201 free_sway_binding(binding);
202 return cmd_results_new(CMD_FAILURE, "bindcode",
203 "Invalid bindcode command "
204 "(expected at least 2 non-option arguments, got %d)", argc);
205 }
206 166
207 binding->command = join_args(argv + 1, argc - 1);
208
209 list_t *split = split_string(argv[0], "+");
210 for (int i = 0; i < split->length; ++i) {
211 // Check for a modifier key
212 uint32_t mod;
213 if ((mod = get_modifier_mask_by_name(split->items[i])) > 0) {
214 binding->modifiers |= mod;
215 continue;
216 }
217 // parse keycode
218 xkb_keycode_t keycode = (int)strtol(split->items[i], NULL, 10);
219 if (!xkb_keycode_is_legal_ext(keycode)) {
220 error =
221 cmd_results_new(CMD_INVALID, "bindcode",
222 "Invalid keycode '%s'", (char *)split->items[i]);
223 free_sway_binding(binding);
224 list_free(split);
225 return error;
226 }
227 xkb_keycode_t *key = calloc(1, sizeof(xkb_keycode_t));
228 *key = keycode - 8;
229 list_add(binding->keys, key); 167 list_add(binding->keys, key);
230 } 168 }
231 free_flat_list(split); 169 free_flat_list(split);
232
233 binding->order = binding_order++; 170 binding->order = binding_order++;
234 171
235 list_t *mode_bindings = config->current_mode->keycode_bindings; 172 list_t *mode_bindings;
173 if (bindcode) {
174 mode_bindings = config->current_mode->keycode_bindings;
175 } else {
176 mode_bindings = config->current_mode->keysym_bindings;
177 }
236 178
237 // overwrite the binding if it already exists 179 // overwrite the binding if it already exists
238 bool overwritten = false; 180 bool overwritten = false;
@@ -251,7 +193,16 @@ struct cmd_results *cmd_bindcode(int argc, char **argv) {
251 list_add(mode_bindings, binding); 193 list_add(mode_bindings, binding);
252 } 194 }
253 195
254 wlr_log(L_DEBUG, "bindcode - Bound %s to command %s", 196 wlr_log(L_DEBUG, "%s - Bound %s to command %s",
255 argv[0], binding->command); 197 bindtype, argv[0], binding->command);
256 return cmd_results_new(CMD_SUCCESS, NULL, NULL); 198 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
199
200}
201
202struct cmd_results *cmd_bindsym(int argc, char **argv) {
203 return cmd_bindsym_or_bindcode(argc, argv, false);
204}
205
206struct cmd_results *cmd_bindcode(int argc, char **argv) {
207 return cmd_bindsym_or_bindcode(argc, argv, true);
257} 208}
diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c
index e873eea3..420cefa6 100644
--- a/sway/input/keyboard.c
+++ b/sway/input/keyboard.c
@@ -9,88 +9,91 @@
9#include "sway/commands.h" 9#include "sway/commands.h"
10#include "log.h" 10#include "log.h"
11 11
12static bool keysym_is_modifier(xkb_keysym_t keysym) { 12/**
13 switch (keysym) { 13 * Update the shortcut model state in response to new input
14 case XKB_KEY_Shift_L: case XKB_KEY_Shift_R: 14 */
15 case XKB_KEY_Control_L: case XKB_KEY_Control_R: 15static void update_shortcut_state(struct sway_shortcut_state *state,
16 case XKB_KEY_Caps_Lock: 16 struct wlr_event_keyboard_key *event, uint32_t new_key,
17 case XKB_KEY_Shift_Lock: 17 bool last_key_was_a_modifier) {
18 case XKB_KEY_Meta_L: case XKB_KEY_Meta_R: 18 if (event->state == WLR_KEY_PRESSED) {
19 case XKB_KEY_Alt_L: case XKB_KEY_Alt_R: 19 if (last_key_was_a_modifier && state->last_key_index >= 0) {
20 case XKB_KEY_Super_L: case XKB_KEY_Super_R: 20 // Last pressed key before this one was a modifier
21 case XKB_KEY_Hyper_L: case XKB_KEY_Hyper_R: 21 state->pressed_keycodes[state->last_key_index] = 0;
22 return true; 22 state->pressed_keys[state->last_key_index] = 0;
23 default: 23 state->last_key_index = -1;
24 return false;
25 }
26}
27
28static size_t pressed_keysyms_length(xkb_keysym_t *pressed_keysyms) {
29 size_t n = 0;
30 for (size_t i = 0; i < SWAY_KEYBOARD_PRESSED_KEYSYMS_CAP; ++i) {
31 if (pressed_keysyms[i] != XKB_KEY_NoSymbol) {
32 ++n;
33 } 24 }
34 }
35 return n;
36}
37 25
38static ssize_t pressed_keysyms_index(xkb_keysym_t *pressed_keysyms, 26 // Add current key to set; there may be duplicates
39 xkb_keysym_t keysym) { 27 for (size_t i = 0; i < SWAY_KEYBOARD_PRESSED_KEYS_CAP; ++i) {
40 for (size_t i = 0; i < SWAY_KEYBOARD_PRESSED_KEYSYMS_CAP; ++i) { 28 if (!state->pressed_keys[i]) {
41 if (pressed_keysyms[i] == keysym) { 29 state->pressed_keys[i] = new_key;
42 return i; 30 state->pressed_keycodes[i] = event->keycode;
31 state->last_key_index = i;
32 break;
33 }
43 } 34 }
44 } 35 } else {
45 return -1; 36 for (size_t i = 0; i < SWAY_KEYBOARD_PRESSED_KEYS_CAP; ++i) {
46} 37 // The same keycode may match multiple keysyms.
47 38 if (state->pressed_keycodes[i] == event->keycode) {
48static void pressed_keysyms_add(xkb_keysym_t *pressed_keysyms, 39 state->pressed_keys[i] = 0;
49 xkb_keysym_t keysym) { 40 state->pressed_keycodes[i] = 0;
50 ssize_t i = pressed_keysyms_index(pressed_keysyms, keysym); 41 }
51 if (i < 0) {
52 i = pressed_keysyms_index(pressed_keysyms, XKB_KEY_NoSymbol);
53 if (i >= 0) {
54 pressed_keysyms[i] = keysym;
55 } 42 }
56 } 43 }
57} 44}
58 45
59static void pressed_keysyms_remove(xkb_keysym_t *pressed_keysyms, 46/**
60 xkb_keysym_t keysym) { 47 *
61 ssize_t i = pressed_keysyms_index(pressed_keysyms, keysym); 48 * Returns a binding which matches the shortcut model state (ignoring the
62 if (i >= 0) { 49 * `release` flag).
63 pressed_keysyms[i] = XKB_KEY_NoSymbol; 50 */
51static struct sway_binding *get_active_binding(
52 struct sway_shortcut_state *state, list_t *bindings,
53 uint32_t modifiers, 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 }
64 } 59 }
65} 60 for (int i = 0; i < bindings->length; ++i) {
61 struct sway_binding *binding = bindings->items[i];
66 62
67static void pressed_keysyms_update(xkb_keysym_t *pressed_keysyms, 63 if (modifiers ^ binding->modifiers ||
68 const xkb_keysym_t *keysyms, size_t keysyms_len, 64 npressed_keys != binding->keys->length ||
69 enum wlr_key_state state) { 65 locked > binding->locked) {
70 for (size_t i = 0; i < keysyms_len; ++i) {
71 if (keysym_is_modifier(keysyms[i])) {
72 continue; 66 continue;
73 } 67 }
74 if (state == WLR_KEY_PRESSED) { 68
75 pressed_keysyms_add(pressed_keysyms, keysyms[i]); 69 bool match = true;
76 } else { // WLR_KEY_RELEASED 70 for (int j = 0; j < binding->keys->length; ++j) {
77 pressed_keysyms_remove(pressed_keysyms, keysyms[i]); 71 uint32_t key = *(uint32_t *)binding->keys->items[j];
72
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;
82 break;
83 }
78 } 84 }
79 }
80}
81 85
82static bool binding_matches_key_state(struct sway_binding *binding, 86 if (match) {
83 enum wlr_key_state key_state) { 87 return binding;
84 if (key_state == WLR_KEY_PRESSED && !binding->release) { 88 }
85 return true;
86 }
87 if (key_state == WLR_KEY_RELEASED && binding->release) {
88 return true;
89 } 89 }
90 90
91 return false; 91 return NULL;
92} 92}
93 93
94/**
95 * Execute the command associated to a binding
96 */
94static void keyboard_execute_command(struct sway_keyboard *keyboard, 97static void keyboard_execute_command(struct sway_keyboard *keyboard,
95 struct sway_binding *binding) { 98 struct sway_binding *binding) {
96 wlr_log(L_DEBUG, "running command for binding: %s", 99 wlr_log(L_DEBUG, "running command for binding: %s",
@@ -113,7 +116,7 @@ static void keyboard_execute_command(struct sway_keyboard *keyboard,
113 * should be propagated to clients. 116 * should be propagated to clients.
114 */ 117 */
115static bool keyboard_execute_compositor_binding(struct sway_keyboard *keyboard, 118static bool keyboard_execute_compositor_binding(struct sway_keyboard *keyboard,
116 xkb_keysym_t *pressed_keysyms, uint32_t modifiers, size_t keysyms_len) { 119 const xkb_keysym_t *pressed_keysyms, uint32_t modifiers, size_t keysyms_len) {
117 for (size_t i = 0; i < keysyms_len; ++i) { 120 for (size_t i = 0; i < keysyms_len; ++i) {
118 xkb_keysym_t keysym = pressed_keysyms[i]; 121 xkb_keysym_t keysym = pressed_keysyms[i];
119 if (keysym >= XKB_KEY_XF86Switch_VT_1 && 122 if (keysym >= XKB_KEY_XF86Switch_VT_1 &&
@@ -134,157 +137,6 @@ static bool keyboard_execute_compositor_binding(struct sway_keyboard *keyboard,
134} 137}
135 138
136/** 139/**
137 * Execute keyboard bindings bound with `bindysm` for the given keyboard state.
138 *
139 * Returns true if the keysym was handled by a binding and false if the event
140 * should be propagated to clients.
141 */
142static bool keyboard_execute_bindsym(struct sway_keyboard *keyboard,
143 xkb_keysym_t *pressed_keysyms, uint32_t modifiers,
144 enum wlr_key_state key_state, bool locked) {
145 // configured bindings
146 int n = pressed_keysyms_length(pressed_keysyms);
147 list_t *keysym_bindings = config->current_mode->keysym_bindings;
148 for (int i = 0; i < keysym_bindings->length; ++i) {
149 struct sway_binding *binding = keysym_bindings->items[i];
150 if (!binding_matches_key_state(binding, key_state) ||
151 modifiers ^ binding->modifiers ||
152 n != binding->keys->length || locked > binding->locked) {
153 continue;
154 }
155
156 bool match = true;
157 for (int j = 0; j < binding->keys->length; ++j) {
158 match =
159 pressed_keysyms_index(pressed_keysyms,
160 *(int*)binding->keys->items[j]) >= 0;
161
162 if (!match) {
163 break;
164 }
165 }
166
167 if (match) {
168 keyboard_execute_command(keyboard, binding);
169 return true;
170 }
171 }
172
173 return false;
174}
175
176static bool binding_matches_keycodes(struct wlr_keyboard *keyboard,
177 struct sway_binding *binding, struct wlr_event_keyboard_key *event, bool locked) {
178 assert(binding->bindcode);
179
180 uint32_t keycode = event->keycode + 8;
181
182 if (!binding_matches_key_state(binding, event->state)) {
183 return false;
184 }
185
186 if (locked > binding->locked) {
187 return false;
188 }
189
190 uint32_t modifiers = wlr_keyboard_get_modifiers(keyboard);
191 if (modifiers ^ binding->modifiers) {
192 return false;
193 }
194
195 // on release, the released key must be in the binding
196 if (event->state == WLR_KEY_RELEASED) {
197 bool found = false;
198 for (int i = 0; i < binding->keys->length; ++i) {
199 uint32_t binding_keycode = *(uint32_t*)binding->keys->items[i] + 8;
200 if (binding_keycode == keycode) {
201 found = true;
202 break;
203 }
204 }
205 if (!found) {
206 return false;
207 }
208 }
209
210 // every keycode in the binding must be present in the pressed keys on the
211 // keyboard
212 for (int i = 0; i < binding->keys->length; ++i) {
213 uint32_t binding_keycode = *(uint32_t*)binding->keys->items[i] + 8;
214 if (event->state == WLR_KEY_RELEASED && keycode == binding_keycode) {
215 continue;
216 }
217
218 bool found = false;
219 for (size_t j = 0; j < keyboard->num_keycodes; ++j) {
220 xkb_keycode_t keycode = keyboard->keycodes[j] + 8;
221 if (keycode == binding_keycode) {
222 found = true;
223 break;
224 }
225 }
226
227 if (!found) {
228 return false;
229 }
230 }
231
232 // every keycode pressed on the keyboard must be present within the binding
233 // keys (unless it is a modifier)
234 for (size_t i = 0; i < keyboard->num_keycodes; ++i) {
235 xkb_keycode_t keycode = keyboard->keycodes[i] + 8;
236 bool found = false;
237 for (int j = 0; j < binding->keys->length; ++j) {
238 uint32_t binding_keycode = *(uint32_t*)binding->keys->items[j] + 8;
239 if (binding_keycode == keycode) {
240 found = true;
241 break;
242 }
243 }
244
245 if (!found) {
246 if (!binding->modifiers) {
247 return false;
248 }
249
250 // check if it is a modifier, which we know matched from the check
251 // above
252 const xkb_keysym_t *keysyms;
253 int num_keysyms =
254 xkb_state_key_get_syms(keyboard->xkb_state,
255 keycode, &keysyms);
256 if (num_keysyms != 1 || !keysym_is_modifier(keysyms[0])) {
257 return false;
258 }
259 }
260 }
261
262 return true;
263}
264
265/**
266 * Execute keyboard bindings bound with `bindcode` for the given keyboard state.
267 *
268 * Returns true if the keysym was handled by a binding and false if the event
269 * should be propagated to clients.
270 */
271static bool keyboard_execute_bindcode(struct sway_keyboard *keyboard,
272 struct wlr_event_keyboard_key *event, bool locked) {
273 struct wlr_keyboard *wlr_keyboard =
274 keyboard->seat_device->input_device->wlr_device->keyboard;
275 list_t *keycode_bindings = config->current_mode->keycode_bindings;
276 for (int i = 0; i < keycode_bindings->length; ++i) {
277 struct sway_binding *binding = keycode_bindings->items[i];
278 if (binding_matches_keycodes(wlr_keyboard, binding, event, locked)) {
279 keyboard_execute_command(keyboard, binding);
280 return true;
281 }
282 }
283
284 return false;
285}
286
287/**
288 * Get keysyms and modifiers from the keyboard as xkb sees them. 140 * Get keysyms and modifiers from the keyboard as xkb sees them.
289 * 141 *
290 * This uses the xkb keysyms translation based on pressed modifiers and clears 142 * This uses the xkb keysyms translation based on pressed modifiers and clears
@@ -339,61 +191,96 @@ static void handle_keyboard_key(struct wl_listener *listener, void *data) {
339 struct wlr_event_keyboard_key *event = data; 191 struct wlr_event_keyboard_key *event = data;
340 bool input_inhibited = keyboard->seat_device->sway_seat->exclusive_client != NULL; 192 bool input_inhibited = keyboard->seat_device->sway_seat->exclusive_client != NULL;
341 193
194 // Identify new keycode, raw keysym(s), and translated keysym(s)
342 xkb_keycode_t keycode = event->keycode + 8; 195 xkb_keycode_t keycode = event->keycode + 8;
343 bool handled = false;
344 196
345 // handle keycodes
346 handled = keyboard_execute_bindcode(keyboard, event, input_inhibited);
347
348 // handle translated keysyms
349 if (!handled && event->state == WLR_KEY_RELEASED) {
350 handled = keyboard_execute_bindsym(keyboard,
351 keyboard->pressed_keysyms_translated,
352 keyboard->modifiers_translated,
353 event->state, input_inhibited);
354 }
355 const xkb_keysym_t *translated_keysyms; 197 const xkb_keysym_t *translated_keysyms;
198 uint32_t translated_modifiers;
356 size_t translated_keysyms_len = 199 size_t translated_keysyms_len =
357 keyboard_keysyms_translated(keyboard, keycode, &translated_keysyms, 200 keyboard_keysyms_translated(keyboard, keycode, &translated_keysyms,
358 &keyboard->modifiers_translated); 201 &translated_modifiers);
359 pressed_keysyms_update(keyboard->pressed_keysyms_translated,
360 translated_keysyms, translated_keysyms_len, event->state);
361 if (!handled && event->state == WLR_KEY_PRESSED) {
362 handled = keyboard_execute_bindsym(keyboard,
363 keyboard->pressed_keysyms_translated,
364 keyboard->modifiers_translated,
365 event->state, input_inhibited);
366 }
367 202
368 // Handle raw keysyms
369 if (!handled && event->state == WLR_KEY_RELEASED) {
370 handled = keyboard_execute_bindsym(keyboard,
371 keyboard->pressed_keysyms_raw, keyboard->modifiers_raw,
372 event->state, input_inhibited);
373 }
374 const xkb_keysym_t *raw_keysyms; 203 const xkb_keysym_t *raw_keysyms;
204 uint32_t raw_modifiers;
375 size_t raw_keysyms_len = 205 size_t raw_keysyms_len =
376 keyboard_keysyms_raw(keyboard, keycode, &raw_keysyms, &keyboard->modifiers_raw); 206 keyboard_keysyms_raw(keyboard, keycode, &raw_keysyms, &raw_modifiers);
377 pressed_keysyms_update(keyboard->pressed_keysyms_raw, raw_keysyms, 207
378 raw_keysyms_len, event->state); 208 struct wlr_input_device *device =
379 if (!handled && event->state == WLR_KEY_PRESSED) { 209 keyboard->seat_device->input_device->wlr_device;
380 handled = keyboard_execute_bindsym(keyboard, 210 uint32_t code_modifiers = wlr_keyboard_get_modifiers(device->keyboard);
381 keyboard->pressed_keysyms_raw, keyboard->modifiers_raw, 211
382 event->state, input_inhibited); 212 bool last_key_was_a_modifier = code_modifiers != keyboard->last_modifiers;
213 keyboard->last_modifiers = code_modifiers;
214
215 // Update shortcut model state
216 update_shortcut_state(&keyboard->state_keycodes, event,
217 (uint32_t)keycode, last_key_was_a_modifier);
218 for (size_t i = 0; i < translated_keysyms_len; ++i) {
219 update_shortcut_state(&keyboard->state_keysyms_translated,
220 event, (uint32_t)translated_keysyms[i],
221 last_key_was_a_modifier && i == 0);
222 }
223 for (size_t i = 0; i < raw_keysyms_len; ++i) {
224 update_shortcut_state(&keyboard->state_keysyms_raw,
225 event, (uint32_t)raw_keysyms[i],
226 last_key_was_a_modifier && i == 0);
227 }
228
229 // identify which binding should be executed.
230 struct sway_binding *binding = get_active_binding(
231 &keyboard->state_keycodes,
232 config->current_mode->keycode_bindings,
233 code_modifiers, input_inhibited);
234 struct sway_binding *translated_binding = get_active_binding(
235 &keyboard->state_keysyms_translated,
236 config->current_mode->keysym_bindings,
237 translated_modifiers, input_inhibited);
238 if (translated_binding && !binding) {
239 binding = translated_binding;
240 } else if (binding && translated_binding && binding != translated_binding) {
241 wlr_log(L_DEBUG, "encountered duplicate bindings %d and %d",
242 binding->order, translated_binding->order);
243 }
244 struct sway_binding *raw_binding = get_active_binding(
245 &keyboard->state_keysyms_raw,
246 config->current_mode->keysym_bindings,
247 raw_modifiers, input_inhibited);
248 if (raw_binding && !binding) {
249 binding = raw_binding;
250 } else if (binding && raw_binding && binding != raw_binding) {
251 wlr_log(L_DEBUG, "encountered duplicate bindings %d and %d",
252 binding->order, raw_binding->order);
253 }
254
255 bool handled = false;
256
257 // Execute the identified binding if need be.
258 if (keyboard->held_binding && binding != keyboard->held_binding &&
259 event->state == WLR_KEY_RELEASED) {
260 keyboard_execute_command(keyboard, keyboard->held_binding);
261 handled = true;
262 }
263 if (binding != keyboard->held_binding) {
264 keyboard->held_binding = NULL;
265 }
266 if (binding && event->state == WLR_KEY_PRESSED) {
267 if (binding->release) {
268 keyboard->held_binding = binding;
269 } else {
270 keyboard_execute_command(keyboard, binding);
271 handled = true;
272 }
383 } 273 }
384 274
385 // Compositor bindings 275 // Compositor bindings
386 if (!handled && event->state == WLR_KEY_PRESSED) { 276 if (!handled && event->state == WLR_KEY_PRESSED) {
387 handled = 277 handled = keyboard_execute_compositor_binding(
388 keyboard_execute_compositor_binding(keyboard, 278 keyboard, translated_keysyms, translated_modifiers,
389 keyboard->pressed_keysyms_translated,
390 keyboard->modifiers_translated,
391 translated_keysyms_len); 279 translated_keysyms_len);
392 } 280 }
393 if (!handled && event->state == WLR_KEY_PRESSED) { 281 if (!handled && event->state == WLR_KEY_PRESSED) {
394 handled = 282 handled = keyboard_execute_compositor_binding(
395 keyboard_execute_compositor_binding(keyboard, 283 keyboard, raw_keysyms, raw_modifiers,
396 keyboard->pressed_keysyms_raw, keyboard->modifiers_raw,
397 raw_keysyms_len); 284 raw_keysyms_len);
398 } 285 }
399 286
@@ -429,6 +316,10 @@ struct sway_keyboard *sway_keyboard_create(struct sway_seat *seat,
429 wl_list_init(&keyboard->keyboard_key.link); 316 wl_list_init(&keyboard->keyboard_key.link);
430 wl_list_init(&keyboard->keyboard_modifiers.link); 317 wl_list_init(&keyboard->keyboard_modifiers.link);
431 318
319 keyboard->state_keycodes.last_key_index = -1;
320 keyboard->state_keysyms_raw.last_key_index = -1;
321 keyboard->state_keysyms_translated.last_key_index = -1;
322
432 return keyboard; 323 return keyboard;
433} 324}
434 325