Add partial support for keyboard input
This commit is contained in:
parent
a46fb7bd7e
commit
e835289d29
231
src/main.c
231
src/main.c
|
@ -1,3 +1,4 @@
|
|||
#include <errno.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
@ -5,6 +6,8 @@
|
|||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <linux/input.h>
|
||||
|
||||
#include "shorthand.h"
|
||||
#include "ppu.c"
|
||||
#include "uxn-fast.c"
|
||||
|
@ -30,6 +33,142 @@ time_elapsed(Time since){
|
|||
return (now.tv_sec - since.tv_sec) * 1e9 + (now.tv_nsec - since.tv_nsec);
|
||||
}
|
||||
|
||||
typedef struct Keyboard {
|
||||
int fd;
|
||||
char map[KEY_MAX / 8 + 1];
|
||||
} Keyboard;
|
||||
|
||||
static Keyboard keyboard;
|
||||
|
||||
void
|
||||
init_input(void) {
|
||||
const char *dev = "/dev/input/by-id/usb-Apple_Inc._Magic_Keyboard_with_Numeric_Keypad_F0T0167000DHTHKAD-if01-event-kbd";
|
||||
keyboard.fd = open(dev, O_RDONLY);
|
||||
if (keyboard.fd == -1) {
|
||||
// TODO: should this be a warning and still work for applications that
|
||||
// don't require a keyboard?
|
||||
fprintf(stderr, "error: no couldn't open keyboard %s: %s.\n", dev, strerror(errno));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
memset(keyboard.map, 0, sizeof(keyboard.map));
|
||||
}
|
||||
|
||||
void
|
||||
poll_keyboard(void) {
|
||||
char map[KEY_MAX / 8 + 1];
|
||||
memset(map, 0, sizeof(map));
|
||||
ioctl(keyboard.fd, EVIOCGKEY(sizeof(map)), map);
|
||||
for (size_t i = 0; i < sizeof(map); i++) {
|
||||
keyboard.map[i] |= map[i];
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
handle_keyboard(void) {
|
||||
// Find mod keys.
|
||||
bool shift_mod = false;
|
||||
// bool ctrl_mod = false;
|
||||
// bool alt_mod = false;
|
||||
// bool meta_mod = false;
|
||||
for (size_t i = 0; i < sizeof(keyboard.map); i++) {
|
||||
for (size_t j = 0; j < 8; j++) {
|
||||
char key = keyboard.map[i] & (1 << j);
|
||||
if (key) {
|
||||
char key_code = i * 8 + j;
|
||||
switch (key_code) {
|
||||
case KEY_LEFTSHIFT:
|
||||
case KEY_RIGHTSHIFT: { shift_mod = true; } break;
|
||||
// case KEY_LEFTCTRL:
|
||||
// case KEY_RIGHTCTRL: { ctrl_mod = true; } break;
|
||||
// case KEY_LEFTALT:
|
||||
// case KEY_RIGHTALT: { alt_mod = true; } break;
|
||||
// case KEY_LEFTMETA:
|
||||
// case KEY_RIGHTMETA: { meta_mod = true; } break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle normal keys.
|
||||
for (size_t i = 0; i < sizeof(keyboard.map); i++) {
|
||||
for (size_t j = 0; j < 8; j++) {
|
||||
char key = keyboard.map[i] & (1 << j);
|
||||
if (key) {
|
||||
char key_code = i * 8 + j;
|
||||
// Special keys.
|
||||
// TODO: ...
|
||||
|
||||
// Normal keys.
|
||||
char rune = '\0';
|
||||
switch (key_code) {
|
||||
case KEY_1: { rune = shift_mod ? '!' : '1'; } break;
|
||||
case KEY_2: { rune = shift_mod ? '@' : '2'; } break;
|
||||
case KEY_3: { rune = shift_mod ? '#' : '3'; } break;
|
||||
case KEY_4: { rune = shift_mod ? '$' : '4'; } break;
|
||||
case KEY_5: { rune = shift_mod ? '%' : '5'; } break;
|
||||
case KEY_6: { rune = shift_mod ? '^' : '6'; } break;
|
||||
case KEY_7: { rune = shift_mod ? '&' : '7'; } break;
|
||||
case KEY_8: { rune = shift_mod ? '*' : '8'; } break;
|
||||
case KEY_9: { rune = shift_mod ? '(' : '9'; } break;
|
||||
case KEY_0: { rune = shift_mod ? ')' : '0'; } break;
|
||||
case KEY_MINUS: { rune = shift_mod ? '_' : '-'; } break;
|
||||
case KEY_EQUAL: { rune = shift_mod ? '+' : '+'; } break;
|
||||
case KEY_Q: { rune = shift_mod ? 'Q' : 'q'; } break;
|
||||
case KEY_W: { rune = shift_mod ? 'W' : 'w'; } break;
|
||||
case KEY_E: { rune = shift_mod ? 'E' : 'e'; } break;
|
||||
case KEY_R: { rune = shift_mod ? 'T' : 't'; } break;
|
||||
case KEY_T: { rune = shift_mod ? 'T' : 't'; } break;
|
||||
case KEY_Y: { rune = shift_mod ? 'Y' : 'y'; } break;
|
||||
case KEY_U: { rune = shift_mod ? 'U' : 'u'; } break;
|
||||
case KEY_I: { rune = shift_mod ? 'I' : 'i'; } break;
|
||||
case KEY_O: { rune = shift_mod ? 'O' : 'o'; } break;
|
||||
case KEY_P: { rune = shift_mod ? 'P' : 'p'; } break;
|
||||
case KEY_LEFTBRACE: { rune = shift_mod ? '{' : '['; } break;
|
||||
case KEY_RIGHTBRACE: { rune = shift_mod ? '}' : ']'; } break;
|
||||
case KEY_A: { rune = shift_mod ? 'A' : 'a'; } break;
|
||||
case KEY_S: { rune = shift_mod ? 'S' : 's'; } break;
|
||||
case KEY_D: { rune = shift_mod ? 'D' : 'd'; } break;
|
||||
case KEY_F: { rune = shift_mod ? 'F' : 'f'; } break;
|
||||
case KEY_G: { rune = shift_mod ? 'G' : 'g'; } break;
|
||||
case KEY_H: { rune = shift_mod ? 'H' : 'h'; } break;
|
||||
case KEY_J: { rune = shift_mod ? 'J' : 'j'; } break;
|
||||
case KEY_K: { rune = shift_mod ? 'K' : 'k'; } break;
|
||||
case KEY_L: { rune = shift_mod ? 'L' : 'l'; } break;
|
||||
case KEY_SEMICOLON: { rune = shift_mod ? ':' : ';'; } break;
|
||||
case KEY_APOSTROPHE: { rune = shift_mod ? '"' : '\''; } break;
|
||||
case KEY_GRAVE: { rune = shift_mod ? '~' : '`'; } break;
|
||||
case KEY_BACKSLASH: { rune = shift_mod ? '|' : '\\'; } break;
|
||||
case KEY_Z: { rune = shift_mod ? 'Z' : 'z'; } break;
|
||||
case KEY_X: { rune = shift_mod ? 'X' : 'x'; } break;
|
||||
case KEY_C: { rune = shift_mod ? 'C' : 'c'; } break;
|
||||
case KEY_V: { rune = shift_mod ? 'V' : 'v'; } break;
|
||||
case KEY_B: { rune = shift_mod ? 'B' : 'b'; } break;
|
||||
case KEY_N: { rune = shift_mod ? 'N' : 'n'; } break;
|
||||
case KEY_M: { rune = shift_mod ? 'M' : 'm'; } break;
|
||||
case KEY_COMMA: { rune = shift_mod ? '<' : ','; } break;
|
||||
case KEY_DOT: { rune = shift_mod ? '>' : '.'; } break;
|
||||
case KEY_SLASH: { rune = shift_mod ? '?' : '/'; } break;
|
||||
case KEY_SPACE: { rune = ' '; } break;
|
||||
case KEY_TAB: { rune = '\t'; } break;
|
||||
case KEY_BACKSPACE: { rune = 0x08; } break;
|
||||
case KEY_ENTER:
|
||||
case KEY_KPENTER: { rune = 0x0d; } break;
|
||||
default: break;
|
||||
}
|
||||
if (rune) {
|
||||
devctrl->dat[3] = rune;
|
||||
uxn_eval(&u, mempeek16(devctrl->dat, 0));
|
||||
devctrl->dat[3] = 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
memset(keyboard.map, 0, sizeof(keyboard.map));
|
||||
}
|
||||
|
||||
void
|
||||
nil_talk(Device *d, u8 b0, u8 w) {
|
||||
(void)d;
|
||||
|
@ -103,51 +242,51 @@ screen_talk(Device *d, u8 b0, u8 w) {
|
|||
if (w) {
|
||||
switch (b0) {
|
||||
case 0x1: {
|
||||
d->vector = mempeek16(d->dat, 0x0);
|
||||
} break;
|
||||
d->vector = mempeek16(d->dat, 0x0);
|
||||
} break;
|
||||
case 0xe: {
|
||||
u16 x = mempeek16(d->dat, 0x8);
|
||||
u16 y = mempeek16(d->dat, 0xa);
|
||||
u8 *addr = &d->mem[mempeek16(d->dat, 0xc)];
|
||||
u8 *layer = d->dat[0xe] >> 4 & 0x1 ? pixels_fg : pixels_bg;
|
||||
u8 mode = d->dat[0xe] >> 5;
|
||||
u8 color = d->dat[0xf] & 0xf;
|
||||
if(!mode) {
|
||||
ppu_pixel(layer, x, y, d->dat[0xe] & 0x3);
|
||||
} else if(mode-- & 0x1) {
|
||||
u8 flipx = mode & 0x2;
|
||||
u8 flipy = mode & 0x4;
|
||||
ppu_1bpp(layer, x, y, addr, color, flipx, flipy);
|
||||
} else {
|
||||
u8 flipx = mode & 0x2;
|
||||
u8 flipy = mode & 0x4;
|
||||
ppu_2bpp(layer, x, y, addr, color, flipx, flipy);
|
||||
}
|
||||
if(d->dat[0x6] & 0x01) { mempoke16(d->dat, 0x8, x + 1); }
|
||||
if(d->dat[0x6] & 0x02) { mempoke16(d->dat, 0xa, y + 1); }
|
||||
} break;
|
||||
u16 x = mempeek16(d->dat, 0x8);
|
||||
u16 y = mempeek16(d->dat, 0xa);
|
||||
u8 *addr = &d->mem[mempeek16(d->dat, 0xc)];
|
||||
u8 *layer = d->dat[0xe] >> 4 & 0x1 ? pixels_fg : pixels_bg;
|
||||
u8 mode = d->dat[0xe] >> 5;
|
||||
u8 color = d->dat[0xf] & 0xf;
|
||||
if(!mode) {
|
||||
ppu_pixel(layer, x, y, d->dat[0xe] & 0x3);
|
||||
} else if(mode-- & 0x1) {
|
||||
u8 flipx = mode & 0x2;
|
||||
u8 flipy = mode & 0x4;
|
||||
ppu_1bpp(layer, x, y, addr, color, flipx, flipy);
|
||||
} else {
|
||||
u8 flipx = mode & 0x2;
|
||||
u8 flipy = mode & 0x4;
|
||||
ppu_2bpp(layer, x, y, addr, color, flipx, flipy);
|
||||
}
|
||||
if(d->dat[0x6] & 0x01) { mempoke16(d->dat, 0x8, x + 1); }
|
||||
if(d->dat[0x6] & 0x02) { mempoke16(d->dat, 0xa, y + 1); }
|
||||
} break;
|
||||
case 0xf: {
|
||||
u16 x = mempeek16(d->dat, 0x8);
|
||||
u16 y = mempeek16(d->dat, 0xa);
|
||||
u8 *addr = &d->mem[mempeek16(d->dat, 0xc)];
|
||||
u8 *layer = d->dat[0xf] >> 6 & 0x1 ? pixels_fg : pixels_bg;
|
||||
u8 color = d->dat[0xf] & 0xf;
|
||||
u8 flipx = (d->dat[0xf] >> 0x4) & 0x1;
|
||||
u8 flipy = (d->dat[0xf] >> 0x5) & 0x1;
|
||||
if(d->dat[0xf] >> 0x7 & 0x1) {
|
||||
ppu_2bpp(layer, x, y, addr, color, flipx, flipy);
|
||||
if(d->dat[0x6] & 0x04) {
|
||||
mempoke16(d->dat, 0xc, mempeek16(d->dat, 0xc) + 16);
|
||||
}
|
||||
} else {
|
||||
ppu_1bpp(layer, x, y, addr, color, flipx, flipy);
|
||||
if(d->dat[0x6] & 0x04) {
|
||||
mempoke16(d->dat, 0xc, mempeek16(d->dat, 0xc) + 8);
|
||||
}
|
||||
}
|
||||
if(d->dat[0x6] & 0x01) { mempoke16(d->dat, 0x8, x + 8); }
|
||||
if(d->dat[0x6] & 0x02) { mempoke16(d->dat, 0xa, y + 8); }
|
||||
} break;
|
||||
u16 x = mempeek16(d->dat, 0x8);
|
||||
u16 y = mempeek16(d->dat, 0xa);
|
||||
u8 *addr = &d->mem[mempeek16(d->dat, 0xc)];
|
||||
u8 *layer = d->dat[0xf] >> 6 & 0x1 ? pixels_fg : pixels_bg;
|
||||
u8 color = d->dat[0xf] & 0xf;
|
||||
u8 flipx = (d->dat[0xf] >> 0x4) & 0x1;
|
||||
u8 flipy = (d->dat[0xf] >> 0x5) & 0x1;
|
||||
if(d->dat[0xf] >> 0x7 & 0x1) {
|
||||
ppu_2bpp(layer, x, y, addr, color, flipx, flipy);
|
||||
if(d->dat[0x6] & 0x04) {
|
||||
mempoke16(d->dat, 0xc, mempeek16(d->dat, 0xc) + 16);
|
||||
}
|
||||
} else {
|
||||
ppu_1bpp(layer, x, y, addr, color, flipx, flipy);
|
||||
if(d->dat[0x6] & 0x04) {
|
||||
mempoke16(d->dat, 0xc, mempeek16(d->dat, 0xc) + 8);
|
||||
}
|
||||
}
|
||||
if(d->dat[0x6] & 0x01) { mempoke16(d->dat, 0x8, x + 8); }
|
||||
if(d->dat[0x6] & 0x02) { mempoke16(d->dat, 0xa, y + 8); }
|
||||
} break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
@ -208,6 +347,9 @@ init_uxn(char *file_name) {
|
|||
// Initialize framebuffer.
|
||||
ppu_init();
|
||||
|
||||
// Initialize keybord.
|
||||
init_input();
|
||||
|
||||
// Prepare devices.
|
||||
uxn_port(&u, 0x0, "system", system_talk);
|
||||
uxn_port(&u, 0x1, "console", console_talk);
|
||||
|
@ -242,8 +384,11 @@ main(int argc, char *argv[]) {
|
|||
uxn_eval(&u, 0x0100);
|
||||
Time frame_time = time_now();
|
||||
while (true) {
|
||||
poll_keyboard();
|
||||
size_t elapsed = time_elapsed(frame_time);
|
||||
if (elapsed >= 16666666) {
|
||||
handle_keyboard();
|
||||
|
||||
// Echo input to standard output.
|
||||
uxn_eval(&u, mempeek16(devscreen->dat, 0));
|
||||
|
||||
|
|
Loading…
Reference in New Issue