swc

Unnamed repository; edit this file 'description' to name the repository.
git clone git://git.nihaljere.xyz/swc
Log | Files | Refs | README | LICENSE

commit 6d459f092046fafa194821984738391b63ee2db3
parent ce14c7287b3a8e3c90ef2ecf153b08d975b299b2
Author: Michael Forney <mforney@mforney.org>
Date:   Wed, 26 Feb 2014 20:57:59 -0800

Properly support binding key releases

Now, the keyboard keeps track of a single array of keys pressed, similar
to th pointer, and the client handler keeps track of an array of keys to
be sent on enter.

This way, we can keep track of the binding used when a key is invoked,
in order to ensure that the same binding is invoked when the key is
released.

Diffstat:
Mlibswc/bindings.c | 70++++++++++++++++++++++++++++++++++++++++++++++++++--------------------
Mlibswc/input.h | 1+
Mlibswc/keyboard.c | 97++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------------
Mlibswc/keyboard.h | 11+++++++++--
4 files changed, 124 insertions(+), 55 deletions(-)

diff --git a/libswc/bindings.c b/libswc/bindings.c @@ -23,7 +23,9 @@ #include "swc.h" #include "bindings.h" +#include "internal.h" #include "keyboard.h" +#include "seat.h" #include "util.h" #include <wayland-util.h> @@ -37,7 +39,7 @@ struct binding }; static bool handle_key(struct keyboard * keyboard, uint32_t time, - uint32_t key, uint32_t state); + struct press * press, uint32_t state); static struct keyboard_handler binding_handler = { .key = &handle_key, @@ -49,51 +51,79 @@ const struct swc_bindings swc_bindings = { .keyboard_handler = &binding_handler }; -static bool handle_binding(struct wl_array * bindings, uint32_t time, - uint32_t modifiers, uint32_t value, uint32_t state) +static struct binding * find_binding(struct wl_array * bindings, + uint32_t modifiers, uint32_t value) { struct binding * binding; wl_array_for_each(binding, bindings) { - if (binding->value == value - && (binding->modifiers == modifiers - || binding->modifiers == SWC_MOD_ANY)) + if (binding->value == value && (binding->modifiers == modifiers + || binding->modifiers == SWC_MOD_ANY)) { - binding->handler(binding->data, time, value, state); - return true; + return binding; } } - return false; + return NULL; } -bool handle_key(struct keyboard * keyboard, uint32_t time, - uint32_t key, uint32_t state) +static struct binding * find_key_binding(uint32_t modifiers, uint32_t key) { + struct binding * binding; + struct swc_xkb * xkb = &swc.seat->keyboard->xkb; xkb_keysym_t keysym; /* First try the keysym the keymap generates in it's current state. */ - keysym = xkb_state_key_get_one_sym(keyboard->xkb.state, XKB_KEY(key)); + keysym = xkb_state_key_get_one_sym(xkb->state, XKB_KEY(key)); + binding = find_binding(&key_bindings, modifiers, keysym); - if (handle_binding(&key_bindings, time, keyboard->modifiers, keysym, state)) - return true; + if (binding) + return binding; xkb_layout_index_t layout; const xkb_keysym_t * keysyms; /* Then try the keysym associated with shift-level 0 for the key. */ - layout = xkb_state_key_get_layout(keyboard->xkb.state, XKB_KEY(key)); - xkb_keymap_key_get_syms_by_level(keyboard->xkb.keymap.map, XKB_KEY(key), + layout = xkb_state_key_get_layout(xkb->state, XKB_KEY(key)); + xkb_keymap_key_get_syms_by_level(xkb->keymap.map, XKB_KEY(key), layout, 0, &keysyms); - if (keysyms && handle_binding(&key_bindings, time, - keyboard->modifiers, keysyms[0], state)) + if (!keysyms) + return NULL; + + binding = find_binding(&key_bindings, modifiers, keysyms[0]); + + return binding; +} + +static bool handle_binding + (uint32_t time, struct press * press, uint32_t state, + struct binding * (* find_binding)(uint32_t, uint32_t)) +{ + struct binding * binding; + + if (state) { - return true; + binding = find_binding(swc.seat->keyboard->modifiers, press->value); + + if (!binding) + return false; + + press->data = binding; } + else + binding = press->data; + + binding->handler(binding->data, time, binding->value, state); + + return true; +} - return false; +bool handle_key(struct keyboard * keyboard, uint32_t time, + struct press * key, uint32_t state) +{ + return handle_binding(time, key, state, &find_key_binding); } bool swc_bindings_initialize() diff --git a/libswc/input.h b/libswc/input.h @@ -83,6 +83,7 @@ struct press { uint32_t value; uint32_t serial; + void * data; }; /* }}} */ diff --git a/libswc/keyboard.c b/libswc/keyboard.c @@ -43,7 +43,7 @@ static void enter(struct input_focus_handler * handler, serial = wl_display_next_serial(swc.display); wl_keyboard_send_enter(resource, serial, view->surface->resource, - &keyboard->client_handler.keys); + &keyboard->client_keys); } static void leave(struct input_focus_handler * handler, @@ -56,19 +56,37 @@ static void leave(struct input_focus_handler * handler, } static bool client_handle_key(struct keyboard * keyboard, uint32_t time, - uint32_t key, uint32_t state) + struct press * press, uint32_t state) { - struct wl_client * client; - struct wl_display * display; - uint32_t serial; + uint32_t * client_key; - if (!keyboard->focus.resource) - return true; + if (state == WL_KEYBOARD_KEY_STATE_PRESSED) + { + client_key = wl_array_add(&keyboard->client_keys, sizeof *client_key); - client = wl_resource_get_client(keyboard->focus.resource); - display = wl_client_get_display(client); - serial = wl_display_next_serial(display); - wl_keyboard_send_key(keyboard->focus.resource, serial, time, key, state); + if (!client_key) + return false; + + *client_key = press->value; + } + else + { + wl_array_for_each(client_key, &keyboard->client_keys) + { + if (*client_key == press->value) + { + swc_array_remove(&keyboard->client_keys, + client_key, sizeof *client_key); + break; + } + } + } + + if (keyboard->focus.resource) + { + wl_keyboard_send_key(keyboard->focus.resource, press->serial, time, + press->value, state); + } return true; } @@ -110,7 +128,8 @@ bool keyboard_initialize(struct keyboard * keyboard) keyboard->focus_handler.leave = &leave; keyboard->client_handler.key = &client_handle_key; keyboard->client_handler.modifiers = &client_handle_modifiers; - wl_array_init(&keyboard->client_handler.keys); + wl_array_init(&keyboard->client_keys); + wl_array_init(&keyboard->keys); wl_list_init(&keyboard->handlers); wl_list_insert(&keyboard->handlers, &keyboard->client_handler.link); @@ -124,7 +143,8 @@ bool keyboard_initialize(struct keyboard * keyboard) void keyboard_finalize(struct keyboard * keyboard) { - wl_array_release(&keyboard->client_handler.keys); + wl_array_release(&keyboard->client_keys); + wl_array_release(&keyboard->keys); input_focus_finalize(&keyboard->focus); swc_xkb_finalize(&keyboard->xkb); } @@ -163,41 +183,52 @@ struct wl_resource * keyboard_bind(struct keyboard * keyboard, } void keyboard_handle_key(struct keyboard * keyboard, uint32_t time, - uint32_t key, uint32_t state) + uint32_t value, uint32_t state) { - uint32_t * pressed_key; + struct key * key; struct keyboard_modifier_state modifier_state; enum xkb_key_direction direction; struct swc_xkb * xkb = &keyboard->xkb; struct keyboard_handler * handler; + uint32_t serial; - /* First handle key events associated with a particular handler. */ - wl_list_for_each(handler, &keyboard->handlers, link) + serial = wl_display_next_serial(swc.display); + + /* First handle key release events associated with a particular handler. */ + wl_array_for_each(key, &keyboard->keys) { - wl_array_for_each(pressed_key, &handler->keys) + if (key->press.value == value) { - if (*pressed_key == key) + /* Ignore repeat events. */ + if (state == WL_KEYBOARD_KEY_STATE_PRESSED) + return; + + if (key->handler) { - /* Ignore repeat events. */ - if (state == WL_KEYBOARD_KEY_STATE_PRESSED) - return; - - swc_array_remove(&handler->keys, - pressed_key, sizeof *pressed_key); - if (handler->key) - handler->key(keyboard, time, key, state); - goto update_xkb_state; + key->press.serial = serial; + key->handler->key(keyboard, time, &key->press, state); } + + swc_array_remove(&keyboard->keys, key, sizeof *key); + goto update_xkb_state; } } - /* Go through handlers again to see if any will accept this key event. */ + key = wl_array_add(&keyboard->keys, sizeof *key); + + if (!key) + goto update_xkb_state; + + key->press.value = value; + key->press.serial = serial; + key->handler = NULL; + + /* Go through handlers to see if any will accept this key event. */ wl_list_for_each(handler, &keyboard->handlers, link) { - if (handler->key && handler->key(keyboard, time, key, state)) + if (handler->key && handler->key(keyboard, time, &key->press, state)) { - pressed_key = wl_array_add(&handler->keys, sizeof *pressed_key); - *pressed_key = key; + key->handler = handler; break; } } @@ -206,7 +237,7 @@ void keyboard_handle_key(struct keyboard * keyboard, uint32_t time, update_xkb_state: direction = state == WL_KEYBOARD_KEY_STATE_PRESSED ? XKB_KEY_DOWN : XKB_KEY_UP; - xkb_state_update_key(xkb->state, XKB_KEY(key), direction); + xkb_state_update_key(xkb->state, XKB_KEY(value), direction); modifier_state.depressed = xkb_state_serialize_mods(xkb->state, XKB_STATE_DEPRESSED); diff --git a/libswc/keyboard.h b/libswc/keyboard.h @@ -33,6 +33,12 @@ struct keyboard; struct wl_client; +struct key +{ + struct press press; + struct keyboard_handler * handler; +}; + struct keyboard_modifier_state { uint32_t depressed; @@ -44,11 +50,10 @@ struct keyboard_modifier_state struct keyboard_handler { bool (* key)(struct keyboard * keyboard, uint32_t time, - uint32_t key, uint32_t state); + struct press * press, uint32_t state); bool (* modifiers)(struct keyboard * keyboard, const struct keyboard_modifier_state * state); - struct wl_array keys; struct wl_list link; }; @@ -58,8 +63,10 @@ struct keyboard struct input_focus_handler focus_handler; struct swc_xkb xkb; + struct wl_array keys; struct wl_list handlers; struct keyboard_handler client_handler; + struct wl_array client_keys; struct keyboard_modifier_state modifier_state; uint32_t modifiers;