[PATCH 1/3] text: add keyboard events

Philipp Brüschweiler blei42 at gmail.com
Sun Jul 22 15:07:38 PDT 2012


* add request_keyboard so input methods can signal that they want
  to receive keyboard events
* keyboard events are grabbed with wl_keyboard_grab and relayed
  to the input method using the created wl_keyboard interface
---
 protocol/text.xml  |   5 +-
 src/compositor.c   |   2 +-
 src/compositor.h   |   5 +-
 src/shell.c        |   5 ++
 src/text-backend.c | 132 +++++++++++++++++++++++++++++++++++++++++++++++++++--
 5 Dateien geändert, 143 Zeilen hinzugefügt(+), 6 Zeilen entfernt(-)

diff --git a/protocol/text.xml b/protocol/text.xml
index a14277a..42c8f35 100644
--- a/protocol/text.xml
+++ b/protocol/text.xml
@@ -1,5 +1,5 @@
 <protocol name="text">
-   <interface name="text_model" version="1">
+  <interface name="text_model" version="1">
     <request name="set_surrounding_text">
       <arg name="text" type="string"/>
     </request>
@@ -48,5 +48,8 @@
       <arg name="text" type="string"/>
       <arg name="index" type="uint"/>
     </request>
+    <request name="request_keyboard">
+      <arg name="keyboard" type="new_id" interface="wl_keyboard"/>
+    </request>
   </interface>
 </protocol>
