1 /*
2  * Copyright © 2012 Openismus GmbH
3  * Copyright © 2012 Intel Corporation
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the next
13  * paragraph) shall be included in all copies or substantial portions of the
14  * Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22  * DEALINGS IN THE SOFTWARE.
23  */
24 
25 #include "config.h"
26 
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 
31 #include <linux/input.h>
32 #include <cairo.h>
33 
34 #include "window.h"
35 #include "input-method-client-protocol.h"
36 #include "text-client-protocol.h"
37 
38 struct keyboard;
39 
40 struct virtual_keyboard {
41 	struct wl_input_panel *input_panel;
42 	struct wl_input_method *input_method;
43 	struct wl_input_method_context *context;
44 	struct display *display;
45 	struct output *output;
46 	char *preedit_string;
47 	uint32_t preedit_style;
48 	struct {
49 		xkb_mod_mask_t shift_mask;
50 	} keysym;
51 	uint32_t serial;
52 	uint32_t content_hint;
53 	uint32_t content_purpose;
54 	char *preferred_language;
55 	char *surrounding_text;
56 	uint32_t surrounding_cursor;
57 	struct keyboard *keyboard;
58 };
59 
60 enum key_type {
61 	keytype_default,
62 	keytype_backspace,
63 	keytype_enter,
64 	keytype_space,
65 	keytype_switch,
66 	keytype_symbols,
67 	keytype_tab,
68 	keytype_arrow_up,
69 	keytype_arrow_left,
70 	keytype_arrow_right,
71 	keytype_arrow_down,
72 	keytype_style
73 };
74 
75 struct key {
76 	enum key_type key_type;
77 
78 	char *label;
79 	char *uppercase;
80 	char *symbol;
81 
82 	unsigned int width;
83 };
84 
85 struct layout {
86 	const struct key *keys;
87 	uint32_t count;
88 
89 	uint32_t columns;
90 	uint32_t rows;
91 
92 	const char *language;
93 	uint32_t text_direction;
94 };
95 
96 static const struct key normal_keys[] = {
97 	{ keytype_default, "q", "Q", "1", 1},
98 	{ keytype_default, "w", "W", "2", 1},
99 	{ keytype_default, "e", "E", "3", 1},
100 	{ keytype_default, "r", "R", "4", 1},
101 	{ keytype_default, "t", "T", "5", 1},
102 	{ keytype_default, "y", "Y", "6", 1},
103 	{ keytype_default, "u", "U", "7", 1},
104 	{ keytype_default, "i", "I", "8", 1},
105 	{ keytype_default, "o", "O", "9", 1},
106 	{ keytype_default, "p", "P", "0", 1},
107 	{ keytype_backspace, "<--", "<--", "<--", 2},
108 
109 	{ keytype_tab, "->|", "->|", "->|", 1},
110 	{ keytype_default, "a", "A", "-", 1},
111 	{ keytype_default, "s", "S", "@", 1},
112 	{ keytype_default, "d", "D", "*", 1},
113 	{ keytype_default, "f", "F", "^", 1},
114 	{ keytype_default, "g", "G", ":", 1},
115 	{ keytype_default, "h", "H", ";", 1},
116 	{ keytype_default, "j", "J", "(", 1},
117 	{ keytype_default, "k", "K", ")", 1},
118 	{ keytype_default, "l", "L", "~", 1},
119 	{ keytype_enter, "Enter", "Enter", "Enter", 2},
120 
121 	{ keytype_switch, "ABC", "abc", "ABC", 2},
122 	{ keytype_default, "z", "Z", "/", 1},
123 	{ keytype_default, "x", "X", "\'", 1},
124 	{ keytype_default, "c", "C", "\"", 1},
125 	{ keytype_default, "v", "V", "+", 1},
126 	{ keytype_default, "b", "B", "=", 1},
127 	{ keytype_default, "n", "N", "?", 1},
128 	{ keytype_default, "m", "M", "!", 1},
129 	{ keytype_default, ",", ",", "\\", 1},
130 	{ keytype_default, ".", ".", "|", 1},
131 	{ keytype_switch, "ABC", "abc", "ABC", 1},
132 
133 	{ keytype_symbols, "?123", "?123", "abc", 1},
134 	{ keytype_space, "", "", "", 5},
135 	{ keytype_arrow_up, "/\\", "/\\", "/\\", 1},
136 	{ keytype_arrow_left, "<", "<", "<", 1},
137 	{ keytype_arrow_right, ">", ">", ">", 1},
138 	{ keytype_arrow_down, "\\/", "\\/", "\\/", 1},
139 	{ keytype_style, "", "", "", 2}
140 };
141 
142 static const struct key numeric_keys[] = {
143 	{ keytype_default, "1", "1", "1", 1},
144 	{ keytype_default, "2", "2", "2", 1},
145 	{ keytype_default, "3", "3", "3", 1},
146 	{ keytype_default, "4", "4", "4", 1},
147 	{ keytype_default, "5", "5", "5", 1},
148 	{ keytype_default, "6", "6", "6", 1},
149 	{ keytype_default, "7", "7", "7", 1},
150 	{ keytype_default, "8", "8", "8", 1},
151 	{ keytype_default, "9", "9", "9", 1},
152 	{ keytype_default, "0", "0", "0", 1},
153 	{ keytype_backspace, "<--", "<--", "<--", 2},
154 
155 	{ keytype_space, "", "", "", 4},
156 	{ keytype_enter, "Enter", "Enter", "Enter", 2},
157 	{ keytype_arrow_up, "/\\", "/\\", "/\\", 1},
158 	{ keytype_arrow_left, "<", "<", "<", 1},
159 	{ keytype_arrow_right, ">", ">", ">", 1},
160 	{ keytype_arrow_down, "\\/", "\\/", "\\/", 1},
161 	{ keytype_style, "", "", "", 2}
162 };
163 
164 static const struct key arabic_keys[] = {
165 	{ keytype_default, "ض", "ﹶ", "۱", 1},
166 	{ keytype_default, "ص", "ﹰ", "۲", 1},
167 	{ keytype_default, "ث", "ﹸ", "۳", 1},
168 	{ keytype_default, "ق", "ﹲ", "۴", 1},
169 	{ keytype_default, "ف", "ﻹ", "۵", 1},
170 	{ keytype_default, "غ", "ﺇ", "۶", 1},
171 	{ keytype_default, "ع", "`", "۷", 1},
172 	{ keytype_default, "ه", "٪", "۸", 1},
173 	{ keytype_default, "خ", ">", "۹", 1},
174 	{ keytype_default, "ح", "<", "۰", 1},
175 	{ keytype_backspace, "-->", "-->", "-->", 2},
176 
177 	{ keytype_tab, "->|", "->|", "->|", 1},
178 	{ keytype_default, "ش", "ﹺ", "ﹼ", 1},
179 	{ keytype_default, "س", "ﹴ", "!", 1},
180 	{ keytype_default, "ي", "[", "@", 1},
181 	{ keytype_default, "ب", "]", "#", 1},
182 	{ keytype_default, "ل", "ﻷ", "$", 1},
183 	{ keytype_default, "ا", "أ", "%", 1},
184 	{ keytype_default, "ت", "-", "^", 1},
185 	{ keytype_default, "ن", "x", "&", 1},
186 	{ keytype_default, "م", "/", "*", 1},
187 	{ keytype_default, "ك", ":", "_", 1},
188 	{ keytype_default, "د", "\"", "+", 1},
189 	{ keytype_enter, "Enter", "Enter", "Enter", 2},
190 
191 	{ keytype_switch, "Shift", "Base", "Shift", 2},
192 	{ keytype_default, "ئ", "~", ")", 1},
193 	{ keytype_default, "ء", "°", "(", 1},
194 	{ keytype_default, "ؤ", "{", "\"", 1},
195 	{ keytype_default, "ر", "}", "\'", 1},
196 	{ keytype_default, "ى", "ﺁ", "؟", 1},
197 	{ keytype_default, "ة", "'", "!", 1},
198 	{ keytype_default, "و", ",", ";", 1},
199 	{ keytype_default, "ﺯ", ".", "\\", 1},
200 	{ keytype_default, "ظ", "؟", "=", 1},
201 	{ keytype_switch, "Shift", "Base", "Shift", 2},
202 
203 	{ keytype_symbols, "؟٣٢١", "؟٣٢١", "Base", 1},
204 	{ keytype_default, "ﻻ", "ﻵ", "|", 1},
205 	{ keytype_default, ",", "،", "،", 1},
206 	{ keytype_space, "", "", "", 6},
207 	{ keytype_default, ".", "ذ", "]", 1},
208 	{ keytype_default, "ط", "ﺝ", "[", 1},
209 	{ keytype_style, "", "", "", 2}
210 };
211 
212 
213 static const struct layout normal_layout = {
214 	normal_keys,
215 	sizeof(normal_keys) / sizeof(*normal_keys),
216 	12,
217 	4,
218 	"en",
219 	WL_TEXT_INPUT_TEXT_DIRECTION_LTR
220 };
221 
222 static const struct layout numeric_layout = {
223 	numeric_keys,
224 	sizeof(numeric_keys) / sizeof(*numeric_keys),
225 	12,
226 	2,
227 	"en",
228 	WL_TEXT_INPUT_TEXT_DIRECTION_LTR
229 };
230 
231 static const struct layout arabic_layout = {
232 	arabic_keys,
233 	sizeof(arabic_keys) / sizeof(*arabic_keys),
234 	13,
235 	4,
236 	"ar",
237 	WL_TEXT_INPUT_TEXT_DIRECTION_RTL
238 };
239 
240 static const char *style_labels[] = {
241 	"default",
242 	"none",
243 	"active",
244 	"inactive",
245 	"highlight",
246 	"underline",
247 	"selection",
248 	"incorrect"
249 };
250 
251 static const double key_width = 60;
252 static const double key_height = 50;
253 
254 enum keyboard_state {
255 	KEYBOARD_STATE_DEFAULT,
256 	KEYBOARD_STATE_UPPERCASE,
257 	KEYBOARD_STATE_SYMBOLS
258 };
259 
260 struct keyboard {
261 	struct virtual_keyboard *keyboard;
262 	struct window *window;
263 	struct widget *widget;
264 
265 	enum keyboard_state state;
266 };
267 
268 static void __attribute__ ((format (printf, 1, 2)))
dbg(const char * fmt,...)269 dbg(const char *fmt, ...)
270 {
271 #ifdef DEBUG
272 	int l;
273 	va_list argp;
274 
275 	va_start(argp, fmt);
276 	l = vfprintf(stderr, fmt, argp);
277 	va_end(argp);
278 #endif
279 }
280 
281 static const char *
label_from_key(struct keyboard * keyboard,const struct key * key)282 label_from_key(struct keyboard *keyboard,
283 	       const struct key *key)
284 {
285 	if (key->key_type == keytype_style)
286 		return style_labels[keyboard->keyboard->preedit_style];
287 
288 	switch(keyboard->state) {
289 	case KEYBOARD_STATE_DEFAULT:
290 		return key->label;
291 	case KEYBOARD_STATE_UPPERCASE:
292 		return key->uppercase;
293 	case KEYBOARD_STATE_SYMBOLS:
294 		return key->symbol;
295 	}
296 
297 	return "";
298 }
299 
300 static void
draw_key(struct keyboard * keyboard,const struct key * key,cairo_t * cr,unsigned int row,unsigned int col)301 draw_key(struct keyboard *keyboard,
302 	 const struct key *key,
303 	 cairo_t *cr,
304 	 unsigned int row,
305 	 unsigned int col)
306 {
307 	const char *label;
308 	cairo_text_extents_t extents;
309 
310 	cairo_save(cr);
311 	cairo_rectangle(cr,
312 			col * key_width, row * key_height,
313 			key->width * key_width, key_height);
314 	cairo_clip(cr);
315 
316 	/* Paint frame */
317 	cairo_rectangle(cr,
318 			col * key_width, row * key_height,
319 			key->width * key_width, key_height);
320 	cairo_set_line_width(cr, 3);
321 	cairo_stroke(cr);
322 
323 	/* Paint text */
324 	label = label_from_key(keyboard, key);
325 	cairo_text_extents(cr, label, &extents);
326 
327 	cairo_translate(cr,
328 			col * key_width,
329 			row * key_height);
330 	cairo_translate(cr,
331 			(key->width * key_width - extents.width) / 2,
332 			(key_height - extents.y_bearing) / 2);
333 	cairo_show_text(cr, label);
334 
335 	cairo_restore(cr);
336 }
337 
338 static const struct layout *
get_current_layout(struct virtual_keyboard * keyboard)339 get_current_layout(struct virtual_keyboard *keyboard)
340 {
341 	switch (keyboard->content_purpose) {
342 		case WL_TEXT_INPUT_CONTENT_PURPOSE_DIGITS:
343 		case WL_TEXT_INPUT_CONTENT_PURPOSE_NUMBER:
344 			return &numeric_layout;
345 		default:
346 			if (keyboard->preferred_language &&
347 			    strcmp(keyboard->preferred_language, "ar") == 0)
348 				return &arabic_layout;
349 			else
350 				return &normal_layout;
351 	}
352 }
353 
354 static void
redraw_handler(struct widget * widget,void * data)355 redraw_handler(struct widget *widget, void *data)
356 {
357 	struct keyboard *keyboard = data;
358 	cairo_surface_t *surface;
359 	struct rectangle allocation;
360 	cairo_t *cr;
361 	unsigned int i;
362 	unsigned int row = 0, col = 0;
363 	const struct layout *layout;
364 
365 	layout = get_current_layout(keyboard->keyboard);
366 
367 	surface = window_get_surface(keyboard->window);
368 	widget_get_allocation(keyboard->widget, &allocation);
369 
370 	cr = cairo_create(surface);
371 	cairo_rectangle(cr, allocation.x, allocation.y, allocation.width, allocation.height);
372 	cairo_clip(cr);
373 
374 	cairo_select_font_face(cr, "sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
375 	cairo_set_font_size(cr, 16);
376 
377 	cairo_translate(cr, allocation.x, allocation.y);
378 
379 	cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
380 	cairo_set_source_rgba(cr, 1, 1, 1, 0.75);
381 	cairo_rectangle(cr, 0, 0, layout->columns * key_width, layout->rows * key_height);
382 	cairo_paint(cr);
383 
384 	cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
385 
386 	for (i = 0; i < layout->count; ++i) {
387 		cairo_set_source_rgb(cr, 0, 0, 0);
388 		draw_key(keyboard, &layout->keys[i], cr, row, col);
389 		col += layout->keys[i].width;
390 		if (col >= layout->columns) {
391 			row += 1;
392 			col = 0;
393 		}
394 	}
395 
396 	cairo_destroy(cr);
397 	cairo_surface_destroy(surface);
398 }
399 
400 static void
resize_handler(struct widget * widget,int32_t width,int32_t height,void * data)401 resize_handler(struct widget *widget,
402 	       int32_t width, int32_t height, void *data)
403 {
404 	/* struct keyboard *keyboard = data; */
405 }
406 
407 static char *
insert_text(const char * text,uint32_t offset,const char * insert)408 insert_text(const char *text, uint32_t offset, const char *insert)
409 {
410 	int tlen = strlen(text), ilen = strlen(insert);
411 	char *new_text = xmalloc(tlen + ilen + 1);
412 
413 	memcpy(new_text, text, offset);
414 	memcpy(new_text + offset, insert, ilen);
415 	memcpy(new_text + offset + ilen, text + offset, tlen - offset);
416 	new_text[tlen + ilen] = '\0';
417 
418 	return new_text;
419 }
420 
421 static void
virtual_keyboard_commit_preedit(struct virtual_keyboard * keyboard)422 virtual_keyboard_commit_preedit(struct virtual_keyboard *keyboard)
423 {
424 	char *surrounding_text;
425 
426 	if (!keyboard->preedit_string ||
427 	    strlen(keyboard->preedit_string) == 0)
428 		return;
429 
430 	wl_input_method_context_cursor_position(keyboard->context,
431 						0, 0);
432 	wl_input_method_context_commit_string(keyboard->context,
433 					      keyboard->serial,
434 					      keyboard->preedit_string);
435 
436 	if (keyboard->surrounding_text) {
437 		surrounding_text = insert_text(keyboard->surrounding_text,
438 					       keyboard->surrounding_cursor,
439 					       keyboard->preedit_string);
440 		free(keyboard->surrounding_text);
441 		keyboard->surrounding_text = surrounding_text;
442 		keyboard->surrounding_cursor += strlen(keyboard->preedit_string);
443 	} else {
444 		keyboard->surrounding_text = strdup(keyboard->preedit_string);
445 		keyboard->surrounding_cursor = strlen(keyboard->preedit_string);
446 	}
447 
448 	free(keyboard->preedit_string);
449 	keyboard->preedit_string = strdup("");
450 }
451 
452 static void
virtual_keyboard_send_preedit(struct virtual_keyboard * keyboard,int32_t cursor)453 virtual_keyboard_send_preedit(struct virtual_keyboard *keyboard,
454 			      int32_t cursor)
455 {
456 	uint32_t index = strlen(keyboard->preedit_string);
457 
458 	if (keyboard->preedit_style)
459 		wl_input_method_context_preedit_styling(keyboard->context,
460 							0,
461 							strlen(keyboard->preedit_string),
462 							keyboard->preedit_style);
463 	if (cursor > 0)
464 		index = cursor;
465 	wl_input_method_context_preedit_cursor(keyboard->context,
466 					       index);
467 	wl_input_method_context_preedit_string(keyboard->context,
468 					       keyboard->serial,
469 					       keyboard->preedit_string,
470 					       keyboard->preedit_string);
471 }
472 
473 static const char *
prev_utf8_char(const char * s,const char * p)474 prev_utf8_char(const char *s, const char *p)
475 {
476 	for (--p; p >= s; --p) {
477 		if ((*p & 0xc0) != 0x80)
478 			return p;
479 	}
480 	return NULL;
481 }
482 
483 static void
delete_before_cursor(struct virtual_keyboard * keyboard)484 delete_before_cursor(struct virtual_keyboard *keyboard)
485 {
486 	const char *start, *end;
487 
488 	if (!keyboard->surrounding_text) {
489 		dbg("delete_before_cursor: No surrounding text available\n");
490 		return;
491 	}
492 
493 	start = prev_utf8_char(keyboard->surrounding_text,
494 			       keyboard->surrounding_text + keyboard->surrounding_cursor);
495 	if (!start) {
496 		dbg("delete_before_cursor: No previous character to delete\n");
497 		return;
498 	}
499 
500 	end = keyboard->surrounding_text + keyboard->surrounding_cursor;
501 
502 	wl_input_method_context_delete_surrounding_text(keyboard->context,
503 							(start - keyboard->surrounding_text) - keyboard->surrounding_cursor,
504 							end - start);
505 	wl_input_method_context_commit_string(keyboard->context,
506 					      keyboard->serial,
507 					      "");
508 
509 	/* Update surrounding text */
510 	keyboard->surrounding_cursor = start - keyboard->surrounding_text;
511 	keyboard->surrounding_text[keyboard->surrounding_cursor] = '\0';
512 	if (*end)
513 		memmove(keyboard->surrounding_text + keyboard->surrounding_cursor, end, strlen(end));
514 }
515 
516 static char *
append(char * s1,const char * s2)517 append(char *s1, const char *s2)
518 {
519 	int len1, len2;
520 	char *s;
521 
522 	len1 = strlen(s1);
523 	len2 = strlen(s2);
524 	s = xrealloc(s1, len1 + len2 + 1);
525 	memcpy(s + len1, s2, len2);
526 	s[len1 + len2] = '\0';
527 
528 	return s;
529 }
530 
531 static void
keyboard_handle_key(struct keyboard * keyboard,uint32_t time,const struct key * key,struct input * input,enum wl_pointer_button_state state)532 keyboard_handle_key(struct keyboard *keyboard, uint32_t time, const struct key *key, struct input *input, enum wl_pointer_button_state state)
533 {
534 	const char *label = NULL;
535 
536 	switch(keyboard->state) {
537 	case KEYBOARD_STATE_DEFAULT :
538 		label = key->label;
539 		break;
540 	case KEYBOARD_STATE_UPPERCASE :
541 		label = key->uppercase;
542 		break;
543 	case KEYBOARD_STATE_SYMBOLS :
544 		label = key->symbol;
545 		break;
546 	}
547 
548 	xkb_mod_mask_t mod_mask = keyboard->state == KEYBOARD_STATE_DEFAULT ? 0 : keyboard->keyboard->keysym.shift_mask;
549 	uint32_t key_state = (state == WL_POINTER_BUTTON_STATE_PRESSED) ? WL_KEYBOARD_KEY_STATE_PRESSED : WL_KEYBOARD_KEY_STATE_RELEASED;
550 
551 	switch (key->key_type) {
552 		case keytype_default:
553 			if (state != WL_POINTER_BUTTON_STATE_PRESSED)
554 				break;
555 
556 			keyboard->keyboard->preedit_string =
557 				append(keyboard->keyboard->preedit_string,
558 				       label);
559 			virtual_keyboard_send_preedit(keyboard->keyboard, -1);
560 			break;
561 		case keytype_backspace:
562 			if (state != WL_POINTER_BUTTON_STATE_PRESSED)
563 				break;
564 
565 			if (strlen(keyboard->keyboard->preedit_string) == 0) {
566 				delete_before_cursor(keyboard->keyboard);
567 			} else {
568 				keyboard->keyboard->preedit_string[strlen(keyboard->keyboard->preedit_string) - 1] = '\0';
569 				virtual_keyboard_send_preedit(keyboard->keyboard, -1);
570 			}
571 			break;
572 		case keytype_enter:
573 			virtual_keyboard_commit_preedit(keyboard->keyboard);
574 			wl_input_method_context_keysym(keyboard->keyboard->context,
575 						       display_get_serial(keyboard->keyboard->display),
576 						       time,
577 						       XKB_KEY_Return, key_state, mod_mask);
578 			break;
579 		case keytype_space:
580 			if (state != WL_POINTER_BUTTON_STATE_PRESSED)
581 				break;
582 			keyboard->keyboard->preedit_string =
583 				append(keyboard->keyboard->preedit_string, " ");
584 			virtual_keyboard_commit_preedit(keyboard->keyboard);
585 			break;
586 		case keytype_switch:
587 			if (state != WL_POINTER_BUTTON_STATE_PRESSED)
588 				break;
589 			switch(keyboard->state) {
590 			case KEYBOARD_STATE_DEFAULT:
591 				keyboard->state = KEYBOARD_STATE_UPPERCASE;
592 				break;
593 			case KEYBOARD_STATE_UPPERCASE:
594 				keyboard->state = KEYBOARD_STATE_DEFAULT;
595 				break;
596 			case KEYBOARD_STATE_SYMBOLS:
597 				keyboard->state = KEYBOARD_STATE_UPPERCASE;
598 				break;
599 			}
600 			break;
601 		case keytype_symbols:
602 			if (state != WL_POINTER_BUTTON_STATE_PRESSED)
603 				break;
604 			switch(keyboard->state) {
605 			case KEYBOARD_STATE_DEFAULT:
606 				keyboard->state = KEYBOARD_STATE_SYMBOLS;
607 				break;
608 			case KEYBOARD_STATE_UPPERCASE:
609 				keyboard->state = KEYBOARD_STATE_SYMBOLS;
610 				break;
611 			case KEYBOARD_STATE_SYMBOLS:
612 				keyboard->state = KEYBOARD_STATE_DEFAULT;
613 				break;
614 			}
615 			break;
616 		case keytype_tab:
617 			virtual_keyboard_commit_preedit(keyboard->keyboard);
618 			wl_input_method_context_keysym(keyboard->keyboard->context,
619 						       display_get_serial(keyboard->keyboard->display),
620 						       time,
621 						       XKB_KEY_Tab, key_state, mod_mask);
622 			break;
623 		case keytype_arrow_up:
624 			virtual_keyboard_commit_preedit(keyboard->keyboard);
625 			wl_input_method_context_keysym(keyboard->keyboard->context,
626 						       display_get_serial(keyboard->keyboard->display),
627 						       time,
628 						       XKB_KEY_Up, key_state, mod_mask);
629 			break;
630 		case keytype_arrow_left:
631 			virtual_keyboard_commit_preedit(keyboard->keyboard);
632 			wl_input_method_context_keysym(keyboard->keyboard->context,
633 						       display_get_serial(keyboard->keyboard->display),
634 						       time,
635 						       XKB_KEY_Left, key_state, mod_mask);
636 			break;
637 		case keytype_arrow_right:
638 			virtual_keyboard_commit_preedit(keyboard->keyboard);
639 			wl_input_method_context_keysym(keyboard->keyboard->context,
640 						       display_get_serial(keyboard->keyboard->display),
641 						       time,
642 						       XKB_KEY_Right, key_state, mod_mask);
643 			break;
644 		case keytype_arrow_down:
645 			virtual_keyboard_commit_preedit(keyboard->keyboard);
646 			wl_input_method_context_keysym(keyboard->keyboard->context,
647 						       display_get_serial(keyboard->keyboard->display),
648 						       time,
649 						       XKB_KEY_Down, key_state, mod_mask);
650 			break;
651 		case keytype_style:
652 			if (state != WL_POINTER_BUTTON_STATE_PRESSED)
653 				break;
654 			keyboard->keyboard->preedit_style = (keyboard->keyboard->preedit_style + 1) % 8; /* TODO */
655 			virtual_keyboard_send_preedit(keyboard->keyboard, -1);
656 			break;
657 	}
658 }
659 
660 static void
button_handler(struct widget * widget,struct input * input,uint32_t time,uint32_t button,enum wl_pointer_button_state state,void * data)661 button_handler(struct widget *widget,
662 	       struct input *input, uint32_t time,
663 	       uint32_t button,
664 	       enum wl_pointer_button_state state, void *data)
665 {
666 	struct keyboard *keyboard = data;
667 	struct rectangle allocation;
668 	int32_t x, y;
669 	int row, col;
670 	unsigned int i;
671 	const struct layout *layout;
672 
673 	layout = get_current_layout(keyboard->keyboard);
674 
675 	if (button != BTN_LEFT) {
676 		return;
677 	}
678 
679 	input_get_position(input, &x, &y);
680 
681 	widget_get_allocation(keyboard->widget, &allocation);
682 	x -= allocation.x;
683 	y -= allocation.y;
684 
685 	row = y / key_height;
686 	col = x / key_width + row * layout->columns;
687 	for (i = 0; i < layout->count; ++i) {
688 		col -= layout->keys[i].width;
689 		if (col < 0) {
690 			keyboard_handle_key(keyboard, time, &layout->keys[i], input, state);
691 			break;
692 		}
693 	}
694 
695 	widget_schedule_redraw(widget);
696 }
697 
698 static void
touch_handler(struct input * input,uint32_t time,float x,float y,uint32_t state,void * data)699 touch_handler(struct input *input, uint32_t time,
700 	      float x, float y, uint32_t state, void *data)
701 {
702 	struct keyboard *keyboard = data;
703 	struct rectangle allocation;
704 	int row, col;
705 	unsigned int i;
706 	const struct layout *layout;
707 
708 	layout = get_current_layout(keyboard->keyboard);
709 
710 	widget_get_allocation(keyboard->widget, &allocation);
711 
712 	x -= allocation.x;
713 	y -= allocation.y;
714 
715 	row = (int)y / key_height;
716 	col = (int)x / key_width + row * layout->columns;
717 	for (i = 0; i < layout->count; ++i) {
718 		col -= layout->keys[i].width;
719 		if (col < 0) {
720 			keyboard_handle_key(keyboard, time,
721 					    &layout->keys[i], input, state);
722 			break;
723 		}
724 	}
725 
726 	widget_schedule_redraw(keyboard->widget);
727 }
728 
729 static void
touch_down_handler(struct widget * widget,struct input * input,uint32_t serial,uint32_t time,int32_t id,float x,float y,void * data)730 touch_down_handler(struct widget *widget, struct input *input,
731 		   uint32_t serial, uint32_t time, int32_t id,
732 		   float x, float y, void *data)
733 {
734   touch_handler(input, time, x, y,
735 		WL_POINTER_BUTTON_STATE_PRESSED, data);
736 }
737 
738 static void
touch_up_handler(struct widget * widget,struct input * input,uint32_t serial,uint32_t time,int32_t id,void * data)739 touch_up_handler(struct widget *widget, struct input *input,
740 		 uint32_t serial, uint32_t time, int32_t id,
741 		 void *data)
742 {
743   float x, y;
744 
745   input_get_touch(input, id, &x, &y);
746 
747   touch_handler(input, time, x, y,
748 		WL_POINTER_BUTTON_STATE_RELEASED, data);
749 }
750 
751 static void
handle_surrounding_text(void * data,struct wl_input_method_context * context,const char * text,uint32_t cursor,uint32_t anchor)752 handle_surrounding_text(void *data,
753 			struct wl_input_method_context *context,
754 			const char *text,
755 			uint32_t cursor,
756 			uint32_t anchor)
757 {
758 	struct virtual_keyboard *keyboard = data;
759 
760 	free(keyboard->surrounding_text);
761 	keyboard->surrounding_text = strdup(text);
762 
763 	keyboard->surrounding_cursor = cursor;
764 }
765 
766 static void
handle_reset(void * data,struct wl_input_method_context * context)767 handle_reset(void *data,
768 	     struct wl_input_method_context *context)
769 {
770 	struct virtual_keyboard *keyboard = data;
771 
772 	dbg("Reset pre-edit buffer\n");
773 
774 	if (strlen(keyboard->preedit_string)) {
775 		free(keyboard->preedit_string);
776 		keyboard->preedit_string = strdup("");
777 	}
778 }
779 
780 static void
handle_content_type(void * data,struct wl_input_method_context * context,uint32_t hint,uint32_t purpose)781 handle_content_type(void *data,
782 		    struct wl_input_method_context *context,
783 		    uint32_t hint,
784 		    uint32_t purpose)
785 {
786 	struct virtual_keyboard *keyboard = data;
787 
788 	keyboard->content_hint = hint;
789 	keyboard->content_purpose = purpose;
790 }
791 
792 static void
handle_invoke_action(void * data,struct wl_input_method_context * context,uint32_t button,uint32_t index)793 handle_invoke_action(void *data,
794 		     struct wl_input_method_context *context,
795 		     uint32_t button,
796 		     uint32_t index)
797 {
798 	struct virtual_keyboard *keyboard = data;
799 
800 	if (button != BTN_LEFT)
801 		return;
802 
803 	virtual_keyboard_send_preedit(keyboard, index);
804 }
805 
806 static void
handle_commit_state(void * data,struct wl_input_method_context * context,uint32_t serial)807 handle_commit_state(void *data,
808 		    struct wl_input_method_context *context,
809 		    uint32_t serial)
810 {
811 	struct virtual_keyboard *keyboard = data;
812 	const struct layout *layout;
813 
814 	keyboard->serial = serial;
815 
816 	layout = get_current_layout(keyboard);
817 
818 	if (keyboard->surrounding_text)
819 		dbg("Surrounding text updated: %s\n", keyboard->surrounding_text);
820 
821 	window_schedule_resize(keyboard->keyboard->window,
822 			       layout->columns * key_width,
823 			       layout->rows * key_height);
824 
825 	wl_input_method_context_language(context, keyboard->serial, layout->language);
826 	wl_input_method_context_text_direction(context, keyboard->serial, layout->text_direction);
827 
828 	widget_schedule_redraw(keyboard->keyboard->widget);
829 }
830 
831 static void
handle_preferred_language(void * data,struct wl_input_method_context * context,const char * language)832 handle_preferred_language(void *data,
833 			  struct wl_input_method_context *context,
834 			  const char *language)
835 {
836 	struct virtual_keyboard *keyboard = data;
837 
838 	if (keyboard->preferred_language)
839 		free(keyboard->preferred_language);
840 
841 	keyboard->preferred_language = NULL;
842 
843 	if (language)
844 		keyboard->preferred_language = strdup(language);
845 }
846 
847 static const struct wl_input_method_context_listener input_method_context_listener = {
848 	handle_surrounding_text,
849 	handle_reset,
850 	handle_content_type,
851 	handle_invoke_action,
852 	handle_commit_state,
853 	handle_preferred_language
854 };
855 
856 static void
input_method_activate(void * data,struct wl_input_method * input_method,struct wl_input_method_context * context)857 input_method_activate(void *data,
858 		      struct wl_input_method *input_method,
859 		      struct wl_input_method_context *context)
860 {
861 	struct virtual_keyboard *keyboard = data;
862 	struct wl_array modifiers_map;
863 	const struct layout *layout;
864 
865 	keyboard->keyboard->state = KEYBOARD_STATE_DEFAULT;
866 
867 	if (keyboard->context)
868 		wl_input_method_context_destroy(keyboard->context);
869 
870 	if (keyboard->preedit_string)
871 		free(keyboard->preedit_string);
872 
873 	keyboard->preedit_string = strdup("");
874 	keyboard->content_hint = 0;
875 	keyboard->content_purpose = 0;
876 	free(keyboard->preferred_language);
877 	keyboard->preferred_language = NULL;
878 	free(keyboard->surrounding_text);
879 	keyboard->surrounding_text = NULL;
880 
881 	keyboard->serial = 0;
882 
883 	keyboard->context = context;
884 	wl_input_method_context_add_listener(context,
885 					     &input_method_context_listener,
886 					     keyboard);
887 
888 	wl_array_init(&modifiers_map);
889 	keysym_modifiers_add(&modifiers_map, "Shift");
890 	keysym_modifiers_add(&modifiers_map, "Control");
891 	keysym_modifiers_add(&modifiers_map, "Mod1");
892 	wl_input_method_context_modifiers_map(context, &modifiers_map);
893 	keyboard->keysym.shift_mask = keysym_modifiers_get_mask(&modifiers_map, "Shift");
894 	wl_array_release(&modifiers_map);
895 
896 	layout = get_current_layout(keyboard);
897 
898 	window_schedule_resize(keyboard->keyboard->window,
899 			       layout->columns * key_width,
900 			       layout->rows * key_height);
901 
902 	wl_input_method_context_language(context, keyboard->serial, layout->language);
903 	wl_input_method_context_text_direction(context, keyboard->serial, layout->text_direction);
904 
905 	widget_schedule_redraw(keyboard->keyboard->widget);
906 }
907 
908 static void
input_method_deactivate(void * data,struct wl_input_method * input_method,struct wl_input_method_context * context)909 input_method_deactivate(void *data,
910 			struct wl_input_method *input_method,
911 			struct wl_input_method_context *context)
912 {
913 	struct virtual_keyboard *keyboard = data;
914 
915 	if (!keyboard->context)
916 		return;
917 
918 	wl_input_method_context_destroy(keyboard->context);
919 	keyboard->context = NULL;
920 }
921 
922 static const struct wl_input_method_listener input_method_listener = {
923 	input_method_activate,
924 	input_method_deactivate
925 };
926 
927 static void
global_handler(struct display * display,uint32_t name,const char * interface,uint32_t version,void * data)928 global_handler(struct display *display, uint32_t name,
929 	       const char *interface, uint32_t version, void *data)
930 {
931 	struct virtual_keyboard *keyboard = data;
932 
933 	if (!strcmp(interface, "wl_input_panel")) {
934 		keyboard->input_panel =
935 			display_bind(display, name, &wl_input_panel_interface, 1);
936 	} else if (!strcmp(interface, "wl_input_method")) {
937 		keyboard->input_method =
938 			display_bind(display, name,
939 				     &wl_input_method_interface, 1);
940 		wl_input_method_add_listener(keyboard->input_method, &input_method_listener, keyboard);
941 	}
942 }
943 
944 static void
keyboard_create(struct output * output,struct virtual_keyboard * virtual_keyboard)945 keyboard_create(struct output *output, struct virtual_keyboard *virtual_keyboard)
946 {
947 	struct keyboard *keyboard;
948 	const struct layout *layout;
949 	struct wl_input_panel_surface *ips;
950 
951 	layout = get_current_layout(virtual_keyboard);
952 
953 	keyboard = xzalloc(sizeof *keyboard);
954 	keyboard->keyboard = virtual_keyboard;
955 	keyboard->window = window_create_custom(virtual_keyboard->display);
956 	keyboard->widget = window_add_widget(keyboard->window, keyboard);
957 
958 	virtual_keyboard->keyboard = keyboard;
959 
960 	window_set_title(keyboard->window, "Virtual keyboard");
961 	window_set_user_data(keyboard->window, keyboard);
962 
963 	widget_set_redraw_handler(keyboard->widget, redraw_handler);
964 	widget_set_resize_handler(keyboard->widget, resize_handler);
965 	widget_set_button_handler(keyboard->widget, button_handler);
966 	widget_set_touch_down_handler(keyboard->widget, touch_down_handler);
967 	widget_set_touch_up_handler(keyboard->widget, touch_up_handler);
968 
969 	window_schedule_resize(keyboard->window,
970 			       layout->columns * key_width,
971 			       layout->rows * key_height);
972 
973 
974 	ips = wl_input_panel_get_input_panel_surface(virtual_keyboard->input_panel,
975 						     window_get_wl_surface(keyboard->window));
976 
977 	wl_input_panel_surface_set_toplevel(ips,
978 					    output_get_wl_output(output),
979 					    WL_INPUT_PANEL_SURFACE_POSITION_CENTER_BOTTOM);
980 }
981 
982 int
main(int argc,char * argv[])983 main(int argc, char *argv[])
984 {
985 	struct virtual_keyboard virtual_keyboard;
986 	struct output *output;
987 
988 	memset(&virtual_keyboard, 0, sizeof virtual_keyboard);
989 
990 	virtual_keyboard.display = display_create(&argc, argv);
991 	if (virtual_keyboard.display == NULL) {
992 		fprintf(stderr, "failed to create display: %m\n");
993 		return -1;
994 	}
995 
996 	display_set_user_data(virtual_keyboard.display, &virtual_keyboard);
997 	display_set_global_handler(virtual_keyboard.display, global_handler);
998 
999 	if (virtual_keyboard.input_panel == NULL) {
1000 		fprintf(stderr, "No input panel global\n");
1001 		return -1;
1002 	}
1003 
1004 	output = display_get_output(virtual_keyboard.display);
1005 	keyboard_create(output, &virtual_keyboard);
1006 
1007 	display_run(virtual_keyboard.display);
1008 
1009 	return 0;
1010 }
1011