103 lines
2.1 KiB
C
103 lines
2.1 KiB
C
/**
|
|
* 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 <fcntl.h>
|
|
|
|
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();
|
|
} |