|
@@ -102,11 +102,16 @@
|
|
|
#include "EGL/egl.h" // Khronos EGL library - Native platform display device control functions
|
|
|
#include "EGL/eglext.h" // Khronos EGL library - Extensions
|
|
|
#include "GLES2/gl2.h" // Khronos OpenGL ES 2.0 library
|
|
|
+
|
|
|
+ // Old device inputs system
|
|
|
+ #define DEFAULT_KEYBOARD_DEV STDIN_FILENO // Standard input
|
|
|
+ #define DEFAULT_MOUSE_DEV "/dev/input/mouse0"
|
|
|
+ #define DEFAULT_GAMEPAD_DEV "/dev/input/js0"
|
|
|
|
|
|
- #define DEFAULT_KEYBOARD_DEV "/dev/input/event0" // Not used, keyboard inputs are read raw from stdin
|
|
|
- #define DEFAULT_MOUSE_DEV "/dev/input/event1"
|
|
|
- //#define DEFAULT_MOUSE_DEV "/dev/input/mouse0"
|
|
|
- #define DEFAULT_GAMEPAD_DEV "/dev/input/js0"
|
|
|
+ // New device input events (evdev) (must be detected)
|
|
|
+ //#define DEFAULT_KEYBOARD_DEV "/dev/input/eventN"
|
|
|
+ //#define DEFAULT_MOUSE_DEV "/dev/input/eventN"
|
|
|
+ //#define DEFAULT_GAMEPAD_DEV "/dev/input/eventN"
|
|
|
#endif
|
|
|
|
|
|
#if defined(PLATFORM_WEB)
|
|
@@ -142,16 +147,11 @@ static int currentButtonState[128] = { 1 }; // Required to check if button p
|
|
|
#elif defined(PLATFORM_RPI)
|
|
|
static EGL_DISPMANX_WINDOW_T nativeWindow; // Native window (graphic device)
|
|
|
|
|
|
-// Input variables (mouse/keyboard)
|
|
|
-static int mouseStream = -1; // Mouse device file descriptor
|
|
|
-static bool mouseReady = false; // Flag to know if mouse is ready
|
|
|
-pthread_t mouseThreadId; // Mouse reading thread id
|
|
|
-
|
|
|
+// Keyboard input variables
|
|
|
// NOTE: For keyboard we will use the standard input (but reconfigured...)
|
|
|
+static struct termios defaultKeyboardSettings; // Used to store default keyboard settings
|
|
|
static int defaultKeyboardMode; // Used to store default keyboard mode
|
|
|
-static struct termios defaultKeyboardSettings; // Used to staore default keyboard settings
|
|
|
-
|
|
|
-static int keyboardMode = 0; // Keyboard mode: 1 - KEYCODES, 2 - ASCII
|
|
|
+static int keyboardMode = 0; // Register Keyboard mode: 1 - KEYCODES, 2 - ASCII
|
|
|
|
|
|
// This array maps Unix keycodes to ASCII equivalent and to GLFW3 equivalent for special function keys (>256)
|
|
|
const short UnixKeycodeToASCII[128] = { 256, 49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 45, 61, 259, 9, 81, 87, 69, 82, 84, 89, 85, 73, 79, 80, 91, 93, 257, 341, 65, 83, 68,
|
|
@@ -159,7 +159,15 @@ const short UnixKeycodeToASCII[128] = { 256, 49, 50, 51, 52, 53, 54, 55, 56, 57,
|
|
|
297, 298, 299, -1, -1, -1, -1, -1, 45, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 257, 345, 47, -1,
|
|
|
346, -1, -1, 265, -1, 263, 262, -1, 264, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 };
|
|
|
|
|
|
+// Mouse input variables
|
|
|
+static int mouseStream = -1; // Mouse device file descriptor
|
|
|
+static bool mouseReady = false; // Flag to know if mouse is ready
|
|
|
+pthread_t mouseThreadId; // Mouse reading thread id
|
|
|
+
|
|
|
+// Gamepad input variables
|
|
|
static int gamepadStream = -1; // Gamepad device file descriptor
|
|
|
+static bool gamepadReady = false; // Flag to know if gamepad is ready
|
|
|
+pthread_t gamepadThreadId; // Gamepad reading thread id
|
|
|
#endif
|
|
|
|
|
|
#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI)
|
|
@@ -244,11 +252,13 @@ static void LogoAnimation(void); // Plays raylib logo app
|
|
|
static void SetupFramebufferSize(int displayWidth, int displayHeight);
|
|
|
|
|
|
#if defined(PLATFORM_RPI)
|
|
|
-static void InitMouse(void); // Mouse initialization (including mouse thread)
|
|
|
-static void *MouseThread(void *arg); // Mouse reading thread
|
|
|
static void InitKeyboard(void); // Init raw keyboard system (standard input reading)
|
|
|
+static void ProcessKeyboard(void); // Process keyboard events
|
|
|
static void RestoreKeyboard(void); // Restore keyboard system
|
|
|
+static void InitMouse(void); // Mouse initialization (including mouse thread)
|
|
|
+static void *MouseThread(void *arg); // Mouse reading thread
|
|
|
static void InitGamepad(void); // Init raw gamepad input
|
|
|
+static void *GamepadThread(void *arg); // Mouse reading thread
|
|
|
#endif
|
|
|
|
|
|
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
|
|
@@ -1128,18 +1138,21 @@ bool IsCursorHidden()
|
|
|
{
|
|
|
return cursorHidden;
|
|
|
}
|
|
|
-#endif //defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB)
|
|
|
|
|
|
-// TODO: Enable gamepad usage on Rapsberry Pi
|
|
|
-// NOTE: emscripten not implemented
|
|
|
-#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
|
|
|
+// NOTE: Gamepad support not implemented in emscripten GLFW3 (PLATFORM_WEB)
|
|
|
+
|
|
|
// Detect if a gamepad is available
|
|
|
bool IsGamepadAvailable(int gamepad)
|
|
|
{
|
|
|
- int result = glfwJoystickPresent(gamepad);
|
|
|
+ bool result = false;
|
|
|
+
|
|
|
+#if defined(PLATFORM_RPI)
|
|
|
+ if (gamepadReady && (gamepad == 0)) result = true;
|
|
|
+#else
|
|
|
+ if (glfwJoystickPresent(gamepad) == 1) result = true;
|
|
|
+#endif
|
|
|
|
|
|
- if (result == 1) return true;
|
|
|
- else return false;
|
|
|
+ return result;
|
|
|
}
|
|
|
|
|
|
// Return axis movement vector for a gamepad
|
|
@@ -1148,10 +1161,14 @@ Vector2 GetGamepadMovement(int gamepad)
|
|
|
Vector2 vec = { 0, 0 };
|
|
|
|
|
|
const float *axes;
|
|
|
- int axisCount;
|
|
|
-
|
|
|
+ int axisCount = 0;
|
|
|
+
|
|
|
+#if defined(PLATFORM_RPI)
|
|
|
+ // TODO: Get gamepad axis information
|
|
|
+#else
|
|
|
axes = glfwGetJoystickAxes(gamepad, &axisCount);
|
|
|
-
|
|
|
+#endif
|
|
|
+
|
|
|
if (axisCount >= 2)
|
|
|
{
|
|
|
vec.x = axes[0]; // Left joystick X
|
|
@@ -1184,16 +1201,20 @@ bool IsGamepadButtonPressed(int gamepad, int button)
|
|
|
// Detect if a gamepad button is being pressed
|
|
|
bool IsGamepadButtonDown(int gamepad, int button)
|
|
|
{
|
|
|
+ bool result = false;
|
|
|
const unsigned char *buttons;
|
|
|
int buttonsCount;
|
|
|
-
|
|
|
+
|
|
|
+#if defined(PLATFORM_RPI)
|
|
|
+ // TODO: Get gamepad buttons information
|
|
|
+#else
|
|
|
buttons = glfwGetJoystickButtons(gamepad, &buttonsCount);
|
|
|
|
|
|
- if ((buttons != NULL) && (buttons[button] == GLFW_PRESS))
|
|
|
- {
|
|
|
- return true;
|
|
|
- }
|
|
|
- else return false;
|
|
|
+ if ((buttons != NULL) && (buttons[button] == GLFW_PRESS)) result = true;
|
|
|
+ else result = false;
|
|
|
+#endif
|
|
|
+
|
|
|
+ return result;
|
|
|
}
|
|
|
|
|
|
// Detect if a gamepad button has NOT been pressed once
|
|
@@ -1216,19 +1237,23 @@ bool IsGamepadButtonReleased(int gamepad, int button)
|
|
|
// Detect if a mouse button is NOT being pressed
|
|
|
bool IsGamepadButtonUp(int gamepad, int button)
|
|
|
{
|
|
|
+ bool result = false;
|
|
|
const unsigned char *buttons;
|
|
|
int buttonsCount;
|
|
|
|
|
|
+#if defined(PLATFORM_RPI)
|
|
|
+ // TODO: Get gamepad buttons information
|
|
|
+#else
|
|
|
buttons = glfwGetJoystickButtons(gamepad, &buttonsCount);
|
|
|
|
|
|
- if ((buttons != NULL) && (buttons[button] == GLFW_RELEASE))
|
|
|
- {
|
|
|
- return true;
|
|
|
- }
|
|
|
- else return false;
|
|
|
-}
|
|
|
+ if ((buttons != NULL) && (buttons[button] == GLFW_RELEASE)) result = true;
|
|
|
+ else result = false;
|
|
|
#endif
|
|
|
|
|
|
+ return result;
|
|
|
+}
|
|
|
+#endif //defined(PLATFORM_DESKTOP) || defined(PLATFORM_RPI) || defined(PLATFORM_WEB)
|
|
|
+
|
|
|
// Returns touch position X
|
|
|
int GetTouchX(void)
|
|
|
{
|
|
@@ -2157,7 +2182,68 @@ static void PollInputEvents(void)
|
|
|
|
|
|
// NOTE: Keyboard reading could be done using input_event(s) reading or just read from stdin,
|
|
|
// we use method 2 (stdin) but maybe in a future we should change to method 1...
|
|
|
+ ProcessKeyboard();
|
|
|
+
|
|
|
+ // NOTE: Gamepad (Joystick) input events polling is done asynchonously in another pthread - GamepadThread()
|
|
|
+
|
|
|
+#endif
|
|
|
+}
|
|
|
|
|
|
+#if defined(PLATFORM_RPI)
|
|
|
+// Initialize Keyboard system (using standard input)
|
|
|
+static void InitKeyboard(void)
|
|
|
+{
|
|
|
+ // NOTE: We read directly from Standard Input (stdin) - STDIN_FILENO file descriptor
|
|
|
+
|
|
|
+ // Make stdin non-blocking (not enough, need to configure to non-canonical mode)
|
|
|
+ int flags = fcntl(STDIN_FILENO, F_GETFL, 0); // F_GETFL: Get the file access mode and the file status flags
|
|
|
+ fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK); // F_SETFL: Set the file status flags to the value specified
|
|
|
+
|
|
|
+ // Save terminal keyboard settings and reconfigure terminal with new settings
|
|
|
+ struct termios keyboardNewSettings;
|
|
|
+ tcgetattr(STDIN_FILENO, &defaultKeyboardSettings); // Get current keyboard settings
|
|
|
+ keyboardNewSettings = defaultKeyboardSettings;
|
|
|
+
|
|
|
+ // New terminal settings for keyboard: turn off buffering (non-canonical mode), echo and key processing
|
|
|
+ // NOTE: ISIG controls if ^C and ^Z generate break signals or not
|
|
|
+ keyboardNewSettings.c_lflag &= ~(ICANON | ECHO | ISIG);
|
|
|
+ //keyboardNewSettings.c_iflag &= ~(ISTRIP | INLCR | ICRNL | IGNCR | IXON | IXOFF);
|
|
|
+ keyboardNewSettings.c_cc[VMIN] = 1;
|
|
|
+ keyboardNewSettings.c_cc[VTIME] = 0;
|
|
|
+
|
|
|
+ // Set new keyboard settings (change occurs immediately)
|
|
|
+ tcsetattr(STDIN_FILENO, TCSANOW, &keyboardNewSettings);
|
|
|
+
|
|
|
+ // NOTE: Reading directly from stdin will give chars already key-mapped by kernel to ASCII or UNICODE, we change that! -> WHY???
|
|
|
+
|
|
|
+ // Save old keyboard mode to restore it at the end
|
|
|
+ if (ioctl(STDIN_FILENO, KDGKBMODE, &defaultKeyboardMode) < 0)
|
|
|
+ {
|
|
|
+ // NOTE: It could mean we are using a remote keyboard through ssh!
|
|
|
+ TraceLog(WARNING, "Could not change keyboard mode (SSH keyboard?)");
|
|
|
+
|
|
|
+ keyboardMode = 2; // ASCII
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ // We reconfigure keyboard mode to get:
|
|
|
+ // - scancodes (K_RAW)
|
|
|
+ // - keycodes (K_MEDIUMRAW)
|
|
|
+ // - ASCII chars (K_XLATE)
|
|
|
+ // - UNICODE chars (K_UNICODE)
|
|
|
+ ioctl(STDIN_FILENO, KDSKBMODE, K_XLATE);
|
|
|
+
|
|
|
+ //http://lct.sourceforge.net/lct/x60.html
|
|
|
+
|
|
|
+ keyboardMode = 2; // keycodes
|
|
|
+ }
|
|
|
+
|
|
|
+ // Register keyboard restore when program finishes
|
|
|
+ atexit(RestoreKeyboard);
|
|
|
+}
|
|
|
+
|
|
|
+static void ProcessKeyboard(void)
|
|
|
+{
|
|
|
// Keyboard input polling (fill keys[256] array with status)
|
|
|
int numKeysBuffer = 0; // Keys available on buffer
|
|
|
char keysBuffer[32]; // Max keys to be read at a time
|
|
@@ -2242,45 +2328,18 @@ static void PollInputEvents(void)
|
|
|
}
|
|
|
*/
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
- // TODO: Gamepad support (use events, easy!)
|
|
|
-/*
|
|
|
- struct js_event gamepadEvent;
|
|
|
-
|
|
|
- read(gamepadStream, &gamepadEvent, sizeof(struct js_event));
|
|
|
-
|
|
|
- if (gamepadEvent.type == JS_EVENT_BUTTON)
|
|
|
- {
|
|
|
- switch (gamepadEvent.number)
|
|
|
- {
|
|
|
- case 0: // 1st Axis X
|
|
|
- case 1: // 1st Axis Y
|
|
|
- case 2: // 2st Axis X
|
|
|
- case 3: // 2st Axis Y
|
|
|
- case 4:
|
|
|
- {
|
|
|
- if (gamepadEvent.value == 1) // Button pressed, 0 release
|
|
|
-
|
|
|
- } break;
|
|
|
- // Buttons is similar, variable for every joystick
|
|
|
- }
|
|
|
- }
|
|
|
- else if (gamepadEvent.type == JS_EVENT_AXIS)
|
|
|
- {
|
|
|
- switch (gamepadEvent.number)
|
|
|
- {
|
|
|
- case 0: // 1st Axis X
|
|
|
- case 1: // 1st Axis Y
|
|
|
- case 2: // 2st Axis X
|
|
|
- case 3: // 2st Axis Y
|
|
|
- // Buttons is similar, variable for every joystick
|
|
|
- }
|
|
|
- }
|
|
|
-*/
|
|
|
-#endif
|
|
|
+// Restore default keyboard input
|
|
|
+static void RestoreKeyboard(void)
|
|
|
+{
|
|
|
+ // Reset to default keyboard settings
|
|
|
+ tcsetattr(STDIN_FILENO, TCSANOW, &defaultKeyboardSettings);
|
|
|
+
|
|
|
+ // Reconfigure keyboard to default mode
|
|
|
+ ioctl(STDIN_FILENO, KDSKBMODE, defaultKeyboardMode);
|
|
|
}
|
|
|
|
|
|
-#if defined(PLATFORM_RPI)
|
|
|
// Mouse initialization (including mouse thread)
|
|
|
static void InitMouse(void)
|
|
|
{
|
|
@@ -2305,118 +2364,156 @@ static void InitMouse(void)
|
|
|
// if too much time passes between reads, queue gets full and new events override older ones...
|
|
|
static void *MouseThread(void *arg)
|
|
|
{
|
|
|
- struct input_event mouseEvent;
|
|
|
+ const unsigned char XSIGN = 1<<4, YSIGN = 1<<5;
|
|
|
+
|
|
|
+ typedef struct {
|
|
|
+ char buttons;
|
|
|
+ char dx, dy;
|
|
|
+ } MouseEvent;
|
|
|
+
|
|
|
+ MouseEvent mouse;
|
|
|
+
|
|
|
+ int mouseRelX = 0;
|
|
|
+ int mouseRelY = 0;
|
|
|
|
|
|
while(1)
|
|
|
{
|
|
|
- // NOTE: read() will return -1 if the events queue is empty
|
|
|
- read(mouseStream, &mouseEvent, sizeof(struct input_event));
|
|
|
-
|
|
|
- // Check event types
|
|
|
- if (mouseEvent.type == EV_REL) // Relative motion event
|
|
|
+ if (read(mouseStream, &mouse, sizeof(MouseEvent)) == (int)sizeof(MouseEvent))
|
|
|
{
|
|
|
- if (mouseEvent.code == REL_X)
|
|
|
- {
|
|
|
- mousePosition.x += (float)mouseEvent.value;
|
|
|
-
|
|
|
- // Screen limits X check
|
|
|
- if (mousePosition.x < 0) mousePosition.x = 0;
|
|
|
- if (mousePosition.x > screenWidth) mousePosition.x = screenWidth;
|
|
|
- }
|
|
|
-
|
|
|
- if (mouseEvent.code == REL_Y)
|
|
|
- {
|
|
|
- mousePosition.y += (float)mouseEvent.value;
|
|
|
-
|
|
|
- // Screen limits Y check
|
|
|
- if (mousePosition.y < 0) mousePosition.y = 0;
|
|
|
- if (mousePosition.y > screenHeight) mousePosition.y = screenHeight;
|
|
|
- }
|
|
|
+ if ((mouse.buttons & 0x08) == 0) break; // This bit should always be set
|
|
|
+
|
|
|
+ // Check Left button pressed
|
|
|
+ if ((mouse.buttons & 0x01) > 0) currentMouseState[0] = 1;
|
|
|
+ else currentMouseState[0] = 0;
|
|
|
|
|
|
- if (mouseEvent.code == REL_WHEEL)
|
|
|
- {
|
|
|
- // mouseEvent.value give 1 or -1 (direction)
|
|
|
- }
|
|
|
- }
|
|
|
- else if (mouseEvent.type == EV_KEY) // Mouse button event
|
|
|
- {
|
|
|
- if (mouseEvent.code == BTN_LEFT) currentMouseState[0] = mouseEvent.value;
|
|
|
- if (mouseEvent.code == BTN_RIGHT) currentMouseState[1] = mouseEvent.value;
|
|
|
- if (mouseEvent.code == BTN_MIDDLE) currentMouseState[2] = mouseEvent.value;
|
|
|
- }
|
|
|
+ // Check Right button pressed
|
|
|
+ if ((mouse.buttons & 0x02) > 0) currentMouseState[1] = 1;
|
|
|
+ else currentMouseState[1] = 0;
|
|
|
+
|
|
|
+ // Check Middle button pressed
|
|
|
+ if ((mouse.buttons & 0x04) > 0) currentMouseState[2] = 1;
|
|
|
+ else currentMouseState[2] = 0;
|
|
|
+
|
|
|
+ mouseRelX = (int)mouse.dx;
|
|
|
+ mouseRelY = (int)mouse.dy;
|
|
|
+
|
|
|
+ if ((mouse.buttons & XSIGN) > 0) mouseRelX = -1*(255 - mouseRelX);
|
|
|
+ if ((mouse.buttons & YSIGN) > 0) mouseRelY = -1*(255 - mouseRelY);
|
|
|
+
|
|
|
+ mousePosition.x += (float)mouseRelX;
|
|
|
+ mousePosition.y -= (float)mouseRelY;
|
|
|
+
|
|
|
+ if (mousePosition.x < 0) mousePosition.x = 0;
|
|
|
+ if (mousePosition.y < 0) mousePosition.y = 0;
|
|
|
+
|
|
|
+ if (mousePosition.x > screenWidth) mousePosition.x = screenWidth;
|
|
|
+ if (mousePosition.y > screenHeight) mousePosition.y = screenHeight;
|
|
|
+ }
|
|
|
+ //else read(mouseStream, &mouse, 1); // Try to sync up again
|
|
|
}
|
|
|
|
|
|
return NULL;
|
|
|
}
|
|
|
|
|
|
-// Initialize Keyboard system (using standard input)
|
|
|
-static void InitKeyboard(void)
|
|
|
+// Init gamepad system
|
|
|
+static void InitGamepad(void)
|
|
|
{
|
|
|
- // NOTE: We read directly from Standard Input (stdin) - STDIN_FILENO file descriptor
|
|
|
-
|
|
|
- // Make stdin non-blocking (not enough, need to configure to non-canonical mode)
|
|
|
- int flags = fcntl(STDIN_FILENO, F_GETFL, 0); // F_GETFL: Get the file access mode and the file status flags
|
|
|
- fcntl(STDIN_FILENO, F_SETFL, flags | O_NONBLOCK); // F_SETFL: Set the file status flags to the value specified
|
|
|
-
|
|
|
- // Save terminal keyboard settings and reconfigure terminal with new settings
|
|
|
- struct termios keyboardNewSettings;
|
|
|
- tcgetattr(STDIN_FILENO, &defaultKeyboardSettings); // Get current keyboard settings
|
|
|
- keyboardNewSettings = defaultKeyboardSettings;
|
|
|
-
|
|
|
- // New terminal settings for keyboard: turn off buffering (non-canonical mode), echo and key processing
|
|
|
- // NOTE: ISIG controls if ^C and ^Z generate break signals or not
|
|
|
- keyboardNewSettings.c_lflag &= ~(ICANON | ECHO | ISIG);
|
|
|
- //keyboardNewSettings.c_iflag &= ~(ISTRIP | INLCR | ICRNL | IGNCR | IXON | IXOFF);
|
|
|
- keyboardNewSettings.c_cc[VMIN] = 1;
|
|
|
- keyboardNewSettings.c_cc[VTIME] = 0;
|
|
|
-
|
|
|
- // Set new keyboard settings (change occurs immediately)
|
|
|
- tcsetattr(STDIN_FILENO, TCSANOW, &keyboardNewSettings);
|
|
|
-
|
|
|
- // NOTE: Reading directly from stdin will give chars already key-mapped by kernel to ASCII or UNICODE, we change that! -> WHY???
|
|
|
-
|
|
|
- // Save old keyboard mode to restore it at the end
|
|
|
- if (ioctl(STDIN_FILENO, KDGKBMODE, &defaultKeyboardMode) < 0)
|
|
|
+ if ((gamepadStream = open(DEFAULT_GAMEPAD_DEV, O_RDONLY|O_NONBLOCK)) < 0)
|
|
|
{
|
|
|
- // NOTE: It could mean we are using a remote keyboard through ssh!
|
|
|
- TraceLog(WARNING, "Could not change keyboard mode (SSH keyboard?)");
|
|
|
-
|
|
|
- keyboardMode = 2; // ASCII
|
|
|
+ TraceLog(WARNING, "Gamepad device could not be opened, no gamepad available");
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- // We reconfigure keyboard mode to get:
|
|
|
- // - scancodes (K_RAW)
|
|
|
- // - keycodes (K_MEDIUMRAW)
|
|
|
- // - ASCII chars (K_XLATE)
|
|
|
- // - UNICODE chars (K_UNICODE)
|
|
|
- ioctl(STDIN_FILENO, KDSKBMODE, K_MEDIUMRAW);
|
|
|
-
|
|
|
- //http://lct.sourceforge.net/lct/x60.html
|
|
|
+ gamepadReady = true;
|
|
|
|
|
|
- keyboardMode = 1; // keycodes
|
|
|
- }
|
|
|
+ int error = pthread_create(&gamepadThreadId, NULL, &GamepadThread, NULL);
|
|
|
|
|
|
- // Register keyboard restore when program finishes
|
|
|
- atexit(RestoreKeyboard);
|
|
|
+ if (error != 0) TraceLog(WARNING, "Error creating gamepad input event thread");
|
|
|
+ else TraceLog(INFO, "Gamepad device initialized successfully");
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
-// Restore default keyboard input
|
|
|
-static void RestoreKeyboard(void)
|
|
|
+// Process Gamepad (/dev/input/js0)
|
|
|
+static void *GamepadThread(void *arg)
|
|
|
{
|
|
|
- // Reset to default keyboard settings
|
|
|
- tcsetattr(STDIN_FILENO, TCSANOW, &defaultKeyboardSettings);
|
|
|
+ #define JS_EVENT_BUTTON 0x01 // Button pressed/released
|
|
|
+ #define JS_EVENT_AXIS 0x02 // Joystick axis moved
|
|
|
+ #define JS_EVENT_INIT 0x80 // Initial state of device
|
|
|
+
|
|
|
+ struct js_event {
|
|
|
+ unsigned int time; // event timestamp in milliseconds
|
|
|
+ short value; // event value
|
|
|
+ unsigned char type; // event type
|
|
|
+ unsigned char number; // event axis/button number
|
|
|
+ };
|
|
|
+
|
|
|
+ // These values are sensible on Logitech Dual Action Rumble and Xbox360 controller
|
|
|
+ const int joystickAxisX = 0;
|
|
|
+ const int joystickAxisY = 1;
|
|
|
+
|
|
|
+ // Read gamepad event
|
|
|
+ struct js_event gamepadEvent;
|
|
|
+ int bytes;
|
|
|
|
|
|
- // Reconfigure keyboard to default mode
|
|
|
- ioctl(STDIN_FILENO, KDSKBMODE, defaultKeyboardMode);
|
|
|
-}
|
|
|
+ int buttons[11];
|
|
|
+ int stickX;
|
|
|
+ int stickY;
|
|
|
+
|
|
|
+ while (1)
|
|
|
+ {
|
|
|
+ if (read(gamepadStream, &gamepadEvent, sizeof(struct js_event)) == (int)sizeof(struct js_event))
|
|
|
+ {
|
|
|
+ gamepadEvent.type &= ~JS_EVENT_INIT; // Ignore synthetic events
|
|
|
+
|
|
|
+ // Process gamepad events by type
|
|
|
+ if (gamepadEvent.type == JS_EVENT_BUTTON)
|
|
|
+ {
|
|
|
+ if (gamepadEvent.number < 11)
|
|
|
+ {
|
|
|
+ switch (gamepadEvent.value)
|
|
|
+ {
|
|
|
+ case 0:
|
|
|
+ case 1: buttons[gamepadEvent.number] = gamepadEvent.value; break;
|
|
|
+ default: break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ /*
|
|
|
+ switch (gamepadEvent.number)
|
|
|
+ {
|
|
|
+ case 0: // 1st Axis X
|
|
|
+ case 1: // 1st Axis Y
|
|
|
+ case 2: // 2st Axis X
|
|
|
+ case 3: // 2st Axis Y
|
|
|
+ case 4:
|
|
|
+ {
|
|
|
+ if (gamepadEvent.value == 1) // Button pressed, 0 release
|
|
|
+ {
|
|
|
+
|
|
|
+ }
|
|
|
|
|
|
-// Init gamepad system
|
|
|
-static void InitGamepad(void)
|
|
|
-{
|
|
|
- // TODO: Add Gamepad support
|
|
|
- if ((gamepadStream = open(DEFAULT_GAMEPAD_DEV, O_RDONLY|O_NONBLOCK)) < 0) TraceLog(WARNING, "Gamepad device could not be opened, no gamepad available");
|
|
|
- else TraceLog(INFO, "Gamepad device initialized successfully");
|
|
|
+ } break;
|
|
|
+ // Buttons is similar, variable for every joystick
|
|
|
+ }
|
|
|
+ */
|
|
|
+ }
|
|
|
+ else if (gamepadEvent.type == JS_EVENT_AXIS)
|
|
|
+ {
|
|
|
+ if (gamepadEvent.number == joystickAxisX) stickX = gamepadEvent.value;
|
|
|
+ if (gamepadEvent.number == joystickAxisY) stickY = gamepadEvent.value;
|
|
|
+ /*
|
|
|
+ switch (gamepadEvent.number)
|
|
|
+ {
|
|
|
+ case 0: // 1st Axis X
|
|
|
+ case 1: // 1st Axis Y
|
|
|
+ case 2: // 2st Axis X
|
|
|
+ case 3: // 2st Axis Y
|
|
|
+ // Buttons is similar, variable for every joystick
|
|
|
+ }
|
|
|
+ */
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else read(gamepadStream, &gamepadEvent, 1); // Try to sync up again
|
|
|
+ }
|
|
|
}
|
|
|
#endif
|
|
|
|