diff --git a/README.md b/README.md index 3f40ee1..5e2fa59 100644 --- a/README.md +++ b/README.md @@ -63,6 +63,7 @@ source code stats (80 column wrapping, a lot of empty lines): | --------------------------------------| ------- | --------- | | game.h (main game logic) | TODO | TODO | | raycastlib.h (ray casting library) | TODO | TODO | +| smallinput.h (test helper) | TODO | TODO | | images.h, levels.h, sounds.h (assets) | TODO | TODO | | settings.h, constants.h | TODO | TODO | | **total** | TODO | TODO | @@ -250,6 +251,7 @@ main_*.* fronted implement. for various platforms, passed to compiler palette.h game 256 color palette raycastlib.h ray casting library settings.h game settings that users can change (FPS, resolution, ...) +smallinput.h helper for some frontends and tests, not needed for the game sounds.h sounds from assets folder converted to C texts.h game texts make.sh compiling script constaining compiler settings diff --git a/main_terminal.c b/main_terminal.c index 0927773..86ad53d 100644 --- a/main_terminal.c +++ b/main_terminal.c @@ -24,6 +24,8 @@ #include #include +#include "smallinput.h" + #define SFG_SCREEN_RESOLUTION_X 127 #define SFG_SCREEN_RESOLUTION_Y 42 #define SFG_DITHERED_SHADOW 1 @@ -43,33 +45,6 @@ const char shades[] = // adjust according to your terminal uint32_t timeStart; -typedef struct -{ - struct timeval time; - __u16 type; - __u16 code; - __s32 value; -} InputEvent; - -InputEvent event; - -#define TOTAL_KEYS 9 - -uint16_t keyCodes[TOTAL_KEYS] = - { - KEY_W, - KEY_S, - KEY_A, - KEY_D, - KEY_SPACE, - KEY_H, - KEY_J, - KEY_K, - KEY_Q - }; - -uint8_t keyStates[TOTAL_KEYS]; - uint32_t getTime() { struct timeval now; @@ -104,6 +79,12 @@ void SFG_sleepMs(uint16_t timeMs) void SFG_getMouseOffset(int16_t *x, int16_t *y) { + int32_t a,b; + + input_getMousePos(&a,&b); + *x = a; + *y = b; + input_setMousePos(0,0); } void SFG_processEvent(uint8_t event, uint8_t data) @@ -114,15 +95,15 @@ int8_t SFG_keyPressed(uint8_t key) { switch (key) { - case SFG_KEY_UP: return keyStates[0]; break; - case SFG_KEY_RIGHT: return keyStates[3]; break; - case SFG_KEY_DOWN: return keyStates[1]; break; - case SFG_KEY_LEFT: return keyStates[2]; break; - case SFG_KEY_A: return keyStates[5]; break; - case SFG_KEY_B: return keyStates[6]; break; - case SFG_KEY_C: return keyStates[7]; break; - case SFG_KEY_MAP: return keyStates[8]; break; - case SFG_KEY_JUMP: return keyStates[4]; break; + case SFG_KEY_UP: return input_getKey('w') || input_getKey(SMALLINPUT_ARROW_UP); break; + case SFG_KEY_RIGHT: return input_getKey('d') || input_getKey(SMALLINPUT_ARROW_RIGHT); break; + case SFG_KEY_DOWN: return input_getKey('s') || input_getKey(SMALLINPUT_ARROW_DOWN); break; + case SFG_KEY_LEFT: return input_getKey('a') || input_getKey(SMALLINPUT_ARROW_LEFT); break; + case SFG_KEY_A: return input_getKey('g'); break; + case SFG_KEY_B: return input_getKey('h') || input_getKey(SMALLINPUT_MOUSE_L); break; + case SFG_KEY_C: return input_getKey('j'); break; + case SFG_KEY_MAP: return input_getKey(SMALLINPUT_TAB); break; + case SFG_KEY_JUMP: return input_getKey(' '); break; default: return 0; break; } } @@ -145,26 +126,17 @@ void handleSignal(int signal) int main() { - int devFile; - signal(SIGINT,handleSignal); signal(SIGQUIT,handleSignal); signal(SIGTERM,handleSignal); timeStart = getTime(); - devFile = open("/dev/input/event0",O_RDONLY); - // ^ replace with your specific keyboard file - - fcntl(devFile, F_SETFL, O_NONBLOCK); - + input_init(); SFG_init(); screen[SCREENSIZE - 1] = 0; // string terminator - for (uint16_t i = 0; i < TOTAL_KEYS; ++i) - keyStates[i] = 0; - for (uint16_t i = 1; i <= SFG_SCREEN_RESOLUTION_Y; ++i) screen[i * (SFG_SCREEN_RESOLUTION_X + 1) - 1] = '\n'; @@ -177,24 +149,8 @@ int main() while (running) { - while (1) - { - int n = read(devFile, &event, sizeof(event)); - - if (n <= 0) - break; - - if (event.type == EV_KEY && (event.value == 1 || event.value == 0)) - { - for (uint8_t i = 0; i < TOTAL_KEYS; ++i) - if (event.code == keyCodes[i]) - { - keyStates[i] = event.value; - break; - } - } - } - + input_update(); + puts("\033[0;0H"); // move cursor to 0;0 puts(screen); fflush(stdout); @@ -202,6 +158,8 @@ int main() if (!SFG_mainLoopBody()) running = 0; } - + puts("\033[?25h"); // show cursor + + input_end(); } diff --git a/smallinput.h b/smallinput.h new file mode 100644 index 0000000..7487f12 --- /dev/null +++ b/smallinput.h @@ -0,0 +1,215 @@ +/** + @file smallinput.h + + Small API for getting keyboard/mouse input, with possiblity to record it and + play back. + + The Linux Input API requires root pirivileges (sudo). + + by Milsolav "drummyfish" Ciz, released under CC0 1.0 (public domain) +*/ + +#ifndef _SMALLINPUT_H +#define _SMALLINPUT_H + +#include + +#define SMALLINPUT_KEY_NONE 0 +#define SMALLINPUT_ARROW_UP 128 +#define SMALLINPUT_ARROW_RIGHT 129 +#define SMALLINPUT_ARROW_DOWN 130 +#define SMALLINPUT_ARROW_LEFT 131 +#define SMALLINPUT_SPACE ' ' +#define SMALLINPUT_BACKSPACE 8 +#define SMALLINPUT_TAB 9 +#define SMALLINPUT_RETURN 13 +#define SMALLINPUT_SHIFT 14 +#define SMALLINPUT_ESCAPE 27 +#define SMALLINPUT_DELETE 127 +#define SMALLINPUT_MOUSE_L 253 +#define SMALLINPUT_MOUSE_M 254 +#define SMALLINPUT_MOUSE_R 255 + +uint8_t input_keyStates[256]; +int32_t input_mousePosition[2]; +uint32_t input_frame = 0; + +#if 1 // TODO: add other options for input handling (SDL, xinput, ...) + /* + This is using Linux Input Subsystem API. Defines can be found in + include/uapi/linux/input-event-codes.h. + */ + + #include + #include + #include + #include + + typedef struct + { + struct timeval time; + uint16_t type; + uint16_t code; + int32_t value; + } LinuxInputEvent; + + #define INPUT_KEYBOARD_FILE "/dev/input/event0" + #define INPUT_MOUSE_FILE "/dev/input/event1" + + int input_keyboardFile = 0; + int input_mouseFile = 0; + + /** + Maps this library's key codes to linux input key codes. + */ + static const int input_linuxCodes[256] = + { + #define no KEY_RESERVED + no,no,no,no,no,no,no,no,KEY_BACKSPACE,KEY_TAB,no,no,no,KEY_ENTER,KEY_LEFTSHIFT,no, + no,no,no,no,no,no,no,no,no,no,no,KEY_ESC,no,no,no,no, + KEY_SPACE,no,no,no,no,no,no,no,no,no,no,no,no,no,no,no, + no,no,no,no,no,no,no,no,no,no,no,no,no,no,no,no, + no,KEY_A,KEY_B,KEY_C,KEY_D,KEY_E,KEY_F,KEY_G,KEY_H,KEY_I,KEY_J,KEY_K,KEY_L,KEY_M,KEY_N,KEY_O, + KEY_P,KEY_Q,KEY_R,KEY_S,KEY_T,KEY_U,KEY_V,KEY_W,KEY_X,KEY_Y,KEY_Z,no,no,no,no,no, + no,KEY_A,KEY_B,KEY_C,KEY_D,KEY_E,KEY_F,KEY_G,KEY_H,KEY_I,KEY_J,KEY_K,KEY_L,KEY_M,KEY_N,KEY_O, + KEY_P,KEY_Q,KEY_R,KEY_S,KEY_T,KEY_U,KEY_V,KEY_W,KEY_X,KEY_Y,KEY_Z,no,no,no,no,KEY_DELETE, + KEY_UP,KEY_RIGHT,KEY_DOWN,KEY_LEFT,no,no,no,no,no,no,no,no,no,no,no,no, + no,no,no,no,no,no,no,no,no,no,no,no,no,no,no,no, + no,no,no,no,no,no,no,no,no,no,no,no,no,no,no,no, + no,no,no,no,no,no,no,no,no,no,no,no,no,no,no,no, + no,no,no,no,no,no,no,no,no,no,no,no,no,no,no,no, + no,no,no,no,no,no,no,no,no,no,no,no,no,no,no,no, + no,no,no,no,no,no,no,no,no,no,no,no,no,no,no,no, + no,no,no,no,no,no,no,no,no,no,no,no,no,no,no,no + #undef no + }; +#endif + +/** + Initializes the library. +*/ +void input_init(void) +{ + input_mousePosition[0] = 0; + input_mousePosition[1] = 0; + input_frame = 0; + + for (int16_t i = 0; i < 256; ++i) + input_keyStates[i] = 0; + + input_keyboardFile = open(INPUT_KEYBOARD_FILE, O_RDONLY); + fcntl(input_keyboardFile, F_SETFL, O_NONBLOCK); + + input_mouseFile = open(INPUT_MOUSE_FILE, O_RDONLY); + fcntl(input_mouseFile, F_SETFL, O_NONBLOCK); +} + +void input_end(void) +{ + close(input_keyboardFile); + close(input_mouseFile); +} + +/** + Should be called once every main loop iteration to retrieve current input + state. +*/ +void input_update(void) +{ + LinuxInputEvent event; + + while (1) // keyboard + { + if (read(input_keyboardFile, &event, sizeof(event)) <= 0) + break; + + if (event.type == EV_KEY && (event.value == 1 || event.value == 0)) + for (uint16_t i = 0; i < 256; ++i) + if (event.code == input_linuxCodes[i]) + { + input_keyStates[i] = event.value; + break; + } + } + + while (1) // mouse + { + if (read(input_mouseFile, &event, sizeof(event)) <= 0) + break; + + if (event.type == EV_REL) + input_mousePosition[event.code % 2] += event.value; + else if (event.type == EV_KEY) + { + input_keyStates[ + event.code == BTN_LEFT ? SMALLINPUT_MOUSE_L : + (event.code == BTN_RIGHT ? SMALLINPUT_MOUSE_R : SMALLINPUT_MOUSE_M)] + = event.value; + } + } + + for (uint16_t i = 0; i < 256; ++i) + if (input_keyStates[i] && input_keyStates[i] < 255) + input_keyStates[i]++; + + input_frame++; +} + +/** + Returns the number of input frames for which given key has been pressed (> 1: + key is pressed, == 1: key was just pressed, == 0: key is not pressed). +*/ +static inline uint8_t input_getKey(uint8_t key) +{ + if (key >= 'a' && key <= 'z') + key = 'A' + (key - 'a'); + + return input_keyStates[key]; +} + +/** + Gets the mouse position. +*/ +static inline void input_getMousePos(int16_t *x, int16_t *y) +{ + *x = input_mousePosition[0]; + *y = input_mousePosition[1]; +} + +static inline void input_setMousePos(int32_t x, int32_t y) +{ + input_mousePosition[0] = x; + input_mousePosition[1] = y; +} + +#if 0 // this can be used to test this +mates + +#include + +int main(void) +{ + input_init(); + + while (1) + { + input_update(); + + puts("\n\n\n\n"); + + for (uint16_t i = 0; i < 256; ++i) + printf("%d (%c): %d, ",i,i,input_keyStates[i]); + + printf("mouse: %d %d (%d %d %d)\n",input_mousePosition[0],input_mousePosition[1],input_getKey(SMALLINPUT_MOUSE_L),input_getKey(SMALLINPUT_MOUSE_M),input_getKey(SMALLINPUT_MOUSE_R)); + + puts(""); + + usleep(10000); + } + + input_end(); +} + +#endif + +#endif