2024-03-25 05:34:59 +00:00
|
|
|
#include <iso646.h>
|
|
|
|
#include <pthread.h>
|
|
|
|
#include <stdbool.h>
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include "fumotris.h"
|
|
|
|
|
|
|
|
#define IO_BUF_SIZE 8
|
|
|
|
|
|
|
|
enum InputType {
|
|
|
|
KEY,
|
|
|
|
AXIS,
|
|
|
|
JOYSTICK,
|
|
|
|
WINDOW,
|
|
|
|
ESCAPE
|
|
|
|
};
|
|
|
|
|
|
|
|
struct InputRecord {
|
|
|
|
enum InputType type;
|
|
|
|
u16 id;
|
|
|
|
|
|
|
|
union {
|
|
|
|
struct {
|
|
|
|
bool is_down;
|
2024-03-26 20:11:58 +00:00
|
|
|
} key;
|
|
|
|
struct {
|
|
|
|
u64 value;
|
2024-03-25 05:34:59 +00:00
|
|
|
} axis;
|
|
|
|
struct {
|
|
|
|
u32 x;
|
|
|
|
u32 y;
|
|
|
|
} joystick;
|
|
|
|
} data;
|
|
|
|
|
|
|
|
double timestamp;
|
|
|
|
};
|
|
|
|
|
2024-03-26 20:11:58 +00:00
|
|
|
struct InputBuffer {
|
|
|
|
struct InputRecord records[IO_BUF_SIZE];
|
2024-03-25 05:34:59 +00:00
|
|
|
size_t count;
|
2024-03-26 20:11:58 +00:00
|
|
|
pthread_mutex_t mutex;
|
2024-03-25 05:34:59 +00:00
|
|
|
};
|
|
|
|
|
2024-03-26 20:11:58 +00:00
|
|
|
struct InputBuffer NewInputBuffer()
|
|
|
|
{
|
|
|
|
struct InputBuffer buf;
|
|
|
|
buf.count = 0;
|
|
|
|
buf.mutex = PTHREAD_MUTEX_INITIALIZER;
|
|
|
|
return buf;
|
|
|
|
}
|
|
|
|
|
2024-03-25 05:34:59 +00:00
|
|
|
struct Axis {
|
2024-03-26 20:11:58 +00:00
|
|
|
u8 type;
|
|
|
|
|
2024-03-25 05:34:59 +00:00
|
|
|
union {
|
|
|
|
struct {
|
|
|
|
u32 value;
|
2024-03-26 20:11:58 +00:00
|
|
|
u32 is_down : 1;
|
|
|
|
u32 is_up : 1;
|
|
|
|
} key;
|
|
|
|
struct {
|
|
|
|
u64 value;
|
2024-03-25 05:34:59 +00:00
|
|
|
} axis;
|
|
|
|
struct {
|
|
|
|
u32 x;
|
|
|
|
u32 y;
|
|
|
|
} joystick;
|
|
|
|
} data;
|
|
|
|
|
|
|
|
double last_pressed;
|
|
|
|
double last_released;
|
|
|
|
};
|
|
|
|
|
|
|
|
enum KeyCode {
|
|
|
|
LEFT,
|
|
|
|
RIGHT,
|
|
|
|
SOFT_DROP,
|
|
|
|
HARD_DROP,
|
|
|
|
ROTATE_CCW,
|
|
|
|
ROTATE_CW,
|
|
|
|
ROTATE_180,
|
|
|
|
SWAP,
|
|
|
|
ESC
|
|
|
|
};
|
|
|
|
|
|
|
|
enum AxisCode {
|
|
|
|
VSCROLL,
|
|
|
|
HSCROLL
|
|
|
|
};
|
|
|
|
|
|
|
|
enum JoystickCode {
|
|
|
|
MOUSE
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef u32 hashtype;
|
|
|
|
hashtype Hash(void *item, size_t size)
|
|
|
|
{
|
|
|
|
u8* data = (u8*)item;
|
|
|
|
|
|
|
|
u32 h = 98317;
|
|
|
|
for (size_t i = 0; i < size; i++) {
|
|
|
|
h ^= data[i];
|
|
|
|
h *= 0x5bd1e995;
|
|
|
|
h ^= h >> 15;
|
|
|
|
}
|
|
|
|
|
|
|
|
return h;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct ident {
|
|
|
|
u16 id;
|
|
|
|
enum InputType type;
|
|
|
|
};
|
|
|
|
|
|
|
|
hashtype hash_ident(u16f id, enum InputType type)
|
|
|
|
{
|
|
|
|
struct ident obj = { id, type };
|
|
|
|
return Hash(&obj, sizeof(struct ident));
|
|
|
|
}
|
|
|
|
|
2024-03-26 20:11:58 +00:00
|
|
|
struct code_bkt {
|
|
|
|
hashtype hash;
|
|
|
|
u16 code;
|
2024-03-25 05:34:59 +00:00
|
|
|
struct Axis axis;
|
|
|
|
};
|
|
|
|
|
2024-03-26 20:11:58 +00:00
|
|
|
struct bind_bkt {
|
|
|
|
hashtype hash;
|
|
|
|
u16 bind;
|
|
|
|
struct Axis *axis;
|
|
|
|
};
|
|
|
|
|
2024-03-25 05:34:59 +00:00
|
|
|
struct Ctrl {
|
2024-03-26 20:11:58 +00:00
|
|
|
struct {
|
|
|
|
size_t capacity;
|
|
|
|
size_t filled;
|
|
|
|
struct code_bkt *bkts;
|
|
|
|
} codes;
|
|
|
|
|
|
|
|
struct {
|
|
|
|
size_t capacity;
|
|
|
|
size_t filled;
|
|
|
|
struct bind_bkt *bkts;
|
|
|
|
} binds;
|
2024-03-25 05:34:59 +00:00
|
|
|
|
|
|
|
pthread_mutex_t mutex;
|
|
|
|
};
|
|
|
|
typedef struct Ctrl Ctrl;
|
|
|
|
|
2024-03-26 20:11:58 +00:00
|
|
|
Ctrl NewCtrl(struct code_bkt *codes, size_t c, struct bind_bkt *binds, size_t b)
|
2024-03-25 05:34:59 +00:00
|
|
|
{
|
2024-03-26 20:11:58 +00:00
|
|
|
memset(codes, 0, sizeof(struct code_bkt) * c);
|
|
|
|
memset(binds, 0, sizeof(struct bind_bkt) * b);
|
|
|
|
|
2024-03-25 05:34:59 +00:00
|
|
|
Ctrl ctrl;
|
2024-03-26 20:11:58 +00:00
|
|
|
ctrl.codes.bkts = codes;
|
|
|
|
ctrl.binds.bkts = binds;
|
2024-03-25 05:34:59 +00:00
|
|
|
ctrl.mutex = PTHREAD_MUTEX_INITIALIZER;
|
2024-03-26 20:11:58 +00:00
|
|
|
|
2024-03-25 05:34:59 +00:00
|
|
|
return ctrl;
|
|
|
|
}
|
|
|
|
|
2024-03-26 20:11:58 +00:00
|
|
|
void CtrlPoll(struct InputBuffer *buf)
|
2024-03-25 05:34:59 +00:00
|
|
|
{
|
2024-03-26 20:11:58 +00:00
|
|
|
for (size_t i = 0; i < buf->count; i++) {
|
|
|
|
struct InputRecord *rec = &buf->records[i];
|
|
|
|
|
|
|
|
switch (rec->type) {
|
|
|
|
case KEY:
|
|
|
|
key_update();
|
|
|
|
break;
|
|
|
|
case AXIS:
|
|
|
|
axis_update();
|
|
|
|
break;
|
|
|
|
case JOYSTICK:
|
|
|
|
joystick_update();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2024-03-25 05:34:59 +00:00
|
|
|
}
|
|
|
|
|
2024-03-26 20:11:58 +00:00
|
|
|
struct ctrl_bkt *get_code_bkt(Ctrl *ctrl, size_t i)
|
2024-03-25 05:34:59 +00:00
|
|
|
{
|
2024-03-26 20:11:58 +00:00
|
|
|
assert(i < ctrl->codes.capacity);
|
|
|
|
return &ctrl->codes.bkts[i];
|
|
|
|
}
|
2024-03-25 05:34:59 +00:00
|
|
|
|
2024-03-26 20:11:58 +00:00
|
|
|
struct ctrl_bkt *get_bind_bkt(Ctrl *ctrl, size_t i)
|
|
|
|
{
|
|
|
|
assert(i < ctrl->binds.capacity);
|
|
|
|
return &ctrl->binds.bkts[i];
|
|
|
|
}
|
|
|
|
|
2024-03-27 00:49:15 +00:00
|
|
|
struct code_bkt *find_code_or_set_empty(Ctrl *ctrl, u16 code, )
|
2024-03-26 20:11:58 +00:00
|
|
|
{
|
|
|
|
const size_t index = hash % ctrl->codes.capacity;
|
|
|
|
size_t i = index;
|
2024-03-25 05:34:59 +00:00
|
|
|
|
2024-03-26 20:11:58 +00:00
|
|
|
while (i != index - 1) {
|
|
|
|
struct code_bkt *bkt = get_code_bkt(ctrl, i);
|
2024-03-27 00:49:15 +00:00
|
|
|
if (bkt->hash == search)
|
|
|
|
return bkt;
|
2024-03-26 20:11:58 +00:00
|
|
|
if (bkt->hash == 0)
|
|
|
|
return bkt;
|
2024-03-25 05:34:59 +00:00
|
|
|
|
2024-03-26 20:11:58 +00:00
|
|
|
i = (i + 1) % ctrl->codes.capacity;
|
2024-03-25 05:34:59 +00:00
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2024-03-27 00:49:15 +00:00
|
|
|
struct ctrl_bkt *find_bind(Ctrl *ctrl, hashtype hash, hashtype search)
|
2024-03-25 05:34:59 +00:00
|
|
|
{
|
2024-03-26 20:11:58 +00:00
|
|
|
const size_t index = hash % ctrl->binds.capacity;
|
|
|
|
size_t i = index;
|
2024-03-25 05:34:59 +00:00
|
|
|
|
2024-03-26 20:11:58 +00:00
|
|
|
while (i != index - 1) {
|
|
|
|
struct bind_bkt *bkt = get_bind_bkt(ctrl, i);
|
|
|
|
if (bkt->hash == 0)
|
|
|
|
return bkt;
|
|
|
|
|
|
|
|
i = (i + 1) % ctrl->binds.capacity;
|
2024-03-25 05:34:59 +00:00
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CtrlMap(Ctrl *ctrl, u16f bind, u16f code, enum InputType type)
|
|
|
|
{
|
2024-03-26 20:11:58 +00:00
|
|
|
if (ctrl->binds.filled == ctrl->binds.capacity)
|
2024-03-25 05:34:59 +00:00
|
|
|
return false;
|
|
|
|
|
2024-03-27 00:49:15 +00:00
|
|
|
struct code_bkt *code_bkt = find_code_or_set_empty(ctrl, code, type);
|
|
|
|
assert(code_bkt != nullptr);
|
2024-03-26 20:11:58 +00:00
|
|
|
|
2024-03-25 05:34:59 +00:00
|
|
|
hashtype bind_hash = hash_ident(bind, type);
|
2024-03-27 00:49:15 +00:00
|
|
|
struct bind_bkt *bind_bkt = find_bind(ctrl, bind_hash, bind_hash);
|
2024-03-26 20:11:58 +00:00
|
|
|
bind_bkt->hash = bind_hash;
|
|
|
|
bind_bkt->bind = bind;
|
|
|
|
bind_bkt->axis = &code_bkt->axis;
|
2024-03-25 05:34:59 +00:00
|
|
|
|
2024-03-26 20:11:58 +00:00
|
|
|
ctrl->binds.filled += 1;
|
2024-03-25 05:34:59 +00:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct Axis *find_bind_axis(Ctrl *ctrl, u16f bind, enum InputType type)
|
|
|
|
{
|
|
|
|
hashtype bind_hash = hash_ident(bind, KEY);
|
|
|
|
struct ctrl_bkt *bind_bkt = find_bind(ctrl, bind_hash, bind_hash);
|
|
|
|
if (bind_bkt == nullptr)
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
return &get_bkt(ctrl, bind_bkt->index)->axis;
|
|
|
|
}
|
|
|
|
|
2024-03-26 20:11:58 +00:00
|
|
|
struct Axis *CtrlGet(Ctrl *ctrl, u16f code, u8f type)
|
2024-03-25 05:34:59 +00:00
|
|
|
{
|
2024-03-26 20:11:58 +00:00
|
|
|
= struct ctrl_bkt *code_bkt = find_code(ctrl, code, type);
|
2024-03-25 05:34:59 +00:00
|
|
|
if (code_bkt == nullptr)
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
return &code_bkt->axis;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CtrlUpdateKey(Ctrl *ctrl, struct InputRecord *record)
|
|
|
|
{
|
|
|
|
struct Axis *axis = find_bind_axis(ctrl, record->id, KEY);
|
|
|
|
if (axis == nullptr)
|
|
|
|
return false;
|
|
|
|
|
2024-03-26 20:11:58 +00:00
|
|
|
if (record->data.key.is_down) {
|
2024-03-25 05:34:59 +00:00
|
|
|
axis->last_pressed = record->timestamp;
|
|
|
|
} else {
|
|
|
|
axis->last_released = record->timestamp;
|
|
|
|
}
|
2024-03-26 20:11:58 +00:00
|
|
|
axis->data.axis.value = record->data.key.is_down;
|
2024-03-25 05:34:59 +00:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CtrlUpdateAxis(Ctrl *ctrl, struct InputRecord *record)
|
|
|
|
{
|
|
|
|
struct Axis *axis = find_bind_axis(ctrl, record->id, AXIS);
|
|
|
|
if (axis == nullptr)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
axis->data.axis.value = record->data.axis.value;
|
|
|
|
axis->last_pressed = record->timestamp;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CtrlUpdateJoystick(Ctrl *ctrl, struct InputRecord *record)
|
|
|
|
{
|
|
|
|
struct Axis *axis = find_bind_axis(ctrl, record->id, JOYSTICK);
|
|
|
|
if (axis == nullptr)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
axis->data.joystick.x = record->data.joystick.x;
|
|
|
|
axis->data.joystick.y = record->data.joystick.y;
|
|
|
|
axis->last_pressed = record->timestamp;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CtrlUpdateWindow(Ctrl *ctrl, struct InputRecord *record)
|
|
|
|
{
|
|
|
|
struct Axis *axis = find_bind_axis(ctrl, record->id, WINDOW);
|
|
|
|
if (axis == nullptr)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
axis->data.joystick.x = record->data.joystick.x;
|
|
|
|
axis->data.joystick.y = record->data.joystick.y;
|
|
|
|
axis->last_pressed = record->timestamp;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|