mirror of
https://github.com/moonlight-stream/moonlight-embedded.git
synced 2025-07-01 23:35:47 +00:00
Mouse emulation support for evdev
This commit is contained in:
parent
3a63466fe2
commit
469b2ed866
@ -59,6 +59,7 @@ include_directories("${PROJECT_BINARY_DIR}")
|
|||||||
add_subdirectory(libgamestream)
|
add_subdirectory(libgamestream)
|
||||||
|
|
||||||
add_executable(moonlight ${SRC_LIST})
|
add_executable(moonlight ${SRC_LIST})
|
||||||
|
target_link_libraries(moonlight m)
|
||||||
target_link_libraries(moonlight gamestream)
|
target_link_libraries(moonlight gamestream)
|
||||||
|
|
||||||
if (CEC_FOUND)
|
if (CEC_FOUND)
|
||||||
|
@ -39,6 +39,7 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <endian.h>
|
#include <endian.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||||
#define int16_to_le(val) val
|
#define int16_to_le(val) val
|
||||||
@ -68,6 +69,7 @@ struct input_device {
|
|||||||
__s32 mouseDeltaX, mouseDeltaY, mouseScroll;
|
__s32 mouseDeltaX, mouseDeltaY, mouseScroll;
|
||||||
__s32 touchDownX, touchDownY, touchX, touchY;
|
__s32 touchDownX, touchDownY, touchX, touchY;
|
||||||
struct timeval touchDownTime;
|
struct timeval touchDownTime;
|
||||||
|
struct timeval btnDownTime;
|
||||||
short controllerId;
|
short controllerId;
|
||||||
int haptic_effect_id;
|
int haptic_effect_id;
|
||||||
int buttonFlags;
|
int buttonFlags;
|
||||||
@ -75,6 +77,8 @@ struct input_device {
|
|||||||
short leftStickX, leftStickY;
|
short leftStickX, leftStickY;
|
||||||
short rightStickX, rightStickY;
|
short rightStickX, rightStickY;
|
||||||
bool gamepadModified;
|
bool gamepadModified;
|
||||||
|
bool mouseEmulation;
|
||||||
|
pthread_t meThread;
|
||||||
struct input_abs_parms xParms, yParms, rxParms, ryParms, zParms, rzParms;
|
struct input_abs_parms xParms, yParms, rxParms, ryParms, zParms, rzParms;
|
||||||
struct input_abs_parms leftParms, rightParms, upParms, downParms;
|
struct input_abs_parms leftParms, rightParms, upParms, downParms;
|
||||||
};
|
};
|
||||||
@ -92,6 +96,15 @@ static const int hat_constants[3][3] = {{HAT_UP | HAT_LEFT, HAT_UP, HAT_UP | HAT
|
|||||||
#define TOUCH_CLICK_DELAY 100000 // microseconds
|
#define TOUCH_CLICK_DELAY 100000 // microseconds
|
||||||
#define TOUCH_RCLICK_TIME 750 // milliseconds
|
#define TOUCH_RCLICK_TIME 750 // milliseconds
|
||||||
|
|
||||||
|
// How long the Start button must be pressed to toggle mouse emulation
|
||||||
|
#define MOUSE_EMULATION_LONG_PRESS_TIME 750
|
||||||
|
// How long between polling the gamepad to send virtual mouse input
|
||||||
|
#define MOUSE_EMULATION_POLLING_INTERVAL 50000
|
||||||
|
// Determines how fast the mouse will move each interval
|
||||||
|
#define MOUSE_EMULATION_MOTION_MULTIPLIER 3
|
||||||
|
// Determines the maximum motion amount before allowing movement
|
||||||
|
#define MOUSE_EMULATION_DEADZONE 2
|
||||||
|
|
||||||
static struct input_device* devices = NULL;
|
static struct input_device* devices = NULL;
|
||||||
static int numDevices = 0;
|
static int numDevices = 0;
|
||||||
static int assignedControllerIds = 0;
|
static int assignedControllerIds = 0;
|
||||||
@ -148,6 +161,10 @@ static void evdev_remove(int devindex) {
|
|||||||
assignedControllerIds &= ~(1 << devices[devindex].controllerId);
|
assignedControllerIds &= ~(1 << devices[devindex].controllerId);
|
||||||
LiSendMultiControllerEvent(devices[devindex].controllerId, assignedControllerIds, 0, 0, 0, 0, 0, 0, 0);
|
LiSendMultiControllerEvent(devices[devindex].controllerId, assignedControllerIds, 0, 0, 0, 0, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
if (devices[devindex].mouseEmulation) {
|
||||||
|
devices[devindex].mouseEmulation = false;
|
||||||
|
pthread_join(devices[devindex].meThread, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
if (devindex != numDevices && numDevices > 0)
|
if (devindex != numDevices && numDevices > 0)
|
||||||
memcpy(&devices[devindex], &devices[numDevices], sizeof(struct input_device));
|
memcpy(&devices[devindex], &devices[numDevices], sizeof(struct input_device));
|
||||||
@ -195,6 +212,41 @@ static char evdev_convert_value_byte(struct input_event *ev, struct input_device
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void *HandleMouseEmulation(void* param)
|
||||||
|
{
|
||||||
|
struct input_device* dev = (struct input_device*) param;
|
||||||
|
|
||||||
|
while (dev->mouseEmulation) {
|
||||||
|
usleep(MOUSE_EMULATION_POLLING_INTERVAL);
|
||||||
|
|
||||||
|
short rawX;
|
||||||
|
short rawY;
|
||||||
|
|
||||||
|
// Determine which analog stick is currently receiving the strongest input
|
||||||
|
if ((uint32_t)abs(dev->leftStickX) + abs(dev->leftStickY) > (uint32_t)abs(dev->rightStickX) + abs(dev->rightStickY)) {
|
||||||
|
rawX = dev->leftStickX;
|
||||||
|
rawY = dev->leftStickY;
|
||||||
|
} else {
|
||||||
|
rawX = dev->rightStickX;
|
||||||
|
rawY = dev->rightStickY;
|
||||||
|
}
|
||||||
|
|
||||||
|
float deltaX;
|
||||||
|
float deltaY;
|
||||||
|
|
||||||
|
// Produce a base vector for mouse movement with increased speed as we deviate further from center
|
||||||
|
deltaX = pow((float)rawX / 32767.0f * MOUSE_EMULATION_MOTION_MULTIPLIER, 3);
|
||||||
|
deltaY = pow((float)rawY / 32767.0f * MOUSE_EMULATION_MOTION_MULTIPLIER, 3);
|
||||||
|
|
||||||
|
// Enforce deadzones
|
||||||
|
deltaX = abs(deltaX) > MOUSE_EMULATION_DEADZONE ? deltaX - MOUSE_EMULATION_DEADZONE : 0;
|
||||||
|
deltaY = abs(deltaY) > MOUSE_EMULATION_DEADZONE ? deltaY - MOUSE_EMULATION_DEADZONE : 0;
|
||||||
|
|
||||||
|
if (deltaX != 0 || deltaY != 0)
|
||||||
|
LiSendMouseMoveEvent(deltaX, -deltaY);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static bool evdev_handle_event(struct input_event *ev, struct input_device *dev) {
|
static bool evdev_handle_event(struct input_event *ev, struct input_device *dev) {
|
||||||
bool gamepadModified = false;
|
bool gamepadModified = false;
|
||||||
|
|
||||||
@ -236,7 +288,9 @@ static bool evdev_handle_event(struct input_event *ev, struct input_device *dev)
|
|||||||
if (dev->controllerId < 0)
|
if (dev->controllerId < 0)
|
||||||
dev->controllerId = 0;
|
dev->controllerId = 0;
|
||||||
}
|
}
|
||||||
LiSendMultiControllerEvent(dev->controllerId, assignedControllerIds, dev->buttonFlags, dev->leftTrigger, dev->rightTrigger, dev->leftStickX, dev->leftStickY, dev->rightStickX, dev->rightStickY);
|
// Send event only if mouse emulation is disabled.
|
||||||
|
if (dev->mouseEmulation == false)
|
||||||
|
LiSendMultiControllerEvent(dev->controllerId, assignedControllerIds, dev->buttonFlags, dev->leftTrigger, dev->rightTrigger, dev->leftStickX, dev->leftStickY, dev->rightStickX, dev->rightStickY);
|
||||||
dev->gamepadModified = false;
|
dev->gamepadModified = false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -360,10 +414,50 @@ static bool evdev_handle_event(struct input_event *ev, struct input_device *dev)
|
|||||||
LiSendMouseButtonEvent(ev->value?BUTTON_ACTION_PRESS:BUTTON_ACTION_RELEASE, mouseCode);
|
LiSendMouseButtonEvent(ev->value?BUTTON_ACTION_PRESS:BUTTON_ACTION_RELEASE, mouseCode);
|
||||||
gamepadModified = false;
|
gamepadModified = false;
|
||||||
} else if (gamepadCode != 0) {
|
} else if (gamepadCode != 0) {
|
||||||
if (ev->value)
|
if (ev->value) {
|
||||||
dev->buttonFlags |= gamepadCode;
|
dev->buttonFlags |= gamepadCode;
|
||||||
else
|
dev->btnDownTime = ev->time;
|
||||||
|
} else
|
||||||
dev->buttonFlags &= ~gamepadCode;
|
dev->buttonFlags &= ~gamepadCode;
|
||||||
|
|
||||||
|
if (gamepadCode == PLAY_FLAG && ev->value == 0) {
|
||||||
|
struct timeval elapsedTime;
|
||||||
|
timersub(&ev->time, &dev->btnDownTime, &elapsedTime);
|
||||||
|
int holdTimeMs = elapsedTime.tv_sec * 1000 + elapsedTime.tv_usec / 1000;
|
||||||
|
if (holdTimeMs >= MOUSE_EMULATION_LONG_PRESS_TIME) {
|
||||||
|
if (dev->mouseEmulation) {
|
||||||
|
dev->mouseEmulation = false;
|
||||||
|
pthread_join(dev->meThread, NULL);
|
||||||
|
dev->meThread = 0;
|
||||||
|
printf("Mouse emulation disabled for controller %d.\n", dev->controllerId);
|
||||||
|
} else {
|
||||||
|
dev->mouseEmulation = true;
|
||||||
|
pthread_create(&dev->meThread, NULL, HandleMouseEmulation, dev);
|
||||||
|
printf("Mouse emulation enabled for controller %d.\n", dev->controllerId);
|
||||||
|
}
|
||||||
|
// clear gamepad state.
|
||||||
|
LiSendMultiControllerEvent(dev->controllerId, assignedControllerIds, 0, 0, 0, 0, 0, 0, 0);
|
||||||
|
}
|
||||||
|
} else if (dev->mouseEmulation) {
|
||||||
|
char action = ev->value ? BUTTON_ACTION_PRESS : BUTTON_ACTION_RELEASE;
|
||||||
|
switch (gamepadCode) {
|
||||||
|
case A_FLAG:
|
||||||
|
LiSendMouseButtonEvent(action, BUTTON_LEFT);
|
||||||
|
break;
|
||||||
|
case B_FLAG:
|
||||||
|
LiSendMouseButtonEvent(action, BUTTON_RIGHT);
|
||||||
|
break;
|
||||||
|
case X_FLAG:
|
||||||
|
LiSendMouseButtonEvent(action, BUTTON_MIDDLE);
|
||||||
|
break;
|
||||||
|
case LB_FLAG:
|
||||||
|
LiSendMouseButtonEvent(action, BUTTON_X1);
|
||||||
|
break;
|
||||||
|
case RB_FLAG:
|
||||||
|
LiSendMouseButtonEvent(action, BUTTON_X2);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
} else if (dev->map != NULL && index == dev->map->btn_lefttrigger)
|
} else if (dev->map != NULL && index == dev->map->btn_lefttrigger)
|
||||||
dev->leftTrigger = ev->value ? UCHAR_MAX : 0;
|
dev->leftTrigger = ev->value ? UCHAR_MAX : 0;
|
||||||
else if (dev->map != NULL && index == dev->map->btn_righttrigger)
|
else if (dev->map != NULL && index == dev->map->btn_righttrigger)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user