1/* swc: swc/bindings.c
2 *
3 * Copyright (c) 2013 Michael Forney
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 */
23
24#include "bindings.h"
25#include "internal.h"
26#include "keyboard.h"
27#include "pointer.h"
28#include "seat.h"
29#include "swc.h"
30#include "util.h"
31
32#include <errno.h>
33#include <wayland-util.h>
34#include <xkbcommon/xkbcommon.h>
35
36struct binding {
37 uint32_t value;
38 uint32_t modifiers;
39 swc_binding_handler handler;
40 void *data;
41};
42
43struct axis_binding {
44 uint32_t axis;
45 uint32_t modifiers;
46 swc_axis_binding_handler handler;
47 void *data;
48};
49
50static bool
51handle_key(struct keyboard *keyboard, uint32_t time, struct key *key,
52 uint32_t state);
53
54static struct keyboard_handler key_binding_handler = {
55 .key = handle_key,
56};
57
58static bool
59handle_button(struct pointer_handler *handler, uint32_t time,
60 struct button *button, uint32_t state);
61static bool
62handle_axis(struct pointer_handler *handler, uint32_t time,
63 enum wl_pointer_axis axis, enum wl_pointer_axis_source source,
64 wl_fixed_t value, int value120);
65
66static struct pointer_handler button_binding_handler = {
67 .button = handle_button,
68 .axis = handle_axis,
69};
70
71static struct wl_array key_bindings, button_bindings, axis_bindings;
72
73const struct swc_bindings swc_bindings = {
74 .keyboard_handler = &key_binding_handler,
75 .pointer_handler = &button_binding_handler,
76};
77
78static struct binding *
79find_binding(struct wl_array *bindings, uint32_t modifiers, uint32_t value)
80{
81 struct binding *binding;
82
83 wl_array_for_each(binding, bindings)
84 {
85 if (binding->value == value && (binding->modifiers == modifiers ||
86 binding->modifiers == SWC_MOD_ANY)) {
87 return binding;
88 }
89 }
90
91 return NULL;
92}
93
94static struct binding *
95find_key_binding(uint32_t modifiers, uint32_t key)
96{
97 struct binding *binding;
98 struct xkb *xkb = &swc.seat->keyboard->xkb;
99 xkb_keysym_t keysym;
100
101 /* First try the keysym the keymap generates in it's current state. */
102 keysym = xkb_state_key_get_one_sym(xkb->state, XKB_KEY(key));
103 binding = find_binding(&key_bindings, modifiers, keysym);
104
105 if (binding) {
106 return binding;
107 }
108
109 xkb_layout_index_t layout;
110 const xkb_keysym_t *keysyms;
111
112 /* Then try the keysym associated with shift-level 0 for the key. */
113 layout = xkb_state_key_get_layout(xkb->state, XKB_KEY(key));
114 xkb_keymap_key_get_syms_by_level(xkb->keymap.map, XKB_KEY(key), layout, 0,
115 &keysyms);
116
117 if (!keysyms) {
118 return NULL;
119 }
120
121 binding = find_binding(&key_bindings, modifiers, keysyms[0]);
122
123 return binding;
124}
125
126static struct binding *
127find_button_binding(uint32_t modifiers, uint32_t value)
128{
129 return find_binding(&button_bindings, modifiers, value);
130}
131
132static struct axis_binding *
133find_axis_binding(uint32_t modifiers, uint32_t axis)
134{
135 struct axis_binding *binding;
136
137 wl_array_for_each(binding, &axis_bindings)
138 {
139 if (binding->axis == axis && (binding->modifiers == modifiers ||
140 binding->modifiers == SWC_MOD_ANY)) {
141 return binding;
142 }
143 }
144
145 return NULL;
146}
147
148static bool
149handle_binding(uint32_t time, struct press *press, uint32_t state,
150 struct binding *(*find_binding)(uint32_t, uint32_t))
151{
152 struct binding *binding;
153 uint32_t modifiers =
154 swc.seat && swc.seat->keyboard ? swc.seat->keyboard->modifiers : 0;
155
156 if (state) {
157 binding = find_binding(modifiers, press->value);
158
159 if (!binding) {
160 return false;
161 }
162
163 press->data = binding;
164 } else {
165 binding = press->data;
166 }
167
168 binding->handler(binding->data, time, binding->value, state);
169
170 return true;
171}
172
173bool
174handle_key(struct keyboard *keyboard, uint32_t time, struct key *key,
175 uint32_t state)
176{
177 return handle_binding(time, &key->press, state, &find_key_binding);
178}
179
180bool
181handle_button(struct pointer_handler *handler, uint32_t time,
182 struct button *button, uint32_t state)
183{
184 return handle_binding(time, &button->press, state, &find_button_binding);
185}
186
187bool
188handle_axis(struct pointer_handler *handler, uint32_t time,
189 enum wl_pointer_axis axis, enum wl_pointer_axis_source source,
190 wl_fixed_t value, int value120)
191{
192 (void)handler;
193 (void)source;
194
195 uint32_t modifiers =
196 swc.seat && swc.seat->keyboard ? swc.seat->keyboard->modifiers : 0;
197 struct axis_binding *binding = find_axis_binding(modifiers, axis);
198 int32_t delta120 = value120;
199
200 if (!binding || !binding->handler) {
201 return false;
202 }
203
204 if (!delta120 && value) {
205 delta120 = (int32_t)(wl_fixed_to_double(value) * 120.0);
206 if (!delta120) {
207 delta120 = value > 0 ? 1 : -1;
208 }
209 }
210
211 binding->handler(binding->data, time, axis, delta120);
212 return true;
213}
214
215bool
216bindings_initialize(void)
217{
218 wl_array_init(&key_bindings);
219 wl_array_init(&button_bindings);
220 wl_array_init(&axis_bindings);
221
222 return true;
223}
224
225void
226bindings_finalize(void)
227{
228 wl_array_release(&key_bindings);
229 wl_array_release(&button_bindings);
230 wl_array_release(&axis_bindings);
231}
232
233EXPORT int
234swc_add_binding(enum swc_binding_type type, uint32_t modifiers, uint32_t value,
235 swc_binding_handler handler, void *data)
236{
237 struct binding *binding;
238 struct wl_array *bindings;
239
240 switch (type) {
241 case SWC_BINDING_KEY:
242 bindings = &key_bindings;
243 break;
244 case SWC_BINDING_BUTTON:
245 bindings = &button_bindings;
246 break;
247 default:
248 return -EINVAL;
249 }
250
251 if (!(binding = wl_array_add(bindings, sizeof(*binding)))) {
252 return -ENOMEM;
253 }
254
255 binding->value = value;
256 binding->modifiers = modifiers;
257 binding->handler = handler;
258 binding->data = data;
259
260 return 0;
261}
262
263EXPORT void
264swc_remove_binding(enum swc_binding_type type, uint32_t modifiers,
265 uint32_t value)
266{
267 struct wl_array *bindings;
268 switch (type) {
269 case SWC_BINDING_KEY:
270 bindings = &key_bindings;
271 break;
272 case SWC_BINDING_BUTTON:
273 bindings = &button_bindings;
274 break;
275 default:
276 return;
277 }
278
279 struct binding *b = find_binding(bindings, modifiers, value);
280 if (!b) {
281 return;
282 }
283
284 struct binding *last = (struct binding *)((char *)bindings->data +
285 bindings->size - sizeof(*b));
286 if (b != last) {
287 *b = *last;
288 }
289 bindings->size -= sizeof(*b);
290}
291
292EXPORT int
293swc_add_axis_binding(uint32_t modifiers, uint32_t axis,
294 swc_axis_binding_handler handler, void *data)
295{
296 struct axis_binding *binding;
297
298 if (!(binding = wl_array_add(&axis_bindings, sizeof(*binding)))) {
299 return -ENOMEM;
300 }
301
302 binding->axis = axis;
303 binding->modifiers = modifiers;
304 binding->handler = handler;
305 binding->data = data;
306
307 return 0;
308}