/** * Copyright (c) 2025 Dominic Masters * * This software is released under the MIT License. * https://opensource.org/licenses/MIT */ #include "input.h" #include "util/memory.h" #include "assert/assert.h" #include input_t INPUT; inputmap_t INPUT_MAP[] = { {"w", INPUT_UP}, {"s", INPUT_DOWN}, {"a", INPUT_LEFT}, {"d", INPUT_RIGHT}, {" ", INPUT_ACTION}, {"e", INPUT_ACTION}, {"\n", INPUT_ACTION}, // Enter key {"\x1B", INPUT_CANCEL}, // Escape key {"\033[A", INPUT_UP}, // Up arrow {"\033[B", INPUT_DOWN}, // Down arrow {"\033[C", INPUT_RIGHT}, // Right arrow {"\033[D", INPUT_LEFT}, // Left arrow { 0 } }; void inputEnableRawMode() { if (INPUT.isRawMode) return; tcgetattr(STDIN_FILENO, &INPUT.origin); struct termios raw = INPUT.origin; raw.c_lflag &= ~(ICANON | ECHO); tcsetattr(STDIN_FILENO, TCSANOW, &raw); INPUT.isRawMode = 1; } void inputDisableRawMode() { if(!INPUT.isRawMode) return; tcsetattr(STDIN_FILENO, TCSANOW, &INPUT.origin); INPUT.isRawMode = 0; } void inputSetNonBlocking() { int flags = fcntl(STDIN_FILENO, F_GETFL, 0); fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK); } void inputInit() { memoryZero(&INPUT, sizeof(input_t)); inputEnableRawMode(); inputSetNonBlocking(); } void inputUpdate() { char_t buffer[INPUT_BUFFER_SIZE]; ssize_t n = read(STDIN_FILENO, buffer, sizeof(buffer) - 1); if(n < 0) { INPUT.previous = INPUT.current; INPUT.current = 0; return; } assertTrue(n < INPUT_BUFFER_SIZE, "Input buffer overflow"); uint8_t val = 0; inputmap_t *map; uint8_t len; char_t *c; for(uint8_t i = 0; i < n; i++) { map = INPUT_MAP; do { len = strlen(map->key); if(i + len > n) { map++; continue; } c = buffer + i; if(memoryCompare(c, map->key, len) != 0) { map++; continue; } // Button was pressed val |= map->value; i += len - 1; } while(map->key); } INPUT.previous = INPUT.current; INPUT.current = val; } void inputDispose() { inputDisableRawMode(); }