summary refs log tree commit diff
path: root/keyboard.h
diff options
context:
space:
mode:
authorJohn Sullivan <jsullivan@csumb.edu>2020-09-11 01:25:28 -0700
committerJohn Sullivan <jsullivan@csumb.edu>2020-09-13 04:44:15 -0700
commit470046a68cb21c69635d48d424b64b76148dac1c (patch)
treeb0bf94141b1e54489332641c503d17ff5845f4a5 /keyboard.h
downloadsuggpicker-470046a68cb21c69635d48d424b64b76148dac1c.tar.gz
Init
Diffstat (limited to 'keyboard.h')
-rw-r--r--keyboard.h217
1 files changed, 217 insertions, 0 deletions
diff --git a/keyboard.h b/keyboard.h
new file mode 100644
index 0000000..f370ba1
--- /dev/null
+++ b/keyboard.h
@@ -0,0 +1,217 @@
+/* clang-format off */
+#define KBD_POINTS KBD_ROWS * KBD_COLS
+/* clang-format on */
+
+enum key_type;
+enum key_modifier_type;
+struct clr_scheme;
+struct key;
+struct layout;
+struct kbd;
+
+enum key_type {
+	Pad = 0,
+	Code,
+	Mod,
+	Layout,
+	Last,
+};
+
+/* Modifiers passed to the virtual_keyboard protocol. They are based on
+ * wayland's wl_keyboard, which doesn't document them.
+ */
+enum key_modifier_type {
+	NoMod = 0,
+	Shift = 1,
+	CapsLock = 2,
+	Ctrl = 4,
+	Super = 64,
+	AltGr = 128,
+};
+
+struct clr_scheme {
+	Color fg;
+	Color bg;
+	Color high;
+	Color text;
+};
+
+struct key {
+	const char *label;
+	const char *shift_label;
+	const uint8_t width;
+	const enum key_type type;
+
+	const uint32_t code;
+	struct layout *layout;
+
+	uint8_t col, row;
+};
+
+struct layout {
+	struct key *keys;
+	struct key *gridpoints[KBD_POINTS];
+};
+
+struct kbd {
+	struct layout *layout;
+	struct clr_scheme scheme;
+
+	uint32_t w, h;
+	uint32_t kw, kh;
+	uint8_t mods;
+	struct key *last_press;
+
+	struct drwsurf *surf;
+	struct zwp_virtual_keyboard_v1 *vkbd;
+};
+
+static inline void draw_inset(struct drwsurf *d, uint32_t x, uint32_t y,
+                              uint32_t width, uint32_t height, uint32_t border,
+                              uint32_t color);
+
+static void kbd_init_layout(struct layout *l);
+static struct key *kbd_get_key(struct kbd *kb, uint32_t x, uint32_t y);
+static void kbd_unpress_key(struct kbd *kb, uint32_t time);
+static void kbd_press_key(struct kbd *kb, struct key *k, uint32_t time);
+static void kbd_draw_key(struct kbd *kb, struct key *k, bool pressed);
+static void kbd_draw_key(struct kbd *kb, struct key *k, bool pressed);
+static void kbd_draw_layout(struct kbd *kb);
+static void kbd_resize(struct kbd *kb, uint32_t w, uint32_t h);
+
+void
+kbd_init_layout(struct layout *l) {
+	uint8_t i = 0, width = 0, ncol = 0, col = 0, row = 0;
+
+	struct key *k = l->keys;
+	struct key **point = l->gridpoints,
+	           **end_point = l->gridpoints + (KBD_POINTS);
+
+	memset(point, 0, sizeof(uint8_t) * KBD_POINTS);
+
+	while ((k->type != Last) && (point < end_point)) {
+		width = k->width;
+		ncol = col + width;
+
+		if (ncol > KBD_COLS) {
+			width = KBD_COLS - col;
+			col = 0;
+			row += 1;
+
+			for (i = 0; (i < width) && (point < end_point); i++, point++) {
+			}
+			continue;
+		}
+
+		k->col = col;
+		k->row = row;
+		col = ncol;
+
+		for (i = 0; (i < width) && (point < end_point); i++, point++) {
+			*point = k;
+		}
+
+		k++;
+	}
+}
+
+struct key *
+kbd_get_key(struct kbd *kb, uint32_t x, uint32_t y) {
+	struct layout *l = kb->layout;
+	uint32_t col = KBD_COLS * ((float)x / (float)kb->w);
+	uint32_t row = KBD_ROWS * ((float)y / (float)kb->h);
+
+	return l->gridpoints[(row * KBD_COLS) + col];
+}
+
+void
+kbd_unpress_key(struct kbd *kb, uint32_t time) {
+	if (kb->last_press) {
+		kbd_draw_key(kb, kb->last_press, false);
+		kb->surf->dirty = true;
+
+		zwp_virtual_keyboard_v1_key(kb->vkbd, time, kb->last_press->code,
+		                            WL_KEYBOARD_KEY_STATE_RELEASED);
+		kb->last_press = NULL;
+	}
+}
+
+void
+kbd_press_key(struct kbd *kb, struct key *k, uint32_t time) {
+	switch (k->type) {
+	case Code:
+		kb->last_press = k;
+		kbd_draw_key(kb, k, true);
+		zwp_virtual_keyboard_v1_key(kb->vkbd, time, kb->last_press->code,
+		                            WL_KEYBOARD_KEY_STATE_PRESSED);
+		break;
+	case Mod:
+		kb->mods ^= k->code;
+		if (k->code == Shift) {
+			kbd_draw_layout(kb);
+		}
+		kbd_draw_key(kb, k, kb->mods & k->code);
+		zwp_virtual_keyboard_v1_modifiers(kb->vkbd, kb->mods, 0, 0, 0);
+		break;
+	case Layout:
+		kb->layout = k->layout;
+		kbd_draw_layout(kb);
+	default:
+		break;
+	}
+
+	kb->surf->dirty = true;
+}
+
+void
+kbd_draw_key(struct kbd *kb, struct key *k, bool pressed) {
+	struct drwsurf *d = kb->surf;
+	const char *label = (kb->mods & Shift) ? k->shift_label : k->label;
+	Color *fill = pressed ? &kb->scheme.high : &kb->scheme.fg;
+	uint32_t x = k->col * kb->kw, y = k->row * kb->kh, width = k->width * kb->kw;
+
+	draw_inset(d, x, y, width, kb->kh, KBD_KEY_BORDER, fill->color);
+	wld_draw_text(d->render, d->ctx->font, kb->scheme.text.color,
+	              x + (width * 0.35), y + (kb->kh / 2), label, -1, NULL);
+}
+
+void
+kbd_draw_layout(struct kbd *kb) {
+	struct drwsurf *d = kb->surf;
+	struct key *next_key = kb->layout->keys;
+	bool pressed = false;
+
+	wld_fill_rectangle(d->render, kb->scheme.bg.color, 0, 0, kb->w, kb->h);
+
+	while (next_key->type != Last) {
+		if (next_key->type == Pad) {
+			next_key++;
+			continue;
+		}
+		pressed = next_key->type == Mod && kb->mods & next_key->code;
+		kbd_draw_key(kb, next_key, pressed);
+		next_key++;
+	}
+}
+
+void
+kbd_resize(struct kbd *kb, uint32_t w, uint32_t h) {
+	struct drwsurf *d = kb->surf;
+
+	kb->w = w;
+	kb->h = h;
+
+	kb->kw = (float)w / (float)KBD_COLS;
+	kb->kh = (float)h / (float)KBD_ROWS;
+
+	drwsurf_resize(d, w, h);
+	kbd_draw_layout(kb);
+	d->dirty = true;
+}
+
+void
+draw_inset(struct drwsurf *d, uint32_t x, uint32_t y, uint32_t width,
+           uint32_t height, uint32_t border, uint32_t color) {
+	wld_fill_rectangle(d->render, color, x + border, y + border, width - border,
+	                   height - border);
+}