Implement button/combo remapping...

This commit is contained in:
rock88 2020-06-12 17:09:57 +03:00
parent ba1e479b4e
commit b0badb2169
13 changed files with 702 additions and 132 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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) {

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

View 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);
};

View file

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

View file

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