mirror of
https://github.com/rock88/moonlight-nx
synced 2024-11-22 03:23:07 +00:00
Separate frontend for mouse/gamepad, libretro support in future?
This commit is contained in:
parent
4bc5beb704
commit
3cc64faea5
12 changed files with 491 additions and 413 deletions
|
@ -21,6 +21,8 @@
|
|||
/* End PBXAggregateTarget section */
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
28896568262B64CD00139ABE /* MouseFrontendSwitch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 28896566262B64CD00139ABE /* MouseFrontendSwitch.cpp */; };
|
||||
28896570262B6EDD00139ABE /* GamepadFrontendSwitch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2889656E262B6EDD00139ABE /* GamepadFrontendSwitch.cpp */; };
|
||||
28AD4A752606120A009314C6 /* glad.c in Sources */ = {isa = PBXBuildFile; fileRef = 28AD4A722606120A009314C6 /* glad.c */; };
|
||||
3602C3B7245D903000368900 /* HostButton.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3602C3B5245D903000368900 /* HostButton.cpp */; };
|
||||
3602C3BA245DB3C800368900 /* AppListWindow.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3602C3B8245DB3C800368900 /* AppListWindow.cpp */; };
|
||||
|
@ -140,6 +142,12 @@
|
|||
/* End PBXCopyFilesBuildPhase section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
28896563262B628700139ABE /* MouseFrontend.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = MouseFrontend.hpp; sourceTree = "<group>"; };
|
||||
28896566262B64CD00139ABE /* MouseFrontendSwitch.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = MouseFrontendSwitch.cpp; sourceTree = "<group>"; };
|
||||
28896567262B64CD00139ABE /* MouseFrontendSwitch.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = MouseFrontendSwitch.hpp; sourceTree = "<group>"; };
|
||||
2889656B262B6E0100139ABE /* GamepadFrontend.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = GamepadFrontend.hpp; sourceTree = "<group>"; };
|
||||
2889656E262B6EDD00139ABE /* GamepadFrontendSwitch.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = GamepadFrontendSwitch.cpp; sourceTree = "<group>"; };
|
||||
2889656F262B6EDD00139ABE /* GamepadFrontendSwitch.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = GamepadFrontendSwitch.hpp; sourceTree = "<group>"; };
|
||||
28AD4A712606120A009314C6 /* glad.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = glad.h; sourceTree = "<group>"; };
|
||||
28AD4A722606120A009314C6 /* glad.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = glad.c; sourceTree = "<group>"; };
|
||||
28AD4A742606120A009314C6 /* khrplatform.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = khrplatform.h; sourceTree = "<group>"; };
|
||||
|
@ -446,10 +454,16 @@
|
|||
362041A125D94D7700D21EE3 /* StreamControlsController.hpp */,
|
||||
3620418B25D7F04400D21EE3 /* MouseController.cpp */,
|
||||
3620418C25D7F04400D21EE3 /* MouseController.hpp */,
|
||||
28896563262B628700139ABE /* MouseFrontend.hpp */,
|
||||
28896566262B64CD00139ABE /* MouseFrontendSwitch.cpp */,
|
||||
28896567262B64CD00139ABE /* MouseFrontendSwitch.hpp */,
|
||||
3620419625D85B5F00D21EE3 /* KeyboardController.cpp */,
|
||||
3620419725D85B5F00D21EE3 /* KeyboardController.hpp */,
|
||||
362041A925D9BE4900D21EE3 /* GamepadController.cpp */,
|
||||
362041AA25D9BE4900D21EE3 /* GamepadController.hpp */,
|
||||
2889656B262B6E0100139ABE /* GamepadFrontend.hpp */,
|
||||
2889656E262B6EDD00139ABE /* GamepadFrontendSwitch.cpp */,
|
||||
2889656F262B6EDD00139ABE /* GamepadFrontendSwitch.hpp */,
|
||||
3689D6DB249154F90008CB75 /* GamepadMapper.cpp */,
|
||||
3689D6DC249154F90008CB75 /* GamepadMapper.hpp */,
|
||||
);
|
||||
|
@ -995,11 +1009,13 @@
|
|||
3652F075245C292B001FABF3 /* VideoStream.c in Sources */,
|
||||
3652EFE0245B3B00001FABF3 /* imageview.cpp in Sources */,
|
||||
3652EFDB245B3B00001FABF3 /* texture.cpp in Sources */,
|
||||
28896568262B64CD00139ABE /* MouseFrontendSwitch.cpp in Sources */,
|
||||
36A0C03D2461F03C0083289C /* Settings.cpp in Sources */,
|
||||
36BFCCF82479725900245D40 /* main.cpp in Sources */,
|
||||
3652F079245C292B001FABF3 /* RtpReorderQueue.c in Sources */,
|
||||
36BFCCF12479723E00245D40 /* xml.cpp in Sources */,
|
||||
3652F065245C292B001FABF3 /* list.c in Sources */,
|
||||
28896570262B6EDD00139ABE /* GamepadFrontendSwitch.cpp in Sources */,
|
||||
3620418D25D7F04400D21EE3 /* MouseController.cpp in Sources */,
|
||||
36DFE0CD2459FA3F00FC51CE /* nanogui_resources.cpp in Sources */,
|
||||
36DDACF824929919001133D1 /* InputSettingsWindow.cpp in Sources */,
|
||||
|
|
|
@ -2,263 +2,78 @@
|
|||
#include "Limelight.h"
|
||||
#include <nanogui/nanogui.h>
|
||||
#include <nanogui/opengl.h>
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
static inline bool pad_is_equal(PadState& state, PadState& other) {
|
||||
return padGetButtons(&state) == padGetButtons(&other) &&
|
||||
padGetStickPos(&state, 0).x == padGetStickPos(&other, 0).x &&
|
||||
padGetStickPos(&state, 0).y == padGetStickPos(&other, 0).y &&
|
||||
padGetStickPos(&state, 1).x == padGetStickPos(&other, 1).x &&
|
||||
padGetStickPos(&state, 1).y == padGetStickPos(&other, 1).y;
|
||||
}
|
||||
|
||||
static inline int pad_button_number(HidNpadButton button) {
|
||||
static std::map<HidNpadButton, int> map = {
|
||||
{ HidNpadButton_A, 0 },
|
||||
{ HidNpadButton_B, 1 },
|
||||
{ HidNpadButton_X, 2 },
|
||||
{ HidNpadButton_Y, 3 },
|
||||
{ HidNpadButton_StickL, 4 },
|
||||
{ HidNpadButton_StickR, 5 },
|
||||
{ HidNpadButton_L, 6 },
|
||||
{ HidNpadButton_R, 7 },
|
||||
{ HidNpadButton_ZL, 8 },
|
||||
{ HidNpadButton_ZR, 9 },
|
||||
{ HidNpadButton_Plus, 10 },
|
||||
{ HidNpadButton_Minus, 11 },
|
||||
{ HidNpadButton_Left, 12 },
|
||||
{ HidNpadButton_Up, 13 },
|
||||
{ HidNpadButton_Right, 14 },
|
||||
{ HidNpadButton_Down, 15 }
|
||||
};
|
||||
return map[button];
|
||||
}
|
||||
|
||||
static inline int pad_button_to_glfw_button(int button) {
|
||||
static std::map<int, int> map = {
|
||||
{ pad_button_number(HidNpadButton_A), NANOGUI_GAMEPAD_BUTTON_A },
|
||||
{ pad_button_number(HidNpadButton_B), NANOGUI_GAMEPAD_BUTTON_B },
|
||||
{ pad_button_number(HidNpadButton_X), NANOGUI_GAMEPAD_BUTTON_X },
|
||||
{ pad_button_number(HidNpadButton_Y), NANOGUI_GAMEPAD_BUTTON_Y },
|
||||
{ pad_button_number(HidNpadButton_StickL), NANOGUI_GAMEPAD_BUTTON_LEFT_THUMB },
|
||||
{ pad_button_number(HidNpadButton_StickR), NANOGUI_GAMEPAD_BUTTON_RIGHT_THUMB },
|
||||
{ pad_button_number(HidNpadButton_L), NANOGUI_GAMEPAD_BUTTON_LEFT_BUMPER },
|
||||
{ pad_button_number(HidNpadButton_R), NANOGUI_GAMEPAD_BUTTON_RIGHT_BUMPER },
|
||||
{ pad_button_number(HidNpadButton_Plus), NANOGUI_GAMEPAD_BUTTON_START },
|
||||
{ pad_button_number(HidNpadButton_Minus), NANOGUI_GAMEPAD_BUTTON_BACK },
|
||||
{ pad_button_number(HidNpadButton_Up), NANOGUI_GAMEPAD_BUTTON_DPAD_UP },
|
||||
{ pad_button_number(HidNpadButton_Down), NANOGUI_GAMEPAD_BUTTON_DPAD_DOWN },
|
||||
{ pad_button_number(HidNpadButton_Left), NANOGUI_GAMEPAD_BUTTON_DPAD_LEFT },
|
||||
{ pad_button_number(HidNpadButton_Right), NANOGUI_GAMEPAD_BUTTON_DPAD_RIGHT }
|
||||
};
|
||||
|
||||
if (map.find(button) != map.end()) {
|
||||
return map[button];
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline int pad_button_to_moonlight_button(int button) {
|
||||
static std::map<int, int> map = {
|
||||
{ pad_button_number(HidNpadButton_A), A_FLAG },
|
||||
{ pad_button_number(HidNpadButton_B), B_FLAG },
|
||||
{ pad_button_number(HidNpadButton_X), X_FLAG },
|
||||
{ pad_button_number(HidNpadButton_Y), Y_FLAG },
|
||||
{ pad_button_number(HidNpadButton_StickL), LS_CLK_FLAG },
|
||||
{ pad_button_number(HidNpadButton_StickR), RS_CLK_FLAG },
|
||||
{ pad_button_number(HidNpadButton_L), LB_FLAG },
|
||||
{ pad_button_number(HidNpadButton_R), RB_FLAG },
|
||||
{ pad_button_number(HidNpadButton_Plus), PLAY_FLAG },
|
||||
{ pad_button_number(HidNpadButton_Minus), BACK_FLAG },
|
||||
{ pad_button_number(HidNpadButton_Up), UP_FLAG },
|
||||
{ pad_button_number(HidNpadButton_Down), DOWN_FLAG },
|
||||
{ pad_button_number(HidNpadButton_Left), LEFT_FLAG },
|
||||
{ pad_button_number(HidNpadButton_Right), RIGHT_FLAG }
|
||||
};
|
||||
return map[button];
|
||||
}
|
||||
|
||||
static inline void padUpdateOverKeyboard(PadState* pad) {
|
||||
static int glfw_keyboard_state[GLFW_KEY_LAST] = {0};
|
||||
|
||||
static std::map<int, HidNpadButton> keyboard_map = {
|
||||
{ GLFW_KEY_UP, HidNpadButton_Up },
|
||||
{ GLFW_KEY_DOWN, HidNpadButton_Down },
|
||||
{ GLFW_KEY_LEFT, HidNpadButton_Left },
|
||||
{ GLFW_KEY_RIGHT, HidNpadButton_Right },
|
||||
{ GLFW_KEY_A, HidNpadButton_A },
|
||||
{ GLFW_KEY_B, HidNpadButton_B },
|
||||
{ GLFW_KEY_X, HidNpadButton_X },
|
||||
{ GLFW_KEY_Y, HidNpadButton_Y },
|
||||
{ GLFW_KEY_Q, HidNpadButton_L },
|
||||
{ GLFW_KEY_E, HidNpadButton_R },
|
||||
{ GLFW_KEY_Z, HidNpadButton_ZL },
|
||||
{ GLFW_KEY_C, HidNpadButton_ZR },
|
||||
{ GLFW_KEY_MINUS, HidNpadButton_Minus },
|
||||
{ GLFW_KEY_EQUAL, HidNpadButton_Plus },
|
||||
{ GLFW_KEY_N, HidNpadButton_StickL },
|
||||
{ GLFW_KEY_M, HidNpadButton_StickR }
|
||||
};
|
||||
|
||||
static std::map<int, std::vector<int>> axis_map = {
|
||||
{ GLFW_KEY_T, { 0, 1, 1 } },
|
||||
{ GLFW_KEY_G, { 0, 1, -1 } },
|
||||
{ GLFW_KEY_F, { 0, 0, -1 } },
|
||||
{ GLFW_KEY_H, { 0, 0, 1 } },
|
||||
{ GLFW_KEY_I, { 1, 1, 1 } },
|
||||
{ GLFW_KEY_K, { 1, 1, -1 } },
|
||||
{ GLFW_KEY_J, { 1, 0, -1 } },
|
||||
{ GLFW_KEY_L, { 1, 0, 1 } }
|
||||
};
|
||||
|
||||
for (auto &pair: keyboard_map) {
|
||||
int is_pressed = glfwGetKey(glfwGetCurrentContext(), pair.first);
|
||||
|
||||
if (glfw_keyboard_state[pair.first] != is_pressed) {
|
||||
glfw_keyboard_state[pair.first] = is_pressed;
|
||||
|
||||
if (is_pressed) {
|
||||
pad->buttons_cur |= pair.second;
|
||||
} else {
|
||||
pad->buttons_cur &= ~pair.second;
|
||||
}
|
||||
static inline void gamepad_callback(short& buttonFlags, int moonlight_button, int nanogui_button, int index, int* nanogui_gamepad_state) {
|
||||
if (buttonFlags & moonlight_button) {
|
||||
if (nanogui_gamepad_state[index] == 0) {
|
||||
nanogui_gamepad_state[index] = 1;
|
||||
nanogui::gamepad_button_callback_event(0, nanogui_button, 1);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &pair: axis_map) {
|
||||
int is_pressed = glfwGetKey(glfwGetCurrentContext(), pair.first);
|
||||
|
||||
if (glfw_keyboard_state[pair.first] != is_pressed) {
|
||||
glfw_keyboard_state[pair.first] = is_pressed;
|
||||
|
||||
if (pair.second[1] == 0) {
|
||||
pad->sticks[pair.second[0]].x = is_pressed ? pair.second[2] * 0x7FFF : 0;
|
||||
} else {
|
||||
pad->sticks[pair.second[0]].y = is_pressed ? pair.second[2] * 0x7FFF : 0;
|
||||
}
|
||||
} else {
|
||||
if (nanogui_gamepad_state[index] == 1) {
|
||||
nanogui_gamepad_state[index] = 0;
|
||||
nanogui::gamepad_button_callback_event(0, nanogui_button, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GamepadController::init() {
|
||||
padConfigureInput(1, HidNpadStyleSet_NpadStandard);
|
||||
padInitializeDefault(&m_pad_state);
|
||||
|
||||
hidInitializeVibrationDevices(m_vibration_device_handles[0], 2, HidNpadIdType_Handheld, HidNpadStyleTag_NpadHandheld);
|
||||
hidInitializeVibrationDevices(m_vibration_device_handles[1], 2, HidNpadIdType_No1, HidNpadStyleTag_NpadJoyDual);
|
||||
void GamepadController::init(GamepadFrontend* frontend) {
|
||||
m_frontend = frontend;
|
||||
}
|
||||
|
||||
void GamepadController::handle_gamepad() {
|
||||
PadState new_state = m_pad_state;
|
||||
PadState prev_state = m_pad_state;
|
||||
m_frontend->handle_gamepad();
|
||||
|
||||
#ifdef __SWITCH__
|
||||
padUpdate(&new_state);
|
||||
#else
|
||||
padUpdateOverKeyboard(&new_state);
|
||||
#endif
|
||||
auto state = m_frontend->gamepad_state();
|
||||
|
||||
if (set_new_pad_state(new_state)) {
|
||||
u64 prev_buttons = padGetButtons(&prev_state);
|
||||
u64 buttons = padGetButtons(&m_pad_state);
|
||||
|
||||
for (int i = 0; i < 28; i++) {
|
||||
bool is_pressed = buttons & BIT(i);
|
||||
|
||||
int glfw_button = pad_button_to_glfw_button(i);
|
||||
|
||||
if (glfw_button == -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((prev_buttons & BIT(i)) != is_pressed) {
|
||||
nanogui::gamepad_button_callback_event(0, glfw_button, is_pressed);
|
||||
}
|
||||
|
||||
if (is_pressed) {
|
||||
m_gamepad_state.buttonFlags |= pad_button_to_moonlight_button(i);
|
||||
} else {
|
||||
m_gamepad_state.buttonFlags &= ~pad_button_to_moonlight_button(i);
|
||||
}
|
||||
}
|
||||
|
||||
m_gamepad_state.leftTrigger = (buttons & HidNpadButton_ZL) ? 0xFF : 0;
|
||||
m_gamepad_state.rightTrigger = (buttons & HidNpadButton_ZR) ? 0xFF : 0;
|
||||
|
||||
if ((prev_buttons & HidNpadButton_ZL) != (buttons & HidNpadButton_ZL)) {
|
||||
nanogui::gamepad_analog_callback_event(0, NANOGUI_GAMEPAD_AXIS_LEFT_TRIGGER, (buttons & HidNpadButton_ZL) ? 1 : 0);
|
||||
}
|
||||
|
||||
if ((prev_buttons & HidNpadButton_ZR) != (buttons & HidNpadButton_ZR)) {
|
||||
nanogui::gamepad_analog_callback_event(0, NANOGUI_GAMEPAD_AXIS_RIGHT_TRIGGER, (buttons & HidNpadButton_ZR) ? 1 : 0);
|
||||
}
|
||||
|
||||
m_gamepad_state.leftStickX = m_pad_state.sticks[0].x;
|
||||
m_gamepad_state.leftStickY = m_pad_state.sticks[0].y;
|
||||
m_gamepad_state.rightStickX = m_pad_state.sticks[1].x;
|
||||
m_gamepad_state.rightStickY = m_pad_state.sticks[1].y;
|
||||
|
||||
if (prev_state.sticks[0].x != m_pad_state.sticks[0].x) {
|
||||
nanogui::gamepad_analog_callback_event(0, NANOGUI_GAMEPAD_AXIS_LEFT_X, (float)m_pad_state.sticks[0].x / 0x7FFF);
|
||||
}
|
||||
|
||||
if (prev_state.sticks[0].y != m_pad_state.sticks[0].y) {
|
||||
nanogui::gamepad_analog_callback_event(0, NANOGUI_GAMEPAD_AXIS_LEFT_Y, (float)m_pad_state.sticks[0].y / 0x7FFF);
|
||||
}
|
||||
|
||||
if (prev_state.sticks[1].x != m_pad_state.sticks[1].x) {
|
||||
nanogui::gamepad_analog_callback_event(0, NANOGUI_GAMEPAD_AXIS_RIGHT_X, (float)m_pad_state.sticks[1].x / 0x7FFF);
|
||||
}
|
||||
|
||||
if (prev_state.sticks[1].y != m_pad_state.sticks[1].y) {
|
||||
nanogui::gamepad_analog_callback_event(0, NANOGUI_GAMEPAD_AXIS_RIGHT_Y, (float)m_pad_state.sticks[1].y / 0x7FFF);
|
||||
}
|
||||
if (state.buttonFlags != m_gamepad_state.buttonFlags) {
|
||||
gamepad_callback(state.buttonFlags, A_FLAG, NANOGUI_GAMEPAD_BUTTON_A, 0, m_nanogui_gamepad_state);
|
||||
gamepad_callback(state.buttonFlags, B_FLAG, NANOGUI_GAMEPAD_BUTTON_B, 1, m_nanogui_gamepad_state);
|
||||
gamepad_callback(state.buttonFlags, X_FLAG, NANOGUI_GAMEPAD_BUTTON_X, 2, m_nanogui_gamepad_state);
|
||||
gamepad_callback(state.buttonFlags, Y_FLAG, NANOGUI_GAMEPAD_BUTTON_Y, 3, m_nanogui_gamepad_state);
|
||||
gamepad_callback(state.buttonFlags, LEFT_FLAG, NANOGUI_GAMEPAD_BUTTON_DPAD_LEFT, 4, m_nanogui_gamepad_state);
|
||||
gamepad_callback(state.buttonFlags, RIGHT_FLAG, NANOGUI_GAMEPAD_BUTTON_DPAD_RIGHT, 5, m_nanogui_gamepad_state);
|
||||
gamepad_callback(state.buttonFlags, UP_FLAG, NANOGUI_GAMEPAD_BUTTON_DPAD_UP, 6, m_nanogui_gamepad_state);
|
||||
gamepad_callback(state.buttonFlags, DOWN_FLAG, NANOGUI_GAMEPAD_BUTTON_DPAD_DOWN, 7, m_nanogui_gamepad_state);
|
||||
gamepad_callback(state.buttonFlags, BACK_FLAG, NANOGUI_GAMEPAD_BUTTON_BACK, 8, m_nanogui_gamepad_state);
|
||||
gamepad_callback(state.buttonFlags, PLAY_FLAG, NANOGUI_GAMEPAD_BUTTON_START, 9, m_nanogui_gamepad_state);
|
||||
gamepad_callback(state.buttonFlags, LB_FLAG, NANOGUI_GAMEPAD_BUTTON_LEFT_BUMPER, 10, m_nanogui_gamepad_state);
|
||||
gamepad_callback(state.buttonFlags, RB_FLAG, NANOGUI_GAMEPAD_BUTTON_RIGHT_BUMPER, 11, m_nanogui_gamepad_state);
|
||||
gamepad_callback(state.buttonFlags, LS_CLK_FLAG, NANOGUI_GAMEPAD_BUTTON_LEFT_THUMB, 12, m_nanogui_gamepad_state);
|
||||
gamepad_callback(state.buttonFlags, RS_CLK_FLAG, NANOGUI_GAMEPAD_BUTTON_RIGHT_THUMB, 13, m_nanogui_gamepad_state);
|
||||
}
|
||||
}
|
||||
|
||||
bool GamepadController::set_new_pad_state(PadState& state) {
|
||||
if (!pad_is_equal(m_pad_state, state)) {
|
||||
m_pad_state = state;
|
||||
return true;
|
||||
|
||||
if (state.leftStickX != m_gamepad_state.leftStickX) {
|
||||
nanogui::gamepad_analog_callback_event(0, NANOGUI_GAMEPAD_AXIS_LEFT_X, (float)state.leftStickX / 0x7FFF);
|
||||
}
|
||||
return false;
|
||||
|
||||
if (state.leftStickY != m_gamepad_state.leftStickY) {
|
||||
nanogui::gamepad_analog_callback_event(0, NANOGUI_GAMEPAD_AXIS_LEFT_Y, (float)state.leftStickY / 0x7FFF);
|
||||
}
|
||||
|
||||
if (state.rightStickX != m_gamepad_state.rightStickX) {
|
||||
nanogui::gamepad_analog_callback_event(0, NANOGUI_GAMEPAD_AXIS_RIGHT_X, (float)state.rightStickX / 0x7FFF);
|
||||
}
|
||||
|
||||
if (state.rightStickY != m_gamepad_state.rightStickY) {
|
||||
nanogui::gamepad_analog_callback_event(0, NANOGUI_GAMEPAD_AXIS_RIGHT_Y, (float)state.rightStickY / 0x7FFF);
|
||||
}
|
||||
|
||||
if (state.leftTrigger != m_gamepad_state.leftTrigger) {
|
||||
nanogui::gamepad_analog_callback_event(0, NANOGUI_GAMEPAD_AXIS_LEFT_TRIGGER, state.leftTrigger ? 1 : 0);
|
||||
}
|
||||
|
||||
if (state.rightTrigger != m_gamepad_state.rightTrigger) {
|
||||
nanogui::gamepad_analog_callback_event(0, NANOGUI_GAMEPAD_AXIS_RIGHT_TRIGGER, state.rightTrigger ? 1 : 0);
|
||||
}
|
||||
|
||||
m_gamepad_state = state;
|
||||
}
|
||||
|
||||
void GamepadController::handle_rumple(unsigned short controller, unsigned short low_freq_motor, unsigned short high_freq_motor) {
|
||||
if (controller == 0) {
|
||||
float low = (float)low_freq_motor / 0xFFFF;
|
||||
float high = (float)high_freq_motor / 0xFFFF;
|
||||
|
||||
memset(m_vibration_values, 0, sizeof(m_vibration_values));
|
||||
|
||||
m_vibration_values[0].amp_low = low;
|
||||
m_vibration_values[0].freq_low = low * 50;
|
||||
m_vibration_values[0].amp_high = high;
|
||||
m_vibration_values[0].freq_high = high * 100;
|
||||
|
||||
m_vibration_values[1].amp_low = low;
|
||||
m_vibration_values[1].freq_low = low * 50;
|
||||
m_vibration_values[1].amp_high = high;
|
||||
m_vibration_values[1].freq_high = high * 100;
|
||||
|
||||
int target_device = padIsHandheld(&m_pad_state) ? 0 : 1;
|
||||
hidSendVibrationValues(m_vibration_device_handles[target_device], m_vibration_values, 2);
|
||||
}
|
||||
m_frontend->handle_rumple(controller, low_freq_motor, high_freq_motor);
|
||||
}
|
||||
|
||||
void GamepadController::stop_rumple() {
|
||||
HidVibrationValue stop;
|
||||
memset(&stop, 0, sizeof(HidVibrationValue));
|
||||
|
||||
stop.freq_low = 160.0f;
|
||||
stop.freq_high = 320.0f;
|
||||
|
||||
memcpy(&m_vibration_values[0], &stop, sizeof(HidVibrationValue));
|
||||
memcpy(&m_vibration_values[1], &stop, sizeof(HidVibrationValue));
|
||||
|
||||
int target_device = padIsHandheld(&m_pad_state) ? 0 : 1;
|
||||
hidSendVibrationValues(m_vibration_device_handles[target_device], m_vibration_values, 2);
|
||||
hidSendVibrationValues(m_vibration_device_handles[1 - target_device], m_vibration_values, 2);
|
||||
m_frontend->stop_rumple();
|
||||
}
|
||||
|
|
|
@ -1,31 +1,10 @@
|
|||
#include "Singleton.hpp"
|
||||
#include <switch.h>
|
||||
#include "GamepadFrontend.hpp"
|
||||
#pragma once
|
||||
|
||||
// Moonlight ready gamepad
|
||||
struct GamepadState {
|
||||
short buttonFlags;
|
||||
unsigned char leftTrigger;
|
||||
unsigned char rightTrigger;
|
||||
short leftStickX;
|
||||
short leftStickY;
|
||||
short rightStickX;
|
||||
short rightStickY;
|
||||
|
||||
bool is_equal(GamepadState other) {
|
||||
return buttonFlags == other.buttonFlags &&
|
||||
leftTrigger == other.leftTrigger &&
|
||||
rightTrigger == other.rightTrigger &&
|
||||
leftStickX == other.leftStickX &&
|
||||
leftStickY == other.leftStickY &&
|
||||
rightStickX == other.rightStickX &&
|
||||
rightStickY == other.rightStickY;
|
||||
}
|
||||
};
|
||||
|
||||
class GamepadController: public Singleton<GamepadController> {
|
||||
public:
|
||||
void init();
|
||||
void init(GamepadFrontend* frontend);
|
||||
|
||||
void handle_gamepad();
|
||||
|
||||
|
@ -37,11 +16,7 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
PadState m_pad_state;
|
||||
GamepadState m_gamepad_state = {0};
|
||||
|
||||
bool set_new_pad_state(PadState& state);
|
||||
|
||||
HidVibrationDeviceHandle m_vibration_device_handles[2][2];
|
||||
HidVibrationValue m_vibration_values[2];
|
||||
int m_nanogui_gamepad_state[14] = {0};
|
||||
GamepadFrontend* m_frontend;
|
||||
};
|
||||
|
|
30
src/controls/GamepadFrontend.hpp
Normal file
30
src/controls/GamepadFrontend.hpp
Normal file
|
@ -0,0 +1,30 @@
|
|||
#pragma once
|
||||
|
||||
// Moonlight ready gamepad
|
||||
struct GamepadState {
|
||||
short buttonFlags;
|
||||
unsigned char leftTrigger;
|
||||
unsigned char rightTrigger;
|
||||
short leftStickX;
|
||||
short leftStickY;
|
||||
short rightStickX;
|
||||
short rightStickY;
|
||||
|
||||
bool is_equal(GamepadState other) {
|
||||
return buttonFlags == other.buttonFlags &&
|
||||
leftTrigger == other.leftTrigger &&
|
||||
rightTrigger == other.rightTrigger &&
|
||||
leftStickX == other.leftStickX &&
|
||||
leftStickY == other.leftStickY &&
|
||||
rightStickX == other.rightStickX &&
|
||||
rightStickY == other.rightStickY;
|
||||
}
|
||||
};
|
||||
|
||||
class GamepadFrontend {
|
||||
public:
|
||||
virtual void handle_gamepad() = 0;
|
||||
virtual void handle_rumple(unsigned short controller, unsigned short low_freq_motor, unsigned short high_freq_motor) = 0;
|
||||
virtual void stop_rumple() = 0;
|
||||
virtual GamepadState gamepad_state() const = 0;
|
||||
};
|
202
src/controls/GamepadFrontendSwitch.cpp
Normal file
202
src/controls/GamepadFrontendSwitch.cpp
Normal file
|
@ -0,0 +1,202 @@
|
|||
#include "GamepadFrontendSwitch.hpp"
|
||||
#include "Limelight.h"
|
||||
#include <nanogui/opengl.h>
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
static inline bool pad_is_equal(PadState& state, PadState& other) {
|
||||
return padGetButtons(&state) == padGetButtons(&other) &&
|
||||
padGetStickPos(&state, 0).x == padGetStickPos(&other, 0).x &&
|
||||
padGetStickPos(&state, 0).y == padGetStickPos(&other, 0).y &&
|
||||
padGetStickPos(&state, 1).x == padGetStickPos(&other, 1).x &&
|
||||
padGetStickPos(&state, 1).y == padGetStickPos(&other, 1).y;
|
||||
}
|
||||
|
||||
static inline int pad_button_number(HidNpadButton button) {
|
||||
static std::map<HidNpadButton, int> map = {
|
||||
{ HidNpadButton_A, 0 },
|
||||
{ HidNpadButton_B, 1 },
|
||||
{ HidNpadButton_X, 2 },
|
||||
{ HidNpadButton_Y, 3 },
|
||||
{ HidNpadButton_StickL, 4 },
|
||||
{ HidNpadButton_StickR, 5 },
|
||||
{ HidNpadButton_L, 6 },
|
||||
{ HidNpadButton_R, 7 },
|
||||
{ HidNpadButton_ZL, 8 },
|
||||
{ HidNpadButton_ZR, 9 },
|
||||
{ HidNpadButton_Plus, 10 },
|
||||
{ HidNpadButton_Minus, 11 },
|
||||
{ HidNpadButton_Left, 12 },
|
||||
{ HidNpadButton_Up, 13 },
|
||||
{ HidNpadButton_Right, 14 },
|
||||
{ HidNpadButton_Down, 15 }
|
||||
};
|
||||
return map[button];
|
||||
}
|
||||
|
||||
static inline int pad_button_to_moonlight_button(int button) {
|
||||
static std::map<int, int> map = {
|
||||
{ pad_button_number(HidNpadButton_A), A_FLAG },
|
||||
{ pad_button_number(HidNpadButton_B), B_FLAG },
|
||||
{ pad_button_number(HidNpadButton_X), X_FLAG },
|
||||
{ pad_button_number(HidNpadButton_Y), Y_FLAG },
|
||||
{ pad_button_number(HidNpadButton_StickL), LS_CLK_FLAG },
|
||||
{ pad_button_number(HidNpadButton_StickR), RS_CLK_FLAG },
|
||||
{ pad_button_number(HidNpadButton_L), LB_FLAG },
|
||||
{ pad_button_number(HidNpadButton_R), RB_FLAG },
|
||||
{ pad_button_number(HidNpadButton_Plus), PLAY_FLAG },
|
||||
{ pad_button_number(HidNpadButton_Minus), BACK_FLAG },
|
||||
{ pad_button_number(HidNpadButton_Up), UP_FLAG },
|
||||
{ pad_button_number(HidNpadButton_Down), DOWN_FLAG },
|
||||
{ pad_button_number(HidNpadButton_Left), LEFT_FLAG },
|
||||
{ pad_button_number(HidNpadButton_Right), RIGHT_FLAG }
|
||||
};
|
||||
return map[button];
|
||||
}
|
||||
|
||||
static inline void padUpdateOverKeyboard(PadState* pad) {
|
||||
static int glfw_keyboard_state[GLFW_KEY_LAST] = {0};
|
||||
|
||||
static std::map<int, HidNpadButton> keyboard_map = {
|
||||
{ GLFW_KEY_UP, HidNpadButton_Up },
|
||||
{ GLFW_KEY_DOWN, HidNpadButton_Down },
|
||||
{ GLFW_KEY_LEFT, HidNpadButton_Left },
|
||||
{ GLFW_KEY_RIGHT, HidNpadButton_Right },
|
||||
{ GLFW_KEY_A, HidNpadButton_A },
|
||||
{ GLFW_KEY_B, HidNpadButton_B },
|
||||
{ GLFW_KEY_X, HidNpadButton_X },
|
||||
{ GLFW_KEY_Y, HidNpadButton_Y },
|
||||
{ GLFW_KEY_Q, HidNpadButton_L },
|
||||
{ GLFW_KEY_E, HidNpadButton_R },
|
||||
{ GLFW_KEY_Z, HidNpadButton_ZL },
|
||||
{ GLFW_KEY_C, HidNpadButton_ZR },
|
||||
{ GLFW_KEY_MINUS, HidNpadButton_Minus },
|
||||
{ GLFW_KEY_EQUAL, HidNpadButton_Plus },
|
||||
{ GLFW_KEY_N, HidNpadButton_StickL },
|
||||
{ GLFW_KEY_M, HidNpadButton_StickR }
|
||||
};
|
||||
|
||||
static std::map<int, std::vector<int>> axis_map = {
|
||||
{ GLFW_KEY_T, { 0, 1, 1 } },
|
||||
{ GLFW_KEY_G, { 0, 1, -1 } },
|
||||
{ GLFW_KEY_F, { 0, 0, -1 } },
|
||||
{ GLFW_KEY_H, { 0, 0, 1 } },
|
||||
{ GLFW_KEY_I, { 1, 1, 1 } },
|
||||
{ GLFW_KEY_K, { 1, 1, -1 } },
|
||||
{ GLFW_KEY_J, { 1, 0, -1 } },
|
||||
{ GLFW_KEY_L, { 1, 0, 1 } }
|
||||
};
|
||||
|
||||
for (auto &pair: keyboard_map) {
|
||||
int is_pressed = glfwGetKey(glfwGetCurrentContext(), pair.first);
|
||||
|
||||
if (glfw_keyboard_state[pair.first] != is_pressed) {
|
||||
glfw_keyboard_state[pair.first] = is_pressed;
|
||||
|
||||
if (is_pressed) {
|
||||
pad->buttons_cur |= pair.second;
|
||||
} else {
|
||||
pad->buttons_cur &= ~pair.second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &pair: axis_map) {
|
||||
int is_pressed = glfwGetKey(glfwGetCurrentContext(), pair.first);
|
||||
|
||||
if (glfw_keyboard_state[pair.first] != is_pressed) {
|
||||
glfw_keyboard_state[pair.first] = is_pressed;
|
||||
|
||||
if (pair.second[1] == 0) {
|
||||
pad->sticks[pair.second[0]].x = is_pressed ? pair.second[2] * 0x7FFF : 0;
|
||||
} else {
|
||||
pad->sticks[pair.second[0]].y = is_pressed ? pair.second[2] * 0x7FFF : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GamepadFrontendSwitch::GamepadFrontendSwitch() {
|
||||
padConfigureInput(1, HidNpadStyleSet_NpadStandard);
|
||||
padInitializeDefault(&m_pad_state);
|
||||
|
||||
hidInitializeVibrationDevices(m_vibration_device_handles[0], 2, HidNpadIdType_Handheld, HidNpadStyleTag_NpadHandheld);
|
||||
hidInitializeVibrationDevices(m_vibration_device_handles[1], 2, HidNpadIdType_No1, HidNpadStyleTag_NpadJoyDual);
|
||||
}
|
||||
|
||||
void GamepadFrontendSwitch::handle_gamepad() {
|
||||
PadState state = m_pad_state;
|
||||
|
||||
#ifdef __SWITCH__
|
||||
padUpdate(&state);
|
||||
#else
|
||||
padUpdateOverKeyboard(&state);
|
||||
#endif
|
||||
|
||||
if (set_new_pad_state(state)) {
|
||||
u64 buttons = padGetButtons(&m_pad_state);
|
||||
|
||||
for (int i = 0; i < 28; i++) {
|
||||
bool is_pressed = buttons & BIT(i);
|
||||
|
||||
if (is_pressed) {
|
||||
m_gamepad_state.buttonFlags |= pad_button_to_moonlight_button(i);
|
||||
} else {
|
||||
m_gamepad_state.buttonFlags &= ~pad_button_to_moonlight_button(i);
|
||||
}
|
||||
}
|
||||
|
||||
m_gamepad_state.leftTrigger = (buttons & HidNpadButton_ZL) ? 0xFF : 0;
|
||||
m_gamepad_state.rightTrigger = (buttons & HidNpadButton_ZR) ? 0xFF : 0;
|
||||
m_gamepad_state.leftStickX = m_pad_state.sticks[0].x;
|
||||
m_gamepad_state.leftStickY = m_pad_state.sticks[0].y;
|
||||
m_gamepad_state.rightStickX = m_pad_state.sticks[1].x;
|
||||
m_gamepad_state.rightStickY = m_pad_state.sticks[1].y;
|
||||
}
|
||||
}
|
||||
|
||||
void GamepadFrontendSwitch::handle_rumple(unsigned short controller, unsigned short low_freq_motor, unsigned short high_freq_motor) {
|
||||
if (controller == 0) {
|
||||
float low = (float)low_freq_motor / 0xFFFF;
|
||||
float high = (float)high_freq_motor / 0xFFFF;
|
||||
|
||||
memset(m_vibration_values, 0, sizeof(m_vibration_values));
|
||||
|
||||
m_vibration_values[0].amp_low = low;
|
||||
m_vibration_values[0].freq_low = low * 50;
|
||||
m_vibration_values[0].amp_high = high;
|
||||
m_vibration_values[0].freq_high = high * 100;
|
||||
|
||||
m_vibration_values[1].amp_low = low;
|
||||
m_vibration_values[1].freq_low = low * 50;
|
||||
m_vibration_values[1].amp_high = high;
|
||||
m_vibration_values[1].freq_high = high * 100;
|
||||
|
||||
int target_device = padIsHandheld(&m_pad_state) ? 0 : 1;
|
||||
hidSendVibrationValues(m_vibration_device_handles[target_device], m_vibration_values, 2);
|
||||
}
|
||||
}
|
||||
|
||||
void GamepadFrontendSwitch::stop_rumple() {
|
||||
HidVibrationValue stop;
|
||||
memset(&stop, 0, sizeof(HidVibrationValue));
|
||||
|
||||
stop.freq_low = 160.0f;
|
||||
stop.freq_high = 320.0f;
|
||||
|
||||
memcpy(&m_vibration_values[0], &stop, sizeof(HidVibrationValue));
|
||||
memcpy(&m_vibration_values[1], &stop, sizeof(HidVibrationValue));
|
||||
|
||||
int target_device = padIsHandheld(&m_pad_state) ? 0 : 1;
|
||||
hidSendVibrationValues(m_vibration_device_handles[target_device], m_vibration_values, 2);
|
||||
hidSendVibrationValues(m_vibration_device_handles[1 - target_device], m_vibration_values, 2);
|
||||
}
|
||||
|
||||
bool GamepadFrontendSwitch::set_new_pad_state(PadState& state) {
|
||||
if (!pad_is_equal(m_pad_state, state)) {
|
||||
m_pad_state = state;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
26
src/controls/GamepadFrontendSwitch.hpp
Normal file
26
src/controls/GamepadFrontendSwitch.hpp
Normal file
|
@ -0,0 +1,26 @@
|
|||
#include "GamepadFrontend.hpp"
|
||||
#include <switch.h>
|
||||
#pragma once
|
||||
|
||||
class GamepadFrontendSwitch: public GamepadFrontend {
|
||||
public:
|
||||
GamepadFrontendSwitch();
|
||||
|
||||
void handle_gamepad();
|
||||
|
||||
void handle_rumple(unsigned short controller, unsigned short low_freq_motor, unsigned short high_freq_motor);
|
||||
void stop_rumple();
|
||||
|
||||
GamepadState gamepad_state() const {
|
||||
return m_gamepad_state;
|
||||
}
|
||||
|
||||
private:
|
||||
PadState m_pad_state = {0};
|
||||
GamepadState m_gamepad_state = {0};
|
||||
|
||||
HidVibrationDeviceHandle m_vibration_device_handles[2][2];
|
||||
HidVibrationValue m_vibration_values[2];
|
||||
|
||||
bool set_new_pad_state(PadState& state);
|
||||
};
|
|
@ -3,84 +3,36 @@
|
|||
#include <nanogui/opengl.h>
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
void MouseController::init(GLFWwindow* window) {
|
||||
hidInitializeMouse();
|
||||
hidInitializeTouchScreen();
|
||||
|
||||
glfwSetCursorPosCallback(window, [](auto _, double x, double y) {
|
||||
MouseController::instance().handle_mouse_move(x, y);
|
||||
});
|
||||
|
||||
glfwSetMouseButtonCallback(window, [](auto _, int button, int action, int modifiers) {
|
||||
MouseController::instance().handle_mouse_buttons(button, action, modifiers);
|
||||
});
|
||||
|
||||
glfwSetScrollCallback(window, [](auto _, double x, double y) {
|
||||
MouseController::instance().handle_mouse_scroll(x, y);
|
||||
});
|
||||
void MouseController::init(MouseFrontend* frontend) {
|
||||
m_frontend = frontend;
|
||||
}
|
||||
|
||||
void MouseController::handle_mouse() {
|
||||
HidMouseState hid_mouse_state;
|
||||
m_frontend->handle_mouse();
|
||||
|
||||
if (hidGetMouseStates(&hid_mouse_state, 1) && (hid_mouse_state.attributes & HidMouseAttribute_IsConnected)) {
|
||||
if (m_hid_mouse_state.x != hid_mouse_state.x || m_hid_mouse_state.y != hid_mouse_state.y || m_hid_mouse_state.buttons != hid_mouse_state.buttons || m_hid_mouse_state.wheel_delta_x != hid_mouse_state.wheel_delta_x) {
|
||||
m_hid_mouse_is_used = true;
|
||||
m_hid_mouse_state = hid_mouse_state;
|
||||
|
||||
MouseState state;
|
||||
state.x = hid_mouse_state.x;
|
||||
state.y = hid_mouse_state.y;
|
||||
state.l_pressed = hid_mouse_state.buttons & HidMouseButton_Left;
|
||||
state.m_pressed = hid_mouse_state.buttons & HidMouseButton_Middle;
|
||||
state.r_pressed = hid_mouse_state.buttons & HidMouseButton_Right;
|
||||
state.scroll_y = (double)hid_mouse_state.wheel_delta_x / 100; // Why wheel_delta_x?
|
||||
|
||||
if (m_mouse_state.x != state.x || m_mouse_state.y != state.y) {
|
||||
nanogui::cursor_pos_callback_event((double)state.x, (double)state.y);
|
||||
}
|
||||
|
||||
if (m_mouse_state.l_pressed != state.l_pressed) {
|
||||
nanogui::mouse_button_callback_event(NANOGUI_MOUSE_BUTTON_1, state.l_pressed ? NANOGUI_PRESS : NANOGUI_RELEASE, 0);
|
||||
}
|
||||
|
||||
if (m_mouse_state.r_pressed != state.r_pressed) {
|
||||
nanogui::mouse_button_callback_event(NANOGUI_MOUSE_BUTTON_2, state.r_pressed ? NANOGUI_PRESS : NANOGUI_RELEASE, 0);
|
||||
}
|
||||
|
||||
if (m_mouse_state.scroll_y != state.scroll_y) {
|
||||
nanogui::scroll_callback_event(0, state.scroll_y);
|
||||
}
|
||||
|
||||
set_new_mouse_state(state);
|
||||
}
|
||||
} else {
|
||||
m_hid_mouse_is_used = false;
|
||||
auto state = m_frontend->mouse_state();
|
||||
|
||||
if (m_mouse_state.x != state.x || m_mouse_state.y != state.y) {
|
||||
nanogui::cursor_pos_callback_event((double)state.x, (double)state.y);
|
||||
}
|
||||
|
||||
// Simulate mouse wheel with two finger movements...
|
||||
HidTouchScreenState hid_touch_screen_state;
|
||||
if (hidGetTouchScreenStates(&hid_touch_screen_state, 1) && hid_touch_screen_state.count == 2) {
|
||||
double y = (hid_touch_screen_state.touches[0].y + hid_touch_screen_state.touches[1].y) / 2;
|
||||
|
||||
if (m_last_touch_y != 0 && m_last_touch_y != y) {
|
||||
auto state = m_mouse_state;
|
||||
state.scroll_y = (m_last_touch_y - y) / 10;
|
||||
|
||||
if (set_new_mouse_state(state)) {
|
||||
// Invert scroll_y for make scroll like on an iOS/Android :C
|
||||
nanogui::scroll_callback_event(0, -state.scroll_y);
|
||||
}
|
||||
}
|
||||
|
||||
m_last_touch_y = y;
|
||||
} else {
|
||||
m_last_touch_y = 0;
|
||||
if (m_mouse_state.l_pressed != state.l_pressed) {
|
||||
nanogui::mouse_button_callback_event(NANOGUI_MOUSE_BUTTON_1, state.l_pressed ? NANOGUI_PRESS : NANOGUI_RELEASE, 0);
|
||||
}
|
||||
|
||||
if (m_mouse_state.r_pressed != state.r_pressed) {
|
||||
nanogui::mouse_button_callback_event(NANOGUI_MOUSE_BUTTON_2, state.r_pressed ? NANOGUI_PRESS : NANOGUI_RELEASE, 0);
|
||||
}
|
||||
|
||||
if (m_mouse_state.scroll_y != state.scroll_y) {
|
||||
nanogui::scroll_callback_event(0, state.scroll_y);
|
||||
}
|
||||
|
||||
m_mouse_state = state;
|
||||
}
|
||||
|
||||
void MouseController::draw_cursor(Application *app) {
|
||||
if (m_hid_mouse_is_used && m_draw_cursor_for_hid_mouse) {
|
||||
if (m_frontend->hid_mouse_is_used() && m_draw_cursor_for_hid_mouse) {
|
||||
auto ctx = app->nvg_context();
|
||||
nvgSave(ctx);
|
||||
nvgReset(ctx);
|
||||
|
@ -96,50 +48,3 @@ void MouseController::draw_cursor(Application *app) {
|
|||
app->nvg_flush();
|
||||
}
|
||||
}
|
||||
|
||||
void MouseController::handle_mouse_move(double x, double y) {
|
||||
m_hid_mouse_is_used = false;
|
||||
|
||||
auto state = m_mouse_state;
|
||||
state.x = (int)x;
|
||||
state.y = (int)y;
|
||||
|
||||
if (set_new_mouse_state(state)) {
|
||||
nanogui::cursor_pos_callback_event(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
void MouseController::handle_mouse_buttons(int button, int action, int modifiers) {
|
||||
m_hid_mouse_is_used = false;
|
||||
|
||||
auto state = m_mouse_state;
|
||||
|
||||
if (button == NANOGUI_MOUSE_BUTTON_1) {
|
||||
state.l_pressed = action == NANOGUI_PRESS;
|
||||
} else if (button == NANOGUI_MOUSE_BUTTON_2) {
|
||||
state.r_pressed = action == NANOGUI_PRESS;
|
||||
}
|
||||
|
||||
if (set_new_mouse_state(state)) {
|
||||
nanogui::mouse_button_callback_event(button, action, modifiers);
|
||||
}
|
||||
}
|
||||
|
||||
void MouseController::handle_mouse_scroll(int x, int y) {
|
||||
m_hid_mouse_is_used = false;
|
||||
|
||||
auto state = m_mouse_state;
|
||||
state.scroll_y = y;
|
||||
|
||||
if (set_new_mouse_state(state)) {
|
||||
nanogui::scroll_callback_event(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
bool MouseController::set_new_mouse_state(MouseState& state) {
|
||||
if (!m_mouse_state.is_equal(state)) {
|
||||
m_mouse_state = state;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -1,28 +1,12 @@
|
|||
#include "Singleton.hpp"
|
||||
#include <switch.h>
|
||||
#include "MouseFrontend.hpp"
|
||||
#pragma once
|
||||
|
||||
class Application;
|
||||
struct GLFWwindow;
|
||||
|
||||
struct MouseState {
|
||||
int x;
|
||||
int y;
|
||||
double scroll_y;
|
||||
bool l_pressed;
|
||||
bool m_pressed;
|
||||
bool r_pressed;
|
||||
|
||||
bool is_equal(MouseState& other) {
|
||||
return x == other.x && y == other.y && scroll_y == other.scroll_y &&
|
||||
l_pressed == other.l_pressed && m_pressed == other.m_pressed &&
|
||||
r_pressed == other.r_pressed;
|
||||
}
|
||||
};
|
||||
|
||||
class MouseController: public Singleton<MouseController> {
|
||||
public:
|
||||
void init(GLFWwindow* window);
|
||||
void init(MouseFrontend* frontend);
|
||||
void handle_mouse();
|
||||
void draw_cursor(Application* app);
|
||||
|
||||
|
@ -31,7 +15,7 @@ public:
|
|||
}
|
||||
|
||||
bool hid_mouse_is_used() const {
|
||||
return m_hid_mouse_is_used;
|
||||
return m_frontend->hid_mouse_is_used();
|
||||
}
|
||||
|
||||
void set_draw_cursor_for_hid_mouse(bool draw_cursor_for_hid_mouse) {
|
||||
|
@ -40,13 +24,7 @@ public:
|
|||
|
||||
private:
|
||||
MouseState m_mouse_state = {0};
|
||||
HidMouseState m_hid_mouse_state = {0};
|
||||
bool m_hid_mouse_is_used = false;
|
||||
bool m_draw_cursor_for_hid_mouse = true;
|
||||
double m_last_touch_y = 0;
|
||||
MouseFrontend* m_frontend;
|
||||
|
||||
void handle_mouse_move(double x, double y);
|
||||
void handle_mouse_buttons(int button, int action, int modifiers);
|
||||
void handle_mouse_scroll(int x, int y);
|
||||
bool set_new_mouse_state(MouseState& state);
|
||||
bool m_draw_cursor_for_hid_mouse = true;
|
||||
};
|
||||
|
|
17
src/controls/MouseFrontend.hpp
Normal file
17
src/controls/MouseFrontend.hpp
Normal file
|
@ -0,0 +1,17 @@
|
|||
#pragma once
|
||||
|
||||
struct MouseState {
|
||||
int x;
|
||||
int y;
|
||||
double scroll_y;
|
||||
bool l_pressed;
|
||||
bool m_pressed;
|
||||
bool r_pressed;
|
||||
};
|
||||
|
||||
class MouseFrontend {
|
||||
public:
|
||||
virtual void handle_mouse() = 0;
|
||||
virtual MouseState mouse_state() const = 0;
|
||||
virtual bool hid_mouse_is_used() const = 0;
|
||||
};
|
81
src/controls/MouseFrontendSwitch.cpp
Normal file
81
src/controls/MouseFrontendSwitch.cpp
Normal file
|
@ -0,0 +1,81 @@
|
|||
#include "MouseFrontendSwitch.hpp"
|
||||
#include <nanogui/opengl.h>
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
static MouseFrontendSwitch* m_frontend = NULL;
|
||||
|
||||
MouseFrontendSwitch::MouseFrontendSwitch(GLFWwindow* window) {
|
||||
m_frontend = this;
|
||||
|
||||
hidInitializeMouse();
|
||||
hidInitializeTouchScreen();
|
||||
|
||||
glfwSetCursorPosCallback(window, [](auto _, double x, double y) {
|
||||
m_frontend->handle_mouse_move(x, y);
|
||||
});
|
||||
|
||||
glfwSetMouseButtonCallback(window, [](auto _, int button, int action, int modifiers) {
|
||||
m_frontend->handle_mouse_buttons(button, action, modifiers);
|
||||
});
|
||||
|
||||
glfwSetScrollCallback(window, [](auto _, double x, double y) {
|
||||
m_frontend->handle_mouse_scroll(x, y);
|
||||
});
|
||||
}
|
||||
|
||||
void MouseFrontendSwitch::handle_mouse() {
|
||||
HidMouseState hid_mouse_state;
|
||||
|
||||
if (hidGetMouseStates(&hid_mouse_state, 1) && (hid_mouse_state.attributes & HidMouseAttribute_IsConnected)) {
|
||||
if (m_hid_mouse_state.x != hid_mouse_state.x || m_hid_mouse_state.y != hid_mouse_state.y || m_hid_mouse_state.buttons != hid_mouse_state.buttons || m_hid_mouse_state.wheel_delta_x != hid_mouse_state.wheel_delta_x) {
|
||||
m_hid_mouse_is_used = true;
|
||||
m_hid_mouse_state = hid_mouse_state;
|
||||
|
||||
m_mouse_state.x = hid_mouse_state.x;
|
||||
m_mouse_state.y = hid_mouse_state.y;
|
||||
m_mouse_state.l_pressed = hid_mouse_state.buttons & HidMouseButton_Left;
|
||||
m_mouse_state.m_pressed = hid_mouse_state.buttons & HidMouseButton_Middle;
|
||||
m_mouse_state.r_pressed = hid_mouse_state.buttons & HidMouseButton_Right;
|
||||
m_mouse_state.scroll_y = (double)hid_mouse_state.wheel_delta_x / 100; // Why wheel_delta_x?
|
||||
}
|
||||
} else {
|
||||
m_hid_mouse_is_used = false;
|
||||
}
|
||||
|
||||
// Simulate mouse wheel with two finger movements...
|
||||
HidTouchScreenState hid_touch_screen_state;
|
||||
if (hidGetTouchScreenStates(&hid_touch_screen_state, 1) && hid_touch_screen_state.count == 2) {
|
||||
double y = (hid_touch_screen_state.touches[0].y + hid_touch_screen_state.touches[1].y) / 2;
|
||||
|
||||
if (m_last_touch_y != 0 && m_last_touch_y != y) {
|
||||
m_mouse_state.scroll_y = (m_last_touch_y - y) / 10;
|
||||
}
|
||||
|
||||
m_last_touch_y = y;
|
||||
} else {
|
||||
m_last_touch_y = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void MouseFrontendSwitch::handle_mouse_move(double x, double y) {
|
||||
m_hid_mouse_is_used = false;
|
||||
|
||||
m_mouse_state.x = (int)x;
|
||||
m_mouse_state.y = (int)y;
|
||||
}
|
||||
|
||||
void MouseFrontendSwitch::handle_mouse_buttons(int button, int action, int modifiers) {
|
||||
m_hid_mouse_is_used = false;
|
||||
|
||||
if (button == NANOGUI_MOUSE_BUTTON_1) {
|
||||
m_mouse_state.l_pressed = action == NANOGUI_PRESS;
|
||||
} else if (button == NANOGUI_MOUSE_BUTTON_2) {
|
||||
m_mouse_state.r_pressed = action == NANOGUI_PRESS;
|
||||
}
|
||||
}
|
||||
|
||||
void MouseFrontendSwitch::handle_mouse_scroll(int x, int y) {
|
||||
m_hid_mouse_is_used = false;
|
||||
|
||||
m_mouse_state.scroll_y = y;
|
||||
}
|
31
src/controls/MouseFrontendSwitch.hpp
Normal file
31
src/controls/MouseFrontendSwitch.hpp
Normal file
|
@ -0,0 +1,31 @@
|
|||
#include "MouseFrontend.hpp"
|
||||
#include <switch.h>
|
||||
#pragma once
|
||||
|
||||
struct GLFWwindow;
|
||||
|
||||
class MouseFrontendSwitch: public MouseFrontend {
|
||||
public:
|
||||
MouseFrontendSwitch(GLFWwindow* window);
|
||||
|
||||
void handle_mouse();
|
||||
|
||||
MouseState mouse_state() const {
|
||||
return m_mouse_state;
|
||||
}
|
||||
|
||||
bool hid_mouse_is_used() const {
|
||||
return m_hid_mouse_is_used;
|
||||
}
|
||||
|
||||
private:
|
||||
MouseState m_mouse_state = {0};
|
||||
HidMouseState m_hid_mouse_state = {0};
|
||||
bool m_hid_mouse_is_used = false;
|
||||
bool m_draw_cursor_for_hid_mouse = true;
|
||||
double m_last_touch_y = 0;
|
||||
|
||||
void handle_mouse_move(double x, double y);
|
||||
void handle_mouse_buttons(int button, int action, int modifiers);
|
||||
void handle_mouse_scroll(int x, int y);
|
||||
};
|
|
@ -6,8 +6,10 @@
|
|||
#include "GameStreamClient.hpp"
|
||||
#include "Logger.hpp"
|
||||
#include "MouseController.hpp"
|
||||
#include "MouseFrontendSwitch.hpp"
|
||||
#include "KeyboardController.hpp"
|
||||
#include "GamepadController.hpp"
|
||||
#include "GamepadFrontendSwitch.hpp"
|
||||
#include <glad/glad.h>
|
||||
#include <switch.h>
|
||||
#include <GLFW/glfw3.h>
|
||||
|
@ -63,9 +65,9 @@ int main(int argc, const char * argv[]) {
|
|||
|
||||
GameStreamClient::instance().start();
|
||||
|
||||
MouseController::instance().init(window);
|
||||
MouseController::instance().init(new MouseFrontendSwitch(window));
|
||||
KeyboardController::instance().init(window);
|
||||
GamepadController::instance().init();
|
||||
GamepadController::instance().init(new GamepadFrontendSwitch());
|
||||
|
||||
nanogui::init();
|
||||
nanogui::ref<Application> app = new Application(Size(m_width, m_height), Size(m_fb_width, m_fb_height));
|
||||
|
|
Loading…
Reference in a new issue