Browse Source

Overhaul mouse and touch for RaspberryPi \n\nNow all '/dev/input/event*' devices are now used for input. No longer uses '/dev/input/mouse*', keyboard and gamepad continue to use existing method\nMultitouch is now supported on RPi with 10 point multitouch\nFixed bugs with IsMouseButtonPressed(Used to constantly fire when holding button) and GetMouseWheelMove(Did not work)\n Fixed exesive CPU usage of GamepadThread

pull/672/head
Berni8k 6 years ago
parent
commit
e07ec6a2e8
2 changed files with 349 additions and 145 deletions
  1. +348
    -144
      src/core.c
  2. +1
    -1
      src/raylib.h

+ 348
- 144
src/core.c View File

@ -189,6 +189,7 @@
#include <unistd.h> // POSIX standard function definitions - read(), close(), STDIN_FILENO
#include <termios.h> // POSIX terminal control definitions - tcgetattr(), tcsetattr()
#include <pthread.h> // POSIX threads management (mouse input)
#include <dirent.h> // POSIX directory browsing
#include <sys/ioctl.h> // UNIX System call for device-specific input/output operations - ioctl()
#include <linux/kd.h> // Linux: KDSKBMODE, K_MEDIUMRAM constants definition
@ -223,9 +224,8 @@
#if defined(PLATFORM_RPI)
// Old device inputs system
#define DEFAULT_KEYBOARD_DEV STDIN_FILENO // Standard input
#define DEFAULT_MOUSE_DEV "/dev/input/mouse0" // Mouse input
#define DEFAULT_TOUCH_DEV "/dev/input/event4" // Touch input virtual device (created by ts_uinput)
#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
// New device input events (evdev) (must be detected)
//#define DEFAULT_KEYBOARD_DEV "/dev/input/eventN"
@ -329,11 +329,22 @@ static int currentMouseWheelY = 0; // Registers current mouse wheel
#if defined(PLATFORM_RPI)
static int mouseStream = -1; // Mouse device file descriptor
static bool mouseReady = false; // Flag to know if mouse is ready
static pthread_t mouseThreadId; // Mouse reading thread id
static int touchStream = -1; // Touch device file descriptor
static bool touchReady = false; // Flag to know if touch interface is ready
static pthread_t touchThreadId; // Touch reading thread id
static char currentMouseStateEvdev[3] = { 0 }; // Holds the new mouse state for the next polling event to grab (Can't be written directly due to multithreading, app could miss the update)
typedef struct {
pthread_t threadId; // Event reading thread id
int fd; // File descriptor to the device it is assigned to
float sensitivity; // Sensitivitzy multiplier for relative mouse movements
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;
static InputEventWorker eventWorkers[10]; // List of worker threads for every monitored "/dev/input/event<N>"
#endif
#if defined(PLATFORM_WEB)
static bool toggleCursorLock = false; // Ask for cursor pointer lock on next click
@ -447,9 +458,8 @@ static void InitKeyboard(void); // Init raw keyboard sys
static void ProcessKeyboard(void); // Process keyboard events
static void RestoreKeyboard(void); // Restore keyboard system
static void InitMouse(void); // Mouse initialization (including mouse thread)
static void *MouseThread(void *arg); // Mouse reading thread
static void InitTouch(void); // Touch device initialization (including touch thread)
static void *TouchThread(void *arg); // Touch device reading thread
static void EventThreadSpawn(char* device); // Indetifies a input device and spawns a thread to handle it if needed
static void *EventThread(void *arg); // Input device event reading thread
static void InitGamepad(void); // Init raw gamepad input
static void *GamepadThread(void *arg); // Mouse reading thread
#endif
@ -566,7 +576,6 @@ void InitWindow(int width, int height, const char *title)
#if defined(PLATFORM_RPI)
// Init raw input system
InitMouse(); // Mouse init
InitTouch(); // Touch init
InitKeyboard(); // Keyboard init
InitGamepad(); // Gamepad init
#endif
@ -661,8 +670,13 @@ void CloseWindow(void)
windowShouldClose = true; // Added to force threads to exit when the close window is called
pthread_join(mouseThreadId, NULL);
pthread_join(touchThreadId, NULL);
for (int i = 0; i < sizeof(eventWorkers)/sizeof(InputEventWorker); ++i)
{
if(eventWorkers[i].threadId == 0)
{
pthread_join(eventWorkers[i].threadId, NULL);
}
}
pthread_join(gamepadThreadId, NULL);
#endif
@ -1984,7 +1998,7 @@ bool IsMouseButtonPressed(int button)
#else
if ((currentMouseState[button] != previousMouseState[button]) && (currentMouseState[button] == 1)) pressed = true;
#endif
return pressed;
}
@ -2128,7 +2142,9 @@ Vector2 GetTouchPosition(int index)
position.x = position.x*((float)renderWidth/(float)displayWidth) - renderOffsetX/2;
position.y = position.y*((float)renderHeight/(float)displayHeight) - renderOffsetY/2;
}
#else // PLATFORM_DESKTOP, PLATFORM_RPI
#elif defined(PLATFORM_RPI)
position = touchPosition[index];
#else // PLATFORM_DESKTOP
if (index == 0) position = GetMousePosition();
#endif
@ -2895,6 +2911,21 @@ static void PollInputEvents(void)
gamepadAxisCount = 0;
#endif
#if defined(PLATFORM_RPI)
// Register previous keys states
for (int i = 0; i < 512; i++) previousKeyState[i] = currentKeyState[i];
// Register previous mouse states
previousMouseWheelY = currentMouseWheelY;
currentMouseWheelY = 0;
for (int i = 0; i < 3; i++)
{
previousMouseState[i] = currentMouseState[i];
currentMouseState[i] = currentMouseStateEvdev[i];
}
#endif
#if defined(PLATFORM_DESKTOP) || defined(PLATFORM_WEB)
// Mouse input polling
double mouseX;
@ -3829,182 +3860,351 @@ static void RestoreKeyboard(void)
// Mouse initialization (including mouse thread)
static void InitMouse(void)
{
// NOTE: We can use /dev/input/mice to read from all available mice
if ((mouseStream = open(DEFAULT_MOUSE_DEV, O_RDONLY|O_NONBLOCK)) < 0)
char Path[256];
DIR *d;
struct dirent *dir;
// Reset variables
for (int i = 0; i < MAX_TOUCH_POINTS; ++i)
{
touchPosition[i].x = -1;
touchPosition[i].y = -1;
}
// Open the linux directory of "/dev/input"
d = opendir(DEFAULT_EVDEV_PATH);
if (d)
{
TraceLog(LOG_WARNING, "Mouse device could not be opened, no mouse available");
while ((dir = readdir(d)) != NULL)
{
if(strncmp("event", dir->d_name, strlen("event")) == 0) // Search for devices named "event*"
{
sprintf(Path, "%s%s", DEFAULT_EVDEV_PATH, dir->d_name);
EventThreadSpawn(Path); // Identify the device and spawn a thread for it
}
}
closedir(d);
}
else
{
mouseReady = true;
int error = pthread_create(&mouseThreadId, NULL, &MouseThread, NULL);
if (error != 0) TraceLog(LOG_WARNING, "Error creating mouse input event thread");
else TraceLog(LOG_INFO, "Mouse device initialized successfully");
TraceLog(LOG_WARNING, "Unable to open linux event directory %s", DEFAULT_EVDEV_PATH);
}
}
// Mouse reading thread
// NOTE: We need a separate thread to avoid loosing mouse events,
// if too much time passes between reads, queue gets full and new events override older ones...
static void *MouseThread(void *arg)
{
const unsigned char XSIGN = (1 << 4);
const unsigned char YSIGN = (1 << 5);
typedef struct {
char buttons;
char dx, dy;
} MouseEvent;
MouseEvent mouse;
static void EventThreadSpawn(char* device)
{
#define BITS_PER_LONG (sizeof(long) * 8)
#define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1)
#define OFF(x) ((x)%BITS_PER_LONG)
#define BIT(x) (1UL<<OFF(x))
#define LONG(x) ((x)/BITS_PER_LONG)
#define TEST_BIT(array, bit) ((array[LONG(bit)] >> OFF(bit)) & 1)
struct input_absinfo absinfo;
unsigned long ev_bits[NBITS(EV_MAX)];
unsigned long abs_bits[NBITS(ABS_MAX)];
unsigned long rel_bits[NBITS(REL_MAX)];
unsigned long key_bits[NBITS(KEY_MAX)];
bool hasAbs = false;
bool hasRel = false;
bool hasAbsMulti = false;
int FreeWorkerId = -1;
int fd = -1;
InputEventWorker* Worker;
/////////////////////////////////// Open the device and allocate worker /////////////////////////////////////////////
// Find a free spot in the workers array
for (int i = 0; i < sizeof(eventWorkers)/sizeof(InputEventWorker); ++i)
{
if(eventWorkers[i].threadId == 0)
{
FreeWorkerId = i;
break;
}
}
int mouseRelX = 0;
int mouseRelY = 0;
// Select the free worker from array
if(FreeWorkerId >= 0)
{
Worker = &(eventWorkers[FreeWorkerId]); // Grab a pointer to the worker
memset(Worker, 0, sizeof(InputEventWorker)); // Clear the worker
}
else
{
TraceLog(LOG_WARNING, "Error creating input device thread for '%s': Out of worker slots", device);
return;
}
while (!windowShouldClose)
// Open the device
fd = open(device, O_RDONLY | O_NONBLOCK);
if(fd < 0)
{
if (read(mouseStream, &mouse, sizeof(MouseEvent)) == (int)sizeof(MouseEvent))
{
if ((mouse.buttons & 0x08) == 0) break; // This bit should always be set
TraceLog(LOG_WARNING, "Error creating input device thread for '%s': Can't open device (Err: %d)", device, Worker->fd);
return;
}
Worker->fd = fd;
// Check Left button pressed
if ((mouse.buttons & 0x01) > 0) currentMouseState[0] = 1;
else currentMouseState[0] = 0;
// At this point we have a connection to the device,
// but we don't yet know what the device is (Could be
// many things, even as simple as a power button)
// Check Right button pressed
if ((mouse.buttons & 0x02) > 0) currentMouseState[1] = 1;
else currentMouseState[1] = 0;
/////////////////////////////////// Identify the device /////////////////////////////////////////////
// Check Middle button pressed
if ((mouse.buttons & 0x04) > 0) currentMouseState[2] = 1;
else currentMouseState[2] = 0;
ioctl(fd, EVIOCGBIT(0, sizeof(ev_bits)), ev_bits); // Read a bitfield of the avalable device properties
// Check for absolute input devices
if (TEST_BIT(ev_bits, EV_ABS))
{
ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(abs_bits)),abs_bits);
mouseRelX = (int)mouse.dx;
mouseRelY = (int)mouse.dy;
// Check for absolute movement support (usualy touchscreens, but also joysticks)
if (TEST_BIT(abs_bits, ABS_X) && TEST_BIT(abs_bits, ABS_Y))
{
hasAbs = true;
// Get the scaling values
ioctl(fd, EVIOCGABS(ABS_X), &absinfo);
Worker->absRange.x = absinfo.minimum;
Worker->absRange.width = absinfo.maximum - absinfo.minimum;
ioctl(fd, EVIOCGABS(ABS_Y), &absinfo);
Worker->absRange.y = absinfo.minimum;
Worker->absRange.height = absinfo.maximum - absinfo.minimum;
}
// Check for multiple absolute movement support (usualy multitouch touchscreens)
if (TEST_BIT(abs_bits, ABS_MT_POSITION_X) && TEST_BIT(abs_bits, 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;
ioctl(fd, EVIOCGABS(ABS_Y), &absinfo);
Worker->absRange.y = absinfo.minimum;
Worker->absRange.height = absinfo.maximum - absinfo.minimum;
}
}
if ((mouse.buttons & XSIGN) > 0) mouseRelX = -1*(255 - mouseRelX);
if ((mouse.buttons & YSIGN) > 0) mouseRelY = -1*(255 - mouseRelY);
// Check for relative movement support (usualy mouse)
if (TEST_BIT(ev_bits, EV_REL))
{
ioctl(fd, EVIOCGBIT(EV_REL, sizeof(rel_bits)),rel_bits);
if (TEST_BIT(rel_bits, REL_X) && TEST_BIT(rel_bits, REL_Y))
{
hasRel = true;
}
}
// NOTE: Mouse movement is normalized to not be screen resolution dependant
// We suppose 2*255 (max relative movement) is equivalent to screenWidth (max pixels width)
// Result after normalization is multiplied by MOUSE_SENSITIVITY factor
// Check for button support to determine the device type(usualy on all input devices)
if (TEST_BIT(ev_bits, EV_KEY))
{
ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(key_bits)),key_bits);
mousePosition.x += (float)mouseRelX*((float)screenWidth/(2*255))*MOUSE_SENSITIVITY;
mousePosition.y -= (float)mouseRelY*((float)screenHeight/(2*255))*MOUSE_SENSITIVITY;
if(hasAbs || hasAbsMulti)
{
if(TEST_BIT(key_bits, BTN_TOUCH))
Worker->isTouch = true; // This is a touchscreen
if(TEST_BIT(key_bits, BTN_TOOL_FINGER))
Worker->isTouch = true; // This is a drawing tablet
if(TEST_BIT(key_bits, BTN_TOOL_PEN))
Worker->isTouch = true; // This is a drawing tablet
if(TEST_BIT(key_bits, BTN_STYLUS))
Worker->isTouch = true; // This is a drawing tablet
if(Worker->isTouch || hasAbsMulti)
Worker->isMultitouch = true; // This is a multitouch capable device
}
if (mousePosition.x < 0) mousePosition.x = 0;
if (mousePosition.y < 0) mousePosition.y = 0;
if(hasRel)
{
if (TEST_BIT(key_bits, BTN_LEFT))
Worker->isMouse = true; // This is a mouse
if (TEST_BIT(key_bits, BTN_RIGHT))
Worker->isMouse = true; // This is a mouse
}
if (mousePosition.x > screenWidth) mousePosition.x = screenWidth;
if (mousePosition.y > screenHeight) mousePosition.y = screenHeight;
}
//else read(mouseStream, &mouse, 1); // Try to sync up again
if (TEST_BIT(key_bits, BTN_A))
Worker->isGamepad = true; // This is a gamepad
if (TEST_BIT(key_bits, BTN_TRIGGER))
Worker->isGamepad = true; // This is a gamepad
if (TEST_BIT(key_bits, BTN_START))
Worker->isGamepad = true; // This is a gamepad
if (TEST_BIT(key_bits, BTN_TL))
Worker->isGamepad = true; // This is a gamepad
if (TEST_BIT(key_bits, BTN_TL))
Worker->isGamepad = true; // This is a gamepad
if (TEST_BIT(key_bits, KEY_SPACE))
Worker->isKeyboard = true; // This is a keyboard
}
return NULL;
}
// Touch initialization (including touch thread)
static void InitTouch(void)
{
if ((touchStream = open(DEFAULT_TOUCH_DEV, O_RDONLY|O_NONBLOCK)) < 0)
/////////////////////////////////// Decide what to do with the device /////////////////////////////////////////////
if(Worker->isTouch || Worker->isMouse)
{
TraceLog(LOG_WARNING, "Touch device could not be opened, no touchscreen available");
// Looks like a interesting device
TraceLog(LOG_INFO, "Opening input device '%s' (%s%s%s%s%s)", device,
Worker->isMouse ? "mouse " : "",
Worker->isMultitouch ? "multitouch " : "",
Worker->isTouch ? "touchscreen " : "",
Worker->isGamepad ? "gamepad " : "",
Worker->isKeyboard ? "keyboard " : ""
);
// Create a thread for this device
int error = pthread_create(&Worker->threadId, NULL, &EventThread, (void*)Worker);
if(error != 0)
{
TraceLog(LOG_WARNING, "Error creating input device thread for '%s': Can't create thread (Err: %d)", device, error);
Worker->threadId = 0;
close(fd);
}
}
else
{
touchReady = true;
int error = pthread_create(&touchThreadId, NULL, &TouchThread, NULL);
if (error != 0) TraceLog(LOG_WARNING, "Error creating touch input event thread");
else TraceLog(LOG_INFO, "Touch device initialized successfully");
// We are not interested in this device
close(fd);
}
}
// Touch reading thread.
// This reads from a Virtual Input Event /dev/input/event4 which is
// created by the ts_uinput daemon. This takes, filters and scales
// raw input from the Touchscreen (which appears in /dev/input/event3)
// based on the Calibration data referenced by tslib.
static void *TouchThread(void *arg)
static void *EventThread(void *arg)
{
struct input_event ev;
GestureEvent gestureEvent;
InputEventWorker* Worker = (InputEventWorker*)arg;
bool GestureNeedsUpdate = false;
while (!windowShouldClose)
{
if (read(touchStream, &ev, sizeof(ev)) == (int)sizeof(ev))
if (read(Worker->fd, &ev, sizeof(ev)) == (int)sizeof(ev))
{
// if pressure > 0 then simulate left mouse button click
if (ev.type == EV_ABS && ev.code == 24 && ev.value == 0 && currentMouseState[0] == 1)
/////////////////////////////// Relative movement parsing ////////////////////////////////////
if(ev.type == EV_REL)
{
currentMouseState[0] = 0;
gestureEvent.touchAction = TOUCH_UP;
gestureEvent.pointCount = 1;
gestureEvent.pointerId[0] = 0;
gestureEvent.pointerId[1] = 1;
gestureEvent.position[0] = (Vector2){ mousePosition.x, mousePosition.y };
gestureEvent.position[1] = (Vector2){ mousePosition.x, mousePosition.y };
gestureEvent.position[0].x /= (float)GetScreenWidth();
gestureEvent.position[0].y /= (float)GetScreenHeight();
gestureEvent.position[1].x /= (float)GetScreenWidth();
gestureEvent.position[1].y /= (float)GetScreenHeight();
ProcessGestureEvent(gestureEvent);
if(ev.code == REL_X)
{
mousePosition.x += ev.value;
touchPosition[0].x = mousePosition.x;
gestureEvent.touchAction = TOUCH_MOVE;
GestureNeedsUpdate = true;
}
if(ev.code == REL_Y)
{
mousePosition.y += ev.value;
touchPosition[0].y = mousePosition.y;
gestureEvent.touchAction = TOUCH_MOVE;
GestureNeedsUpdate = true;
}
if(ev.code == REL_WHEEL)
{
currentMouseWheelY += ev.value;
}
}
if (ev.type == EV_ABS && ev.code == 24 && ev.value > 0 && currentMouseState[0] == 0)
/////////////////////////////// Absolute movement parsing ////////////////////////////////////
if(ev.type == EV_ABS)
{
currentMouseState[0] = 1;
gestureEvent.touchAction = TOUCH_DOWN;
gestureEvent.pointCount = 1;
gestureEvent.pointerId[0] = 0;
gestureEvent.pointerId[1] = 1;
gestureEvent.position[0] = (Vector2){ mousePosition.x, mousePosition.y };
gestureEvent.position[1] = (Vector2){ mousePosition.x, mousePosition.y };
gestureEvent.position[0].x /= (float)GetScreenWidth();
gestureEvent.position[0].y /= (float)GetScreenHeight();
gestureEvent.position[1].x /= (float)GetScreenWidth();
gestureEvent.position[1].y /= (float)GetScreenHeight();
ProcessGestureEvent(gestureEvent);
// Basic movement
if(ev.code == ABS_X)
{
mousePosition.x = (ev.value - Worker->absRange.x) * screenWidth / Worker->absRange.width; //Scale acording to absRange
gestureEvent.touchAction = TOUCH_MOVE;
GestureNeedsUpdate = true;
}
if(ev.code == ABS_Y)
{
mousePosition.y = (ev.value - Worker->absRange.y) * screenHeight / Worker->absRange.height; //Scale acording to absRange
gestureEvent.touchAction = TOUCH_MOVE;
GestureNeedsUpdate = true;
}
//Multitouch movement
if(ev.code == ABS_MT_SLOT)
{
Worker->touchSlot = ev.value; //Remeber the slot number for the folowing events
}
if(ev.code == ABS_MT_POSITION_X)
{
if(Worker->touchSlot < MAX_TOUCH_POINTS)
touchPosition[Worker->touchSlot].x = (ev.value - Worker->absRange.x) * screenWidth / Worker->absRange.width; //Scale acording to absRange
}
if(ev.code == ABS_MT_POSITION_Y)
{
if(Worker->touchSlot < MAX_TOUCH_POINTS)
touchPosition[Worker->touchSlot].y = (ev.value - Worker->absRange.y) * screenHeight / Worker->absRange.height; //Scale acording to absRange
}
if(ev.code == ABS_MT_TRACKING_ID)
{
if( (ev.value < 0) && (Worker->touchSlot < MAX_TOUCH_POINTS) )
{
//Touch has ended for this point
touchPosition[Worker->touchSlot].x = -1;
touchPosition[Worker->touchSlot].y = -1;
}
}
}
// x & y values supplied by event4 have been scaled & de-jittered using tslib calibration data
if (ev.type == EV_ABS && ev.code == 0)
/////////////////////////////// Button parsing ////////////////////////////////////
if(ev.type == EV_KEY)
{
mousePosition.x = ev.value;
if (mousePosition.x < 0) mousePosition.x = 0;
if (mousePosition.x > screenWidth) mousePosition.x = screenWidth;
gestureEvent.touchAction = TOUCH_MOVE;
gestureEvent.pointCount = 1;
gestureEvent.pointerId[0] = 0;
gestureEvent.pointerId[1] = 1;
gestureEvent.position[0] = (Vector2){ mousePosition.x, mousePosition.y };
gestureEvent.position[1] = (Vector2){ mousePosition.x, mousePosition.y };
gestureEvent.position[0].x /= (float)GetScreenWidth();
gestureEvent.position[0].y /= (float)GetScreenHeight();
gestureEvent.position[1].x /= (float)GetScreenWidth();
gestureEvent.position[1].y /= (float)GetScreenHeight();
ProcessGestureEvent(gestureEvent);
if((ev.code == BTN_TOUCH) || (ev.code == BTN_LEFT))
{
currentMouseStateEvdev[MOUSE_LEFT_BUTTON] = ev.value;
if(ev.value > 0)
gestureEvent.touchAction = TOUCH_DOWN;
else
gestureEvent.touchAction = TOUCH_UP;
GestureNeedsUpdate = true;
}
if(ev.code == BTN_RIGHT)
{
currentMouseStateEvdev[MOUSE_RIGHT_BUTTON] = ev.value;
}
if(ev.code == BTN_MIDDLE)
{
currentMouseStateEvdev[MOUSE_MIDDLE_BUTTON] = ev.value;
}
}
if (ev.type == EV_ABS && ev.code == 1)
/////////////////////////////// Screen confinement ////////////////////////////////////
if(mousePosition.x < 0)
mousePosition.x = 0;
if(mousePosition.x > screenWidth / mouseScale)
mousePosition.x = screenWidth / mouseScale;
if(mousePosition.y < 0)
mousePosition.y = 0;
if(mousePosition.y > screenHeight / mouseScale)
mousePosition.y = screenHeight / mouseScale;
/////////////////////////////// Gesture update ////////////////////////////////////
if(GestureNeedsUpdate)
{
mousePosition.y = ev.value;
if (mousePosition.y < 0) mousePosition.y = 0;
if (mousePosition.y > screenHeight) mousePosition.y = screenHeight;
gestureEvent.touchAction = TOUCH_MOVE;
gestureEvent.pointCount = 1;
gestureEvent.pointCount = 0;
if(touchPosition[0].x >= 0) gestureEvent.pointCount++;
if(touchPosition[1].x >= 0) gestureEvent.pointCount++;
k">if(touchPosition[2].x >= 0) gestureEvent.pointCount++;
k">if(touchPosition[3].x >= 0) gestureEvent.pointCount++;
gestureEvent.pointerId[0] = 0;
gestureEvent.pointerId[1] = 1;
gestureEvent.position[0] = (Vector2){ mousePosition.x, mousePosition.y };
gestureEvent.position[1] = (Vector2){ mousePosition.x, mousePosition.y };
gestureEvent.position[0].x /= (float)GetScreenWidth();
gestureEvent.position[0].y /= (float)GetScreenHeight();
gestureEvent.position[1].x /= (float)GetScreenWidth();
gestureEvent.position[1].y /= (float)GetScreenHeight();
gestureEvent.pointerId[2] = 2;
gestureEvent.pointerId[3] = 3;
gestureEvent.position[0] = touchPosition[0];
gestureEvent.position[1] = touchPosition[1];
gestureEvent.position[2] = touchPosition[2];
gestureEvent.position[3] = touchPosition[3];
ProcessGestureEvent(gestureEvent);
}
}
else
{
usleep(5000); //Sleep for 5ms to avoid hogging CPU time
}
}
return NULL;
@ -4090,6 +4290,10 @@ static void *GamepadThread(void *arg)
}
}
}
else
{
usleep(1000); //Sleep for 1ms to avoid hogging CPU time
}
}
}

+ 1
- 1
src/raylib.h View File

@ -223,7 +223,7 @@
#define MOUSE_MIDDLE_BUTTON 2
// Touch points registered
#define MAX_TOUCH_POINTS 2
#define MAX_TOUCH_POINTS 10
// Gamepad Number
#define GAMEPAD_PLAYER1 0

Loading…
Cancel
Save