svkbd

Unnamed repository; edit this file 'description' to name the repository.
git clone git://git.nihaljere.xyz/svkbd
Log | Files | Refs | README | LICENSE

svkbd.c (25950B)


      1 /* See LICENSE file for copyright and license details. */
      2 #include <poll.h>
      3 #include <sys/time.h>
      4 
      5 #include <ctype.h>
      6 #include <float.h>
      7 #include <locale.h>
      8 #include <signal.h>
      9 #include <stdarg.h>
     10 #include <stdio.h>
     11 #include <stdlib.h>
     12 #include <string.h>
     13 #include <time.h>
     14 #include <unistd.h>
     15 
     16 #include <wayland-client.h>
     17 #include <wld/wayland.h>
     18 #include <wld/wld.h>
     19 #include <swc.h>
     20 #include <xkbcommon/xkbcommon.h>
     21 #include <linux/input-event-codes.h>
     22 
     23 #include "drw.h"
     24 #include "util.h"
     25 #include "swc-client-protocol.h"
     26 #include "input-method-unstable-v2-client-protocol.h"
     27 
     28 /* macros */
     29 #define LENGTH(x)		 (sizeof x / sizeof x[0])
     30 #define STRINGTOKEYSYM(X) (XStringToxkb_keysym_t(X))
     31 #define TEXTW(X)		  (drw_fontset_getwidth(drw, (X)))
     32 
     33 /* enums */
     34 enum {
     35 	SchemeNorm, SchemeNormABC, SchemeNormABCShift, SchemeNormShift, SchemePress,
     36 	SchemePressShift, SchemeHighlight, SchemeHighlightShift, SchemeOverlay,
     37 	SchemeOverlayShift, SchemeLast
     38 };
     39 
     40 /* typedefs */
     41 typedef struct {
     42 	char *label;
     43 	char *label2;
     44 	xkb_keysym_t keysym;
     45 	unsigned int width;
     46 	char *str;
     47 	xkb_keysym_t modifier;
     48 	int x, y, w, h;
     49 	bool pressed;
     50 	bool highlighted;
     51 	bool isoverlay;
     52 } Key;
     53 
     54 typedef struct {
     55 	xkb_keysym_t mod;
     56 	unsigned int button;
     57 } Buttonmod;
     58 
     59 /* function declarations */
     60 static void printdbg(const char *fmt, ...);
     61 static void cleanup(void);
     62 static void countrows();
     63 static int countkeys(Key *layer);
     64 static void drawkeyboard(void);
     65 static void drawkey(Key *k);
     66 static Key *findkey(int x, int y);
     67 static void press(Key *k);
     68 static double get_press_duration();
     69 static void run(void);
     70 static void setup(void);
     71 static void simulate_keypress(xkb_keysym_t keysym);
     72 static void simulate_keyrelease(xkb_keysym_t keysym);
     73 static void showoverlay(int idx);
     74 static void hideoverlay();
     75 static void cyclelayer();
     76 static void setlayer();
     77 static void togglelayer();
     78 static void unpress(Key *k);
     79 static void updatekeys();
     80 static void printkey(Key *k, xkb_keysym_t mod);
     81 
     82 /* variables */
     83 static Drw *drw;
     84 static Clr* scheme[SchemeLast];
     85 static bool running = true, isdock = false;
     86 static struct timeval pressbegin;
     87 static int currentlayer = 0;
     88 static int enableoverlays = 1;
     89 static int currentoverlay = -1; /* -1 = no overlay */
     90 static int pressonrelease = 1;
     91 static xkb_keysym_t overlaykeysym = 0; /* keysym for which the overlay is presented */
     92 static int releaseprotect = 0; /* set to 1 after overlay is shown, protecting against immediate release */
     93 static int tmp_keycode = 1;
     94 static int rows = 0, ww = 0, wh = 0, wx = 0, wy = 0;
     95 static int simulateoutput = 1; /* simulate key presses for X */
     96 static int printoutput = 0; /* print key pressed to stdout */
     97 static char *name = "svkbd";
     98 static int debug = 0;
     99 static int numlayers = 0;
    100 static int numkeys = 0;
    101 
    102 static char *colors[10][2]; /* 10 schemes, 2 colors each */
    103 static char *fonts[] = { 0 };
    104 
    105 static xkb_keysym_t ispressingkeysym;
    106 
    107 bool ispressing = false;
    108 bool sigtermd = false;
    109 
    110 static struct {
    111 	int x, y;
    112 } ptrstate;
    113 
    114 #define MAX_POINTS 32
    115 
    116 /* we assume that the slot id is at maximum the number of fingers on the screen */
    117 static struct {
    118 	int x, y;
    119 	Key *k;
    120 } touchstate[MAX_POINTS];
    121 
    122 static int mon = -1;
    123 static struct wl_display *dpy;
    124 static struct wl_compositor *compositor;
    125 static struct wl_pointer *pointer;
    126 static struct wl_touch *touch;
    127 static struct wl_seat *seat;
    128 static struct wl_surface *surface;
    129 static struct wl_registry *reg;
    130 static struct swc_panel_manager *panelman;
    131 static struct swc_panel *panel;
    132 static struct zwp_input_method_manager_v2 *immanager;
    133 static struct zwp_input_method_v2 *im;
    134 
    135 /* Input Method */
    136 #define MAX_SURROUNDING_TEXT 4000
    137 static char surrounding_text[MAX_SURROUNDING_TEXT];
    138 static char surrounding_text2[MAX_SURROUNDING_TEXT];
    139 static uint32_t cursor;
    140 static uint32_t cursor2;
    141 static uint32_t anchor;
    142 static uint32_t anchor2;
    143 static uint32_t cause;
    144 static uint32_t cause2;
    145 static uint32_t hint;
    146 static uint32_t hint2;
    147 static uint32_t purpose;
    148 static uint32_t purpose2;
    149 static bool active;
    150 static bool active2;
    151 static uint32_t serial = 0;
    152 
    153 /* configuration, allows nested code to access above variables */
    154 #include "config.h"
    155 #ifndef LAYOUT
    156 #error "make sure to define LAYOUT"
    157 #endif
    158 #include LAYOUT
    159 
    160 static Key keys[KEYS] = { NULL };
    161 static Key* layers[LAYERS];
    162 
    163 void
    164 cleanup(void)
    165 {
    166 	int i;
    167 
    168 	for (i = 0; i < SchemeLast; i++)
    169 		free(scheme[i]);
    170 	drw_sync(drw);
    171 	drw_free(drw);
    172 }
    173 
    174 void
    175 countrows(void)
    176 {
    177 	int i;
    178 
    179 	for (i = 0, rows = 1; i < numkeys; i++) {
    180 		if (keys[i].keysym == 0) {
    181 			rows++;
    182 			if ((i > 0) && (keys[i-1].keysym == 0)) {
    183 				rows--;
    184 				break;
    185 			}
    186 		}
    187 	}
    188 }
    189 
    190 int
    191 countkeys(Key *layer)
    192 {
    193 	int i, nkeys = 0;
    194 
    195 	for (i = 0; i < KEYS; i++) {
    196 		if (i > 0 && layer[i].keysym == 0 && layer[i - 1].keysym == 0) {
    197 			nkeys--;
    198 			break;
    199 		}
    200 		nkeys++;
    201 	}
    202 
    203 	return nkeys;
    204 }
    205 
    206 void
    207 drawkeyboard(void)
    208 {
    209 	int i;
    210 	warn("drawing keyboard...");
    211 	wld_set_target_surface(drw->renderer, drw->surface);
    212 
    213 	for (i = 0; i < numkeys; i++) {
    214 		if (keys[i].keysym != 0)
    215 			drawkey(&keys[i]);
    216 	}
    217 	drw_map(drw, surface, 0, 0, ww, wh);
    218 }
    219 
    220 void
    221 drawkey(Key *k)
    222 {
    223 	int x, y, w, h;
    224 	const char *l;
    225 
    226 	wld_set_target_surface(drw->renderer, drw->surface);
    227 	int use_scheme = SchemeNorm;
    228 
    229 	if (k->pressed)
    230 		use_scheme = SchemePress;
    231 	else if (k->highlighted)
    232 		use_scheme = SchemeHighlight;
    233 	else if (k->isoverlay)
    234 		use_scheme = SchemeOverlay;
    235 	else if ((k->keysym == XKB_KEY_Return) ||
    236 			((k->keysym >= XKB_KEY_a) && (k->keysym <= XKB_KEY_z)) ||
    237 			((k->keysym >= XKB_KEY_Cyrillic_io) && (k->keysym <= XKB_KEY_Cyrillic_hardsign)))
    238 		use_scheme = SchemeNormABC;
    239 	else
    240 		use_scheme = SchemeNorm;
    241 
    242 	drw_setscheme(drw, scheme[use_scheme]);
    243 	drw_rect(drw, k->x, k->y, k->w, k->h, 1, 1);
    244 
    245 	if (k->keysym == XKB_KEY_KP_Insert) {
    246 		if (enableoverlays) {
    247 			l = "≅";
    248 		} else {
    249 			l = "≇";
    250 		}
    251 	} else if (k->label) {
    252 		l = k->label;
    253 	} else {
    254 		warn("key missing label");
    255 	}
    256 	h = drw->fonts[0].wld->height + 10;
    257 	y = k->y + (k->h / 2) - (h / 2);
    258 	w = TEXTW(l);
    259 	x = k->x + (k->w / 2) - (w / 2);
    260 	drw_text(drw, x, y, w, h, 0, l, 0);
    261 	if (k->label2) {
    262 		if (use_scheme == SchemeNorm)
    263 			use_scheme = SchemeNormShift;
    264 		else if (use_scheme == SchemeNormABC)
    265 			use_scheme = SchemeNormABCShift;
    266 		else if (use_scheme == SchemePress)
    267 			use_scheme = SchemePressShift;
    268 		else if (use_scheme == SchemeHighlight)
    269 			use_scheme = SchemeHighlightShift;
    270 		else if (use_scheme == SchemeOverlay)
    271 			use_scheme = SchemeOverlayShift;
    272 		drw_setscheme(drw, scheme[use_scheme]);
    273 		x += w;
    274 		//y -= 15;
    275 		l = k->label2;
    276 		w = TEXTW(l);
    277 		drw_text(drw, x, y, w, h, 0, l, 0);
    278 	}
    279 }
    280 
    281 Key *
    282 findkey(int x, int y) {
    283 	int i;
    284 
    285 	for (i = 0; i < numkeys; i++) {
    286 		if (keys[i].keysym && x > keys[i].x &&
    287 				x < keys[i].x + keys[i].w &&
    288 				y > keys[i].y && y < keys[i].y + keys[i].h) {
    289 			return &keys[i];
    290 		}
    291 	}
    292 	return NULL;
    293 }
    294 
    295 int
    296 hasoverlay(xkb_keysym_t keysym)
    297 {
    298 	int begin, i;
    299 
    300 	begin = 0;
    301 	for (i = 0; i < OVERLAYS; i++) {
    302 		if (overlay[i].keysym == XKB_KEY_Cancel) {
    303 			begin = i + 1;
    304 		} else if (overlay[i].keysym == keysym) {
    305 			return begin + 1;
    306 		}
    307 	}
    308 	return -1;
    309 }
    310 
    311 void
    312 record_press_begin(xkb_keysym_t ks)
    313 {
    314 	/* record the begin of the press, don't simulate the actual keypress yet */
    315 	gettimeofday(&pressbegin, NULL);
    316 	ispressingkeysym = ks;
    317 }
    318 
    319 
    320 /* TODO replace with something saner */
    321 bool
    322 IsModifierKey(int ks)
    323 {
    324 	return (ks >= XKB_KEY_Shift_L && ks <= XKB_KEY_Hyper_R);
    325 }
    326 
    327 void
    328 press(Key *k)
    329 {
    330 	fprintf(stderr, "pressed key %s\n", k->label);
    331 	k->pressed = true;
    332 }
    333 
    334 void
    335 printkey(Key *k, xkb_keysym_t mod)
    336 {
    337 	int i, shift;
    338 
    339 	shift = (mod == XKB_KEY_Shift_L) || (mod == XKB_KEY_Shift_R) || (mod == XKB_KEY_Shift_Lock);
    340 	if (!shift) {
    341 		for (i = 0; i < numkeys; i++) {
    342 			if ((keys[i].pressed) && ((keys[i].keysym == XKB_KEY_Shift_L) ||
    343 				(keys[i].keysym == XKB_KEY_Shift_R) || (keys[i].keysym == XKB_KEY_Shift_Lock))) {
    344 				shift = true;
    345 				break;
    346 			}
    347 		}
    348 	}
    349 	printdbg("Printing key %ld (shift=%d)\n", k->keysym, shift);
    350 	if (k->keysym == XKB_KEY_Cancel)
    351 		return;
    352 
    353 	xkb_keysym_t *keysym = &(k->keysym);
    354 
    355 	char buffer[32];
    356 	xkb_keysym_t ignore;
    357 	int l = xkb_keysym_get_name(*keysym, buffer, sizeof(buffer));
    358 	buffer[l] = '\0';
    359 	printdbg("Print buffer: [%s] (length=%d)\n", &buffer, l);
    360 	printf("%s", buffer);
    361 }
    362 
    363 void
    364 simulate_keypress(xkb_keysym_t keysym)
    365 {
    366 }
    367 
    368 void
    369 simulate_keyrelease(xkb_keysym_t keysym)
    370 {
    371 }
    372 
    373 double
    374 get_press_duration(void)
    375 {
    376 	struct timeval now;
    377 
    378 	gettimeofday(&now, NULL);
    379 
    380 	return (double) ((now.tv_sec * 1000000L + now.tv_usec) -
    381 		   (pressbegin.tv_sec * 1000000L + pressbegin.tv_usec)) /
    382 		   (double) 1000000L;
    383 }
    384 
    385 void
    386 unpress(Key *k)
    387 {
    388 	warn("sending...\n");
    389 	int i;
    390 
    391 	if (k != NULL) {
    392 		switch(k->keysym) {
    393 		case XKB_KEY_Cancel:
    394 			cyclelayer();
    395 			return;
    396 		case XKB_KEY_script_switch:
    397 			togglelayer();
    398 			return;
    399 		case XKB_KEY_KP_Insert:
    400 			enableoverlays = !enableoverlays;
    401 			return;
    402 		case XKB_KEY_Break:
    403 			running = false;
    404 			return;
    405 		case XKB_KEY_BackSpace:
    406 			zwp_input_method_v2_delete_surrounding_text(im, 1, 0);
    407 			break;
    408 		case XKB_KEY_Return:
    409 			zwp_input_method_v2_commit_string(im, "\n");
    410 			break;
    411 		default:
    412 			zwp_input_method_v2_commit_string(im, k->label);
    413 			break;
    414 		}
    415 		zwp_input_method_v2_commit(im, serial);
    416 
    417 		k->pressed = false;
    418 		fprintf(stderr, "unpress of %s, %d\n", k->label, k->pressed);
    419 	}
    420 
    421 }
    422 
    423 static void
    424 regglobal(void *d, struct wl_registry *r, uint32_t name, const char *interface, uint32_t version)
    425 {
    426 	if (strcmp(interface, "wl_compositor") == 0)
    427 		compositor = wl_registry_bind(r, name, &wl_compositor_interface, 1);
    428 	else if (strcmp(interface, "wl_seat") == 0)
    429 		seat = wl_registry_bind(r, name, &wl_seat_interface, 1);
    430 	else if (strcmp(interface, "swc_panel_manager") == 0)
    431 		panelman = wl_registry_bind(r, name, &swc_panel_manager_interface, 1);
    432 	else if (strcmp(interface, "zwp_input_method_manager_v2") == 0)
    433 		immanager = wl_registry_bind(r, name, &zwp_input_method_manager_v2_interface, 1);
    434 }
    435 
    436 static void
    437 regglobalremove(void *d, struct wl_registry *reg, uint32_t name)
    438 {
    439 }
    440 
    441 static const struct wl_registry_listener reglistener = { regglobal, regglobalremove };
    442 
    443 static void
    444 pointerenter(void *data, struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface, wl_fixed_t sx, wl_fixed_t sy)
    445 {
    446 	ptrstate.x = wl_fixed_to_int(sx);
    447 	ptrstate.y = wl_fixed_to_int(sy);
    448 }
    449 
    450 static void
    451 pointerleave(void *data, struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface)
    452 {
    453 	if (currentoverlay != -1)
    454 		hideoverlay();
    455 	ispressingkeysym = 0;
    456 	unpress(NULL);
    457 }
    458 
    459 static void
    460 pointermotion(void *data, struct wl_pointer *wl_pointer, uint32_t time, wl_fixed_t sx, wl_fixed_t sy)
    461 {
    462 	ptrstate.x = wl_fixed_to_int(sx);
    463 	ptrstate.y = wl_fixed_to_int(sy);
    464 	int i;
    465 	int lostfocus = -1;
    466 	int gainedfocus = -1;
    467 
    468 	for (i = 0; i < numkeys; i++) {
    469 		if (keys[i].keysym && ptrstate.x > keys[i].x
    470 				&& ptrstate.x < keys[i].x + keys[i].w
    471 				&& ptrstate.y > keys[i].y
    472 				&& ptrstate.y < keys[i].y + keys[i].h) {
    473 			if (!keys[i].highlighted) {
    474 				if (ispressing) {
    475 					gainedfocus = i;
    476 				} else {
    477 					keys[i].highlighted = true;
    478 					drawkeyboard();
    479 				}
    480 			}
    481 			continue;
    482 		} else if (keys[i].highlighted) {
    483 			keys[i].highlighted = false;
    484 			drawkeyboard();
    485 		}
    486 	}
    487 
    488 	for (i = 0; i < numkeys; i++) {
    489 		if (!IsModifierKey(keys[i].keysym) && keys[i].pressed && lostfocus != gainedfocus) {
    490 			printdbg("Pressed key lost focus: %ld\n", keys[i].keysym);
    491 			lostfocus = i;
    492 			ispressingkeysym = 0;
    493 			keys[i].pressed = false;
    494 		}
    495 	}
    496 
    497 	if ((lostfocus != -1) && (gainedfocus != -1) && (lostfocus != gainedfocus)) {
    498 		printdbg("Clicking new key that gained focus\n");
    499 		press(&keys[gainedfocus]);
    500 		keys[gainedfocus].pressed = true;
    501 		keys[gainedfocus].highlighted = true;
    502 	}
    503 }
    504 
    505 void
    506 pointerbutton(void *data, struct wl_pointer *wl_pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state)
    507 {
    508 	Key *k;
    509 	int i;
    510 
    511 	ispressing = true;
    512 
    513 	switch (state) {
    514 	case WL_POINTER_BUTTON_STATE_PRESSED:
    515 		if ((k = findkey(ptrstate.x, ptrstate.y)))
    516 			press(k);
    517 
    518 		break;
    519 	
    520 	case WL_POINTER_BUTTON_STATE_RELEASED:
    521 		if ((k = findkey(ptrstate.x, ptrstate.y)))
    522 			unpress(k);
    523 		break;
    524 	}
    525 }
    526 
    527 
    528 static const struct wl_pointer_listener pointerlistener = { pointerenter, pointerleave, pointermotion, pointerbutton };
    529 
    530 void
    531 touchdown(void *data, struct wl_touch *wl_touch, uint32_t serial, uint32_t time, struct wl_surface *surface, int32_t id, wl_fixed_t x, wl_fixed_t y)
    532 {
    533 	Key *k;
    534 
    535 	ispressing = true;
    536 	touchstate[id].x = wl_fixed_to_int(x);
    537 	touchstate[id].y = wl_fixed_to_int(y);
    538 
    539 	if ((k = findkey(touchstate[id].x, touchstate[id].y)))
    540 		press(k);
    541 
    542 	touchstate[id].k = k;
    543 }
    544 
    545 void
    546 touchup(void *data, struct wl_touch *wl_touch, uint32_t serial, uint32_t time, int32_t id)
    547 {
    548 	/*
    549 	Key *k;
    550 	if ((k = findkey(touchstate[id].x, touchstate[id].y)))
    551 		unpress(k);
    552 	touchstate[id].x = DBL_MIN;
    553 	touchstate[id].y = DBL_MIN;
    554 	touchstate[id].k = NULL;
    555 	*/
    556 	unpress(touchstate[id].k);
    557 	touchstate[id].x = -1;
    558 	touchstate[id].y = -1;
    559 	touchstate[id].k = NULL;
    560 }
    561 
    562 void
    563 touchmotion(void *data, struct wl_touch *wl_touch, uint32_t time, int32_t id, wl_fixed_t x, wl_fixed_t y)
    564 {
    565 	Key *k;
    566 	touchstate[id].x = wl_fixed_to_int(x);
    567 	touchstate[id].y = wl_fixed_to_int(y);
    568 
    569 	int i;
    570 	int lostfocus = -1;
    571 	int gainedfocus = -1;
    572 
    573 	if ((k = findkey(touchstate[id].x, touchstate[id].y))) {
    574 		if (k == touchstate[id].k)
    575 			return;
    576 
    577 		if (touchstate[id].k)
    578 			touchstate[id].k->pressed = false;
    579 
    580 		press(k);
    581 		touchstate[id].k = k;
    582 	} else if (touchstate[id].k) {
    583 		touchstate[id].k->pressed = false;
    584 		touchstate[id].k = NULL;
    585 	}
    586 }
    587 
    588 void
    589 touchframe(void *data, struct wl_touch *wl_touch)
    590 {
    591 	drawkeyboard();
    592 }
    593 
    594 void
    595 touchcancel(void *data, struct wl_touch *wl_touch)
    596 {
    597 	int i;
    598 	for (i = 0; i < numkeys; i++)
    599 		keys[i].pressed = false;
    600 
    601 	for (i = 0; i < MAX_POINTS; i++) {
    602 		touchstate[i].x = -1;
    603 		touchstate[i].y = -1;
    604 		touchstate[i].k = NULL;
    605 	}
    606 	drawkeyboard();
    607 	fprintf(stderr, "cancel!\n");
    608 }
    609 
    610 static const struct wl_touch_listener touchlistener = { touchdown, touchup, touchmotion, touchframe , touchcancel};
    611 
    612 void
    613 imactivate(void *data, struct zwp_input_method_v2 *input_method)
    614 {
    615 	surrounding_text2[0] = '\0';
    616 	cause2 = 0;
    617 	hint2 = 0;
    618 	purpose2 = 0;
    619 	active2 = true;
    620 }
    621 
    622 void
    623 imdeactivate(void *data, struct zwp_input_method_v2 *input_method)
    624 {
    625 	active2 = false;
    626 }
    627 
    628 void
    629 imdone(void *data, struct zwp_input_method_v2 *input_method)
    630 {
    631 	serial += 1;
    632 	memcpy(surrounding_text2, surrounding_text, sizeof(surrounding_text));
    633 	cause = cause2;
    634 	hint = hint2;
    635 	purpose = purpose2;
    636 	active = active2;
    637 }
    638 
    639 void
    640 imsurrounding_text(void *data, struct zwp_input_method_v2 *input_method, const char *text, uint32_t tcursor, uint32_t tanchor)
    641 {
    642 	memcpy(surrounding_text2, text, strlen(text));
    643 	cursor2 = tcursor;
    644 	anchor2 = tanchor;
    645 }
    646 
    647 void
    648 imtext_change_cause(void *data, struct zwp_input_method_v2 *input_method, uint32_t tcause)
    649 {
    650 	cause2 = tcause;
    651 }
    652 
    653 void
    654 imcontent_type(void *data, struct zwp_input_method_v2 *input_method, uint32_t thint, uint32_t tpurpose)
    655 {
    656 	hint2 = thint;
    657 	purpose2 = tpurpose;
    658 }
    659 
    660 void
    661 imunavailable(void *data, struct zwp_input_method_v2 *input_method)
    662 {
    663 	zwp_input_method_v2_destroy(im);
    664 	zwp_input_method_manager_v2_destroy(immanager);
    665 }
    666 
    667 static const struct zwp_input_method_v2_listener imlistener = {
    668 	.activate = imactivate,
    669 	.deactivate = imdeactivate,
    670 	.surrounding_text = imsurrounding_text,
    671 	.text_change_cause = imtext_change_cause,
    672 	.content_type = imcontent_type,
    673 	.done = imdone,
    674 	.unavailable = imunavailable
    675 };
    676 
    677 static void
    678 panel_docked(void *data, struct swc_panel *panel, uint32_t length)
    679 {
    680 	ww = length;
    681 }
    682 
    683 static const struct swc_panel_listener panellistener = { .docked = &panel_docked };
    684 
    685 void
    686 run(void)
    687 {
    688 	struct pollfd fds[2];
    689 	struct timeval tv;
    690 	double duration = 0.0;
    691 	int overlayidx = -1;
    692 	int i, r;
    693 
    694 	fds[0].fd = wl_display_get_fd(dpy);
    695 	fds[0].events = POLLIN;
    696 
    697 	/* TODO use timer_create to create timer for long presses */
    698 	fds[1].fd = -1;
    699 	fds[1].events = POLLIN;
    700 	tv.tv_sec = 0;
    701 	tv.tv_usec = scan_rate;
    702 
    703 	while (running) {
    704 		if (poll(fds, sizeof(fds) / sizeof(fds[0]), -1) == -1) {
    705 			fprintf(stderr, "poll failed\n");
    706 			break;
    707 		}
    708 
    709 		if (fds[0].revents & POLLIN) {
    710 			if (wl_display_dispatch(dpy) == -1) {
    711 				warn("failed to dispatch display:");
    712 				break;
    713 			}
    714 		}
    715 
    716 		if (0) {
    717 			/* time-out expired without anything interesting happening, check for long-presses */
    718 			if (ispressing && ispressingkeysym) {
    719 				duration = get_press_duration();
    720 				if (debug >= 2)
    721 					printdbg("%f\n", duration);
    722 				overlayidx = hasoverlay(ispressingkeysym);
    723 				duration = get_press_duration();
    724 				if ((overlayidx != -1) && (duration >= overlay_delay)) {
    725 					printdbg("press duration %f, activating overlay\n", duration);
    726 					showoverlay(overlayidx);
    727 					pressbegin.tv_sec = 0;
    728 					pressbegin.tv_usec = 0;
    729 					ispressingkeysym = 0;
    730 				} else if ((overlayidx == -1) && (duration >= repeat_delay)) {
    731 					printdbg("press duration %f, activating repeat\n", duration);
    732 					simulate_keyrelease(ispressingkeysym);
    733 					simulate_keypress(ispressingkeysym);
    734 				}
    735 			}
    736 		}
    737 		if (r == -1 || sigtermd) {
    738 			/* an error occurred or we received a signal */
    739 			/* E.g. Generally in scripts we want to call SIGTERM on svkbd in which case
    740 					if the user is holding for example the enter key (to execute
    741 					the kill or script that does the kill), that causes an issue
    742 					since then X doesn't know the keyup is never coming.. (since
    743 					process will be dead before finger lifts - in that case we
    744 					just trigger out fake up presses for all keys */
    745 			printdbg("signal received, releasing all keys");
    746 			running = false;
    747 		}
    748 	}
    749 }
    750 
    751 void
    752 setup(void)
    753 {
    754 	int i, j, rh;
    755 
    756 	drw = drw_create(dpy);
    757 
    758 	if (!compositor || !seat || !panelman)
    759 		exit(1);
    760 
    761 	pointer = wl_seat_get_pointer(seat);
    762 	wl_pointer_add_listener(pointer, &pointerlistener, NULL);
    763 
    764 	touch = wl_seat_get_touch(seat);
    765 	wl_touch_add_listener(touch, &touchlistener, NULL);
    766 
    767 	for (i = 0; i < MAX_POINTS; i++) {
    768 		touchstate[i].x = touchstate[i].y = -1;
    769 	}
    770 
    771 	wl_display_roundtrip(dpy);
    772 
    773 	if (!pointer || !touch)
    774 		exit(1);
    775 
    776 	im = zwp_input_method_manager_v2_get_input_method(immanager, seat);
    777 	zwp_input_method_v2_add_listener(im, &imlistener, NULL);
    778 
    779 	wl_display_roundtrip(dpy);
    780 
    781 	if (!im)
    782 		exit(1);
    783 
    784 	/* Apply defaults to font and colors */
    785 	if (!fonts[0])
    786 		fonts[0] = estrdup(defaultfonts[0]);
    787 	for (i = 0; i < SchemeLast; ++i) {
    788 		for (j = 0; j < 2; ++j) {
    789 			if (!colors[i][j])
    790 				colors[i][j] = estrdup(defaultcolors[i][j]);
    791 		}
    792 	}
    793 
    794 	if (!drw_fontset_create(drw, (const char **) fonts, LENGTH(fonts)))
    795 		die("no fonts could be loaded");
    796 	free(fonts[0]);
    797 
    798 	/* init appearance */
    799 	for (j = 0; j < SchemeLast; j++)
    800 		scheme[j] = drw_scm_create(drw, (const char **) colors[j], 2);
    801 
    802 	for (j = 0; j < SchemeLast; ++j) {
    803 		free(colors[j][ColFg]);
    804 		free(colors[j][ColBg]);
    805 	}
    806 
    807 	drw_setscheme(drw, scheme[SchemeNorm]);
    808 
    809 	surface = wl_compositor_create_surface(compositor);
    810 	panel = swc_panel_manager_create_panel(panelman, surface);
    811 	swc_panel_add_listener(panel, &panellistener, NULL);
    812 	swc_panel_dock(panel, SWC_PANEL_EDGE_BOTTOM, NULL, 0);
    813 	wl_display_roundtrip(dpy);
    814 
    815 	/* init appearance */
    816 	countrows();
    817 	/* TODO calculate row height properly */
    818 	rh = drw->fonts[0].wld->height + 15;
    819 	if (!ww)
    820 	   exit(1);
    821 	if (!wh)
    822 		wh = rh * rows;
    823 
    824 
    825 	for (i = 0; i < numkeys; i++)
    826 		keys[i].pressed = 0;
    827 
    828 	drw_resize(drw, surface, ww, wh);
    829 	swc_panel_set_strut(panel, wh, 0, ww);
    830 	updatekeys();
    831 	drawkeyboard();
    832 	wl_display_roundtrip(dpy);
    833 }
    834 
    835 void
    836 updatekeys(void)
    837 {
    838 	int i, j;
    839 	int x = 0, y = 0, h, base, r = rows;
    840 
    841 	h = (wh - 1) / rows;
    842 	for (i = 0; i < numkeys; i++, r--) {
    843 		for (j = i, base = 0; j < numkeys && keys[j].keysym != 0; j++)
    844 			base += keys[j].width;
    845 		for (x = 0; i < numkeys && keys[i].keysym != 0; i++) {
    846 			keys[i].x = x;
    847 			keys[i].y = y;
    848 			keys[i].w = keys[i].width * (ww - 1) / base;
    849 			keys[i].h = r == 1 ? wh - y - 1 : h;
    850 			x += keys[i].w;
    851 		}
    852 		if (base != 0)
    853 			keys[i - 1].w = ww - 1 - keys[i - 1].x;
    854 		y += h;
    855 	}
    856 }
    857 
    858 void
    859 usage(char *argv0)
    860 {
    861 	fprintf(stderr, "usage: %s [-hdnovDOR] [-g geometry] [-fn font] [-l layers] [-s initial_layer]\n", argv0);
    862 	fprintf(stderr, "Options:\n");
    863 	fprintf(stderr, "  -d		 - Set Dock Window Type\n");
    864 	fprintf(stderr, "  -D		 - Enable debug\n");
    865 	fprintf(stderr, "  -O		 - Disable overlays\n");
    866 	fprintf(stderr, "  -R		 - Disable press-on-release\n");
    867 	fprintf(stderr, "  -n		 - Do not simulate key presses for X\n");
    868 	fprintf(stderr, "  -o		 - Print to standard output\n");
    869 	fprintf(stderr, "  -l		 - Comma separated list of layers to enable\n");
    870 	fprintf(stderr, "  -s		 - Layer to select on program start\n");
    871 	fprintf(stderr, "  -H [int]   - Height fraction, one key row takes 1/x of the screen height\n");
    872 	fprintf(stderr, "  -fn [font] - Set font (Xft, e.g: DejaVu Sans:bold:size=20)\n");
    873 	fprintf(stderr, "  -g		 - Set the window position or size using the X geometry format\n");
    874 	exit(1);
    875 }
    876 
    877 void
    878 setlayer(void)
    879 {
    880 	numkeys = countkeys(layers[currentlayer]);
    881 	memcpy(&keys, layers[currentlayer], sizeof(Key) * numkeys);
    882 	countrows();
    883 }
    884 
    885 void
    886 cyclelayer(void)
    887 {
    888 	currentlayer++;
    889 	if (currentlayer >= numlayers)
    890 		currentlayer = 0;
    891 	printdbg("Cycling to layer %d\n", currentlayer);
    892 	setlayer();
    893 	updatekeys();
    894 	drawkeyboard();
    895 }
    896 
    897 void
    898 togglelayer(void)
    899 {
    900 	if (currentlayer > 0) {
    901 		currentlayer = 0;
    902 	} else if (numlayers > 1) {
    903 		currentlayer = 1;
    904 	}
    905 	printdbg("Toggling layer %d\n", currentlayer);
    906 	setlayer();
    907 	updatekeys();
    908 	drawkeyboard();
    909 }
    910 
    911 void
    912 showoverlay(int idx)
    913 {
    914 	int i, j;
    915 
    916 	printdbg("Showing overlay %d\n", idx);
    917 
    918 	/* unpress existing key (visually only) */
    919 	for (i = 0; i < numkeys; i++) {
    920 		if (keys[i].pressed && !IsModifierKey(keys[i].keysym)) {
    921 			keys[i].pressed = 0;
    922 			break;
    923 		}
    924 	}
    925 
    926 	for (i = idx, j=0; i < OVERLAYS; i++, j++) {
    927 		if (overlay[i].keysym == XKB_KEY_Cancel) {
    928 			break;
    929 		}
    930 		while (keys[j].keysym == 0)
    931 			j++;
    932 		if (overlay[i].width > 1)
    933 			j += overlay[i].width - 1;
    934 		keys[j].label = overlay[i].label;
    935 		keys[j].label2 = overlay[i].label2;
    936 		keys[j].keysym = overlay[i].keysym;
    937 		keys[j].modifier = overlay[i].modifier;
    938 		keys[j].isoverlay = true;
    939 	}
    940 	currentoverlay = idx;
    941 	overlaykeysym = ispressingkeysym;
    942 	releaseprotect = 1;
    943 	updatekeys();
    944 	drawkeyboard();
    945 }
    946 
    947 void
    948 hideoverlay(void)
    949 {
    950 	printdbg("Hiding overlay, overlay was #%d\n", currentoverlay);
    951 	currentoverlay = -1;
    952 	overlaykeysym = 0;
    953 	currentlayer--;
    954 	cyclelayer();
    955 }
    956 
    957 void
    958 sigterm(int signo)
    959 {
    960 	running = false;
    961 	sigtermd = true;
    962 	printdbg("SIGTERM received\n");
    963 }
    964 
    965 void
    966 init_layers(char *layer_names_list, const char *initial_layer_name)
    967 {
    968 	char *s;
    969 	int j, found;
    970 
    971 	if (layer_names_list == NULL) {
    972 		numlayers = LAYERS;
    973 		memcpy(&layers, &available_layers, sizeof(available_layers));
    974 		if (initial_layer_name != NULL) {
    975 			for (j = 0; j < LAYERS; j++) {
    976 				if (strcmp(layer_names[j], initial_layer_name) == 0) {
    977 					currentlayer = j;
    978 					break;
    979 				}
    980 			}
    981 		}
    982 	} else {
    983 		s = strtok(layer_names_list, ",");
    984 		while (s != NULL) {
    985 			if (numlayers + 1 > LAYERS)
    986 				die("too many layers specified");
    987 			found = 0;
    988 			for (j = 0; j < LAYERS; j++) {
    989 				if (strcmp(layer_names[j], s) == 0) {
    990 					fprintf(stderr, "Adding layer %s\n", s);
    991 					layers[numlayers] = available_layers[j];
    992 					if (initial_layer_name != NULL && strcmp(layer_names[j], initial_layer_name) == 0) {
    993 						currentlayer = numlayers;
    994 					}
    995 					found = 1;
    996 					break;
    997 				}
    998 			}
    999 			if (!found) {
   1000 				fprintf(stderr, "Undefined layer: %s\n", s);
   1001 				exit(3);
   1002 			}
   1003 			numlayers++;
   1004 			s = strtok(NULL, ",");
   1005 		}
   1006 	}
   1007 	setlayer();
   1008 }
   1009 
   1010 void
   1011 printdbg(const char *fmt, ...)
   1012 {
   1013 	if (!debug)
   1014 		return;
   1015 
   1016 	va_list ap;
   1017 	va_start(ap, fmt);
   1018 	vfprintf(stderr, fmt, ap);
   1019 	va_end(ap);
   1020 	fflush(stderr);
   1021 }
   1022 
   1023 int
   1024 main(int argc, char *argv[])
   1025 {
   1026 	char *initial_layer_name = NULL;
   1027 	char *layer_names_list = NULL;
   1028 	char *tmp;
   1029 	int i, xr, yr, bitm;
   1030 	unsigned int wr, hr;
   1031 
   1032 	signal(SIGTERM, sigterm);
   1033 
   1034 	if (OVERLAYS <= 1) {
   1035 		enableoverlays = 0;
   1036 	} else {
   1037 		if ((tmp = getenv("SVKBD_ENABLEOVERLAYS")))
   1038 			enableoverlays = atoi(tmp);
   1039 	}
   1040 	if ((tmp = getenv("SVKBD_LAYERS")))
   1041 		layer_names_list = estrdup(tmp);
   1042 
   1043 	if ((tmp = getenv("SVKBD_HEIGHTFACTOR")))
   1044 		heightfactor = atoi(tmp);
   1045 
   1046 	if ((tmp = getenv("SVKBD_PRESSONRELEASE"))) /* defaults to 1 */
   1047 		pressonrelease = atoi(tmp);
   1048 
   1049 	/* parse command line arguments */
   1050 	for (i = 1; argv[i]; i++) {
   1051 		if (!strcmp(argv[i], "-v")) {
   1052 			die("svkbd-"VERSION);
   1053 		} else if (!strcmp(argv[i], "-d")) {
   1054 			isdock = true;
   1055 		} else if (!strncmp(argv[i], "-g", 2)) {
   1056 			if (i >= argc - 1)
   1057 				usage(argv[0]);
   1058 
   1059 			/* TODO implement */
   1060 		} else if (!strcmp(argv[i], "-fn")) { /* font or font set */
   1061 			if (i >= argc - 1)
   1062 				usage(argv[0]);
   1063 			fonts[0] = estrdup(argv[++i]);
   1064 		} else if (!strcmp(argv[i], "-D")) {
   1065 			debug = 1;
   1066 		} else if (!strcmp(argv[i], "-h")) {
   1067 			usage(argv[0]);
   1068 		} else if (!strcmp(argv[i], "-O")) {
   1069 			enableoverlays = 0;
   1070 		} else if (!strcmp(argv[i], "-o")) {
   1071 			printoutput = 1;
   1072 		} else if (!strcmp(argv[i], "-n")) {
   1073 			simulateoutput = 0;
   1074 		} else if (!strcmp(argv[i], "-R")) {
   1075 			pressonrelease = 0;
   1076 		} else if (!strcmp(argv[i], "-l")) {
   1077 			if (i >= argc - 1)
   1078 				usage(argv[0]);
   1079 			free(layer_names_list);
   1080 			layer_names_list = estrdup(argv[++i]);
   1081 		} else if (!strcmp(argv[i], "-s")) {
   1082 			if (i >= argc - 1)
   1083 				usage(argv[0]);
   1084 			initial_layer_name = argv[++i];
   1085 		} else if (!strcmp(argv[i], "-H")) {
   1086 			if (i >= argc - 1)
   1087 				usage(argv[0]);
   1088 			heightfactor = atoi(argv[++i]);
   1089 		} else {
   1090 			fprintf(stderr, "Invalid argument: %s\n", argv[i]);
   1091 			usage(argv[0]);
   1092 		}
   1093 	}
   1094 
   1095 	if (printoutput)
   1096 		setbuf(stdout, NULL); /* unbuffered output */
   1097 
   1098 	if (heightfactor <= 0)
   1099 		die("height factor must be a positive integer");
   1100 
   1101 	init_layers(layer_names_list, initial_layer_name);
   1102 
   1103 	if (!setlocale(LC_CTYPE, ""))
   1104 		fprintf(stderr, "warning: no locale support");
   1105 	if (!(dpy = wl_display_connect(NULL)))
   1106 		die("cannot open display");
   1107 	if (!(reg = wl_display_get_registry(dpy)))
   1108 		die("cannot get registry");
   1109 	wl_registry_add_listener(reg, &reglistener, NULL);
   1110 	wl_display_roundtrip(dpy);
   1111 	setup();
   1112 	run();
   1113 	cleanup();
   1114 	wl_display_disconnect(dpy);
   1115 	free(layer_names_list);
   1116 
   1117 	return 0;
   1118 }