mirror of
https://github.com/moonlight-stream/moonlight-embedded.git
synced 2026-04-04 15:06:03 +00:00
Merge branch 'library' into master
This commit is contained in:
103
src/input/cec.c
Normal file
103
src/input/cec.c
Normal file
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* This file is part of Moonlight Embedded.
|
||||
*
|
||||
* Copyright (C) 2015 Iwan Timmer
|
||||
*
|
||||
* Moonlight is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Moonlight is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Moonlight; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_LIBCEC
|
||||
#include <ceccloader.h>
|
||||
|
||||
static libcec_configuration g_config;
|
||||
static char g_strPort[50] = { 0 };
|
||||
static libcec_interface_t g_iface;
|
||||
static ICECCallbacks g_callbacks;
|
||||
|
||||
static int on_cec_keypress(void* userdata, const cec_keypress key) {
|
||||
char value;
|
||||
switch (key.keycode) {
|
||||
case CEC_USER_CONTROL_CODE_UP:
|
||||
value = KEY_UP;
|
||||
break;
|
||||
case CEC_USER_CONTROL_CODE_DOWN:
|
||||
value = KEY_DOWN;
|
||||
break;
|
||||
case CEC_USER_CONTROL_CODE_LEFT:
|
||||
value = KEY_LEFT;
|
||||
break;
|
||||
case CEC_USER_CONTROL_CODE_RIGHT:
|
||||
value = KEY_RIGHT;
|
||||
break;
|
||||
case CEC_USER_CONTROL_CODE_ENTER:
|
||||
case CEC_USER_CONTROL_CODE_SELECT:
|
||||
value = KEY_ENTER;
|
||||
break;
|
||||
case CEC_USER_CONTROL_CODE_ROOT_MENU:
|
||||
value = KEY_TAB;
|
||||
break;
|
||||
case CEC_USER_CONTROL_CODE_AN_RETURN:
|
||||
case CEC_USER_CONTROL_CODE_EXIT:
|
||||
value = KEY_ESC;
|
||||
break;
|
||||
default:
|
||||
value = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (value != 0) {
|
||||
short code = 0x80 << 8 | keyCodes[value];
|
||||
LiSendKeyboardEvent(code, (key.duration > 0)?KEY_ACTION_UP:KEY_ACTION_DOWN, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void init_cec() {
|
||||
libcecc_reset_configuration(&g_config);
|
||||
g_config.clientVersion = LIBCEC_VERSION_CURRENT;
|
||||
g_config.bActivateSource = 0;
|
||||
g_callbacks.CBCecKeyPress = &on_cec_keypress;
|
||||
g_config.callbacks = &g_callbacks;
|
||||
snprintf(g_config.strDeviceName, sizeof(g_config.strDeviceName), "Moonlight");
|
||||
g_config.callbacks = &g_callbacks;
|
||||
g_config.deviceTypes.types[0] = CEC_DEVICE_TYPE_PLAYBACK_DEVICE;
|
||||
|
||||
if (libcecc_initialise(&g_config, &g_iface, NULL) != 1) {
|
||||
fprintf(stderr, "Failed to initialize libcec interface\n");
|
||||
fflush(stderr);
|
||||
return;
|
||||
}
|
||||
|
||||
g_iface.init_video_standalone(g_iface.connection);
|
||||
|
||||
cec_adapter devices[10];
|
||||
int8_t iDevicesFound = g_iface.find_adapters(g_iface.connection, devices, sizeof(devices) / sizeof(devices), NULL);
|
||||
|
||||
if (iDevicesFound <= 0) {
|
||||
fprintf(stderr, "No CEC devices found\n");
|
||||
fflush(stderr);
|
||||
libcecc_destroy(&g_iface);
|
||||
return;
|
||||
}
|
||||
|
||||
strcpy(g_strPort, devices[0].comm);
|
||||
if (!g_iface.open(g_iface.connection, g_strPort, 5000)) {
|
||||
fprintf(stderr, "Unable to open the device on port %s\n", g_strPort);
|
||||
fflush(stderr);
|
||||
libcecc_destroy(&g_iface);
|
||||
return;
|
||||
}
|
||||
|
||||
g_iface.set_active_source(g_iface.connection, g_config.deviceTypes.types[0]);
|
||||
}
|
||||
#endif /* HAVE_LIBCEC */
|
||||
20
src/input/cec.h
Normal file
20
src/input/cec.h
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* This file is part of Moonlight Embedded.
|
||||
*
|
||||
* Copyright (C) 2015 Iwan Timmer
|
||||
*
|
||||
* Moonlight is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Moonlight is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Moonlight; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
void init_cec();
|
||||
537
src/input/evdev.c
Normal file
537
src/input/evdev.c
Normal file
@@ -0,0 +1,537 @@
|
||||
/*
|
||||
* This file is part of Moonlight Embedded.
|
||||
*
|
||||
* Copyright (C) 2015 Iwan Timmer
|
||||
*
|
||||
* Moonlight is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Moonlight is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Moonlight; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "../loop.h"
|
||||
#include "../global.h"
|
||||
|
||||
#include "keyboard.h"
|
||||
#include "mapping.h"
|
||||
|
||||
#include "libevdev/libevdev.h"
|
||||
#include "limelight-common/Limelight.h"
|
||||
|
||||
#include <libudev.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <poll.h>
|
||||
#include <limits.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
|
||||
struct input_abs_parms {
|
||||
int min, max;
|
||||
int flat;
|
||||
int avg;
|
||||
int range, diff;
|
||||
};
|
||||
|
||||
struct input_device {
|
||||
struct libevdev *dev;
|
||||
struct mapping map;
|
||||
int fd;
|
||||
char modifiers;
|
||||
__s32 mouseDeltaX, mouseDeltaY, mouseScroll;
|
||||
short controllerId;
|
||||
int buttonFlags;
|
||||
char leftTrigger, rightTrigger;
|
||||
short leftStickX, leftStickY;
|
||||
short rightStickX, rightStickY;
|
||||
bool gamepadModified;
|
||||
struct input_abs_parms xParms, yParms, rxParms, ryParms, zParms, rzParms;
|
||||
struct input_abs_parms dpadxParms, dpadyParms;
|
||||
};
|
||||
|
||||
static struct input_device* devices = NULL;
|
||||
static int numDevices = 0;
|
||||
static int assignedControllerIds = 0;
|
||||
|
||||
static short* currentKey;
|
||||
static short* currentAbs;
|
||||
static bool* currentReverse;
|
||||
|
||||
static bool grabbingDevices;
|
||||
|
||||
#define QUIT_MODIFIERS (MODIFIER_SHIFT|MODIFIER_ALT|MODIFIER_CTRL)
|
||||
#define QUIT_KEY KEY_Q
|
||||
|
||||
static bool (*handler) (struct input_event*, struct input_device*);
|
||||
|
||||
static void evdev_init_parms(struct input_device *dev, struct input_abs_parms *parms, int code) {
|
||||
parms->flat = libevdev_get_abs_flat(dev->dev, code);
|
||||
parms->min = libevdev_get_abs_minimum(dev->dev, code);
|
||||
parms->max = libevdev_get_abs_maximum(dev->dev, code);
|
||||
parms->avg = (parms->min+parms->max)/2;
|
||||
parms->range = parms->max - parms->avg;
|
||||
parms->diff = parms->max - parms->min;
|
||||
}
|
||||
|
||||
static void evdev_remove(int devindex) {
|
||||
numDevices--;
|
||||
|
||||
if (devices[devindex].controllerId >= 0)
|
||||
assignedControllerIds &= ~(1 << devices[devindex].controllerId);
|
||||
|
||||
if (devindex != numDevices && numDevices > 0)
|
||||
memcpy(&devices[devindex], &devices[numDevices], sizeof(struct input_device));
|
||||
|
||||
fprintf(stderr, "Removed input device\n");
|
||||
}
|
||||
|
||||
static short evdev_convert_value(struct input_event *ev, struct input_device *dev, struct input_abs_parms *parms, bool reverse) {
|
||||
if (abs(ev->value - parms->avg) < parms->flat)
|
||||
return 0;
|
||||
else if (ev->value > parms->max)
|
||||
return reverse?SHRT_MIN:SHRT_MAX;
|
||||
else if (ev->value < parms->min)
|
||||
return reverse?SHRT_MAX:SHRT_MIN;
|
||||
else if (reverse)
|
||||
return (parms->max - (ev->value<parms->avg?parms->flat*2:0) - ev->value) * (SHRT_MAX-SHRT_MIN) / (parms->max-parms->min-parms->flat*2) - SHRT_MIN;
|
||||
else
|
||||
return (ev->value - (ev->value>parms->avg?parms->flat*2:0) - parms->min) * (SHRT_MAX-SHRT_MIN) / (parms->max-parms->min-parms->flat*2) - SHRT_MIN;
|
||||
}
|
||||
|
||||
static char evdev_convert_value_byte(struct input_event *ev, struct input_device *dev, struct input_abs_parms *parms) {
|
||||
if (abs(ev->value-parms->min)<parms->flat)
|
||||
return 0;
|
||||
else if (ev->value>parms->max)
|
||||
return UCHAR_MAX;
|
||||
else {
|
||||
int value = ev->value - parms->flat;
|
||||
return (value-parms->min) * UCHAR_MAX / (parms->diff-parms->flat);
|
||||
}
|
||||
}
|
||||
|
||||
static int evdev_convert_value_direction(struct input_event *ev, struct input_device *dev, struct input_abs_parms *parms, bool reverse) {
|
||||
if (ev->value > (parms->avg+parms->range/4))
|
||||
return reverse?-1:1;
|
||||
else if (ev->value < (parms->avg-parms->range/4))
|
||||
return reverse?1:-1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool evdev_handle_event(struct input_event *ev, struct input_device *dev) {
|
||||
bool gamepadModified = false;
|
||||
|
||||
switch (ev->type) {
|
||||
case EV_SYN:
|
||||
if (dev->mouseDeltaX != 0 || dev->mouseDeltaY != 0) {
|
||||
LiSendMouseMoveEvent(dev->mouseDeltaX, dev->mouseDeltaY);
|
||||
dev->mouseDeltaX = 0;
|
||||
dev->mouseDeltaY = 0;
|
||||
}
|
||||
if (dev->mouseScroll != 0) {
|
||||
LiSendScrollEvent(dev->mouseScroll);
|
||||
dev->mouseScroll = 0;
|
||||
}
|
||||
if (dev->gamepadModified) {
|
||||
if (dev->controllerId < 0) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if ((assignedControllerIds & (1 << i)) == 0) {
|
||||
assignedControllerIds |= (1 << i);
|
||||
dev->controllerId = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
//Use id 0 when too many gamepads are connected
|
||||
if (dev->controllerId < 0)
|
||||
dev->controllerId = 0;
|
||||
}
|
||||
LiSendMultiControllerEvent(dev->controllerId, dev->buttonFlags, dev->leftTrigger, dev->rightTrigger, dev->leftStickX, dev->leftStickY, dev->rightStickX, dev->rightStickY);
|
||||
dev->gamepadModified = false;
|
||||
}
|
||||
break;
|
||||
case EV_KEY:
|
||||
if (ev->code < sizeof(keyCodes)/sizeof(keyCodes[0])) {
|
||||
char modifier = 0;
|
||||
switch (ev->code) {
|
||||
case KEY_LEFTSHIFT:
|
||||
case KEY_RIGHTSHIFT:
|
||||
modifier = MODIFIER_SHIFT;
|
||||
break;
|
||||
case KEY_LEFTALT:
|
||||
case KEY_RIGHTALT:
|
||||
modifier = MODIFIER_ALT;
|
||||
break;
|
||||
case KEY_LEFTCTRL:
|
||||
case KEY_RIGHTCTRL:
|
||||
modifier = MODIFIER_CTRL;
|
||||
break;
|
||||
}
|
||||
if (modifier != 0) {
|
||||
if (ev->value)
|
||||
dev->modifiers |= modifier;
|
||||
else
|
||||
dev->modifiers &= ~modifier;
|
||||
}
|
||||
|
||||
// Quit the stream if all the required quit keys are down
|
||||
if ((dev->modifiers & QUIT_MODIFIERS) == QUIT_MODIFIERS &&
|
||||
ev->code == QUIT_KEY && ev->value != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
short code = 0x80 << 8 | keyCodes[ev->code];
|
||||
LiSendKeyboardEvent(code, ev->value?KEY_ACTION_DOWN:KEY_ACTION_UP, dev->modifiers);
|
||||
} else {
|
||||
int mouseCode = 0;
|
||||
short gamepadCode = 0;
|
||||
switch (ev->code) {
|
||||
case BTN_LEFT:
|
||||
mouseCode = BUTTON_LEFT;
|
||||
break;
|
||||
case BTN_MIDDLE:
|
||||
mouseCode = BUTTON_MIDDLE;
|
||||
break;
|
||||
case BTN_RIGHT:
|
||||
mouseCode = BUTTON_RIGHT;
|
||||
break;
|
||||
default:
|
||||
if (ev->code == dev->map.btn_south)
|
||||
gamepadCode = A_FLAG;
|
||||
else if (ev->code == dev->map.btn_west)
|
||||
gamepadCode = X_FLAG;
|
||||
else if (ev->code == dev->map.btn_north)
|
||||
gamepadCode = Y_FLAG;
|
||||
else if (ev->code == dev->map.btn_east)
|
||||
gamepadCode = B_FLAG;
|
||||
else if (ev->code == dev->map.btn_dpad_up)
|
||||
gamepadCode = UP_FLAG;
|
||||
else if (ev->code == dev->map.btn_dpad_down)
|
||||
gamepadCode = DOWN_FLAG;
|
||||
else if (ev->code == dev->map.btn_dpad_right)
|
||||
gamepadCode = RIGHT_FLAG;
|
||||
else if (ev->code == dev->map.btn_dpad_left)
|
||||
gamepadCode = LEFT_FLAG;
|
||||
else if (ev->code == dev->map.btn_thumbl)
|
||||
gamepadCode = LS_CLK_FLAG;
|
||||
else if (ev->code == dev->map.btn_thumbr)
|
||||
gamepadCode = RS_CLK_FLAG;
|
||||
else if (ev->code == dev->map.btn_tl)
|
||||
gamepadCode = LB_FLAG;
|
||||
else if (ev->code == dev->map.btn_tr)
|
||||
gamepadCode = RB_FLAG;
|
||||
else if (ev->code == dev->map.btn_start)
|
||||
gamepadCode = PLAY_FLAG;
|
||||
else if (ev->code == dev->map.btn_select)
|
||||
gamepadCode = BACK_FLAG;
|
||||
else if (ev->code == dev->map.btn_mode)
|
||||
gamepadCode = SPECIAL_FLAG;
|
||||
}
|
||||
|
||||
if (mouseCode != 0) {
|
||||
LiSendMouseButtonEvent(ev->value?BUTTON_ACTION_PRESS:BUTTON_ACTION_RELEASE, mouseCode);
|
||||
} else {
|
||||
gamepadModified = true;
|
||||
|
||||
if (gamepadCode != 0) {
|
||||
if (ev->value)
|
||||
dev->buttonFlags |= gamepadCode;
|
||||
else
|
||||
dev->buttonFlags &= ~gamepadCode;
|
||||
} else if (ev->code == dev->map.btn_tl2)
|
||||
dev->leftTrigger = ev->value?UCHAR_MAX:0;
|
||||
else if (ev->code == dev->map.btn_tr2)
|
||||
dev->rightTrigger = ev->value?UCHAR_MAX:0;
|
||||
else {
|
||||
fprintf(stderr, "Unmapped button: %d\n", ev->code);
|
||||
gamepadModified = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case EV_REL:
|
||||
switch (ev->code) {
|
||||
case REL_X:
|
||||
dev->mouseDeltaX = ev->value;
|
||||
break;
|
||||
case REL_Y:
|
||||
dev->mouseDeltaY = ev->value;
|
||||
break;
|
||||
case REL_WHEEL:
|
||||
dev->mouseScroll = ev->value;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case EV_ABS:
|
||||
gamepadModified = true;
|
||||
if (ev->code == dev->map.abs_x)
|
||||
dev->leftStickX = evdev_convert_value(ev, dev, &dev->xParms, dev->map.reverse_x);
|
||||
else if (ev->code == dev->map.abs_y)
|
||||
dev->leftStickY = evdev_convert_value(ev, dev, &dev->yParms, dev->map.reverse_y);
|
||||
else if (ev->code == dev->map.abs_rx)
|
||||
dev->rightStickX = evdev_convert_value(ev, dev, &dev->rxParms, dev->map.reverse_rx);
|
||||
else if (ev->code == dev->map.abs_ry)
|
||||
dev->rightStickY = evdev_convert_value(ev, dev, &dev->ryParms, dev->map.reverse_ry);
|
||||
else if (ev->code == dev->map.abs_z)
|
||||
dev->leftTrigger = evdev_convert_value_byte(ev, dev, &dev->zParms);
|
||||
else if (ev->code == dev->map.abs_rz)
|
||||
dev->rightTrigger = evdev_convert_value_byte(ev, dev, &dev->rzParms);
|
||||
else if (ev->code == dev->map.abs_dpad_x) {
|
||||
int dir = evdev_convert_value_direction(ev, dev, &dev->dpadxParms, dev->map.reverse_dpad_x);
|
||||
if (dir == 1) {
|
||||
dev->buttonFlags |= RIGHT_FLAG;
|
||||
dev->buttonFlags &= ~LEFT_FLAG;
|
||||
} else if (dir == 0) {
|
||||
dev->buttonFlags &= ~RIGHT_FLAG;
|
||||
dev->buttonFlags &= ~LEFT_FLAG;
|
||||
} else {
|
||||
dev->buttonFlags &= ~RIGHT_FLAG;
|
||||
dev->buttonFlags |= LEFT_FLAG;
|
||||
}
|
||||
} else if (ev->code == dev->map.abs_dpad_y) {
|
||||
int dir = evdev_convert_value_direction(ev, dev, &dev->dpadyParms, dev->map.reverse_dpad_y);
|
||||
if (dir == 1) {
|
||||
dev->buttonFlags |= DOWN_FLAG;
|
||||
dev->buttonFlags &= ~UP_FLAG;
|
||||
} else if (dir == 0) {
|
||||
dev->buttonFlags &= ~DOWN_FLAG;
|
||||
dev->buttonFlags &= ~UP_FLAG;
|
||||
} else {
|
||||
dev->buttonFlags &= ~DOWN_FLAG;
|
||||
dev->buttonFlags |= UP_FLAG;
|
||||
}
|
||||
} else
|
||||
gamepadModified = false;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
dev->gamepadModified |= gamepadModified;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool evdev_handle_mapping_event(struct input_event *ev, struct input_device *dev) {
|
||||
switch (ev->type) {
|
||||
case EV_KEY:
|
||||
if (currentKey != NULL) {
|
||||
if (ev->value)
|
||||
*currentKey = ev->code;
|
||||
else if (ev->code == *currentKey)
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case EV_ABS:
|
||||
if (currentAbs != NULL) {
|
||||
struct input_abs_parms parms;
|
||||
evdev_init_parms(dev, &parms, ev->code);
|
||||
|
||||
if (ev->value > parms.avg + parms.range/2) {
|
||||
*currentAbs = ev->code;
|
||||
*currentReverse = false;
|
||||
} else if (ev->value < parms.avg - parms.range/2) {
|
||||
*currentAbs = ev->code;
|
||||
*currentReverse = true;
|
||||
} else if (ev->code == *currentAbs)
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void evdev_drain(void) {
|
||||
for (int i = 0; i < numDevices; i++) {
|
||||
struct input_event ev;
|
||||
while (libevdev_next_event(devices[i].dev, LIBEVDEV_READ_FLAG_NORMAL, &ev) >= 0);
|
||||
}
|
||||
}
|
||||
|
||||
static int evdev_handle(int fd) {
|
||||
for (int i=0;i<numDevices;i++) {
|
||||
if (devices[i].fd = fd) {
|
||||
int rc;
|
||||
struct input_event ev;
|
||||
while ((rc = libevdev_next_event(devices[i].dev, LIBEVDEV_READ_FLAG_NORMAL, &ev)) >= 0) {
|
||||
if (rc == LIBEVDEV_READ_STATUS_SYNC)
|
||||
fprintf(stderr, "Error: cannot keep up\n");
|
||||
else if (rc == LIBEVDEV_READ_STATUS_SUCCESS) {
|
||||
if (!handler(&ev, &devices[i]))
|
||||
return LOOP_RETURN;
|
||||
}
|
||||
}
|
||||
if (rc == -ENODEV) {
|
||||
evdev_remove(i);
|
||||
} else if (rc != -EAGAIN && rc < 0) {
|
||||
fprintf(stderr, "Error: %s\n", strerror(-rc));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
return LOOP_OK;
|
||||
}
|
||||
|
||||
void evdev_create(const char* device, char* mapFile) {
|
||||
int fd = open(device, O_RDONLY|O_NONBLOCK);
|
||||
if (fd <= 0) {
|
||||
fprintf(stderr, "Failed to open device %s\n", device);
|
||||
fflush(stderr);
|
||||
return;
|
||||
}
|
||||
|
||||
int dev = numDevices;
|
||||
numDevices++;
|
||||
|
||||
if (devices == NULL) {
|
||||
devices = malloc(sizeof(struct input_device));
|
||||
} else {
|
||||
devices = realloc(devices, sizeof(struct input_device)*numDevices);
|
||||
}
|
||||
|
||||
if (devices == NULL) {
|
||||
fprintf(stderr, "Not enough memory\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
memset(&devices[dev], 0, sizeof(devices[0]));
|
||||
devices[dev].fd = fd;
|
||||
devices[dev].dev = libevdev_new();
|
||||
libevdev_set_fd(devices[dev].dev, devices[dev].fd);
|
||||
|
||||
if (mapFile != NULL)
|
||||
mapping_load(mapFile, &(devices[dev].map));
|
||||
|
||||
devices[dev].controllerId = -1;
|
||||
evdev_init_parms(&devices[dev], &(devices[dev].xParms), devices[dev].map.abs_x);
|
||||
evdev_init_parms(&devices[dev], &(devices[dev].yParms), devices[dev].map.abs_y);
|
||||
evdev_init_parms(&devices[dev], &(devices[dev].zParms), devices[dev].map.abs_z);
|
||||
evdev_init_parms(&devices[dev], &(devices[dev].rxParms), devices[dev].map.abs_rx);
|
||||
evdev_init_parms(&devices[dev], &(devices[dev].ryParms), devices[dev].map.abs_ry);
|
||||
evdev_init_parms(&devices[dev], &(devices[dev].rzParms), devices[dev].map.abs_rz);
|
||||
evdev_init_parms(&devices[dev], &(devices[dev].dpadxParms), devices[dev].map.abs_dpad_x);
|
||||
evdev_init_parms(&devices[dev], &(devices[dev].dpadyParms), devices[dev].map.abs_dpad_y);
|
||||
|
||||
if (grabbingDevices) {
|
||||
if (ioctl(fd, EVIOCGRAB, 1) < 0) {
|
||||
fprintf(stderr, "EVIOCGRAB failed with error %d\n", errno);
|
||||
}
|
||||
}
|
||||
|
||||
loop_add_fd(devices[dev].fd, &evdev_handle, POLLIN);
|
||||
}
|
||||
|
||||
static void evdev_map_key(char* keyName, short* key) {
|
||||
printf("Press %s\n", keyName);
|
||||
currentKey = key;
|
||||
currentAbs = NULL;
|
||||
*key = -1;
|
||||
loop_main();
|
||||
|
||||
usleep(250000);
|
||||
evdev_drain();
|
||||
}
|
||||
|
||||
static void evdev_map_abs(char* keyName, short* abs, bool* reverse) {
|
||||
printf("Move %s\n", keyName);
|
||||
currentKey = NULL;
|
||||
currentAbs = abs;
|
||||
currentReverse = reverse;
|
||||
*abs = -1;
|
||||
loop_main();
|
||||
|
||||
usleep(250000);
|
||||
evdev_drain();
|
||||
}
|
||||
|
||||
static void evdev_map_abskey(char* keyName, short* key, short* abs, bool* reverse) {
|
||||
printf("Press %s\n", keyName);
|
||||
currentKey = key;
|
||||
currentAbs = abs;
|
||||
currentReverse = reverse;
|
||||
*key = -1;
|
||||
*abs = -1;
|
||||
*currentReverse = false;
|
||||
loop_main();
|
||||
|
||||
usleep(250000);
|
||||
evdev_drain();
|
||||
}
|
||||
|
||||
void evdev_map(char* fileName) {
|
||||
struct mapping map;
|
||||
|
||||
handler = evdev_handle_mapping_event;
|
||||
|
||||
evdev_map_abs("Left Stick Right", &(map.abs_x), &(map.reverse_x));
|
||||
evdev_map_abs("Left Stick Up", &(map.abs_y), &(map.reverse_y));
|
||||
evdev_map_key("Left Stick Button", &(map.btn_thumbl));
|
||||
|
||||
evdev_map_abs("Right Stick Right", &(map.abs_rx), &(map.reverse_rx));
|
||||
evdev_map_abs("Right Stick Up", &(map.abs_ry), &(map.reverse_ry));
|
||||
evdev_map_key("Right Stick Button", &(map.btn_thumbr));
|
||||
|
||||
evdev_map_abskey("D-Pad Right", &(map.btn_dpad_right), &(map.abs_dpad_x), &(map.reverse_dpad_x));
|
||||
if (map.btn_dpad_right >= 0)
|
||||
evdev_map_key("D-Pad Left", &(map.btn_dpad_left));
|
||||
else
|
||||
map.btn_dpad_left = -1;
|
||||
|
||||
evdev_map_abskey("D-Pad Down", &(map.btn_dpad_down), &(map.abs_dpad_y), &(map.reverse_dpad_y));
|
||||
if (map.btn_dpad_down >= 0)
|
||||
evdev_map_key("D-Pad Up", &(map.btn_dpad_up));
|
||||
else
|
||||
map.btn_dpad_up = -1;
|
||||
|
||||
evdev_map_key("Button X (1)", &(map.btn_west));
|
||||
evdev_map_key("Button A (2)", &(map.btn_south));
|
||||
evdev_map_key("Button B (3)", &(map.btn_east));
|
||||
evdev_map_key("Button Y (4)", &(map.btn_north));
|
||||
evdev_map_key("Back Button", &(map.btn_select));
|
||||
evdev_map_key("Start Button", &(map.btn_start));
|
||||
evdev_map_key("Special Button", &(map.btn_mode));
|
||||
|
||||
bool ignored;
|
||||
evdev_map_abskey("Left Trigger", &(map.btn_tl2), &(map.abs_z), &ignored);
|
||||
evdev_map_abskey("Right Trigger", &(map.btn_tr2), &(map.abs_rz), &ignored);
|
||||
|
||||
evdev_map_key("Left Bumper", &(map.btn_tl));
|
||||
evdev_map_key("Right Bumper", &(map.btn_tr));
|
||||
mapping_save(fileName, &map);
|
||||
}
|
||||
|
||||
void evdev_start() {
|
||||
// After grabbing, the only way to quit via the keyboard
|
||||
// is via the special key combo that the input handling
|
||||
// code looks for. For this reason, we wait to grab until
|
||||
// we're ready to take input events. Ctrl+C works up until
|
||||
// this point.
|
||||
for (int i = 0; i < numDevices; i++) {
|
||||
if (ioctl(devices[i].fd, EVIOCGRAB, 1) < 0) {
|
||||
fprintf(stderr, "EVIOCGRAB failed with error %d\n", errno);
|
||||
}
|
||||
}
|
||||
|
||||
// Any new input devices detected after this point will be grabbed immediately
|
||||
grabbingDevices = true;
|
||||
|
||||
// Handle input events until the quit combo is pressed
|
||||
}
|
||||
|
||||
void evdev_stop() {
|
||||
evdev_drain();
|
||||
}
|
||||
|
||||
void evdev_init() {
|
||||
handler = evdev_handle_event;
|
||||
}
|
||||
26
src/input/evdev.h
Normal file
26
src/input/evdev.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* This file is part of Moonlight Embedded.
|
||||
*
|
||||
* Copyright (C) 2015 Iwan Timmer
|
||||
*
|
||||
* Moonlight is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Moonlight is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Moonlight; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
void evdev_create(const char* device, char* mapFile);
|
||||
void evdev_loop();
|
||||
void evdev_map(char* fileName);
|
||||
|
||||
void evdev_init();
|
||||
void evdev_start();
|
||||
void evdev_stop();
|
||||
142
src/input/keyboard.h
Normal file
142
src/input/keyboard.h
Normal file
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* This file is part of Moonlight Embedded.
|
||||
*
|
||||
* Copyright (C) 2015 Iwan Timmer
|
||||
*
|
||||
* Moonlight is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Moonlight is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Moonlight; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
static const short keyCodes[] = {
|
||||
0, //VK_RESERVED
|
||||
0x1B, //VK_ESCAPE
|
||||
0x31, //VK_1
|
||||
0x32, //VK_2
|
||||
0x33, //VK_3
|
||||
0x34, //VK_4
|
||||
0x35, //VK_5
|
||||
0x36, //VK_6
|
||||
0x37, //VK_7
|
||||
0x38, //VK_8
|
||||
0x39, //VK_9
|
||||
0x30, //VK_0
|
||||
0xBD, //VK_MINUS
|
||||
0xBB, //VK_EQUALS
|
||||
0x08, //VK_BACK_SPACE
|
||||
0x09, //VK_TAB
|
||||
0x51, //VK_Q
|
||||
0x57, //VK_W
|
||||
0x45, //VK_E
|
||||
0x52, //VK_R
|
||||
0x54, //VK_T
|
||||
0x59, //VK_Y
|
||||
0x55, //VK_U
|
||||
0x49, //VK_I
|
||||
0x4F, //VK_O
|
||||
0x50, //VK_P
|
||||
0xDB, //VK_BRACELEFT
|
||||
0xDD, //VK_BRACERIGHT
|
||||
0x0D, //VK_ENTER
|
||||
0x11, //VK_CONTROL Left control
|
||||
0x41, //VK_A
|
||||
0x53, //VK_S
|
||||
0x44, //VK_D
|
||||
0x46, //VK_F
|
||||
0x47, //VK_G
|
||||
0x48, //VK_H
|
||||
0x4A, //VK_J
|
||||
0x4B, //VK_K
|
||||
0x4C, //VK_L
|
||||
0xBA, //VK_SEMICOLON
|
||||
0xDE, //VK_APOSTROPHE
|
||||
0xC0, //VK_GRAVE
|
||||
0x10, //VK_SHIFT Left shift
|
||||
0xDC, //VK_BACK_SLASH
|
||||
0x5A, //VK_Z
|
||||
0x58, //VK_X
|
||||
0x43, //VK_C
|
||||
0x56, //VK_V
|
||||
0x42, //VK_B
|
||||
0x4E, //VK_N
|
||||
0x4D, //VK_M
|
||||
0xBC, //VK_COMMA
|
||||
0xBE, //VK_DOT
|
||||
0xBF, //VK_SLASH
|
||||
0x10, //VK_SHIFT Right shift
|
||||
0, //VK_KPASTERISK
|
||||
0x11, //VK_ALT Left alt
|
||||
0x20, //VK_SPACE
|
||||
0x14, //VK_CAPS_LOCK
|
||||
0x70, //VK_F1
|
||||
0x71, //VK_F2
|
||||
0x72, //VK_F3
|
||||
0x73, //VK_F4
|
||||
0x74, //VK_F5
|
||||
0x75, //VK_F6
|
||||
0x76, //VK_F7
|
||||
0x77, //VK_F8
|
||||
0x78, //VK_F9
|
||||
0x79, //VK_F10
|
||||
0x90, //VK_NUM_LOCK
|
||||
0x91, //VK_SCROLL_LOCK
|
||||
0x67, //VK_NUMPAD7
|
||||
0x68, //VK_NUMPAD8
|
||||
0x69, //VK_NUMPAD9
|
||||
0, //VK_NUMPAD_MINUS
|
||||
0x64, //VK_NUMPAD4
|
||||
0x65, //VK_NUMPAD5
|
||||
0x66, //VK_NUMPAD6
|
||||
0, //VK_NUMPADPLUS
|
||||
0x61, //VK_NUMPAD1
|
||||
0x62, //VK_NUMPAD2
|
||||
0x63, //VK_NUMPAD3
|
||||
0x60, //VK_NUMPAD0
|
||||
0, //KeyEvent.VK_NUMPADDOT
|
||||
0,
|
||||
0, //KeyEvent.VK_ZENKAKUHANKAKU
|
||||
0, //KeyEvent.VK_102ND
|
||||
0x7A, //VK_F11
|
||||
0x7B, //VK_F12
|
||||
0, //KeyEvent.VK_RO
|
||||
0xF1, //VK_KATAKANA
|
||||
0xF2, //VK_HIRAGANA
|
||||
0, //VK_HENKAN
|
||||
0, //VK_KATAKANAHIRAGANA
|
||||
0, //VK_MUHENKAN
|
||||
0, //VK_KPJPCOMMA
|
||||
0, //VK_KPENTER
|
||||
0x11, //VK_CONTROL Right ctrl
|
||||
0, //VK_KPSLASH
|
||||
0, //VK_SYSRQ
|
||||
0x11, //VK_ALT Right alt
|
||||
0, //KeyEvent.VK_LINEFEED
|
||||
0x24, //VK_HOME
|
||||
0x26, //VK_UP
|
||||
0x21, //VK_PAGE_UP
|
||||
0x25, //VK_LEFT
|
||||
0x27, //VK_RIGHT
|
||||
0x23, //VK_END
|
||||
0x28, //VK_DOWN
|
||||
0x22, //VK_PAGE_DOWN
|
||||
0x9B, //VK_INSERT
|
||||
0x2E, //VK_DELETE
|
||||
0, //VK_MACRO
|
||||
0, //VK_MUTE
|
||||
0, //VK_VOLUMEDOWN
|
||||
0, //VK_VOLUMEUP
|
||||
0, //VK_POWER SC System Power Down
|
||||
0, //VK_KPEQUAL
|
||||
0, //VK_KPPLUSMINUS
|
||||
0x13, //VK_PAUSE
|
||||
0, //VK_SCALE AL Compiz Scale (Expose)
|
||||
};
|
||||
168
src/input/mapping.c
Normal file
168
src/input/mapping.c
Normal file
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* This file is part of Moonlight Embedded.
|
||||
*
|
||||
* Copyright (C) 2015 Iwan Timmer
|
||||
*
|
||||
* Moonlight is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Moonlight is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Moonlight; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "mapping.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define write_config(fd, key, value) fprintf(fd, "%s = %hd\n", key, value)
|
||||
#define write_config_bool(fd, key, value) fprintf(fd, "%s = %s\n", key, value?"true":"false");
|
||||
|
||||
void mapping_load(char* fileName, struct mapping* map) {
|
||||
FILE* fd = fopen(fileName, "r");
|
||||
if (fd == NULL) {
|
||||
fprintf(stderr, "Can't open mapping file: %s\n", fileName);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
char *line = NULL;
|
||||
size_t len = 0;
|
||||
while (getline(&line, &len, fd) != -1) {
|
||||
char *key = NULL, *value = NULL;
|
||||
if (sscanf(line, "%ms = %ms", &key, &value) == 2) {
|
||||
long int_value = strtol(value, NULL, 10);
|
||||
if (strcmp("abs_x", key) == 0)
|
||||
map->abs_x = int_value;
|
||||
else if (strcmp("abs_y", key) == 0)
|
||||
map->abs_y = int_value;
|
||||
else if (strcmp("abs_z", key) == 0)
|
||||
map->abs_z = int_value;
|
||||
else if (strcmp("abs_rx", key) == 0)
|
||||
map->abs_rx = int_value;
|
||||
else if (strcmp("abs_ry", key) == 0)
|
||||
map->abs_ry = int_value;
|
||||
else if (strcmp("abs_rz", key) == 0)
|
||||
map->abs_rz = int_value;
|
||||
else if (strcmp("abs_deadzone", key) == 0)
|
||||
map->abs_deadzone = int_value;
|
||||
else if (strcmp("abs_dpad_x", key) == 0)
|
||||
map->abs_dpad_x = int_value;
|
||||
else if (strcmp("abs_dpad_y", key) == 0)
|
||||
map->abs_dpad_y = int_value;
|
||||
else if (strcmp("btn_south", key) == 0)
|
||||
map->btn_south = int_value;
|
||||
else if (strcmp("btn_north", key) == 0)
|
||||
map->btn_north = int_value;
|
||||
else if (strcmp("btn_east", key) == 0)
|
||||
map->btn_east = int_value;
|
||||
else if (strcmp("btn_west", key) == 0)
|
||||
map->btn_west = int_value;
|
||||
else if (strcmp("btn_select", key) == 0)
|
||||
map->btn_select = int_value;
|
||||
else if (strcmp("btn_start", key) == 0)
|
||||
map->btn_start = int_value;
|
||||
else if (strcmp("btn_mode", key) == 0)
|
||||
map->btn_mode = int_value;
|
||||
else if (strcmp("btn_thumbl", key) == 0)
|
||||
map->btn_thumbl = int_value;
|
||||
else if (strcmp("btn_thumbr", key) == 0)
|
||||
map->btn_thumbr = int_value;
|
||||
else if (strcmp("btn_tl", key) == 0)
|
||||
map->btn_tl = int_value;
|
||||
else if (strcmp("btn_tr", key) == 0)
|
||||
map->btn_tr = int_value;
|
||||
else if (strcmp("btn_tl2", key) == 0)
|
||||
map->btn_tl2 = int_value;
|
||||
else if (strcmp("btn_tr2", key) == 0)
|
||||
map->btn_tr2 = int_value;
|
||||
else if (strcmp("btn_dpad_up", key) == 0)
|
||||
map->btn_dpad_up = int_value;
|
||||
else if (strcmp("btn_dpad_down", key) == 0)
|
||||
map->btn_dpad_down = int_value;
|
||||
else if (strcmp("btn_dpad_left", key) == 0)
|
||||
map->btn_dpad_left = int_value;
|
||||
else if (strcmp("btn_dpad_right", key) == 0)
|
||||
map->btn_dpad_right = int_value;
|
||||
else if (strcmp("reverse_x", key) == 0)
|
||||
map->reverse_x = strcmp("true", value) == 0;
|
||||
else if (strcmp("reverse_y", key) == 0)
|
||||
map->reverse_y = strcmp("true", value) == 0;
|
||||
else if (strcmp("reverse_rx", key) == 0)
|
||||
map->reverse_rx = strcmp("true", value) == 0;
|
||||
else if (strcmp("reverse_ry", key) == 0)
|
||||
map->reverse_ry = strcmp("true", value) == 0;
|
||||
else if (strcmp("reverse_dpad_x", key) == 0)
|
||||
map->reverse_dpad_x = strcmp("true", value) == 0;
|
||||
else if (strcmp("reverse_dpad_y", key) == 0)
|
||||
map->reverse_dpad_y = strcmp("true", value) == 0;
|
||||
else
|
||||
fprintf(stderr, "Can't map (%s)\n", key);
|
||||
}
|
||||
if (key != NULL)
|
||||
free(key);
|
||||
|
||||
if (value != NULL)
|
||||
free(value);
|
||||
}
|
||||
free(line);
|
||||
}
|
||||
|
||||
void mapping_save(char* fileName, struct mapping* map) {
|
||||
FILE* fd = fopen(fileName, "w");
|
||||
if (fd == NULL) {
|
||||
fprintf(stderr, "Can't open mapping file: %s\n", fileName);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
write_config(fd, "abs_x", map->abs_x);
|
||||
write_config(fd, "abs_y", map->abs_y);
|
||||
write_config(fd, "abs_z", map->abs_z);
|
||||
|
||||
write_config_bool(fd, "reverse_x", map->reverse_x);
|
||||
write_config_bool(fd, "reverse_y", map->reverse_y);
|
||||
|
||||
write_config(fd, "abs_rx", map->abs_rx);
|
||||
write_config(fd, "abs_ry", map->abs_ry);
|
||||
write_config(fd, "abs_rz", map->abs_rz);
|
||||
|
||||
write_config_bool(fd, "reverse_rx", map->reverse_rx);
|
||||
write_config_bool(fd, "reverse_ry", map->reverse_ry);
|
||||
|
||||
write_config(fd, "abs_deadzone", map->abs_deadzone);
|
||||
|
||||
write_config(fd, "abs_dpad_x", map->abs_dpad_x);
|
||||
write_config(fd, "abs_dpad_y", map->abs_dpad_y);
|
||||
|
||||
write_config_bool(fd, "reverse_dpad_x", map->reverse_dpad_x);
|
||||
write_config_bool(fd, "reverse_dpad_y", map->reverse_dpad_y);
|
||||
|
||||
write_config(fd, "btn_north", map->btn_north);
|
||||
write_config(fd, "btn_east", map->btn_east);
|
||||
write_config(fd, "btn_south", map->btn_south);
|
||||
write_config(fd, "btn_west", map->btn_west);
|
||||
|
||||
write_config(fd, "btn_select", map->btn_select);
|
||||
write_config(fd, "btn_start", map->btn_start);
|
||||
write_config(fd, "btn_mode", map->btn_mode);
|
||||
|
||||
write_config(fd, "btn_thumbl", map->btn_thumbl);
|
||||
write_config(fd, "btn_thumbr", map->btn_thumbr);
|
||||
|
||||
write_config(fd, "btn_tl", map->btn_tl);
|
||||
write_config(fd, "btn_tr", map->btn_tr);
|
||||
write_config(fd, "btn_tl2", map->btn_tl2);
|
||||
write_config(fd, "btn_tr2", map->btn_tr2);
|
||||
|
||||
write_config(fd, "btn_dpad_up", map->btn_dpad_up);
|
||||
write_config(fd, "btn_dpad_down", map->btn_dpad_down);
|
||||
write_config(fd, "btn_dpad_left", map->btn_dpad_left);
|
||||
write_config(fd, "btn_dpad_right", map->btn_dpad_right);
|
||||
}
|
||||
43
src/input/mapping.h
Normal file
43
src/input/mapping.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* This file is part of Moonlight Embedded.
|
||||
*
|
||||
* Copyright (C) 2015 Iwan Timmer
|
||||
*
|
||||
* Moonlight is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Moonlight is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Moonlight; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
struct mapping {
|
||||
short abs_x, abs_y, abs_z;
|
||||
short abs_rx, abs_ry, abs_rz;
|
||||
|
||||
bool reverse_x, reverse_y;
|
||||
bool reverse_rx, reverse_ry;
|
||||
|
||||
short abs_deadzone;
|
||||
|
||||
short abs_dpad_x, abs_dpad_y;
|
||||
bool reverse_dpad_x, reverse_dpad_y;
|
||||
|
||||
short btn_south, btn_east, btn_north, btn_west;
|
||||
short btn_select, btn_start, btn_mode;
|
||||
short btn_thumbl, btn_thumbr;
|
||||
short btn_tl, btn_tr, btn_tl2, btn_tr2;
|
||||
|
||||
short btn_dpad_up, btn_dpad_down, btn_dpad_left, btn_dpad_right;
|
||||
};
|
||||
|
||||
void mapping_load(char* fileName, struct mapping* map);
|
||||
void mapping_save(char* fileName, struct mapping* map);
|
||||
97
src/input/udev.c
Normal file
97
src/input/udev.c
Normal file
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* This file is part of Moonlight Embedded.
|
||||
*
|
||||
* Copyright (C) 2015 Iwan Timmer
|
||||
*
|
||||
* Moonlight is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Moonlight is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Moonlight; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "../loop.h"
|
||||
|
||||
#include "evdev.h"
|
||||
|
||||
#include <libudev.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <poll.h>
|
||||
|
||||
static bool autoadd;
|
||||
static char* defaultMapfile;
|
||||
|
||||
static struct udev *udev;
|
||||
static struct udev_monitor *udev_mon;
|
||||
static int udev_fd;
|
||||
|
||||
static int udev_handle(int fd) {
|
||||
struct udev_device *dev = udev_monitor_receive_device(udev_mon);
|
||||
const char *action = udev_device_get_action(dev);
|
||||
if (action != NULL) {
|
||||
if (autoadd && strcmp("add", action) == 0) {
|
||||
const char *devnode = udev_device_get_devnode(dev);
|
||||
int id;
|
||||
if (devnode != NULL && sscanf(devnode, "/dev/input/event%d", &id) == 1) {
|
||||
evdev_create(devnode, defaultMapfile);
|
||||
}
|
||||
}
|
||||
udev_device_unref(dev);
|
||||
}
|
||||
return LOOP_OK;
|
||||
}
|
||||
|
||||
void udev_init(bool autoload, char* mapfile) {
|
||||
udev = udev_new();
|
||||
if (!udev) {
|
||||
fprintf(stderr, "Can't create udev\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
autoadd = autoload;
|
||||
if (autoload) {
|
||||
struct udev_enumerate *enumerate = udev_enumerate_new(udev);
|
||||
udev_enumerate_add_match_subsystem(enumerate, "input");
|
||||
udev_enumerate_scan_devices(enumerate);
|
||||
struct udev_list_entry *devices = udev_enumerate_get_list_entry(enumerate);
|
||||
|
||||
struct udev_list_entry *dev_list_entry;
|
||||
udev_list_entry_foreach(dev_list_entry, devices) {
|
||||
const char *path = udev_list_entry_get_name(dev_list_entry);
|
||||
struct udev_device *dev = udev_device_new_from_syspath(udev, path);
|
||||
const char *devnode = udev_device_get_devnode(dev);
|
||||
int id;
|
||||
if (devnode != NULL && sscanf(devnode, "/dev/input/event%d", &id) == 1) {
|
||||
evdev_create(devnode, mapfile);
|
||||
}
|
||||
udev_device_unref(dev);
|
||||
}
|
||||
|
||||
udev_enumerate_unref(enumerate);
|
||||
}
|
||||
|
||||
udev_mon = udev_monitor_new_from_netlink(udev, "udev");
|
||||
udev_monitor_filter_add_match_subsystem_devtype(udev_mon, "input", NULL);
|
||||
udev_monitor_enable_receiving(udev_mon);
|
||||
|
||||
defaultMapfile = mapfile;
|
||||
|
||||
int udev_fd = udev_monitor_get_fd(udev_mon);
|
||||
loop_add_fd(udev_fd, &udev_handle, POLLIN);
|
||||
}
|
||||
|
||||
void evdev_destroy() {
|
||||
udev_unref(udev);
|
||||
}
|
||||
21
src/input/udev.h
Normal file
21
src/input/udev.h
Normal file
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* This file is part of Moonlight Embedded.
|
||||
*
|
||||
* Copyright (C) 2015 Iwan Timmer
|
||||
*
|
||||
* Moonlight is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Moonlight is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Moonlight; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
void udev_init(bool autoload, char* mapfile);
|
||||
void evdev_destroy();
|
||||
Reference in New Issue
Block a user