summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/sway/config.h3
-rw-r--r--include/sway/input/keyboard.h8
-rw-r--r--sway/commands.c2
-rw-r--r--sway/commands/bind.c245
-rw-r--r--sway/config.c3
-rw-r--r--sway/input/keyboard.c384
-rw-r--r--sway/meson.build1
7 files changed, 641 insertions, 5 deletions
diff --git a/include/sway/config.h b/include/sway/config.h
index eecdde3a..405092e3 100644
--- a/include/sway/config.h
+++ b/include/sway/config.h
@@ -46,7 +46,8 @@ struct sway_mouse_binding {
46 */ 46 */
47struct sway_mode { 47struct sway_mode {
48 char *name; 48 char *name;
49 list_t *bindings; 49 list_t *keysym_bindings;
50 list_t *keycode_bindings;
50}; 51};
51 52
52/** 53/**
diff --git a/include/sway/input/keyboard.h b/include/sway/input/keyboard.h
index d9251f4c..8ec3eb35 100644
--- a/include/sway/input/keyboard.h
+++ b/include/sway/input/keyboard.h
@@ -3,6 +3,8 @@
3 3
4#include "sway/input/seat.h" 4#include "sway/input/seat.h"
5 5
6#define SWAY_KEYBOARD_PRESSED_KEYSYMS_CAP 32
7
6struct sway_keyboard { 8struct sway_keyboard {
7 struct sway_seat_device *seat_device; 9 struct sway_seat_device *seat_device;
8 10
@@ -10,6 +12,12 @@ struct sway_keyboard {
10 12
11 struct wl_listener keyboard_key; 13 struct wl_listener keyboard_key;
12 struct wl_listener keyboard_modifiers; 14 struct wl_listener keyboard_modifiers;
15
16 xkb_keysym_t pressed_keysyms_translated[SWAY_KEYBOARD_PRESSED_KEYSYMS_CAP];
17 uint32_t modifiers_translated;
18
19 xkb_keysym_t pressed_keysyms_raw[SWAY_KEYBOARD_PRESSED_KEYSYMS_CAP];
20 uint32_t modifiers_raw;
13}; 21};
14 22
15struct sway_keyboard *sway_keyboard_create(struct sway_seat *seat, 23struct sway_keyboard *sway_keyboard_create(struct sway_seat *seat,
diff --git a/sway/commands.c b/sway/commands.c
index 34afb6a0..b0078a46 100644
--- a/sway/commands.c
+++ b/sway/commands.c
@@ -127,6 +127,8 @@ struct cmd_results *add_color(const char *name, char *buffer, const char *color)
127 127
128/* Keep alphabetized */ 128/* Keep alphabetized */
129static struct cmd_handler handlers[] = { 129static struct cmd_handler handlers[] = {
130 { "bindcode", cmd_bindcode },
131 { "bindsym", cmd_bindsym },
130 { "exec", cmd_exec }, 132 { "exec", cmd_exec },
131 { "exec_always", cmd_exec_always }, 133 { "exec_always", cmd_exec_always },
132 { "exit", cmd_exit }, 134 { "exit", cmd_exit },
diff --git a/sway/commands/bind.c b/sway/commands/bind.c
new file mode 100644
index 00000000..79121404
--- /dev/null
+++ b/sway/commands/bind.c
@@ -0,0 +1,245 @@
1#ifdef __linux__
2#include <linux/input-event-codes.h>
3#elif __FreeBSD__
4#include <dev/evdev/input-event-codes.h>
5#endif
6#include <xkbcommon/xkbcommon.h>
7#include <xkbcommon/xkbcommon-names.h>
8#include <strings.h>
9#include "sway/commands.h"
10#include "sway/config.h"
11#include "list.h"
12#include "log.h"
13#include "stringop.h"
14#include "util.h"
15
16int binding_order = 0;
17
18void free_sway_binding(struct sway_binding *binding) {
19 if (!binding) {
20 return;
21 }
22
23 if (binding->keys) {
24 free_flat_list(binding->keys);
25 }
26 free(binding->command);
27 free(binding);
28}
29
30/**
31 * Returns true if the bindings have the same key and modifier combinations.
32 * Note that keyboard layout is not considered, so the bindings might actually
33 * not be equivalent on some layouts.
34 */
35bool binding_key_compare(struct sway_binding *binding_a,
36 struct sway_binding *binding_b) {
37 if (binding_a->release != binding_b->release) {
38 return false;
39 }
40
41 if (binding_a->bindcode != binding_b->bindcode) {
42 return false;
43 }
44
45 if (binding_a->modifiers ^ binding_b->modifiers) {
46 return false;
47 }
48
49 if (binding_a->keys->length != binding_b->keys->length) {
50 return false;
51 }
52
53 int keys_len = binding_a->keys->length;
54 for (int i = 0; i < keys_len; ++i) {
55 uint32_t key_a = *(uint32_t*)binding_a->keys->items[i];
56 bool found = false;
57 for (int j = 0; j < keys_len; ++j) {
58 uint32_t key_b = *(uint32_t*)binding_b->keys->items[j];
59 if (key_b == key_a) {
60 found = true;
61 break;
62 }
63 }
64 if (!found) {
65 return false;
66 }
67 }
68
69 return true;
70}
71
72struct cmd_results *cmd_bindsym(int argc, char **argv) {
73 struct cmd_results *error = NULL;
74 if ((error = checkarg(argc, "bindsym", EXPECTED_MORE_THAN, 1))) {
75 return error;
76 }
77
78 struct sway_binding *binding = calloc(1, sizeof(struct sway_binding));
79 if (!binding) {
80 return cmd_results_new(CMD_FAILURE, "bindsym",
81 "Unable to allocate binding");
82 }
83 binding->keys = create_list();
84 binding->modifiers = 0;
85 binding->release = false;
86 binding->bindcode = false;
87
88 // Handle --release
89 if (strcmp("--release", argv[0]) == 0) {
90 if (argc >= 3) {
91 binding->release = true;
92 argv++;
93 argc--;
94 } else {
95 free_sway_binding(binding);
96 return cmd_results_new(CMD_FAILURE, "bindsym",
97 "Invalid bindsym command "
98 "(expected more than 2 arguments, got %d)", argc);
99 }
100 }
101
102 binding->command = join_args(argv + 1, argc - 1);
103
104 list_t *split = split_string(argv[0], "+");
105 for (int i = 0; i < split->length; ++i) {
106 // Check for a modifier key
107 uint32_t mod;
108 if ((mod = get_modifier_mask_by_name(split->items[i])) > 0) {
109 binding->modifiers |= mod;
110 continue;
111 }
112 // Check for xkb key
113 xkb_keysym_t sym = xkb_keysym_from_name(split->items[i],
114 XKB_KEYSYM_CASE_INSENSITIVE);
115
116 // Check for mouse binding
117 if (strncasecmp(split->items[i], "button", strlen("button")) == 0 &&
118 strlen(split->items[i]) == strlen("button0")) {
119 sym = ((char *)split->items[i])[strlen("button")] - '1' + BTN_LEFT;
120 }
121 if (!sym) {
122 struct cmd_results *ret = cmd_results_new(CMD_INVALID, "bindsym",
123 "Unknown key '%s'", (char *)split->items[i]);
124 free_sway_binding(binding);
125 free_flat_list(split);
126 return ret;
127 }
128 xkb_keysym_t *key = calloc(1, sizeof(xkb_keysym_t));
129 if (!key) {
130 free_sway_binding(binding);
131 free_flat_list(split);
132 return cmd_results_new(CMD_FAILURE, "bindsym",
133 "Unable to allocate binding");
134 }
135 *key = sym;
136 list_add(binding->keys, key);
137 }
138 free_flat_list(split);
139 binding->order = binding_order++;
140
141 list_t *mode_bindings = config->current_mode->keysym_bindings;
142
143 // overwrite the binding if it already exists
144 bool overwritten = false;
145 for (int i = 0; i < mode_bindings->length; ++i) {
146 struct sway_binding *config_binding = mode_bindings->items[i];
147 if (binding_key_compare(binding, config_binding)) {
148 sway_log(L_DEBUG, "overwriting old binding with command '%s'",
149 config_binding->command);
150 free_sway_binding(config_binding);
151 mode_bindings->items[i] = binding;
152 overwritten = true;
153 }
154 }
155
156 if (!overwritten) {
157 list_add(mode_bindings, binding);
158 }
159
160 sway_log(L_DEBUG, "bindsym - Bound %s to command %s",
161 argv[0], binding->command);
162 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
163}
164
165struct cmd_results *cmd_bindcode(int argc, char **argv) {
166 struct cmd_results *error = NULL;
167 if ((error = checkarg(argc, "bindcode", EXPECTED_MORE_THAN, 1))) {
168 return error;
169 }
170
171 struct sway_binding *binding = calloc(1, sizeof(struct sway_binding));
172 if (!binding) {
173 return cmd_results_new(CMD_FAILURE, "bindsym",
174 "Unable to allocate binding");
175 }
176 binding->keys = create_list();
177 binding->modifiers = 0;
178 binding->release = false;
179 binding->bindcode = true;
180
181 // Handle --release
182 if (strcmp("--release", argv[0]) == 0) {
183 if (argc >= 3) {
184 binding->release = true;
185 argv++;
186 argc--;
187 } else {
188 free_sway_binding(binding);
189 return cmd_results_new(CMD_FAILURE, "bindcode",
190 "Invalid bindcode command "
191 "(expected more than 2 arguments, got %d)", argc);
192 }
193 }
194
195 binding->command = join_args(argv + 1, argc - 1);
196
197 list_t *split = split_string(argv[0], "+");
198 for (int i = 0; i < split->length; ++i) {
199 // Check for a modifier key
200 uint32_t mod;
201 if ((mod = get_modifier_mask_by_name(split->items[i])) > 0) {
202 binding->modifiers |= mod;
203 continue;
204 }
205 // parse keycode
206 xkb_keycode_t keycode = (int)strtol(split->items[i], NULL, 10);
207 if (!xkb_keycode_is_legal_ext(keycode)) {
208 error =
209 cmd_results_new(CMD_INVALID, "bindcode",
210 "Invalid keycode '%s'", (char *)split->items[i]);
211 free_sway_binding(binding);
212 list_free(split);
213 return error;
214 }
215 xkb_keycode_t *key = calloc(1, sizeof(xkb_keycode_t));
216 *key = keycode - 8;
217 list_add(binding->keys, key);
218 }
219 free_flat_list(split);
220
221 binding->order = binding_order++;
222
223 list_t *mode_bindings = config->current_mode->keycode_bindings;
224
225 // overwrite the binding if it already exists
226 bool overwritten = false;
227 for (int i = 0; i < mode_bindings->length; ++i) {
228 struct sway_binding *config_binding = mode_bindings->items[i];
229 if (binding_key_compare(binding, config_binding)) {
230 sway_log(L_DEBUG, "overwriting old binding with command '%s'",
231 config_binding->command);
232 free_sway_binding(config_binding);
233 mode_bindings->items[i] = binding;
234 overwritten = true;
235 }
236 }
237
238 if (!overwritten) {
239 list_add(mode_bindings, binding);
240 }
241
242 sway_log(L_DEBUG, "bindcode - Bound %s to command %s",
243 argv[0], binding->command);
244 return cmd_results_new(CMD_SUCCESS, NULL, NULL);
245}
diff --git a/sway/config.c b/sway/config.c
index b591ae9e..312e0779 100644
--- a/sway/config.c
+++ b/sway/config.c
@@ -53,7 +53,8 @@ static void config_defaults(struct sway_config *config) {
53 goto cleanup; 53 goto cleanup;
54 if (!(config->current_mode->name = malloc(sizeof("default")))) goto cleanup; 54 if (!(config->current_mode->name = malloc(sizeof("default")))) goto cleanup;
55 strcpy(config->current_mode->name, "default"); 55 strcpy(config->current_mode->name, "default");
56 if (!(config->current_mode->bindings = create_list())) goto cleanup; 56 if (!(config->current_mode->keysym_bindings = create_list())) goto cleanup;
57 if (!(config->current_mode->keycode_bindings = create_list())) goto cleanup;
57 list_add(config->modes, config->current_mode); 58 list_add(config->modes, config->current_mode);
58 59
59 config->floating_mod = 0; 60 config->floating_mod = 0;
diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c
index 724941d8..c2bb2578 100644
--- a/sway/input/keyboard.c
+++ b/sway/input/keyboard.c
@@ -1,8 +1,325 @@
1#include <assert.h>
2#include <wlr/backend/multi.h>
3#include <wlr/backend/session.h>
1#include "sway/input/seat.h" 4#include "sway/input/seat.h"
2#include "sway/input/keyboard.h" 5#include "sway/input/keyboard.h"
3#include "sway/input/input-manager.h" 6#include "sway/input/input-manager.h"
7#include "sway/commands.h"
4#include "log.h" 8#include "log.h"
5 9
10static bool keysym_is_modifier(xkb_keysym_t keysym) {
11 switch (keysym) {
12 case XKB_KEY_Shift_L: case XKB_KEY_Shift_R:
13 case XKB_KEY_Control_L: case XKB_KEY_Control_R:
14 case XKB_KEY_Caps_Lock:
15 case XKB_KEY_Shift_Lock:
16 case XKB_KEY_Meta_L: case XKB_KEY_Meta_R:
17 case XKB_KEY_Alt_L: case XKB_KEY_Alt_R:
18 case XKB_KEY_Super_L: case XKB_KEY_Super_R:
19 case XKB_KEY_Hyper_L: case XKB_KEY_Hyper_R:
20 return true;
21 default:
22 return false;
23 }
24}
25
26static size_t pressed_keysyms_length(xkb_keysym_t *pressed_keysyms) {
27 size_t n = 0;
28 for (size_t i = 0; i < SWAY_KEYBOARD_PRESSED_KEYSYMS_CAP; ++i) {
29 if (pressed_keysyms[i] != XKB_KEY_NoSymbol) {
30 ++n;
31 }
32 }
33 return n;
34}
35
36static ssize_t pressed_keysyms_index(xkb_keysym_t *pressed_keysyms,
37 xkb_keysym_t keysym) {
38 for (size_t i = 0; i < SWAY_KEYBOARD_PRESSED_KEYSYMS_CAP; ++i) {
39 if (pressed_keysyms[i] == keysym) {
40 return i;
41 }
42 }
43 return -1;
44}
45
46static void pressed_keysyms_add(xkb_keysym_t *pressed_keysyms,
47 xkb_keysym_t keysym) {
48 ssize_t i = pressed_keysyms_index(pressed_keysyms, keysym);
49 if (i < 0) {
50 i = pressed_keysyms_index(pressed_keysyms, XKB_KEY_NoSymbol);
51 if (i >= 0) {
52 pressed_keysyms[i] = keysym;
53 }
54 }
55}
56
57static void pressed_keysyms_remove(xkb_keysym_t *pressed_keysyms,
58 xkb_keysym_t keysym) {
59 ssize_t i = pressed_keysyms_index(pressed_keysyms, keysym);
60 if (i >= 0) {
61 pressed_keysyms[i] = XKB_KEY_NoSymbol;
62 }
63}
64
65static void pressed_keysyms_update(xkb_keysym_t *pressed_keysyms,
66 const xkb_keysym_t *keysyms, size_t keysyms_len,
67 enum wlr_key_state state) {
68 for (size_t i = 0; i < keysyms_len; ++i) {
69 if (keysym_is_modifier(keysyms[i])) {
70 continue;
71 }
72 if (state == WLR_KEY_PRESSED) {
73 pressed_keysyms_add(pressed_keysyms, keysyms[i]);
74 } else { // WLR_KEY_RELEASED
75 pressed_keysyms_remove(pressed_keysyms, keysyms[i]);
76 }
77 }
78}
79
80static bool binding_matches_key_state(struct sway_binding *binding,
81 enum wlr_key_state key_state) {
82 if (key_state == WLR_KEY_PRESSED && !binding->release) {
83 return true;
84 }
85 if (key_state == WLR_KEY_RELEASED && binding->release) {
86 return true;
87 }
88
89 return false;
90}
91
92static void binding_execute_command(struct sway_binding *binding) {
93 sway_log(L_DEBUG, "running command for binding: %s",
94 binding->command);
95 struct cmd_results *results = handle_command(binding->command);
96 if (results->status != CMD_SUCCESS) {
97 sway_log(L_DEBUG, "could not run command for binding: %s",
98 binding->command);
99 }
100 free_cmd_results(results);
101}
102
103/**
104 * Execute a built-in, hardcoded compositor binding. These are triggered from a
105 * single keysym.
106 *
107 * Returns true if the keysym was handled by a binding and false if the event
108 * should be propagated to clients.
109 */
110static bool keyboard_execute_compositor_binding(struct sway_keyboard *keyboard,
111 xkb_keysym_t *pressed_keysyms, uint32_t modifiers, size_t keysyms_len) {
112 for (size_t i = 0; i < keysyms_len; ++i) {
113 xkb_keysym_t keysym = pressed_keysyms[i];
114 if (keysym >= XKB_KEY_XF86Switch_VT_1 &&
115 keysym <= XKB_KEY_XF86Switch_VT_12) {
116 if (wlr_backend_is_multi(server.backend)) {
117 struct wlr_session *session =
118 wlr_multi_get_session(server.backend);
119 if (session) {
120 unsigned vt = keysym - XKB_KEY_XF86Switch_VT_1 + 1;
121 wlr_session_change_vt(session, vt);
122 }
123 }
124 return true;
125 }
126 }
127
128 return false;
129}
130
131/**
132 * Execute keyboard bindings bound with `bindysm` for the given keyboard state.
133 *
134 * Returns true if the keysym was handled by a binding and false if the event
135 * should be propagated to clients.
136 */
137static bool keyboard_execute_bindsym(struct sway_keyboard *keyboard,
138 xkb_keysym_t *pressed_keysyms, uint32_t modifiers,
139 enum wlr_key_state key_state) {
140 // configured bindings
141 int n = pressed_keysyms_length(pressed_keysyms);
142 list_t *keysym_bindings = config->current_mode->keysym_bindings;
143 for (int i = 0; i < keysym_bindings->length; ++i) {
144 struct sway_binding *binding = keysym_bindings->items[i];
145 if (!binding_matches_key_state(binding, key_state) ||
146 modifiers ^ binding->modifiers ||
147 n != binding->keys->length) {
148 continue;
149 }
150
151 bool match = true;
152 for (int j = 0; j < binding->keys->length; ++j) {
153 match =
154 pressed_keysyms_index(pressed_keysyms,
155 *(int*)binding->keys->items[j]) >= 0;
156
157 if (!match) {
158 break;
159 }
160 }
161
162 if (match) {
163 binding_execute_command(binding);
164 return true;
165 }
166 }
167
168 return false;
169}
170
171static bool binding_matches_keycodes(struct wlr_keyboard *keyboard,
172 struct sway_binding *binding, struct wlr_event_keyboard_key *event) {
173 assert(binding->bindcode);
174
175 uint32_t keycode = event->keycode + 8;
176
177 if (!binding_matches_key_state(binding, event->state)) {
178 return false;
179 }
180
181 uint32_t modifiers = wlr_keyboard_get_modifiers(keyboard);
182 if (modifiers ^ binding->modifiers) {
183 return false;
184 }
185
186 // on release, the released key must be in the binding
187 if (event->state == WLR_KEY_RELEASED) {
188 bool found = false;
189 for (int i = 0; i < binding->keys->length; ++i) {
190 uint32_t binding_keycode = *(uint32_t*)binding->keys->items[i] + 8;
191 if (binding_keycode == keycode) {
192 found = true;
193 break;
194 }
195 }
196 if (!found) {
197 return false;
198 }
199 }
200
201 // every keycode in the binding must be present in the pressed keys on the
202 // keyboard
203 for (int i = 0; i < binding->keys->length; ++i) {
204 uint32_t binding_keycode = *(uint32_t*)binding->keys->items[i] + 8;
205 if (event->state == WLR_KEY_RELEASED && keycode == binding_keycode) {
206 continue;
207 }
208
209 bool found = false;
210 for (size_t j = 0; j < keyboard->num_keycodes; ++j) {
211 xkb_keycode_t keycode = keyboard->keycodes[j] + 8;
212 if (keycode == binding_keycode) {
213 found = true;
214 break;
215 }
216 }
217
218 if (!found) {
219 return false;
220 }
221 }
222
223 // every keycode pressed on the keyboard must be present within the binding
224 // keys (unless it is a modifier)
225 for (size_t i = 0; i < keyboard->num_keycodes; ++i) {
226 xkb_keycode_t keycode = keyboard->keycodes[i] + 8;
227 bool found = false;
228 for (int j = 0; j < binding->keys->length; ++j) {
229 uint32_t binding_keycode = *(uint32_t*)binding->keys->items[j] + 8;
230 if (binding_keycode == keycode) {
231 found = true;
232 break;
233 }
234 }
235
236 if (!found) {
237 if (!binding->modifiers) {
238 return false;
239 }
240
241 // check if it is a modifier, which we know matched from the check
242 // above
243 const xkb_keysym_t *keysyms;
244 int num_keysyms =
245 xkb_state_key_get_syms(keyboard->xkb_state,
246 keycode, &keysyms);
247 if (num_keysyms != 1 || !keysym_is_modifier(keysyms[0])) {
248 return false;
249 }
250 }
251 }
252
253 return true;
254}
255
256/**
257 * Execute keyboard bindings bound with `bindcode` for the given keyboard state.
258 *
259 * Returns true if the keysym was handled by a binding and false if the event
260 * should be propagated to clients.
261 */
262static bool keyboard_execute_bindcode(struct sway_keyboard *keyboard,
263 struct wlr_event_keyboard_key *event) {
264 struct wlr_keyboard *wlr_keyboard =
265 keyboard->seat_device->input_device->wlr_device->keyboard;
266 list_t *keycode_bindings = config->current_mode->keycode_bindings;
267 for (int i = 0; i < keycode_bindings->length; ++i) {
268 struct sway_binding *binding = keycode_bindings->items[i];
269 if (binding_matches_keycodes(wlr_keyboard, binding, event)) {
270 binding_execute_command(binding);
271 return true;
272 }
273 }
274
275 return false;
276}
277
278/**
279 * Get keysyms and modifiers from the keyboard as xkb sees them.
280 *
281 * This uses the xkb keysyms translation based on pressed modifiers and clears
282 * the consumed modifiers from the list of modifiers passed to keybind
283 * detection.
284 *
285 * On US layout, pressing Alt+Shift+2 will trigger Alt+@.
286 */
287static size_t keyboard_keysyms_translated(struct sway_keyboard *keyboard,
288 xkb_keycode_t keycode, const xkb_keysym_t **keysyms,
289 uint32_t *modifiers) {
290 struct wlr_input_device *device =
291 keyboard->seat_device->input_device->wlr_device;
292 *modifiers = wlr_keyboard_get_modifiers(device->keyboard);
293 xkb_mod_mask_t consumed = xkb_state_key_get_consumed_mods2(
294 device->keyboard->xkb_state, keycode, XKB_CONSUMED_MODE_XKB);
295 *modifiers = *modifiers & ~consumed;
296
297 return xkb_state_key_get_syms(device->keyboard->xkb_state,
298 keycode, keysyms);
299}
300
301/**
302 * Get keysyms and modifiers from the keyboard as if modifiers didn't change
303 * keysyms.
304 *
305 * This avoids the xkb keysym translation based on modifiers considered pressed
306 * in the state.
307 *
308 * This will trigger keybinds such as Alt+Shift+2.
309 */
310static size_t keyboard_keysyms_raw(struct sway_keyboard *keyboard,
311 xkb_keycode_t keycode, const xkb_keysym_t **keysyms,
312 uint32_t *modifiers) {
313 struct wlr_input_device *device =
314 keyboard->seat_device->input_device->wlr_device;
315 *modifiers = wlr_keyboard_get_modifiers(device->keyboard);
316
317 xkb_layout_index_t layout_index = xkb_state_key_get_layout(
318 device->keyboard->xkb_state, keycode);
319 return xkb_keymap_key_get_syms_by_level(device->keyboard->keymap,
320 keycode, layout_index, 0, keysyms);
321}
322
6static void handle_keyboard_key(struct wl_listener *listener, void *data) { 323static void handle_keyboard_key(struct wl_listener *listener, void *data) {
7 struct sway_keyboard *keyboard = 324 struct sway_keyboard *keyboard =
8 wl_container_of(listener, keyboard, keyboard_key); 325 wl_container_of(listener, keyboard, keyboard_key);
@@ -10,9 +327,70 @@ static void handle_keyboard_key(struct wl_listener *listener, void *data) {
10 struct wlr_input_device *wlr_device = 327 struct wlr_input_device *wlr_device =
11 keyboard->seat_device->input_device->wlr_device; 328 keyboard->seat_device->input_device->wlr_device;
12 struct wlr_event_keyboard_key *event = data; 329 struct wlr_event_keyboard_key *event = data;
13 wlr_seat_set_keyboard(wlr_seat, wlr_device); 330
14 wlr_seat_keyboard_notify_key(wlr_seat, event->time_msec, 331 xkb_keycode_t keycode = event->keycode + 8;
15 event->keycode, event->state); 332 bool handled = false;
333
334 // handle keycodes
335 handled = keyboard_execute_bindcode(keyboard, event);
336
337 // handle translated keysyms
338 if (!handled && event->state == WLR_KEY_RELEASED) {
339 handled = keyboard_execute_bindsym(keyboard,
340 keyboard->pressed_keysyms_translated,
341 keyboard->modifiers_translated,
342 event->state);
343 }
344 const xkb_keysym_t *translated_keysyms;
345 size_t translated_keysyms_len =
346 keyboard_keysyms_translated(keyboard, keycode, &translated_keysyms,
347 &keyboard->modifiers_translated);
348 pressed_keysyms_update(keyboard->pressed_keysyms_translated,
349 translated_keysyms, translated_keysyms_len, event->state);
350 if (!handled && event->state == WLR_KEY_PRESSED) {
351 handled = keyboard_execute_bindsym(keyboard,
352 keyboard->pressed_keysyms_translated,
353 keyboard->modifiers_translated,
354 event->state);
355 }
356
357 // Handle raw keysyms
358 if (!handled && event->state == WLR_KEY_RELEASED) {
359 handled = keyboard_execute_bindsym(keyboard,
360 keyboard->pressed_keysyms_raw, keyboard->modifiers_raw,
361 event->state);
362 }
363 const xkb_keysym_t *raw_keysyms;
364 size_t raw_keysyms_len =
365 keyboard_keysyms_raw(keyboard, keycode, &raw_keysyms, &keyboard->modifiers_raw);
366 pressed_keysyms_update(keyboard->pressed_keysyms_raw, raw_keysyms,
367 raw_keysyms_len, event->state);
368 if (!handled && event->state == WLR_KEY_PRESSED) {
369 handled = keyboard_execute_bindsym(keyboard,
370 keyboard->pressed_keysyms_raw, keyboard->modifiers_raw,
371 event->state);
372 }
373
374 // Compositor bindings
375 if (!handled && event->state == WLR_KEY_PRESSED) {
376 handled =
377 keyboard_execute_compositor_binding(keyboard,
378 keyboard->pressed_keysyms_translated,
379 keyboard->modifiers_translated,
380 translated_keysyms_len);
381 }
382 if (!handled && event->state == WLR_KEY_PRESSED) {
383 handled =
384 keyboard_execute_compositor_binding(keyboard,
385 keyboard->pressed_keysyms_raw, keyboard->modifiers_raw,
386 raw_keysyms_len);
387 }
388
389 if (!handled || event->state == WLR_KEY_RELEASED) {
390 wlr_seat_set_keyboard(wlr_seat, wlr_device);
391 wlr_seat_keyboard_notify_key(wlr_seat, event->time_msec,
392 event->keycode, event->state);
393 }
16} 394}
17 395
18static void handle_keyboard_modifiers(struct wl_listener *listener, 396static void handle_keyboard_modifiers(struct wl_listener *listener,
diff --git a/sway/meson.build b/sway/meson.build
index fee2ddd2..01d5ef36 100644
--- a/sway/meson.build
+++ b/sway/meson.build
@@ -6,6 +6,7 @@ sway_sources = files(
6 'input/seat.c', 6 'input/seat.c',
7 'input/cursor.c', 7 'input/cursor.c',
8 'input/keyboard.c', 8 'input/keyboard.c',
9 'commands/bind.c',
9 'commands/exit.c', 10 'commands/exit.c',
10 'commands/exec.c', 11 'commands/exec.c',
11 'commands/exec_always.c', 12 'commands/exec_always.c',