mirror of
https://github.com/moonlight-stream/moonlight-embedded.git
synced 2025-07-02 07:45:48 +00:00
Merge branch 'library' into pc
This commit is contained in:
commit
2dd653d22b
@ -4,19 +4,11 @@ cmake_minimum_required(VERSION 3.1)
|
||||
SET(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake")
|
||||
|
||||
aux_source_directory(./src SRC_LIST)
|
||||
aux_source_directory(./src/input SRC_LIST)
|
||||
list(APPEND SRC_LIST ./src/video/fake.c)
|
||||
|
||||
aux_source_directory(./third_party/moonlight-common-c/limelight-common SRC_LIST)
|
||||
aux_source_directory(./third_party/moonlight-common-c/limelight-common/OpenAES SRC_LIST)
|
||||
|
||||
include_directories(./third_party/moonlight-common-c)
|
||||
|
||||
set(MOONLIGHT_DEFINITIONS)
|
||||
|
||||
find_package(Threads REQUIRED)
|
||||
find_package(CURL REQUIRED)
|
||||
find_package(OpenSSL REQUIRED)
|
||||
find_package(EXPAT REQUIRED)
|
||||
find_package(ALSA REQUIRED)
|
||||
find_package(Opus REQUIRED)
|
||||
find_package(Broadcom)
|
||||
@ -25,18 +17,12 @@ find_package(CEC)
|
||||
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(EVDEV REQUIRED libevdev)
|
||||
pkg_check_modules(AVAHI REQUIRED avahi-client)
|
||||
pkg_check_modules(UDEV REQUIRED libudev)
|
||||
pkg_check_modules(SDL sdl2)
|
||||
pkg_check_modules(AVCODEC libavcodec)
|
||||
pkg_check_modules(AVUTIL libavutil)
|
||||
pkg_check_modules(SWSCALE libswscale)
|
||||
|
||||
if(CEC_FOUND)
|
||||
include_directories(./third_party/libcec)
|
||||
list(APPEND MOONLIGHT_DEFINITIONS HAVE_LIBCEC)
|
||||
endif()
|
||||
|
||||
if(BROADCOM_FOUND)
|
||||
aux_source_directory(./third_party/ilclient SRC_LIST)
|
||||
aux_source_directory(./third_party/h264bitstream SRC_LIST)
|
||||
@ -54,28 +40,37 @@ if (AVCODEC_FOUND AND AVUTIL_FOUND AND SWSCALE_FOUND AND SDL_FOUND)
|
||||
list(APPEND MOONLIGHT_DEFINITIONS HAVE_SDL)
|
||||
endif()
|
||||
|
||||
add_subdirectory(libgamestream)
|
||||
|
||||
add_executable(moonlight ${SRC_LIST})
|
||||
target_link_libraries(moonlight PUBLIC gamestream)
|
||||
set_property(TARGET moonlight PROPERTY C_STANDARD 11)
|
||||
|
||||
if (CEC_FOUND)
|
||||
list(APPEND MOONLIGHT_DEFINITIONS HAVE_LIBCEC)
|
||||
target_include_directories(moonlight PRIVATE ./third_party/libcec ${CEC_INCLUDE_DIRS})
|
||||
target_link_libraries (moonlight PUBLIC ${CEC_LIBRARIES})
|
||||
endif()
|
||||
|
||||
if(BROADCOM_FOUND)
|
||||
include_directories(./third_party/ilclient ./third_party/h264bitstream ${BROADCOM_INCLUDE_DIRS})
|
||||
target_include_directories(moonlight PRIVATE ./third_party/ilclient ./third_party/h264bitstream ${BROADCOM_INCLUDE_DIRS})
|
||||
target_link_libraries (moonlight PUBLIC ${BROADCOM_LIBRARIES})
|
||||
list(APPEND MOONLIGHT_DEFINITIONS ${BROADCOM_DEFINITIONS})
|
||||
endif()
|
||||
|
||||
if(FREESCALE_FOUND)
|
||||
include_directories(${FREESCALE_INCLUDE_DIRS})
|
||||
target_include_directories(moonlight PRIVATE ${FREESCALE_INCLUDE_DIRS})
|
||||
target_link_libraries (moonlight PUBLIC ${FREESCALE_LIBRARIES})
|
||||
endif()
|
||||
|
||||
if (AVCODEC_FOUND AND AVUTIL_FOUND AND SWSCALE_FOUND AND SDL_FOUND)
|
||||
include_directories(${SDL_INCLUDE_DIRS} ${AVCODEC_INCLUDE_DIRS} ${AVUTIL_INCLUDE_DIRS} ${SWSCALE_INCLUDE_DIRS})
|
||||
target_include_directories(moonlight PRIVATE ${SDL_INCLUDE_DIRS} ${AVCODEC_INCLUDE_DIRS} ${AVUTIL_INCLUDE_DIRS} ${SWSCALE_INCLUDE_DIRS})
|
||||
target_link_libraries(moonlight PUBLIC ${SDL_LIBRARIES} ${AVCODEC_LIBRARIES} ${AVUTIL_LIBRARIES} ${SWSCALE_LIBRARIES})
|
||||
endif()
|
||||
|
||||
set_property(TARGET moonlight PROPERTY COMPILE_DEFINITIONS ${MOONLIGHT_DEFINITIONS})
|
||||
include_directories(./third_party/moonlight-common-c ${OPUS_INCLUDE_DIRS} ${EVDEV_INCLUDE_DIRS} ${AVAHI_INCLUDE_DIRS} ${UDEV_INCLUDE_DIRS} ${CEC_INCLUDE_DIRS})
|
||||
target_link_libraries (moonlight PUBLIC ${CMAKE_THREAD_LIBS_INIT} ${CURL_LIBRARIES} ${OPENSSL_LIBRARIES} ${EXPAT_LIBRARIES} ${EVDEV_LIBRARIES} ${ALSA_LIBRARY} ${OPUS_LIBRARY} ${AVAHI_LIBRARIES} ${UDEV_LIBRARIES} ${CMAKE_DL_LIBS} ${CEC_LIBRARIES})
|
||||
target_include_directories(moonlight PRIVATE ./libgamestream ./third_party/moonlight-common-c ${OPUS_INCLUDE_DIRS} ${EVDEV_INCLUDE_DIRS} ${UDEV_INCLUDE_DIRS})
|
||||
target_link_libraries (moonlight PUBLIC ${EVDEV_LIBRARIES} ${ALSA_LIBRARY} ${OPUS_LIBRARY} ${UDEV_LIBRARIES} ${CMAKE_DL_LIBS})
|
||||
|
||||
include(${CMAKE_ROOT}/Modules/GNUInstallDirs.cmake)
|
||||
install(TARGETS moonlight DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
|
20
libgamestream/CMakeLists.txt
Normal file
20
libgamestream/CMakeLists.txt
Normal file
@ -0,0 +1,20 @@
|
||||
find_package(Threads REQUIRED)
|
||||
find_package(CURL REQUIRED)
|
||||
find_package(OpenSSL REQUIRED)
|
||||
find_package(EXPAT REQUIRED)
|
||||
|
||||
pkg_check_modules(AVAHI REQUIRED avahi-client)
|
||||
|
||||
aux_source_directory(./ GAMESTREAM_SRC_LIST)
|
||||
|
||||
aux_source_directory(../third_party/moonlight-common-c/limelight-common GAMESTREAM_SRC_LIST)
|
||||
aux_source_directory(../third_party/moonlight-common-c/limelight-common/OpenAES GAMESTREAM_SRC_LIST)
|
||||
|
||||
add_library(gamestream SHARED ${GAMESTREAM_SRC_LIST})
|
||||
set_property(TARGET gamestream PROPERTY C_STANDARD 11)
|
||||
set_target_properties(gamestream PROPERTIES SOVERSION 0 VERSION 2.1.0)
|
||||
|
||||
target_include_directories(gamestream PRIVATE ../third_party/moonlight-common-c ${AVAHI_INCLUDE_DIRS})
|
||||
target_link_libraries (gamestream PUBLIC ${CMAKE_THREAD_LIBS_INIT} ${CURL_LIBRARIES} ${OPENSSL_LIBRARIES} ${EXPAT_LIBRARIES} ${AVAHI_LIBRARIES} ${CMAKE_DL_LIBS})
|
||||
|
||||
#install(TARGETS gamestream DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
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_DOWN:KEY_ACTION_UP, 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();
|
@ -17,6 +17,8 @@
|
||||
* along with Moonlight; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "../loop.h"
|
||||
|
||||
#include "keyboard.h"
|
||||
#include "mapping.h"
|
||||
#include "global.h"
|
||||
@ -24,20 +26,13 @@
|
||||
#include "libevdev/libevdev.h"
|
||||
#include "limelight-common/Limelight.h"
|
||||
|
||||
#ifdef HAVE_LIBCEC
|
||||
#include <ceccloader.h>
|
||||
#endif
|
||||
|
||||
#include <libudev.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/signalfd.h>
|
||||
#include <fcntl.h>
|
||||
#include <poll.h>
|
||||
#include <limits.h>
|
||||
@ -55,7 +50,6 @@ struct input_device {
|
||||
struct libevdev *dev;
|
||||
struct mapping map;
|
||||
int fd;
|
||||
int fdindex;
|
||||
char modifiers;
|
||||
__s32 mouseDeltaX, mouseDeltaY, mouseScroll;
|
||||
short controllerId;
|
||||
@ -68,107 +62,17 @@ struct input_device {
|
||||
struct input_abs_parms dpadxParms, dpadyParms;
|
||||
};
|
||||
|
||||
static struct pollfd* fds = NULL;
|
||||
static struct input_device* devices = NULL;
|
||||
static int numDevices = 0, numFds = 0;
|
||||
static int numDevices = 0;
|
||||
static int assignedControllerIds = 0;
|
||||
|
||||
static short* currentKey;
|
||||
static short* currentAbs;
|
||||
static bool* currentReverse;
|
||||
|
||||
static bool autoadd;
|
||||
static char* defaultMapfile;
|
||||
static struct udev *udev;
|
||||
static struct udev_monitor *udev_mon;
|
||||
static int udev_fdindex;
|
||||
static bool (*handler) (struct input_event*, struct input_device*);
|
||||
|
||||
static int sig_fdindex;
|
||||
|
||||
#ifdef HAVE_LIBCEC
|
||||
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_DOWN:KEY_ACTION_UP, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static 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
|
||||
|
||||
static void input_init_parms(struct input_device *dev, struct input_abs_parms *parms, int code) {
|
||||
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);
|
||||
@ -177,154 +81,19 @@ static void input_init_parms(struct input_device *dev, struct input_abs_parms *p
|
||||
parms->diff = parms->max - parms->min;
|
||||
}
|
||||
|
||||
void input_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;
|
||||
int fdindex = numFds;
|
||||
numDevices++;
|
||||
numFds++;
|
||||
|
||||
if (fds == NULL) {
|
||||
fds = malloc(sizeof(struct pollfd));
|
||||
devices = malloc(sizeof(struct input_device));
|
||||
} else {
|
||||
fds = realloc(fds, sizeof(struct pollfd)*numFds);
|
||||
devices = realloc(devices, sizeof(struct input_device)*numDevices);
|
||||
}
|
||||
|
||||
if (fds == NULL || 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);
|
||||
devices[dev].fdindex = fdindex;
|
||||
fds[fdindex].fd = devices[dev].fd;
|
||||
fds[fdindex].events = POLLIN;
|
||||
|
||||
if (mapFile != NULL)
|
||||
mapping_load(mapFile, &(devices[dev].map));
|
||||
|
||||
devices[dev].controllerId = -1;
|
||||
input_init_parms(&devices[dev], &(devices[dev].xParms), devices[dev].map.abs_x);
|
||||
input_init_parms(&devices[dev], &(devices[dev].yParms), devices[dev].map.abs_y);
|
||||
input_init_parms(&devices[dev], &(devices[dev].zParms), devices[dev].map.abs_z);
|
||||
input_init_parms(&devices[dev], &(devices[dev].rxParms), devices[dev].map.abs_rx);
|
||||
input_init_parms(&devices[dev], &(devices[dev].ryParms), devices[dev].map.abs_ry);
|
||||
input_init_parms(&devices[dev], &(devices[dev].rzParms), devices[dev].map.abs_rz);
|
||||
input_init_parms(&devices[dev], &(devices[dev].dpadxParms), devices[dev].map.abs_dpad_x);
|
||||
input_init_parms(&devices[dev], &(devices[dev].dpadyParms), devices[dev].map.abs_dpad_y);
|
||||
}
|
||||
|
||||
static void input_remove(int devindex) {
|
||||
static void evdev_remove(int devindex) {
|
||||
numDevices--;
|
||||
numFds--;
|
||||
|
||||
if (devices[devindex].controllerId >= 0)
|
||||
assignedControllerIds &= ~(1 << devices[devindex].controllerId);
|
||||
|
||||
int fdindex = devices[devindex].fdindex;
|
||||
if (fdindex != numFds && numFds > 0) {
|
||||
memcpy(&fds[fdindex], &fds[numFds], sizeof(struct pollfd));
|
||||
if (numFds == udev_fdindex)
|
||||
udev_fdindex = fdindex;
|
||||
else if (numFds == sig_fdindex)
|
||||
sig_fdindex = fdindex;
|
||||
else {
|
||||
for (int i=0;i<numDevices;i++) {
|
||||
if (devices[i].fdindex == numFds) {
|
||||
devices[i].fdindex = fdindex;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (devindex != numDevices && numDevices > 0)
|
||||
memcpy(&devices[devindex], &devices[numDevices], sizeof(struct input_device));
|
||||
|
||||
fprintf(stderr, "Removed input device\n");
|
||||
}
|
||||
|
||||
void input_init(char* mapfile) {
|
||||
#ifdef HAVE_LIBCEC
|
||||
init_cec();
|
||||
#endif
|
||||
|
||||
udev = udev_new();
|
||||
if (!udev) {
|
||||
fprintf(stderr, "Can't create udev\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
autoadd = (numDevices == 0);
|
||||
if (autoadd) {
|
||||
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) {
|
||||
input_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);
|
||||
|
||||
udev_fdindex = numFds++;
|
||||
sig_fdindex = numFds++;
|
||||
|
||||
if (fds == NULL)
|
||||
fds = malloc(sizeof(struct pollfd)*numFds);
|
||||
else
|
||||
fds = realloc(fds, sizeof(struct pollfd)*numFds);
|
||||
|
||||
if (fds == NULL) {
|
||||
fprintf(stderr, "Not enough memory\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
defaultMapfile = mapfile;
|
||||
fds[udev_fdindex].fd = udev_monitor_get_fd(udev_mon);
|
||||
fds[udev_fdindex].events = POLLIN;
|
||||
|
||||
main_thread_id = pthread_self();
|
||||
sigset_t sigset;
|
||||
sigemptyset(&sigset);
|
||||
sigaddset(&sigset, SIGHUP);
|
||||
sigaddset(&sigset, SIGTERM);
|
||||
sigaddset(&sigset, SIGINT);
|
||||
sigaddset(&sigset, SIGQUIT);
|
||||
sigprocmask(SIG_BLOCK, &sigset, NULL);
|
||||
fds[sig_fdindex].fd = signalfd(-1, &sigset, 0);
|
||||
fds[sig_fdindex].events = POLLIN | POLLERR | POLLHUP;
|
||||
}
|
||||
|
||||
void input_destroy() {
|
||||
udev_unref(udev);
|
||||
}
|
||||
|
||||
static short input_convert_value(struct input_event *ev, struct input_device *dev, struct input_abs_parms *parms, bool reverse) {
|
||||
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)
|
||||
@ -337,7 +106,7 @@ static short input_convert_value(struct input_event *ev, struct input_device *de
|
||||
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 input_convert_value_byte(struct input_event *ev, struct input_device *dev, struct input_abs_parms *parms) {
|
||||
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)
|
||||
@ -348,7 +117,7 @@ static char input_convert_value_byte(struct input_event *ev, struct input_device
|
||||
}
|
||||
}
|
||||
|
||||
static int input_convert_value_direction(struct input_event *ev, struct input_device *dev, struct input_abs_parms *parms, bool reverse) {
|
||||
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))
|
||||
@ -357,7 +126,7 @@ static int input_convert_value_direction(struct input_event *ev, struct input_de
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool input_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;
|
||||
|
||||
switch (ev->type) {
|
||||
@ -495,19 +264,19 @@ static bool input_handle_event(struct input_event *ev, struct input_device *dev)
|
||||
case EV_ABS:
|
||||
gamepadModified = true;
|
||||
if (ev->code == dev->map.abs_x)
|
||||
dev->leftStickX = input_convert_value(ev, dev, &dev->xParms, dev->map.reverse_x);
|
||||
dev->leftStickX = evdev_convert_value(ev, dev, &dev->xParms, dev->map.reverse_x);
|
||||
else if (ev->code == dev->map.abs_y)
|
||||
dev->leftStickY = input_convert_value(ev, dev, &dev->yParms, dev->map.reverse_y);
|
||||
dev->leftStickY = evdev_convert_value(ev, dev, &dev->yParms, dev->map.reverse_y);
|
||||
else if (ev->code == dev->map.abs_rx)
|
||||
dev->rightStickX = input_convert_value(ev, dev, &dev->rxParms, dev->map.reverse_rx);
|
||||
dev->rightStickX = evdev_convert_value(ev, dev, &dev->rxParms, dev->map.reverse_rx);
|
||||
else if (ev->code == dev->map.abs_ry)
|
||||
dev->rightStickY = input_convert_value(ev, dev, &dev->ryParms, dev->map.reverse_ry);
|
||||
dev->rightStickY = evdev_convert_value(ev, dev, &dev->ryParms, dev->map.reverse_ry);
|
||||
else if (ev->code == dev->map.abs_z)
|
||||
dev->leftTrigger = input_convert_value_byte(ev, dev, &dev->zParms);
|
||||
dev->leftTrigger = evdev_convert_value_byte(ev, dev, &dev->zParms);
|
||||
else if (ev->code == dev->map.abs_rz)
|
||||
dev->rightTrigger = input_convert_value_byte(ev, dev, &dev->rzParms);
|
||||
dev->rightTrigger = evdev_convert_value_byte(ev, dev, &dev->rzParms);
|
||||
else if (ev->code == dev->map.abs_dpad_x) {
|
||||
int dir = input_convert_value_direction(ev, dev, &dev->dpadxParms, dev->map.reverse_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;
|
||||
@ -519,7 +288,7 @@ static bool input_handle_event(struct input_event *ev, struct input_device *dev)
|
||||
dev->buttonFlags |= LEFT_FLAG;
|
||||
}
|
||||
} else if (ev->code == dev->map.abs_dpad_y) {
|
||||
int dir = input_convert_value_direction(ev, dev, &dev->dpadyParms, dev->map.reverse_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;
|
||||
@ -540,7 +309,7 @@ static bool input_handle_event(struct input_event *ev, struct input_device *dev)
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool input_handle_mapping_event(struct input_event *ev, struct input_device *dev) {
|
||||
static bool evdev_handle_mapping_event(struct input_event *ev, struct input_device *dev) {
|
||||
switch (ev->type) {
|
||||
case EV_KEY:
|
||||
if (currentKey != NULL) {
|
||||
@ -553,7 +322,7 @@ static bool input_handle_mapping_event(struct input_event *ev, struct input_devi
|
||||
case EV_ABS:
|
||||
if (currentAbs != NULL) {
|
||||
struct input_abs_parms parms;
|
||||
input_init_parms(dev, &parms, ev->code);
|
||||
evdev_init_parms(dev, &parms, ev->code);
|
||||
|
||||
if (ev->value > parms.avg + parms.range/2) {
|
||||
*currentAbs = ev->code;
|
||||
@ -569,91 +338,104 @@ static bool input_handle_mapping_event(struct input_event *ev, struct input_devi
|
||||
return true;
|
||||
}
|
||||
|
||||
static void input_drain(void) {
|
||||
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 bool input_poll(bool (*handler) (struct input_event*, struct input_device*)) {
|
||||
while (poll(fds, numFds, -1)) {
|
||||
if (fds[udev_fdindex].revents > 0) {
|
||||
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) {
|
||||
input_create(devnode, defaultMapfile);
|
||||
}
|
||||
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;
|
||||
}
|
||||
udev_device_unref(dev);
|
||||
}
|
||||
} else if (fds[sig_fdindex].revents > 0) {
|
||||
struct signalfd_siginfo info;
|
||||
read(fds[sig_fdindex].fd, &info, sizeof(info));
|
||||
|
||||
switch (info.ssi_signo) {
|
||||
case SIGINT:
|
||||
case SIGTERM:
|
||||
case SIGQUIT:
|
||||
case SIGHUP:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (int i=0;i<numDevices;i++) {
|
||||
if (fds[devices[i].fdindex].revents > 0) {
|
||||
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 true;
|
||||
}
|
||||
}
|
||||
if (rc == -ENODEV) {
|
||||
input_remove(i);
|
||||
} else if (rc != -EAGAIN && rc < 0) {
|
||||
fprintf(stderr, "Error: %s\n", strerror(-rc));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (rc == -ENODEV) {
|
||||
evdev_remove(i);
|
||||
} else if (rc != -EAGAIN && rc < 0) {
|
||||
fprintf(stderr, "Error: %s\n", strerror(-rc));
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return LOOP_OK;
|
||||
}
|
||||
|
||||
static void input_map_key(char* keyName, short* key) {
|
||||
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);
|
||||
|
||||
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;
|
||||
if (!input_poll(input_handle_mapping_event))
|
||||
exit(1);
|
||||
loop_main();
|
||||
|
||||
usleep(250000);
|
||||
input_drain();
|
||||
evdev_drain();
|
||||
}
|
||||
|
||||
static void input_map_abs(char* keyName, short* abs, bool* reverse) {
|
||||
static void evdev_map_abs(char* keyName, short* abs, bool* reverse) {
|
||||
printf("Move %s\n", keyName);
|
||||
currentKey = NULL;
|
||||
currentAbs = abs;
|
||||
currentReverse = reverse;
|
||||
*abs = -1;
|
||||
if (!input_poll(input_handle_mapping_event))
|
||||
exit(1);
|
||||
loop_main();
|
||||
|
||||
usleep(250000);
|
||||
input_drain();
|
||||
evdev_drain();
|
||||
}
|
||||
|
||||
static void input_map_abskey(char* keyName, short* key, short* abs, bool* reverse) {
|
||||
static void evdev_map_abskey(char* keyName, short* key, short* abs, bool* reverse) {
|
||||
printf("Press %s\n", keyName);
|
||||
currentKey = key;
|
||||
currentAbs = abs;
|
||||
@ -661,53 +443,54 @@ static void input_map_abskey(char* keyName, short* key, short* abs, bool* revers
|
||||
*key = -1;
|
||||
*abs = -1;
|
||||
*currentReverse = false;
|
||||
if (!input_poll(input_handle_mapping_event))
|
||||
exit(1);
|
||||
loop_main();
|
||||
|
||||
usleep(250000);
|
||||
input_drain();
|
||||
evdev_drain();
|
||||
}
|
||||
|
||||
void input_map(char* fileName) {
|
||||
void evdev_map(char* fileName) {
|
||||
struct mapping map;
|
||||
|
||||
input_map_abs("Left Stick Right", &(map.abs_x), &(map.reverse_x));
|
||||
input_map_abs("Left Stick Up", &(map.abs_y), &(map.reverse_y));
|
||||
input_map_key("Left Stick Button", &(map.btn_thumbl));
|
||||
handler = evdev_handle_mapping_event;
|
||||
|
||||
input_map_abs("Right Stick Right", &(map.abs_rx), &(map.reverse_rx));
|
||||
input_map_abs("Right Stick Up", &(map.abs_ry), &(map.reverse_ry));
|
||||
input_map_key("Right Stick Button", &(map.btn_thumbr));
|
||||
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));
|
||||
|
||||
input_map_abskey("D-Pad Right", &(map.btn_dpad_right), &(map.abs_dpad_x), &(map.reverse_dpad_x));
|
||||
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)
|
||||
input_map_key("D-Pad Left", &(map.btn_dpad_left));
|
||||
evdev_map_key("D-Pad Left", &(map.btn_dpad_left));
|
||||
else
|
||||
map.btn_dpad_left = -1;
|
||||
|
||||
input_map_abskey("D-Pad Down", &(map.btn_dpad_down), &(map.abs_dpad_y), &(map.reverse_dpad_y));
|
||||
evdev_map_abskey("D-Pad Down", &(map.btn_dpad_down), &(map.abs_dpad_y), &(map.reverse_dpad_y));
|
||||
if (map.btn_dpad_down >= 0)
|
||||
input_map_key("D-Pad Up", &(map.btn_dpad_up));
|
||||
evdev_map_key("D-Pad Up", &(map.btn_dpad_up));
|
||||
else
|
||||
map.btn_dpad_up = -1;
|
||||
|
||||
input_map_key("Button X (1)", &(map.btn_west));
|
||||
input_map_key("Button A (2)", &(map.btn_south));
|
||||
input_map_key("Button B (3)", &(map.btn_east));
|
||||
input_map_key("Button Y (4)", &(map.btn_north));
|
||||
input_map_key("Back Button", &(map.btn_select));
|
||||
input_map_key("Start Button", &(map.btn_start));
|
||||
input_map_key("Special Button", &(map.btn_mode));
|
||||
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;
|
||||
input_map_abskey("Left Trigger", &(map.btn_tl2), &(map.abs_z), &ignored);
|
||||
input_map_abskey("Right Trigger", &(map.btn_tr2), &(map.abs_rz), &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);
|
||||
|
||||
input_map_key("Left Bumper", &(map.btn_tl));
|
||||
input_map_key("Right Bumper", &(map.btn_tr));
|
||||
evdev_map_key("Left Bumper", &(map.btn_tl));
|
||||
evdev_map_key("Right Bumper", &(map.btn_tr));
|
||||
mapping_save(fileName, &map);
|
||||
}
|
||||
|
||||
void input_loop() {
|
||||
input_poll(input_handle_event);
|
||||
void evdev_init() {
|
||||
handler = evdev_handle_event;
|
||||
}
|
@ -17,9 +17,8 @@
|
||||
* along with Moonlight; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
void input_init(char* mapfile);
|
||||
void input_create(char* device, char* mapFile);
|
||||
void input_loop();
|
||||
void input_map(char* fileName);
|
||||
void evdev_create(const char* device, char* mapFile);
|
||||
void evdev_loop();
|
||||
void evdev_map(char* fileName);
|
||||
|
||||
void input_destroy();
|
||||
void evdev_init();
|
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();
|
113
src/loop.c
Normal file
113
src/loop.c
Normal file
@ -0,0 +1,113 @@
|
||||
/*
|
||||
* 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 <sys/stat.h>
|
||||
#include <sys/signalfd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <poll.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
|
||||
static struct pollfd* fds = NULL;
|
||||
static FdHandler* fdHandlers = NULL;
|
||||
static int numFds = 0;
|
||||
|
||||
static int sigFd;
|
||||
|
||||
static int loop_sig_handler(int fd) {
|
||||
struct signalfd_siginfo info;
|
||||
read(fd, &info, sizeof(info));
|
||||
switch (info.ssi_signo) {
|
||||
case SIGINT:
|
||||
case SIGTERM:
|
||||
case SIGQUIT:
|
||||
case SIGHUP:
|
||||
return LOOP_RETURN;
|
||||
}
|
||||
return LOOP_OK;
|
||||
}
|
||||
|
||||
void loop_add_fd(int fd, FdHandler handler, int events) {
|
||||
int fdindex = numFds;
|
||||
numFds++;
|
||||
|
||||
if (fds == NULL) {
|
||||
fds = malloc(sizeof(struct pollfd));
|
||||
fdHandlers = malloc(sizeof(FdHandler*));
|
||||
} else {
|
||||
fds = realloc(fds, sizeof(struct pollfd)*numFds);
|
||||
fdHandlers = realloc(fdHandlers, sizeof(FdHandler*)*numFds);
|
||||
}
|
||||
|
||||
if (fds == NULL || fdHandlers == NULL) {
|
||||
fprintf(stderr, "Not enough memory\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
fds[fdindex].fd = fd;
|
||||
fds[fdindex].events = events;
|
||||
}
|
||||
|
||||
void loop_remove_fd(int fd) {
|
||||
numFds--;
|
||||
int fdindex;
|
||||
|
||||
for (int i=0;i<numFds;i++) {
|
||||
if (fds[i].fd = fd)
|
||||
fdindex = i;
|
||||
break;
|
||||
}
|
||||
|
||||
if (fdindex != numFds && numFds > 0) {
|
||||
memcpy(&fds[fdindex], &fds[numFds], sizeof(struct pollfd));
|
||||
memcpy(&fdHandlers[fdindex], &fdHandlers[numFds], sizeof(FdHandler*));
|
||||
}
|
||||
}
|
||||
|
||||
void loop_main() {
|
||||
main_thread_id = pthread_self();
|
||||
sigset_t sigset;
|
||||
sigemptyset(&sigset);
|
||||
sigaddset(&sigset, SIGHUP);
|
||||
sigaddset(&sigset, SIGTERM);
|
||||
sigaddset(&sigset, SIGINT);
|
||||
sigaddset(&sigset, SIGQUIT);
|
||||
sigprocmask(SIG_BLOCK, &sigset, NULL);
|
||||
sigFd = signalfd(-1, &sigset, 0);
|
||||
loop_add_fd(sigFd, loop_sig_handler, POLLIN | POLLERR | POLLHUP);
|
||||
|
||||
//static bool evdev_poll(bool (*handler) (struct input_event*, struct input_device*)) {
|
||||
while (poll(fds, numFds, -1)) {
|
||||
for (int i=0;i<numFds;i++) {
|
||||
if (fds[i].revents > 0) {
|
||||
int ret = fdHandlers[i](fds[i].fd);
|
||||
if (ret == LOOP_RETURN) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
28
src/loop.h
Normal file
28
src/loop.h
Normal file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
#define LOOP_RETURN 1
|
||||
#define LOOP_OK 0
|
||||
|
||||
typedef int(*FdHandler)(int fd);
|
||||
|
||||
void loop_add_fd(int fd, FdHandler handler, int events);
|
||||
void loop_remove_fd(int fd);
|
||||
|
||||
void loop_main();
|
22
src/main.c
22
src/main.c
@ -17,13 +17,17 @@
|
||||
* along with Moonlight; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "loop.h"
|
||||
#include "client.h"
|
||||
#include "connection.h"
|
||||
#include "video.h"
|
||||
#include "audio.h"
|
||||
#include "input.h"
|
||||
#include "discover.h"
|
||||
|
||||
#include "input/evdev.h"
|
||||
#include "input/udev.h"
|
||||
#include "input/cec.h"
|
||||
|
||||
#include "limelight-common/Limelight.h"
|
||||
|
||||
#include <stdio.h>
|
||||
@ -60,10 +64,14 @@ static void stream(STREAM_CONFIGURATION* config, const char* address, const char
|
||||
client_start_app(config, address, appId, sops, localaudio);
|
||||
|
||||
video_init();
|
||||
evdev_init();
|
||||
#ifdef HAVE_LIBCEC
|
||||
cec_init();
|
||||
#endif /* HAVE_LIBCEC */
|
||||
|
||||
LiStartConnection(address, config, &connection_callbacks, decoder_callbacks, &audio_callbacks, NULL, NULL, 0, client_get_server_version());
|
||||
|
||||
input_loop();
|
||||
loop_main();
|
||||
|
||||
LiStopConnection();
|
||||
}
|
||||
@ -172,6 +180,7 @@ int main(int argc, char* argv[]) {
|
||||
int option_index = 0;
|
||||
bool sops = true;
|
||||
bool localaudio = false;
|
||||
bool autoadd = true;
|
||||
int c;
|
||||
while ((c = getopt_long_only(argc, argv, "-abc:d:efg:h:i:j:k:lm:n", long_options, &option_index)) != -1) {
|
||||
switch (c) {
|
||||
@ -205,7 +214,8 @@ int main(int argc, char* argv[]) {
|
||||
app = optarg;
|
||||
break;
|
||||
case 'j':
|
||||
input_create(optarg, mapping);
|
||||
evdev_create(optarg, mapping);
|
||||
autoadd = false;
|
||||
break;
|
||||
case 'k':
|
||||
mapping = get_path(optarg);
|
||||
@ -238,8 +248,8 @@ int main(int argc, char* argv[]) {
|
||||
perror("No filename for mapping");
|
||||
exit(-1);
|
||||
}
|
||||
input_init(mapping);
|
||||
input_map(address);
|
||||
udev_init(autoadd, mapping);
|
||||
evdev_map(address);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
@ -263,7 +273,7 @@ int main(int argc, char* argv[]) {
|
||||
pair_check();
|
||||
applist(address);
|
||||
} else if (strcmp("stream", action) == 0) {
|
||||
input_init(mapping);
|
||||
udev_init(autoadd, mapping);
|
||||
pair_check();
|
||||
stream(&config, address, app, sops, localaudio);
|
||||
} else if (strcmp("pair", action) == 0)
|
||||
|
Loading…
x
Reference in New Issue
Block a user