Rewrite controls

This commit is contained in:
rock88 2020-05-06 23:51:39 +03:00
parent 7688adcc3f
commit 11d54f819f
13 changed files with 359 additions and 307 deletions

View file

@ -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 \

View file

@ -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;

View file

@ -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 = "<group>"; };
3602C3BC245DBA9100368900 /* AppButton.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = AppButton.hpp; sourceTree = "<group>"; };
3602C3C0245DC7E300368900 /* Makefile */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = "<group>"; };
361F8A38245CB44E00A8D9C0 /* moonlight_libretro_wrapper.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = moonlight_libretro_wrapper.cpp; sourceTree = "<group>"; };
361F8A39245CB44E00A8D9C0 /* moonlight_libretro_wrapper.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = moonlight_libretro_wrapper.h; sourceTree = "<group>"; };
3603E93A246316400051287D /* InputController.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = InputController.cpp; sourceTree = "<group>"; };
3603E93B246316400051287D /* InputController.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = InputController.hpp; sourceTree = "<group>"; };
3652ECE8245B3AFF001FABF3 /* colorpicker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = colorpicker.h; sourceTree = "<group>"; };
3652ECE9245B3AFF001FABF3 /* renderpass.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = renderpass.h; sourceTree = "<group>"; };
3652ECEA245B3AFF001FABF3 /* theme.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = theme.h; sourceTree = "<group>"; };
@ -272,7 +272,7 @@
3652F081245C60D1001FABF3 /* LoadingOverlay.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = LoadingOverlay.cpp; sourceTree = "<group>"; };
3652F082245C60D1001FABF3 /* LoadingOverlay.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = LoadingOverlay.hpp; sourceTree = "<group>"; };
3652F084245C6CFC001FABF3 /* libretro.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = libretro.h; sourceTree = "<group>"; };
3652F085245C6CFC001FABF3 /* moonlight_libretro.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = moonlight_libretro.c; sourceTree = "<group>"; };
3652F085245C6CFC001FABF3 /* moonlight_libretro.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = moonlight_libretro.cpp; sourceTree = "<group>"; };
3652F089245C8569001FABF3 /* ContentWindow.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ContentWindow.cpp; sourceTree = "<group>"; };
367CD958245DE25F00A95738 /* StreamWindow.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = StreamWindow.cpp; sourceTree = "<group>"; };
367CD959245DE25F00A95738 /* StreamWindow.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = StreamWindow.hpp; sourceTree = "<group>"; };
@ -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 */,

162
src/InputController.cpp Normal file
View file

@ -0,0 +1,162 @@
#include "InputController.hpp"
#include "Settings.hpp"
#include "Limelight.h"
#include "libretro.h"
#include "Limelight.h"
#include <nanogui/nanogui.h>
#include <nanogui/opengl.h>
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
);
}

52
src/InputController.hpp Normal file
View file

@ -0,0 +1,52 @@
#include <stdio.h>
#include <stdint.h>
#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();
};

View file

@ -4,8 +4,14 @@
#include <fstream>
#include <iomanip>
#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<type>(); \
}
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<std::vector<std::string>>());
TRY_JSON(m_resolution = json["settings"]["resolution"].get<int>());
TRY_JSON(m_fps = json["settings"]["fps"].get<int>());
TRY_JSON(m_bitrate = json["settings"]["bitrate"].get<int>());
TRY_JSON(m_swap_ab_xy = json["settings"]["swap_ab_xy"].get<bool>());
JSON_GET_VALUE(m_hosts, json["hosts"], is_array, std::vector<std::string>);
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());
}
}

View file

@ -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();
}

View file

@ -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<Application> 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);

View file

@ -3,12 +3,16 @@
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <curl/curl.h>
#include <openssl/ssl.h>
#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);
}

View file

@ -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 <curl/curl.h>
#include <openssl/ssl.h>
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();
}

View file

@ -1,30 +0,0 @@
#include <stdio.h>
#include <stdint.h>
#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();

View file

