aboutsummaryrefslogtreecommitdiffstats
path: root/sway/input/keyboard.c
diff options
context:
space:
mode:
authorLibravatar Tony Crisci <tony@dubstepdish.com>2017-12-27 13:20:28 -0500
committerLibravatar Tony Crisci <tony@dubstepdish.com>2017-12-27 13:20:28 -0500
commiteea80e7276f49e5d07b22db071f3ab0b6f9ffe18 (patch)
tree539c9f313ae2d38123f654de63cd77bd462b80de /sway/input/keyboard.c
parentbinding config (diff)
downloadsway-eea80e7276f49e5d07b22db071f3ab0b6f9ffe18.tar.gz
sway-eea80e7276f49e5d07b22db071f3ab0b6f9ffe18.tar.zst
sway-eea80e7276f49e5d07b22db071f3ab0b6f9ffe18.zip
keyboard translate keysyms
Diffstat (limited to 'sway/input/keyboard.c')
-rw-r--r--sway/input/keyboard.c147
1 files changed, 144 insertions, 3 deletions
diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c
index 724941d8..25def7ac 100644
--- a/sway/input/keyboard.c
+++ b/sway/input/keyboard.c
@@ -3,6 +3,121 @@
3#include "sway/input/input-manager.h" 3#include "sway/input/input-manager.h"
4#include "log.h" 4#include "log.h"
5 5
6/*
7 * Get keysyms and modifiers from the keyboard as xkb sees them.
8 *
9 * This uses the xkb keysyms translation based on pressed modifiers and clears
10 * the consumed modifiers from the list of modifiers passed to keybind
11 * detection.
12 *
13 * On US layout, pressing Alt+Shift+2 will trigger Alt+@.
14 */
15static size_t keyboard_keysyms_translated(struct sway_keyboard *keyboard,
16 xkb_keycode_t keycode, const xkb_keysym_t **keysyms,
17 uint32_t *modifiers) {
18 struct wlr_input_device *device =
19 keyboard->seat_device->input_device->wlr_device;
20 *modifiers = wlr_keyboard_get_modifiers(device->keyboard);
21 xkb_mod_mask_t consumed = xkb_state_key_get_consumed_mods2(
22 device->keyboard->xkb_state, keycode, XKB_CONSUMED_MODE_XKB);
23 *modifiers = *modifiers & ~consumed;
24
25 return xkb_state_key_get_syms(device->keyboard->xkb_state,
26 keycode, keysyms);
27}
28
29/*
30 * Get keysyms and modifiers from the keyboard as if modifiers didn't change
31 * keysyms.
32 *
33 * This avoids the xkb keysym translation based on modifiers considered pressed
34 * in the state.
35 *
36 * This will trigger keybinds such as Alt+Shift+2.
37 */
38static size_t keyboard_keysyms_raw(struct sway_keyboard *keyboard,
39 xkb_keycode_t keycode, const xkb_keysym_t **keysyms,
40 uint32_t *modifiers) {
41 struct wlr_input_device *device =
42 keyboard->seat_device->input_device->wlr_device;
43 *modifiers = wlr_keyboard_get_modifiers(device->keyboard);
44
45 xkb_layout_index_t layout_index = xkb_state_key_get_layout(
46 device->keyboard->xkb_state, keycode);
47 return xkb_keymap_key_get_syms_by_level(device->keyboard->keymap,
48 keycode, layout_index, 0, keysyms);
49}
50
51static ssize_t pressed_keysyms_index(xkb_keysym_t *pressed_keysyms,
52 xkb_keysym_t keysym) {
53 for (size_t i = 0; i < SWAY_KEYBOARD_PRESSED_KEYSYMS_CAP; ++i) {
54 if (pressed_keysyms[i] == keysym) {
55 return i;
56 }
57 }
58 return -1;
59}
60
61static size_t pressed_keysyms_length(xkb_keysym_t *pressed_keysyms) {
62 size_t n = 0;
63 for (size_t i = 0; i < SWAY_KEYBOARD_PRESSED_KEYSYMS_CAP; ++i) {
64 if (pressed_keysyms[i] != XKB_KEY_NoSymbol) {
65 ++n;
66 }
67 }
68 return n;
69}
70
71static void pressed_keysyms_add(xkb_keysym_t *pressed_keysyms,
72 xkb_keysym_t keysym) {
73 ssize_t i = pressed_keysyms_index(pressed_keysyms, keysym);
74 if (i < 0) {
75 i = pressed_keysyms_index(pressed_keysyms, XKB_KEY_NoSymbol);
76 if (i >= 0) {
77 pressed_keysyms[i] = keysym;
78 }
79 }
80}
81
82static void pressed_keysyms_remove(xkb_keysym_t *pressed_keysyms,
83 xkb_keysym_t keysym) {
84 ssize_t i = pressed_keysyms_index(pressed_keysyms, keysym);
85 if (i >= 0) {
86 pressed_keysyms[i] = XKB_KEY_NoSymbol;
87 }
88}
89
90static bool keysym_is_modifier(xkb_keysym_t keysym) {
91 switch (keysym) {
92 case XKB_KEY_Shift_L: case XKB_KEY_Shift_R:
93 case XKB_KEY_Control_L: case XKB_KEY_Control_R:
94 case XKB_KEY_Caps_Lock:
95 case XKB_KEY_Shift_Lock:
96 case XKB_KEY_Meta_L: case XKB_KEY_Meta_R:
97 case XKB_KEY_Alt_L: case XKB_KEY_Alt_R:
98 case XKB_KEY_Super_L: case XKB_KEY_Super_R:
99 case XKB_KEY_Hyper_L: case XKB_KEY_Hyper_R:
100 return true;
101 default:
102 return false;
103 }
104}
105
106static void pressed_keysyms_update(xkb_keysym_t *pressed_keysyms,
107 const xkb_keysym_t *keysyms, size_t keysyms_len,
108 enum wlr_key_state state) {
109 for (size_t i = 0; i < keysyms_len; ++i) {
110 if (keysym_is_modifier(keysyms[i])) {
111 continue;
112 }
113 if (state == WLR_KEY_PRESSED) {
114 pressed_keysyms_add(pressed_keysyms, keysyms[i]);
115 } else { // WLR_KEY_RELEASED
116 pressed_keysyms_remove(pressed_keysyms, keysyms[i]);
117 }
118 }
119}
120
6static void handle_keyboard_key(struct wl_listener *listener, void *data) { 121static void handle_keyboard_key(struct wl_listener *listener, void *data) {
7 struct sway_keyboard *keyboard = 122 struct sway_keyboard *keyboard =
8 wl_container_of(listener, keyboard, keyboard_key); 123 wl_container_of(listener, keyboard, keyboard_key);
@@ -10,9 +125,35 @@ static void handle_keyboard_key(struct wl_listener *listener, void *data) {
10 struct wlr_input_device *wlr_device = 125 struct wlr_input_device *wlr_device =
11 keyboard->seat_device->input_device->wlr_device; 126 keyboard->seat_device->input_device->wlr_device;
12 struct wlr_event_keyboard_key *event = data; 127 struct wlr_event_keyboard_key *event = data;
13 wlr_seat_set_keyboard(wlr_seat, wlr_device); 128
14 wlr_seat_keyboard_notify_key(wlr_seat, event->time_msec, 129 xkb_keycode_t keycode = event->keycode + 8;
15 event->keycode, event->state); 130 bool handled = false;
131 uint32_t modifiers;
132 const xkb_keysym_t *keysyms;
133 size_t keysyms_len;
134
135 // handle translated keysyms
136 keysyms_len = keyboard_keysyms_translated(keyboard, keycode, &keysyms,
137 &modifiers);
138 pressed_keysyms_update(keyboard->pressed_keysyms_translated, keysyms,
139 keysyms_len, event->state);
140 if (event->state == WLR_KEY_PRESSED) {
141 // TODO execute binding
142 }
143
144 // Handle raw keysyms
145 keysyms_len = keyboard_keysyms_raw(keyboard, keycode, &keysyms, &modifiers);
146 pressed_keysyms_update(keyboard->pressed_keysyms_raw, keysyms, keysyms_len,
147 event->state);
148 if (event->state == WLR_KEY_PRESSED && !handled) {
149 // TODO execute binding
150 }
151
152 if (!handled) {
153 wlr_seat_set_keyboard(wlr_seat, wlr_device);
154 wlr_seat_keyboard_notify_key(wlr_seat, event->time_msec,
155 event->keycode, event->state);
156 }
16} 157}
17 158
18static void handle_keyboard_modifiers(struct wl_listener *listener, 159static void handle_keyboard_modifiers(struct wl_listener *listener,