aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBad Diode <bd@badd10de.dev>2022-03-05 19:23:24 +0100
committerBad Diode <bd@badd10de.dev>2022-03-05 19:23:24 +0100
commit85ee9eb4b40d505f5298ff4759d973ab741422d9 (patch)
tree48d7924e0706eefcd724c4bb3997ad704d07beae
parentd08a7dfac6ea835603a580668761aa27e70f669b (diff)
downloaduxnfb-85ee9eb4b40d505f5298ff4759d973ab741422d9.tar.gz
uxnfb-85ee9eb4b40d505f5298ff4759d973ab741422d9.zip
Add initial mouse support
-rw-r--r--Makefile26
-rw-r--r--src/main.c112
2 files changed, 105 insertions, 33 deletions
diff --git a/Makefile b/Makefile
index 8548dbc..10dc4fb 100644
--- a/Makefile
+++ b/Makefile
@@ -1,14 +1,16 @@
1BASE_UXN := src/uxn 1BASE_UXN := src/uxn
2SRC_DIR ?= src 2SRC_DIR ?= src
3BUILD_DIR ?= build 3BUILD_DIR ?= build
4SRC_MAIN ?= $(SRC_DIR)/main.c 4SRC_MAIN ?= $(SRC_DIR)/main.c
5EXE_NAME ?= uxnfb 5EXE_NAME ?= uxnfb
6BIN := $(BUILD_DIR)/$(EXE_NAME) 6BIN := $(BUILD_DIR)/$(EXE_NAME)
7UXN_HEAD := $(BASE_UXN)/src/uxn.h 7UXN_HEAD := $(BASE_UXN)/src/uxn.h
8TAL_SRC ?= $(BASE_UXN)/projects/examples/devices/screen.tal 8TAL_SRC ?= $(BASE_UXN)/projects/examples/devices/screen.tal
9UXN_ROM ?= $(BUILD_DIR)/rom.rom 9UXN_ROM ?= $(BUILD_DIR)/rom.rom
10UXN_ASM ?= $(BUILD_DIR)/uxnasm 10UXN_ASM ?= $(BUILD_DIR)/uxnasm
11KBD_PATH ?= /dev/input/event1 11KBD_PATH ?= /dev/input/event1
12MOUSE_PATH ?= /dev/input/mice
13C_DEFINES := -DKBD_PATH=\"$(KBD_PATH)\" -DMOUSE_PATH=\"$(MOUSE_PATH)\"
12 14
13CC ?= cc 15CC ?= cc
14CFLAGS := -Wall -Wextra -pedantic 16CFLAGS := -Wall -Wextra -pedantic
@@ -30,7 +32,7 @@ endif
30main: $(BIN) 32main: $(BIN)
31 33
32$(BIN): $(SRC_MAIN) $(BUILD_DIR) $(UXN_HEAD) 34$(BIN): $(SRC_MAIN) $(BUILD_DIR) $(UXN_HEAD)
33 $(CC) $(CFLAGS) -o $(BIN) $(SRC_MAIN) -DKBD_PATH=\"$(KBD_PATH)\" 35 $(CC) $(CFLAGS) -o $(BIN) $(SRC_MAIN) $(C_DEFINES)
34 36
35$(BUILD_DIR): 37$(BUILD_DIR):
36 mkdir -p $(BUILD_DIR) 38 mkdir -p $(BUILD_DIR)
diff --git a/src/main.c b/src/main.c
index aac3211..a431029 100644
--- a/src/main.c
+++ b/src/main.c
@@ -12,6 +12,8 @@
12#include "ppu.c" 12#include "ppu.c"
13#include "uxn-fast.c" 13#include "uxn-fast.c"
14 14
15#define CLAMP(X, MIN, MAX) ((X) <= (MIN) ? (MIN) : (X) > (MAX) ? (MAX): (X))
16
15static Uxn u; 17static Uxn u;
16static Device *devscreen; 18static Device *devscreen;
17static Device *devctrl; 19static Device *devctrl;
@@ -33,52 +35,103 @@ time_elapsed(Time since){
33 return (now.tv_sec - since.tv_sec) * 1e9 + (now.tv_nsec - since.tv_nsec); 35 return (now.tv_sec - since.tv_sec) * 1e9 + (now.tv_nsec - since.tv_nsec);
34} 36}
35 37
38typedef struct Mouse {
39 s32 x;
40 s32 y;
41 bool left;
42 bool mid;
43 bool right;
44 bool update;
45} Mouse;
46
36typedef struct Input { 47typedef struct Input {
37 int kb_fd; 48 int kbd_fd;
49 int mouse_fd;
38 char map[KEY_MAX / 8 + 1]; 50 char map[KEY_MAX / 8 + 1];
39 u8 controller; 51 u8 controller;
52 Mouse mouse;
40} Input; 53} Input;
41 54
42static Input input; 55// NOTE: For event codes and input documentation:
56// - https://www.kernel.org/doc/Documentation/input/event-codes.txt
57// - /usr/include/linux/input.h
58static Input in;
43 59
44void 60void
45init_input(void) { 61init_input(void) {
46 memset(&input, 0, sizeof(input)); 62 memset(&in, 0, sizeof(in));
47 input.kb_fd = -1; 63 in.kbd_fd = -1;
64 in.mouse_fd = -1;
48 65
49 const char *dev = KBD_PATH; 66 in.kbd_fd = open(KBD_PATH, O_RDONLY | O_NONBLOCK);
50 input.kb_fd = open(dev, O_RDONLY); 67 if (in.kbd_fd == -1) {
51 if (input.kb_fd == -1) {
52 // NOTE: Some applications may not require a keyboard so this is 68 // NOTE: Some applications may not require a keyboard so this is
53 // optional, but we are still displaying an error. 69 // optional, but we are still displaying an error.
54 fprintf(stderr, "error: no couldn't open keyboard %s: %s.\n", dev, strerror(errno)); 70 fprintf(stderr, "error: no couldn't open keyboard %s: %s.\n", KBD_PATH, strerror(errno));
71 }
72
73 in.mouse_fd = open(MOUSE_PATH, O_RDONLY | O_NONBLOCK);
74 if (in.mouse_fd == -1) {
75 // NOTE: Some applications may not require a mouse so this is
76 // optional, but we are still displaying an error.
77 fprintf(stderr, "error: no couldn't open mouse %s: %s.\n", MOUSE_PATH, strerror(errno));
55 } 78 }
56} 79}
57 80
58void 81void
59poll_keyboard(void) { 82poll_keyboard(void) {
60 if (input.kb_fd == -1) { 83 if (in.kbd_fd == -1) {
61 return; 84 return;
62 } 85 }
63 86
87 // TODO: use read() instead to avoid updating the keyboard if no events have
88 // occurred. Similar to the mouse implementation.
64 char map[KEY_MAX / 8 + 1]; 89 char map[KEY_MAX / 8 + 1];
65 memset(map, 0, sizeof(map)); 90 memset(map, 0, sizeof(map));
66 ioctl(input.kb_fd, EVIOCGKEY(sizeof(map)), map); 91 ioctl(in.kbd_fd, EVIOCGKEY(sizeof(map)), map);
67 for (size_t i = 0; i < sizeof(map); i++) { 92 for (size_t i = 0; i < sizeof(map); i++) {
68 input.map[i] |= map[i]; 93 in.map[i] |= map[i];
69 } 94 }
70} 95}
71 96
72void 97void
98poll_mouse(void) {
99 if (in.mouse_fd == -1) {
100 return;
101 }
102
103 struct input_event mouse_event;
104 if (read(in.mouse_fd, &mouse_event, sizeof(mouse_event)) != -1) {
105 if (mouse_event.type == EV_REL) {
106 if (mouse_event.code == REL_X) {
107 in.mouse.x = CLAMP(
108 in.mouse.x + (s32)mouse_event.value, 0, (s32)screen_width);
109 } else if (mouse_event.code == REL_Y) {
110 in.mouse.y = CLAMP(
111 in.mouse.y + (s32)mouse_event.value, 0, (s32)screen_height);
112 }
113 }
114 in.mouse.update = true;
115 // TODO: Handle mouse keys
116 }
117}
118
119void
120poll_input(void) {
121 poll_keyboard();
122 poll_mouse();
123}
124
125void
73handle_keyboard(void) { 126handle_keyboard(void) {
74 // Find mod keys. 127 // Find mod keys.
75 bool shift_mod = false; 128 bool shift_mod = false;
76 // bool ctrl_mod = false; 129 // bool ctrl_mod = false;
77 // bool alt_mod = false; 130 // bool alt_mod = false;
78 // bool meta_mod = false; 131 // bool meta_mod = false;
79 for (size_t i = 0; i < sizeof(input.map); i++) { 132 for (size_t i = 0; i < sizeof(in.map); i++) {
80 for (size_t j = 0; j < 8; j++) { 133 for (size_t j = 0; j < 8; j++) {
81 char key = input.map[i] & (1 << j); 134 char key = in.map[i] & (1 << j);
82 if (key) { 135 if (key) {
83 char key_code = i * 8 + j; 136 char key_code = i * 8 + j;
84 switch (key_code) { 137 switch (key_code) {
@@ -98,9 +151,9 @@ handle_keyboard(void) {
98 151
99 // Handle normal keys. 152 // Handle normal keys.
100 u8 controller_now = 0; 153 u8 controller_now = 0;
101 for (size_t i = 0; i < sizeof(input.map); i++) { 154 for (size_t i = 0; i < sizeof(in.map); i++) {
102 for (size_t j = 0; j < 8; j++) { 155 for (size_t j = 0; j < 8; j++) {
103 char key = input.map[i] & (1 << j); 156 char key = in.map[i] & (1 << j);
104 if (key) { 157 if (key) {
105 char key_code = i * 8 + j; 158 char key_code = i * 8 + j;
106 // Normal keys. 159 // Normal keys.
@@ -204,15 +257,32 @@ handle_keyboard(void) {
204 } 257 }
205 } 258 }
206 259
207 if (controller_now != input.controller) { 260 if (controller_now != in.controller) {
208 devctrl->dat[2] = controller_now; 261 devctrl->dat[2] = controller_now;
209 uxn_eval(&u, mempeek16(devctrl->dat, 0)); 262 uxn_eval(&u, mempeek16(devctrl->dat, 0));
210 input.controller = controller_now; 263 in.controller = controller_now;
211 } 264 }
212 265
213 // Reset input state. 266 // Reset input state.
214 devctrl->dat[3] = 0; 267 devctrl->dat[3] = 0;
215 memset(input.map, 0, sizeof(input.map)); 268 memset(in.map, 0, sizeof(in.map));
269}
270
271void
272handle_mouse(void) {
273 if (in.mouse.update) {
274 // TODO: Handle mouse keys
275 mempoke16(devmouse->dat, 0x2, in.mouse.x);
276 mempoke16(devmouse->dat, 0x4, in.mouse.y);
277 uxn_eval(&u, mempeek16(devmouse->dat, 0));
278 in.mouse.update = false;
279 }
280}
281
282void
283handle_input(void) {
284 handle_keyboard();
285 handle_mouse();
216} 286}
217 287
218void 288void
@@ -430,10 +500,10 @@ main(int argc, char *argv[]) {
430 uxn_eval(&u, 0x0100); 500 uxn_eval(&u, 0x0100);
431 Time frame_time = time_now(); 501 Time frame_time = time_now();
432 while (true) { 502 while (true) {
433 poll_keyboard(); 503 poll_input();
434 size_t elapsed = time_elapsed(frame_time); 504 size_t elapsed = time_elapsed(frame_time);
435 if (elapsed >= 16666666) { 505 if (elapsed >= 16666666) {
436 handle_keyboard(); 506 handle_input();
437 507
438 // Echo input to standard output. 508 // Echo input to standard output.
439 uxn_eval(&u, mempeek16(devscreen->dat, 0)); 509 uxn_eval(&u, mempeek16(devscreen->dat, 0));