Browse Source

Merge pull request #672 from Berni8k/master

RaspberryPi Mouse and touch overhaul
Ray 6 years ago
parent
commit
30f2483bdb
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

@@ -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++;
+                if(touchPosition[2].x >= 0) gestureEvent.pointCount++;
+                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

@@ -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