diff --git a/src/bindings.c b/src/bindings.c index 7cbded92..fb758d12 100644 --- a/src/bindings.c +++ b/src/bindings.c @@ -75,6 +75,24 @@ weston_compositor_add_key_binding(struct weston_compositor *compositor, return binding; } +WL_EXPORT struct weston_binding * +weston_compositor_add_modifier_binding(struct weston_compositor *compositor, + uint32_t modifier, + weston_modifier_binding_handler_t handler, + void *data) +{ + struct weston_binding *binding; + + binding = weston_compositor_add_binding(compositor, 0, 0, 0, + modifier, handler, data); + if (binding == NULL) + return NULL; + + wl_list_insert(compositor->modifier_binding_list.prev, &binding->link); + + return binding; +} + WL_EXPORT struct weston_binding * weston_compositor_add_button_binding(struct weston_compositor *compositor, uint32_t button, uint32_t modifier, @@ -248,6 +266,10 @@ weston_compositor_run_key_binding(struct weston_compositor *compositor, if (state == WL_KEYBOARD_KEY_STATE_RELEASED) return; + /* Invalidate all active modifier bindings. */ + wl_list_for_each(b, &compositor->modifier_binding_list, link) + b->key = key; + wl_list_for_each(b, &compositor->key_binding_list, link) { if (b->key == key && b->modifier == seat->modifier_state) { weston_key_binding_handler_t handler = b->handler; @@ -263,6 +285,34 @@ weston_compositor_run_key_binding(struct weston_compositor *compositor, } } +WL_EXPORT void +weston_compositor_run_modifier_binding(struct weston_compositor *compositor, + struct weston_seat *seat, + enum weston_keyboard_modifier modifier, + enum wl_keyboard_key_state state) +{ + struct weston_binding *b; + + wl_list_for_each(b, &compositor->modifier_binding_list, link) { + weston_modifier_binding_handler_t handler = b->handler; + + if (b->modifier != modifier) + continue; + + /* Prime the modifier binding. */ + if (state == WL_KEYBOARD_KEY_STATE_PRESSED) { + b->key = 0; + continue; + } + /* Ignore the binding if a key was pressed in between. */ + else if (b->key != 0) { + return; + } + + handler(seat, modifier, b->data); + } +} + WL_EXPORT void weston_compositor_run_button_binding(struct weston_compositor *compositor, struct weston_seat *seat, @@ -274,6 +324,10 @@ weston_compositor_run_button_binding(struct weston_compositor *compositor, if (state == WL_POINTER_BUTTON_STATE_RELEASED) return; + /* Invalidate all active modifier bindings. */ + wl_list_for_each(b, &compositor->modifier_binding_list, link) + b->key = button; + wl_list_for_each(b, &compositor->button_binding_list, link) { if (b->button == button && b->modifier == seat->modifier_state) { weston_button_binding_handler_t handler = b->handler; @@ -308,6 +362,10 @@ weston_compositor_run_axis_binding(struct weston_compositor *compositor, { struct weston_binding *b; + /* Invalidate all active modifier bindings. */ + wl_list_for_each(b, &compositor->modifier_binding_list, link) + b->key = axis; + wl_list_for_each(b, &compositor->axis_binding_list, link) { if (b->axis == axis && b->modifier == seat->modifier_state) { weston_axis_binding_handler_t handler = b->handler; diff --git a/src/compositor.c b/src/compositor.c index b8e0c6e6..cca81708 100644 --- a/src/compositor.c +++ b/src/compositor.c @@ -3331,6 +3331,7 @@ weston_compositor_init(struct weston_compositor *ec, wl_list_init(&ec->seat_list); wl_list_init(&ec->output_list); wl_list_init(&ec->key_binding_list); + wl_list_init(&ec->modifier_binding_list); wl_list_init(&ec->button_binding_list); wl_list_init(&ec->touch_binding_list); wl_list_init(&ec->axis_binding_list); diff --git a/src/compositor.h b/src/compositor.h index 2ceac2d3..ea53f3f9 100644 --- a/src/compositor.h +++ b/src/compositor.h @@ -579,6 +579,7 @@ struct weston_compositor { struct wl_list view_list; struct wl_list plane_list; struct wl_list key_binding_list; + struct wl_list modifier_binding_list; struct wl_list button_binding_list; struct wl_list touch_binding_list; struct wl_list axis_binding_list; @@ -1015,6 +1016,15 @@ weston_compositor_add_key_binding(struct weston_compositor *compositor, weston_key_binding_handler_t binding, void *data); +typedef void (*weston_modifier_binding_handler_t)(struct weston_seat *seat, + enum weston_keyboard_modifier modifier, + void *data); +struct weston_binding * +weston_compositor_add_modifier_binding(struct weston_compositor *compositor, + enum weston_keyboard_modifier modifier, + weston_modifier_binding_handler_t binding, + void *data); + typedef void (*weston_button_binding_handler_t)(struct weston_seat *seat, uint32_t time, uint32_t button, void *data); @@ -1059,6 +1069,12 @@ weston_compositor_run_key_binding(struct weston_compositor *compositor, struct weston_seat *seat, uint32_t time, uint32_t key, enum wl_keyboard_key_state state); + +void +weston_compositor_run_modifier_binding(struct weston_compositor *compositor, + struct weston_seat *seat, + enum weston_keyboard_modifier modifier, + enum wl_keyboard_key_state state); void weston_compositor_run_button_binding(struct weston_compositor *compositor, struct weston_seat *seat, uint32_t time, diff --git a/src/input.c b/src/input.c index 159049e6..fc93f884 100644 --- a/src/input.c +++ b/src/input.c @@ -759,6 +759,41 @@ notify_motion(struct weston_seat *seat, pointer->grab->interface->motion(pointer->grab, time, pointer->x + dx, pointer->y + dy); } +static void +run_modifier_bindings(struct weston_seat *seat, uint32_t old, uint32_t new) +{ + struct weston_compositor *compositor = seat->compositor; + uint32_t diff; + unsigned int i; + struct { + uint32_t xkb; + enum weston_keyboard_modifier weston; + } mods[] = { + { seat->xkb_info->ctrl_mod, MODIFIER_CTRL }, + { seat->xkb_info->alt_mod, MODIFIER_ALT }, + { seat->xkb_info->super_mod, MODIFIER_SUPER }, + { seat->xkb_info->shift_mod, MODIFIER_SHIFT }, + }; + + diff = new & ~old; + for (i = 0; i < ARRAY_LENGTH(mods); i++) { + if (diff & (1 << mods[i].xkb)) + weston_compositor_run_modifier_binding(compositor, + seat, + mods[i].weston, + WL_KEYBOARD_KEY_STATE_PRESSED); + } + + diff = old & ~new; + for (i = 0; i < ARRAY_LENGTH(mods); i++) { + if (diff & (1 << mods[i].xkb)) + weston_compositor_run_modifier_binding(compositor, + seat, + mods[i].weston, + WL_KEYBOARD_KEY_STATE_RELEASED); + } +} + WL_EXPORT void notify_motion_absolute(struct weston_seat *seat, uint32_t time, wl_fixed_t x, wl_fixed_t y) @@ -878,6 +913,9 @@ notify_modifiers(struct weston_seat *seat, uint32_t serial) group != seat->keyboard->modifiers.group) changed = 1; + run_modifier_bindings(seat, seat->keyboard->modifiers.mods_depressed, + mods_depressed); + seat->keyboard->modifiers.mods_depressed = mods_depressed; seat->keyboard->modifiers.mods_latched = mods_latched; seat->keyboard->modifiers.mods_locked = mods_locked;