suggestion picker: a persistent layer to complement virtual keyboards like wvkbd
Diffstat (limited to 'keyboard.h')
| -rw-r--r-- | keyboard.h | 217 |
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); +} |