Add USB mouse support

This commit is contained in:
rock88 2021-02-07 19:01:27 +03:00
parent 535708f91f
commit 352d2093f2
5 changed files with 190 additions and 72 deletions

View file

@ -319,6 +319,7 @@
36BFCCF42479724900245D40 /* GameStreamClient.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = GameStreamClient.hpp; sourceTree = "<group>"; };
36BFCCF52479724900245D40 /* GameStreamClient.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GameStreamClient.cpp; sourceTree = "<group>"; };
36BFCCF72479725900245D40 /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = main.cpp; sourceTree = "<group>"; };
36CF721D25D038C700878A8E /* switch.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = switch.h; sourceTree = "<group>"; };
36D3F8422469B5C400CDEF9B /* MoonlightSession.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = MoonlightSession.cpp; sourceTree = "<group>"; };
36D3F8432469B5C400CDEF9B /* MoonlightSession.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = MoonlightSession.hpp; sourceTree = "<group>"; };
36D3F8492469CC2600CDEF9B /* IAudioRenderer.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = IAudioRenderer.hpp; sourceTree = "<group>"; };
@ -653,6 +654,7 @@
36DFDCF12459F79000FC51CE /* ui */,
36D3F8462469C8DD00CDEF9B /* streaming */,
36F1646E2474736E00D70AD9 /* switch */,
36CF721C25D038C700878A8E /* switch_support */,
364A6A8D24786E2200460028 /* BoxArtManager.cpp */,
364A6A8E24786E2200460028 /* BoxArtManager.hpp */,
36A0C03B2461F03C0083289C /* Settings.cpp */,
@ -682,6 +684,14 @@
path = libgamestream;
sourceTree = "<group>";
};
36CF721C25D038C700878A8E /* switch_support */ = {
isa = PBXGroup;
children = (
36CF721D25D038C700878A8E /* switch.h */,
);
path = switch_support;
sourceTree = "<group>";
};
36D3F8462469C8DD00CDEF9B /* streaming */ = {
isa = PBXGroup;
children = (
@ -1093,6 +1103,7 @@
"\"$(SRCROOT)/third_party/moonlight-common-c/enet/include\"",
"\"$(SRCROOT)/third_party/moonlight-common-c/src\"",
"\"$(SRCROOT)/src/switch\"",
"\"$(SRCROOT)/src/switch_support\"",
/opt/devkitpro/libnx/include2,
);
LIBRARY_SEARCH_PATHS = /usr/local/lib;
@ -1185,6 +1196,7 @@
"\"$(SRCROOT)/third_party/moonlight-common-c/enet/include\"",
"\"$(SRCROOT)/third_party/moonlight-common-c/src\"",
"\"$(SRCROOT)/src/switch\"",
"\"$(SRCROOT)/src/switch_support\"",
/opt/devkitpro/libnx/include2,
);
LIBRARY_SEARCH_PATHS = /usr/local/lib;

View file

