Add initial mouse support

This commit is contained in:
Bad Diode 2022-03-05 19:23:24 +01:00
parent d08a7dfac6
commit 85ee9eb4b4
2 changed files with 105 additions and 33 deletions

View File

@ -1,14 +1,16 @@
BASE_UXN := src/uxn BASE_UXN := src/uxn
SRC_DIR ?= src SRC_DIR ?= src
BUILD_DIR ?= build BUILD_DIR ?= build
SRC_MAIN ?= $(SRC_DIR)/main.c SRC_MAIN ?= $(SRC_DIR)/main.c
EXE_NAME ?= uxnfb EXE_NAME ?= uxnfb
BIN := $(BUILD_DIR)/$(EXE_NAME) BIN := $(BUILD_DIR)/$(EXE_NAME)
UXN_HEAD := $(BASE_UXN)/src/uxn.h UXN_HEAD := $(BASE_UXN)/src/uxn.h
TAL_SRC ?= $(BASE_UXN)/projects/examples/devices/screen.tal TAL_SRC ?= $(BASE_UXN)/projects/examples/devices/screen.tal
UXN_ROM ?= $(BUILD_DIR)/rom.rom UXN_ROM ?= $(BUILD_DIR)/rom.rom
UXN_ASM ?= $(BUILD_DIR)/uxnasm UXN_ASM ?= $(BUILD_DIR)/uxnasm
KBD_PATH ?= /dev/input/event1 KBD_PATH ?= /dev/input/event1
MOUSE_PATH ?= /dev/input/mice
C_DEFINES := -DKBD_PATH=\"$(KBD_PATH)\" -DMOUSE_PATH=\"$(MOUSE_PATH)\"
CC ?= cc CC ?= cc
CFLAGS := -Wall -Wextra -pedantic CFLAGS := -Wall -Wextra -pedantic
@ -30,7 +32,7 @@ endif
main: $(BIN) main: $(BIN)
$(BIN): $(SRC_MAIN) $(BUILD_DIR) $(UXN_HEAD) $(BIN): $(SRC_MAIN) $(BUILD_DIR) $(UXN_HEAD)
$(CC) $(CFLAGS) -o $(BIN) $(SRC_MAIN) -DKBD_PATH=\"$(KBD_PATH)\" $(CC) $(CFLAGS) -o $(BIN) $(SRC_MAIN) $(C_DEFINES)
$(BUILD_DIR): $(BUILD_DIR):
mkdir -p $(BUILD_DIR) mkdir -p $(BUILD_DIR)

View File

@ -12,6 +12,8 @@
#include "ppu.c" #include "ppu.c"
#include "uxn-fast.c" #include "uxn-fast.c"
#define CLAMP(X, MIN, MAX) ((X) <= (MIN) ? (MIN) : (X) > (MAX) ? (MAX): (X))
static Uxn u; static Uxn u;
static Device *devscreen; static Device *devscreen;
static Device *devctrl; static Device *devctrl;
@ -33,42 +35,93 @@ time_elapsed(Time since){
return (now.tv_sec - since.tv_sec) * 1e9 + (now.tv_nsec - since.tv_nsec); return (now.tv_sec - since.tv_sec) * 1e9 + (now.tv_nsec - since.tv_nsec);
} }
typedef struct Mouse {
s32 x;
s32 y;
bool left;
bool mid;
bool right;
bool update;
} Mouse;
typedef struct Input { typedef struct Input {
int kb_fd; int kbd_fd;
int mouse_fd;
char map[KEY_MAX / 8 + 1]; char map[KEY_MAX / 8 + 1];
u8 controller; u8 controller;
Mouse mouse;
} Input; } Input;
static Input input; // NOTE: For event codes and input documentation:
// - https://www.kernel.org/doc/Documentation/input/event-codes.txt
// - /usr/include/linux/input.h
static Input in;
void void
init_input(void) { init_input(void) {
memset(&input, 0, sizeof(input)); memset(&in, 0, sizeof(in));
input.kb_fd = -1; in.kbd_fd = -1;
in.mouse_fd = -1;
const char *dev = KBD_PATH; in.kbd_fd = open(KBD_PATH, O_RDONLY | O_NONBLOCK);
input.kb_fd = open(dev, O_RDONLY); if (in.kbd_fd == -1) {
if (input.kb_fd == -1) {
// NOTE: Some applications may not require a keyboard so this is // NOTE: Some applications may not require a keyboard so this is
// optional, but we are still displaying an error. // optional, but we are still displaying an error.
fprintf(stderr, "error: no couldn't open keyboard %s: %s.\n", dev, strerror(errno)); fprintf(stderr, "error: no couldn't open keyboard %s: %s.\n", KBD_PATH, strerror(errno));
}
in.mouse_fd = open(MOUSE_PATH, O_RDONLY | O_NONBLOCK);
if (in.mouse_fd == -1) {
// NOTE: Some applications may not require a mouse so this is
// optional, but we are still displaying an error.
fprintf(stderr, "error: no couldn't open mouse %s: %s.\n", MOUSE_PATH, strerror(errno));
} }
} }
void void
poll_keyboard(void) { poll_keyboard(void) {
if (input.kb_fd == -1) { if (in.kbd_fd == -1) {
return; return;
} }
// TODO: use read() instead to avoid updating the keyboard if no events have
// occurred. Similar to the mouse implementation.
char map[KEY_MAX / 8 + 1]; char map[KEY_MAX / 8 + 1];
memset(map, 0, sizeof(map)); memset(map, 0, sizeof(map));
ioctl(input.kb_fd, EVIOCGKEY(sizeof(map)), map); ioctl(in.kbd_fd, EVIOCGKEY(sizeof(map)), map);
for (size_t i = 0; i < sizeof(map); i++) { for (size_t i = 0; i < sizeof(map); i++) {
input.map[i] |= map[i]; in.map[i] |= map[i];
} }
} }
void
poll_mouse(void) {
if (in.mouse_fd == -1) {
return;
}
struct input_event mouse_event;
if (read(in.mouse_fd, &mouse_event, sizeof(mouse_event)) != -1) {
if (mouse_event.type == EV_REL) {
if (mouse_event.code == REL_X) {
in.mouse.x = CLAMP(
in.mouse.x + (s32)mouse_event.value, 0, (s32)screen_width);
} else if (mouse_event.code == REL_Y) {
in.mouse.y = CLAMP(
in.mouse.y + (s32)mouse_event.value, 0, (s32)screen_height);
}
}
in.mouse.update = true;
// TODO: Handle mouse keys
}
}
void
poll_input(void) {
poll_keyboard();
poll_mouse();
}
void void
handle_keyboard(void) { handle_keyboard(void) {
// Find mod keys. // Find mod keys.
@ -76,9 +129,9 @@ handle_keyboard(void) {
// bool ctrl_mod = false; // bool ctrl_mod = false;
// bool alt_mod = false; // bool alt_mod = false;
// bool meta_mod = false; // bool meta_mod = false;
for (size_t i = 0; i < sizeof(input.map); i++) { for (size_t i = 0; i < sizeof(in.map); i++) {
for (size_t j = 0; j < 8; j++) { for (size_t j = 0; j < 8; j++) {
char key = input.map[i] & (1 << j); char key = in.map[i] & (1 << j);
if (key) { if (key) {
char key_code = i * 8 + j; char key_code = i * 8 + j;
switch (key_code) { switch (key_code) {
@ -98,9 +151,9 @@ handle_keyboard(void) {
// Handle normal keys. // Handle normal keys.
u8 controller_now = 0; u8 controller_now = 0;
for (size_t i = 0; i < sizeof(input.map); i++) { for (size_t i = 0; i < sizeof(in.map); i++) {
for (size_t j = 0; j < 8; j++) { for (size_t j = 0; j < 8; j++) {
char key = input.map[i] & (1 << j); char key = in.map[i] & (1 << j);
if (key) { if (key) {
char key_code = i * 8 + j; char key_code = i * 8 + j;
// Normal keys. // Normal keys.
@ -204,15 +257,32 @@ handle_keyboard(void) {
} }
} }
if (controller_now != input.controller) { if (controller_now != in.controller) {
devctrl->dat[2] = controller_now; devctrl->dat[2] = controller_now;
uxn_eval(&u, mempeek16(devctrl->dat, 0)); uxn_eval(&u, mempeek16(devctrl->dat, 0));
input.controller = controller_now; in.controller = controller_now;
} }
// Reset input state. // Reset input state.
devctrl->dat[3] = 0; devctrl->dat[3] = 0;
memset(input.map, 0, sizeof(input.map)); memset(in.map, 0, sizeof(in.map));
}
void
handle_mouse(void) {
if (in.mouse.update) {
// TODO: Handle mouse keys
mempoke16(devmouse->dat, 0x2, in.mouse.x);
mempoke16(devmouse->dat, 0x4, in.mouse.y);
uxn_eval(&u, mempeek16(devmouse->dat, 0));
in.mouse.update = false;
}
}
void
handle_input(void) {
handle_keyboard();
handle_mouse();
} }
void void
@ -430,10 +500,10 @@ main(int argc, char *argv[]) {
uxn_eval(&u, 0x0100); uxn_eval(&u, 0x0100);
Time frame_time = time_now(); Time frame_time = time_now();
while (true) { while (true) {
poll_keyboard(); poll_input();
size_t elapsed = time_elapsed(frame_time); size_t elapsed = time_elapsed(frame_time);
if (elapsed >= 16666666) { if (elapsed >= 16666666) {
handle_keyboard(); handle_input();
// Echo input to standard output. // Echo input to standard output.
uxn_eval(&u, mempeek16(devscreen->dat, 0)); uxn_eval(&u, mempeek16(devscreen->dat, 0));