diff --git a/Makefile b/Makefile index 0808796..a31f978 100755 --- a/Makefile +++ b/Makefile @@ -114,7 +114,7 @@ MOONLIGHT_LIBRETRO_CXX_SOURCES = \ src/ui/LoadingOverlay.cpp \ src/GameStreamClient.cpp \ src/Settings.cpp \ - src/moonlight_libretro_wrapper.cpp + src/InputController.cpp MOONLIGHT_COMMON_C_SOURCES = \ third_party/moonlight-common-c/enet/callbacks.c \ diff --git a/libgamestream/client.c b/libgamestream/client.c index 90e4142..f5ca366 100644 --- a/libgamestream/client.c +++ b/libgamestream/client.c @@ -58,7 +58,7 @@ static EVP_PKEY *privateKey; const char* gs_error; -static int mkdirtree(const char* directory) { +int mkdirtree(const char* directory) { char buffer[PATH_MAX]; char* p = buffer; diff --git a/moonlight.xcodeproj/project.pbxproj b/moonlight.xcodeproj/project.pbxproj index 8a22d85..3065a95 100644 --- a/moonlight.xcodeproj/project.pbxproj +++ b/moonlight.xcodeproj/project.pbxproj @@ -10,7 +10,7 @@ 3602C3B7245D903000368900 /* HostButton.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3602C3B5245D903000368900 /* HostButton.cpp */; }; 3602C3BA245DB3C800368900 /* AppListWindow.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3602C3B8245DB3C800368900 /* AppListWindow.cpp */; }; 3602C3BD245DBA9100368900 /* AppButton.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3602C3BB245DBA9100368900 /* AppButton.cpp */; }; - 361F8A3A245CB44E00A8D9C0 /* moonlight_libretro_wrapper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 361F8A38245CB44E00A8D9C0 /* moonlight_libretro_wrapper.cpp */; }; + 3603E93C246316400051287D /* InputController.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3603E93A246316400051287D /* InputController.cpp */; }; 3652EFCD245B3B00001FABF3 /* widget.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3652EF0F245B3B00001FABF3 /* widget.cpp */; }; 3652EFCE245B3B00001FABF3 /* common.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3652EF10245B3B00001FABF3 /* common.cpp */; }; 3652EFCF245B3B00001FABF3 /* checkbox.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3652EF11245B3B00001FABF3 /* checkbox.cpp */; }; @@ -81,7 +81,7 @@ 3652F07F245C292B001FABF3 /* LinkedBlockingQueue.c in Sources */ = {isa = PBXBuildFile; fileRef = 3652F062245C292B001FABF3 /* LinkedBlockingQueue.c */; }; 3652F080245C292B001FABF3 /* ByteBuffer.c in Sources */ = {isa = PBXBuildFile; fileRef = 3652F064245C292B001FABF3 /* ByteBuffer.c */; }; 3652F083245C60D1001FABF3 /* LoadingOverlay.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3652F081245C60D1001FABF3 /* LoadingOverlay.cpp */; }; - 3652F086245C6CFC001FABF3 /* moonlight_libretro.c in Sources */ = {isa = PBXBuildFile; fileRef = 3652F085245C6CFC001FABF3 /* moonlight_libretro.c */; }; + 3652F086245C6CFC001FABF3 /* moonlight_libretro.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3652F085245C6CFC001FABF3 /* moonlight_libretro.cpp */; }; 3652F08A245C8569001FABF3 /* ContentWindow.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3652F089245C8569001FABF3 /* ContentWindow.cpp */; }; 367CD95A245DE25F00A95738 /* StreamWindow.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 367CD958245DE25F00A95738 /* StreamWindow.cpp */; }; 36A0C0372461DBA30083289C /* AddHostButton.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 36A0C0352461DBA30083289C /* AddHostButton.cpp */; }; @@ -122,8 +122,8 @@ 3602C3BB245DBA9100368900 /* AppButton.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = AppButton.cpp; sourceTree = ""; }; 3602C3BC245DBA9100368900 /* AppButton.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = AppButton.hpp; sourceTree = ""; }; 3602C3C0245DC7E300368900 /* Makefile */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = ""; }; - 361F8A38245CB44E00A8D9C0 /* moonlight_libretro_wrapper.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = moonlight_libretro_wrapper.cpp; sourceTree = ""; }; - 361F8A39245CB44E00A8D9C0 /* moonlight_libretro_wrapper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = moonlight_libretro_wrapper.h; sourceTree = ""; }; + 3603E93A246316400051287D /* InputController.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = InputController.cpp; sourceTree = ""; }; + 3603E93B246316400051287D /* InputController.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = InputController.hpp; sourceTree = ""; }; 3652ECE8245B3AFF001FABF3 /* colorpicker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = colorpicker.h; sourceTree = ""; }; 3652ECE9245B3AFF001FABF3 /* renderpass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = renderpass.h; sourceTree = ""; }; 3652ECEA245B3AFF001FABF3 /* theme.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = theme.h; sourceTree = ""; }; @@ -272,7 +272,7 @@ 3652F081245C60D1001FABF3 /* LoadingOverlay.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = LoadingOverlay.cpp; sourceTree = ""; }; 3652F082245C60D1001FABF3 /* LoadingOverlay.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = LoadingOverlay.hpp; sourceTree = ""; }; 3652F084245C6CFC001FABF3 /* libretro.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = libretro.h; sourceTree = ""; }; - 3652F085245C6CFC001FABF3 /* moonlight_libretro.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = moonlight_libretro.c; sourceTree = ""; }; + 3652F085245C6CFC001FABF3 /* moonlight_libretro.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = moonlight_libretro.cpp; sourceTree = ""; }; 3652F089245C8569001FABF3 /* ContentWindow.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ContentWindow.cpp; sourceTree = ""; }; 367CD958245DE25F00A95738 /* StreamWindow.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = StreamWindow.cpp; sourceTree = ""; }; 367CD959245DE25F00A95738 /* StreamWindow.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = StreamWindow.hpp; sourceTree = ""; }; @@ -634,10 +634,10 @@ 3652F004245C28C6001FABF3 /* GameStreamClient.hpp */, 36A0C03B2461F03C0083289C /* Settings.cpp */, 36A0C03C2461F03C0083289C /* Settings.hpp */, + 3603E93A246316400051287D /* InputController.cpp */, + 3603E93B246316400051287D /* InputController.hpp */, 3652F084245C6CFC001FABF3 /* libretro.h */, - 361F8A39245CB44E00A8D9C0 /* moonlight_libretro_wrapper.h */, - 361F8A38245CB44E00A8D9C0 /* moonlight_libretro_wrapper.cpp */, - 3652F085245C6CFC001FABF3 /* moonlight_libretro.c */, + 3652F085245C6CFC001FABF3 /* moonlight_libretro.cpp */, 36B406962459F460005BD903 /* moonlight_glfw.cpp */, ); path = src; @@ -806,7 +806,6 @@ 3652F075245C292B001FABF3 /* VideoStream.c in Sources */, 3652EFE0245B3B00001FABF3 /* imageview.cpp in Sources */, 3652EFDB245B3B00001FABF3 /* texture.cpp in Sources */, - 361F8A3A245CB44E00A8D9C0 /* moonlight_libretro_wrapper.cpp in Sources */, 36A0C03D2461F03C0083289C /* Settings.cpp in Sources */, 3652F079245C292B001FABF3 /* RtpReorderQueue.c in Sources */, 3652F065245C292B001FABF3 /* list.c in Sources */, @@ -814,7 +813,7 @@ 36DFE217245A278700FC51CE /* glsym_gl.c in Sources */, 3652F06A245C292B001FABF3 /* protocol.c in Sources */, 3652EFFC245B6434001FABF3 /* MainWindow.cpp in Sources */, - 3652F086245C6CFC001FABF3 /* moonlight_libretro.c in Sources */, + 3652F086245C6CFC001FABF3 /* moonlight_libretro.cpp in Sources */, 3652EFD3245B3B00001FABF3 /* button.cpp in Sources */, 3652EFE6245B3B00001FABF3 /* traits.cpp in Sources */, 3652EFDE245B3B00001FABF3 /* tabwidget.cpp in Sources */, @@ -876,6 +875,7 @@ 3652F011245C2919001FABF3 /* client.c in Sources */, 3652EFE4245B3B00001FABF3 /* combobox.cpp in Sources */, 36A56313245F194000901354 /* gl_render.c in Sources */, + 3603E93C246316400051287D /* InputController.cpp in Sources */, 3652EFF2245B3B00001FABF3 /* textbox.cpp in Sources */, 3652F074245C292B001FABF3 /* Platform.c in Sources */, 3652EFCD245B3B00001FABF3 /* widget.cpp in Sources */, diff --git a/src/InputController.cpp b/src/InputController.cpp new file mode 100644 index 0000000..b53f6ba --- /dev/null +++ b/src/InputController.cpp @@ -0,0 +1,162 @@ +#include "InputController.hpp" +#include "Settings.hpp" +#include "Limelight.h" +#include "libretro.h" +#include "Limelight.h" +#include +#include + +extern retro_input_state_t input_state_cb; + +int16_t keyboard_state[RETROK_LAST]; +struct MouseState mouse_state; +struct GamePadState game_pad_state; + +static int m_width = 1, m_height = 1; + +void InputController::handle_mouse(int width, int height) { + m_width = width; + m_height = height; + + int mouse_l_press = input_state_cb(0, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_LEFT); + int mouse_r_press = input_state_cb(0, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_RIGHT); + + int mouse_x = input_state_cb(0, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_X); + int mouse_y = input_state_cb(0, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_Y); + int pointer_x = 0, pointer_y = 0; + + // TODO: Pointer on macOS currently broken + // https://github.com/libretro/RetroArch/issues/10168 + if (input_state_cb(0, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_PRESSED)) { + pointer_x = (input_state_cb(0, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_X) + 0x7fff) * width / 0xffff; + pointer_y = (input_state_cb(0, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_Y) + 0x7fff) * height / 0xffff; + } + + #ifndef __LAKKA_SWITCH__ + if (mouse_x != 0 && mouse_y != 0) { + mouse_state.x = mouse_x; + mouse_state.y = mouse_y; + nanogui::cursor_pos_callback_event(mouse_x, mouse_y); + } else + #endif + if (mouse_l_press && pointer_x != 0 && pointer_y != 0) { + mouse_state.x = pointer_x; + mouse_state.y = pointer_y; + nanogui::cursor_pos_callback_event(pointer_x, pointer_y); + } + + if (!mouse_state.l_press && mouse_l_press) { + mouse_state.l_press = true; + nanogui::mouse_button_callback_event(NANOGUI_MOUSE_BUTTON_1, NANOGUI_PRESS, 0); + } else if (mouse_state.l_press && !mouse_l_press) { + mouse_state.l_press = false; + nanogui::mouse_button_callback_event(NANOGUI_MOUSE_BUTTON_1, NANOGUI_RELEASE, 0); + } + + if (!mouse_state.r_press && mouse_r_press) { + mouse_state.r_press = true; + nanogui::mouse_button_callback_event(NANOGUI_MOUSE_BUTTON_2, NANOGUI_PRESS, 0); + } else if (mouse_state.r_press && !mouse_r_press) { + mouse_state.r_press = false; + nanogui::mouse_button_callback_event(NANOGUI_MOUSE_BUTTON_2, NANOGUI_RELEASE, 0); + } +} + +void InputController::handle_keyboard() { + // +} + +void InputController::handle_game_pad() { + game_pad_state.leftTrigger = 0xFFFF * input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L2); + game_pad_state.rightTrigger = 0xFFFF * input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R2); + + game_pad_state.leftStickX = input_state_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X); + game_pad_state.leftStickY = 0xFFFF - input_state_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y); + game_pad_state.rightStickX = input_state_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X); + game_pad_state.rightStickY = 0xFFFF - input_state_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y); + + #define SET_GAME_PAD_STATE(LIMELIGHT_KEY, RETRO_KEY) \ + input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_KEY) ? (game_pad_state.buttonFlags |= LIMELIGHT_KEY) : (game_pad_state.buttonFlags &= ~LIMELIGHT_KEY); + + SET_GAME_PAD_STATE(UP_FLAG, RETRO_DEVICE_ID_JOYPAD_UP); + SET_GAME_PAD_STATE(DOWN_FLAG, RETRO_DEVICE_ID_JOYPAD_DOWN); + SET_GAME_PAD_STATE(LEFT_FLAG, RETRO_DEVICE_ID_JOYPAD_LEFT); + SET_GAME_PAD_STATE(RIGHT_FLAG, RETRO_DEVICE_ID_JOYPAD_RIGHT); + + SET_GAME_PAD_STATE(BACK_FLAG, RETRO_DEVICE_ID_JOYPAD_SELECT); + SET_GAME_PAD_STATE(PLAY_FLAG, RETRO_DEVICE_ID_JOYPAD_START); + + SET_GAME_PAD_STATE(LB_FLAG, RETRO_DEVICE_ID_JOYPAD_L); + SET_GAME_PAD_STATE(RB_FLAG, RETRO_DEVICE_ID_JOYPAD_R); + + SET_GAME_PAD_STATE(LS_CLK_FLAG, RETRO_DEVICE_ID_JOYPAD_L3); + SET_GAME_PAD_STATE(RS_CLK_FLAG, RETRO_DEVICE_ID_JOYPAD_R3); + + if (Settings::settings()->swap_ab_xy()) { + SET_GAME_PAD_STATE(A_FLAG, RETRO_DEVICE_ID_JOYPAD_B); + SET_GAME_PAD_STATE(B_FLAG, RETRO_DEVICE_ID_JOYPAD_A); + SET_GAME_PAD_STATE(X_FLAG, RETRO_DEVICE_ID_JOYPAD_Y); + SET_GAME_PAD_STATE(Y_FLAG, RETRO_DEVICE_ID_JOYPAD_X); + } else { + SET_GAME_PAD_STATE(A_FLAG, RETRO_DEVICE_ID_JOYPAD_A); + SET_GAME_PAD_STATE(B_FLAG, RETRO_DEVICE_ID_JOYPAD_B); + SET_GAME_PAD_STATE(X_FLAG, RETRO_DEVICE_ID_JOYPAD_X); + SET_GAME_PAD_STATE(Y_FLAG, RETRO_DEVICE_ID_JOYPAD_Y); + } +} + +void InputController::send_to_stream() { +#if defined(__LAKKA_SWITCH__) + static int mouse_x = mouse_state.x, mouse_y = mouse_state.y; + static int last_mouse_x = mouse_state.x, last_mouse_y = mouse_state.y; + + bool move_mouse = (game_pad_state.leftTrigger == 0) && (game_pad_state.rightTrigger == 0); + + if (move_mouse) { + mouse_x = std::min(std::max(mouse_x + mouse_state.x - last_mouse_x, 0), m_width); + mouse_y = std::min(std::max(mouse_y + mouse_state.y - last_mouse_y, 0), m_height); + + LiSendMousePositionEvent(mouse_x, mouse_y, m_width, m_height); + } + + last_mouse_x = mouse_state.x; + last_mouse_y = mouse_state.y; + + if (mouse_state.l_press && ((game_pad_state.buttonFlags & LB_FLAG) || game_pad_state.leftTrigger)) { + LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_LEFT); + } else { + LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_LEFT); + } + + if (mouse_state.l_press && ((game_pad_state.buttonFlags & RB_FLAG) || game_pad_state.rightTrigger)) { + LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_RIGHT); + } else { + LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_RIGHT); + } + +#else + LiSendMousePositionEvent(mouse_state.x, mouse_state.y, m_width, m_height); + LiSendMouseButtonEvent(mouse_state.l_press ? BUTTON_ACTION_PRESS : BUTTON_ACTION_RELEASE, BUTTON_LEFT); + LiSendMouseButtonEvent(mouse_state.r_press ? BUTTON_ACTION_PRESS : BUTTON_ACTION_RELEASE, BUTTON_RIGHT); +#endif + + static bool send_alt_enter = false; + + if (!send_alt_enter && GAME_PAD_COMBO(LEFT_FLAG)) { + send_alt_enter = true; + LiSendKeyboardEvent(0x0D, KEY_ACTION_DOWN, MODIFIER_ALT); + } else if (send_alt_enter && !GAME_PAD_COMBO(LEFT_FLAG)) { + send_alt_enter = false; + LiSendKeyboardEvent(0x0D, KEY_ACTION_UP, MODIFIER_ALT); + } + + LiSendControllerEvent( + game_pad_state.buttonFlags, + game_pad_state.leftTrigger, + game_pad_state.rightTrigger, + game_pad_state.leftStickX, + game_pad_state.leftStickY, + game_pad_state.rightStickX, + game_pad_state.rightStickY + ); +} diff --git a/src/InputController.hpp b/src/InputController.hpp new file mode 100644 index 0000000..8f49141 --- /dev/null +++ b/src/InputController.hpp @@ -0,0 +1,52 @@ +#include +#include +#pragma once + +extern int16_t keyboard_state[]; + +struct MouseState { + int x; + int y; + bool l_press; + bool r_press; +}; + +extern struct MouseState mouse_state; + +struct GamePadState { + short buttonFlags; + unsigned char leftTrigger; + unsigned char rightTrigger; + short leftStickX; + short leftStickY; + short rightStickX; + short rightStickY; +}; + +extern struct GamePadState game_pad_state; + +#define GAME_PAD_COMBO(KEY) \ + ((game_pad_state.buttonFlags & LB_FLAG) && (game_pad_state.buttonFlags & RB_FLAG) && (game_pad_state.buttonFlags & KEY)) + +class InputController { +public: + static InputController* controller() { + static InputController controller; + return &controller; + } + + void handle_input(int width, int height) { + handle_mouse(width, height); + handle_keyboard(); + handle_game_pad(); + }; + + void send_to_stream(); + +private: + InputController() {}; + + void handle_mouse(int width, int height); + void handle_keyboard(); + void handle_game_pad(); +}; diff --git a/src/Settings.cpp b/src/Settings.cpp index 89b5f5a..dce48ad 100644 --- a/src/Settings.cpp +++ b/src/Settings.cpp @@ -4,8 +4,14 @@ #include #include -#define TRY_JSON(x) try { \ - x; } catch (const std::exception &e) {} +extern "C" { + int mkdirtree(const char* directory); +} + +#define JSON_GET_VALUE(to, json, check, type) \ + if (json.check()) { \ + to = json.get(); \ + } void Settings::add_host(const std::string address) { if (std::find(m_hosts.begin(), m_hosts.end(), address) == m_hosts.end()) { @@ -24,24 +30,30 @@ void Settings::load() { nlohmann::json json; stream >> json; - TRY_JSON(m_hosts = json["hosts"].get>()); - TRY_JSON(m_resolution = json["settings"]["resolution"].get()); - TRY_JSON(m_fps = json["settings"]["fps"].get()); - TRY_JSON(m_bitrate = json["settings"]["bitrate"].get()); - TRY_JSON(m_swap_ab_xy = json["settings"]["swap_ab_xy"].get()); + JSON_GET_VALUE(m_hosts, json["hosts"], is_array, std::vector); + JSON_GET_VALUE(m_resolution, json["settings"]["resolution"], is_number_integer, int); + JSON_GET_VALUE(m_fps, json["settings"]["fps"], is_number_integer, int); + JSON_GET_VALUE(m_bitrate, json["settings"]["bitrate"], is_number_integer, int); + JSON_GET_VALUE(m_swap_ab_xy, json["settings"]["swap_ab_xy"], is_number_integer, bool); } void Settings::save() { - nlohmann::json json; - - json["hosts"] = m_hosts; - json["settings"] = { - {"resolution", m_resolution}, - {"fps", m_fps}, - {"bitrate", m_bitrate}, - {"swap_ab_xy", m_swap_ab_xy} - }; - - std::ofstream stream(m_working_dir + "/settings.json"); - stream << std::setw(4) << json << std::endl; + try { + mkdirtree(m_working_dir.c_str()); + + nlohmann::json json; + + json["hosts"] = m_hosts; + json["settings"] = { + {"resolution", m_resolution}, + {"fps", m_fps}, + {"bitrate", m_bitrate}, + {"swap_ab_xy", m_swap_ab_xy} + }; + + std::ofstream stream(m_working_dir + "/settings.json"); + stream << std::setw(4) << json << std::endl; + } catch (const std::exception &e) { + printf("Save settings error: %s\n", e.what()); + } } diff --git a/src/Settings.hpp b/src/Settings.hpp index ae75ad1..e94c10d 100644 --- a/src/Settings.hpp +++ b/src/Settings.hpp @@ -15,7 +15,7 @@ public: } void set_working_dir(std::string working_dir) { - m_working_dir = working_dir + "/moonlight"; + m_working_dir = std::string(working_dir + "/moonlight"); load(); } diff --git a/src/moonlight_glfw.cpp b/src/moonlight_glfw.cpp index bcbfaa0..8c3a5b0 100644 --- a/src/moonlight_glfw.cpp +++ b/src/moonlight_glfw.cpp @@ -5,11 +5,51 @@ #include "Application.hpp" #include "Settings.hpp" #include "Limelight.h" -#include "moonlight_libretro_wrapper.h" #include "gl_render.h" #include "libretro.h" +#include "InputController.hpp" + +extern retro_input_state_t input_state_cb; + +static int mouse_x = 0, mouse_y = 0; +static int mouse_l = 0, mouse_r = 0; + +static int glfw_keyboard_state[GLFW_KEY_LAST]; + +#define GLFW_KEY_TO_RETRO(RETRO, KEY) \ + if (id == RETRO) return glfw_keyboard_state[KEY]; + +static int16_t glfw_input_state_cb(unsigned port, unsigned device, unsigned index, unsigned id) { + if (device == RETRO_DEVICE_MOUSE) { + if (id == RETRO_DEVICE_ID_MOUSE_X) { + return mouse_x; + } else if (id == RETRO_DEVICE_ID_MOUSE_Y) { + return mouse_y; + } else if (id == RETRO_DEVICE_ID_MOUSE_LEFT) { + return mouse_l; + } else if (id == RETRO_DEVICE_ID_MOUSE_RIGHT) { + return mouse_r; + } + } else if (device == RETRO_DEVICE_JOYPAD) { + GLFW_KEY_TO_RETRO(RETRO_DEVICE_ID_JOYPAD_UP, GLFW_KEY_UP); + GLFW_KEY_TO_RETRO(RETRO_DEVICE_ID_JOYPAD_DOWN, GLFW_KEY_DOWN); + GLFW_KEY_TO_RETRO(RETRO_DEVICE_ID_JOYPAD_LEFT, GLFW_KEY_LEFT); + GLFW_KEY_TO_RETRO(RETRO_DEVICE_ID_JOYPAD_RIGHT, GLFW_KEY_RIGHT); + GLFW_KEY_TO_RETRO(RETRO_DEVICE_ID_JOYPAD_L, GLFW_KEY_Q); + GLFW_KEY_TO_RETRO(RETRO_DEVICE_ID_JOYPAD_R, GLFW_KEY_E); + GLFW_KEY_TO_RETRO(RETRO_DEVICE_ID_JOYPAD_L2, GLFW_KEY_Z); + GLFW_KEY_TO_RETRO(RETRO_DEVICE_ID_JOYPAD_R2, GLFW_KEY_C); + GLFW_KEY_TO_RETRO(RETRO_DEVICE_ID_JOYPAD_A, GLFW_KEY_A); + GLFW_KEY_TO_RETRO(RETRO_DEVICE_ID_JOYPAD_B, GLFW_KEY_B); + GLFW_KEY_TO_RETRO(RETRO_DEVICE_ID_JOYPAD_X, GLFW_KEY_X); + GLFW_KEY_TO_RETRO(RETRO_DEVICE_ID_JOYPAD_Y, GLFW_KEY_Y); + } + return 0; +} int main(int argc, const char * argv[]) { + input_state_cb = glfw_input_state_cb; + glfwInit(); glfwSetErrorCallback([](int i, const char *error) { @@ -29,11 +69,16 @@ int main(int argc, const char * argv[]) { gl_render_init(); glfwSetCursorPosCallback(window, [](GLFWwindow *w, double x, double y) { - nanogui::cursor_pos_callback_event(x, y); + mouse_x = x; + mouse_y = y; }); glfwSetMouseButtonCallback(window, [](GLFWwindow *w, int button, int action, int modifiers) { - nanogui::mouse_button_callback_event(button, action, modifiers); + if (button == 0) { + mouse_l = action; + } else if (button == 1) { + mouse_r = action; + } }); glfwSetScrollCallback(window, [](GLFWwindow *w, double x, double y) { @@ -41,12 +86,7 @@ int main(int argc, const char * argv[]) { }); glfwSetKeyCallback(window, [](GLFWwindow *w, int key, int scancode, int action, int mods) { - if (GLFW_KEY_A <= key && key <= GLFW_KEY_Z) { - keyboard_state[RETROK_a + key - GLFW_KEY_A] = action == GLFW_PRESS; - } - - keyboard_state[RETROK_w] ? game_pad_state.buttonFlags |= UP_FLAG : game_pad_state.buttonFlags &= ~UP_FLAG; - keyboard_state[RETROK_s] ? game_pad_state.buttonFlags |= DOWN_FLAG : game_pad_state.buttonFlags &= ~DOWN_FLAG; + glfw_keyboard_state[key] = action != GLFW_RELEASE; }); int width, height, fb_width, fb_height; @@ -58,11 +98,13 @@ int main(int argc, const char * argv[]) { nanogui::init(); nanogui::ref app = new Application(Size(width, height), Size(fb_width, fb_height)); - nanogui::setup(1.0 / 60.0 * 1000); + nanogui::setup(1.0 / 15.0); while (!glfwWindowShouldClose(window)) { glfwPollEvents(); + InputController::controller()->handle_input(width, height); + int width, height; glfwGetFramebufferSize(window, &width, &height); glViewport(0, 0, width, height); diff --git a/src/moonlight_libretro.c b/src/moonlight_libretro.cpp similarity index 73% rename from src/moonlight_libretro.c rename to src/moonlight_libretro.cpp index 4ea6acb..fdbfc10 100644 --- a/src/moonlight_libretro.c +++ b/src/moonlight_libretro.cpp @@ -3,12 +3,16 @@ #include #include #include +#include +#include #include "glsym/glsym.h" #include "libretro.h" -#include "moonlight_libretro_wrapper.h" +#include "gl_render.h" +#include "Application.hpp" +#include "InputController.hpp" +#include "Settings.hpp" -#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) static struct retro_hw_render_callback hw_render; #if defined(HAVE_PSGL) @@ -39,10 +43,32 @@ retro_audio_sample_batch_t audio_batch_cb; static retro_environment_t environ_cb; static retro_input_poll_t input_poll_cb; retro_input_state_t input_state_cb; -static retro_log_printf_t log_cb; + +static Application* app; +static bool moonlight_is_initialized = false; + +void moonlight_init(int width, int height) { + if (moonlight_is_initialized) { + return; + } + + moonlight_is_initialized = true; + + gl_render_init(); + + nanogui::init(); + app = new Application(Size(width, height), Size(width, height)); + + nanogui::setup(1.0 / 15.0); +} void retro_init(void) { - moonlight_libretro_wrapper_preinit(); + #ifdef __LAKKA_SWITCH__ + Settings::settings()->set_working_dir("/storage/system"); + #endif + + OpenSSL_add_all_algorithms(); + curl_global_init(CURL_GLOBAL_ALL); } void retro_deinit(void) { @@ -87,13 +113,11 @@ void retro_set_environment(retro_environment_t cb) { bool no_game = true; cb(RETRO_ENVIRONMENT_SET_SUPPORT_NO_GAME, &no_game); -#ifdef __LAKKA_SWITCH__ - moonlight_libretro_wrapper_set_working_dir("/storage/system"); -#else +#ifndef __LAKKA_SWITCH__ const char *dir = NULL; cb(RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY, &dir); if (dir != NULL) { - moonlight_libretro_wrapper_set_working_dir(dir); + Settings::settings()->set_working_dir(dir); } #endif } @@ -123,51 +147,15 @@ static void update_variables(void) { } void retro_run(void) { - moonlight_libretro_wrapper_init(width, height); + moonlight_init(width, height); - // Handle inputs input_poll_cb(); + InputController::controller()->handle_input(width, height); - double mouse_x = input_state_cb(0, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_X); - double mouse_y = input_state_cb(0, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_Y); - double pointer_x = 0; - double pointer_y = 0; - - // TODO: Pointers in MacBook currently work incorrectly... - if (input_state_cb(0, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_PRESSED)) { - int p_x = input_state_cb(0, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_X); - int p_y = input_state_cb(0, RETRO_DEVICE_POINTER, 0, RETRO_DEVICE_ID_POINTER_Y); - pointer_x = (p_x + 0x7fff) * width / 0xffff; - pointer_y = (p_y + 0x7fff) * height / 0xffff; - } - - #ifndef __LAKKA_SWITCH__ - if (mouse_x != 0 && mouse_y != 0) { - moonlight_libretro_wrapper_handle_mouse_move(mouse_x, mouse_y); - } - #endif - - if (input_state_cb(0, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_LEFT)) { - if (pointer_x != 0 && pointer_y != 0) { - moonlight_libretro_wrapper_handle_mouse_move(pointer_x, pointer_y); - } - - moonlight_libretro_wrapper_handle_mouse_button(0, 1, 0); - } else if (!input_state_cb(0, RETRO_DEVICE_MOUSE, 0, RETRO_DEVICE_ID_MOUSE_LEFT)) { - moonlight_libretro_wrapper_handle_mouse_button(0, 0, 0); - } - - for (int i = 0; i < RETROK_LAST; i++) { - keyboard_state[i] = input_state_cb(0, RETRO_DEVICE_KEYBOARD, 0, i); - } - - moonlight_libretro_wrapper_handle_game_pad(); - - // Draw glBindFramebuffer(RARCH_GL_FRAMEBUFFER, hw_render.get_current_framebuffer()); glViewport(0, 0, width, height); - moonlight_libretro_wrapper_draw(); + nanogui::draw(); video_cb(RETRO_HW_FRAME_BUFFER_VALID, width, height, 0); } diff --git a/src/moonlight_libretro_wrapper.cpp b/src/moonlight_libretro_wrapper.cpp deleted file mode 100644 index 0d2d9b4..0000000 --- a/src/moonlight_libretro_wrapper.cpp +++ /dev/null @@ -1,105 +0,0 @@ -#include "moonlight_libretro_wrapper.h" -#include "libretro.h" -#include "gl_render.h" -#include "Application.hpp" -#include "Settings.hpp" -#include "Limelight.h" -#include "Settings.hpp" -#include -#include - -static bool moonlight_is_initialized = false; - -static Application* app; -static std::string working_dir; - -int16_t keyboard_state[RETROK_LAST]; -struct GamePadState game_pad_state; - -extern retro_input_state_t input_state_cb; - -void moonlight_libretro_wrapper_preinit() { - OpenSSL_add_all_algorithms(); - curl_global_init(CURL_GLOBAL_ALL); -} - -void moonlight_libretro_wrapper_init(int width, int height) { - if (moonlight_is_initialized) { - return; - } - - moonlight_is_initialized = true; - - Settings::settings()->set_working_dir(working_dir); - - gl_render_init(); - - nanogui::init(); - app = new Application(Size(width, height), Size(width, height)); - - //nanogui::setup(1.0 / 60.0 * 1000); no needs anymore? -} - -void moonlight_libretro_wrapper_set_working_dir(const char* dir) { - std::string str(dir, strlen(dir)); - working_dir = str; -} - -void moonlight_libretro_wrapper_handle_mouse_move(double x, double y) { - nanogui::cursor_pos_callback_event(x, y); -} - -void moonlight_libretro_wrapper_handle_mouse_button(int button, int action, int modifiers) { - nanogui::mouse_button_callback_event(button, action, modifiers); -} - -static void set_game_pad_state(short flag, int16_t state) { - if (state) { - game_pad_state.buttonFlags |= flag; - } else { - game_pad_state.buttonFlags &= ~flag; - } -} - -void moonlight_libretro_wrapper_handle_game_pad() { - game_pad_state.leftTrigger = 0xFFFF * input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_L2); - game_pad_state.rightTrigger = 0xFFFF * input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_R2); - - game_pad_state.leftStickX = input_state_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_X); - game_pad_state.leftStickY = 0xFFFF - input_state_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_LEFT, RETRO_DEVICE_ID_ANALOG_Y); - game_pad_state.rightStickX = input_state_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_X); - game_pad_state.rightStickY = 0xFFFF - input_state_cb(0, RETRO_DEVICE_ANALOG, RETRO_DEVICE_INDEX_ANALOG_RIGHT, RETRO_DEVICE_ID_ANALOG_Y); - - #define GAME_PAD_STATE(KEY) \ - input_state_cb(0, RETRO_DEVICE_JOYPAD, 0, KEY) - - set_game_pad_state(UP_FLAG, GAME_PAD_STATE(RETRO_DEVICE_ID_JOYPAD_UP)); - set_game_pad_state(DOWN_FLAG, GAME_PAD_STATE(RETRO_DEVICE_ID_JOYPAD_DOWN)); - set_game_pad_state(LEFT_FLAG, GAME_PAD_STATE(RETRO_DEVICE_ID_JOYPAD_LEFT)); - set_game_pad_state(RIGHT_FLAG, GAME_PAD_STATE(RETRO_DEVICE_ID_JOYPAD_RIGHT)); - - set_game_pad_state(BACK_FLAG, GAME_PAD_STATE(RETRO_DEVICE_ID_JOYPAD_SELECT)); - set_game_pad_state(PLAY_FLAG, GAME_PAD_STATE(RETRO_DEVICE_ID_JOYPAD_START)); - - set_game_pad_state(LB_FLAG, GAME_PAD_STATE(RETRO_DEVICE_ID_JOYPAD_L)); - set_game_pad_state(RB_FLAG, GAME_PAD_STATE(RETRO_DEVICE_ID_JOYPAD_R)); - - set_game_pad_state(LS_CLK_FLAG, GAME_PAD_STATE(RETRO_DEVICE_ID_JOYPAD_L3)); - set_game_pad_state(RS_CLK_FLAG, GAME_PAD_STATE(RETRO_DEVICE_ID_JOYPAD_R3)); - - if (Settings::settings()->swap_ab_xy()) { - set_game_pad_state(A_FLAG, GAME_PAD_STATE(RETRO_DEVICE_ID_JOYPAD_B)); - set_game_pad_state(B_FLAG, GAME_PAD_STATE(RETRO_DEVICE_ID_JOYPAD_A)); - set_game_pad_state(X_FLAG, GAME_PAD_STATE(RETRO_DEVICE_ID_JOYPAD_Y)); - set_game_pad_state(Y_FLAG, GAME_PAD_STATE(RETRO_DEVICE_ID_JOYPAD_X)); - } else { - set_game_pad_state(A_FLAG, GAME_PAD_STATE(RETRO_DEVICE_ID_JOYPAD_A)); - set_game_pad_state(B_FLAG, GAME_PAD_STATE(RETRO_DEVICE_ID_JOYPAD_B)); - set_game_pad_state(X_FLAG, GAME_PAD_STATE(RETRO_DEVICE_ID_JOYPAD_X)); - set_game_pad_state(Y_FLAG, GAME_PAD_STATE(RETRO_DEVICE_ID_JOYPAD_Y)); - } -} - -void moonlight_libretro_wrapper_draw() { - nanogui::draw(); -} diff --git a/src/moonlight_libretro_wrapper.h b/src/moonlight_libretro_wrapper.h deleted file mode 100755 index d8412de..0000000 --- a/src/moonlight_libretro_wrapper.h +++ /dev/null @@ -1,30 +0,0 @@ -#include -#include - -#ifdef __cplusplus -#define EXTERN extern "C" -#else -#define EXTERN extern -#endif - -EXTERN int16_t keyboard_state[]; - -struct GamePadState { - short buttonFlags; - unsigned char leftTrigger; - unsigned char rightTrigger; - short leftStickX; - short leftStickY; - short rightStickX; - short rightStickY; -}; - -EXTERN struct GamePadState game_pad_state; - -EXTERN void moonlight_libretro_wrapper_preinit(); -EXTERN void moonlight_libretro_wrapper_init(int width, int height); -EXTERN void moonlight_libretro_wrapper_set_working_dir(const char* dir); -EXTERN void moonlight_libretro_wrapper_handle_mouse_move(double x, double y); -EXTERN void moonlight_libretro_wrapper_handle_mouse_button(int button, int action, int modifiers); -EXTERN void moonlight_libretro_wrapper_handle_game_pad(); -EXTERN void moonlight_libretro_wrapper_draw(); diff --git a/src/ui/buttons/HostButton.cpp b/src/ui/buttons/HostButton.cpp index 56a1636..1c00d71 100644 --- a/src/ui/buttons/HostButton.cpp +++ b/src/ui/buttons/HostButton.cpp @@ -13,8 +13,7 @@ HostButton::HostButton(Widget* parent, const std::string &host): Button(parent, add()->set_fixed_height(170); auto label = add