diff options
author | Bad Diode <bd@badd10de.dev> | 2022-03-04 23:08:57 +0100 |
---|---|---|
committer | Bad Diode <bd@badd10de.dev> | 2022-03-04 23:08:57 +0100 |
commit | e835289d291bb8d0a9f0b56130412226c4cbec7c (patch) | |
tree | 77a4395deeec8b8de8b6589287547c613586f0a6 | |
parent | a46fb7bd7eb1cf4c3237c2f3c944dfc82bcc2ee5 (diff) | |
download | uxnfb-e835289d291bb8d0a9f0b56130412226c4cbec7c.tar.gz uxnfb-e835289d291bb8d0a9f0b56130412226c4cbec7c.zip |
Add partial support for keyboard input
-rw-r--r-- | src/main.c | 231 |
1 files changed, 188 insertions, 43 deletions
@@ -1,3 +1,4 @@ | |||
1 | #include <errno.h> | ||
1 | #include <stdbool.h> | 2 | #include <stdbool.h> |
2 | #include <stdint.h> | 3 | #include <stdint.h> |
3 | #include <stdio.h> | 4 | #include <stdio.h> |
@@ -5,6 +6,8 @@ | |||
5 | #include <time.h> | 6 | #include <time.h> |
6 | #include <unistd.h> | 7 | #include <unistd.h> |
7 | 8 | ||
9 | #include <linux/input.h> | ||
10 | |||
8 | #include "shorthand.h" | 11 | #include "shorthand.h" |
9 | #include "ppu.c" | 12 | #include "ppu.c" |
10 | #include "uxn-fast.c" | 13 | #include "uxn-fast.c" |
@@ -30,6 +33,142 @@ time_elapsed(Time since){ | |||
30 | return (now.tv_sec - since.tv_sec) * 1e9 + (now.tv_nsec - since.tv_nsec); | 33 | return (now.tv_sec - since.tv_sec) * 1e9 + (now.tv_nsec - since.tv_nsec); |
31 | } | 34 | } |
32 | 35 | ||
36 | typedef struct Keyboard { | ||
37 | int fd; | ||
38 | char map[KEY_MAX / 8 + 1]; | ||
39 | } Keyboard; | ||
40 | |||
41 | static Keyboard keyboard; | ||
42 | |||
43 | void | ||
44 | init_input(void) { | ||
45 | const char *dev = "/dev/input/by-id/usb-Apple_Inc._Magic_Keyboard_with_Numeric_Keypad_F0T0167000DHTHKAD-if01-event-kbd"; | ||
46 | keyboard.fd = open(dev, O_RDONLY); | ||
47 | if (keyboard.fd == -1) { | ||
48 | // TODO: should this be a warning and still work for applications that | ||
49 | // don't require a keyboard? | ||
50 | fprintf(stderr, "error: no couldn't open keyboard %s: %s.\n", dev, strerror(errno)); | ||
51 | exit(EXIT_FAILURE); | ||
52 | } | ||
53 | |||
54 | memset(keyboard.map, 0, sizeof(keyboard.map)); | ||
55 | } | ||
56 | |||
57 | void | ||
58 | poll_keyboard(void) { | ||
59 | char map[KEY_MAX / 8 + 1]; | ||
60 | memset(map, 0, sizeof(map)); | ||
61 | ioctl(keyboard.fd, EVIOCGKEY(sizeof(map)), map); | ||
62 | for (size_t i = 0; i < sizeof(map); i++) { | ||
63 | keyboard.map[i] |= map[i]; | ||
64 | } | ||
65 | } | ||
66 | |||
67 | void | ||
68 | handle_keyboard(void) { | ||
69 | // Find mod keys. | ||
70 | bool shift_mod = false; | ||
71 | // bool ctrl_mod = false; | ||
72 | // bool alt_mod = false; | ||
73 | // bool meta_mod = false; | ||
74 | for (size_t i = 0; i < sizeof(keyboard.map); i++) { | ||
75 | for (size_t j = 0; j < 8; j++) { | ||
76 | char key = keyboard.map[i] & (1 << j); | ||
77 | if (key) { | ||
78 | char key_code = i * 8 + j; | ||
79 | switch (key_code) { | ||
80 | case KEY_LEFTSHIFT: | ||
81 | case KEY_RIGHTSHIFT: { shift_mod = true; } break; | ||
82 | // case KEY_LEFTCTRL: | ||
83 | // case KEY_RIGHTCTRL: { ctrl_mod = true; } break; | ||
84 | // case KEY_LEFTALT: | ||
85 | // case KEY_RIGHTALT: { alt_mod = true; } break; | ||
86 | // case KEY_LEFTMETA: | ||
87 | // case KEY_RIGHTMETA: { meta_mod = true; } break; | ||
88 | default: break; | ||
89 | } | ||
90 | } | ||
91 | } | ||
92 | } | ||
93 | |||
94 | // Handle normal keys. | ||
95 | for (size_t i = 0; i < sizeof(keyboard.map); i++) { | ||
96 | for (size_t j = 0; j < 8; j++) { | ||
97 | char key = keyboard.map[i] & (1 << j); | ||
98 | if (key) { | ||
99 | char key_code = i * 8 + j; | ||
100 | // Special keys. | ||
101 | // TODO: ... | ||
102 | |||
103 | // Normal keys. | ||
104 | char rune = '\0'; | ||
105 | switch (key_code) { | ||
106 | case KEY_1: { rune = shift_mod ? '!' : '1'; } break; | ||
107 | case KEY_2: { rune = shift_mod ? '@' : '2'; } break; | ||
108 | case KEY_3: { rune = shift_mod ? '#' : '3'; } break; | ||
109 | case KEY_4: { rune = shift_mod ? '$' : '4'; } break; | ||
110 | case KEY_5: { rune = shift_mod ? '%' : '5'; } break; | ||
111 | case KEY_6: { rune = shift_mod ? '^' : '6'; } break; | ||
112 | case KEY_7: { rune = shift_mod ? '&' : '7'; } break; | ||
113 | case KEY_8: { rune = shift_mod ? '*' : '8'; } break; | ||
114 | case KEY_9: { rune = shift_mod ? '(' : '9'; } break; | ||
115 | case KEY_0: { rune = shift_mod ? ')' : '0'; } break; | ||
116 | case KEY_MINUS: { rune = shift_mod ? '_' : '-'; } break; | ||
117 | case KEY_EQUAL: { rune = shift_mod ? '+' : '+'; } break; | ||
118 | case KEY_Q: { rune = shift_mod ? 'Q' : 'q'; } break; | ||
119 | case KEY_W: { rune = shift_mod ? 'W' : 'w'; } break; | ||
120 | case KEY_E: { rune = shift_mod ? 'E' : 'e'; } break; | ||
121 | case KEY_R: { rune = shift_mod ? 'T' : 't'; } break; | ||
122 | case KEY_T: { rune = shift_mod ? 'T' : 't'; } break; | ||
123 | case KEY_Y: { rune = shift_mod ? 'Y' : 'y'; } break; | ||
124 | case KEY_U: { rune = shift_mod ? 'U' : 'u'; } break; | ||
125 | case KEY_I: { rune = shift_mod ? 'I' : 'i'; } break; | ||
126 | case KEY_O: { rune = shift_mod ? 'O' : 'o'; } break; | ||
127 | case KEY_P: { rune = shift_mod ? 'P' : 'p'; } break; | ||
128 | case KEY_LEFTBRACE: { rune = shift_mod ? '{' : '['; } break; | ||
129 | case KEY_RIGHTBRACE: { rune = shift_mod ? '}' : ']'; } break; | ||
130 | case KEY_A: { rune = shift_mod ? 'A' : 'a'; } break; | ||
131 | case KEY_S: { rune = shift_mod ? 'S' : 's'; } break; | ||
132 | case KEY_D: { rune = shift_mod ? 'D' : 'd'; } break; | ||
133 | case KEY_F: { rune = shift_mod ? 'F' : 'f'; } break; | ||
134 | case KEY_G: { rune = shift_mod ? 'G' : 'g'; } break; | ||
135 | case KEY_H: { rune = shift_mod ? 'H' : 'h'; } break; | ||
136 | case KEY_J: { rune = shift_mod ? 'J' : 'j'; } break; | ||
137 | case KEY_K: { rune = shift_mod ? 'K' : 'k'; } break; | ||
138 | case KEY_L: { rune = shift_mod ? 'L' : 'l'; } break; | ||
139 | case KEY_SEMICOLON: { rune = shift_mod ? ':' : ';'; } break; | ||
140 | case KEY_APOSTROPHE: { rune = shift_mod ? '"' : '\''; } break; | ||
141 | case KEY_GRAVE: { rune = shift_mod ? '~' : '`'; } break; | ||
142 | case KEY_BACKSLASH: { rune = shift_mod ? '|' : '\\'; } break; | ||
143 | case KEY_Z: { rune = shift_mod ? 'Z' : 'z'; } break; | ||
144 | case KEY_X: { rune = shift_mod ? 'X' : 'x'; } break; | ||
145 | case KEY_C: { rune = shift_mod ? 'C' : 'c'; } break; | ||
146 | case KEY_V: { rune = shift_mod ? 'V' : 'v'; } break; | ||
147 | case KEY_B: { rune = shift_mod ? 'B' : 'b'; } break; | ||
148 | case KEY_N: { rune = shift_mod ? 'N' : 'n'; } break; | ||
149 | case KEY_M: { rune = shift_mod ? 'M' : 'm'; } break; | ||
150 | case KEY_COMMA: { rune = shift_mod ? '<' : ','; } break; | ||
151 | case KEY_DOT: { rune = shift_mod ? '>' : '.'; } break; | ||
152 | case KEY_SLASH: { rune = shift_mod ? '?' : '/'; } break; | ||
153 | case KEY_SPACE: { rune = ' '; } break; | ||
154 | case KEY_TAB: { rune = '\t'; } break; | ||
155 | case KEY_BACKSPACE: { rune = 0x08; } break; | ||
156 | case KEY_ENTER: | ||
157 | case KEY_KPENTER: { rune = 0x0d; } break; | ||
158 | default: break; | ||
159 | } | ||
160 | if (rune) { | ||
161 | devctrl->dat[3] = rune; | ||
162 | uxn_eval(&u, mempeek16(devctrl->dat, 0)); | ||
163 | devctrl->dat[3] = 0; | ||
164 | continue; | ||
165 | } | ||
166 | } | ||
167 | } | ||
168 | } | ||
169 | memset(keyboard.map, 0, sizeof(keyboard.map)); | ||
170 | } | ||
171 | |||
33 | void | 172 | void |
34 | nil_talk(Device *d, u8 b0, u8 w) { | 173 | nil_talk(Device *d, u8 b0, u8 w) { |
35 | (void)d; | 174 | (void)d; |
@@ -103,51 +242,51 @@ screen_talk(Device *d, u8 b0, u8 w) { | |||
103 | if (w) { | 242 | if (w) { |
104 | switch (b0) { | 243 | switch (b0) { |
105 | case 0x1: { | 244 | case 0x1: { |
106 | d->vector = mempeek16(d->dat, 0x0); | 245 | d->vector = mempeek16(d->dat, 0x0); |
107 | } break; | 246 | } break; |
108 | case 0xe: { | 247 | case 0xe: { |
109 | u16 x = mempeek16(d->dat, 0x8); | 248 | u16 x = mempeek16(d->dat, 0x8); |
110 | u16 y = mempeek16(d->dat, 0xa); | 249 | u16 y = mempeek16(d->dat, 0xa); |
111 | u8 *addr = &d->mem[mempeek16(d->dat, 0xc)]; | 250 | u8 *addr = &d->mem[mempeek16(d->dat, 0xc)]; |
112 | u8 *layer = d->dat[0xe] >> 4 & 0x1 ? pixels_fg : pixels_bg; | 251 | u8 *layer = d->dat[0xe] >> 4 & 0x1 ? pixels_fg : pixels_bg; |
113 | u8 mode = d->dat[0xe] >> 5; | 252 | u8 mode = d->dat[0xe] >> 5; |
114 | u8 color = d->dat[0xf] & 0xf; | 253 | u8 color = d->dat[0xf] & 0xf; |
115 | if(!mode) { | 254 | if(!mode) { |
116 | ppu_pixel(layer, x, y, d->dat[0xe] & 0x3); | 255 | ppu_pixel(layer, x, y, d->dat[0xe] & 0x3); |
117 | } else if(mode-- & 0x1) { | 256 | } else if(mode-- & 0x1) { |
118 | u8 flipx = mode & 0x2; | 257 | u8 flipx = mode & 0x2; |
119 | u8 flipy = mode & 0x4; | 258 | u8 flipy = mode & 0x4; |
120 | ppu_1bpp(layer, x, y, addr, color, flipx, flipy); | 259 | ppu_1bpp(layer, x, y, addr, color, flipx, flipy); |
121 | } else { | 260 | } else { |
122 | u8 flipx = mode & 0x2; | 261 | u8 flipx = mode & 0x2; |
123 | u8 flipy = mode & 0x4; | 262 | u8 flipy = mode & 0x4; |
124 | ppu_2bpp(layer, x, y, addr, color, flipx, flipy); | 263 | ppu_2bpp(layer, x, y, addr, color, flipx, flipy); |
125 | } | 264 | } |
126 | if(d->dat[0x6] & 0x01) { mempoke16(d->dat, 0x8, x + 1); } | 265 | if(d->dat[0x6] & 0x01) { mempoke16(d->dat, 0x8, x + 1); } |
127 | if(d->dat[0x6] & 0x02) { mempoke16(d->dat, 0xa, y + 1); } | 266 | if(d->dat[0x6] & 0x02) { mempoke16(d->dat, 0xa, y + 1); } |
128 | } break; | 267 | } break; |
129 | case 0xf: { | 268 | case 0xf: { |
130 | u16 x = mempeek16(d->dat, 0x8); | 269 | u16 x = mempeek16(d->dat, 0x8); |
131 | u16 y = mempeek16(d->dat, 0xa); | 270 | u16 y = mempeek16(d->dat, 0xa); |
132 | u8 *addr = &d->mem[mempeek16(d->dat, 0xc)]; | 271 | u8 *addr = &d->mem[mempeek16(d->dat, 0xc)]; |
133 | u8 *layer = d->dat[0xf] >> 6 & 0x1 ? pixels_fg : pixels_bg; | 272 | u8 *layer = d->dat[0xf] >> 6 & 0x1 ? pixels_fg : pixels_bg; |
134 | u8 color = d->dat[0xf] & 0xf; | 273 | u8 color = d->dat[0xf] & 0xf; |
135 | u8 flipx = (d->dat[0xf] >> 0x4) & 0x1; | 274 | u8 flipx = (d->dat[0xf] >> 0x4) & 0x1; |
136 | u8 flipy = (d->dat[0xf] >> 0x5) & 0x1; | 275 | u8 flipy = (d->dat[0xf] >> 0x5) & 0x1; |
137 | if(d->dat[0xf] >> 0x7 & 0x1) { | 276 | if(d->dat[0xf] >> 0x7 & 0x1) { |
138 | ppu_2bpp(layer, x, y, addr, color, flipx, flipy); | 277 | ppu_2bpp(layer, x, y, addr, color, flipx, flipy); |
139 | if(d->dat[0x6] & 0x04) { | 278 | if(d->dat[0x6] & 0x04) { |
140 | mempoke16(d->dat, 0xc, mempeek16(d->dat, 0xc) + 16); | 279 | mempoke16(d->dat, 0xc, mempeek16(d->dat, 0xc) + 16); |
141 | } | 280 | } |
142 | } else { | 281 | } else { |
143 | ppu_1bpp(layer, x, y, addr, color, flipx, flipy); | 282 | ppu_1bpp(layer, x, y, addr, color, flipx, flipy); |
144 | if(d->dat[0x6] & 0x04) { | 283 | if(d->dat[0x6] & 0x04) { |
145 | mempoke16(d->dat, 0xc, mempeek16(d->dat, 0xc) + 8); | 284 | mempoke16(d->dat, 0xc, mempeek16(d->dat, 0xc) + 8); |
146 | } | 285 | } |
147 | } | 286 | } |
148 | if(d->dat[0x6] & 0x01) { mempoke16(d->dat, 0x8, x + 8); } | 287 | if(d->dat[0x6] & 0x01) { mempoke16(d->dat, 0x8, x + 8); } |
149 | if(d->dat[0x6] & 0x02) { mempoke16(d->dat, 0xa, y + 8); } | 288 | if(d->dat[0x6] & 0x02) { mempoke16(d->dat, 0xa, y + 8); } |
150 | } break; | 289 | } break; |
151 | default: break; | 290 | default: break; |
152 | } | 291 | } |
153 | } | 292 | } |
@@ -208,6 +347,9 @@ init_uxn(char *file_name) { | |||
208 | // Initialize framebuffer. | 347 | // Initialize framebuffer. |
209 | ppu_init(); | 348 | ppu_init(); |
210 | 349 | ||
350 | // Initialize keybord. | ||
351 | init_input(); | ||
352 | |||
211 | // Prepare devices. | 353 | // Prepare devices. |
212 | uxn_port(&u, 0x0, "system", system_talk); | 354 | uxn_port(&u, 0x0, "system", system_talk); |
213 | uxn_port(&u, 0x1, "console", console_talk); | 355 | uxn_port(&u, 0x1, "console", console_talk); |
@@ -242,8 +384,11 @@ main(int argc, char *argv[]) { | |||
242 | uxn_eval(&u, 0x0100); | 384 | uxn_eval(&u, 0x0100); |
243 | Time frame_time = time_now(); | 385 | Time frame_time = time_now(); |
244 | while (true) { | 386 | while (true) { |
387 | poll_keyboard(); | ||
245 | size_t elapsed = time_elapsed(frame_time); | 388 | size_t elapsed = time_elapsed(frame_time); |
246 | if (elapsed >= 16666666) { | 389 | if (elapsed >= 16666666) { |
390 | handle_keyboard(); | ||
391 | |||
247 | // Echo input to standard output. | 392 | // Echo input to standard output. |
248 | uxn_eval(&u, mempeek16(devscreen->dat, 0)); | 393 | uxn_eval(&u, mempeek16(devscreen->dat, 0)); |
249 | 394 | ||