summaryrefslogtreecommitdiff
path: root/src/input_common
diff options
context:
space:
mode:
Diffstat (limited to 'src/input_common')
-rw-r--r--src/input_common/CMakeLists.txt2
-rw-r--r--src/input_common/main.cpp261
-rw-r--r--src/input_common/main.h144
-rw-r--r--src/input_common/sdl/sdl_impl.cpp116
-rw-r--r--src/input_common/settings.h4
-rw-r--r--src/input_common/touch_from_button.cpp50
-rw-r--r--src/input_common/touch_from_button.h23
7 files changed, 388 insertions, 212 deletions
diff --git a/src/input_common/CMakeLists.txt b/src/input_common/CMakeLists.txt
index c673b8389..09361e37e 100644
--- a/src/input_common/CMakeLists.txt
+++ b/src/input_common/CMakeLists.txt
@@ -11,6 +11,8 @@ add_library(input_common STATIC
motion_input.h
settings.cpp
settings.h
+ touch_from_button.cpp
+ touch_from_button.h
gcadapter/gc_adapter.cpp
gcadapter/gc_adapter.h
gcadapter/gc_poller.cpp
diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp
index 8e67a7437..ea1a1cee6 100644
--- a/src/input_common/main.cpp
+++ b/src/input_common/main.cpp
@@ -11,6 +11,7 @@
#include "input_common/keyboard.h"
#include "input_common/main.h"
#include "input_common/motion_emu.h"
+#include "input_common/touch_from_button.h"
#include "input_common/udp/udp.h"
#ifdef HAVE_SDL2
#include "input_common/sdl/sdl.h"
@@ -18,66 +19,176 @@
namespace InputCommon {
-static std::shared_ptr<Keyboard> keyboard;
-static std::shared_ptr<MotionEmu> motion_emu;
+struct InputSubsystem::Impl {
+ void Initialize() {
+ auto gcadapter = std::make_shared<GCAdapter::Adapter>();
+ gcbuttons = std::make_shared<GCButtonFactory>(gcadapter);
+ Input::RegisterFactory<Input::ButtonDevice>("gcpad", gcbuttons);
+ gcanalog = std::make_shared<GCAnalogFactory>(gcadapter);
+ Input::RegisterFactory<Input::AnalogDevice>("gcpad", gcanalog);
+
+ keyboard = std::make_shared<Keyboard>();
+ Input::RegisterFactory<Input::ButtonDevice>("keyboard", keyboard);
+ Input::RegisterFactory<Input::AnalogDevice>("analog_from_button",
+ std::make_shared<AnalogFromButton>());
+ motion_emu = std::make_shared<MotionEmu>();
+ Input::RegisterFactory<Input::MotionDevice>("motion_emu", motion_emu);
+ Input::RegisterFactory<Input::TouchDevice>("touch_from_button",
+ std::make_shared<TouchFromButtonFactory>());
+
#ifdef HAVE_SDL2
-static std::unique_ptr<SDL::State> sdl;
+ sdl = SDL::Init();
#endif
-static std::unique_ptr<CemuhookUDP::State> udp;
-static std::shared_ptr<GCButtonFactory> gcbuttons;
-static std::shared_ptr<GCAnalogFactory> gcanalog;
-
-void Init() {
- auto gcadapter = std::make_shared<GCAdapter::Adapter>();
- gcbuttons = std::make_shared<GCButtonFactory>(gcadapter);
- Input::RegisterFactory<Input::ButtonDevice>("gcpad", gcbuttons);
- gcanalog = std::make_shared<GCAnalogFactory>(gcadapter);
- Input::RegisterFactory<Input::AnalogDevice>("gcpad", gcanalog);
-
- keyboard = std::make_shared<Keyboard>();
- Input::RegisterFactory<Input::ButtonDevice>("keyboard", keyboard);
- Input::RegisterFactory<Input::AnalogDevice>("analog_from_button",
- std::make_shared<AnalogFromButton>());
- motion_emu = std::make_shared<MotionEmu>();
- Input::RegisterFactory<Input::MotionDevice>("motion_emu", motion_emu);
+ udp = CemuhookUDP::Init();
+ }
+
+ void Shutdown() {
+ Input::UnregisterFactory<Input::ButtonDevice>("keyboard");
+ keyboard.reset();
+ Input::UnregisterFactory<Input::AnalogDevice>("analog_from_button");
+ Input::UnregisterFactory<Input::MotionDevice>("motion_emu");
+ motion_emu.reset();
+ Input::UnregisterFactory<Input::TouchDevice>("touch_from_button");
#ifdef HAVE_SDL2
- sdl = SDL::Init();
+ sdl.reset();
#endif
- udp = CemuhookUDP::Init();
-}
+ udp.reset();
+ Input::UnregisterFactory<Input::ButtonDevice>("gcpad");
+ Input::UnregisterFactory<Input::AnalogDevice>("gcpad");
+
+ gcbuttons.reset();
+ gcanalog.reset();
+ }
+
+ [[nodiscard]] std::vector<Common::ParamPackage> GetInputDevices() const {
+ std::vector<Common::ParamPackage> devices = {
+ Common::ParamPackage{{"display", "Any"}, {"class", "any"}},
+ Common::ParamPackage{{"display", "Keyboard/Mouse"}, {"class", "key"}},
+ };
+#ifdef HAVE_SDL2
+ auto sdl_devices = sdl->GetInputDevices();
+ devices.insert(devices.end(), sdl_devices.begin(), sdl_devices.end());
+#endif
+ auto udp_devices = udp->GetInputDevices();
+ devices.insert(devices.end(), udp_devices.begin(), udp_devices.end());
+ return devices;
+ }
+
+ [[nodiscard]] AnalogMapping GetAnalogMappingForDevice(
+ const Common::ParamPackage& params) const {
+ if (!params.Has("class") || params.Get("class", "") == "any") {
+ return {};
+ }
+ if (params.Get("class", "") == "key") {
+ // TODO consider returning the SDL key codes for the default keybindings
+ return {};
+ }
+#ifdef HAVE_SDL2
+ if (params.Get("class", "") == "sdl") {
+ return sdl->GetAnalogMappingForDevice(params);
+ }
+#endif
+ return {};
+ }
+
+ [[nodiscard]] ButtonMapping GetButtonMappingForDevice(
+ const Common::ParamPackage& params) const {
+ if (!params.Has("class") || params.Get("class", "") == "any") {
+ return {};
+ }
+ if (params.Get("class", "") == "key") {
+ // TODO consider returning the SDL key codes for the default keybindings
+ return {};
+ }
+#ifdef HAVE_SDL2
+ if (params.Get("class", "") == "sdl") {
+ return sdl->GetButtonMappingForDevice(params);
+ }
+#endif
+ return {};
+ }
-void Shutdown() {
- Input::UnregisterFactory<Input::ButtonDevice>("keyboard");
- keyboard.reset();
- Input::UnregisterFactory<Input::AnalogDevice>("analog_from_button");
- Input::UnregisterFactory<Input::MotionDevice>("motion_emu");
- motion_emu.reset();
+ std::shared_ptr<Keyboard> keyboard;
+ std::shared_ptr<MotionEmu> motion_emu;
#ifdef HAVE_SDL2
- sdl.reset();
+ std::unique_ptr<SDL::State> sdl;
#endif
- udp.reset();
- Input::UnregisterFactory<Input::ButtonDevice>("gcpad");
- Input::UnregisterFactory<Input::AnalogDevice>("gcpad");
+ std::unique_ptr<CemuhookUDP::State> udp;
+ std::shared_ptr<GCButtonFactory> gcbuttons;
+ std::shared_ptr<GCAnalogFactory> gcanalog;
+};
- gcbuttons.reset();
- gcanalog.reset();
+InputSubsystem::InputSubsystem() : impl{std::make_unique<Impl>()} {}
+
+InputSubsystem::~InputSubsystem() = default;
+
+void InputSubsystem::Initialize() {
+ impl->Initialize();
+}
+
+void InputSubsystem::Shutdown() {
+ impl->Shutdown();
+}
+
+Keyboard* InputSubsystem::GetKeyboard() {
+ return impl->keyboard.get();
+}
+
+const Keyboard* InputSubsystem::GetKeyboard() const {
+ return impl->keyboard.get();
+}
+
+MotionEmu* InputSubsystem::GetMotionEmu() {
+ return impl->motion_emu.get();
}
-Keyboard* GetKeyboard() {
- return keyboard.get();
+const MotionEmu* InputSubsystem::GetMotionEmu() const {
+ return impl->motion_emu.get();
}
-MotionEmu* GetMotionEmu() {
- return motion_emu.get();
+std::vector<Common::ParamPackage> InputSubsystem::GetInputDevices() const {
+ return impl->GetInputDevices();
}
-GCButtonFactory* GetGCButtons() {
- return gcbuttons.get();
+AnalogMapping InputSubsystem::GetAnalogMappingForDevice(const Common::ParamPackage& device) const {
+ return impl->GetAnalogMappingForDevice(device);
}
-GCAnalogFactory* GetGCAnalogs() {
- return gcanalog.get();
+ButtonMapping InputSubsystem::GetButtonMappingForDevice(const Common::ParamPackage& device) const {
+ return impl->GetButtonMappingForDevice(device);
+}
+
+GCAnalogFactory* InputSubsystem::GetGCAnalogs() {
+ return impl->gcanalog.get();
+}
+
+const GCAnalogFactory* InputSubsystem::GetGCAnalogs() const {
+ return impl->gcanalog.get();
+}
+
+GCButtonFactory* InputSubsystem::GetGCButtons() {
+ return impl->gcbuttons.get();
+}
+
+const GCButtonFactory* InputSubsystem::GetGCButtons() const {
+ return impl->gcbuttons.get();
+}
+
+void InputSubsystem::ReloadInputDevices() {
+ if (!impl->udp) {
+ return;
+ }
+ impl->udp->ReloadUDPClient();
+}
+
+std::vector<std::unique_ptr<Polling::DevicePoller>> InputSubsystem::GetPollers(
+ Polling::DeviceType type) const {
+#ifdef HAVE_SDL2
+ return impl->sdl->GetPollers(type);
+#else
+ return {};
+#endif
}
std::string GenerateKeyboardParam(int key_code) {
@@ -101,68 +212,4 @@ std::string GenerateAnalogParamFromKeys(int key_up, int key_down, int key_left,
};
return circle_pad_param.Serialize();
}
-
-std::vector<Common::ParamPackage> GetInputDevices() {
- std::vector<Common::ParamPackage> devices = {
- Common::ParamPackage{{"display", "Any"}, {"class", "any"}},
- Common::ParamPackage{{"display", "Keyboard/Mouse"}, {"class", "key"}},
- };
-#ifdef HAVE_SDL2
- auto sdl_devices = sdl->GetInputDevices();
- devices.insert(devices.end(), sdl_devices.begin(), sdl_devices.end());
-#endif
- auto udp_devices = udp->GetInputDevices();
- devices.insert(devices.end(), udp_devices.begin(), udp_devices.end());
- return devices;
-}
-
-std::unordered_map<Settings::NativeButton::Values, Common::ParamPackage> GetButtonMappingForDevice(
- const Common::ParamPackage& params) {
- std::unordered_map<Settings::NativeButton::Values, Common::ParamPackage> mappings;
- if (!params.Has("class") || params.Get("class", "") == "any") {
- return {};
- }
- if (params.Get("class", "") == "key") {
- // TODO consider returning the SDL key codes for the default keybindings
- return {};
- }
-#ifdef HAVE_SDL2
- if (params.Get("class", "") == "sdl") {
- return sdl->GetButtonMappingForDevice(params);
- }
-#endif
- return {};
-}
-
-std::unordered_map<Settings::NativeAnalog::Values, Common::ParamPackage> GetAnalogMappingForDevice(
- const Common::ParamPackage& params) {
- std::unordered_map<Settings::NativeAnalog::Values, Common::ParamPackage> mappings;
- if (!params.Has("class") || params.Get("class", "") == "any") {
- return {};
- }
- if (params.Get("class", "") == "key") {
- // TODO consider returning the SDL key codes for the default keybindings
- return {};
- }
-#ifdef HAVE_SDL2
- if (params.Get("class", "") == "sdl") {
- return sdl->GetAnalogMappingForDevice(params);
- }
-#endif
- return {};
-}
-
-namespace Polling {
-
-std::vector<std::unique_ptr<DevicePoller>> GetPollers(DeviceType type) {
- std::vector<std::unique_ptr<DevicePoller>> pollers;
-
-#ifdef HAVE_SDL2
- pollers = sdl->GetPollers(type);
-#endif
-
- return pollers;
-}
-
-} // namespace Polling
} // namespace InputCommon
diff --git a/src/input_common/main.h b/src/input_common/main.h
index e706c3750..f3fbf696e 100644
--- a/src/input_common/main.h
+++ b/src/input_common/main.h
@@ -8,60 +8,20 @@
#include <string>
#include <unordered_map>
#include <vector>
-#include "input_common/gcadapter/gc_poller.h"
-#include "input_common/settings.h"
namespace Common {
class ParamPackage;
}
-namespace InputCommon {
-
-/// Initializes and registers all built-in input device factories.
-void Init();
-
-/// Deregisters all built-in input device factories and shuts them down.
-void Shutdown();
-
-class Keyboard;
-
-/// Gets the keyboard button device factory.
-Keyboard* GetKeyboard();
-
-class MotionEmu;
-
-/// Gets the motion emulation factory.
-MotionEmu* GetMotionEmu();
-
-GCButtonFactory* GetGCButtons();
-
-GCAnalogFactory* GetGCAnalogs();
-
-/// Generates a serialized param package for creating a keyboard button device
-std::string GenerateKeyboardParam(int key_code);
-
-/// Generates a serialized param package for creating an analog device taking input from keyboard
-std::string GenerateAnalogParamFromKeys(int key_up, int key_down, int key_left, int key_right,
- int key_modifier, float modifier_scale);
-
-/**
- * Return a list of available input devices that this Factory can create a new device with.
- * Each returned Parampackage should have a `display` field used for display, a class field for
- * backends to determine if this backend is meant to service the request and any other information
- * needed to identify this in the backend later.
- */
-std::vector<Common::ParamPackage> GetInputDevices();
-
-/**
- * Given a ParamPackage for a Device returned from `GetInputDevices`, attempt to get the default
- * mapping for the device. This is currently only implemented for the sdl backend devices.
- */
-using ButtonMapping = std::unordered_map<Settings::NativeButton::Values, Common::ParamPackage>;
-using AnalogMapping = std::unordered_map<Settings::NativeAnalog::Values, Common::ParamPackage>;
+namespace Settings::NativeAnalog {
+enum Values : int;
+}
-ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage&);
-AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage&);
+namespace Settings::NativeButton {
+enum Values : int;
+}
+namespace InputCommon {
namespace Polling {
enum class DeviceType { Button, AnalogPreferred };
@@ -86,8 +46,92 @@ public:
*/
virtual Common::ParamPackage GetNextInput() = 0;
};
-
-// Get all DevicePoller from all backends for a specific device type
-std::vector<std::unique_ptr<DevicePoller>> GetPollers(DeviceType type);
} // namespace Polling
+
+class GCAnalogFactory;
+class GCButtonFactory;
+class Keyboard;
+class MotionEmu;
+
+/**
+ * Given a ParamPackage for a Device returned from `GetInputDevices`, attempt to get the default
+ * mapping for the device. This is currently only implemented for the SDL backend devices.
+ */
+using AnalogMapping = std::unordered_map<Settings::NativeAnalog::Values, Common::ParamPackage>;
+using ButtonMapping = std::unordered_map<Settings::NativeButton::Values, Common::ParamPackage>;
+
+class InputSubsystem {
+public:
+ explicit InputSubsystem();
+ ~InputSubsystem();
+
+ InputSubsystem(const InputSubsystem&) = delete;
+ InputSubsystem& operator=(const InputSubsystem&) = delete;
+
+ InputSubsystem(InputSubsystem&&) = delete;
+ InputSubsystem& operator=(InputSubsystem&&) = delete;
+
+ /// Initializes and registers all built-in input device factories.
+ void Initialize();
+
+ /// Unregisters all built-in input device factories and shuts them down.
+ void Shutdown();
+
+ /// Retrieves the underlying keyboard device.
+ [[nodiscard]] Keyboard* GetKeyboard();
+
+ /// Retrieves the underlying keyboard device.
+ [[nodiscard]] const Keyboard* GetKeyboard() const;
+
+ /// Retrieves the underlying motion emulation factory.
+ [[nodiscard]] MotionEmu* GetMotionEmu();
+
+ /// Retrieves the underlying motion emulation factory.
+ [[nodiscard]] const MotionEmu* GetMotionEmu() const;
+
+ /**
+ * Returns all available input devices that this Factory can create a new device with.
+ * Each returned ParamPackage should have a `display` field used for display, a class field for
+ * backends to determine if this backend is meant to service the request and any other
+ * information needed to identify this in the backend later.
+ */
+ [[nodiscard]] std::vector<Common::ParamPackage> GetInputDevices() const;
+
+ /// Retrieves the analog mappings for the given device.
+ [[nodiscard]] AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage& device) const;
+
+ /// Retrieves the button mappings for the given device.
+ [[nodiscard]] ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage& device) const;
+
+ /// Retrieves the underlying GameCube analog handler.
+ [[nodiscard]] GCAnalogFactory* GetGCAnalogs();
+
+ /// Retrieves the underlying GameCube analog handler.
+ [[nodiscard]] const GCAnalogFactory* GetGCAnalogs() const;
+
+ /// Retrieves the underlying GameCube button handler.
+ [[nodiscard]] GCButtonFactory* GetGCButtons();
+
+ /// Retrieves the underlying GameCube button handler.
+ [[nodiscard]] const GCButtonFactory* GetGCButtons() const;
+
+ /// Reloads the input devices
+ void ReloadInputDevices();
+
+ /// Get all DevicePoller from all backends for a specific device type
+ [[nodiscard]] std::vector<std::unique_ptr<Polling::DevicePoller>> GetPollers(
+ Polling::DeviceType type) const;
+
+private:
+ struct Impl;
+ std::unique_ptr<Impl> impl;
+};
+
+/// Generates a serialized param package for creating a keyboard button device
+std::string GenerateKeyboardParam(int key_code);
+
+/// Generates a serialized param package for creating an analog device taking input from keyboard
+std::string GenerateAnalogParamFromKeys(int key_up, int key_down, int key_left, int key_right,
+ int key_modifier, float modifier_scale);
+
} // namespace InputCommon
diff --git a/src/input_common/sdl/sdl_impl.cpp b/src/input_common/sdl/sdl_impl.cpp
index 7605c884d..a9e676f4b 100644
--- a/src/input_common/sdl/sdl_impl.cpp
+++ b/src/input_common/sdl/sdl_impl.cpp
@@ -3,6 +3,7 @@
// Refer to the license.txt file included.
#include <algorithm>
+#include <array>
#include <atomic>
#include <cmath>
#include <functional>
@@ -17,11 +18,11 @@
#include <vector>
#include <SDL.h>
#include "common/logging/log.h"
-#include "common/math_util.h"
#include "common/param_package.h"
#include "common/threadsafe_queue.h"
#include "core/frontend/input.h"
#include "input_common/sdl/sdl_impl.h"
+#include "input_common/settings.h"
namespace InputCommon::SDL {
@@ -358,7 +359,7 @@ public:
return std::make_tuple(x / r * (r - deadzone) / (1 - deadzone),
y / r * (r - deadzone) / (1 - deadzone));
}
- return std::make_tuple<float, float>(0.0f, 0.0f);
+ return {};
}
bool GetAnalogDirectionStatus(Input::AnalogDirection direction) const override {
@@ -574,10 +575,10 @@ std::vector<Common::ParamPackage> SDLState::GetInputDevices() {
namespace {
Common::ParamPackage BuildAnalogParamPackageForButton(int port, std::string guid, u8 axis,
- float value = 0.1) {
+ float value = 0.1f) {
Common::ParamPackage params({{"engine", "sdl"}});
params.Set("port", port);
- params.Set("guid", guid);
+ params.Set("guid", std::move(guid));
params.Set("axis", axis);
if (value > 0) {
params.Set("direction", "+");
@@ -592,7 +593,7 @@ Common::ParamPackage BuildAnalogParamPackageForButton(int port, std::string guid
Common::ParamPackage BuildButtonParamPackageForButton(int port, std::string guid, u8 button) {
Common::ParamPackage params({{"engine", "sdl"}});
params.Set("port", port);
- params.Set("guid", guid);
+ params.Set("guid", std::move(guid));
params.Set("button", button);
return params;
}
@@ -601,7 +602,7 @@ Common::ParamPackage BuildHatParamPackageForButton(int port, std::string guid, u
Common::ParamPackage params({{"engine", "sdl"}});
params.Set("port", port);
- params.Set("guid", guid);
+ params.Set("guid", std::move(guid));
params.Set("hat", hat);
switch (value) {
case SDL_HAT_UP:
@@ -670,55 +671,62 @@ Common::ParamPackage BuildParamPackageForAnalog(int port, const std::string& gui
} // Anonymous namespace
ButtonMapping SDLState::GetButtonMappingForDevice(const Common::ParamPackage& params) {
- // This list is missing ZL/ZR since those are not considered buttons in SDL GameController.
- // We will add those afterwards
- // This list also excludes Screenshot since theres not really a mapping for that
- std::unordered_map<Settings::NativeButton::Values, SDL_GameControllerButton>
- switch_to_sdl_button = {
- {Settings::NativeButton::A, SDL_CONTROLLER_BUTTON_B},
- {Settings::NativeButton::B, SDL_CONTROLLER_BUTTON_A},
- {Settings::NativeButton::X, SDL_CONTROLLER_BUTTON_Y},
- {Settings::NativeButton::Y, SDL_CONTROLLER_BUTTON_X},
- {Settings::NativeButton::LStick, SDL_CONTROLLER_BUTTON_LEFTSTICK},
- {Settings::NativeButton::RStick, SDL_CONTROLLER_BUTTON_RIGHTSTICK},
- {Settings::NativeButton::L, SDL_CONTROLLER_BUTTON_LEFTSHOULDER},
- {Settings::NativeButton::R, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER},
- {Settings::NativeButton::Plus, SDL_CONTROLLER_BUTTON_START},
- {Settings::NativeButton::Minus, SDL_CONTROLLER_BUTTON_BACK},
- {Settings::NativeButton::DLeft, SDL_CONTROLLER_BUTTON_DPAD_LEFT},
- {Settings::NativeButton::DUp, SDL_CONTROLLER_BUTTON_DPAD_UP},
- {Settings::NativeButton::DRight, SDL_CONTROLLER_BUTTON_DPAD_RIGHT},
- {Settings::NativeButton::DDown, SDL_CONTROLLER_BUTTON_DPAD_DOWN},
- {Settings::NativeButton::SL, SDL_CONTROLLER_BUTTON_LEFTSHOULDER},
- {Settings::NativeButton::SR, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER},
- {Settings::NativeButton::Home, SDL_CONTROLLER_BUTTON_GUIDE},
- };
if (!params.Has("guid") || !params.Has("port")) {
return {};
}
const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0));
- auto controller = joystick->GetSDLGameController();
- if (!controller) {
+ auto* controller = joystick->GetSDLGameController();
+ if (controller == nullptr) {
return {};
}
- ButtonMapping mapping{};
+ // This list is missing ZL/ZR since those are not considered buttons in SDL GameController.
+ // We will add those afterwards
+ // This list also excludes Screenshot since theres not really a mapping for that
+ using ButtonBindings =
+ std::array<std::pair<Settings::NativeButton::Values, SDL_GameControllerButton>, 17>;
+ static constexpr ButtonBindings switch_to_sdl_button{{
+ {Settings::NativeButton::A, SDL_CONTROLLER_BUTTON_B},
+ {Settings::NativeButton::B, SDL_CONTROLLER_BUTTON_A},
+ {Settings::NativeButton::X, SDL_CONTROLLER_BUTTON_Y},
+ {Settings::NativeButton::Y, SDL_CONTROLLER_BUTTON_X},
+ {Settings::NativeButton::LStick, SDL_CONTROLLER_BUTTON_LEFTSTICK},
+ {Settings::NativeButton::RStick, SDL_CONTROLLER_BUTTON_RIGHTSTICK},
+ {Settings::NativeButton::L, SDL_CONTROLLER_BUTTON_LEFTSHOULDER},
+ {Settings::NativeButton::R, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER},
+ {Settings::NativeButton::Plus, SDL_CONTROLLER_BUTTON_START},
+ {Settings::NativeButton::Minus, SDL_CONTROLLER_BUTTON_BACK},
+ {Settings::NativeButton::DLeft, SDL_CONTROLLER_BUTTON_DPAD_LEFT},
+ {Settings::NativeButton::DUp, SDL_CONTROLLER_BUTTON_DPAD_UP},
+ {Settings::NativeButton::DRight, SDL_CONTROLLER_BUTTON_DPAD_RIGHT},
+ {Settings::NativeButton::DDown, SDL_CONTROLLER_BUTTON_DPAD_DOWN},
+ {Settings::NativeButton::SL, SDL_CONTROLLER_BUTTON_LEFTSHOULDER},
+ {Settings::NativeButton::SR, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER},
+ {Settings::NativeButton::Home, SDL_CONTROLLER_BUTTON_GUIDE},
+ }};
+
+ // Add the missing bindings for ZL/ZR
+ using ZBindings =
+ std::array<std::pair<Settings::NativeButton::Values, SDL_GameControllerAxis>, 2>;
+ static constexpr ZBindings switch_to_sdl_axis{{
+ {Settings::NativeButton::ZL, SDL_CONTROLLER_AXIS_TRIGGERLEFT},
+ {Settings::NativeButton::ZR, SDL_CONTROLLER_AXIS_TRIGGERRIGHT},
+ }};
+
+ ButtonMapping mapping;
+ mapping.reserve(switch_to_sdl_button.size() + switch_to_sdl_axis.size());
+
for (const auto& [switch_button, sdl_button] : switch_to_sdl_button) {
const auto& binding = SDL_GameControllerGetBindForButton(controller, sdl_button);
- mapping[switch_button] =
- BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding);
+ mapping.insert_or_assign(
+ switch_button,
+ BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding));
}
-
- // Add the missing bindings for ZL/ZR
- std::unordered_map<Settings::NativeButton::Values, SDL_GameControllerAxis> switch_to_sdl_axis =
- {
- {Settings::NativeButton::ZL, SDL_CONTROLLER_AXIS_TRIGGERLEFT},
- {Settings::NativeButton::ZR, SDL_CONTROLLER_AXIS_TRIGGERRIGHT},
- };
for (const auto& [switch_button, sdl_axis] : switch_to_sdl_axis) {
const auto& binding = SDL_GameControllerGetBindForAxis(controller, sdl_axis);
- mapping[switch_button] =
- BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding);
+ mapping.insert_or_assign(
+ switch_button,
+ BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding));
}
return mapping;
@@ -729,8 +737,8 @@ AnalogMapping SDLState::GetAnalogMappingForDevice(const Common::ParamPackage& pa
return {};
}
const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0));
- auto controller = joystick->GetSDLGameController();
- if (!controller) {
+ auto* controller = joystick->GetSDLGameController();
+ if (controller == nullptr) {
return {};
}
@@ -739,16 +747,18 @@ AnalogMapping SDLState::GetAnalogMappingForDevice(const Common::ParamPackage& pa
SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTX);
const auto& binding_left_y =
SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTY);
- mapping[Settings::NativeAnalog::LStick] =
- BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(),
- binding_left_x.value.axis, binding_left_y.value.axis);
+ mapping.insert_or_assign(Settings::NativeAnalog::LStick,
+ BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(),
+ binding_left_x.value.axis,
+ binding_left_y.value.axis));
const auto& binding_right_x =
SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX);
const auto& binding_right_y =
SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY);
- mapping[Settings::NativeAnalog::RStick] =
- BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(),
- binding_right_x.value.axis, binding_right_y.value.axis);
+ mapping.insert_or_assign(Settings::NativeAnalog::RStick,
+ BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(),
+ binding_right_x.value.axis,
+ binding_right_y.value.axis));
return mapping;
}
@@ -784,7 +794,7 @@ public:
}
return {};
}
- std::optional<Common::ParamPackage> FromEvent(const SDL_Event& event) {
+ [[nodiscard]] std::optional<Common::ParamPackage> FromEvent(const SDL_Event& event) const {
switch (event.type) {
case SDL_JOYAXISMOTION:
if (std::abs(event.jaxis.value / 32767.0) < 0.5) {
@@ -795,7 +805,7 @@ public:
case SDL_JOYHATMOTION:
return {SDLEventToButtonParamPackage(state, event)};
}
- return {};
+ return std::nullopt;
}
};
diff --git a/src/input_common/settings.h b/src/input_common/settings.h
index 8e481a7fe..2d258960b 100644
--- a/src/input_common/settings.h
+++ b/src/input_common/settings.h
@@ -10,7 +10,7 @@
namespace Settings {
namespace NativeButton {
-enum Values {
+enum Values : int {
A,
B,
X,
@@ -52,7 +52,7 @@ extern const std::array<const char*, NumButtons> mapping;
} // namespace NativeButton
namespace NativeAnalog {
-enum Values {
+enum Values : int {
LStick,
RStick,
diff --git a/src/input_common/touch_from_button.cpp b/src/input_common/touch_from_button.cpp
new file mode 100644
index 000000000..98da0ef1a
--- /dev/null
+++ b/src/input_common/touch_from_button.cpp
@@ -0,0 +1,50 @@
+// Copyright 2020 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include "core/frontend/framebuffer_layout.h"
+#include "core/settings.h"
+#include "input_common/touch_from_button.h"
+
+namespace InputCommon {
+
+class TouchFromButtonDevice final : public Input::TouchDevice {
+public:
+ TouchFromButtonDevice() {
+ for (const auto& config_entry :
+ Settings::values.touch_from_button_maps[Settings::values.touch_from_button_map_index]
+ .buttons) {
+ const Common::ParamPackage package{config_entry};
+ map.emplace_back(
+ Input::CreateDevice<Input::ButtonDevice>(config_entry),
+ std::clamp(package.Get("x", 0), 0, static_cast<int>(Layout::ScreenUndocked::Width)),
+ std::clamp(package.Get("y", 0), 0,
+ static_cast<int>(Layout::ScreenUndocked::Height)));
+ }
+ }
+
+ std::tuple<float, float, bool> GetStatus() const override {
+ for (const auto& m : map) {
+ const bool state = std::get<0>(m)->GetStatus();
+ if (state) {
+ const float x = static_cast<float>(std::get<1>(m)) /
+ static_cast<int>(Layout::ScreenUndocked::Width);
+ const float y = static_cast<float>(std::get<2>(m)) /
+ static_cast<int>(Layout::ScreenUndocked::Height);
+ return {x, y, true};
+ }
+ }
+ return {};
+ }
+
+private:
+ // A vector of the mapped button, its x and its y-coordinate
+ std::vector<std::tuple<std::unique_ptr<Input::ButtonDevice>, int, int>> map;
+};
+
+std::unique_ptr<Input::TouchDevice> TouchFromButtonFactory::Create(
+ const Common::ParamPackage& params) {
+ return std::make_unique<TouchFromButtonDevice>();
+}
+
+} // namespace InputCommon
diff --git a/src/input_common/touch_from_button.h b/src/input_common/touch_from_button.h
new file mode 100644
index 000000000..8b4d1aa96
--- /dev/null
+++ b/src/input_common/touch_from_button.h
@@ -0,0 +1,23 @@
+// Copyright 2020 Citra Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <memory>
+#include "core/frontend/input.h"
+
+namespace InputCommon {
+
+/**
+ * A touch device factory that takes a list of button devices and combines them into a touch device.
+ */
+class TouchFromButtonFactory final : public Input::Factory<Input::TouchDevice> {
+public:
+ /**
+ * Creates a touch device from a list of button devices
+ */
+ std::unique_ptr<Input::TouchDevice> Create(const Common::ParamPackage& params) override;
+};
+
+} // namespace InputCommon