upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/main/keyboard.c
diff options
context:
space:
mode:
Diffstat (limited to 'main/keyboard.c')
-rw-r--r--main/keyboard.c162
1 files changed, 162 insertions, 0 deletions
diff --git a/main/keyboard.c b/main/keyboard.c
new file mode 100644
index 0000000..741bd08
--- /dev/null
+++ b/main/keyboard.c
@@ -0,0 +1,162 @@
1#include "keyboard.h"
2#include <string.h>
3
4static const char *s_alpha_lower[] = {
5 "qwertyuiop",
6 "asdfghjkl",
7 "\001zxcvbnm\b",
8 "\002\003 \004"
9};
10
11static const char *s_alpha_upper[] = {
12 "QWERTYUIOP",
13 "ASDFGHJKL",
14 "\001ZXCVBNM\b",
15 "\002\003 \004"
16};
17
18static const char *s_numsym[] = {
19 "1234567890",
20 "-/:;()$&@\"",
21 "\001.,?!'\\b",
22 "\002\003 \004"
23};
24
25#define CTRL_SHIFT '\001'
26#define CTRL_LAYER '\002'
27#define CTRL_SPACE '\003'
28#define CTRL_DONE '\004'
29#define CTRL_BS '\b'
30
31void kb_state_init(kb_state_t *st) {
32 if (!st) return;
33 memset(st, 0, sizeof(*st));
34 st->layer = KB_ALPHA_LOWER;
35 st->reveal = false;
36}
37
38static const char **get_layer(kb_layer_t layer) {
39 switch (layer) {
40 case KB_ALPHA_UPPER: return s_alpha_upper;
41 case KB_NUMSYM: return s_numsym;
42 default: return s_alpha_lower;
43 }
44}
45
46static int key_is_ctrl(char c) {
47 return c == CTRL_SHIFT || c == CTRL_LAYER || c == CTRL_SPACE || c == CTRL_DONE || c == CTRL_BS;
48}
49
50int kb_get_row_keys(int row, kb_layer_t layer, const char **keys_out) {
51 if (row < 0 || row >= KB_ROW_COUNT) {
52 *keys_out = NULL;
53 return 0;
54 }
55 const char **layer_rows = get_layer(layer);
56 const char *row_str = layer_rows[row];
57 *keys_out = row_str;
58 return (int)strlen(row_str);
59}
60
61static int row_x_offset(int row) {
62 switch (row) {
63 case 0: return 5;
64 case 1: return 14;
65 case 2: return 23;
66 case 3: return 5;
67 default: return 0;
68 }
69}
70
71static int key_width_at(int row, int col, int total_keys) {
72 (void)col;
73 if (row == 3) {
74 if (col == 0) return 42;
75 if (col == total_keys - 1) return 50;
76 if (total_keys == 3 && col == 1) return 168;
77 if (total_keys == 4 && col == 1) return 168;
78 if (total_keys == 4 && col == 2) return 42;
79 }
80 return KB_KEY_W;
81}
82
83kb_result_t kb_hit_test(int tx, int ty, kb_layer_t layer) {
84 kb_result_t result = {KB_ACTION_NONE, 0};
85
86 if (ty < KB_START_Y || ty >= KB_START_Y + KB_ROW_COUNT * (KB_KEY_H + KB_KEY_GAP)) {
87 return result;
88 }
89
90 int row = (ty - KB_START_Y) / (KB_KEY_H + KB_KEY_GAP);
91 if (row < 0 || row >= KB_ROW_COUNT) return result;
92
93 const char *row_str;
94 int total_keys = kb_get_row_keys(row, layer, &row_str);
95 if (total_keys == 0) return result;
96
97 int x_off = row_x_offset(row);
98 int cx = x_off;
99
100 for (int col = 0; col < total_keys; col++) {
101 int kw = key_width_at(row, col, total_keys);
102 if (tx >= cx && tx < cx + kw) {
103 char c = row_str[col];
104 if (c == CTRL_SHIFT) {
105 result.action = KB_ACTION_SHIFT;
106 } else if (c == CTRL_LAYER) {
107 result.action = KB_ACTION_LAYER;
108 } else if (c == CTRL_SPACE) {
109 result.action = KB_ACTION_SPACE;
110 result.ch = ' ';
111 } else if (c == CTRL_DONE) {
112 result.action = KB_ACTION_DONE;
113 } else if (c == CTRL_BS) {
114 result.action = KB_ACTION_BACKSPACE;
115 } else {
116 result.action = KB_ACTION_CHAR;
117 result.ch = c;
118 }
119 return result;
120 }
121 cx += kw + KB_KEY_GAP;
122 }
123
124 return result;
125}
126
127void kb_apply(kb_state_t *st, kb_result_t result) {
128 if (!st || result.action == KB_ACTION_NONE) return;
129
130 switch (result.action) {
131 case KB_ACTION_CHAR:
132 if (st->cursor < KB_INPUT_MAX) {
133 st->input[st->cursor++] = result.ch;
134 st->input[st->cursor] = '\0';
135 }
136 break;
137 case KB_ACTION_BACKSPACE:
138 if (st->cursor > 0) {
139 st->cursor--;
140 st->input[st->cursor] = '\0';
141 }
142 break;
143 case KB_ACTION_SHIFT:
144 if (st->layer == KB_ALPHA_LOWER) st->layer = KB_ALPHA_UPPER;
145 else if (st->layer == KB_ALPHA_UPPER) st->layer = KB_ALPHA_LOWER;
146 break;
147 case KB_ACTION_LAYER:
148 if (st->layer == KB_NUMSYM) st->layer = KB_ALPHA_LOWER;
149 else st->layer = KB_NUMSYM;
150 break;
151 case KB_ACTION_SPACE:
152 if (st->cursor < KB_INPUT_MAX) {
153 st->input[st->cursor++] = ' ';
154 st->input[st->cursor] = '\0';
155 }
156 break;
157 case KB_ACTION_DONE:
158 break;
159 default:
160 break;
161 }
162}