main neuswc / libswc / bindings.c
  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}