From b5fde246ee4941a732abcaf74338bd41bf16bb3a Mon Sep 17 00:00:00 2001 From: XProger Date: Sun, 4 Mar 2018 23:28:42 +0300 Subject: [PATCH] #15 Linux gamepads support --- src/libs/minimp3/minimp3.cpp | 6 +- src/platform/nix/main.cpp | 112 ++++++++++++++++++++++++++++++++++- 2 files changed, 114 insertions(+), 4 deletions(-) diff --git a/src/libs/minimp3/minimp3.cpp b/src/libs/minimp3/minimp3.cpp index cae9609..e537cde 100644 --- a/src/libs/minimp3/minimp3.cpp +++ b/src/libs/minimp3/minimp3.cpp @@ -875,7 +875,7 @@ static void init_get_bits(bitstream_t *s, const uint8_t *buffer, int bit_size) { } static INLINE unsigned int get_bits(bitstream_t *s, int n){ - register int tmp; + int tmp; OPEN_READER(re, s) UPDATE_CACHE(re, s) tmp= SHOW_UBITS(re, s, n); @@ -2000,8 +2000,8 @@ static void mp3_synth_filter( int32_t sb_samples[SBLIMIT] ) { int32_t tmp[32]; - register int16_t *synth_buf; - register const int16_t *w, *w2, *p; + int16_t *synth_buf; + const int16_t *w, *w2, *p; int j, offset, v; int16_t *samples2; int sum, sum2; diff --git a/src/platform/nix/main.cpp b/src/platform/nix/main.cpp index 1867f6d..afe61d3 100644 --- a/src/platform/nix/main.cpp +++ b/src/platform/nix/main.cpp @@ -1,6 +1,8 @@ #include #include #include +#include +#include #include #include #include @@ -193,14 +195,119 @@ InputKey mouseToInputKey(int btn) { return ikNone; } +struct JoyDevice { + int fd; + vec2 L, R; +} joyDevice[INPUT_JOY_COUNT]; + bool osJoyReady(int index) { - return false; + return joyDevice[index].fd != -1; } void osJoyVibrate(int index, float L, float R) { // TODO } +void joyInit() { + LOG("init gamepads:\n"); + char name[128]; + for (int i = 0; i < INPUT_JOY_COUNT; i++) { + JoyDevice &joy = joyDevice[i]; + // open device + sprintf(name, "/dev/input/js%d", i); + joy.fd = open(name, O_RDONLY | O_NONBLOCK); + if (joy.fd == -1) + continue; + // skip init messages + js_event event; + while (read(joy.fd, &event, sizeof(event)) != -1 && (event.type & JS_EVENT_INIT)); + // get gamepad info + int8 axes, buttons; + ioctl(joy.fd, JSIOCGAXES, &axes); + ioctl(joy.fd, JSIOCGBUTTONS, &buttons); + + if (axes < 4 || buttons < 11) { // is it really a gamepad? + close(joy.fd); + joy.fd = -1; + continue; + } + + if (ioctl(joy.fd, JSIOCGNAME(sizeof(name)), name) < 0) + strcpy(name, "Unknown"); + + LOG("gamepad %d\n", i); + LOG(" name : %s\n", name); + LOG(" btns : %d\n", int(buttons)); + LOG(" axes : %d\n", int(axes)); + } +} + +#define JOY_DEAD_ZONE_STICK 8192 +#define JOY_DEAD_ZONE_TRIGGER 8192 + +float joyAxisValue(int value) { + if (value > -JOY_DEAD_ZONE_STICK && value < JOY_DEAD_ZONE_STICK) + return 0.0f; + return value / 32767.0f; +} + +float joyTrigger(int value) { + if (value + 32767 < JOY_DEAD_ZONE_TRIGGER) + return 0.0f; + return min(1.0f, (value + 32767) / 65536.0f); +} + +vec2 joyDir(const vec2 &value) { + float dist = min(1.0f, value.length()); + return value.normal() * dist; +} + +void joyUpdate() { + static const JoyKey keys[] = { jkA, jkB, jkX, jkY, jkLB, jkRB, jkSelect, jkStart, jkNone /*jkHome*/, jkL, jkR }; + + for (int i = 0; i < INPUT_JOY_COUNT; i++) { + JoyDevice &joy = joyDevice[i]; + + if (joy.fd == -1) + continue; + + js_event event; + while (read(joy.fd, &event, sizeof(event)) != -1) { + // buttons + if (event.type & JS_EVENT_BUTTON) + Input::setJoyDown(i, event.number >= COUNT(keys) ? jkNone : keys[event.number], event.value == 1); + // axes + if (event.type & JS_EVENT_AXIS) { + + switch (event.number) { + // Left stick + case 0 : joy.L.x = joyAxisValue(event.value); break; + case 1 : joy.L.y = joyAxisValue(event.value); break; + // Right stick + case 3 : joy.R.x = joyAxisValue(event.value); break; + case 4 : joy.R.y = joyAxisValue(event.value); break; + // Left trigger + case 2 : Input::setJoyPos(i, jkLT, joyTrigger(event.value)); break; + // Right trigger + case 5 : Input::setJoyPos(i, jkRT, joyTrigger(event.value)); break; + // D-PAD + case 6 : + Input::setJoyDown(i, jkLeft, event.value < -0x4000); + Input::setJoyDown(i, jkRight, event.value > 0x4000); + break; + case 7 : + Input::setJoyDown(i, jkUp, event.value < -0x4000); + Input::setJoyDown(i, jkDown, event.value > 0x4000); + break; + } + + Input::setJoyPos(i, jkL, joyDir(joy.L)); + Input::setJoyPos(i, jkR, joyDir(joy.R)); + } + } + } +} + void toggle_fullscreen(Display* dpy, Window win) { const size_t _NET_WM_STATE_TOGGLE=2; @@ -296,6 +403,8 @@ int main(int argc, char **argv) { Atom WM_DELETE_WINDOW = XInternAtom(dpy, "WM_DELETE_WINDOW", 0); XSetWMProtocols(dpy, wnd, &WM_DELETE_WINDOW, 1); + joyInit(); + timeval t; gettimeofday(&t, NULL); startTime = t.tv_sec; @@ -311,6 +420,7 @@ int main(int argc, char **argv) { Core::quit(); WndProc(event,dpy,wnd); } else { + joyUpdate(); bool updated = Game::update(); if (updated) { Game::render();