From c9a624595b7685463424978e18e540f04a9cc221 Mon Sep 17 00:00:00 2001 From: Tom Date: Mon, 13 Apr 2020 13:16:08 -0600 Subject: [PATCH 1/3] initial touchscreen support (rotated 90 degrees for the moment) --- src/input/evdev.c | 53 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 47 insertions(+), 6 deletions(-) diff --git a/src/input/evdev.c b/src/input/evdev.c index bb46f7b..8a2f14c 100644 --- a/src/input/evdev.c +++ b/src/input/evdev.c @@ -57,6 +57,7 @@ struct input_device { struct libevdev *dev; bool is_keyboard; bool is_mouse; + bool is_touchscreen; struct mapping* map; int key_map[KEY_MAX]; int abs_map[ABS_MAX]; @@ -64,6 +65,7 @@ struct input_device { int fd; char modifiers; __s32 mouseDeltaX, mouseDeltaY, mouseScroll; + __s32 touchStartX, touchStartY, touchX, touchY; short controllerId; int haptic_effect_id; int buttonFlags; @@ -82,6 +84,10 @@ static const int hat_constants[3][3] = {{HAT_UP | HAT_LEFT, HAT_UP, HAT_UP | HAT #define set_hat(flags, flag, hat, hat_flag) flags = (hat & hat_flag) == hat_flag ? flags | flag : flags & ~flag +#define NO_TOUCH -1 +#define TOUCH_THRESHOLD 10 +#define TOUCH_BUTTON_DELAY 100 * 1000 // microseconds + static struct input_device* devices = NULL; static int numDevices = 0; static int assignedControllerIds = 0; @@ -244,6 +250,20 @@ static bool evdev_handle_event(struct input_event *ev, struct input_device *dev) int index = ev->code > BTN_MISC && ev->code < (BTN_MISC + KEY_MAX) ? dev->key_map[ev->code - BTN_MISC] : -1; switch (ev->code) { + case BTN_TOUCH: + if (!ev->value) { + int deltaX = dev->touchX - dev->touchStartX; + int deltaY = dev->touchY - dev->touchStartY; + if (deltaX * deltaX + deltaY * deltaY < TOUCH_THRESHOLD * TOUCH_THRESHOLD) { + LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_LEFT); + usleep(TOUCH_BUTTON_DELAY); + LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_LEFT); + } + } + dev->touchStartX = NO_TOUCH; + dev->touchStartY = NO_TOUCH; + gamepadModified = false; + break; case BTN_LEFT: mouseCode = BUTTON_LEFT; break; @@ -329,7 +349,7 @@ static bool evdev_handle_event(struct input_event *ev, struct input_device *dev) } break; case EV_ABS: - if (dev->map == NULL) + if (dev->map == NULL && !dev->is_touchscreen) break; gamepadModified = true; @@ -358,7 +378,24 @@ static bool evdev_handle_event(struct input_event *ev, struct input_device *dev) set_hat(dev->buttonFlags, LEFT_FLAG, hat_state, dev->map->hat_dir_dpleft); break; default: - if (index == dev->map->abs_leftx) + if (dev->is_touchscreen) { + if (ev->code == ABS_Y) { + if (dev->touchStartX == NO_TOUCH) { + dev->touchStartX = ev->value; + dev->touchX = ev->value; + } + dev->mouseDeltaX += (ev->value - dev->touchX); + dev->touchX = ev->value; + } else if (ev->code == ABS_X) { + if (dev->touchStartY == NO_TOUCH) { + dev->touchStartY = ev->value; + dev->touchY = ev->value; + } + dev->mouseDeltaY += -(ev->value - dev->touchY); + dev->touchY = ev->value; + } + gamepadModified = false; + } else if (index == dev->map->abs_leftx) dev->leftStickX = evdev_convert_value(ev, dev, &dev->xParms, dev->map->reverse_leftx); else if (index == dev->map->abs_lefty) dev->leftStickY = evdev_convert_value(ev, dev, &dev->yParms, !dev->map->reverse_lefty); @@ -504,13 +541,14 @@ void evdev_create(const char* device, struct mapping* mappings, bool verbose) { bool is_keyboard = libevdev_has_event_code(evdev, EV_KEY, KEY_Q); bool is_mouse = libevdev_has_event_type(evdev, EV_REL) || libevdev_has_event_code(evdev, EV_KEY, BTN_LEFT); + bool is_touchscreen = libevdev_has_event_code(evdev, EV_KEY, BTN_TOUCH); - if (mappings == NULL && !(is_keyboard || is_mouse)) { + if (mappings == NULL && !(is_keyboard || is_mouse || is_touchscreen)) { fprintf(stderr, "No mapping available for %s (%s) on %s\n", name, str_guid, device); mappings = default_mapping; } - if (!is_keyboard && !is_mouse) + if (!is_keyboard && !is_mouse && !is_touchscreen) evdev_gamepads++; int dev = numDevices; @@ -535,6 +573,9 @@ void evdev_create(const char* device, struct mapping* mappings, bool verbose) { memset(&devices[dev].abs_map, -2, sizeof(devices[dev].abs_map)); devices[dev].is_keyboard = is_keyboard; devices[dev].is_mouse = is_mouse; + devices[dev].is_touchscreen = is_touchscreen; + devices[dev].touchStartX = NO_TOUCH; + devices[dev].touchStartY = NO_TOUCH; int nbuttons = 0; for (int i = BTN_JOYSTICK; i < KEY_MAX; ++i) { @@ -569,7 +610,7 @@ void evdev_create(const char* device, struct mapping* mappings, bool verbose) { fprintf(stderr, "Mapping for %s (%s) on %s is incorrect\n", name, str_guid, device); } - if (grabbingDevices && (is_keyboard || is_mouse)) { + if (grabbingDevices && (is_keyboard || is_mouse || is_touchscreen)) { if (ioctl(fd, EVIOCGRAB, 1) < 0) { fprintf(stderr, "EVIOCGRAB failed with error %d\n", errno); } @@ -696,7 +737,7 @@ void evdev_start() { // we're ready to take input events. Ctrl+C works up until // this point. for (int i = 0; i < numDevices; i++) { - if ((devices[i].is_keyboard || devices[i].is_mouse) && ioctl(devices[i].fd, EVIOCGRAB, 1) < 0) { + if ((devices[i].is_keyboard || devices[i].is_mouse || devices[i].is_touchscreen) && ioctl(devices[i].fd, EVIOCGRAB, 1) < 0) { fprintf(stderr, "EVIOCGRAB failed with error %d\n", errno); } } From 6b8260c1e5245396374e48d53bd27506a00b1895 Mon Sep 17 00:00:00 2001 From: Tom Date: Sat, 18 Apr 2020 07:03:59 -0600 Subject: [PATCH 2/3] refactored touchscreen code for clarity and safety, and removed hacked in rotation --- src/input/evdev.c | 86 ++++++++++++++++++++++++++--------------------- 1 file changed, 47 insertions(+), 39 deletions(-) diff --git a/src/input/evdev.c b/src/input/evdev.c index 8a2f14c..2f924ef 100644 --- a/src/input/evdev.c +++ b/src/input/evdev.c @@ -65,7 +65,7 @@ struct input_device { int fd; char modifiers; __s32 mouseDeltaX, mouseDeltaY, mouseScroll; - __s32 touchStartX, touchStartY, touchX, touchY; + __s32 touchDownX, touchDownY, touchX, touchY; short controllerId; int haptic_effect_id; int buttonFlags; @@ -84,9 +84,9 @@ static const int hat_constants[3][3] = {{HAT_UP | HAT_LEFT, HAT_UP, HAT_UP | HAT #define set_hat(flags, flag, hat, hat_flag) flags = (hat & hat_flag) == hat_flag ? flags | flag : flags & ~flag -#define NO_TOUCH -1 -#define TOUCH_THRESHOLD 10 -#define TOUCH_BUTTON_DELAY 100 * 1000 // microseconds +#define TOUCH_UP -1 +#define TOUCH_CLICK_RADIUS 10 +#define TOUCH_CLICK_DELAY 100000 // microseconds static struct input_device* devices = NULL; static int numDevices = 0; @@ -250,20 +250,6 @@ static bool evdev_handle_event(struct input_event *ev, struct input_device *dev) int index = ev->code > BTN_MISC && ev->code < (BTN_MISC + KEY_MAX) ? dev->key_map[ev->code - BTN_MISC] : -1; switch (ev->code) { - case BTN_TOUCH: - if (!ev->value) { - int deltaX = dev->touchX - dev->touchStartX; - int deltaY = dev->touchY - dev->touchStartY; - if (deltaX * deltaX + deltaY * deltaY < TOUCH_THRESHOLD * TOUCH_THRESHOLD) { - LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_LEFT); - usleep(TOUCH_BUTTON_DELAY); - LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_LEFT); - } - } - dev->touchStartX = NO_TOUCH; - dev->touchStartY = NO_TOUCH; - gamepadModified = false; - break; case BTN_LEFT: mouseCode = BUTTON_LEFT; break; @@ -279,6 +265,21 @@ static bool evdev_handle_event(struct input_event *ev, struct input_device *dev) case BTN_EXTRA: mouseCode = BUTTON_X2; break; + case BTN_TOUCH: + if (ev->value != 1) { + if (dev->touchDownX != TOUCH_UP && dev->touchDownY != TOUCH_UP) { + int deltaX = dev->touchX - dev->touchDownX; + int deltaY = dev->touchY - dev->touchDownY; + if (deltaX * deltaX + deltaY * deltaY < TOUCH_CLICK_RADIUS * TOUCH_CLICK_RADIUS) { + LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_LEFT); + usleep(TOUCH_CLICK_DELAY); + LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_LEFT); + } + } + dev->touchDownX = TOUCH_UP; + dev->touchDownY = TOUCH_UP; + } + break; default: gamepadModified = true; if (dev->map == NULL) @@ -349,7 +350,31 @@ static bool evdev_handle_event(struct input_event *ev, struct input_device *dev) } break; case EV_ABS: - if (dev->map == NULL && !dev->is_touchscreen) + if (dev->is_touchscreen) { + switch (ev->code) { + case ABS_X: + if (dev->touchDownX == TOUCH_UP) { + dev->touchDownX = ev->value; + dev->touchX = ev->value; + } else { + dev->mouseDeltaX += (ev->value - dev->touchX); + dev->touchX = ev->value; + } + break; + case ABS_Y: + if (dev->touchDownY == TOUCH_UP) { + dev->touchDownY = ev->value; + dev->touchY = ev->value; + } else { + dev->mouseDeltaY += (ev->value - dev->touchY); + dev->touchY = ev->value; + } + break; + } + break; + } + + if (dev->map == NULL) break; gamepadModified = true; @@ -378,24 +403,7 @@ static bool evdev_handle_event(struct input_event *ev, struct input_device *dev) set_hat(dev->buttonFlags, LEFT_FLAG, hat_state, dev->map->hat_dir_dpleft); break; default: - if (dev->is_touchscreen) { - if (ev->code == ABS_Y) { - if (dev->touchStartX == NO_TOUCH) { - dev->touchStartX = ev->value; - dev->touchX = ev->value; - } - dev->mouseDeltaX += (ev->value - dev->touchX); - dev->touchX = ev->value; - } else if (ev->code == ABS_X) { - if (dev->touchStartY == NO_TOUCH) { - dev->touchStartY = ev->value; - dev->touchY = ev->value; - } - dev->mouseDeltaY += -(ev->value - dev->touchY); - dev->touchY = ev->value; - } - gamepadModified = false; - } else if (index == dev->map->abs_leftx) + if (index == dev->map->abs_leftx) dev->leftStickX = evdev_convert_value(ev, dev, &dev->xParms, dev->map->reverse_leftx); else if (index == dev->map->abs_lefty) dev->leftStickY = evdev_convert_value(ev, dev, &dev->yParms, !dev->map->reverse_lefty); @@ -574,8 +582,8 @@ void evdev_create(const char* device, struct mapping* mappings, bool verbose) { devices[dev].is_keyboard = is_keyboard; devices[dev].is_mouse = is_mouse; devices[dev].is_touchscreen = is_touchscreen; - devices[dev].touchStartX = NO_TOUCH; - devices[dev].touchStartY = NO_TOUCH; + devices[dev].touchDownX = TOUCH_UP; + devices[dev].touchDownY = TOUCH_UP; int nbuttons = 0; for (int i = BTN_JOYSTICK; i < KEY_MAX; ++i) { From 5beb32d0663dfe4db55755fbb5d94a1385e9015e Mon Sep 17 00:00:00 2001 From: Tom Date: Sat, 18 Apr 2020 07:34:52 -0600 Subject: [PATCH 3/3] Emulating right click on touch screens with a long press --- src/input/evdev.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/input/evdev.c b/src/input/evdev.c index 2f924ef..b2ecf8f 100644 --- a/src/input/evdev.c +++ b/src/input/evdev.c @@ -66,6 +66,7 @@ struct input_device { char modifiers; __s32 mouseDeltaX, mouseDeltaY, mouseScroll; __s32 touchDownX, touchDownY, touchX, touchY; + struct timeval touchDownTime; short controllerId; int haptic_effect_id; int buttonFlags; @@ -87,6 +88,7 @@ static const int hat_constants[3][3] = {{HAT_UP | HAT_LEFT, HAT_UP, HAT_UP | HAT #define TOUCH_UP -1 #define TOUCH_CLICK_RADIUS 10 #define TOUCH_CLICK_DELAY 100000 // microseconds +#define TOUCH_RCLICK_TIME 750 // milliseconds static struct input_device* devices = NULL; static int numDevices = 0; @@ -266,14 +268,20 @@ static bool evdev_handle_event(struct input_event *ev, struct input_device *dev) mouseCode = BUTTON_X2; break; case BTN_TOUCH: - if (ev->value != 1) { + if (ev->value == 1) { + dev->touchDownTime = ev->time; + } else { if (dev->touchDownX != TOUCH_UP && dev->touchDownY != TOUCH_UP) { int deltaX = dev->touchX - dev->touchDownX; int deltaY = dev->touchY - dev->touchDownY; if (deltaX * deltaX + deltaY * deltaY < TOUCH_CLICK_RADIUS * TOUCH_CLICK_RADIUS) { - LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_LEFT); + struct timeval elapsedTime; + timersub(&ev->time, &dev->touchDownTime, &elapsedTime); + int holdTimeMs = elapsedTime.tv_sec * 1000 + elapsedTime.tv_usec / 1000; + int button = holdTimeMs >= TOUCH_RCLICK_TIME ? BUTTON_RIGHT : BUTTON_LEFT; + LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, button); usleep(TOUCH_CLICK_DELAY); - LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_LEFT); + LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, button); } } dev->touchDownX = TOUCH_UP;