|
@@ -57,6 +57,12 @@
|
|
#include <sys/ioctl.h> // Required for: ioctl() - UNIX System call for device-specific input/output operations
|
|
#include <sys/ioctl.h> // Required for: ioctl() - UNIX System call for device-specific input/output operations
|
|
#include <linux/kd.h> // Linux: KDSKBMODE, K_MEDIUMRAM constants definition
|
|
#include <linux/kd.h> // Linux: KDSKBMODE, K_MEDIUMRAM constants definition
|
|
#include <linux/input.h> // Linux: Keycodes constants definition (KEY_A, ...)
|
|
#include <linux/input.h> // Linux: Keycodes constants definition (KEY_A, ...)
|
|
|
|
+
|
|
|
|
+// So both `linux/input.h` and `raylib.h` define KEY_F12
|
|
|
|
+// To avoid conflict with the capturing code in rcore.c we undefine the macro KEY_F12,
|
|
|
|
+// so the enum KEY_F12 from raylib is used
|
|
|
|
+#undef KEY_F12
|
|
|
|
+
|
|
#include <linux/joystick.h> // Linux: Joystick support library
|
|
#include <linux/joystick.h> // Linux: Joystick support library
|
|
|
|
|
|
#include <gbm.h> // Generic Buffer Management (native platform for EGL on DRM)
|
|
#include <gbm.h> // Generic Buffer Management (native platform for EGL on DRM)
|
|
@@ -71,27 +77,12 @@
|
|
//----------------------------------------------------------------------------------
|
|
//----------------------------------------------------------------------------------
|
|
#define USE_LAST_TOUCH_DEVICE // When multiple touchscreens are connected, only use the one with the highest event<N> number
|
|
#define USE_LAST_TOUCH_DEVICE // When multiple touchscreens are connected, only use the one with the highest event<N> number
|
|
|
|
|
|
-#define DEFAULT_GAMEPAD_DEV "/dev/input/js" // Gamepad input (base dev for all gamepads: js0, js1, ...)
|
|
|
|
#define DEFAULT_EVDEV_PATH "/dev/input/" // Path to the linux input events
|
|
#define DEFAULT_EVDEV_PATH "/dev/input/" // Path to the linux input events
|
|
|
|
|
|
//----------------------------------------------------------------------------------
|
|
//----------------------------------------------------------------------------------
|
|
// Types and Structures Definition
|
|
// Types and Structures Definition
|
|
//----------------------------------------------------------------------------------
|
|
//----------------------------------------------------------------------------------
|
|
|
|
|
|
-typedef struct {
|
|
|
|
- pthread_t threadId; // Event reading thread id
|
|
|
|
-
|
|
|
|
- int fd; // File descriptor to the device it is assigned to
|
|
|
|
- int eventNum; // Number of 'event<N>' device
|
|
|
|
- Rectangle absRange; // Range of values for absolute pointing devices (touchscreens)
|
|
|
|
- int touchSlot; // Hold the touch slot number of the currently being sent multitouch block
|
|
|
|
- bool isMouse; // True if device supports relative X Y movements
|
|
|
|
- bool isTouch; // True if device supports absolute X Y movements and has BTN_TOUCH
|
|
|
|
- bool isMultitouch; // True if device supports multiple absolute movevents and has BTN_TOUCH
|
|
|
|
- bool isKeyboard; // True if device has letter keycodes
|
|
|
|
- bool isGamepad; // True if device has gamepad buttons
|
|
|
|
-} InputEventWorker;
|
|
|
|
-
|
|
|
|
typedef struct {
|
|
typedef struct {
|
|
// Display data
|
|
// Display data
|
|
int fd; // File descriptor for /dev/dri/...
|
|
int fd; // File descriptor for /dev/dri/...
|
|
@@ -108,9 +99,6 @@ typedef struct {
|
|
EGLContext context; // Graphic context, mode in which drawing can be done
|
|
EGLContext context; // Graphic context, mode in which drawing can be done
|
|
EGLConfig config; // Graphic config
|
|
EGLConfig config; // Graphic config
|
|
|
|
|
|
- // Input data
|
|
|
|
- InputEventWorker eventWorker[10]; // List of worker threads for every monitored "/dev/input/event<N>"
|
|
|
|
-
|
|
|
|
// Keyboard data
|
|
// Keyboard data
|
|
int defaultKeyboardMode; // Default keyboard mode
|
|
int defaultKeyboardMode; // Default keyboard mode
|
|
bool eventKeyboardMode; // Keyboard in event mode
|
|
bool eventKeyboardMode; // Keyboard in event mode
|
|
@@ -129,7 +117,9 @@ typedef struct {
|
|
|
|
|
|
// Gamepad data
|
|
// Gamepad data
|
|
int gamepadStreamFd[MAX_GAMEPADS]; // Gamepad device file descriptor
|
|
int gamepadStreamFd[MAX_GAMEPADS]; // Gamepad device file descriptor
|
|
-
|
|
|
|
|
|
+ int gamepadAbsAxisRange[MAX_GAMEPADS][MAX_GAMEPAD_AXIS][2]; // [0] = min, [1] = range value of the axis
|
|
|
|
+ int gamepadAbsAxisMap[MAX_GAMEPADS][ABS_CNT]; // Maps the axes gamepads from the evdev api to a sequential one
|
|
|
|
+ int gamepadCount; // The number of gamepads registered
|
|
} PlatformData;
|
|
} PlatformData;
|
|
|
|
|
|
//----------------------------------------------------------------------------------
|
|
//----------------------------------------------------------------------------------
|
|
@@ -145,6 +135,8 @@ static PlatformData platform = { 0 }; // Platform specific data
|
|
// Scancode to keycode mapping for US keyboards
|
|
// Scancode to keycode mapping for US keyboards
|
|
// TODO: Replace this with a keymap from the X11 to get the correct regional map for the keyboard:
|
|
// TODO: Replace this with a keymap from the X11 to get the correct regional map for the keyboard:
|
|
// Currently non US keyboards will have the wrong mapping for some keys
|
|
// Currently non US keyboards will have the wrong mapping for some keys
|
|
|
|
+// NOTE: Replacing this with the keymap from X11 would probably be useless, as people use the drm
|
|
|
|
+// backend to *avoid* X11
|
|
static const int keymapUS[] = {
|
|
static const int keymapUS[] = {
|
|
0, 256, 49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 45, 61, 259, 258, 81, 87, 69, 82, 84,
|
|
0, 256, 49, 50, 51, 52, 53, 54, 55, 56, 57, 48, 45, 61, 259, 258, 81, 87, 69, 82, 84,
|
|
89, 85, 73, 79, 80, 91, 93, 257, 341, 65, 83, 68, 70, 71, 72, 74, 75, 76, 59, 39, 96,
|
|
89, 85, 73, 79, 80, 91, 93, 257, 341, 65, 83, 68, 70, 71, 72, 74, 75, 76, 59, 39, 96,
|
|
@@ -178,19 +170,17 @@ static const int EvkeyToUnicodeLUT[] = {
|
|
int InitPlatform(void); // Initialize platform (graphics, inputs and more)
|
|
int InitPlatform(void); // Initialize platform (graphics, inputs and more)
|
|
void ClosePlatform(void); // Close platform
|
|
void ClosePlatform(void); // Close platform
|
|
|
|
|
|
|
|
+#if defined(SUPPORT_SSH_KEYBOARD_RPI)
|
|
static void InitKeyboard(void); // Initialize raw keyboard system
|
|
static void InitKeyboard(void); // Initialize raw keyboard system
|
|
static void RestoreKeyboard(void); // Restore keyboard system
|
|
static void RestoreKeyboard(void); // Restore keyboard system
|
|
-#if defined(SUPPORT_SSH_KEYBOARD_RPI)
|
|
|
|
static void ProcessKeyboard(void); // Process keyboard events
|
|
static void ProcessKeyboard(void); // Process keyboard events
|
|
#endif
|
|
#endif
|
|
|
|
|
|
static void InitEvdevInput(void); // Initialize evdev inputs
|
|
static void InitEvdevInput(void); // Initialize evdev inputs
|
|
static void ConfigureEvdevDevice(char *device); // Identifies a input device and configures it for use if appropriate
|
|
static void ConfigureEvdevDevice(char *device); // Identifies a input device and configures it for use if appropriate
|
|
static void PollKeyboardEvents(void); // Process evdev keyboard events
|
|
static void PollKeyboardEvents(void); // Process evdev keyboard events
|
|
-static void *EventThread(void *arg); // Input device events reading thread
|
|
|
|
-
|
|
|
|
-static void InitGamepad(void); // Initialize raw gamepad input
|
|
|
|
-static void PollGamepadEvents(void); // Gamepad reading function
|
|
|
|
|
|
+static void PollGamepadEvents(void); // Process evdev gamepad events
|
|
|
|
+static void PollMouseEvents(void); // Process evdev mouse events
|
|
|
|
|
|
static int FindMatchingConnectorMode(const drmModeConnector *connector, const drmModeModeInfo *mode); // Search matching DRM mode in connector's mode list
|
|
static int FindMatchingConnectorMode(const drmModeConnector *connector, const drmModeModeInfo *mode); // Search matching DRM mode in connector's mode list
|
|
static int FindExactConnectorMode(const drmModeConnector *connector, uint width, uint height, uint fps, bool allowInterlaced); // Search exactly matching DRM connector mode in connector's list
|
|
static int FindExactConnectorMode(const drmModeConnector *connector, uint width, uint height, uint fps, bool allowInterlaced); // Search exactly matching DRM connector mode in connector's list
|
|
@@ -564,6 +554,16 @@ void PollInputEvents(void)
|
|
|
|
|
|
PollKeyboardEvents();
|
|
PollKeyboardEvents();
|
|
|
|
|
|
|
|
+ #if defined(SUPPORT_SSH_KEYBOARD_RPI)
|
|
|
|
+ // NOTE: Keyboard reading could be done using input_event(s) or just read from stdin, both methods are used here.
|
|
|
|
+ // stdin reading is still used for legacy purposes, it allows keyboard input trough SSH console
|
|
|
|
+
|
|
|
|
+ if (!platform.eventKeyboardMode) ProcessKeyboard();
|
|
|
|
+ #endif
|
|
|
|
+
|
|
|
|
+ // Check exit key
|
|
|
|
+ if (CORE.Input.Keyboard.currentKeyState[CORE.Input.Keyboard.exitKey] == 1) CORE.Window.shouldClose = true;
|
|
|
|
+
|
|
// Register previous mouse position
|
|
// Register previous mouse position
|
|
if (platform.cursorRelative) CORE.Input.Mouse.currentPosition = (Vector2){ 0.0f, 0.0f };
|
|
if (platform.cursorRelative) CORE.Input.Mouse.currentPosition = (Vector2){ 0.0f, 0.0f };
|
|
else CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition;
|
|
else CORE.Input.Mouse.previousPosition = CORE.Input.Mouse.currentPosition;
|
|
@@ -591,181 +591,9 @@ void PollInputEvents(void)
|
|
// Map touch position to mouse position for convenience
|
|
// Map touch position to mouse position for convenience
|
|
CORE.Input.Touch.position[0] = CORE.Input.Mouse.currentPosition;
|
|
CORE.Input.Touch.position[0] = CORE.Input.Mouse.currentPosition;
|
|
|
|
|
|
-#if defined(SUPPORT_SSH_KEYBOARD_RPI)
|
|
|
|
- // NOTE: Keyboard reading could be done using input_event(s) or just read from stdin, both methods are used here.
|
|
|
|
- // stdin reading is still used for legacy purposes, it allows keyboard input trough SSH console
|
|
|
|
-
|
|
|
|
- if (!platform.eventKeyboardMode) ProcessKeyboard();
|
|
|
|
-#endif
|
|
|
|
-
|
|
|
|
// Handle the mouse/touch/gestures events:
|
|
// Handle the mouse/touch/gestures events:
|
|
// NOTE: Replaces the EventThread handling that is now commented.
|
|
// NOTE: Replaces the EventThread handling that is now commented.
|
|
- {
|
|
|
|
- int fd = platform.mouseFd;
|
|
|
|
- if (fd == -1) return;
|
|
|
|
-
|
|
|
|
- struct input_event event = { 0 };
|
|
|
|
-
|
|
|
|
- int touchAction = -1; // 0-TOUCH_ACTION_UP, 1-TOUCH_ACTION_DOWN, 2-TOUCH_ACTION_MOVE
|
|
|
|
-
|
|
|
|
- // Try to read data from the mouse/touch/gesture and only continue if successful
|
|
|
|
- while (read(fd, &event, sizeof(event)) == (int)sizeof(event))
|
|
|
|
- {
|
|
|
|
- // Relative movement parsing
|
|
|
|
- if (event.type == EV_REL)
|
|
|
|
- {
|
|
|
|
- if (event.code == REL_X)
|
|
|
|
- {
|
|
|
|
- if (platform.cursorRelative)
|
|
|
|
- {
|
|
|
|
- CORE.Input.Mouse.currentPosition.x = event.value;
|
|
|
|
- CORE.Input.Mouse.previousPosition.x = 0.0f;
|
|
|
|
- }
|
|
|
|
- else CORE.Input.Mouse.currentPosition.x += event.value;
|
|
|
|
- CORE.Input.Touch.position[0].x = CORE.Input.Mouse.currentPosition.x;
|
|
|
|
-
|
|
|
|
- touchAction = 2; // TOUCH_ACTION_MOVE
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (event.code == REL_Y)
|
|
|
|
- {
|
|
|
|
- if (platform.cursorRelative)
|
|
|
|
- {
|
|
|
|
- CORE.Input.Mouse.currentPosition.y = event.value;
|
|
|
|
- CORE.Input.Mouse.previousPosition.y = 0.0f;
|
|
|
|
- }
|
|
|
|
- else CORE.Input.Mouse.currentPosition.y += event.value;
|
|
|
|
- CORE.Input.Touch.position[0].y = CORE.Input.Mouse.currentPosition.y;
|
|
|
|
-
|
|
|
|
- touchAction = 2; // TOUCH_ACTION_MOVE
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (event.code == REL_WHEEL) platform.eventWheelMove.y += event.value;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // Absolute movement parsing
|
|
|
|
- if (event.type == EV_ABS)
|
|
|
|
- {
|
|
|
|
- // Basic movement
|
|
|
|
- if (event.code == ABS_X)
|
|
|
|
- {
|
|
|
|
- CORE.Input.Mouse.currentPosition.x = (event.value - platform.absRange.x)*CORE.Window.screen.width/platform.absRange.width; // Scale according to absRange
|
|
|
|
- CORE.Input.Touch.position[0].x = (event.value - platform.absRange.x)*CORE.Window.screen.width/platform.absRange.width; // Scale according to absRange
|
|
|
|
-
|
|
|
|
- touchAction = 2; // TOUCH_ACTION_MOVE
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (event.code == ABS_Y)
|
|
|
|
- {
|
|
|
|
- CORE.Input.Mouse.currentPosition.y = (event.value - platform.absRange.y)*CORE.Window.screen.height/platform.absRange.height; // Scale according to absRange
|
|
|
|
- CORE.Input.Touch.position[0].y = (event.value - platform.absRange.y)*CORE.Window.screen.height/platform.absRange.height; // Scale according to absRange
|
|
|
|
-
|
|
|
|
- touchAction = 2; // TOUCH_ACTION_MOVE
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // Multitouch movement
|
|
|
|
- if (event.code == ABS_MT_SLOT) platform.touchSlot = event.value; // Remember the slot number for the folowing events
|
|
|
|
-
|
|
|
|
- if (event.code == ABS_MT_POSITION_X)
|
|
|
|
- {
|
|
|
|
- if (platform.touchSlot < MAX_TOUCH_POINTS) CORE.Input.Touch.position[platform.touchSlot].x = (event.value - platform.absRange.x)*CORE.Window.screen.width/platform.absRange.width; // Scale according to absRange
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (event.code == ABS_MT_POSITION_Y)
|
|
|
|
- {
|
|
|
|
- if (platform.touchSlot < MAX_TOUCH_POINTS) CORE.Input.Touch.position[platform.touchSlot].y = (event.value - platform.absRange.y)*CORE.Window.screen.height/platform.absRange.height; // Scale according to absRange
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (event.code == ABS_MT_TRACKING_ID)
|
|
|
|
- {
|
|
|
|
- if ((event.value < 0) && (platform.touchSlot < MAX_TOUCH_POINTS))
|
|
|
|
- {
|
|
|
|
- // Touch has ended for this point
|
|
|
|
- CORE.Input.Touch.position[platform.touchSlot].x = -1;
|
|
|
|
- CORE.Input.Touch.position[platform.touchSlot].y = -1;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // Touchscreen tap
|
|
|
|
- if (event.code == ABS_PRESSURE)
|
|
|
|
- {
|
|
|
|
- int previousMouseLeftButtonState = platform.currentButtonStateEvdev[MOUSE_BUTTON_LEFT];
|
|
|
|
-
|
|
|
|
- if (!event.value && previousMouseLeftButtonState)
|
|
|
|
- {
|
|
|
|
- platform.currentButtonStateEvdev[MOUSE_BUTTON_LEFT] = 0;
|
|
|
|
-
|
|
|
|
- touchAction = 0; // TOUCH_ACTION_UP
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (event.value && !previousMouseLeftButtonState)
|
|
|
|
- {
|
|
|
|
- platform.currentButtonStateEvdev[MOUSE_BUTTON_LEFT] = 1;
|
|
|
|
-
|
|
|
|
- touchAction = 1; // TOUCH_ACTION_DOWN
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // Button parsing
|
|
|
|
- if (event.type == EV_KEY)
|
|
|
|
- {
|
|
|
|
- // Mouse button parsing
|
|
|
|
- if ((event.code == BTN_TOUCH) || (event.code == BTN_LEFT))
|
|
|
|
- {
|
|
|
|
- platform.currentButtonStateEvdev[MOUSE_BUTTON_LEFT] = event.value;
|
|
|
|
-
|
|
|
|
- if (event.value > 0) touchAction = 1; // TOUCH_ACTION_DOWN
|
|
|
|
- else touchAction = 0; // TOUCH_ACTION_UP
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (event.code == BTN_RIGHT) platform.currentButtonStateEvdev[MOUSE_BUTTON_RIGHT] = event.value;
|
|
|
|
- if (event.code == BTN_MIDDLE) platform.currentButtonStateEvdev[MOUSE_BUTTON_MIDDLE] = event.value;
|
|
|
|
- if (event.code == BTN_SIDE) platform.currentButtonStateEvdev[MOUSE_BUTTON_SIDE] = event.value;
|
|
|
|
- if (event.code == BTN_EXTRA) platform.currentButtonStateEvdev[MOUSE_BUTTON_EXTRA] = event.value;
|
|
|
|
- if (event.code == BTN_FORWARD) platform.currentButtonStateEvdev[MOUSE_BUTTON_FORWARD] = event.value;
|
|
|
|
- if (event.code == BTN_BACK) platform.currentButtonStateEvdev[MOUSE_BUTTON_BACK] = event.value;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // Screen confinement
|
|
|
|
- if (!CORE.Input.Mouse.cursorHidden)
|
|
|
|
- {
|
|
|
|
- if (CORE.Input.Mouse.currentPosition.x < 0) CORE.Input.Mouse.currentPosition.x = 0;
|
|
|
|
- if (CORE.Input.Mouse.currentPosition.x > CORE.Window.screen.width/CORE.Input.Mouse.scale.x) CORE.Input.Mouse.currentPosition.x = CORE.Window.screen.width/CORE.Input.Mouse.scale.x;
|
|
|
|
-
|
|
|
|
- if (CORE.Input.Mouse.currentPosition.y < 0) CORE.Input.Mouse.currentPosition.y = 0;
|
|
|
|
- if (CORE.Input.Mouse.currentPosition.y > CORE.Window.screen.height/CORE.Input.Mouse.scale.y) CORE.Input.Mouse.currentPosition.y = CORE.Window.screen.height/CORE.Input.Mouse.scale.y;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // Update touch point count
|
|
|
|
- CORE.Input.Touch.pointCount = 0;
|
|
|
|
- for (int i = 0; i < MAX_TOUCH_POINTS; i++)
|
|
|
|
- {
|
|
|
|
- if (CORE.Input.Touch.position[i].x >= 0) CORE.Input.Touch.pointCount++;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
-#if defined(SUPPORT_GESTURES_SYSTEM)
|
|
|
|
- if (touchAction > -1)
|
|
|
|
- {
|
|
|
|
- GestureEvent gestureEvent = { 0 };
|
|
|
|
-
|
|
|
|
- gestureEvent.touchAction = touchAction;
|
|
|
|
- gestureEvent.pointCount = CORE.Input.Touch.pointCount;
|
|
|
|
-
|
|
|
|
- for (int i = 0; i < MAX_TOUCH_POINTS; i++)
|
|
|
|
- {
|
|
|
|
- gestureEvent.pointId[i] = i;
|
|
|
|
- gestureEvent.position[i] = CORE.Input.Touch.position[i];
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- ProcessGestureEvent(gestureEvent);
|
|
|
|
-
|
|
|
|
- touchAction = -1;
|
|
|
|
- }
|
|
|
|
-#endif
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ PollMouseEvents();
|
|
}
|
|
}
|
|
|
|
|
|
//----------------------------------------------------------------------------------
|
|
//----------------------------------------------------------------------------------
|
|
@@ -1123,8 +951,11 @@ int InitPlatform(void)
|
|
// Initialize input events system
|
|
// Initialize input events system
|
|
//----------------------------------------------------------------------------
|
|
//----------------------------------------------------------------------------
|
|
InitEvdevInput(); // Evdev inputs initialization
|
|
InitEvdevInput(); // Evdev inputs initialization
|
|
- InitGamepad(); // Gamepad init
|
|
|
|
- InitKeyboard(); // Keyboard init (stdin)
|
|
|
|
|
|
+
|
|
|
|
+ #if defined(SUPPORT_SSH_KEYBOARD_RPI)
|
|
|
|
+ InitKeyboard(); // Keyboard init (stdin)
|
|
|
|
+ #endif
|
|
|
|
+
|
|
//----------------------------------------------------------------------------
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
|
// Initialize storage system
|
|
// Initialize storage system
|
|
@@ -1203,28 +1034,30 @@ void ClosePlatform(void)
|
|
platform.device = EGL_NO_DISPLAY;
|
|
platform.device = EGL_NO_DISPLAY;
|
|
}
|
|
}
|
|
|
|
|
|
- // Wait for mouse and gamepad threads to finish before closing
|
|
|
|
- // NOTE: Those threads should already have finished at this point
|
|
|
|
- // because they are controlled by CORE.Window.shouldClose variable
|
|
|
|
-
|
|
|
|
CORE.Window.shouldClose = true; // Added to force threads to exit when the close window is called
|
|
CORE.Window.shouldClose = true; // Added to force threads to exit when the close window is called
|
|
|
|
|
|
- // Close the evdev keyboard
|
|
|
|
- if (platform.keyboardFd != -1)
|
|
|
|
|
|
+ // Close the evdev devices
|
|
|
|
+
|
|
|
|
+ if (platform.mouseFd != -1) {
|
|
|
|
+ close(platform.mouseFd);
|
|
|
|
+ platform.mouseFd = -1;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ for (int i = 0; i < platform.gamepadCount; i++)
|
|
{
|
|
{
|
|
- close(platform.keyboardFd);
|
|
|
|
- platform.keyboardFd = -1;
|
|
|
|
|
|
+ close(platform.gamepadStreamFd[i]);
|
|
|
|
+ platform.gamepadStreamFd[i] = -1;
|
|
}
|
|
}
|
|
|
|
|
|
- for (int i = 0; i < sizeof(platform.eventWorker)/sizeof(InputEventWorker); ++i)
|
|
|
|
|
|
+ if (platform.keyboardFd != -1)
|
|
{
|
|
{
|
|
- if (platform.eventWorker[i].threadId)
|
|
|
|
- {
|
|
|
|
- pthread_join(platform.eventWorker[i].threadId, NULL);
|
|
|
|
- }
|
|
|
|
|
|
+ close(platform.keyboardFd);
|
|
|
|
+ platform.keyboardFd = -1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+#if defined(SUPPORT_SSH_KEYBOARD_RPI)
|
|
|
|
+
|
|
// Initialize Keyboard system (using standard input)
|
|
// Initialize Keyboard system (using standard input)
|
|
static void InitKeyboard(void)
|
|
static void InitKeyboard(void)
|
|
{
|
|
{
|
|
@@ -1256,7 +1089,7 @@ static void InitKeyboard(void)
|
|
int result = ioctl(STDIN_FILENO, KDGKBMODE, &platform.defaultKeyboardMode);
|
|
int result = ioctl(STDIN_FILENO, KDGKBMODE, &platform.defaultKeyboardMode);
|
|
|
|
|
|
// In case of failure, it could mean a remote keyboard is used (SSH)
|
|
// In case of failure, it could mean a remote keyboard is used (SSH)
|
|
- if (result < 0) TRACELOG(LOG_WARNING, "RPI: Failed to change keyboard mode, an SSH keyboard is probably used");
|
|
|
|
|
|
+ if (result < 0) TRACELOG(LOG_WARNING, "DRM: Failed to change keyboard mode, an SSH keyboard is probably used");
|
|
else
|
|
else
|
|
{
|
|
{
|
|
// Reconfigure keyboard mode to get:
|
|
// Reconfigure keyboard mode to get:
|
|
@@ -1282,7 +1115,6 @@ static void RestoreKeyboard(void)
|
|
ioctl(STDIN_FILENO, KDSKBMODE, platform.defaultKeyboardMode);
|
|
ioctl(STDIN_FILENO, KDSKBMODE, platform.defaultKeyboardMode);
|
|
}
|
|
}
|
|
|
|
|
|
-#if defined(SUPPORT_SSH_KEYBOARD_RPI)
|
|
|
|
// Process keyboard inputs
|
|
// Process keyboard inputs
|
|
static void ProcessKeyboard(void)
|
|
static void ProcessKeyboard(void)
|
|
{
|
|
{
|
|
@@ -1383,18 +1215,6 @@ static void ProcessKeyboard(void)
|
|
CORE.Input.Keyboard.keyPressedQueueCount++;
|
|
CORE.Input.Keyboard.keyPressedQueueCount++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
-
|
|
|
|
- // Check exit key (same functionality as GLFW3 KeyCallback())
|
|
|
|
- if (CORE.Input.Keyboard.currentKeyState[CORE.Input.Keyboard.exitKey] == 1) CORE.Window.shouldClose = true;
|
|
|
|
-
|
|
|
|
-#if defined(SUPPORT_SCREEN_CAPTURE)
|
|
|
|
- // Check screen capture key (raylib key: KEY_F12)
|
|
|
|
- if (CORE.Input.Keyboard.currentKeyState[301] == 1)
|
|
|
|
- {
|
|
|
|
- TakeScreenshot(TextFormat("screenshot%03i.png", screenshotCounter));
|
|
|
|
- screenshotCounter++;
|
|
|
|
- }
|
|
|
|
-#endif
|
|
|
|
}
|
|
}
|
|
#endif // SUPPORT_SSH_KEYBOARD_RPI
|
|
#endif // SUPPORT_SSH_KEYBOARD_RPI
|
|
|
|
|
|
@@ -1408,6 +1228,7 @@ static void InitEvdevInput(void)
|
|
|
|
|
|
// Initialise keyboard file descriptor
|
|
// Initialise keyboard file descriptor
|
|
platform.keyboardFd = -1;
|
|
platform.keyboardFd = -1;
|
|
|
|
+ platform.mouseFd = -1;
|
|
|
|
|
|
// Reset variables
|
|
// Reset variables
|
|
for (int i = 0; i < MAX_TOUCH_POINTS; ++i)
|
|
for (int i = 0; i < MAX_TOUCH_POINTS; ++i)
|
|
@@ -1440,7 +1261,7 @@ static void InitEvdevInput(void)
|
|
|
|
|
|
closedir(directory);
|
|
closedir(directory);
|
|
}
|
|
}
|
|
- else TRACELOG(LOG_WARNING, "RPI: Failed to open linux event directory: %s", DEFAULT_EVDEV_PATH);
|
|
|
|
|
|
+ else TRACELOG(LOG_WARNING, "DRM: Failed to open linux event directory: %s", DEFAULT_EVDEV_PATH);
|
|
}
|
|
}
|
|
|
|
|
|
// Identifies a input device and configures it for use if appropriate
|
|
// Identifies a input device and configures it for use if appropriate
|
|
@@ -1453,62 +1274,18 @@ static void ConfigureEvdevDevice(char *device)
|
|
#define LONG(x) ((x)/BITS_PER_LONG)
|
|
#define LONG(x) ((x)/BITS_PER_LONG)
|
|
#define TEST_BIT(array, bit) ((array[LONG(bit)] >> OFF(bit)) & 1)
|
|
#define TEST_BIT(array, bit) ((array[LONG(bit)] >> OFF(bit)) & 1)
|
|
|
|
|
|
- struct input_absinfo absinfo = { 0 };
|
|
|
|
unsigned long evBits[NBITS(EV_MAX)] = { 0 };
|
|
unsigned long evBits[NBITS(EV_MAX)] = { 0 };
|
|
unsigned long absBits[NBITS(ABS_MAX)] = { 0 };
|
|
unsigned long absBits[NBITS(ABS_MAX)] = { 0 };
|
|
unsigned long relBits[NBITS(REL_MAX)] = { 0 };
|
|
unsigned long relBits[NBITS(REL_MAX)] = { 0 };
|
|
unsigned long keyBits[NBITS(KEY_MAX)] = { 0 };
|
|
unsigned long keyBits[NBITS(KEY_MAX)] = { 0 };
|
|
- bool hasAbs = false;
|
|
|
|
- bool hasRel = false;
|
|
|
|
- bool hasAbsMulti = false;
|
|
|
|
- int freeWorkerId = -1;
|
|
|
|
- int fd = -1;
|
|
|
|
-
|
|
|
|
- InputEventWorker *worker = NULL;
|
|
|
|
-
|
|
|
|
- // Open the device and allocate worker
|
|
|
|
- //-------------------------------------------------------------------------------------------------------
|
|
|
|
- // Find a free spot in the workers array
|
|
|
|
- for (int i = 0; i < sizeof(platform.eventWorker)/sizeof(InputEventWorker); ++i)
|
|
|
|
- {
|
|
|
|
- if (platform.eventWorker[i].threadId == 0)
|
|
|
|
- {
|
|
|
|
- freeWorkerId = i;
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // Select the free worker from array
|
|
|
|
- if (freeWorkerId >= 0)
|
|
|
|
- {
|
|
|
|
- worker = &(platform.eventWorker[freeWorkerId]); // Grab a pointer to the worker
|
|
|
|
- memset(worker, 0, sizeof(InputEventWorker)); // Clear the worker
|
|
|
|
- }
|
|
|
|
- else
|
|
|
|
- {
|
|
|
|
- TRACELOG(LOG_WARNING, "RPI: Failed to create input device thread for %s, out of worker slots", device);
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
|
|
|
|
// Open the device
|
|
// Open the device
|
|
- fd = open(device, O_RDONLY | O_NONBLOCK);
|
|
|
|
|
|
+ int fd = open(device, O_RDONLY | O_NONBLOCK);
|
|
if (fd < 0)
|
|
if (fd < 0)
|
|
{
|
|
{
|
|
- TRACELOG(LOG_WARNING, "RPI: Failed to open input device: %s", device);
|
|
|
|
|
|
+ TRACELOG(LOG_WARNING, "DRM: Failed to open input device: %s", device);
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
- worker->fd = fd;
|
|
|
|
-
|
|
|
|
- // Grab number on the end of the devices name "event<N>"
|
|
|
|
- int devNum = 0;
|
|
|
|
- char *ptrDevName = strrchr(device, 't');
|
|
|
|
- worker->eventNum = -1;
|
|
|
|
-
|
|
|
|
- if (ptrDevName != NULL)
|
|
|
|
- {
|
|
|
|
- if (sscanf(ptrDevName, "t%d", &devNum) == 1) worker->eventNum = devNum;
|
|
|
|
- }
|
|
|
|
- else worker->eventNum = 0; // TODO: HACK: Grab number for mouse0 device!
|
|
|
|
|
|
|
|
// At this point we have a connection to the device, but we don't yet know what the device is.
|
|
// At this point we have a connection to the device, but we don't yet know what the device is.
|
|
// It could be many things, even as simple as a power button...
|
|
// It could be many things, even as simple as a power button...
|
|
@@ -1516,149 +1293,166 @@ static void ConfigureEvdevDevice(char *device)
|
|
|
|
|
|
// Identify the device
|
|
// Identify the device
|
|
//-------------------------------------------------------------------------------------------------------
|
|
//-------------------------------------------------------------------------------------------------------
|
|
- ioctl(fd, EVIOCGBIT(0, sizeof(evBits)), evBits); // Read a bitfield of the available device properties
|
|
|
|
|
|
+ struct input_absinfo absinfo[ABS_CNT] = { 0 };
|
|
|
|
|
|
- // Check for absolute input devices
|
|
|
|
- if (TEST_BIT(evBits, EV_ABS))
|
|
|
|
- {
|
|
|
|
|
|
+ // These flags aren't really a one of
|
|
|
|
+ // Some devices could have properties we assosciate with keyboards as well as properties
|
|
|
|
+ // we assosciate with mice
|
|
|
|
+ bool isKeyboard = false;
|
|
|
|
+ bool isMouse = false;
|
|
|
|
+ bool isTouch = false;
|
|
|
|
+ bool isGamepad = false;
|
|
|
|
+
|
|
|
|
+ int absAxisCount = 0;
|
|
|
|
+
|
|
|
|
+ ioctl(fd, EVIOCGBIT(0, sizeof(evBits)), evBits);
|
|
|
|
+ ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keyBits)), keyBits);
|
|
|
|
+
|
|
|
|
+ if (TEST_BIT(evBits, EV_ABS)) {
|
|
ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absBits)), absBits);
|
|
ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absBits)), absBits);
|
|
|
|
|
|
- // Check for absolute movement support (usually touchscreens, but also joysticks)
|
|
|
|
- if (TEST_BIT(absBits, ABS_X) && TEST_BIT(absBits, ABS_Y))
|
|
|
|
|
|
+ // If the device has an X an Y axis it's either a touch device, a special mouse or a gamepad
|
|
|
|
+ bool hasAbsXY = TEST_BIT(absBits, ABS_X) && TEST_BIT(absBits, ABS_Y);
|
|
|
|
+
|
|
|
|
+ if (hasAbsXY)
|
|
{
|
|
{
|
|
- hasAbs = true;
|
|
|
|
-
|
|
|
|
- // Get the scaling values
|
|
|
|
- ioctl(fd, EVIOCGABS(ABS_X), &absinfo);
|
|
|
|
- worker->absRange.x = absinfo.minimum;
|
|
|
|
- worker->absRange.width = absinfo.maximum - absinfo.minimum;
|
|
|
|
- platform.absRange.x = absinfo.minimum;
|
|
|
|
- platform.absRange.width = absinfo.maximum - absinfo.minimum;
|
|
|
|
-
|
|
|
|
- ioctl(fd, EVIOCGABS(ABS_Y), &absinfo);
|
|
|
|
- worker->absRange.y = absinfo.minimum;
|
|
|
|
- worker->absRange.height = absinfo.maximum - absinfo.minimum;
|
|
|
|
- platform.absRange.y = absinfo.minimum;
|
|
|
|
- platform.absRange.height = absinfo.maximum - absinfo.minimum;
|
|
|
|
|
|
+ absAxisCount += 2;
|
|
|
|
+ ioctl(fd, EVIOCGABS(ABS_X), &absinfo[ABS_X]);
|
|
|
|
+ ioctl(fd, EVIOCGABS(ABS_Y), &absinfo[ABS_Y]);
|
|
}
|
|
}
|
|
|
|
|
|
- // Check for multiple absolute movement support (usually multitouch touchscreens)
|
|
|
|
- if (TEST_BIT(absBits, ABS_MT_POSITION_X) && TEST_BIT(absBits, ABS_MT_POSITION_Y))
|
|
|
|
- {
|
|
|
|
- hasAbsMulti = true;
|
|
|
|
-
|
|
|
|
- // Get the scaling values
|
|
|
|
- ioctl(fd, EVIOCGABS(ABS_X), &absinfo);
|
|
|
|
- worker->absRange.x = absinfo.minimum;
|
|
|
|
- worker->absRange.width = absinfo.maximum - absinfo.minimum;
|
|
|
|
- platform.absRange.x = absinfo.minimum;
|
|
|
|
- platform.absRange.width = absinfo.maximum - absinfo.minimum;
|
|
|
|
-
|
|
|
|
- ioctl(fd, EVIOCGABS(ABS_Y), &absinfo);
|
|
|
|
- worker->absRange.y = absinfo.minimum;
|
|
|
|
- worker->absRange.height = absinfo.maximum - absinfo.minimum;
|
|
|
|
- platform.absRange.y = absinfo.minimum;
|
|
|
|
- platform.absRange.height = absinfo.maximum - absinfo.minimum;
|
|
|
|
|
|
+ // If it has any of these buttons it's a touch device
|
|
|
|
+ if (hasAbsXY &&
|
|
|
|
+ (TEST_BIT(keyBits, BTN_STYLUS) ||
|
|
|
|
+ TEST_BIT(keyBits, BTN_TOOL_PEN) ||
|
|
|
|
+ TEST_BIT(keyBits, BTN_TOOL_FINGER) ||
|
|
|
|
+ TEST_BIT(keyBits, BTN_TOUCH))) isTouch = true;
|
|
|
|
+
|
|
|
|
+ // Absolute mice should really only exist with VMWare, but it shouldn't
|
|
|
|
+ // matter if we support them
|
|
|
|
+ else if (hasAbsXY && TEST_BIT(keyBits, BTN_MOUSE)) isMouse = true;
|
|
|
|
+
|
|
|
|
+ // If any of the common joystick axis is present, we assume it's a gamepad
|
|
|
|
+ else {
|
|
|
|
+ for (int axis = (hasAbsXY ? ABS_Z : ABS_X); axis < ABS_PRESSURE; axis++)
|
|
|
|
+ {
|
|
|
|
+ if (TEST_BIT(absBits, axis)) {
|
|
|
|
+ isGamepad = true;
|
|
|
|
+ absAxisCount++;
|
|
|
|
+
|
|
|
|
+ ioctl(fd, EVIOCGABS(axis), &absinfo[axis]);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ // If the device has multitouch axes, it's a touch device
|
|
|
|
+ if (TEST_BIT(absBits, ABS_MT_POSITION_X) &&
|
|
|
|
+ TEST_BIT(absBits, ABS_MT_POSITION_Y)) isTouch = true;
|
|
}
|
|
}
|
|
|
|
|
|
- // Check for relative movement support (usually mouse)
|
|
|
|
if (TEST_BIT(evBits, EV_REL))
|
|
if (TEST_BIT(evBits, EV_REL))
|
|
{
|
|
{
|
|
ioctl(fd, EVIOCGBIT(EV_REL, sizeof(relBits)), relBits);
|
|
ioctl(fd, EVIOCGBIT(EV_REL, sizeof(relBits)), relBits);
|
|
|
|
|
|
- if (TEST_BIT(relBits, REL_X) && TEST_BIT(relBits, REL_Y)) hasRel = true;
|
|
|
|
|
|
+ // If it has any of the gamepad or touch features we tested so far, it's not a mouse
|
|
|
|
+ if (!isTouch &&
|
|
|
|
+ !isGamepad &&
|
|
|
|
+ TEST_BIT(relBits, REL_X) &&
|
|
|
|
+ TEST_BIT(relBits, REL_Y) &&
|
|
|
|
+ TEST_BIT(keyBits, BTN_MOUSE)) isMouse = true;
|
|
}
|
|
}
|
|
|
|
|
|
- // Check for button support to determine the device type(usually on all input devices)
|
|
|
|
|
|
+
|
|
if (TEST_BIT(evBits, EV_KEY))
|
|
if (TEST_BIT(evBits, EV_KEY))
|
|
{
|
|
{
|
|
- ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keyBits)), keyBits);
|
|
|
|
|
|
+ // The first 32 keys as defined in input-event-codes.h are pretty much
|
|
|
|
+ // exclusive to keyboards, so we can test them using a mask
|
|
|
|
+ // Leave out the first bit to not test KEY_RESERVED
|
|
|
|
+ const unsigned long mask = 0xFFFFFFFE;
|
|
|
|
+ if ((keyBits[0] & mask) == mask) isKeyboard = true;
|
|
|
|
|
|
- if (hasAbs || hasAbsMulti)
|
|
|
|
|
|
+ // If we find any of the common gamepad buttons we assume it's a gamepad
|
|
|
|
+ else
|
|
{
|
|
{
|
|
- if (TEST_BIT(keyBits, BTN_TOUCH)) worker->isTouch = true; // This is a touchscreen
|
|
|
|
- if (TEST_BIT(keyBits, BTN_TOOL_FINGER)) worker->isTouch = true; // This is a drawing tablet
|
|
|
|
- if (TEST_BIT(keyBits, BTN_TOOL_PEN)) worker->isTouch = true; // This is a drawing tablet
|
|
|
|
- if (TEST_BIT(keyBits, BTN_STYLUS)) worker->isTouch = true; // This is a drawing tablet
|
|
|
|
- if (worker->isTouch || hasAbsMulti) worker->isMultitouch = true; // This is a multitouch capable device
|
|
|
|
- }
|
|
|
|
|
|
+ for (int button = BTN_JOYSTICK; button < BTN_DIGI; ++button)
|
|
|
|
+ {
|
|
|
|
+ if (TEST_BIT(keyBits, button)) isGamepad = true;
|
|
|
|
+ }
|
|
|
|
|
|
- if (hasRel)
|
|
|
|
- {
|
|
|
|
- if (TEST_BIT(keyBits, BTN_LEFT)) worker->isMouse = true; // This is a mouse
|
|
|
|
- if (TEST_BIT(keyBits, BTN_RIGHT)) worker->isMouse = true; // This is a mouse
|
|
|
|
|
|
+ for (int button = BTN_TRIGGER_HAPPY1; button <= BTN_TRIGGER_HAPPY40; button++)
|
|
|
|
+ {
|
|
|
|
+ if (TEST_BIT(keyBits, button)) isGamepad = true;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
-
|
|
|
|
- if (TEST_BIT(keyBits, BTN_A)) worker->isGamepad = true; // This is a gamepad
|
|
|
|
- if (TEST_BIT(keyBits, BTN_TRIGGER)) worker->isGamepad = true; // This is a gamepad
|
|
|
|
- if (TEST_BIT(keyBits, BTN_START)) worker->isGamepad = true; // This is a gamepad
|
|
|
|
- if (TEST_BIT(keyBits, BTN_TL)) worker->isGamepad = true; // This is a gamepad
|
|
|
|
- if (TEST_BIT(keyBits, BTN_TL)) worker->isGamepad = true; // This is a gamepad
|
|
|
|
-
|
|
|
|
- if (TEST_BIT(keyBits, KEY_SPACE)) worker->isKeyboard = true; // This is a keyboard
|
|
|
|
}
|
|
}
|
|
- //-------------------------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
- // Decide what to do with the device
|
|
|
|
- //-------------------------------------------------------------------------------------------------------
|
|
|
|
- if (worker->isKeyboard && (platform.keyboardFd == -1))
|
|
|
|
- {
|
|
|
|
- // Use the first keyboard encountered. This assumes that a device that says it's a keyboard is just a
|
|
|
|
- // keyboard. The keyboard is polled synchronously, whereas other input devices are polled in separate
|
|
|
|
- // threads so that they don't drop events when the frame rate is slow.
|
|
|
|
- TRACELOG(LOG_INFO, "RPI: Opening keyboard device: %s", device);
|
|
|
|
- platform.keyboardFd = worker->fd;
|
|
|
|
- }
|
|
|
|
- else if (worker->isTouch || worker->isMouse)
|
|
|
|
|
|
+ const char *deviceKindStr = "unknown";
|
|
|
|
+ if (isMouse || isTouch)
|
|
{
|
|
{
|
|
- // Looks like an interesting device
|
|
|
|
- TRACELOG(LOG_INFO, "RPI: Opening input device: %s (%s%s%s%s)", device,
|
|
|
|
- worker->isMouse? "mouse " : "",
|
|
|
|
- worker->isMultitouch? "multitouch " : "",
|
|
|
|
- worker->isTouch? "touchscreen " : "",
|
|
|
|
- worker->isGamepad? "gamepad " : "");
|
|
|
|
- platform.mouseFd = worker->fd;
|
|
|
|
-
|
|
|
|
- // NOTE: moved the mouse/touch/gesture input to PollInputEvents()/
|
|
|
|
- // so added the "platform.mouseFd = worker->fd;" line above
|
|
|
|
- // and commented the thread code below:
|
|
|
|
-
|
|
|
|
- // Create a thread for this device
|
|
|
|
- //int error = pthread_create(&worker->threadId, NULL, &EventThread, (void *)worker);
|
|
|
|
- //if (error != 0)
|
|
|
|
- //{
|
|
|
|
- // TRACELOG(LOG_WARNING, "RPI: Failed to create input device thread: %s (error: %d)", device, error);
|
|
|
|
- // worker->threadId = 0;
|
|
|
|
- // close(fd);
|
|
|
|
- //}
|
|
|
|
|
|
+ deviceKindStr = "mouse";
|
|
|
|
+ if (platform.mouseFd != -1) close(platform.mouseFd);
|
|
|
|
|
|
|
|
+ platform.mouseFd = fd;
|
|
|
|
+
|
|
|
|
+// TODO: What is this supposed to do?
|
|
|
|
+// Previously if set, it just didn't do anything as the thread code got deleted, so no new
|
|
|
|
+// threads were created and this deleted all old threads, thus doing nothing
|
|
|
|
+// And the description isn't quite clear as to how it behaves together with a mouse
|
|
#if defined(USE_LAST_TOUCH_DEVICE)
|
|
#if defined(USE_LAST_TOUCH_DEVICE)
|
|
- // Find touchscreen with the highest index
|
|
|
|
- int maxTouchNumber = -1;
|
|
|
|
|
|
+#endif
|
|
|
|
|
|
- for (int i = 0; i < sizeof(platform.eventWorker)/sizeof(InputEventWorker); ++i)
|
|
|
|
|
|
+ if (absAxisCount > 0)
|
|
{
|
|
{
|
|
- if (platform.eventWorker[i].isTouch && (platform.eventWorker[i].eventNum > maxTouchNumber)) maxTouchNumber = platform.eventWorker[i].eventNum;
|
|
|
|
|
|
+ platform.absRange.x = absinfo[ABS_X].minimum;
|
|
|
|
+ platform.absRange.width = absinfo[ABS_X].maximum - absinfo[ABS_X].minimum;
|
|
|
|
+
|
|
|
|
+ platform.absRange.y = absinfo[ABS_Y].minimum;
|
|
|
|
+ platform.absRange.height = absinfo[ABS_Y].maximum - absinfo[ABS_Y].minimum;
|
|
}
|
|
}
|
|
|
|
+ }
|
|
|
|
+ else if (isGamepad && !isMouse && !isKeyboard && platform.gamepadCount < MAX_GAMEPADS)
|
|
|
|
+ {
|
|
|
|
+ deviceKindStr = "gamepad";
|
|
|
|
+ int index = platform.gamepadCount++;
|
|
|
|
+
|
|
|
|
+ platform.gamepadStreamFd[index] = fd;
|
|
|
|
+ CORE.Input.Gamepad.ready[index] = true;
|
|
|
|
+
|
|
|
|
+ ioctl(platform.gamepadStreamFd[index], EVIOCGNAME(64), &CORE.Input.Gamepad.name[index]);
|
|
|
|
+ CORE.Input.Gamepad.axisCount[index] = absAxisCount;
|
|
|
|
|
|
- // Find touchscreens with lower indexes
|
|
|
|
- for (int i = 0; i < sizeof(platform.eventWorker)/sizeof(InputEventWorker); ++i)
|
|
|
|
|
|
+ if (absAxisCount > 0)
|
|
{
|
|
{
|
|
- if (platform.eventWorker[i].isTouch && (platform.eventWorker[i].eventNum < maxTouchNumber))
|
|
|
|
|
|
+ // TODO / NOTE
|
|
|
|
+ // So gamepad axis (as in the actual linux joydev.c) are just simply enumerated
|
|
|
|
+ // and (at least for some input drivers like xpat) it's convention to use
|
|
|
|
+ // ABS_X, ABX_Y for one joystick ABS_RX, ABS_RY for the other and the Z axes for the
|
|
|
|
+ // shoulder buttons
|
|
|
|
+ // If these are now enumerated you get LJOY_X, LJOY_Y, LEFT_SHOULDERB, RJOY_X, ...
|
|
|
|
+ // That means they don't match the GamepadAxis enum
|
|
|
|
+ // This could be fixed
|
|
|
|
+ int axisIndex = 0;
|
|
|
|
+ for (int axis = ABS_X; axis < ABS_PRESSURE; axis++)
|
|
{
|
|
{
|
|
- if (platform.eventWorker[i].threadId != 0)
|
|
|
|
- {
|
|
|
|
- TRACELOG(LOG_WARNING, "RPI: Found duplicate touchscreen, killing touchscreen on event: %d", i);
|
|
|
|
- pthread_cancel(platform.eventWorker[i].threadId);
|
|
|
|
- close(platform.eventWorker[i].fd);
|
|
|
|
- }
|
|
|
|
|
|
+ platform.gamepadAbsAxisRange[index][axisIndex][0] = absinfo[axisIndex].minimum;
|
|
|
|
+ platform.gamepadAbsAxisRange[index][axisIndex][1] = absinfo[axisIndex].maximum - absinfo[axisIndex].minimum;
|
|
|
|
+
|
|
|
|
+ platform.gamepadAbsAxisMap[index][axis] = axisIndex++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
-#endif
|
|
|
|
}
|
|
}
|
|
- else close(fd); // We are not interested in this device
|
|
|
|
- //-------------------------------------------------------------------------------------------------------
|
|
|
|
|
|
+ else if (isKeyboard && (platform.keyboardFd == -1))
|
|
|
|
+ {
|
|
|
|
+ deviceKindStr = "keyboard";
|
|
|
|
+ platform.keyboardFd = fd;
|
|
|
|
+ }
|
|
|
|
+ else
|
|
|
|
+ {
|
|
|
|
+ close(fd);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ TRACELOG(LOG_INFO, "Initialized input device %s as %s", device, deviceKindStr);
|
|
}
|
|
}
|
|
|
|
|
|
// Poll and process evdev keyboard events
|
|
// Poll and process evdev keyboard events
|
|
@@ -1673,332 +1467,261 @@ static void PollKeyboardEvents(void)
|
|
// Try to read data from the keyboard and only continue if successful
|
|
// Try to read data from the keyboard and only continue if successful
|
|
while (read(fd, &event, sizeof(event)) == (int)sizeof(event))
|
|
while (read(fd, &event, sizeof(event)) == (int)sizeof(event))
|
|
{
|
|
{
|
|
- // Button parsing
|
|
|
|
- if (event.type == EV_KEY)
|
|
|
|
- {
|
|
|
|
|
|
+ // Check if the event is a key event
|
|
|
|
+ if (event.type != EV_KEY) continue;
|
|
|
|
+
|
|
#if defined(SUPPORT_SSH_KEYBOARD_RPI)
|
|
#if defined(SUPPORT_SSH_KEYBOARD_RPI)
|
|
- // Change keyboard mode to events
|
|
|
|
- platform.eventKeyboardMode = true;
|
|
|
|
|
|
+ // If the event was a key, we know a working keyboard is connected, so disable the SSH keyboard
|
|
|
|
+ platform.eventKeyboardMode = true;
|
|
#endif
|
|
#endif
|
|
- // Keyboard button parsing
|
|
|
|
- if ((event.code >= 1) && (event.code <= 255)) //Keyboard keys appear for codes 1 to 255
|
|
|
|
|
|
+
|
|
|
|
+ // Keyboard keys appear for codes 1 to 255, ignore everthing else
|
|
|
|
+ if ((event.code >= 1) && (event.code <= 255))
|
|
|
|
+ {
|
|
|
|
+
|
|
|
|
+ // Lookup the scancode in the keymap to get a keycode
|
|
|
|
+ keycode = keymapUS[event.code];
|
|
|
|
+
|
|
|
|
+ // Make sure we got a valid keycode
|
|
|
|
+ if ((keycode > 0) && (keycode < MAX_KEYBOARD_KEYS))
|
|
{
|
|
{
|
|
- keycode = keymapUS[event.code & 0xFF]; // The code we get is a scancode so we look up the appropriate keycode
|
|
|
|
|
|
|
|
- // Make sure we got a valid keycode
|
|
|
|
- if ((keycode > 0) && (keycode < sizeof(CORE.Input.Keyboard.currentKeyState)))
|
|
|
|
|
|
+ // WARNING: https://www.kernel.org/doc/Documentation/input/input.txt
|
|
|
|
+ // Event interface: 'value' is the value the event carries. Either a relative change for EV_REL,
|
|
|
|
+ // absolute new value for EV_ABS (joysticks ...), or 0 for EV_KEY for release, 1 for keypress and 2 for autorepeat
|
|
|
|
+ CORE.Input.Keyboard.currentKeyState[keycode] = (event.value >= 1);
|
|
|
|
+ CORE.Input.Keyboard.keyRepeatInFrame[keycode] = (event.value == 2);
|
|
|
|
+
|
|
|
|
+ // If the key is pressed add it to the queues
|
|
|
|
+ if (event.value == 1)
|
|
{
|
|
{
|
|
- // WARNING: https://www.kernel.org/doc/Documentation/input/input.txt
|
|
|
|
- // Event interface: 'value' is the value the event carries. Either a relative change for EV_REL,
|
|
|
|
- // absolute new value for EV_ABS (joysticks ...), or 0 for EV_KEY for release, 1 for keypress and 2 for autorepeat
|
|
|
|
- CORE.Input.Keyboard.currentKeyState[keycode] = (event.value >= 1)? 1 : 0;
|
|
|
|
- CORE.Input.Keyboard.keyRepeatInFrame[keycode] = (event.value == 2)? 1 : 0;
|
|
|
|
- if (event.value >= 1)
|
|
|
|
|
|
+ if (CORE.Input.Keyboard.keyPressedQueueCount < MAX_CHAR_PRESSED_QUEUE)
|
|
{
|
|
{
|
|
- CORE.Input.Keyboard.keyPressedQueue[CORE.Input.Keyboard.keyPressedQueueCount] = keycode; // Register last key pressed
|
|
|
|
|
|
+ CORE.Input.Keyboard.keyPressedQueue[CORE.Input.Keyboard.keyPressedQueueCount] = keycode;
|
|
CORE.Input.Keyboard.keyPressedQueueCount++;
|
|
CORE.Input.Keyboard.keyPressedQueueCount++;
|
|
}
|
|
}
|
|
|
|
|
|
- #if defined(SUPPORT_SCREEN_CAPTURE)
|
|
|
|
- // Check screen capture key (raylib key: KEY_F12)
|
|
|
|
- if (CORE.Input.Keyboard.currentKeyState[301] == 1)
|
|
|
|
|
|
+ if (CORE.Input.Keyboard.charPressedQueueCount < MAX_CHAR_PRESSED_QUEUE)
|
|
{
|
|
{
|
|
- TakeScreenshot(TextFormat("screenshot%03i.png", screenshotCounter));
|
|
|
|
- screenshotCounter++;
|
|
|
|
|
|
+ // TODO/FIXME: This is not actually converting to unicode properly because it's not taking things like shift into account
|
|
|
|
+ CORE.Input.Keyboard.charPressedQueue[CORE.Input.Keyboard.charPressedQueueCount] = EvkeyToUnicodeLUT[event.code];
|
|
|
|
+ CORE.Input.Keyboard.charPressedQueueCount++;
|
|
}
|
|
}
|
|
- #endif
|
|
|
|
-
|
|
|
|
- // Detect char presses (unicode)
|
|
|
|
- if (event.value == 1)
|
|
|
|
- {
|
|
|
|
- // Check if there is space available in the queue
|
|
|
|
- if (CORE.Input.Keyboard.charPressedQueueCount < MAX_CHAR_PRESSED_QUEUE)
|
|
|
|
- {
|
|
|
|
- // Add character to the queue
|
|
|
|
- CORE.Input.Keyboard.charPressedQueue[CORE.Input.Keyboard.charPressedQueueCount] = EvkeyToUnicodeLUT[event.code];
|
|
|
|
- CORE.Input.Keyboard.charPressedQueueCount++;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (CORE.Input.Keyboard.currentKeyState[CORE.Input.Keyboard.exitKey] == 1) CORE.Window.shouldClose = true;
|
|
|
|
-
|
|
|
|
- TRACELOGD("RPI: KEY_%s ScanCode: %4i KeyCode: %4i", (event.value == 0)? "UP" : "DOWN", event.code, keycode);
|
|
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ TRACELOG(LOG_DEBUG, "DRM: KEY_%s Keycode(linux): %4i KeyCode(raylib): %4i", (event.value == 0) ? "UP " : "DOWN", event.code, keycode);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
-// Input device events reading thread
|
|
|
|
-static void *EventThread(void *arg)
|
|
|
|
|
|
+static void PollGamepadEvents(void)
|
|
{
|
|
{
|
|
-/*
|
|
|
|
|
|
+ // Read gamepad event
|
|
struct input_event event = { 0 };
|
|
struct input_event event = { 0 };
|
|
- InputEventWorker *worker = (InputEventWorker *)arg;
|
|
|
|
-
|
|
|
|
- int touchAction = -1; // 0-TOUCH_ACTION_UP, 1-TOUCH_ACTION_DOWN, 2-TOUCH_ACTION_MOVE
|
|
|
|
- bool gestureUpdate = false; // Flag to note gestures require to update
|
|
|
|
|
|
|
|
- while (!CORE.Window.shouldClose)
|
|
|
|
|
|
+ for (int i = 0; i < platform.gamepadCount; i++)
|
|
{
|
|
{
|
|
- // Try to read data from the device and only continue if successful
|
|
|
|
- while (read(worker->fd, &event, sizeof(event)) == (int)sizeof(event))
|
|
|
|
|
|
+ if (!CORE.Input.Gamepad.ready[i]) continue;
|
|
|
|
+
|
|
|
|
+ // Register previous gamepad states
|
|
|
|
+ for (int k = 0; k < MAX_GAMEPAD_BUTTONS; k++) CORE.Input.Gamepad.previousButtonState[i][k] = CORE.Input.Gamepad.currentButtonState[i][k];
|
|
|
|
+
|
|
|
|
+ while (read(platform.gamepadStreamFd[i], &event, sizeof(event)) == (int)sizeof(event))
|
|
{
|
|
{
|
|
- // Relative movement parsing
|
|
|
|
- if (event.type == EV_REL)
|
|
|
|
|
|
+ if (event.type == EV_KEY)
|
|
{
|
|
{
|
|
- if (event.code == REL_X)
|
|
|
|
- {
|
|
|
|
- if (platform.cursorRelative)
|
|
|
|
- {
|
|
|
|
- CORE.Input.Mouse.currentPosition.x -= event.value;
|
|
|
|
- CORE.Input.Touch.position[0].x = CORE.Input.Mouse.currentPosition.x;
|
|
|
|
- }
|
|
|
|
- else
|
|
|
|
- {
|
|
|
|
- CORE.Input.Mouse.currentPosition.x += event.value;
|
|
|
|
- CORE.Input.Touch.position[0].x = CORE.Input.Mouse.currentPosition.x;
|
|
|
|
- }
|
|
|
|
|
|
+ if (event.code >= MAX_GAMEPAD_BUTTONS) continue;
|
|
|
|
|
|
- touchAction = 2; // TOUCH_ACTION_MOVE
|
|
|
|
- gestureUpdate = true;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (event.code == REL_Y)
|
|
|
|
- {
|
|
|
|
- if (platform.cursorRelative)
|
|
|
|
- {
|
|
|
|
- CORE.Input.Mouse.currentPosition.y -= event.value;
|
|
|
|
- CORE.Input.Touch.position[0].y = CORE.Input.Mouse.currentPosition.y;
|
|
|
|
- }
|
|
|
|
- else
|
|
|
|
- {
|
|
|
|
- CORE.Input.Mouse.currentPosition.y += event.value;
|
|
|
|
- CORE.Input.Touch.position[0].y = CORE.Input.Mouse.currentPosition.y;
|
|
|
|
- }
|
|
|
|
|
|
+ TRACELOG(LOG_DEBUG, "DRM: Gamepad %i button: %i, value: %i", i, event.code, event.value);
|
|
|
|
|
|
- touchAction = 2; // TOUCH_ACTION_MOVE
|
|
|
|
- gestureUpdate = true;
|
|
|
|
- }
|
|
|
|
|
|
+ // 1 - button pressed, 0 - button released
|
|
|
|
+ CORE.Input.Gamepad.currentButtonState[i][event.code] = event.value;
|
|
|
|
|
|
- if (event.code == REL_WHEEL) platform.eventWheelMove.y += event.value;
|
|
|
|
|
|
+ if (event.value == 1) CORE.Input.Gamepad.lastButtonPressed = event.code;
|
|
|
|
+ else CORE.Input.Gamepad.lastButtonPressed = 0; // GAMEPAD_BUTTON_UNKNOWN
|
|
}
|
|
}
|
|
-
|
|
|
|
- // Absolute movement parsing
|
|
|
|
- if (event.type == EV_ABS)
|
|
|
|
|
|
+ else if (event.type == EV_ABS)
|
|
{
|
|
{
|
|
- // Basic movement
|
|
|
|
- if (event.code == ABS_X)
|
|
|
|
- {
|
|
|
|
- CORE.Input.Mouse.currentPosition.x = (event.value - worker->absRange.x)*CORE.Window.screen.width/worker->absRange.width; // Scale according to absRange
|
|
|
|
- CORE.Input.Touch.position[0].x = (event.value - worker->absRange.x)*CORE.Window.screen.width/worker->absRange.width; // Scale according to absRange
|
|
|
|
-
|
|
|
|
- touchAction = 2; // TOUCH_ACTION_MOVE
|
|
|
|
- gestureUpdate = true;
|
|
|
|
- }
|
|
|
|
|
|
+ if (event.code >= MAX_GAMEPAD_AXIS) continue;
|
|
|
|
|
|
- if (event.code == ABS_Y)
|
|
|
|
- {
|
|
|
|
- CORE.Input.Mouse.currentPosition.y = (event.value - worker->absRange.y)*CORE.Window.screen.height/worker->absRange.height; // Scale according to absRange
|
|
|
|
- CORE.Input.Touch.position[0].y = (event.value - worker->absRange.y)*CORE.Window.screen.height/worker->absRange.height; // Scale according to absRange
|
|
|
|
|
|
+ TRACELOG(LOG_DEBUG, "DRM: Gamepad %i axis: %i, value: %i", i, platform.gamepadAbsAxisMap[i][event.code], event.value);
|
|
|
|
|
|
- touchAction = 2; // TOUCH_ACTION_MOVE
|
|
|
|
- gestureUpdate = true;
|
|
|
|
- }
|
|
|
|
|
|
+ int min = platform.gamepadAbsAxisRange[i][event.code][0];
|
|
|
|
+ int range = platform.gamepadAbsAxisRange[i][event.code][1];
|
|
|
|
|
|
- // Multitouch movement
|
|
|
|
- if (event.code == ABS_MT_SLOT) worker->touchSlot = event.value; // Remember the slot number for the folowing events
|
|
|
|
|
|
+ // NOTE: Scaling of event.value to get values between -1..1
|
|
|
|
+ CORE.Input.Gamepad.axisState[i][platform.gamepadAbsAxisMap[i][event.code]] = (2 * (float)(event.value - min) / range) - 1;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
|
|
- if (event.code == ABS_MT_POSITION_X)
|
|
|
|
- {
|
|
|
|
- if (worker->touchSlot < MAX_TOUCH_POINTS) CORE.Input.Touch.position[worker->touchSlot].x = (event.value - worker->absRange.x)*CORE.Window.screen.width/worker->absRange.width; // Scale according to absRange
|
|
|
|
- }
|
|
|
|
|
|
+static void PollMouseEvents(void)
|
|
|
|
+{
|
|
|
|
+ int fd = platform.mouseFd;
|
|
|
|
+ if (fd == -1) return;
|
|
|
|
|
|
- if (event.code == ABS_MT_POSITION_Y)
|
|
|
|
- {
|
|
|
|
- if (worker->touchSlot < MAX_TOUCH_POINTS) CORE.Input.Touch.position[worker->touchSlot].y = (event.value - worker->absRange.y)*CORE.Window.screen.height/worker->absRange.height; // Scale according to absRange
|
|
|
|
- }
|
|
|
|
|
|
+ struct input_event event = { 0 };
|
|
|
|
|
|
- if (event.code == ABS_MT_TRACKING_ID)
|
|
|
|
- {
|
|
|
|
- if ((event.value < 0) && (worker->touchSlot < MAX_TOUCH_POINTS))
|
|
|
|
- {
|
|
|
|
- // Touch has ended for this point
|
|
|
|
- CORE.Input.Touch.position[worker->touchSlot].x = -1;
|
|
|
|
- CORE.Input.Touch.position[worker->touchSlot].y = -1;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ int touchAction = -1; // 0-TOUCH_ACTION_UP, 1-TOUCH_ACTION_DOWN, 2-TOUCH_ACTION_MOVE
|
|
|
|
|
|
- // Touchscreen tap
|
|
|
|
- if (event.code == ABS_PRESSURE)
|
|
|
|
|
|
+ // Try to read data from the mouse/touch/gesture and only continue if successful
|
|
|
|
+ while (read(fd, &event, sizeof(event)) == (int)sizeof(event))
|
|
|
|
+ {
|
|
|
|
+ // Relative movement parsing
|
|
|
|
+ if (event.type == EV_REL)
|
|
|
|
+ {
|
|
|
|
+ if (event.code == REL_X)
|
|
|
|
+ {
|
|
|
|
+ if (platform.cursorRelative)
|
|
{
|
|
{
|
|
- int previousMouseLeftButtonState = platform.currentButtonStateEvdev[MOUSE_BUTTON_LEFT];
|
|
|
|
-
|
|
|
|
- if (!event.value && previousMouseLeftButtonState)
|
|
|
|
- {
|
|
|
|
- platform.currentButtonStateEvdev[MOUSE_BUTTON_LEFT] = 0;
|
|
|
|
-
|
|
|
|
- touchAction = 0; // TOUCH_ACTION_UP
|
|
|
|
- gestureUpdate = true;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (event.value && !previousMouseLeftButtonState)
|
|
|
|
- {
|
|
|
|
- platform.currentButtonStateEvdev[MOUSE_BUTTON_LEFT] = 1;
|
|
|
|
-
|
|
|
|
- touchAction = 1; // TOUCH_ACTION_DOWN
|
|
|
|
- gestureUpdate = true;
|
|
|
|
- }
|
|
|
|
|
|
+ CORE.Input.Mouse.currentPosition.x = event.value;
|
|
|
|
+ CORE.Input.Mouse.previousPosition.x = 0.0f;
|
|
}
|
|
}
|
|
|
|
+ else CORE.Input.Mouse.currentPosition.x += event.value;
|
|
|
|
+ CORE.Input.Touch.position[0].x = CORE.Input.Mouse.currentPosition.x;
|
|
|
|
|
|
|
|
+ touchAction = 2; // TOUCH_ACTION_MOVE
|
|
}
|
|
}
|
|
|
|
|
|
- // Button parsing
|
|
|
|
- if (event.type == EV_KEY)
|
|
|
|
|
|
+ if (event.code == REL_Y)
|
|
{
|
|
{
|
|
- // Mouse button parsing
|
|
|
|
- if ((event.code == BTN_TOUCH) || (event.code == BTN_LEFT))
|
|
|
|
|
|
+ if (platform.cursorRelative)
|
|
{
|
|
{
|
|
- platform.currentButtonStateEvdev[MOUSE_BUTTON_LEFT] = event.value;
|
|
|
|
-
|
|
|
|
- if (event.value > 0) touchAction = 1; // TOUCH_ACTION_DOWN
|
|
|
|
- else touchAction = 0; // TOUCH_ACTION_UP
|
|
|
|
- gestureUpdate = true;
|
|
|
|
|
|
+ CORE.Input.Mouse.currentPosition.y = event.value;
|
|
|
|
+ CORE.Input.Mouse.previousPosition.y = 0.0f;
|
|
}
|
|
}
|
|
|
|
+ else CORE.Input.Mouse.currentPosition.y += event.value;
|
|
|
|
+ CORE.Input.Touch.position[0].y = CORE.Input.Mouse.currentPosition.y;
|
|
|
|
|
|
- if (event.code == BTN_RIGHT) platform.currentButtonStateEvdev[MOUSE_BUTTON_RIGHT] = event.value;
|
|
|
|
- if (event.code == BTN_MIDDLE) platform.currentButtonStateEvdev[MOUSE_BUTTON_MIDDLE] = event.value;
|
|
|
|
- if (event.code == BTN_SIDE) platform.currentButtonStateEvdev[MOUSE_BUTTON_SIDE] = event.value;
|
|
|
|
- if (event.code == BTN_EXTRA) platform.currentButtonStateEvdev[MOUSE_BUTTON_EXTRA] = event.value;
|
|
|
|
- if (event.code == BTN_FORWARD) platform.currentButtonStateEvdev[MOUSE_BUTTON_FORWARD] = event.value;
|
|
|
|
- if (event.code == BTN_BACK) platform.currentButtonStateEvdev[MOUSE_BUTTON_BACK] = event.value;
|
|
|
|
|
|
+ touchAction = 2; // TOUCH_ACTION_MOVE
|
|
}
|
|
}
|
|
|
|
|
|
- // Screen confinement
|
|
|
|
- if (!CORE.Input.Mouse.cursorHidden)
|
|
|
|
|
|
+ if (event.code == REL_WHEEL) platform.eventWheelMove.y += event.value;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ // Absolute movement parsing
|
|
|
|
+ if (event.type == EV_ABS)
|
|
|
|
+ {
|
|
|
|
+ // Basic movement
|
|
|
|
+ if (event.code == ABS_X)
|
|
{
|
|
{
|
|
- if (CORE.Input.Mouse.currentPosition.x < 0) CORE.Input.Mouse.currentPosition.x = 0;
|
|
|
|
- if (CORE.Input.Mouse.currentPosition.x > CORE.Window.screen.width/CORE.Input.Mouse.scale.x) CORE.Input.Mouse.currentPosition.x = CORE.Window.screen.width/CORE.Input.Mouse.scale.x;
|
|
|
|
|
|
+ CORE.Input.Mouse.currentPosition.x = (event.value - platform.absRange.x)*CORE.Window.screen.width/platform.absRange.width; // Scale according to absRange
|
|
|
|
+ CORE.Input.Touch.position[0].x = (event.value - platform.absRange.x)*CORE.Window.screen.width/platform.absRange.width; // Scale according to absRange
|
|
|
|
|
|
- if (CORE.Input.Mouse.currentPosition.y < 0) CORE.Input.Mouse.currentPosition.y = 0;
|
|
|
|
- if (CORE.Input.Mouse.currentPosition.y > CORE.Window.screen.height/CORE.Input.Mouse.scale.y) CORE.Input.Mouse.currentPosition.y = CORE.Window.screen.height/CORE.Input.Mouse.scale.y;
|
|
|
|
|
|
+ touchAction = 2; // TOUCH_ACTION_MOVE
|
|
}
|
|
}
|
|
|
|
|
|
- // Update touch point count
|
|
|
|
- CORE.Input.Touch.pointCount = 0;
|
|
|
|
- for (int i = 0; i < MAX_TOUCH_POINTS; i++)
|
|
|
|
|
|
+ if (event.code == ABS_Y)
|
|
{
|
|
{
|
|
- if (CORE.Input.Touch.position[i].x >= 0) CORE.Input.Touch.pointCount++;
|
|
|
|
|
|
+ CORE.Input.Mouse.currentPosition.y = (event.value - platform.absRange.y)*CORE.Window.screen.height/platform.absRange.height; // Scale according to absRange
|
|
|
|
+ CORE.Input.Touch.position[0].y = (event.value - platform.absRange.y)*CORE.Window.screen.height/platform.absRange.height; // Scale according to absRange
|
|
|
|
+
|
|
|
|
+ touchAction = 2; // TOUCH_ACTION_MOVE
|
|
}
|
|
}
|
|
|
|
|
|
-#if defined(SUPPORT_GESTURES_SYSTEM)
|
|
|
|
- if (gestureUpdate)
|
|
|
|
|
|
+ // Multitouch movement
|
|
|
|
+ if (event.code == ABS_MT_SLOT) platform.touchSlot = event.value; // Remember the slot number for the folowing events
|
|
|
|
+
|
|
|
|
+ if (event.code == ABS_MT_POSITION_X)
|
|
{
|
|
{
|
|
- GestureEvent gestureEvent = { 0 };
|
|
|
|
|
|
+ if (platform.touchSlot < MAX_TOUCH_POINTS) CORE.Input.Touch.position[platform.touchSlot].x = (event.value - platform.absRange.x)*CORE.Window.screen.width/platform.absRange.width; // Scale according to absRange
|
|
|
|
+ }
|
|
|
|
|
|
- gestureEvent.touchAction = touchAction;
|
|
|
|
- gestureEvent.pointCount = CORE.Input.Touch.pointCount;
|
|
|
|
|
|
+ if (event.code == ABS_MT_POSITION_Y)
|
|
|
|
+ {
|
|
|
|
+ if (platform.touchSlot < MAX_TOUCH_POINTS) CORE.Input.Touch.position[platform.touchSlot].y = (event.value - platform.absRange.y)*CORE.Window.screen.height/platform.absRange.height; // Scale according to absRange
|
|
|
|
+ }
|
|
|
|
|
|
- for (int i = 0; i < MAX_TOUCH_POINTS; i++)
|
|
|
|
|
|
+ if (event.code == ABS_MT_TRACKING_ID)
|
|
|
|
+ {
|
|
|
|
+ if ((event.value < 0) && (platform.touchSlot < MAX_TOUCH_POINTS))
|
|
{
|
|
{
|
|
- gestureEvent.pointId[i] = i;
|
|
|
|
- gestureEvent.position[i] = CORE.Input.Touch.position[i];
|
|
|
|
|
|
+ // Touch has ended for this point
|
|
|
|
+ CORE.Input.Touch.position[platform.touchSlot].x = -1;
|
|
|
|
+ CORE.Input.Touch.position[platform.touchSlot].y = -1;
|
|
}
|
|
}
|
|
-
|
|
|
|
- ProcessGestureEvent(gestureEvent);
|
|
|
|
}
|
|
}
|
|
-#endif
|
|
|
|
- }
|
|
|
|
|
|
|
|
- WaitTime(0.005); // Sleep for 5ms to avoid hogging CPU time
|
|
|
|
- }
|
|
|
|
|
|
+ // Touchscreen tap
|
|
|
|
+ if (event.code == ABS_PRESSURE)
|
|
|
|
+ {
|
|
|
|
+ int previousMouseLeftButtonState = platform.currentButtonStateEvdev[MOUSE_BUTTON_LEFT];
|
|
|
|
|
|
- close(worker->fd);
|
|
|
|
-*/
|
|
|
|
- return NULL;
|
|
|
|
-}
|
|
|
|
|
|
+ if (!event.value && previousMouseLeftButtonState)
|
|
|
|
+ {
|
|
|
|
+ platform.currentButtonStateEvdev[MOUSE_BUTTON_LEFT] = 0;
|
|
|
|
|
|
-// Initialize gamepad system
|
|
|
|
-static void InitGamepad(void)
|
|
|
|
-{
|
|
|
|
- char gamepadDev[128] = { 0 };
|
|
|
|
|
|
+ touchAction = 0; // TOUCH_ACTION_UP
|
|
|
|
+ }
|
|
|
|
|
|
- for (int i = 0; i < MAX_GAMEPADS; i++)
|
|
|
|
- {
|
|
|
|
- sprintf(gamepadDev, "%s%i", DEFAULT_GAMEPAD_DEV, i);
|
|
|
|
|
|
+ if (event.value && !previousMouseLeftButtonState)
|
|
|
|
+ {
|
|
|
|
+ platform.currentButtonStateEvdev[MOUSE_BUTTON_LEFT] = 1;
|
|
|
|
+
|
|
|
|
+ touchAction = 1; // TOUCH_ACTION_DOWN
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
|
|
- if ((platform.gamepadStreamFd[i] = open(gamepadDev, O_RDONLY | O_NONBLOCK)) < 0)
|
|
|
|
- {
|
|
|
|
- // NOTE: Only show message for first gamepad
|
|
|
|
- if (i == 0) TRACELOG(LOG_WARNING, "RPI: Failed to open Gamepad device, no gamepad available");
|
|
|
|
}
|
|
}
|
|
- else
|
|
|
|
|
|
+
|
|
|
|
+ // Button parsing
|
|
|
|
+ if (event.type == EV_KEY)
|
|
{
|
|
{
|
|
- CORE.Input.Gamepad.ready[i] = true;
|
|
|
|
|
|
+ // Mouse button parsing
|
|
|
|
+ if ((event.code == BTN_TOUCH) || (event.code == BTN_LEFT))
|
|
|
|
+ {
|
|
|
|
+ platform.currentButtonStateEvdev[MOUSE_BUTTON_LEFT] = event.value;
|
|
|
|
|
|
- // NOTE: Only show message for first gamepad
|
|
|
|
- if (i == 0) TRACELOG(LOG_INFO, "RPI: Gamepad device initialized successfully");
|
|
|
|
|
|
+ if (event.value > 0) touchAction = 1; // TOUCH_ACTION_DOWN
|
|
|
|
+ else touchAction = 0; // TOUCH_ACTION_UP
|
|
|
|
+ }
|
|
|
|
|
|
- ioctl(platform.gamepadStreamFd[i], JSIOCGNAME(64), &CORE.Input.Gamepad.name[i]);
|
|
|
|
- ioctl(platform.gamepadStreamFd[i], JSIOCGAXES, &CORE.Input.Gamepad.axisCount[i]);
|
|
|
|
|
|
+ if (event.code == BTN_RIGHT) platform.currentButtonStateEvdev[MOUSE_BUTTON_RIGHT] = event.value;
|
|
|
|
+ if (event.code == BTN_MIDDLE) platform.currentButtonStateEvdev[MOUSE_BUTTON_MIDDLE] = event.value;
|
|
|
|
+ if (event.code == BTN_SIDE) platform.currentButtonStateEvdev[MOUSE_BUTTON_SIDE] = event.value;
|
|
|
|
+ if (event.code == BTN_EXTRA) platform.currentButtonStateEvdev[MOUSE_BUTTON_EXTRA] = event.value;
|
|
|
|
+ if (event.code == BTN_FORWARD) platform.currentButtonStateEvdev[MOUSE_BUTTON_FORWARD] = event.value;
|
|
|
|
+ if (event.code == BTN_BACK) platform.currentButtonStateEvdev[MOUSE_BUTTON_BACK] = event.value;
|
|
}
|
|
}
|
|
- }
|
|
|
|
-}
|
|
|
|
|
|
|
|
-// Process Gamepad (/dev/input/js0)
|
|
|
|
-static void PollGamepadEvents(void)
|
|
|
|
-{
|
|
|
|
- #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
|
|
|
|
- };
|
|
|
|
|
|
+ // Screen confinement
|
|
|
|
+ if (!CORE.Input.Mouse.cursorHidden)
|
|
|
|
+ {
|
|
|
|
+ if (CORE.Input.Mouse.currentPosition.x < 0) CORE.Input.Mouse.currentPosition.x = 0;
|
|
|
|
+ if (CORE.Input.Mouse.currentPosition.x > CORE.Window.screen.width/CORE.Input.Mouse.scale.x) CORE.Input.Mouse.currentPosition.x = CORE.Window.screen.width/CORE.Input.Mouse.scale.x;
|
|
|
|
|
|
- // Read gamepad event
|
|
|
|
- struct js_event gamepadEvent = { 0 };
|
|
|
|
|
|
+ if (CORE.Input.Mouse.currentPosition.y < 0) CORE.Input.Mouse.currentPosition.y = 0;
|
|
|
|
+ if (CORE.Input.Mouse.currentPosition.y > CORE.Window.screen.height/CORE.Input.Mouse.scale.y) CORE.Input.Mouse.currentPosition.y = CORE.Window.screen.height/CORE.Input.Mouse.scale.y;
|
|
|
|
+ }
|
|
|
|
|
|
- for (int i = 0; i < MAX_GAMEPADS; i++)
|
|
|
|
- {
|
|
|
|
- if (CORE.Input.Gamepad.ready[i])
|
|
|
|
|
|
+ // Update touch point count
|
|
|
|
+ CORE.Input.Touch.pointCount = 0;
|
|
|
|
+ for (int i = 0; i < MAX_TOUCH_POINTS; i++)
|
|
{
|
|
{
|
|
- // Register previous gamepad states
|
|
|
|
- for (int k = 0; k < MAX_GAMEPAD_BUTTONS; k++) CORE.Input.Gamepad.previousButtonState[i][k] = CORE.Input.Gamepad.currentButtonState[i][k];
|
|
|
|
|
|
+ if (CORE.Input.Touch.position[i].x >= 0) CORE.Input.Touch.pointCount++;
|
|
|
|
+ }
|
|
|
|
|
|
- while (read(platform.gamepadStreamFd[i], &gamepadEvent, sizeof(struct js_event)) == (int)sizeof(struct js_event))
|
|
|
|
- {
|
|
|
|
- gamepadEvent.type &= ~JS_EVENT_INIT; // Ignore synthetic events
|
|
|
|
|
|
+#if defined(SUPPORT_GESTURES_SYSTEM)
|
|
|
|
+ if (touchAction > -1)
|
|
|
|
+ {
|
|
|
|
+ GestureEvent gestureEvent = { 0 };
|
|
|
|
|
|
- // Process gamepad events by type
|
|
|
|
- if (gamepadEvent.type == JS_EVENT_BUTTON)
|
|
|
|
- {
|
|
|
|
- TRACELOG(LOG_DEBUG, "RPI: Gamepad %i button: %i, value: %i", i, gamepadEvent.number, gamepadEvent.value);
|
|
|
|
|
|
+ gestureEvent.touchAction = touchAction;
|
|
|
|
+ gestureEvent.pointCount = CORE.Input.Touch.pointCount;
|
|
|
|
|
|
- if (gamepadEvent.number < MAX_GAMEPAD_BUTTONS)
|
|
|
|
- {
|
|
|
|
- // 1 - button pressed, 0 - button released
|
|
|
|
- CORE.Input.Gamepad.currentButtonState[i][gamepadEvent.number] = (int)gamepadEvent.value;
|
|
|
|
|
|
+ for (int i = 0; i < MAX_TOUCH_POINTS; i++)
|
|
|
|
+ {
|
|
|
|
+ gestureEvent.pointId[i] = i;
|
|
|
|
+ gestureEvent.position[i] = CORE.Input.Touch.position[i];
|
|
|
|
+ }
|
|
|
|
|
|
- if ((int)gamepadEvent.value == 1) CORE.Input.Gamepad.lastButtonPressed = gamepadEvent.number;
|
|
|
|
- else CORE.Input.Gamepad.lastButtonPressed = 0; // GAMEPAD_BUTTON_UNKNOWN
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- else if (gamepadEvent.type == JS_EVENT_AXIS)
|
|
|
|
- {
|
|
|
|
- TRACELOG(LOG_DEBUG, "RPI: Gamepad %i axis: %i, value: %i", i, gamepadEvent.number, gamepadEvent.value);
|
|
|
|
|
|
+ ProcessGestureEvent(gestureEvent);
|
|
|
|
|
|
- if (gamepadEvent.number < MAX_GAMEPAD_AXIS)
|
|
|
|
- {
|
|
|
|
- // NOTE: Scaling of gamepadEvent.value to get values between -1..1
|
|
|
|
- CORE.Input.Gamepad.axisState[i][gamepadEvent.number] = (float)gamepadEvent.value/32768;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
|
|
+ touchAction = -1;
|
|
}
|
|
}
|
|
|
|
+#endif
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|