@ -13,8 +13,7 @@ HostButton::HostButton(Widget* parent, const std::string &host): Button(parent,
add<Widget>()->set_fixed_height(170);
auto label = add<Label>(host);
label->set_font_size(20);
inc_ref();
label->inc_ref();
GameStreamClient::client()->connect(host, [this, label](auto result) {
if (result.isSuccess()) {
@ -27,8 +26,12 @@ HostButton::HostButton(Widget* parent, const std::string &host): Button(parent,
m_is_active = false;
m_host_status_icon = FA_POWER_OFF;
}
screen()->perform_layout();
this->dec_ref();
if (m_parent != NULL) {
screen()->perform_layout();
}
label->dec_ref();
});
}

View file

@ -2,20 +2,15 @@
#include "LoadingOverlay.hpp"
#include "GameStreamClient.hpp"
#include "Settings.hpp"
#include "InputController.hpp"
#include "gl_render.h"
#include "video_decoder.h"
#include "audio_decoder.h"
#include "nanovg.h"
#include "moonlight_libretro_wrapper.h"
#include "libretro.h"
#include <algorithm>
#include <memory>
static bool pressed = false, sent_l_press = false, sent_r_press = false;
static bool sent_alt_tab = false;
static int current_mouse_x = 0, current_mouse_y = 0;
static int start_mouse_x = 0, start_mouse_y = 0;
using namespace nanogui;
static std::weak_ptr<StreamWindow *> _weak;
@ -28,12 +23,6 @@ StreamWindow::StreamWindow(Widget *parent, const std::string &address, int app_i
m_connection_status_is_poor = false;
m_size = parent->size();
pressed = sent_l_press = sent_r_press = false;
sent_alt_tab = false;
current_mouse_x = width() / 2;
current_mouse_y = height() / 2;
start_mouse_x = start_mouse_y = 0;
LiInitializeStreamConfiguration(&m_config);
int h = Settings::settings()->resolution();
@ -121,83 +110,22 @@ void StreamWindow::draw(NVGcontext *ctx) {
}
// TODO: Get out of here...
if (keyboard_state[RETROK_q] || ((game_pad_state.buttonFlags & LB_FLAG) && (game_pad_state.buttonFlags & RB_FLAG) && (game_pad_state.buttonFlags & DOWN_FLAG))) {
async([this] {
this->terminate(true);
});
}
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
);
// Send Alt + Tab
if (sent_alt_tab) {
sent_alt_tab = false;
LiSendKeyboardEvent(0x09, KEY_ACTION_UP, MODIFIER_ALT);
if (GAME_PAD_COMBO(DOWN_FLAG)) {
async([this] { this->terminate(true); });
}
if ((game_pad_state.buttonFlags & LB_FLAG) && (game_pad_state.buttonFlags & RB_FLAG) && (game_pad_state.buttonFlags & LEFT_FLAG)) {
sent_alt_tab = true;
LiSendKeyboardEvent(0x09, KEY_ACTION_DOWN, MODIFIER_ALT);
if (GAME_PAD_COMBO(UP_FLAG)) {
async([this] { this->terminate(false); });
}
InputController::controller()->send_to_stream();
}
bool StreamWindow::mouse_button_event(const nanogui::Vector2i &p, int button, bool down, int modifiers) {
#if defined(__LIBRETRO__) && (defined(__LAKKA_SWITCH__) || defined(__APPLE__))
if (button == 0) {
if (down && !pressed) {
start_mouse_x = p.x();
start_mouse_y = p.y();
}
pressed = down;
if (pressed && (keyboard_state[RETROK_LCTRL] || (game_pad_state.buttonFlags & LB_FLAG))) {
sent_l_press = true;
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_LEFT);
} else if (sent_l_press) {
sent_l_press = false;
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_LEFT);
}
if (pressed && (keyboard_state[RETROK_LALT] || (game_pad_state.buttonFlags & RB_FLAG))) {
sent_r_press = true;
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_RIGHT);
} else if (sent_r_press) {
sent_r_press = false;
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_RIGHT);
}
}
#else
if (button == 0) {
LiSendMouseButtonEvent(down ? BUTTON_ACTION_PRESS : BUTTON_ACTION_RELEASE, BUTTON_LEFT);
} else if (button == 1) {
LiSendMouseButtonEvent(down ? BUTTON_ACTION_PRESS : BUTTON_ACTION_RELEASE, BUTTON_RIGHT);
}
#endif
return true;
}
bool StreamWindow::mouse_motion_event(const Vector2i &p, const Vector2i &rel, int button, int modifiers) {
#if defined(__LIBRETRO__) && (defined(__LAKKA_SWITCH__) || defined(__APPLE__))
if (pressed) {
current_mouse_x = std::min(std::max(current_mouse_x + p.x() - start_mouse_x, 0), width());
current_mouse_y = std::min(std::max(current_mouse_y + p.y() - start_mouse_y, 0), height());
LiSendMousePositionEvent(current_mouse_x, current_mouse_y, width(), height());
start_mouse_x = p.x();
start_mouse_y = p.y();
}
#else
LiSendMousePositionEvent(p.x(), p.y(), width(), height());
#endif
return true;
}