diff --git a/src/compositor.c b/src/compositor.c
index 3f2828e..5cf6129 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -3172,7 +3172,7 @@ weston_compositor_init(struct weston_compositor *ec,
 
 	screenshooter_create(ec);
 	text_cursor_position_notifier_create(ec);
-	input_method_create(ec);
+	ec->input_method = input_method_create(ec);
 
 	wl_data_device_manager_init(ec->wl_display);
 
diff --git a/src/compositor.h b/src/compositor.h
index 22c0174..5044e4e 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -292,6 +292,9 @@ struct weston_compositor {
 	/* There can be more than one, but not right now... */
 	struct weston_seat *seat;
 
+	struct input_method *input_method;
+	struct wl_listener input_method_keyboard_focus_listener;
+
 	struct weston_layer fade_layer;
 	struct weston_layer cursor_layer;
 
@@ -714,7 +717,7 @@ clipboard_create(struct weston_seat *seat);
 void
 text_cursor_position_notifier_create(struct weston_compositor *ec);
 
-void
+struct input_method *
 input_method_create(struct weston_compositor *ec);
 
 struct weston_process;
diff --git a/src/shell.c b/src/shell.c
index a9e4d4f..41ddfbf 100644
--- a/src/shell.c
+++ b/src/shell.c
@@ -3370,6 +3370,11 @@ shell_init(struct weston_compositor *ec)
 		wl_signal_add(&ec->seat->seat.pointer->focus_signal,
 			      &shell->pointer_focus_listener);
 
+	if (ec->seat->seat.keyboard)
+		wl_signal_add(&ec->seat->seat.keyboard->focus_signal,
+			      &ec->input_method_keyboard_focus_listener);
+
+
 	shell_add_bindings(ec, shell);
 
 	return 0;
diff --git a/src/text-backend.c b/src/text-backend.c
index 353a983..5b1b00d 100644
--- a/src/text-backend.c
+++ b/src/text-backend.c
@@ -24,6 +24,7 @@
 
 #include "compositor.h"
 #include "text-server-protocol.h"
+#include "log.h"
 
 struct input_method;
 
@@ -33,10 +34,13 @@ struct text_model {
 	struct wl_list link;
 
 	struct input_method *input_method;
+	struct wl_keyboard_grab grab;
+	struct wl_surface *surface;
 };
 
 struct input_method {
 	struct wl_resource *input_method_binding;
+	struct wl_resource *keyboard_binding;
 	struct wl_global *input_method_global;
 	struct wl_global *text_model_manager_global;
 	struct wl_listener destroy_listener;
@@ -50,6 +54,12 @@ static void
 deactivate_text_model(struct text_model *text_model)
 {
 	struct weston_compositor *ec = text_model->input_method->ec;
+	struct wl_keyboard_grab *grab = &text_model->grab;
+
+	if (grab->keyboard && (grab->keyboard->grab == grab)) {
+		wl_keyboard_end_grab(grab->keyboard);
+		weston_log("end keyboard grab\n");
+	}
 
 	if (text_model->input_method->active_model == text_model) {
 		text_model->input_method->active_model = NULL;
@@ -70,6 +80,41 @@ destroy_text_model(struct wl_resource *resource)
 }
 
 static void
+text_model_key(struct wl_keyboard_grab *grab,
+	       uint32_t time, uint32_t key, uint32_t state_w)
+{
+	struct text_model *text_model = container_of(grab, struct text_model, grab);
+	struct input_method *input_method = text_model->input_method;
+
+	uint32_t serial = wl_display_next_serial(input_method->ec->wl_display);
+	if (input_method->keyboard_binding) {
+		wl_keyboard_send_key(input_method->keyboard_binding,
+				     serial, time, key, state_w);
+	}
+}
+
+static void
+text_model_modifier(struct wl_keyboard_grab *grab, uint32_t serial,
+		    uint32_t mods_depressed, uint32_t mods_latched,
+		    uint32_t mods_locked, uint32_t group)
+{
+	struct text_model *text_model = container_of(grab, struct text_model, grab);
+	struct input_method *input_method = text_model->input_method;
+
+	uint32_t new_serial = wl_display_next_serial(input_method->ec->wl_display);
+	if (input_method->keyboard_binding) {
+		wl_keyboard_send_modifiers(input_method->keyboard_binding,
+					   new_serial, mods_depressed, mods_latched,
+					   mods_locked, group);
+	}
+}
+
+static const struct wl_keyboard_grab_interface text_model_grab = {
+	text_model_key,
+	text_model_modifier,
+};
+
+static void
 text_model_set_surrounding_text(struct wl_client *client,
 				struct wl_resource *resource,
 				const char *text)
@@ -93,6 +138,17 @@ text_model_activate(struct wl_client *client,
 	text_model->input_method->active_model = text_model;
 
 	wl_signal_emit(&ec->show_input_panel_signal, ec);
+
+	if (text_model->input_method->input_method_binding &&
+	    text_model->input_method->keyboard_binding) {
+		struct wl_seat *seat = &text_model->input_method->ec->seat->seat;
+
+		if (seat->keyboard->grab != &seat->keyboard->default_grab) {
+			wl_keyboard_end_grab(seat->keyboard);
+		}
+		wl_keyboard_start_grab(seat->keyboard, &text_model->grab);
+		weston_log("start keyboard grab\n");
+	}
 }
 
 static void
@@ -164,6 +220,9 @@ static void text_model_manager_create_text_model(struct wl_client *client,
 	text_model->resource.data = text_model;
 
 	text_model->input_method = input_method;
+	text_model->surface = container_of(surface, struct wl_surface, resource);
+
+	text_model->grab.interface = &text_model_grab;
 
 	wl_client_add_resource(client, &text_model->resource);
 
@@ -202,8 +261,46 @@ input_method_commit_string(struct wl_client *client,
 	}
 }
 
+static void
+unbind_keyboard_binding(struct wl_resource *resource)
+{
+	struct input_method *input_method = resource->data;
+
+	input_method->keyboard_binding = NULL;
+}
+
+static void
+input_method_request_keyboard(struct wl_client *client,
+			      struct wl_resource *resource,
+			      uint32_t keyboard_id)
+{
+	struct input_method *input_method = resource->data;
+
+	if (input_method->keyboard_binding) {
+		wl_resource_post_error(resource, WL_DISPLAY_ERROR_INVALID_OBJECT,
+				       "keyboard already bound");
+		return;
+	}
+
+	input_method->keyboard_binding =
+		wl_client_add_object(client, &wl_keyboard_interface,
+				     NULL, keyboard_id, input_method);
+
+	if (input_method->keyboard_binding == NULL)
+		return;
+
+	input_method->keyboard_binding->destroy = unbind_keyboard_binding;
+
+	struct weston_seat *seat = input_method->ec->seat;
+	wl_keyboard_send_keymap(input_method->keyboard_binding,
+				WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1,
+				seat->xkb_info.keymap_fd,
+				seat->xkb_info.keymap_size);
+}
+
 static const struct input_method_interface input_method_implementation = {
-	input_method_commit_string
+	input_method_commit_string,
+	input_method_request_keyboard
 };
 
 static void
@@ -213,6 +310,10 @@ unbind_input_method(struct wl_resource *resource)
 
 	input_method->input_method_binding = NULL;
 	free(resource);
+
+	if (input_method->keyboard_binding) {
+		wl_resource_destroy(input_method->keyboard_binding);
+	}
 }
 
 static void
@@ -252,7 +353,26 @@ input_method_notifier_destroy(struct wl_listener *listener, void *data)
 	free(input_method);
 }
 
-void
+static void
+handle_keyboard_focus(struct wl_listener *listener, void *data)
+{
+	struct wl_pointer *pointer = data;
+	struct weston_surface *surface =
+		(struct weston_surface *) pointer->focus;
+
+	struct weston_compositor *compositor =
+		container_of(listener, struct weston_compositor,
+			     input_method_keyboard_focus_listener);
+
+	struct text_model *active_model = compositor->input_method->active_model;
+
+	if (active_model &&
+	    (!surface || active_model->surface != &surface->surface)) {
+		deactivate_text_model(active_model);
+	}
+}
+
+WL_EXPORT struct input_method *
 input_method_create(struct weston_compositor *ec)
 {
 	struct input_method *input_method;
@@ -260,7 +380,6 @@ input_method_create(struct weston_compositor *ec)
 	input_method = calloc(1, sizeof *input_method);
 
 	input_method->ec = ec;
-	input_method->active_model = NULL;
 
 	wl_list_init(&input_method->models);
 
@@ -276,4 +395,11 @@ input_method_create(struct weston_compositor *ec)
 
 	input_method->destroy_listener.notify = input_method_notifier_destroy;
 	wl_signal_add(&ec->destroy_signal, &input_method->destroy_listener);
+
+	/* Initialize the listener. It will be added by the shell when the
+	 * seat is initialized.
+	 */
+	ec->input_method_keyboard_focus_listener.notify = handle_keyboard_focus;
+
+	return input_method;
 }
-- 
1.7.11.2



More information about the wayland-devel mailing list