mirror of
https://github.com/rock88/moonlight-nx
synced 2024-11-10 06:14:15 +00:00
Implement button/combo remapping...
This commit is contained in:
parent
ba1e479b4e
commit
b0badb2169
13 changed files with 702 additions and 132 deletions
|
@ -85,6 +85,7 @@
|
|||
3678EF732476D9DA0097345D /* DebugFileRecorderAudioRenderer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3678EF712476D9DA0097345D /* DebugFileRecorderAudioRenderer.cpp */; };
|
||||
367CD95A245DE25F00A95738 /* StreamWindow.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 367CD958245DE25F00A95738 /* StreamWindow.cpp */; };
|
||||
367D2D7424829A0800A946F4 /* LogsWindow.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 367D2D7224829A0800A946F4 /* LogsWindow.cpp */; };
|
||||
3689D6DD249154F90008CB75 /* GamepadMapper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 3689D6DB249154F90008CB75 /* GamepadMapper.cpp */; };
|
||||
36A0C0372461DBA30083289C /* AddHostButton.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 36A0C0352461DBA30083289C /* AddHostButton.cpp */; };
|
||||
36A0C03A2461E4C00083289C /* SettingsWindow.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 36A0C0382461E4C00083289C /* SettingsWindow.cpp */; };
|
||||
36A0C03D2461F03C0083289C /* Settings.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 36A0C03B2461F03C0083289C /* Settings.cpp */; };
|
||||
|
@ -98,6 +99,7 @@
|
|||
36DBDE9C2450BCD90057C8D3 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 36DBDE9B2450BCD90057C8D3 /* CoreGraphics.framework */; };
|
||||
36DBDE9E2450BCF00057C8D3 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 36DBDE9D2450BCF00057C8D3 /* IOKit.framework */; };
|
||||
36DBDEA02450BCF80057C8D3 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 36DBDE9F2450BCF70057C8D3 /* AppKit.framework */; };
|
||||
36DDACF824929919001133D1 /* InputSettingsWindow.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 36DDACF624929919001133D1 /* InputSettingsWindow.cpp */; };
|
||||
36DFE0CD2459FA3F00FC51CE /* nanogui_resources.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 36DFE0CB2459FA3F00FC51CE /* nanogui_resources.cpp */; };
|
||||
36DFE0CE2459FAB100FC51CE /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 36DBDEA22450C2640057C8D3 /* OpenGL.framework */; };
|
||||
36E63790247010C70032F5FB /* Data.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 36E6378E247010C70032F5FB /* Data.cpp */; };
|
||||
|
@ -284,6 +286,8 @@
|
|||
367D2D7224829A0800A946F4 /* LogsWindow.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = LogsWindow.cpp; sourceTree = "<group>"; };
|
||||
367D2D7324829A0800A946F4 /* LogsWindow.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = LogsWindow.hpp; sourceTree = "<group>"; };
|
||||
3689D6D0248EBEFA0008CB75 /* build.yml */ = {isa = PBXFileReference; lastKnownFileType = text.yaml; name = build.yml; path = .github/workflows/build.yml; sourceTree = "<group>"; };
|
||||
3689D6DB249154F90008CB75 /* GamepadMapper.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = GamepadMapper.cpp; sourceTree = "<group>"; };
|
||||
3689D6DC249154F90008CB75 /* GamepadMapper.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = GamepadMapper.hpp; sourceTree = "<group>"; };
|
||||
36A0C0352461DBA30083289C /* AddHostButton.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = AddHostButton.cpp; sourceTree = "<group>"; };
|
||||
36A0C0362461DBA30083289C /* AddHostButton.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = AddHostButton.hpp; sourceTree = "<group>"; };
|
||||
36A0C0382461E4C00083289C /* SettingsWindow.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = SettingsWindow.cpp; sourceTree = "<group>"; };
|
||||
|
@ -310,6 +314,8 @@
|
|||
36DBDE9F2450BCF70057C8D3 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; };
|
||||
36DBDEA22450C2640057C8D3 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; };
|
||||
36DBDEA42450C2850057C8D3 /* Metal.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Metal.framework; path = System/Library/Frameworks/Metal.framework; sourceTree = SDKROOT; };
|
||||
36DDACF624929919001133D1 /* InputSettingsWindow.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = InputSettingsWindow.cpp; sourceTree = "<group>"; };
|
||||
36DDACF724929919001133D1 /* InputSettingsWindow.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = InputSettingsWindow.hpp; sourceTree = "<group>"; };
|
||||
36DFDCF22459F7A200FC51CE /* Application.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Application.cpp; sourceTree = "<group>"; };
|
||||
36DFDCF32459F7A200FC51CE /* Application.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Application.hpp; sourceTree = "<group>"; };
|
||||
36DFE0CB2459FA3F00FC51CE /* nanogui_resources.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = nanogui_resources.cpp; sourceTree = "<group>"; };
|
||||
|
@ -369,6 +375,8 @@
|
|||
367CD959245DE25F00A95738 /* StreamWindow.hpp */,
|
||||
36A0C0382461E4C00083289C /* SettingsWindow.cpp */,
|
||||
36A0C0392461E4C00083289C /* SettingsWindow.hpp */,
|
||||
36DDACF624929919001133D1 /* InputSettingsWindow.cpp */,
|
||||
36DDACF724929919001133D1 /* InputSettingsWindow.hpp */,
|
||||
367D2D7224829A0800A946F4 /* LogsWindow.cpp */,
|
||||
367D2D7324829A0800A946F4 /* LogsWindow.hpp */,
|
||||
);
|
||||
|
@ -631,6 +639,8 @@
|
|||
36A0C03C2461F03C0083289C /* Settings.hpp */,
|
||||
3603E93A246316400051287D /* InputController.cpp */,
|
||||
3603E93B246316400051287D /* InputController.hpp */,
|
||||
3689D6DB249154F90008CB75 /* GamepadMapper.cpp */,
|
||||
3689D6DC249154F90008CB75 /* GamepadMapper.hpp */,
|
||||
3658241124819E56008B8758 /* Logger.cpp */,
|
||||
3658241224819E56008B8758 /* Logger.hpp */,
|
||||
36BFCCF72479725900245D40 /* main.cpp */,
|
||||
|
@ -872,6 +882,7 @@
|
|||
36BFCCF12479723E00245D40 /* xml.cpp in Sources */,
|
||||
3652F065245C292B001FABF3 /* list.c in Sources */,
|
||||
36DFE0CD2459FA3F00FC51CE /* nanogui_resources.cpp in Sources */,
|
||||
36DDACF824929919001133D1 /* InputSettingsWindow.cpp in Sources */,
|
||||
3652F06A245C292B001FABF3 /* protocol.c in Sources */,
|
||||
3652EFFC245B6434001FABF3 /* MainWindow.cpp in Sources */,
|
||||
3652EFD3245B3B00001FABF3 /* button.cpp in Sources */,
|
||||
|
@ -883,6 +894,7 @@
|
|||
36A0C0372461DBA30083289C /* AddHostButton.cpp in Sources */,
|
||||
3652F06E245C292B001FABF3 /* rs.c in Sources */,
|
||||
3652EFD1245B3B00001FABF3 /* colorpicker.cpp in Sources */,
|
||||
3689D6DD249154F90008CB75 /* GamepadMapper.cpp in Sources */,
|
||||
3652F066245C292B001FABF3 /* compress.c in Sources */,
|
||||
3652F07D245C292B001FABF3 /* Misc.c in Sources */,
|
||||
3652F070245C292B001FABF3 /* SimpleStun.c in Sources */,
|
||||
|
|
191
src/GamepadMapper.cpp
Normal file
191
src/GamepadMapper.cpp
Normal file
|
@ -0,0 +1,191 @@
|
|||
#include "GamepadMapper.hpp"
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <nanogui/opengl.h>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
static int gamepad_button_to_nanogui_button(GamepadButtons button) {
|
||||
switch (button) {
|
||||
case GamepadButtonA: return NANOGUI_GAMEPAD_BUTTON_A;
|
||||
case GamepadButtonB: return NANOGUI_GAMEPAD_BUTTON_B;
|
||||
case GamepadButtonX: return NANOGUI_GAMEPAD_BUTTON_X;
|
||||
case GamepadButtonY: return NANOGUI_GAMEPAD_BUTTON_Y;
|
||||
case GamepadButtonUp: return NANOGUI_GAMEPAD_BUTTON_DPAD_UP;
|
||||
case GamepadButtonDown: return NANOGUI_GAMEPAD_BUTTON_DPAD_DOWN;
|
||||
case GamepadButtonLeft: return NANOGUI_GAMEPAD_BUTTON_DPAD_LEFT;
|
||||
case GamepadButtonRight: return NANOGUI_GAMEPAD_BUTTON_DPAD_RIGHT;
|
||||
case GamepadButtonPlus: return NANOGUI_GAMEPAD_BUTTON_START;
|
||||
case GamepadButtonMinus: return NANOGUI_GAMEPAD_BUTTON_BACK;
|
||||
case GamepadButtonLeftThumb: return NANOGUI_GAMEPAD_BUTTON_LEFT_THUMB;
|
||||
case GamepadButtonRightThumb: return NANOGUI_GAMEPAD_BUTTON_RIGHT_THUMB;
|
||||
case GamepadButtonL: return NANOGUI_GAMEPAD_BUTTON_LEFT_BUMPER;
|
||||
case GamepadButtonR: return NANOGUI_GAMEPAD_BUTTON_RIGHT_BUMPER;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
GamepadMapper::GamepadMapper() {
|
||||
load_defaults();
|
||||
}
|
||||
|
||||
bool GamepadMapper::gamepad_combo_is_enabled(GLFWgamepadstate& gamepad, GamepadCombo combo) {
|
||||
if (m_combo.find(combo) != m_combo.end()) {
|
||||
bool result = true;
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
GamepadButtons button = m_combo[combo][i];
|
||||
|
||||
if (button == GamepadButtonUnknown) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (button < GamepadButtonZL) {
|
||||
result = result && gamepad.buttons[gamepad_button_to_nanogui_button(button)];
|
||||
} else if (button == GamepadButtonZL) {
|
||||
result = result && (gamepad.axes[NANOGUI_GAMEPAD_AXIS_LEFT_TRIGGER] == 1);
|
||||
} else if (button == GamepadButtonZL) {
|
||||
result = result && (gamepad.axes[NANOGUI_GAMEPAD_AXIS_RIGHT_TRIGGER] == 1);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
GLFWgamepadstate GamepadMapper::map(GLFWgamepadstate &gamepad) {
|
||||
GLFWgamepadstate result = gamepad;
|
||||
|
||||
for (int i = 0; i < NANOGUI_GAMEPAD_BUTTON_DPAD_LEFT + 1; i++) {
|
||||
if (m_gamepad_map[i] < GamepadButtonZL) {
|
||||
result.buttons[gamepad_button_to_nanogui_button(m_gamepad_map[i])] = gamepad.buttons[gamepad_button_to_nanogui_button((GamepadButtons)i)];
|
||||
} else if (i < GamepadButtonZL && m_gamepad_map[i] == GamepadButtonZL) {
|
||||
result.axes[NANOGUI_GAMEPAD_AXIS_LEFT_TRIGGER] = gamepad.buttons[gamepad_button_to_nanogui_button((GamepadButtons)i)] ? 1 : -1;
|
||||
} else if (i < GamepadButtonZL && m_gamepad_map[i] == GamepadButtonZR) {
|
||||
result.axes[NANOGUI_GAMEPAD_AXIS_RIGHT_TRIGGER] = gamepad.buttons[gamepad_button_to_nanogui_button((GamepadButtons)i)] ? 1 : -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_gamepad_map[GamepadButtonZL] < GamepadButtonZL) {
|
||||
result.buttons[gamepad_button_to_nanogui_button(m_gamepad_map[GamepadButtonZL])] = gamepad.axes[NANOGUI_GAMEPAD_AXIS_LEFT_TRIGGER] > 0;
|
||||
} else if (m_gamepad_map[GamepadButtonZL] == GamepadButtonZR) {
|
||||
result.axes[NANOGUI_GAMEPAD_AXIS_RIGHT_TRIGGER] = gamepad.axes[NANOGUI_GAMEPAD_AXIS_LEFT_TRIGGER];
|
||||
}
|
||||
|
||||
if (m_gamepad_map[GamepadButtonZR] < GamepadButtonZL) {
|
||||
result.buttons[gamepad_button_to_nanogui_button(m_gamepad_map[GamepadButtonZR])] = gamepad.axes[NANOGUI_GAMEPAD_AXIS_RIGHT_TRIGGER] > 0;
|
||||
} else if (m_gamepad_map[GamepadButtonZR] == GamepadButtonZL) {
|
||||
result.axes[NANOGUI_GAMEPAD_AXIS_LEFT_TRIGGER] = gamepad.axes[NANOGUI_GAMEPAD_AXIS_RIGHT_TRIGGER];
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
GamepadButtons GamepadMapper::convert_nanogui_gamepad_button(int button) {
|
||||
switch (button) {
|
||||
case NANOGUI_GAMEPAD_BUTTON_A: return GamepadButtonA;
|
||||
case NANOGUI_GAMEPAD_BUTTON_B: return GamepadButtonB;
|
||||
case NANOGUI_GAMEPAD_BUTTON_X: return GamepadButtonX;
|
||||
case NANOGUI_GAMEPAD_BUTTON_Y: return GamepadButtonY;
|
||||
case NANOGUI_GAMEPAD_BUTTON_DPAD_UP: return GamepadButtonUp;
|
||||
case NANOGUI_GAMEPAD_BUTTON_DPAD_DOWN: return GamepadButtonDown;
|
||||
case NANOGUI_GAMEPAD_BUTTON_DPAD_LEFT: return GamepadButtonLeft;
|
||||
case NANOGUI_GAMEPAD_BUTTON_DPAD_RIGHT: return GamepadButtonRight;
|
||||
case NANOGUI_GAMEPAD_BUTTON_START: return GamepadButtonPlus;
|
||||
case NANOGUI_GAMEPAD_BUTTON_BACK: return GamepadButtonMinus;
|
||||
case NANOGUI_GAMEPAD_BUTTON_LEFT_THUMB: return GamepadButtonLeftThumb;
|
||||
case NANOGUI_GAMEPAD_BUTTON_RIGHT_THUMB: return GamepadButtonRightThumb;
|
||||
case NANOGUI_GAMEPAD_BUTTON_LEFT_BUMPER: return GamepadButtonL;
|
||||
case NANOGUI_GAMEPAD_BUTTON_RIGHT_BUMPER: return GamepadButtonR;
|
||||
default: return GamepadButtonUnknown;
|
||||
}
|
||||
}
|
||||
|
||||
GamepadButtons GamepadMapper::convert_nanogui_analog_axis(int axis) {
|
||||
switch (axis) {
|
||||
case NANOGUI_GAMEPAD_AXIS_LEFT_TRIGGER: return GamepadButtonZL;
|
||||
case NANOGUI_GAMEPAD_AXIS_RIGHT_TRIGGER: return GamepadButtonZR;
|
||||
default: return GamepadButtonUnknown;
|
||||
}
|
||||
}
|
||||
|
||||
void GamepadMapper::map_button(GamepadButtons origin_button, GamepadButtons new_button) {
|
||||
m_gamepad_map[origin_button] = new_button;
|
||||
}
|
||||
|
||||
GamepadButtons GamepadMapper::mapped_button(int button) {
|
||||
return m_gamepad_map[button];
|
||||
}
|
||||
|
||||
void GamepadMapper::set_combo_buttons(std::array<GamepadButtons, 3> buttons, GamepadCombo combo) {
|
||||
m_combo[combo] = buttons;
|
||||
}
|
||||
|
||||
std::array<GamepadButtons, 3> GamepadMapper::combo_buttons(GamepadCombo combo) {
|
||||
return m_combo[combo];
|
||||
}
|
||||
|
||||
std::string GamepadMapper::button_label(GamepadButtons button, bool use_switch_label) {
|
||||
static std::map<GamepadButtons, std::vector<std::string>> map = {
|
||||
{GamepadButtonA, {"A"}},
|
||||
{GamepadButtonB, {"B"}},
|
||||
{GamepadButtonX, {"X"}},
|
||||
{GamepadButtonY, {"Y"}},
|
||||
{GamepadButtonUp, {"Up"}},
|
||||
{GamepadButtonDown, {"Down"}},
|
||||
{GamepadButtonLeft, {"Left"}},
|
||||
{GamepadButtonRight, {"Right"}},
|
||||
{GamepadButtonPlus, {"Start", "Plus"}},
|
||||
{GamepadButtonMinus, {"Back", "Minus"}},
|
||||
{GamepadButtonLeftThumb, {"Left Thumb"}},
|
||||
{GamepadButtonRightThumb, {"Right Thumb"}},
|
||||
{GamepadButtonL, {"LB", "L"}},
|
||||
{GamepadButtonR, {"RB", "R"}},
|
||||
{GamepadButtonZL, {"LT", "ZL"}},
|
||||
{GamepadButtonZR, {"RT", "ZR"}}
|
||||
};
|
||||
|
||||
if (map.find(button) != map.end()) {
|
||||
return use_switch_label ? map[button].back() : map[button].front();
|
||||
}
|
||||
return "N/A";
|
||||
}
|
||||
|
||||
std::string GamepadMapper::combo_label(GamepadCombo combo) {
|
||||
static std::map<GamepadCombo, std::string> map = {
|
||||
{GamepadComboGuide, "Guide"},
|
||||
{GamepadComboExit, "Exit"},
|
||||
{GamepadComboExitAndClose, "Exit And Close"},
|
||||
{GamepadComboAltEnter, "Alt + Enter"},
|
||||
{GamepadComboEscape, "Escape"},
|
||||
{GamepadComboShowStats, "Show Stats"},
|
||||
{GamepadComboHideStats, "Hide Stats"}
|
||||
};
|
||||
|
||||
if (map.find(combo) != map.end()) {
|
||||
return map[combo];
|
||||
}
|
||||
return "N/A";
|
||||
}
|
||||
|
||||
void GamepadMapper::load_gamepad_map(int app_id) {
|
||||
// TODO: Load from JSON
|
||||
}
|
||||
|
||||
void GamepadMapper::save_gamepad_map(int app_id) {
|
||||
// TODO: Save to JSON
|
||||
}
|
||||
|
||||
void GamepadMapper::load_defaults() {
|
||||
for (int i = 0; i < GamepadButtonLast; i++) {
|
||||
m_gamepad_map[i] = (GamepadButtons)i;
|
||||
}
|
||||
|
||||
m_combo.clear();
|
||||
m_combo[GamepadComboGuide] = {GamepadButtonMinus, GamepadButtonPlus, GamepadButtonUnknown};
|
||||
m_combo[GamepadComboExit] = {GamepadButtonL, GamepadButtonR, GamepadButtonUp};
|
||||
m_combo[GamepadComboExitAndClose] = {GamepadButtonL, GamepadButtonR, GamepadButtonDown};
|
||||
m_combo[GamepadComboAltEnter] = {GamepadButtonL, GamepadButtonR, GamepadButtonLeft};
|
||||
m_combo[GamepadComboEscape] = {GamepadButtonL, GamepadButtonR, GamepadButtonRight};
|
||||
m_combo[GamepadComboShowStats] = {GamepadButtonZL, GamepadButtonZR, GamepadButtonLeft};
|
||||
m_combo[GamepadComboHideStats] = {GamepadButtonZL, GamepadButtonZR, GamepadButtonRight};
|
||||
}
|
85
src/GamepadMapper.hpp
Normal file
85
src/GamepadMapper.hpp
Normal file
|
@ -0,0 +1,85 @@
|
|||
#include <stdio.h>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <array>
|
||||
#pragma once
|
||||
|
||||
struct GLFWgamepadstate;
|
||||
|
||||
enum GamepadButtons: int {
|
||||
GamepadButtonUnknown = -1,
|
||||
GamepadButtonA,
|
||||
GamepadButtonB,
|
||||
GamepadButtonX,
|
||||
GamepadButtonY,
|
||||
GamepadButtonUp,
|
||||
GamepadButtonDown,
|
||||
GamepadButtonLeft,
|
||||
GamepadButtonRight,
|
||||
GamepadButtonPlus,
|
||||
GamepadButtonMinus,
|
||||
GamepadButtonLeftThumb,
|
||||
GamepadButtonRightThumb,
|
||||
GamepadButtonL,
|
||||
GamepadButtonR,
|
||||
GamepadButtonZL,
|
||||
GamepadButtonZR,
|
||||
GamepadButtonLast
|
||||
};
|
||||
|
||||
enum GamepadCombo: int {
|
||||
GamepadComboGuide,
|
||||
GamepadComboExit,
|
||||
GamepadComboExitAndClose,
|
||||
GamepadComboAltEnter,
|
||||
GamepadComboEscape,
|
||||
GamepadComboShowStats,
|
||||
GamepadComboHideStats,
|
||||
GamepadComboLast
|
||||
};
|
||||
|
||||
class GamepadMapper {
|
||||
public:
|
||||
static GamepadMapper* mapper() {
|
||||
static GamepadMapper mapper;
|
||||
return &mapper;
|
||||
}
|
||||
|
||||
void load_gamepad_map(int app_id);
|
||||
void save_gamepad_map(int app_id);
|
||||
|
||||
bool gamepad_combo_is_enabled(GLFWgamepadstate& gamepad, GamepadCombo combo);
|
||||
|
||||
GLFWgamepadstate map(GLFWgamepadstate& gamepad);
|
||||
|
||||
GamepadButtons convert_nanogui_gamepad_button(int button);
|
||||
GamepadButtons convert_nanogui_analog_axis(int axis);
|
||||
|
||||
void map_button(GamepadButtons origin_button, GamepadButtons new_button);
|
||||
GamepadButtons mapped_button(int origin_button);
|
||||
|
||||
void set_combo_buttons(std::array<GamepadButtons, 3> buttons, GamepadCombo combo);
|
||||
std::array<GamepadButtons, 3> combo_buttons(GamepadCombo combo);
|
||||
|
||||
int button_count() const {
|
||||
return m_button_count;
|
||||
}
|
||||
|
||||
int combo_count() const {
|
||||
return m_combo_count;
|
||||
}
|
||||
|
||||
std::string button_label(GamepadButtons button, bool use_switch_label);
|
||||
std::string combo_label(GamepadCombo combo);
|
||||
|
||||
private:
|
||||
GamepadMapper();
|
||||
|
||||
void load_defaults();
|
||||
|
||||
const int m_button_count = GamepadButtonLast;
|
||||
const int m_combo_count = GamepadComboLast;
|
||||
|
||||
GamepadButtons m_gamepad_map[GamepadButtonLast];
|
||||
std::map<GamepadCombo, std::array<GamepadButtons, 3>> m_combo;
|
||||
};
|
|
@ -1,7 +1,6 @@
|
|||
#include "InputController.hpp"
|
||||
#include "Settings.hpp"
|
||||
#include "Limelight.h"
|
||||
#include "Limelight.h"
|
||||
#include <nanogui/nanogui.h>
|
||||
#include <nanogui/opengl.h>
|
||||
#include <GLFW/glfw3.h>
|
||||
|
@ -16,13 +15,11 @@ static HidVibrationValue VibrationValue_stop;
|
|||
struct MouseState {
|
||||
int x;
|
||||
int y;
|
||||
bool l_press;
|
||||
bool r_press;
|
||||
bool is_pressed;
|
||||
};
|
||||
|
||||
struct MouseState mouse_state;
|
||||
struct GamePadState game_pad_state;
|
||||
static GLFWgamepadstate last_glfw_gamepad_state;
|
||||
static GLFWgamepadstate glfw_gamepad_state;
|
||||
|
||||
static int m_width = 1, m_height = 1;
|
||||
|
||||
|
@ -45,24 +42,15 @@ void InputController::handle_cursor_event(int width, int height, int x, int y) {
|
|||
}
|
||||
|
||||
void InputController::handle_mouse_event(int button, int action, int modifiers) {
|
||||
bool mouse_l_press = button == GLFW_MOUSE_BUTTON_1 && action == GLFW_PRESS;
|
||||
bool mouse_r_press = button == GLFW_MOUSE_BUTTON_2 && action == GLFW_PRESS;
|
||||
bool is_pressed = button == GLFW_MOUSE_BUTTON_1 && action == GLFW_PRESS;
|
||||
|
||||
if (!mouse_state.l_press && mouse_l_press) {
|
||||
mouse_state.l_press = true;
|
||||
if (!mouse_state.is_pressed && is_pressed) {
|
||||
mouse_state.is_pressed = 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;
|
||||
} else if (mouse_state.is_pressed && !is_pressed) {
|
||||
mouse_state.is_pressed = 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_event(int key, int scancode, int action, int modifiers) {
|
||||
|
@ -70,7 +58,8 @@ void InputController::handle_keyboard_event(int key, int scancode, int action, i
|
|||
|
||||
#ifndef __SWITCH__
|
||||
// Translate keyboard keys to gamepad
|
||||
extern GLFWgamepadstate glfw_gamepad_state;
|
||||
GLFWgamepadstate glfw_gamepad_state;
|
||||
memset(&glfw_gamepad_state, 0, sizeof(GLFWgamepadstate));
|
||||
static int glfw_keyboard_state[GLFW_KEY_LAST];
|
||||
glfw_keyboard_state[key] = action != GLFW_RELEASE;
|
||||
|
||||
|
@ -88,74 +77,39 @@ void InputController::handle_keyboard_event(int key, int scancode, int action, i
|
|||
GLFW_KEYBOARD_TO_GAMEPAD(GLFW_KEY_X, GLFW_GAMEPAD_BUTTON_X);
|
||||
GLFW_KEYBOARD_TO_GAMEPAD(GLFW_KEY_Y, GLFW_GAMEPAD_BUTTON_Y);
|
||||
GLFW_KEYBOARD_TO_GAMEPAD(GLFW_KEY_ESCAPE, GLFW_GAMEPAD_BUTTON_START);
|
||||
GLFW_KEYBOARD_TO_GAMEPAD(GLFW_KEY_MINUS, GLFW_GAMEPAD_BUTTON_BACK);
|
||||
GLFW_KEYBOARD_TO_GAMEPAD(GLFW_KEY_R, GLFW_GAMEPAD_BUTTON_LEFT_THUMB);
|
||||
GLFW_KEYBOARD_TO_GAMEPAD(GLFW_KEY_T, GLFW_GAMEPAD_BUTTON_RIGHT_THUMB);
|
||||
|
||||
glfw_gamepad_state.axes[GLFW_GAMEPAD_AXIS_LEFT_TRIGGER] = glfw_keyboard_state[GLFW_KEY_Z] ? 1 : -1;
|
||||
glfw_gamepad_state.axes[GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER] = glfw_keyboard_state[GLFW_KEY_C] ? 1 : -1;
|
||||
|
||||
handle_gamepad_event(&glfw_gamepad_state);
|
||||
handle_gamepad_event(glfw_gamepad_state);
|
||||
#endif
|
||||
}
|
||||
|
||||
void InputController::handle_gamepad_event(GLFWgamepadstate* gamepad) {
|
||||
game_pad_state.leftTrigger = 0xFFFF * (gamepad->axes[GLFW_GAMEPAD_AXIS_LEFT_TRIGGER] + 1) / 2;
|
||||
game_pad_state.rightTrigger = 0xFFFF * (gamepad->axes[GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER] + 1) / 2;
|
||||
game_pad_state.leftStickX = gamepad->axes[GLFW_GAMEPAD_AXIS_LEFT_X] * 0x7FFF;
|
||||
game_pad_state.leftStickY = 0xFFFF - gamepad->axes[GLFW_GAMEPAD_AXIS_LEFT_Y] * 0x7FFF;
|
||||
game_pad_state.rightStickX = gamepad->axes[GLFW_GAMEPAD_AXIS_RIGHT_X] * 0x7FFF;
|
||||
game_pad_state.rightStickY = 0xFFFF - gamepad->axes[GLFW_GAMEPAD_AXIS_RIGHT_Y] * 0x7FFF;
|
||||
|
||||
#define SET_GAME_PAD_STATE(LIMELIGHT_KEY, GLFW_GAMEPAD_BUTTON) \
|
||||
gamepad->buttons[GLFW_GAMEPAD_BUTTON] ? (game_pad_state.buttonFlags |= LIMELIGHT_KEY) : (game_pad_state.buttonFlags &= ~LIMELIGHT_KEY);
|
||||
|
||||
SET_GAME_PAD_STATE(UP_FLAG, GLFW_GAMEPAD_BUTTON_DPAD_UP);
|
||||
SET_GAME_PAD_STATE(DOWN_FLAG, GLFW_GAMEPAD_BUTTON_DPAD_DOWN);
|
||||
SET_GAME_PAD_STATE(LEFT_FLAG, GLFW_GAMEPAD_BUTTON_DPAD_LEFT);
|
||||
SET_GAME_PAD_STATE(RIGHT_FLAG, GLFW_GAMEPAD_BUTTON_DPAD_RIGHT);
|
||||
|
||||
SET_GAME_PAD_STATE(BACK_FLAG, GLFW_GAMEPAD_BUTTON_BACK);
|
||||
SET_GAME_PAD_STATE(PLAY_FLAG, GLFW_GAMEPAD_BUTTON_START);
|
||||
|
||||
SET_GAME_PAD_STATE(LB_FLAG, GLFW_GAMEPAD_BUTTON_LEFT_BUMPER);
|
||||
SET_GAME_PAD_STATE(RB_FLAG, GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER);
|
||||
|
||||
SET_GAME_PAD_STATE(LS_CLK_FLAG, GLFW_GAMEPAD_BUTTON_LEFT_THUMB);
|
||||
SET_GAME_PAD_STATE(RS_CLK_FLAG, GLFW_GAMEPAD_BUTTON_RIGHT_THUMB);
|
||||
|
||||
if (Settings::settings()->swap_ab_xy()) {
|
||||
SET_GAME_PAD_STATE(A_FLAG, GLFW_GAMEPAD_BUTTON_B);
|
||||
SET_GAME_PAD_STATE(B_FLAG, GLFW_GAMEPAD_BUTTON_A);
|
||||
SET_GAME_PAD_STATE(X_FLAG, GLFW_GAMEPAD_BUTTON_Y);
|
||||
SET_GAME_PAD_STATE(Y_FLAG, GLFW_GAMEPAD_BUTTON_X);
|
||||
} else {
|
||||
SET_GAME_PAD_STATE(A_FLAG, GLFW_GAMEPAD_BUTTON_A);
|
||||
SET_GAME_PAD_STATE(B_FLAG, GLFW_GAMEPAD_BUTTON_B);
|
||||
SET_GAME_PAD_STATE(X_FLAG, GLFW_GAMEPAD_BUTTON_X);
|
||||
SET_GAME_PAD_STATE(Y_FLAG, GLFW_GAMEPAD_BUTTON_Y);
|
||||
}
|
||||
|
||||
// Send to nanogui
|
||||
if (gamepad->buttons != last_glfw_gamepad_state.buttons) {
|
||||
void InputController::handle_gamepad_event(GLFWgamepadstate& gamepad) {
|
||||
if (gamepad.buttons != glfw_gamepad_state.buttons) {
|
||||
for (int j = 0; j <= GLFW_GAMEPAD_BUTTON_LAST; j++) {
|
||||
if (gamepad->buttons[j] == last_glfw_gamepad_state.buttons[j]) {
|
||||
if (gamepad.buttons[j] == glfw_gamepad_state.buttons[j]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nanogui::gamepad_button_callback_event(0, j, gamepad->buttons[j]);
|
||||
nanogui::gamepad_button_callback_event(0, j, gamepad.buttons[j]);
|
||||
}
|
||||
}
|
||||
|
||||
if (gamepad->axes != last_glfw_gamepad_state.axes) {
|
||||
if (gamepad.axes != glfw_gamepad_state.axes) {
|
||||
for (int j = 0; j <= GLFW_GAMEPAD_AXIS_LAST; j++) {
|
||||
if (gamepad->axes[j] == last_glfw_gamepad_state.axes[j]) {
|
||||
if (gamepad.axes[j] == glfw_gamepad_state.axes[j]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nanogui::gamepad_analog_callback_event(0, j, gamepad->axes[j]);
|
||||
nanogui::gamepad_analog_callback_event(0, j, gamepad.axes[j]);
|
||||
}
|
||||
}
|
||||
|
||||
last_glfw_gamepad_state = *gamepad;
|
||||
|
||||
glfw_gamepad_state = gamepad;
|
||||
}
|
||||
|
||||
void InputController::handle_rumple(unsigned short low_freq_motor, unsigned short high_freq_motor) {
|
||||
|
@ -194,18 +148,31 @@ void InputController::stop_rumple() {
|
|||
#endif
|
||||
}
|
||||
|
||||
bool InputController::gamepad_combo_is_enabled(GamepadCombo combo) {
|
||||
return GamepadMapper::mapper()->gamepad_combo_is_enabled(glfw_gamepad_state, combo);
|
||||
}
|
||||
|
||||
bool InputController::gamepad_button_is_enabled(int button) {
|
||||
return glfw_gamepad_state.buttons[button];
|
||||
}
|
||||
|
||||
bool InputController::gamepad_trigger_is_enabled(int trigger) {
|
||||
return glfw_gamepad_state.axes[trigger] > 0;
|
||||
}
|
||||
|
||||
void InputController::send_to_stream() {
|
||||
static bool pressed = false, released = false;
|
||||
// Mouse
|
||||
static bool is_pressed = false, is_released = false;
|
||||
static int mouse_x = mouse_state.x, mouse_y = mouse_state.y;
|
||||
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.l_press && !pressed) {
|
||||
pressed = true;
|
||||
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.l_press && pressed) {
|
||||
pressed = false;
|
||||
} else if (!mouse_state.is_pressed && is_pressed) {
|
||||
is_pressed = false;
|
||||
}
|
||||
|
||||
if (Settings::settings()->click_by_tap()) {
|
||||
|
@ -215,25 +182,25 @@ void InputController::send_to_stream() {
|
|||
LiSendMousePositionEvent(mouse_state.x, mouse_state.y, m_width, m_height);
|
||||
}
|
||||
|
||||
if (((game_pad_state.buttonFlags & RB_FLAG) || game_pad_state.rightTrigger)) {
|
||||
if (mouse_state.l_press) {
|
||||
released = false;
|
||||
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 (!released) {
|
||||
released = true;
|
||||
} else if (!is_released) {
|
||||
is_released = true;
|
||||
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_RIGHT);
|
||||
}
|
||||
} else {
|
||||
if (mouse_state.l_press) {
|
||||
released = false;
|
||||
if (mouse_state.is_pressed) {
|
||||
is_released = false;
|
||||
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_LEFT);
|
||||
} else if (!released) {
|
||||
released = true;
|
||||
} else if (!is_released) {
|
||||
is_released = true;
|
||||
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_LEFT);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
bool move_mouse = (game_pad_state.leftTrigger == 0) && (game_pad_state.rightTrigger == 0);
|
||||
bool move_mouse = !gamepad_trigger_is_enabled(NANOGUI_GAMEPAD_AXIS_LEFT_TRIGGER) && !gamepad_trigger_is_enabled(NANOGUI_GAMEPAD_AXIS_RIGHT_TRIGGER);
|
||||
|
||||
if (move_mouse) {
|
||||
mouse_x = std::min(std::max(mouse_x + mouse_state.x - last_mouse_x, 0), m_width);
|
||||
|
@ -249,52 +216,85 @@ void InputController::send_to_stream() {
|
|||
last_mouse_x = mouse_state.x;
|
||||
last_mouse_y = mouse_state.y;
|
||||
|
||||
if ((game_pad_state.buttonFlags & LB_FLAG) || game_pad_state.leftTrigger) {
|
||||
if (mouse_state.l_press) {
|
||||
released = false;
|
||||
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 (!released) {
|
||||
released = true;
|
||||
} else if (!is_released) {
|
||||
is_released = true;
|
||||
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_LEFT);
|
||||
}
|
||||
} else if ((game_pad_state.buttonFlags & RB_FLAG) || game_pad_state.rightTrigger) {
|
||||
if (mouse_state.l_press) {
|
||||
released = false;
|
||||
} 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 (!released) {
|
||||
released = true;
|
||||
} else if (!is_released) {
|
||||
is_released = true;
|
||||
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_RIGHT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Keyboard
|
||||
static bool send_alt_enter = false;
|
||||
|
||||
if (!send_alt_enter && GAME_PAD_COMBO(LEFT_FLAG)) {
|
||||
if (!send_alt_enter && gamepad_combo_is_enabled(GamepadComboAltEnter)) {
|
||||
send_alt_enter = true;
|
||||
LiSendKeyboardEvent(0x0D, KEY_ACTION_DOWN, MODIFIER_ALT);
|
||||
} else if (send_alt_enter && !GAME_PAD_COMBO(LEFT_FLAG)) {
|
||||
} else if (send_alt_enter && !gamepad_combo_is_enabled(GamepadComboAltEnter)) {
|
||||
send_alt_enter = false;
|
||||
LiSendKeyboardEvent(0x0D, KEY_ACTION_UP, MODIFIER_ALT);
|
||||
}
|
||||
|
||||
static bool send_escape = false;
|
||||
|
||||
if (!send_escape && GAME_PAD_COMBO(RIGHT_FLAG)) {
|
||||
if (!send_escape && gamepad_combo_is_enabled(GamepadComboEscape)) {
|
||||
send_escape = true;
|
||||
LiSendKeyboardEvent(0x1B, KEY_ACTION_DOWN, 0);
|
||||
} else if (send_escape && !GAME_PAD_COMBO(RIGHT_FLAG)) {
|
||||
} else if (send_escape && !gamepad_combo_is_enabled(GamepadComboEscape)) {
|
||||
send_escape = false;
|
||||
LiSendKeyboardEvent(0x1B, KEY_ACTION_UP, 0);
|
||||
}
|
||||
|
||||
// Gamepad
|
||||
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;
|
||||
unsigned char rightTrigger = 0xFFFF * (mapped_gamepad.axes[GLFW_GAMEPAD_AXIS_RIGHT_TRIGGER] + 1) / 2;
|
||||
unsigned char leftStickX = mapped_gamepad.axes[GLFW_GAMEPAD_AXIS_LEFT_X] * 0x7FFF;
|
||||
unsigned char leftStickY = 0xFFFF - mapped_gamepad.axes[GLFW_GAMEPAD_AXIS_LEFT_Y] * 0x7FFF;
|
||||
unsigned char rightStickX = mapped_gamepad.axes[GLFW_GAMEPAD_AXIS_RIGHT_X] * 0x7FFF;
|
||||
unsigned char rightStickY = 0xFFFF - mapped_gamepad.axes[GLFW_GAMEPAD_AXIS_RIGHT_Y] * 0x7FFF;
|
||||
|
||||
#define SET_GAME_PAD_STATE(LIMELIGHT_KEY, GLFW_GAMEPAD_BUTTON) \
|
||||
mapped_gamepad.buttons[GLFW_GAMEPAD_BUTTON] ? (buttonFlags |= LIMELIGHT_KEY) : (buttonFlags &= ~LIMELIGHT_KEY);
|
||||
|
||||
SET_GAME_PAD_STATE(UP_FLAG, GLFW_GAMEPAD_BUTTON_DPAD_UP);
|
||||
SET_GAME_PAD_STATE(DOWN_FLAG, GLFW_GAMEPAD_BUTTON_DPAD_DOWN);
|
||||
SET_GAME_PAD_STATE(LEFT_FLAG, GLFW_GAMEPAD_BUTTON_DPAD_LEFT);
|
||||
SET_GAME_PAD_STATE(RIGHT_FLAG, GLFW_GAMEPAD_BUTTON_DPAD_RIGHT);
|
||||
|
||||
SET_GAME_PAD_STATE(BACK_FLAG, GLFW_GAMEPAD_BUTTON_BACK);
|
||||
SET_GAME_PAD_STATE(PLAY_FLAG, GLFW_GAMEPAD_BUTTON_START);
|
||||
|
||||
SET_GAME_PAD_STATE(LB_FLAG, GLFW_GAMEPAD_BUTTON_LEFT_BUMPER);
|
||||
SET_GAME_PAD_STATE(RB_FLAG, GLFW_GAMEPAD_BUTTON_RIGHT_BUMPER);
|
||||
|
||||
SET_GAME_PAD_STATE(LS_CLK_FLAG, GLFW_GAMEPAD_BUTTON_LEFT_THUMB);
|
||||
SET_GAME_PAD_STATE(RS_CLK_FLAG, GLFW_GAMEPAD_BUTTON_RIGHT_THUMB);
|
||||
|
||||
SET_GAME_PAD_STATE(A_FLAG, GLFW_GAMEPAD_BUTTON_A);
|
||||
SET_GAME_PAD_STATE(B_FLAG, GLFW_GAMEPAD_BUTTON_B);
|
||||
SET_GAME_PAD_STATE(X_FLAG, GLFW_GAMEPAD_BUTTON_X);
|
||||
SET_GAME_PAD_STATE(Y_FLAG, GLFW_GAMEPAD_BUTTON_Y);
|
||||
|
||||
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
|
||||
buttonFlags,
|
||||
leftTrigger,
|
||||
rightTrigger,
|
||||
leftStickX,
|
||||
leftStickY,
|
||||
rightStickX,
|
||||
rightStickY
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,27 +1,8 @@
|
|||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include "GamepadMapper.hpp"
|
||||
#pragma once
|
||||
|
||||
struct GLFWgamepadstate;
|
||||
|
||||
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))
|
||||
|
||||
#define GAME_PAD_COMBO_R(KEY) \
|
||||
(game_pad_state.leftTrigger && game_pad_state.rightTrigger && (game_pad_state.buttonFlags & KEY))
|
||||
|
||||
class InputController {
|
||||
public:
|
||||
static InputController* controller() {
|
||||
|
@ -32,12 +13,17 @@ public:
|
|||
void handle_cursor_event(int width, int height, int x, int y);
|
||||
void handle_mouse_event(int button, int action, int modifiers);
|
||||
void handle_keyboard_event(int key, int scancode, int action, int modifiers);
|
||||
void handle_gamepad_event(GLFWgamepadstate* gamepad);
|
||||
void handle_gamepad_event(GLFWgamepadstate& gamepad);
|
||||
void handle_rumple(unsigned short low_freq_motor, unsigned short high_freq_motor);
|
||||
void stop_rumple();
|
||||
|
||||
bool gamepad_combo_is_enabled(GamepadCombo combo);
|
||||
|
||||
void send_to_stream();
|
||||
|
||||
private:
|
||||
InputController();
|
||||
|
||||
bool gamepad_button_is_enabled(int button);
|
||||
bool gamepad_trigger_is_enabled(int trigger);
|
||||
};
|
||||
|
|
|
@ -90,7 +90,7 @@ int main(int argc, const char * argv[]) {
|
|||
|
||||
#ifdef __SWITCH__
|
||||
glfwGetGamepadState(GLFW_JOYSTICK_1, &glfw_gamepad_state);
|
||||
InputController::controller()->handle_gamepad_event(&glfw_gamepad_state);
|
||||
InputController::controller()->handle_gamepad_event(glfw_gamepad_state);
|
||||
#endif
|
||||
|
||||
int width, height;
|
||||
|
|
|
@ -96,3 +96,8 @@ void Application::gamepad_analog_callback_event(int jid, int axis, float value)
|
|||
m_windows.back()->gamepad_analog_event(jid, axis, value);
|
||||
}
|
||||
}
|
||||
|
||||
void Application::perform_layout() {
|
||||
m_focus_path.clear();
|
||||
Screen::perform_layout();
|
||||
}
|
||||
|
|
|
@ -22,6 +22,9 @@ public:
|
|||
void gamepad_button_callback_event(int jid, int button, int action) override;
|
||||
void gamepad_analog_callback_event(int jid, int axis, float value) override;
|
||||
|
||||
void perform_layout();
|
||||
|
||||
private:
|
||||
|
||||
std::vector<Widget *> m_windows;
|
||||
};
|
||||
|
|
|
@ -56,8 +56,8 @@ public:
|
|||
void perform_layout(NVGcontext *ctx) override;
|
||||
|
||||
void perform_layout() {
|
||||
screen()->perform_layout();
|
||||
screen()->update_focus(NULL);
|
||||
application()->perform_layout();
|
||||
application()->update_focus(NULL);
|
||||
}
|
||||
|
||||
void set_box_layout(nanogui::Orientation orientation, nanogui::Alignment alignment = nanogui::Alignment::Middle, int margin = 30, int spacing = 10) {
|
||||
|
|
263
src/ui/windows/InputSettingsWindow.cpp
Normal file
263
src/ui/windows/InputSettingsWindow.cpp
Normal file
|
@ -0,0 +1,263 @@
|
|||
#include "InputSettingsWindow.hpp"
|
||||
#include <nanogui/opengl.h>
|
||||
#include <functional>
|
||||
|
||||
using namespace nanogui;
|
||||
|
||||
class GamepadInputOverlay: Widget {
|
||||
public:
|
||||
GamepadInputOverlay(Widget* parent, std::string caption, int button_count = 1): Widget(parent) {
|
||||
m_button_count = button_count;
|
||||
m_caption = caption;
|
||||
set_fixed_size(parent->screen()->size());
|
||||
screen()->perform_layout();
|
||||
}
|
||||
|
||||
bool gamepad_button_event(int jid, int button, int action) override {
|
||||
if (action) {
|
||||
GamepadButtons gamepad_button = GamepadMapper::mapper()->convert_nanogui_gamepad_button(button);
|
||||
handle_button_input(button, gamepad_button);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool gamepad_analog_event(int jid, int axis, float value) override {
|
||||
if (value > 0) {
|
||||
GamepadButtons gamepad_button = GamepadMapper::mapper()->convert_nanogui_analog_axis(axis);
|
||||
handle_button_input(-1, gamepad_button);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool is_done() const {
|
||||
bool result = false;
|
||||
|
||||
for (int i = 0; i < m_button_count; i++) {
|
||||
result = m_buttons[i] != GamepadButtonUnknown;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void handle_button_input(int button, GamepadButtons gamepad_button) {
|
||||
if (gamepad_button == GamepadButtonUnknown) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_done()) {
|
||||
if (button == NANOGUI_GAMEPAD_BUTTON_A) {
|
||||
if (m_completion) {
|
||||
inc_ref();
|
||||
m_completion(m_buttons);
|
||||
dec_ref();
|
||||
}
|
||||
} else if (button == NANOGUI_GAMEPAD_BUTTON_B) {
|
||||
m_buttons[0] = GamepadButtonUnknown;
|
||||
m_buttons[1] = GamepadButtonUnknown;
|
||||
m_buttons[2] = GamepadButtonUnknown;
|
||||
}
|
||||
} else {
|
||||
if (m_buttons[0] == GamepadButtonUnknown) {
|
||||
m_buttons[0] = gamepad_button;
|
||||
} else if (m_buttons[1] == GamepadButtonUnknown && m_buttons[0] != gamepad_button) {
|
||||
m_buttons[1] = gamepad_button;
|
||||
} else if (m_buttons[2] == GamepadButtonUnknown && m_buttons[0] != gamepad_button && m_buttons[1] != gamepad_button) {
|
||||
m_buttons[2] = gamepad_button;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void draw(NVGcontext *ctx) override {
|
||||
nvgSave(ctx);
|
||||
|
||||
// Draw bg
|
||||
nvgFillColor(ctx, Color(0, 0, 0, 220));
|
||||
nvgBeginPath(ctx);
|
||||
nvgRect(ctx, 0, 0, width(), height());
|
||||
nvgFill(ctx);
|
||||
|
||||
// Draw text
|
||||
nvgFillColor(ctx, Color(255, 255, 255, 200));
|
||||
nvgFontSize(ctx, 30);
|
||||
nvgFontFace(ctx, "sans");
|
||||
nvgTextAlign(ctx, NVG_ALIGN_CENTER | NVG_ALIGN_MIDDLE);
|
||||
nvgText(ctx, width() / 2, height() / 2 - 80, m_caption.c_str(), NULL);
|
||||
|
||||
if (m_buttons[0] != GamepadButtonUnknown) {
|
||||
std::string string = "\"" + GamepadMapper::mapper()->button_label(m_buttons[0], true) + "\"";
|
||||
|
||||
if (m_buttons[1] != GamepadButtonUnknown) {
|
||||
string += " + \"" + GamepadMapper::mapper()->button_label(m_buttons[1], true) + "\"";
|
||||
}
|
||||
|
||||
if (m_buttons[2] != GamepadButtonUnknown) {
|
||||
string += " + \"" + GamepadMapper::mapper()->button_label(m_buttons[2], true) + "\"";
|
||||
}
|
||||
|
||||
nvgText(ctx, width() / 2, height() / 2, string.c_str(), NULL);
|
||||
|
||||
if (is_done()) {
|
||||
string = "Press \"" +
|
||||
GamepadMapper::mapper()->button_label(GamepadButtonA, true) +
|
||||
"\" for Accept, \"" +
|
||||
GamepadMapper::mapper()->button_label(GamepadButtonB, true) +
|
||||
"\" for Cancel.";
|
||||
nvgText(ctx, width() / 2, height() / 2 + 80, string.c_str(), NULL);
|
||||
}
|
||||
}
|
||||
|
||||
nvgRestore(ctx);
|
||||
}
|
||||
|
||||
void set_completion(std::function<void(std::array<GamepadButtons, 3>)> completion) {
|
||||
m_completion = completion;
|
||||
}
|
||||
|
||||
void dispose() {
|
||||
screen()->remove_child(this);
|
||||
}
|
||||
|
||||
private:
|
||||
int m_button_count;
|
||||
std::string m_caption;
|
||||
std::function<void(std::array<GamepadButtons, 3>)> m_completion;
|
||||
std::array<GamepadButtons, 3> m_buttons = {GamepadButtonUnknown, GamepadButtonUnknown, GamepadButtonUnknown};
|
||||
};
|
||||
|
||||
static GamepadInputOverlay* overlay = nullptr;
|
||||
|
||||
InputSettingsWindow::InputSettingsWindow(Widget* parent): ContentWindow(parent, "Input Settings") {
|
||||
set_left_pop_button();
|
||||
|
||||
set_box_layout(Orientation::Vertical, Alignment::Minimum);
|
||||
|
||||
reload_gamepad_input_settings();
|
||||
}
|
||||
|
||||
Widget* InputSettingsWindow::new_container(Widget* parent, int width) {
|
||||
auto container = parent->add<Widget>();
|
||||
container->set_layout(new GroupLayout(30, 10, 30, 10));
|
||||
container->set_fixed_width(width);
|
||||
return container;
|
||||
}
|
||||
|
||||
void InputSettingsWindow::reload_gamepad_input_settings() {
|
||||
clean_container();
|
||||
clean_right_title_buttons();
|
||||
|
||||
set_right_title_button(FA_KEYBOARD, [this] {
|
||||
reload_combo_settings();
|
||||
});
|
||||
|
||||
container()->add<Label>("Gamepad mapping (X360 -> Switch)");
|
||||
|
||||
auto content = container()->add<Widget>();
|
||||
content->set_layout(new BoxLayout(Orientation::Horizontal, Alignment::Minimum, 30, 10));
|
||||
auto button_container = new_container(content);
|
||||
|
||||
for (int i = 0; i < GamepadMapper::mapper()->button_count(); i++) {
|
||||
if (i == GamepadButtonUp) {
|
||||
button_container = new_container(content);
|
||||
}
|
||||
|
||||
if (i == GamepadButtonPlus) {
|
||||
button_container = new_container(content);
|
||||
}
|
||||
|
||||
if (i == GamepadButtonL) {
|
||||
button_container = new_container(content);
|
||||
}
|
||||
|
||||
button_container->add<Label>(GamepadMapper::mapper()->button_label((GamepadButtons)i, false));
|
||||
auto button = button_container->add<Button>(GamepadMapper::mapper()->button_label(GamepadMapper::mapper()->mapped_button(i), true));
|
||||
button->set_callback([this, i] {
|
||||
assign_button((GamepadButtons)i);
|
||||
});
|
||||
}
|
||||
perform_layout();
|
||||
}
|
||||
|
||||
void InputSettingsWindow::reload_combo_settings() {
|
||||
clean_container();
|
||||
clean_right_title_buttons();
|
||||
|
||||
set_right_title_button(FA_GAMEPAD, [this] {
|
||||
reload_gamepad_input_settings();
|
||||
});
|
||||
|
||||
container()->add<Label>("Keyboard Combo mapping");
|
||||
|
||||
auto content = container()->add<Widget>();
|
||||
content->set_layout(new BoxLayout(Orientation::Horizontal, Alignment::Minimum, 30, 10));
|
||||
auto button_container = new_container(content, 360);
|
||||
|
||||
for (int i = 0; i < GamepadMapper::mapper()->combo_count(); i++) {
|
||||
if (i == GamepadComboEscape) {
|
||||
button_container = new_container(content, 360);
|
||||
}
|
||||
|
||||
auto buttons = GamepadMapper::mapper()->combo_buttons((GamepadCombo)i);
|
||||
|
||||
std::string combo_text = "";
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (buttons[i] != GamepadButtonUnknown) {
|
||||
combo_text += GamepadMapper::mapper()->button_label(GamepadMapper::mapper()->mapped_button(buttons[i]), true);
|
||||
|
||||
if (i < 2 && buttons[i + 1] != GamepadButtonUnknown) {
|
||||
combo_text += " + ";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
button_container->add<Label>(GamepadMapper::mapper()->combo_label((GamepadCombo)i));
|
||||
auto button = button_container->add<Button>(combo_text);
|
||||
button->set_callback([this, i] {
|
||||
assign_combo((GamepadCombo)i, i == GamepadComboGuide ? 2 : 3);
|
||||
});
|
||||
}
|
||||
|
||||
perform_layout();
|
||||
}
|
||||
|
||||
bool InputSettingsWindow::mouse_button_event(const Vector2i &p, int button, bool down, int modifiers) {
|
||||
if (overlay) {
|
||||
return false;
|
||||
}
|
||||
return ContentWindow::mouse_button_event(p, button, down, modifiers);
|
||||
}
|
||||
|
||||
bool InputSettingsWindow::gamepad_button_event(int jid, int button, int action) {
|
||||
if (overlay) {
|
||||
return overlay->gamepad_button_event(jid, button, action);
|
||||
}
|
||||
return ContentWindow::gamepad_button_event(jid, button, action);
|
||||
}
|
||||
|
||||
bool InputSettingsWindow::gamepad_analog_event(int jid, int axis, float value) {
|
||||
if (overlay) {
|
||||
return overlay->gamepad_analog_event(jid, axis, value);
|
||||
}
|
||||
return ContentWindow::gamepad_button_event(jid, axis, value);
|
||||
}
|
||||
|
||||
void InputSettingsWindow::assign_button(GamepadButtons button) {
|
||||
overlay = screen()->add<GamepadInputOverlay>("Press button for reassign \"" + GamepadMapper::mapper()->button_label(button, false) + "\"");
|
||||
overlay->set_completion([this, button](auto result) {
|
||||
overlay->dispose();
|
||||
overlay = NULL;
|
||||
|
||||
GamepadMapper::mapper()->map_button(button, result[0]);
|
||||
reload_gamepad_input_settings();
|
||||
});
|
||||
}
|
||||
|
||||
void InputSettingsWindow::assign_combo(GamepadCombo combo, int buttons_count) {
|
||||
overlay = screen()->add<GamepadInputOverlay>("Enter combo for reassign \"" + GamepadMapper::mapper()->combo_label(combo) + "\"", buttons_count);
|
||||
overlay->set_completion([this, combo](auto result) {
|
||||
overlay->dispose();
|
||||
overlay = NULL;
|
||||
|
||||
GamepadMapper::mapper()->set_combo_buttons(result, combo);
|
||||
reload_combo_settings();
|
||||
});
|
||||
}
|
21
src/ui/windows/InputSettingsWindow.hpp
Normal file
21
src/ui/windows/InputSettingsWindow.hpp
Normal file
|
@ -0,0 +1,21 @@
|
|||
#include "ContentWindow.hpp"
|
||||
#include "GamepadMapper.hpp"
|
||||
#pragma once
|
||||
|
||||
class InputSettingsWindow: public ContentWindow {
|
||||
public:
|
||||
InputSettingsWindow(nanogui::Widget* parent);
|
||||
|
||||
bool mouse_button_event(const nanogui::Vector2i &p, int button, bool down, int modifiers) override;
|
||||
bool gamepad_button_event(int jid, int button, int action) override;
|
||||
bool gamepad_analog_event(int jid, int axis, float value) override;
|
||||
|
||||
private:
|
||||
nanogui::Widget* new_container(nanogui::Widget* parent, int width = 240);
|
||||
|
||||
void reload_gamepad_input_settings();
|
||||
void reload_combo_settings();
|
||||
|
||||
void assign_button(GamepadButtons button);
|
||||
void assign_combo(GamepadCombo combo, int buttons_count);
|
||||
};
|
|
@ -8,6 +8,7 @@
|
|||
#include "SettingsWindow.hpp"
|
||||
#include "LogsWindow.hpp"
|
||||
#include "Settings.hpp"
|
||||
#include "InputSettingsWindow.hpp"
|
||||
#include "nanovg.h"
|
||||
|
||||
using namespace nanogui;
|
||||
|
@ -18,6 +19,9 @@ MainWindow::MainWindow(Widget *parent): ContentWindow(parent, "Moonlight") {
|
|||
set_right_title_button(FA_SYNC, [this] {
|
||||
this->reload();
|
||||
});
|
||||
set_right_title_button(FA_GAMEPAD, [this] {
|
||||
push<InputSettingsWindow>();
|
||||
});
|
||||
set_right_title_button(FA_COG, [this] {
|
||||
push<SettingsWindow>();
|
||||
});
|
||||
|
|
|
@ -26,7 +26,7 @@ StreamWindow::StreamWindow(Widget *parent, const std::string &address, int app_i
|
|||
m_session->set_audio_renderer(new DebugFileRecorderAudioRenderer(false));
|
||||
#endif
|
||||
|
||||
m_loader = add<LoadingOverlay>();
|
||||
m_loader = add<LoadingOverlay>("Starting...");
|
||||
|
||||
inc_ref();
|
||||
m_session->start([this](auto result) {
|
||||
|
@ -124,15 +124,15 @@ void StreamWindow::draw(NVGcontext *ctx) {
|
|||
}
|
||||
|
||||
// TODO: Get out of here...
|
||||
if (GAME_PAD_COMBO(DOWN_FLAG)) {
|
||||
if (InputController::controller()->gamepad_combo_is_enabled(GamepadComboExitAndClose)) {
|
||||
async([this] { this->terminate(true); });
|
||||
} else if (GAME_PAD_COMBO(UP_FLAG)) {
|
||||
} else if (InputController::controller()->gamepad_combo_is_enabled(GamepadComboExit)) {
|
||||
async([this] { this->terminate(false); });
|
||||
}
|
||||
|
||||
if (!m_draw_stats && GAME_PAD_COMBO_R(LEFT_FLAG)) {
|
||||
if (!m_draw_stats && InputController::controller()->gamepad_combo_is_enabled(GamepadComboShowStats)) {
|
||||
m_draw_stats = true;
|
||||
} else if (m_draw_stats && GAME_PAD_COMBO_R(RIGHT_FLAG)) {
|
||||
} else if (m_draw_stats && InputController::controller()->gamepad_combo_is_enabled(GamepadComboHideStats)) {
|
||||
m_draw_stats = false;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue