Updating rcore_drm.c to only use one api for input
This commit is contained in:
parent
b905dafca0
commit
1f50818430
|
|
@ -71,27 +71,12 @@
|
|||
//----------------------------------------------------------------------------------
|
||||
#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
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
// 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 {
|
||||
// Display data
|
||||
int fd; // File descriptor for /dev/dri/...
|
||||
|
|
@ -108,9 +93,6 @@ typedef struct {
|
|||
EGLContext context; // Graphic context, mode in which drawing can be done
|
||||
EGLConfig config; // Graphic config
|
||||
|
||||
// Input data
|
||||
InputEventWorker eventWorker[10]; // List of worker threads for every monitored "/dev/input/event<N>"
|
||||
|
||||
// Keyboard data
|
||||
int defaultKeyboardMode; // Default keyboard mode
|
||||
bool eventKeyboardMode; // Keyboard in event mode
|
||||
|
|
@ -129,7 +111,9 @@ typedef struct {
|
|||
|
||||
// Gamepad data
|
||||
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;
|
||||
|
||||
//----------------------------------------------------------------------------------
|
||||
|
|
@ -145,6 +129,8 @@ static PlatformData platform = { 0 }; // Platform specific data
|
|||
// 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:
|
||||
// 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[] = {
|
||||
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,
|
||||
|
|
@ -178,19 +164,17 @@ static const int EvkeyToUnicodeLUT[] = {
|
|||
int InitPlatform(void); // Initialize platform (graphics, inputs and more)
|
||||
void ClosePlatform(void); // Close platform
|
||||
|
||||
#if defined(SUPPORT_SSH_KEYBOARD_RPI)
|
||||
static void InitKeyboard(void); // Initialize raw keyboard system
|
||||
static void RestoreKeyboard(void); // Restore keyboard system
|
||||
#if defined(SUPPORT_SSH_KEYBOARD_RPI)
|
||||
static void ProcessKeyboard(void); // Process keyboard events
|
||||
#endif
|
||||
|
||||
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 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 FindExactConnectorMode(const drmModeConnector *connector, uint width, uint height, uint fps, bool allowInterlaced); // Search exactly matching DRM connector mode in connector's list
|
||||
|
|
@ -600,172 +584,7 @@ void PollInputEvents(void)
|
|||
|
||||
// Handle the mouse/touch/gestures events:
|
||||
// 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 +942,11 @@ int InitPlatform(void)
|
|||
// Initialize input events system
|
||||
//----------------------------------------------------------------------------
|
||||
InitEvdevInput(); // Evdev inputs initialization
|
||||
InitGamepad(); // Gamepad init
|
||||
|
||||
#if defined(SUPPORT_SSH_KEYBOARD_RPI)
|
||||
InitKeyboard(); // Keyboard init (stdin)
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
// Initialize storage system
|
||||
|
|
@ -1203,28 +1025,30 @@ void ClosePlatform(void)
|
|||
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
|
||||
|
||||
// Close the evdev keyboard
|
||||
// Close the evdev devices
|
||||
|
||||
if (platform.mouseFd != -1) {
|
||||
close(platform.mouseFd);
|
||||
platform.mouseFd = -1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < platform.gamepadCount; i++)
|
||||
{
|
||||
close(platform.gamepadStreamFd[i]);
|
||||
platform.gamepadStreamFd[i] = -1;
|
||||
}
|
||||
|
||||
if (platform.keyboardFd != -1)
|
||||
{
|
||||
close(platform.keyboardFd);
|
||||
platform.keyboardFd = -1;
|
||||
}
|
||||
|
||||
for (int i = 0; i < sizeof(platform.eventWorker)/sizeof(InputEventWorker); ++i)
|
||||
{
|
||||
if (platform.eventWorker[i].threadId)
|
||||
{
|
||||
pthread_join(platform.eventWorker[i].threadId, NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(SUPPORT_SSH_KEYBOARD_RPI)
|
||||
|
||||
// Initialize Keyboard system (using standard input)
|
||||
static void InitKeyboard(void)
|
||||
{
|
||||
|
|
@ -1282,7 +1106,6 @@ static void RestoreKeyboard(void)
|
|||
ioctl(STDIN_FILENO, KDSKBMODE, platform.defaultKeyboardMode);
|
||||
}
|
||||
|
||||
#if defined(SUPPORT_SSH_KEYBOARD_RPI)
|
||||
// Process keyboard inputs
|
||||
static void ProcessKeyboard(void)
|
||||
{
|
||||
|
|
@ -1408,6 +1231,7 @@ static void InitEvdevInput(void)
|
|||
|
||||
// Initialise keyboard file descriptor
|
||||
platform.keyboardFd = -1;
|
||||
platform.mouseFd = -1;
|
||||
|
||||
// Reset variables
|
||||
for (int i = 0; i < MAX_TOUCH_POINTS; ++i)
|
||||
|
|
@ -1453,62 +1277,18 @@ static void ConfigureEvdevDevice(char *device)
|
|||
#define LONG(x) ((x)/BITS_PER_LONG)
|
||||
#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 absBits[NBITS(ABS_MAX)] = { 0 };
|
||||
unsigned long relBits[NBITS(REL_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
|
||||
fd = open(device, O_RDONLY | O_NONBLOCK);
|
||||
int fd = open(device, O_RDONLY | O_NONBLOCK);
|
||||
if (fd < 0)
|
||||
{
|
||||
TRACELOG(LOG_WARNING, "RPI: Failed to open input device: %s", device);
|
||||
TRACELOG(LOG_WARNING, "Failed to open input device: %s", device);
|
||||
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.
|
||||
// It could be many things, even as simple as a power button...
|
||||
|
|
@ -1516,149 +1296,166 @@ static void ConfigureEvdevDevice(char *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);
|
||||
|
||||
// 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))
|
||||
// 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++)
|
||||
{
|
||||
hasAbsMulti = true;
|
||||
if (TEST_BIT(absBits, axis)) {
|
||||
isGamepad = true;
|
||||
absAxisCount++;
|
||||
|
||||
// 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;
|
||||
ioctl(fd, EVIOCGABS(axis), &absinfo[axis]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check for relative movement support (usually mouse)
|
||||
// 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;
|
||||
}
|
||||
|
||||
if (TEST_BIT(evBits, EV_REL))
|
||||
{
|
||||
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))
|
||||
{
|
||||
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)
|
||||
for (int button = BTN_TRIGGER_HAPPY1; button <= BTN_TRIGGER_HAPPY40; button++)
|
||||
{
|
||||
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
|
||||
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))
|
||||
const char *deviceKindStr = "unknown";
|
||||
if (isMouse || isTouch)
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
// 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;
|
||||
deviceKindStr = "mouse";
|
||||
if (platform.mouseFd != -1) close(platform.mouseFd);
|
||||
|
||||
// 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);
|
||||
//}
|
||||
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)
|
||||
// Find touchscreen with the highest index
|
||||
int maxTouchNumber = -1;
|
||||
|
||||
for (int i = 0; i < sizeof(platform.eventWorker)/sizeof(InputEventWorker); ++i)
|
||||
{
|
||||
if (platform.eventWorker[i].isTouch && (platform.eventWorker[i].eventNum > maxTouchNumber)) maxTouchNumber = platform.eventWorker[i].eventNum;
|
||||
}
|
||||
|
||||
// Find touchscreens with lower indexes
|
||||
for (int i = 0; i < sizeof(platform.eventWorker)/sizeof(InputEventWorker); ++i)
|
||||
{
|
||||
if (platform.eventWorker[i].isTouch && (platform.eventWorker[i].eventNum < maxTouchNumber))
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (absAxisCount > 0)
|
||||
{
|
||||
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 close(fd); // We are not interested in this device
|
||||
//-------------------------------------------------------------------------------------------------------
|
||||
}
|
||||
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;
|
||||
|
||||
if (absAxisCount > 0)
|
||||
{
|
||||
// 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++)
|
||||
{
|
||||
platform.gamepadAbsAxisRange[index][axisIndex][0] = absinfo[axisIndex].minimum;
|
||||
platform.gamepadAbsAxisRange[index][axisIndex][1] = absinfo[axisIndex].maximum - absinfo[axisIndex].minimum;
|
||||
|
||||
platform.gamepadAbsAxisMap[index][axis] = axisIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
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
|
||||
|
|
@ -1722,27 +1519,70 @@ static void PollKeyboardEvents(void)
|
|||
|
||||
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);
|
||||
TRACELOGD("KEY_%s ScanCode: %4i KeyCode: %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 };
|
||||
|
||||
for (int i = 0; i < platform.gamepadCount; i++)
|
||||
{
|
||||
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))
|
||||
{
|
||||
if (event.type == EV_KEY)
|
||||
{
|
||||
if (event.code >= MAX_GAMEPAD_BUTTONS) return;
|
||||
|
||||
TRACELOG(LOG_DEBUG, "Gamepad %i button: %i, value: %i", i, event.code, event.value);
|
||||
|
||||
// 1 - button pressed, 0 - button released
|
||||
CORE.Input.Gamepad.currentButtonState[i][event.code] = event.value;
|
||||
|
||||
if (event.value == 1) CORE.Input.Gamepad.lastButtonPressed = event.code;
|
||||
else CORE.Input.Gamepad.lastButtonPressed = 0; // GAMEPAD_BUTTON_UNKNOWN
|
||||
}
|
||||
else if (event.type == EV_ABS)
|
||||
{
|
||||
if (event.code >= MAX_GAMEPAD_AXIS) return;
|
||||
|
||||
TRACELOG(LOG_DEBUG, "Gamepad %i axis: %i, value: %i", i, platform.gamepadAbsAxisMap[i][event.code], event.value);
|
||||
|
||||
if (event.type == EV_REL) CORE.Input.Gamepad.axisState[i][event.code] += (float)event.value;
|
||||
else
|
||||
{
|
||||
int min = platform.gamepadAbsAxisRange[i][event.code][0];
|
||||
int range = platform.gamepadAbsAxisRange[i][event.code][1];
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void PollMouseEvents(void)
|
||||
{
|
||||
int fd = platform.mouseFd;
|
||||
if (fd == -1) return;
|
||||
|
||||
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)
|
||||
{
|
||||
// Try to read data from the device and only continue if successful
|
||||
while (read(worker->fd, &event, sizeof(event)) == (int)sizeof(event))
|
||||
// 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)
|
||||
|
|
@ -1751,34 +1591,26 @@ static void *EventThread(void *arg)
|
|||
{
|
||||
if (platform.cursorRelative)
|
||||
{
|
||||
CORE.Input.Mouse.currentPosition.x -= event.value;
|
||||
CORE.Input.Touch.position[0].x = CORE.Input.Mouse.currentPosition.x;
|
||||
CORE.Input.Mouse.currentPosition.x = event.value;
|
||||
CORE.Input.Mouse.previousPosition.x = 0.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
CORE.Input.Mouse.currentPosition.x += event.value;
|
||||
else CORE.Input.Mouse.currentPosition.x += event.value;
|
||||
CORE.Input.Touch.position[0].x = CORE.Input.Mouse.currentPosition.x;
|
||||
}
|
||||
|
||||
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;
|
||||
CORE.Input.Mouse.currentPosition.y = event.value;
|
||||
CORE.Input.Mouse.previousPosition.y = 0.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
CORE.Input.Mouse.currentPosition.y += event.value;
|
||||
else CORE.Input.Mouse.currentPosition.y += event.value;
|
||||
CORE.Input.Touch.position[0].y = CORE.Input.Mouse.currentPosition.y;
|
||||
}
|
||||
|
||||
touchAction = 2; // TOUCH_ACTION_MOVE
|
||||
gestureUpdate = true;
|
||||
}
|
||||
|
||||
if (event.code == REL_WHEEL) platform.eventWheelMove.y += event.value;
|
||||
|
|
@ -1790,42 +1622,40 @@ static void *EventThread(void *arg)
|
|||
// 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
|
||||
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
|
||||
gestureUpdate = true;
|
||||
}
|
||||
|
||||
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
|
||||
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
|
||||
gestureUpdate = true;
|
||||
}
|
||||
|
||||
// Multitouch movement
|
||||
if (event.code == ABS_MT_SLOT) worker->touchSlot = event.value; // Remember the slot number for the folowing events
|
||||
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 (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
|
||||
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 (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
|
||||
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) && (worker->touchSlot < MAX_TOUCH_POINTS))
|
||||
if ((event.value < 0) && (platform.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;
|
||||
CORE.Input.Touch.position[platform.touchSlot].x = -1;
|
||||
CORE.Input.Touch.position[platform.touchSlot].y = -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1839,7 +1669,6 @@ static void *EventThread(void *arg)
|
|||
platform.currentButtonStateEvdev[MOUSE_BUTTON_LEFT] = 0;
|
||||
|
||||
touchAction = 0; // TOUCH_ACTION_UP
|
||||
gestureUpdate = true;
|
||||
}
|
||||
|
||||
if (event.value && !previousMouseLeftButtonState)
|
||||
|
|
@ -1847,7 +1676,6 @@ static void *EventThread(void *arg)
|
|||
platform.currentButtonStateEvdev[MOUSE_BUTTON_LEFT] = 1;
|
||||
|
||||
touchAction = 1; // TOUCH_ACTION_DOWN
|
||||
gestureUpdate = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1863,7 +1691,6 @@ static void *EventThread(void *arg)
|
|||
|
||||
if (event.value > 0) touchAction = 1; // TOUCH_ACTION_DOWN
|
||||
else touchAction = 0; // TOUCH_ACTION_UP
|
||||
gestureUpdate = true;
|
||||
}
|
||||
|
||||
if (event.code == BTN_RIGHT) platform.currentButtonStateEvdev[MOUSE_BUTTON_RIGHT] = event.value;
|
||||
|
|
@ -1892,7 +1719,7 @@ static void *EventThread(void *arg)
|
|||
}
|
||||
|
||||
#if defined(SUPPORT_GESTURES_SYSTEM)
|
||||
if (gestureUpdate)
|
||||
if (touchAction > -1)
|
||||
{
|
||||
GestureEvent gestureEvent = { 0 };
|
||||
|
||||
|
|
@ -1906,100 +1733,11 @@ static void *EventThread(void *arg)
|
|||
}
|
||||
|
||||
ProcessGestureEvent(gestureEvent);
|
||||
|
||||
touchAction = -1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
WaitTime(0.005); // Sleep for 5ms to avoid hogging CPU time
|
||||
}
|
||||
|
||||
close(worker->fd);
|
||||
*/
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Initialize gamepad system
|
||||
static void InitGamepad(void)
|
||||
{
|
||||
char gamepadDev[128] = { 0 };
|
||||
|
||||
for (int i = 0; i < MAX_GAMEPADS; i++)
|
||||
{
|
||||
sprintf(gamepadDev, "%s%i", DEFAULT_GAMEPAD_DEV, i);
|
||||
|
||||
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
|
||||
{
|
||||
CORE.Input.Gamepad.ready[i] = true;
|
||||
|
||||
// NOTE: Only show message for first gamepad
|
||||
if (i == 0) TRACELOG(LOG_INFO, "RPI: Gamepad device initialized successfully");
|
||||
|
||||
ioctl(platform.gamepadStreamFd[i], JSIOCGNAME(64), &CORE.Input.Gamepad.name[i]);
|
||||
ioctl(platform.gamepadStreamFd[i], JSIOCGAXES, &CORE.Input.Gamepad.axisCount[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
};
|
||||
|
||||
// Read gamepad event
|
||||
struct js_event gamepadEvent = { 0 };
|
||||
|
||||
for (int i = 0; i < MAX_GAMEPADS; i++)
|
||||
{
|
||||
if (CORE.Input.Gamepad.ready[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];
|
||||
|
||||
while (read(platform.gamepadStreamFd[i], &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)
|
||||
{
|
||||
TRACELOG(LOG_DEBUG, "RPI: Gamepad %i button: %i, value: %i", i, gamepadEvent.number, gamepadEvent.value);
|
||||
|
||||
if (gamepadEvent.number < MAX_GAMEPAD_BUTTONS)
|
||||
{
|
||||
// 1 - button pressed, 0 - button released
|
||||
CORE.Input.Gamepad.currentButtonState[i][gamepadEvent.number] = (int)gamepadEvent.value;
|
||||
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Search matching DRM mode in connector's mode list
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user