@ -4,9 +4,9 @@
#include <nanogui/nanogui.h>
#include <nanogui/opengl.h>
#include <GLFW/glfw3.h>
#include <switch.h>
#ifdef __SWITCH__
#include <switch.h>
static HidVibrationDeviceHandle VibrationDeviceHandles[2][2];
static HidVibrationValue VibrationValues[2];
static HidVibrationValue VibrationValue_stop;
@ -167,87 +167,119 @@ bool InputController::gamepad_trigger_is_enabled(int trigger) {
return glfw_gamepad_state.axes[trigger] > 0;
}
void InputController::send_to_stream() {
// Mouse
void InputController::send_mouse_to_stream() {
static bool is_pressed = false, is_released = false;
static bool l_is_pressed = false, r_is_pressed = false;
static int last_mouse_x = 0, last_mouse_y = 0;
static int last_send_mouse_x = 0, last_send_mouse_y = 0;
if (mouse_state.is_pressed && !is_pressed) {
is_pressed = true;
last_mouse_x = mouse_state.x;
last_mouse_y = mouse_state.y;
} else if (!mouse_state.is_pressed && is_pressed) {
is_pressed = false;
}
HidMouseState mouseState;
if (Settings::settings()->click_by_tap()) {
if (last_send_mouse_x != mouse_state.x || last_send_mouse_y != mouse_state.y) {
LiSendMousePositionEvent(mouse_state.x, mouse_state.y, m_width, m_height);
last_send_mouse_x = mouse_state.x;
last_send_mouse_y = mouse_state.y;
if (hidGetMouseStates(&mouseState, 1) > 0 && (mouseState.attributes & HidMouseAttribute_IsConnected)) {
if (last_send_mouse_x != mouseState.x || last_send_mouse_y != mouseState.y) {
LiSendMousePositionEvent(mouseState.x, mouseState.y, m_width, m_height);
last_send_mouse_x = mouseState.x;
last_send_mouse_y = mouseState.y;
}
if (gamepad_button_is_enabled(NANOGUI_GAMEPAD_BUTTON_RIGHT_BUMPER) || gamepad_trigger_is_enabled(NANOGUI_GAMEPAD_AXIS_RIGHT_TRIGGER)) {
if (mouse_state.is_pressed) {
is_released = false;
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_RIGHT);
} else if (!is_released) {
is_released = true;
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_RIGHT);
}
} else {
if (mouse_state.is_pressed) {
is_released = false;
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_LEFT);
} else if (!is_released) {
is_released = true;
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_LEFT);
}
if ((mouseState.buttons & HidMouseButton_Left) && !l_is_pressed) {
l_is_pressed = true;
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_LEFT);
} else if (!(mouseState.buttons & HidMouseButton_Left) && l_is_pressed) {
l_is_pressed = false;
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_LEFT);
}
if ((mouseState.buttons & HidMouseButton_Right) && !r_is_pressed) {
r_is_pressed = true;
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_RIGHT);
} else if (!(mouseState.buttons & HidMouseButton_Right) && r_is_pressed) {
r_is_pressed = false;
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_RIGHT);
}
// Why wheel_delta_x?
if (mouseState.wheel_delta_x != 0) {
LiSendScrollEvent(mouseState.wheel_delta_x);
}
} else {
bool move_mouse = !gamepad_trigger_is_enabled(NANOGUI_GAMEPAD_AXIS_LEFT_TRIGGER) && !gamepad_trigger_is_enabled(NANOGUI_GAMEPAD_AXIS_RIGHT_TRIGGER);
if (mouse_state.is_pressed && !is_pressed) {
is_pressed = true;
last_mouse_x = mouse_state.x;
last_mouse_y = mouse_state.y;
} else if (!mouse_state.is_pressed && is_pressed) {
is_pressed = false;
}
if (move_mouse) {
int relative_mouse_x = mouse_state.x - last_mouse_x;
int relative_mouse_y = mouse_state.y - last_mouse_y;
if (Settings::settings()->click_by_tap()) {
if (last_send_mouse_x != mouse_state.x || last_send_mouse_y != mouse_state.y) {
LiSendMousePositionEvent(mouse_state.x, mouse_state.y, m_width, m_height);
last_send_mouse_x = mouse_state.x;
last_send_mouse_y = mouse_state.y;
}
if (relative_mouse_x != last_send_mouse_x || relative_mouse_y != last_send_mouse_y) {
LiSendMouseMoveEvent(relative_mouse_x, relative_mouse_y);
last_send_mouse_x = relative_mouse_x;
last_send_mouse_y = relative_mouse_y;
if (gamepad_button_is_enabled(NANOGUI_GAMEPAD_BUTTON_RIGHT_BUMPER) || gamepad_trigger_is_enabled(NANOGUI_GAMEPAD_AXIS_RIGHT_TRIGGER)) {
if (mouse_state.is_pressed) {
is_released = false;
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_RIGHT);
} else if (!is_released) {
is_released = true;
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_RIGHT);
}
} else {
if (mouse_state.is_pressed) {
is_released = false;
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_LEFT);
} else if (!is_released) {
is_released = true;
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_LEFT);
}
}
} else {
bool move_mouse = !gamepad_trigger_is_enabled(NANOGUI_GAMEPAD_AXIS_LEFT_TRIGGER) && !gamepad_trigger_is_enabled(NANOGUI_GAMEPAD_AXIS_RIGHT_TRIGGER);
if (move_mouse) {
int relative_mouse_x = mouse_state.x - last_mouse_x;
int relative_mouse_y = mouse_state.y - last_mouse_y;
if (relative_mouse_x != last_send_mouse_x || relative_mouse_y != last_send_mouse_y) {
LiSendMouseMoveEvent(relative_mouse_x, relative_mouse_y);
last_send_mouse_x = relative_mouse_x;
last_send_mouse_y = relative_mouse_y;
}
}
last_mouse_x = mouse_state.x;
last_mouse_y = mouse_state.y;
if (gamepad_button_is_enabled(NANOGUI_GAMEPAD_BUTTON_LEFT_BUMPER) || gamepad_trigger_is_enabled(NANOGUI_GAMEPAD_AXIS_LEFT_TRIGGER)) {
if (mouse_state.is_pressed) {
is_released = false;
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_LEFT);
} else if (!is_released) {
is_released = true;
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_LEFT);
}
} else if (gamepad_button_is_enabled(NANOGUI_GAMEPAD_BUTTON_RIGHT_BUMPER) || gamepad_trigger_is_enabled(NANOGUI_GAMEPAD_AXIS_RIGHT_TRIGGER)) {
if (mouse_state.is_pressed) {
is_released = false;
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_RIGHT);
} else if (!is_released) {
is_released = true;
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_RIGHT);
}
}
}
last_mouse_x = mouse_state.x;
last_mouse_y = mouse_state.y;
if (gamepad_button_is_enabled(NANOGUI_GAMEPAD_BUTTON_LEFT_BUMPER) || gamepad_trigger_is_enabled(NANOGUI_GAMEPAD_AXIS_LEFT_TRIGGER)) {
if (mouse_state.is_pressed) {
is_released = false;
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_LEFT);
} else if (!is_released) {
is_released = true;
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_LEFT);
}
} else if (gamepad_button_is_enabled(NANOGUI_GAMEPAD_BUTTON_RIGHT_BUMPER) || gamepad_trigger_is_enabled(NANOGUI_GAMEPAD_AXIS_RIGHT_TRIGGER)) {
if (mouse_state.is_pressed) {
is_released = false;
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_RIGHT);
} else if (!is_released) {
is_released = true;
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_RIGHT);
}
// Scroll
if (m_scroll_y != 0) {
LiSendHighResScrollEvent(m_scroll_y > 0 ? fmax(m_scroll_y, 1) : fmin(m_scroll_y, -1));
m_scroll_y = 0;
}
}
// Scroll
if (m_scroll_y != 0) {
LiSendHighResScrollEvent(m_scroll_y > 0 ? fmax(m_scroll_y, 1) : fmin(m_scroll_y, -1));
m_scroll_y = 0;
}
// Keyboard
}
void InputController::send_keyboard_to_stream() {
static bool send_alt_enter = false;
if (!send_alt_enter && gamepad_combo_is_enabled(GamepadComboAltEnter)) {
@ -267,8 +299,9 @@ void InputController::send_to_stream() {
send_escape = false;
LiSendKeyboardEvent(0x1B, KEY_ACTION_UP, 0);
}
// Gamepad
}
void InputController::send_gamepad_to_stream() {
auto mapped_gamepad = GamepadMapper::mapper()->map(glfw_gamepad_state);
short buttonFlags = 0;
unsigned char leftTrigger = 0xFFFF * (mapped_gamepad.axes[GLFW_GAMEPAD_AXIS_LEFT_TRIGGER] + 1) / 2;

View file

@ -20,11 +20,19 @@ public:
bool gamepad_combo_is_enabled(GamepadCombo combo);
void send_to_stream();
void send_to_stream() {
send_mouse_to_stream();
send_keyboard_to_stream();
send_gamepad_to_stream();
}
private:
InputController();
void send_mouse_to_stream();
void send_keyboard_to_stream();
void send_gamepad_to_stream();
bool gamepad_button_is_enabled(int button);
bool gamepad_trigger_is_enabled(int trigger);
};

View file

@ -7,10 +7,7 @@
#include "GameStreamClient.hpp"
#include "Logger.hpp"
#include <glad/glad.h>
#ifdef __SWITCH__
#include <switch.h>
#endif
#include <GLFW/glfw3.h>
@ -80,6 +77,8 @@ int main(int argc, const char * argv[]) {
InputController::controller()->handle_keyboard_event(key, scancode, action, mods);
});
hidInitializeMouse();
nanogui::init();
nanogui::ref<Application> app = new Application(Size(m_width, m_height), Size(m_fb_width, m_fb_height));

