diff --git a/CMakeLists.txt b/CMakeLists.txt index 28f9cd2..a798374 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,8 @@ cmake_minimum_required(VERSION 3.1) -project(moonlight-embedded VERSION 2.4.3 LANGUAGES C) +project(moonlight-embedded VERSION 2.4.4 LANGUAGES C) SET(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake") include(${CMAKE_ROOT}/Modules/GNUInstallDirs.cmake) +set_property(GLOBAL PROPERTY C_STANDARD 99) aux_source_directory(./src SRC_LIST) list(APPEND SRC_LIST ./src/input/evdev.c ./src/input/mapping.c ./src/input/udev.c) @@ -25,7 +26,7 @@ pkg_check_modules(VDPAU vdpau) pkg_check_modules(LIBVA libva) pkg_check_modules(LIBVA_X11 libva-x11) pkg_check_modules(PULSE libpulse-simple) -pkg_check_modules(CEC libcec>=3.0.0) +pkg_check_modules(CEC libcec>=4) pkg_check_modules(EGL egl) pkg_check_modules(GLES glesv2) @@ -106,7 +107,6 @@ add_subdirectory(libgamestream) add_executable(moonlight ${SRC_LIST}) target_link_libraries(moonlight gamestream) -set_property(TARGET moonlight PROPERTY C_STANDARD 99) if (CEC_FOUND) list(APPEND MOONLIGHT_DEFINITIONS HAVE_LIBCEC) diff --git a/cmake/FindFreescale.cmake b/cmake/FindFreescale.cmake index 0063c89..8092a54 100644 --- a/cmake/FindFreescale.cmake +++ b/cmake/FindFreescale.cmake @@ -7,7 +7,7 @@ mark_as_advanced(BROADCOM_INCLUDE_DIR) find_path(KERNEL_INCLUDE_DIR NAMES linux/mxc_v4l2.h DOC "Kernel include directory" - PATHS /lib/modules/${CMAKE_SYSTEM_VERSION}/build) + PATHS /lib/modules/${CMAKE_SYSTEM_VERSION}/build/include) mark_as_advanced(KERNEL_INCLUDE_DIR) find_library(VPU_LIBRARY diff --git a/docs/README.pod b/docs/README.pod index 5eb375e..7aeb5f2 100644 --- a/docs/README.pod +++ b/docs/README.pod @@ -31,6 +31,10 @@ List all available games and application on host. Quit the current running game or application on host. +=item B + +Create a mapping for the specified I device. + =item B Show help for all available commands. diff --git a/libgamestream/CMakeLists.txt b/libgamestream/CMakeLists.txt index 3e5e521..06c1b21 100644 --- a/libgamestream/CMakeLists.txt +++ b/libgamestream/CMakeLists.txt @@ -1,4 +1,5 @@ set(SO_VERSION 2) +set_property(GLOBAL PROPERTY C_STANDARD 99) find_package(LibUUID REQUIRED) find_package(Threads REQUIRED) @@ -16,10 +17,8 @@ aux_source_directory(../third_party/moonlight-common-c/src MOONLIGHT_COMMON_SRC_ aux_source_directory(../third_party/moonlight-common-c/reedsolomon MOONLIGHT_COMMON_SRC_LIST) add_library(moonlight-common SHARED ${MOONLIGHT_COMMON_SRC_LIST}) -set_property(TARGET moonlight-common PROPERTY C_STANDARD 99) add_library(gamestream SHARED ${GAMESTREAM_SRC_LIST}) -set_property(TARGET gamestream PROPERTY C_STANDARD 99) target_link_libraries(gamestream moonlight-common) set_target_properties(gamestream PROPERTIES SOVERSION ${SO_VERSION} VERSION ${PROJECT_VERSION}) diff --git a/libgamestream/client.c b/libgamestream/client.c index a296f5e..e19936a 100644 --- a/libgamestream/client.c +++ b/libgamestream/client.c @@ -245,7 +245,7 @@ static int load_server_status(PSERVER_DATA server) { server->supports4K = serverCodecModeSupportText != NULL; server->serverMajorVersion = atoi(server->serverInfo.serverInfoAppVersion); - if (strstr(stateText, "_SERVER_AVAILABLE")) { + if (strstr(stateText, "_SERVER_BUSY") == NULL) { // After GFE 2.8, current game remains set even after streaming // has ended. We emulate the old behavior by forcing it to zero // if streaming is not active. diff --git a/src/config.c b/src/config.c index 32a4d72..3697ffc 100644 --- a/src/config.c +++ b/src/config.c @@ -27,6 +27,8 @@ #include #include #include +#include +#include #define MOONLIGHT_PATH "/moonlight" #define USER_PATHS "." @@ -76,6 +78,11 @@ char* get_path(char* name, char* extra_data_dirs) { return name; } + if (!home_dir) { + struct passwd *pw = getpwuid(getuid()); + home_dir = pw->pw_dir; + } + if (!extra_data_dirs) extra_data_dirs = "/usr/share:/usr/local/share"; if (!xdg_config_dir) @@ -335,13 +342,14 @@ void config_parse(int argc, char* argv[], PCONFIGURATION config) { config_save(config->config_file, config); if (config->key_dir[0] == 0x0) { - const char *xdg_cache_dir = getenv("XDG_CACHE_DIR"); - if (xdg_cache_dir != NULL) - sprintf(config->key_dir, "%s" MOONLIGHT_PATH, xdg_cache_dir); - else { - const char *home_dir = getenv("HOME"); - sprintf(config->key_dir, "%s" DEFAULT_CACHE_DIR MOONLIGHT_PATH, home_dir); - } + struct passwd *pw = getpwuid(getuid()); + const char *dir; + if ((dir = getenv("XDG_CACHE_DIR")) != NULL) + sprintf(config->key_dir, "%s" MOONLIGHT_PATH, dir); + else if ((dir = getenv("HOME")) != NULL) + sprintf(config->key_dir, "%s" DEFAULT_CACHE_DIR MOONLIGHT_PATH, dir); + else + sprintf(config->key_dir, "%s" DEFAULT_CACHE_DIR MOONLIGHT_PATH, pw->pw_dir); } if (config->stream.fps == -1) diff --git a/src/input/evdev.c b/src/input/evdev.c index e160015..f6f5746 100644 --- a/src/input/evdev.c +++ b/src/input/evdev.c @@ -84,6 +84,8 @@ static int numDevices = 0; static int assignedControllerIds = 0; static short* currentKey; +static short* currentHat; +static short* currentHatDir; static short* currentAbs; static bool* currentReverse; @@ -243,6 +245,7 @@ static bool evdev_handle_event(struct input_event *ev, struct input_device *dev) mouseCode = BUTTON_RIGHT; break; default: + gamepadModified = true; if (dev->map == NULL) break; else if (index == dev->map->btn_a) @@ -279,9 +282,8 @@ static bool evdev_handle_event(struct input_event *ev, struct input_device *dev) if (mouseCode != 0) { LiSendMouseButtonEvent(ev->value?BUTTON_ACTION_PRESS:BUTTON_ACTION_RELEASE, mouseCode); + gamepadModified = false; } else if (gamepadCode != 0) { - gamepadModified = true; - if (ev->value) dev->buttonFlags |= gamepadCode; else @@ -366,28 +368,42 @@ static bool evdev_handle_event(struct input_event *ev, struct input_device *dev) } static bool evdev_handle_mapping_event(struct input_event *ev, struct input_device *dev) { + int index, hat_index; switch (ev->type) { case EV_KEY: + index = ev->code > BTN_MISC && ev->code < (BTN_MISC + KEY_MAX) ? dev->key_map[ev->code - BTN_MISC] : -1; if (currentKey != NULL) { if (ev->value) - *currentKey = ev->code; - else if (ev->code == *currentKey) + *currentKey = index; + else if (*currentKey != -1 && index == *currentKey) return false; } break; case EV_ABS: + hat_index = (ev->code - ABS_HAT0X) / 2; + if (hat_index >= 0 && hat_index < 4) { + int hat_dir_index = (ev->code - ABS_HAT0X) % 2; + dev->hats_state[hat_index][hat_dir_index] = ev->value < 0 ? -1 : (ev->value == 0 ? 0 : 1); + } if (currentAbs != NULL) { struct input_abs_parms parms; evdev_init_parms(dev, &parms, ev->code); + printf("%d: %d >< %d / %d\n", ev->code, ev->value, parms.avg + parms.range/2, parms.avg - parms.range/2); if (ev->value > parms.avg + parms.range/2) { - *currentAbs = ev->code; + *currentAbs = dev->abs_map[ev->code]; *currentReverse = false; } else if (ev->value < parms.avg - parms.range/2) { - *currentAbs = ev->code; + *currentAbs = dev->abs_map[ev->code]; *currentReverse = true; } else if (ev->code == *currentAbs) return false; + } else if (currentHat != NULL) { + if (hat_index >= 0 && hat_index < 4) { + *currentHat = hat_index; + *currentHatDir = hat_constants[dev->hats_state[hat_index][1] + 1][dev->hats_state[hat_index][0] + 1]; + return false; + } } break; } @@ -537,6 +553,117 @@ void evdev_create(const char* device, struct mapping* mappings, bool verbose) { 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; + currentHat = NULL; + 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; + currentHat = NULL; + currentAbs = abs; + currentReverse = reverse; + *abs = -1; + loop_main(); + + usleep(250000); + evdev_drain(); +} + +static void evdev_map_hatkey(char* keyName, short* hat, short* hat_dir, short* key) { + printf("Press %s\n", keyName); + currentKey = key; + currentHat = hat; + currentHatDir = hat_dir; + currentAbs = NULL; + *key = -1; + *hat = -1; + *hat_dir = -1; + *currentReverse = false; + loop_main(); + + usleep(250000); + evdev_drain(); +} + +static void evdev_map_abskey(char* keyName, short* abs, short* key, bool* reverse) { + printf("Press %s\n", keyName); + currentKey = key; + currentHat = NULL; + currentAbs = abs; + currentReverse = reverse; + *key = -1; + *abs = -1; + *currentReverse = false; + loop_main(); + + usleep(250000); + evdev_drain(); +} + +void evdev_map(char* device) { + int fd = open(device, O_RDONLY|O_NONBLOCK); + struct libevdev *evdev = libevdev_new(); + libevdev_set_fd(evdev, fd); + const char* name = libevdev_get_name(evdev); + + int16_t guid[8] = {0}; + guid[0] = int16_to_le(libevdev_get_id_bustype(evdev)); + guid[2] = int16_to_le(libevdev_get_id_vendor(evdev)); + guid[4] = int16_to_le(libevdev_get_id_product(evdev)); + guid[6] = int16_to_le(libevdev_get_id_version(evdev)); + char str_guid[33]; + char* buf = str_guid; + for (int i = 0; i < 16; i++) + buf += sprintf(buf, "%02x", ((unsigned char*) guid)[i]); + + struct mapping map; + strncpy(map.name, libevdev_get_name(evdev), sizeof(map.name)); + strncpy(map.guid, str_guid, sizeof(map.name)); + + libevdev_free(evdev); + close(fd); + + handler = evdev_handle_mapping_event; + + evdev_map_abs("Left Stick Right", &(map.abs_leftx), &(map.reverse_leftx)); + evdev_map_abs("Left Stick Up", &(map.abs_lefty), &(map.reverse_lefty)); + evdev_map_key("Left Stick Button", &(map.btn_leftstick)); + + evdev_map_abs("Right Stick Right", &(map.abs_rightx), &(map.reverse_rightx)); + evdev_map_abs("Right Stick Up", &(map.abs_righty), &(map.reverse_righty)); + evdev_map_key("Right Stick Button", &(map.btn_rightstick)); + + evdev_map_hatkey("D-Pad Right", &(map.hat_dpright), &(map.hat_dir_dpright), &(map.btn_dpright)); + evdev_map_hatkey("D-Pad Left", &(map.hat_dpleft), &(map.hat_dir_dpleft), &(map.btn_dpleft)); + evdev_map_hatkey("D-Pad Up", &(map.hat_dpup), &(map.hat_dir_dpup), &(map.btn_dpup)); + evdev_map_hatkey("D-Pad Down", &(map.hat_dpdown), &(map.hat_dir_dpdown), &(map.btn_dpdown)); + + evdev_map_key("Button X (1)", &(map.btn_x)); + evdev_map_key("Button A (2)", &(map.btn_a)); + evdev_map_key("Button B (3)", &(map.btn_b)); + evdev_map_key("Button Y (4)", &(map.btn_y)); + evdev_map_key("Back Button", &(map.btn_back)); + evdev_map_key("Start Button", &(map.btn_start)); + evdev_map_key("Special Button", &(map.btn_guide)); + + bool ignored; + evdev_map_abskey("Left Trigger", &(map.abs_lefttrigger), &(map.btn_lefttrigger), &ignored); + evdev_map_abskey("Right Trigger", &(map.abs_righttrigger), &(map.btn_righttrigger), &ignored); + + evdev_map_key("Left Bumper", &(map.btn_leftshoulder)); + evdev_map_key("Right Bumper", &(map.btn_rightshoulder)); + mapping_print(&map); +} + void evdev_start() { // After grabbing, the only way to quit via the keyboard // is via the special key combo that the input handling diff --git a/src/input/evdev.h b/src/input/evdev.h index 706c376..430dff8 100644 --- a/src/input/evdev.h +++ b/src/input/evdev.h @@ -25,3 +25,4 @@ void evdev_loop(); void evdev_init(); void evdev_start(); void evdev_stop(); +void evdev_map(char* device); diff --git a/src/input/mapping.c b/src/input/mapping.c index 800327b..5371002 100644 --- a/src/input/mapping.c +++ b/src/input/mapping.c @@ -155,3 +155,39 @@ struct mapping* mapping_load(char* fileName, bool verbose) { return mappings; } + +#define print_btn(btn, code) if (code > -1) printf("%s:b%d,", btn, code) +#define print_abs(abs, code) if (code > -1) printf("%s:a%d,", abs, code) +#define print_hat(hat, code, dir) if (code > -1) printf("%s:h%d.%d,", hat, code, dir) + +void mapping_print(struct mapping* map) { + printf("%s,%s,", map->guid, map->name); + print_btn("a", map->btn_a); + print_btn("b", map->btn_b); + print_btn("x", map->btn_x); + print_btn("y", map->btn_y); + print_btn("start", map->btn_start); + print_btn("guide", map->btn_guide); + print_btn("back", map->btn_back); + print_btn("leftstick", map->btn_leftstick); + print_btn("rightstick", map->btn_rightstick); + print_btn("leftshoulder", map->btn_leftshoulder); + print_btn("rightshoulder", map->btn_rightshoulder); + print_btn("dpup", map->btn_dpup); + print_btn("dpleft", map->btn_dpleft); + print_btn("dpdown", map->btn_dpdown); + print_btn("dpright", map->btn_dpright); + print_hat("dpup", map->hat_dpup, map->hat_dir_dpup); + print_hat("dpleft", map->hat_dpleft, map->hat_dir_dpleft); + print_hat("dpdown", map->hat_dpdown, map->hat_dir_dpdown); + print_hat("dpright", map->hat_dpright, map->hat_dir_dpright); + print_abs("leftx", map->abs_leftx); + print_abs("lefty", map->abs_lefty); + print_abs("rightx", map->abs_rightx); + print_abs("righty", map->abs_righty); + print_abs("lefttrigger", map->abs_lefttrigger); + print_abs("righttrigger", map->abs_righttrigger); + print_btn("lefttrigger", map->btn_lefttrigger); + print_btn("righttrigger", map->btn_righttrigger); + printf("platform:Linux\n"); +} diff --git a/src/input/mapping.h b/src/input/mapping.h index a82b6c9..b4c7bcb 100644 --- a/src/input/mapping.h +++ b/src/input/mapping.h @@ -49,3 +49,4 @@ struct mapping { struct mapping* mapping_parse(char* mapping); struct mapping* mapping_load(char* fileName, bool verbose); +void mapping_print(struct mapping*); diff --git a/src/main.c b/src/main.c index e111e88..c353f61 100644 --- a/src/main.c +++ b/src/main.c @@ -139,6 +139,7 @@ static void help() { printf("\tstream\t\t\tStream computer to device\n"); printf("\tlist\t\t\tList available games and applications\n"); printf("\tquit\t\t\tQuit the application or game being streamed\n"); + printf("\tmap\t\t\tCreate mapping file for gamepad\n"); printf("\thelp\t\t\tShow this help\n"); printf("\n Global Options\n\n"); printf("\t-config \tLoad configuration file\n"); @@ -194,6 +195,17 @@ int main(int argc, char* argv[]) { if (config.debug_level > 0) printf("Moonlight Embedded %d.%d.%d (%s)\n", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, COMPILE_OPTIONS); + if (strcmp("map", config.action) == 0) { + if (config.inputsCount != 1) { + printf("You need to specify one input device using -input.\n"); + exit(-1); + } + + evdev_create(config.inputs[0], NULL, config.debug_level > 0); + evdev_map(config.inputs[0]); + exit(0); + } + if (config.address == NULL) { config.address = malloc(MAX_ADDRESS_SIZE); if (config.address == NULL) { diff --git a/src/video/ffmpeg.c b/src/video/ffmpeg.c index ad8311c..40a4956 100644 --- a/src/video/ffmpeg.c +++ b/src/video/ffmpeg.c @@ -27,6 +27,7 @@ #endif #include +#include #include #include diff --git a/src/video/ffmpeg_vaapi.h b/src/video/ffmpeg_vaapi.h index bb6de04..f87fcd7 100644 --- a/src/video/ffmpeg_vaapi.h +++ b/src/video/ffmpeg_vaapi.h @@ -18,6 +18,7 @@ */ #include +#include int vaapi_init_lib(); int vaapi_init(AVCodecContext* decoder_ctx); diff --git a/src/video/imx.c b/src/video/imx.c index b50ae67..2958832 100644 --- a/src/video/imx.c +++ b/src/video/imx.c @@ -34,6 +34,7 @@ #include +#include #include #include #include diff --git a/src/video/x11.c b/src/video/x11.c index 5309b3d..8b60cd7 100644 --- a/src/video/x11.c +++ b/src/video/x11.c @@ -34,6 +34,8 @@ #include #include +#include +#include #include #include #include