1 #define _POSIX_C_SOURCE 199309L
2 #include <assert.h>
3 #include <stdlib.h>
4 #include <unistd.h>
5 #include <sys/mman.h>
6 #include <wlr/types/wlr_seat.h>
7 #include <wlr/types/wlr_virtual_keyboard_v1.h>
8 #include <wlr/util/log.h>
9 #include <xkbcommon/xkbcommon.h>
10 #include "util/signal.h"
11 #include "virtual-keyboard-unstable-v1-protocol.h"
12 
13 
keyboard_led_update(struct wlr_keyboard * wlr_kb,uint32_t leds)14 static void keyboard_led_update(struct wlr_keyboard *wlr_kb, uint32_t leds) {
15 	// unsupported by virtual keyboard protocol
16 }
17 
keyboard_destroy(struct wlr_keyboard * wlr_kb)18 static void keyboard_destroy(struct wlr_keyboard *wlr_kb) {
19 	// safe to ignore - keyboard will be destroyed only iff associated virtual
20 	// keyboard is torn down, no need to tear down the keyboard separately
21 }
22 
23 static const struct wlr_keyboard_impl keyboard_impl = {
24 	.destroy = keyboard_destroy,
25 	.led_update = keyboard_led_update
26 };
27 
input_device_destroy(struct wlr_input_device * dev)28 static void input_device_destroy(struct wlr_input_device *dev) {
29 }
30 
31 static const struct wlr_input_device_impl input_device_impl = {
32 	.destroy = input_device_destroy
33 };
34 
35 static const struct zwp_virtual_keyboard_v1_interface virtual_keyboard_impl;
36 
virtual_keyboard_from_resource(struct wl_resource * resource)37 static struct wlr_virtual_keyboard_v1 *virtual_keyboard_from_resource(
38 		struct wl_resource *resource) {
39 	assert(wl_resource_instance_of(resource,
40 	   &zwp_virtual_keyboard_v1_interface, &virtual_keyboard_impl));
41 	return wl_resource_get_user_data(resource);
42 }
43 
wlr_input_device_get_virtual_keyboard(struct wlr_input_device * wlr_dev)44 struct wlr_virtual_keyboard_v1 *wlr_input_device_get_virtual_keyboard(
45 		struct wlr_input_device *wlr_dev) {
46 	if (wlr_dev->impl != &input_device_impl) {
47 		return NULL;
48 	}
49 	return (struct wlr_virtual_keyboard_v1 *)wlr_dev;
50 }
51 
virtual_keyboard_keymap(struct wl_client * client,struct wl_resource * resource,uint32_t format,int32_t fd,uint32_t size)52 static void virtual_keyboard_keymap(struct wl_client *client,
53 		struct wl_resource *resource, uint32_t format, int32_t fd,
54 		uint32_t size) {
55 	struct wlr_virtual_keyboard_v1 *keyboard =
56 		virtual_keyboard_from_resource(resource);
57 
58 	struct xkb_context *context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
59 	if (!context) {
60 		goto context_fail;
61 	}
62 	void *data = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
63 	if (data == MAP_FAILED) {
64 		goto fd_fail;
65 	}
66 	struct xkb_keymap *keymap = xkb_keymap_new_from_string(context, data,
67 		XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS);
68 	munmap(data, size);
69 	if (!keymap) {
70 		goto keymap_fail;
71 	}
72 	wlr_keyboard_set_keymap(keyboard->input_device.keyboard, keymap);
73 	keyboard->has_keymap = true;
74 	xkb_keymap_unref(keymap);
75 	xkb_context_unref(context);
76 	close(fd);
77 	return;
78 keymap_fail:
79 fd_fail:
80 	xkb_context_unref(context);
81 context_fail:
82 	wl_client_post_no_memory(client);
83 	close(fd);
84 }
85 
virtual_keyboard_key(struct wl_client * client,struct wl_resource * resource,uint32_t time,uint32_t key,uint32_t state)86 static void virtual_keyboard_key(struct wl_client *client,
87 		struct wl_resource *resource, uint32_t time, uint32_t key,
88 		uint32_t state) {
89 	struct wlr_virtual_keyboard_v1 *keyboard =
90 		virtual_keyboard_from_resource(resource);
91 	if (!keyboard->has_keymap) {
92 		wl_resource_post_error(resource,
93 			ZWP_VIRTUAL_KEYBOARD_V1_ERROR_NO_KEYMAP,
94 			"Cannot send a keypress before defining a keymap");
95 		return;
96 	}
97 	struct wlr_event_keyboard_key event = {
98 		.time_msec = time,
99 		.keycode = key,
100 		.update_state = false,
101 		.state = state,
102 	};
103 	wlr_keyboard_notify_key(keyboard->input_device.keyboard, &event);
104 }
105 
virtual_keyboard_modifiers(struct wl_client * client,struct wl_resource * resource,uint32_t mods_depressed,uint32_t mods_latched,uint32_t mods_locked,uint32_t group)106 static void virtual_keyboard_modifiers(struct wl_client *client,
107 		struct wl_resource *resource, uint32_t mods_depressed,
108 		uint32_t mods_latched, uint32_t mods_locked, uint32_t group) {
109 	struct wlr_virtual_keyboard_v1 *keyboard =
110 		virtual_keyboard_from_resource(resource);
111 	if (!keyboard->has_keymap) {
112 		wl_resource_post_error(resource,
113 			ZWP_VIRTUAL_KEYBOARD_V1_ERROR_NO_KEYMAP,
114 			"Cannot send a modifier state before defining a keymap");
115 		return;
116 	}
117 	wlr_keyboard_notify_modifiers(keyboard->input_device.keyboard,
118 		mods_depressed, mods_latched, mods_locked, group);
119 }
120 
virtual_keyboard_destroy_resource(struct wl_resource * resource)121 static void virtual_keyboard_destroy_resource(struct wl_resource *resource) {
122 	struct wlr_virtual_keyboard_v1 *keyboard =
123 		virtual_keyboard_from_resource(resource);
124 	wlr_signal_emit_safe(&keyboard->events.destroy, keyboard);
125 	wl_list_remove(&keyboard->link);
126 	wlr_input_device_destroy(&keyboard->input_device);
127 	free(keyboard);
128 }
129 
virtual_keyboard_destroy(struct wl_client * client,struct wl_resource * resource)130 static void virtual_keyboard_destroy(struct wl_client *client,
131 		struct wl_resource *resource) {
132 	wl_resource_destroy(resource);
133 }
134 
135 static const struct zwp_virtual_keyboard_v1_interface virtual_keyboard_impl = {
136 	.keymap = virtual_keyboard_keymap,
137 	.key = virtual_keyboard_key,
138 	.modifiers = virtual_keyboard_modifiers,
139 	.destroy = virtual_keyboard_destroy,
140 };
141 
142 static const struct zwp_virtual_keyboard_manager_v1_interface manager_impl;
143 
manager_from_resource(struct wl_resource * resource)144 static struct wlr_virtual_keyboard_manager_v1 *manager_from_resource(
145 		struct wl_resource *resource) {
146 	assert(wl_resource_instance_of(resource,
147 		&zwp_virtual_keyboard_manager_v1_interface, &manager_impl));
148 	return wl_resource_get_user_data(resource);
149 }
150 
virtual_keyboard_manager_create_virtual_keyboard(struct wl_client * client,struct wl_resource * resource,struct wl_resource * seat,uint32_t id)151 static void virtual_keyboard_manager_create_virtual_keyboard(
152 		struct wl_client *client, struct wl_resource *resource,
153 		struct wl_resource *seat, uint32_t id) {
154 	struct wlr_virtual_keyboard_manager_v1 *manager =
155 		manager_from_resource(resource);
156 
157 	struct wlr_virtual_keyboard_v1 *virtual_keyboard = calloc(1,
158 		sizeof(struct wlr_virtual_keyboard_v1));
159 	if (!virtual_keyboard) {
160 		wl_client_post_no_memory(client);
161 		return;
162 	}
163 
164 	struct wlr_keyboard* keyboard = calloc(1, sizeof(struct wlr_keyboard));
165 	if (!keyboard) {
166 		wlr_log(WLR_ERROR, "Cannot allocate wlr_keyboard");
167 		free(virtual_keyboard);
168 		wl_client_post_no_memory(client);
169 		return;
170 	}
171 	wlr_keyboard_init(keyboard, &keyboard_impl);
172 
173 	struct wl_resource *keyboard_resource = wl_resource_create(client,
174 		&zwp_virtual_keyboard_v1_interface, wl_resource_get_version(resource),
175 		id);
176 	if (!keyboard_resource) {
177 		free(keyboard);
178 		free(virtual_keyboard);
179 		wl_client_post_no_memory(client);
180 		return;
181 	}
182 
183 	wl_resource_set_implementation(keyboard_resource, &virtual_keyboard_impl,
184 		virtual_keyboard, virtual_keyboard_destroy_resource);
185 
186 	wlr_input_device_init(&virtual_keyboard->input_device,
187 		WLR_INPUT_DEVICE_KEYBOARD, &input_device_impl, "virtual keyboard",
188 		0x0, 0x0);
189 
190 	struct wlr_seat_client *seat_client = wlr_seat_client_from_resource(seat);
191 
192 	virtual_keyboard->input_device.keyboard = keyboard;
193 	virtual_keyboard->resource = keyboard_resource;
194 	virtual_keyboard->seat = seat_client->seat;
195 	wl_signal_init(&virtual_keyboard->events.destroy);
196 
197 	wl_list_insert(&manager->virtual_keyboards, &virtual_keyboard->link);
198 
199 	wlr_signal_emit_safe(&manager->events.new_virtual_keyboard,
200 		virtual_keyboard);
201 }
202 
203 static const struct zwp_virtual_keyboard_manager_v1_interface manager_impl = {
204 	.create_virtual_keyboard = virtual_keyboard_manager_create_virtual_keyboard,
205 };
206 
virtual_keyboard_manager_bind(struct wl_client * client,void * data,uint32_t version,uint32_t id)207 static void virtual_keyboard_manager_bind(struct wl_client *client, void *data,
208 		uint32_t version, uint32_t id) {
209 	struct wlr_virtual_keyboard_manager_v1 *manager = data;
210 
211 	struct wl_resource *resource = wl_resource_create(client,
212 		&zwp_virtual_keyboard_manager_v1_interface, version, id);
213 	if (!resource) {
214 		wl_client_post_no_memory(client);
215 		return;
216 	}
217 
218 	wl_resource_set_implementation(resource, &manager_impl, manager, NULL);
219 }
220 
handle_display_destroy(struct wl_listener * listener,void * data)221 static void handle_display_destroy(struct wl_listener *listener, void *data) {
222 	struct wlr_virtual_keyboard_manager_v1 *manager =
223 		wl_container_of(listener, manager, display_destroy);
224 	wlr_signal_emit_safe(&manager->events.destroy, manager);
225 	wl_list_remove(&manager->display_destroy.link);
226 	wl_global_destroy(manager->global);
227 	free(manager);
228 }
229 
230 struct wlr_virtual_keyboard_manager_v1*
wlr_virtual_keyboard_manager_v1_create(struct wl_display * display)231 		wlr_virtual_keyboard_manager_v1_create(
232 		struct wl_display *display) {
233 	struct wlr_virtual_keyboard_manager_v1 *manager = calloc(1,
234 		sizeof(struct wlr_virtual_keyboard_manager_v1));
235 	if (!manager) {
236 		return NULL;
237 	}
238 
239 	manager->global = wl_global_create(display,
240 		&zwp_virtual_keyboard_manager_v1_interface, 1, manager,
241 		virtual_keyboard_manager_bind);
242 	if (!manager->global) {
243 		free(manager);
244 		return NULL;
245 	}
246 
247 	manager->display_destroy.notify = handle_display_destroy;
248 	wl_display_add_destroy_listener(display, &manager->display_destroy);
249 
250 	wl_list_init(&manager->virtual_keyboards);
251 
252 	wl_signal_init(&manager->events.new_virtual_keyboard);
253 	wl_signal_init(&manager->events.destroy);
254 
255 	return manager;
256 }
257