View file

@ -0,0 +1,66 @@
// Some mock part of libnx stuff for import and use <switch.h> on others plaforms
typedef uint8_t u8; ///< 8-bit unsigned integer.
typedef uint16_t u16; ///< 16-bit unsigned integer.
typedef uint32_t u32; ///< 32-bit unsigned integer.
typedef uint64_t u64; ///< 64-bit unsigned integer.
typedef __uint128_t u128; ///< 128-bit unsigned integer.
typedef int8_t s8; ///< 8-bit signed integer.
typedef int16_t s16; ///< 16-bit signed integer.
typedef int32_t s32; ///< 32-bit signed integer.
typedef int64_t s64; ///< 64-bit signed integer.
typedef __int128_t s128; ///< 128-bit unsigned integer.
typedef volatile u8 vu8; ///< 8-bit volatile unsigned integer.
typedef volatile u16 vu16; ///< 16-bit volatile unsigned integer.
typedef volatile u32 vu32; ///< 32-bit volatile unsigned integer.
typedef volatile u64 vu64; ///< 64-bit volatile unsigned integer.
typedef volatile u128 vu128; ///< 128-bit volatile unsigned integer.
typedef volatile s8 vs8; ///< 8-bit volatile signed integer.
typedef volatile s16 vs16; ///< 16-bit volatile signed integer.
typedef volatile s32 vs32; ///< 32-bit volatile signed integer.
typedef volatile s64 vs64; ///< 64-bit volatile signed integer.
typedef volatile s128 vs128; ///< 128-bit volatile signed integer.
typedef u32 Handle; ///< Kernel object handle.
typedef u32 Result; ///< Function error code result type.
/// Checks whether a result code indicates success.
#define R_SUCCEEDED(res) ((res)==0)
/// Checks whether a result code indicates failure.
#define R_FAILED(res) ((res)!=0)
#define BIT(n) (1U<<(n))
typedef struct HidMouseState {
u64 sampling_number; ///< SamplingNumber
s32 x; ///< X
s32 y; ///< Y
s32 delta_x; ///< DeltaX
s32 delta_y; ///< DeltaY
s32 wheel_delta_x; ///< WheelDeltaX
s32 wheel_delta_y; ///< WheelDeltaY
u32 buttons; ///< Bitfield of \ref HidMouseButton.
u32 attributes; ///< Bitfield of \ref HidMouseAttribute.
} HidMouseState;
typedef enum {
HidMouseAttribute_Transferable = BIT(0), ///< Transferable
HidMouseAttribute_IsConnected = BIT(1), ///< IsConnected
} HidMouseAttribute;
typedef enum {
HidMouseButton_Left = BIT(0),
HidMouseButton_Right = BIT(1),
HidMouseButton_Middle = BIT(2),
HidMouseButton_Forward = BIT(3),
HidMouseButton_Back = BIT(4),
} HidMouseButton;
static void hidInitializeMouse(void) {};
static size_t hidGetMouseStates(HidMouseState *states, size_t count) {
return 0;
}