[PATCH v2] input: don't send to clients key events eaten by bindings

Giulio Camuffo giuliocamuffo at gmail.com
Thu Nov 6 09:55:33 PST 2014


weston key bindings are supposed to eat the key events, and not pass it
on to clients, and indeed the wl_keyboard.key event is not sent. But
we must also not put the key in the keys array to pass to client with
the wl_keyboard.enter event, or else we may send the 'eaten' one too.
In the case of a key binding hiding a surface having the keyboard focus,
the shell may decide to give the focus to another surface, but that will
happen before the key is released, so the new focus surface will receive
the code of the bound key in the wl_keyboard.enter array.
---


v2: made sure not to insert the same key in the keys array multiple times

 src/bindings.c   |  7 +++++--
 src/compositor.h |  3 ++-
 src/input.c      | 48 ++++++++++++++++++++++++++++++++----------------
 3 files changed, 39 insertions(+), 19 deletions(-)

diff --git a/src/bindings.c b/src/bindings.c
index 5e24725..452d224 100644
--- a/src/bindings.c
+++ b/src/bindings.c
@@ -255,16 +255,17 @@ install_binding_grab(struct weston_seat *seat, uint32_t time, uint32_t key)
 	weston_keyboard_start_grab(seat->keyboard, &grab->grab);
 }
 
-WL_EXPORT void
+WL_EXPORT int
 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)
 {
 	struct weston_binding *b, *tmp;
+	int eaten = 0;
 
 	if (state == WL_KEYBOARD_KEY_STATE_RELEASED)
-		return;
+		return 0;
 
 	/* Invalidate all active modifier bindings. */
 	wl_list_for_each(b, &compositor->modifier_binding_list, link)
@@ -281,8 +282,10 @@ weston_compositor_run_key_binding(struct weston_compositor *compositor,
 			if (seat->keyboard->grab ==
 			    &seat->keyboard->default_grab)
 				install_binding_grab(seat, time, key);
+			++eaten;
 		}
 	}
+	return eaten;
 }
 
 WL_EXPORT void
diff --git a/src/compositor.h b/src/compositor.h
index 27ea693..55f73db 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -473,6 +473,7 @@ struct weston_keyboard {
 	uint32_t grab_time;
 
 	struct wl_array keys;
+	struct wl_array eaten_keys;
 
 	struct {
 		uint32_t mods_depressed;
@@ -1144,7 +1145,7 @@ weston_binding_destroy(struct weston_binding *binding);
 void
 weston_binding_list_destroy_all(struct wl_list *list);
 
-void
+int
 weston_compositor_run_key_binding(struct weston_compositor *compositor,
 				  struct weston_seat *seat, uint32_t time,
 				  uint32_t key,
diff --git a/src/input.c b/src/input.c
index b504d06..17afcbb 100644
--- a/src/input.c
+++ b/src/input.c
@@ -1307,6 +1307,24 @@ update_keymap(struct weston_seat *seat)
 }
 #endif
 
+static int
+remove_key(uint32_t key, enum wl_keyboard_key_state state,
+	   struct wl_array *array)
+{
+	uint32_t *k, *end;
+	end = array->data + array->size;
+	for (k = array->data; k < end; k++) {
+		if (*k == key) {
+			/* Ignore server-generated repeats. */
+			if (state == WL_KEYBOARD_KEY_STATE_PRESSED)
+				return -1;
+			*k = *--end;
+		}
+	}
+	array->size = (void *) end - array->data;
+	return 0;
+}
+
 WL_EXPORT void
 notify_key(struct weston_seat *seat, uint32_t time, uint32_t key,
 	   enum wl_keyboard_key_state state,
@@ -1315,7 +1333,9 @@ notify_key(struct weston_seat *seat, uint32_t time, uint32_t key,
 	struct weston_compositor *compositor = seat->compositor;
 	struct weston_keyboard *keyboard = seat->keyboard;
 	struct weston_keyboard_grab *grab = keyboard->grab;
-	uint32_t *k, *end;
+	uint32_t *k;
+	int eaten = 0;
+	struct wl_array *array;
 
 	if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
 		weston_compositor_idle_inhibit(compositor);
@@ -1325,28 +1345,24 @@ notify_key(struct weston_seat *seat, uint32_t time, uint32_t key,
 		weston_compositor_idle_release(compositor);
 	}
 
-	end = keyboard->keys.data + keyboard->keys.size;
-	for (k = keyboard->keys.data; k < end; k++) {
-		if (*k == key) {
-			/* Ignore server-generated repeats. */
-			if (state == WL_KEYBOARD_KEY_STATE_PRESSED)
-				return;
-			*k = *--end;
-		}
-	}
-	keyboard->keys.size = (void *) end - keyboard->keys.data;
-	if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
-		k = wl_array_add(&keyboard->keys, sizeof *k);
-		*k = key;
-	}
+	if (remove_key(key, state, &keyboard->keys) == -1)
+		return;
+	if (remove_key(key, state, &keyboard->eaten_keys) == -1)
+		return;
 
 	if (grab == &keyboard->default_grab ||
 	    grab == &keyboard->input_method_grab) {
-		weston_compositor_run_key_binding(compositor, seat, time, key,
+		eaten = weston_compositor_run_key_binding(compositor, seat, time, key,
 						  state);
 		grab = keyboard->grab;
 	}
 
+	array = eaten == 0 ? &keyboard->keys : &keyboard->eaten_keys;
+	if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
+		k = wl_array_add(array, sizeof *k);
+		*k = key;
+	}
+
 	grab->interface->key(grab, time, key, state);
 
 	if (keyboard->pending_keymap &&
-- 
2.1.3



More information about the wayland-devel mailing list