Add initial mouse support
This commit is contained in:
parent
d08a7dfac6
commit
85ee9eb4b4
26
Makefile
26
Makefile
|
@ -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)
|
||||||
|
|
112
src/main.c
112
src/main.c
|
@ -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));
|
||||||
|
|
Loading…
Reference in New Issue