From 29ae42f3e2c297898d88858861f7d860ce9fc2f3 Mon Sep 17 00:00:00 2001 From: german77 Date: Mon, 20 Sep 2021 17:43:13 -0500 Subject: [PATCH] input_common: Rewrite main and add the new drivers --- src/input_common/main.cpp | 292 ++++++++++++++++++++++++++++++++++++-- src/input_common/main.h | 89 +++++++----- 2 files changed, 331 insertions(+), 50 deletions(-) diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp index da501b6cc..46ca6b76c 100644 --- a/src/input_common/main.cpp +++ b/src/input_common/main.cpp @@ -4,54 +4,265 @@ #include #include +#include "common/input.h" #include "common/param_package.h" -#include "common/settings.h" +#include "input_common/drivers/gc_adapter.h" +#include "input_common/drivers/keyboard.h" +#include "input_common/drivers/mouse.h" +#include "input_common/drivers/tas_input.h" +#include "input_common/drivers/touch_screen.h" +#include "input_common/drivers/udp_client.h" +#include "input_common/helpers/stick_from_buttons.h" +#include "input_common/helpers/touch_from_buttons.h" +#include "input_common/input_engine.h" +#include "input_common/input_mapping.h" +#include "input_common/input_poller.h" #include "input_common/main.h" #ifdef HAVE_SDL2 -#include "input_common/sdl/sdl.h" +#include "input_common/drivers/sdl_driver.h" #endif namespace InputCommon { struct InputSubsystem::Impl { void Initialize() { + mapping_factory = std::make_shared(); + MappingCallback mapping_callback{[this](MappingData data) { RegisterInput(data); }}; + + keyboard = std::make_shared("keyboard"); + keyboard->SetMappingCallback(mapping_callback); + keyboard_factory = std::make_shared(keyboard); + Input::RegisterFactory(keyboard->GetEngineName(), keyboard_factory); + + mouse = std::make_shared("mouse"); + mouse->SetMappingCallback(mapping_callback); + mouse_factory = std::make_shared(mouse); + Input::RegisterFactory(mouse->GetEngineName(), mouse_factory); + + touch_screen = std::make_shared("touch"); + touch_screen_factory = std::make_shared(touch_screen); + Input::RegisterFactory(touch_screen->GetEngineName(), + touch_screen_factory); + + gcadapter = std::make_shared("gcpad"); + gcadapter->SetMappingCallback(mapping_callback); + gcadapter_factory = std::make_shared(gcadapter); + Input::RegisterFactory(gcadapter->GetEngineName(), gcadapter_factory); + + udp_client = std::make_shared("cemuhookudp"); + udp_client->SetMappingCallback(mapping_callback); + udp_client_factory = std::make_shared(udp_client); + Input::RegisterFactory(udp_client->GetEngineName(), udp_client_factory); + + tas_input = std::make_shared("tas"); + tas_input->SetMappingCallback(mapping_callback); + tas_input_factory = std::make_shared(tas_input); + Input::RegisterFactory(tas_input->GetEngineName(), tas_input_factory); + +#ifdef HAVE_SDL2 + sdl = std::make_shared("sdl"); + sdl->SetMappingCallback(mapping_callback); + sdl_factory = std::make_shared(sdl); + Input::RegisterFactory(sdl->GetEngineName(), sdl_factory); +#endif + + Input::RegisterFactory("touch_from_button", + std::make_shared()); + Input::RegisterFactory("analog_from_button", + std::make_shared()); } void Shutdown() { + Input::UnregisterFactory(keyboard->GetEngineName()); + keyboard.reset(); + + Input::UnregisterFactory(mouse->GetEngineName()); + mouse.reset(); + + Input::UnregisterFactory(touch_screen->GetEngineName()); + touch_screen.reset(); + + Input::UnregisterFactory(gcadapter->GetEngineName()); + gcadapter.reset(); + + Input::UnregisterFactory(udp_client->GetEngineName()); + udp_client.reset(); + + Input::UnregisterFactory(tas_input->GetEngineName()); + tas_input.reset(); + +#ifdef HAVE_SDL2 + Input::UnregisterFactory(sdl->GetEngineName()); + sdl.reset(); +#endif + + Input::UnregisterFactory("touch_from_button"); + Input::UnregisterFactory("analog_from_button"); } [[nodiscard]] std::vector GetInputDevices() const { std::vector devices = { - Common::ParamPackage{{"display", "Any"}, {"class", "any"}}, - Common::ParamPackage{{"display", "Keyboard/Mouse"}, {"class", "keyboard"}}, + Common::ParamPackage{{"display", "Any"}, {"engine", "any"}}, }; - return {}; + + auto keyboard_devices = keyboard->GetInputDevices(); + devices.insert(devices.end(), keyboard_devices.begin(), keyboard_devices.end()); + auto mouse_devices = mouse->GetInputDevices(); + devices.insert(devices.end(), mouse_devices.begin(), mouse_devices.end()); + auto gcadapter_devices = gcadapter->GetInputDevices(); + devices.insert(devices.end(), gcadapter_devices.begin(), gcadapter_devices.end()); + auto tas_input_devices = tas_input->GetInputDevices(); + devices.insert(devices.end(), tas_input_devices.begin(), tas_input_devices.end()); +#ifdef HAVE_SDL2 + auto sdl_devices = sdl->GetInputDevices(); + devices.insert(devices.end(), sdl_devices.begin(), sdl_devices.end()); +#endif + + return devices; } [[nodiscard]] AnalogMapping GetAnalogMappingForDevice( const Common::ParamPackage& params) const { - if (!params.Has("class") || params.Get("class", "") == "any") { + if (!params.Has("engine") || params.Get("engine", "") == "any") { return {}; } + const std::string engine = params.Get("engine", ""); + if (engine == gcadapter->GetEngineName()) { + return gcadapter->GetAnalogMappingForDevice(params); + } + if (engine == tas_input->GetEngineName()) { + return tas_input->GetAnalogMappingForDevice(params); + } +#ifdef HAVE_SDL2 + if (engine == sdl->GetEngineName()) { + return sdl->GetAnalogMappingForDevice(params); + } +#endif return {}; } [[nodiscard]] ButtonMapping GetButtonMappingForDevice( const Common::ParamPackage& params) const { - if (!params.Has("class") || params.Get("class", "") == "any") { + if (!params.Has("engine") || params.Get("engine", "") == "any") { return {}; } + const std::string engine = params.Get("engine", ""); + if (engine == gcadapter->GetEngineName()) { + return gcadapter->GetButtonMappingForDevice(params); + } + if (engine == tas_input->GetEngineName()) { + return tas_input->GetButtonMappingForDevice(params); + } +#ifdef HAVE_SDL2 + if (engine == sdl->GetEngineName()) { + return sdl->GetButtonMappingForDevice(params); + } +#endif return {}; } [[nodiscard]] MotionMapping GetMotionMappingForDevice( const Common::ParamPackage& params) const { - if (!params.Has("class") || params.Get("class", "") == "any") { + if (!params.Has("engine") || params.Get("engine", "") == "any") { return {}; } + const std::string engine = params.Get("engine", ""); + if (engine == gcadapter->GetEngineName()) { + return gcadapter->GetMotionMappingForDevice(params); + } +#ifdef HAVE_SDL2 + if (engine == sdl->GetEngineName()) { + return sdl->GetMotionMappingForDevice(params); + } +#endif return {}; } + std::string GetButtonName(const Common::ParamPackage& params) const { + if (!params.Has("engine") || params.Get("engine", "") == "any") { + return "Unknown"; + } + const std::string engine = params.Get("engine", ""); + if (engine == mouse->GetEngineName()) { + return mouse->GetUIName(params); + } + if (engine == gcadapter->GetEngineName()) { + return gcadapter->GetUIName(params); + } + if (engine == udp_client->GetEngineName()) { + return udp_client->GetUIName(params); + } + if (engine == tas_input->GetEngineName()) { + return tas_input->GetUIName(params); + } +#ifdef HAVE_SDL2 + if (engine == sdl->GetEngineName()) { + return sdl->GetUIName(params); + } +#endif + return "Bad engine"; + } + + bool IsController(const Common::ParamPackage& params) { + const std::string engine = params.Get("engine", ""); + if (engine == mouse->GetEngineName()) { + return true; + } + if (engine == gcadapter->GetEngineName()) { + return true; + } + if (engine == tas_input->GetEngineName()) { + return true; + } +#ifdef HAVE_SDL2 + if (engine == sdl->GetEngineName()) { + return true; + } +#endif + return false; + } + + void BeginConfiguration() { + keyboard->BeginConfiguration(); + mouse->BeginConfiguration(); + gcadapter->BeginConfiguration(); + udp_client->BeginConfiguration(); +#ifdef HAVE_SDL2 + sdl->BeginConfiguration(); +#endif + } + + void EndConfiguration() { + keyboard->EndConfiguration(); + mouse->EndConfiguration(); + gcadapter->EndConfiguration(); + udp_client->EndConfiguration(); +#ifdef HAVE_SDL2 + sdl->EndConfiguration(); +#endif + } + + void RegisterInput(MappingData data) { + mapping_factory->RegisterInput(data); + } + + std::shared_ptr mapping_factory; + std::shared_ptr keyboard; + std::shared_ptr keyboard_factory; + std::shared_ptr mouse; + std::shared_ptr mouse_factory; + std::shared_ptr gcadapter; + std::shared_ptr gcadapter_factory; + std::shared_ptr touch_screen; + std::shared_ptr touch_screen_factory; + std::shared_ptr udp_client; + std::shared_ptr udp_client_factory; + std::shared_ptr tas_input; + std::shared_ptr tas_input_factory; +#ifdef HAVE_SDL2 + std::shared_ptr sdl; + std::shared_ptr sdl_factory; +#endif }; InputSubsystem::InputSubsystem() : impl{std::make_unique()} {} @@ -66,6 +277,38 @@ void InputSubsystem::Shutdown() { impl->Shutdown(); } +Keyboard* InputSubsystem::GetKeyboard() { + return impl->keyboard.get(); +} + +const Keyboard* InputSubsystem::GetKeyboard() const { + return impl->keyboard.get(); +} + +Mouse* InputSubsystem::GetMouse() { + return impl->mouse.get(); +} + +const Mouse* InputSubsystem::GetMouse() const { + return impl->mouse.get(); +} + +TouchScreen* InputSubsystem::GetTouchScreen() { + return impl->touch_screen.get(); +} + +const TouchScreen* InputSubsystem::GetTouchScreen() const { + return impl->touch_screen.get(); +} + +TasInput::Tas* InputSubsystem::GetTas() { + return impl->tas_input.get(); +} + +const TasInput::Tas* InputSubsystem::GetTas() const { + return impl->tas_input.get(); +} + std::vector InputSubsystem::GetInputDevices() const { return impl->GetInputDevices(); } @@ -82,12 +325,37 @@ MotionMapping InputSubsystem::GetMotionMappingForDevice(const Common::ParamPacka return impl->GetMotionMappingForDevice(device); } -void InputSubsystem::ReloadInputDevices() { +std::string InputSubsystem::GetButtonName(const Common::ParamPackage& params) const { + const std::string toggle = params.Get("toggle", false) ? "~" : ""; + const std::string inverted = params.Get("inverted", false) ? "!" : ""; + const std::string button_name = impl->GetButtonName(params); + std::string axis_direction = ""; + if (params.Has("axis")) { + axis_direction = params.Get("invert", "+"); + } + return fmt::format("{}{}{}{}", toggle, inverted, button_name, axis_direction); } -std::vector> InputSubsystem::GetPollers([ - [maybe_unused]] Polling::DeviceType type) const { - return {}; +bool InputSubsystem::IsController(const Common::ParamPackage& params) const { + return impl->IsController(params); +} + +void InputSubsystem::ReloadInputDevices() { + impl->udp_client.get()->ReloadSockets(); +} + +void InputSubsystem::BeginMapping(Polling::InputType type) { + impl->BeginConfiguration(); + impl->mapping_factory->BeginMapping(type); +} + +const Common::ParamPackage InputSubsystem::GetNextInput() const { + return impl->mapping_factory->GetNextInput(); +} + +void InputSubsystem::StopMapping() const { + impl->EndConfiguration(); + impl->mapping_factory->StopMapping(); } std::string GenerateKeyboardParam(int key_code) { diff --git a/src/input_common/main.h b/src/input_common/main.h index b504ebe54..a4a24d076 100644 --- a/src/input_common/main.h +++ b/src/input_common/main.h @@ -25,47 +25,26 @@ namespace Settings::NativeMotion { enum Values : int; } -namespace MouseInput { +namespace InputCommon { +class Keyboard; class Mouse; -} +class TouchScreen; +struct MappingData; +} // namespace InputCommon -namespace TasInput { +namespace InputCommon::TasInput { class Tas; -} +} // namespace InputCommon::TasInput namespace InputCommon { namespace Polling { - -enum class DeviceType { Button, AnalogPreferred, Motion }; - /// Type of input desired for mapping purposes enum class InputType { None, Button, Stick, Motion, Touch }; - -/** - * A class that can be used to get inputs from an input device like controllers without having to - * poll the device's status yourself - */ -class DevicePoller { -public: - virtual ~DevicePoller() = default; - /// Setup and start polling for inputs, should be called before GetNextInput - /// If a device_id is provided, events should be filtered to only include events from this - /// device id - virtual void Start(const std::string& device_id = "") = 0; - /// Stop polling - virtual void Stop() = 0; - /** - * Every call to this function returns the next input recorded since calling Start - * @return A ParamPackage of the recorded input, which can be used to create an InputDevice. - * If there has been no input, the package is empty - */ - virtual Common::ParamPackage GetNextInput() = 0; -}; } // namespace Polling /** * 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. + * mapping for the device. */ using AnalogMapping = std::unordered_map; using ButtonMapping = std::unordered_map; @@ -88,10 +67,34 @@ public: /// 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 mouse device. + [[nodiscard]] Mouse* GetMouse(); + + /// Retrieves the underlying mouse device. + [[nodiscard]] const Mouse* GetMouse() const; + + /// Retrieves the underlying touch screen device. + [[nodiscard]] TouchScreen* GetTouchScreen(); + + /// Retrieves the underlying touch screen device. + [[nodiscard]] const TouchScreen* GetTouchScreen() const; + + /// Retrieves the underlying tas input device. + [[nodiscard]] TasInput::Tas* GetTas(); + + /// Retrieves the underlying tas input device. + [[nodiscard]] const TasInput::Tas* GetTas() 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 + * Each returned ParamPackage should have a `display` field used for display, a `engine` 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 GetInputDevices() const; @@ -105,23 +108,33 @@ public: /// Retrieves the motion mappings for the given device. [[nodiscard]] MotionMapping GetMotionMappingForDevice(const Common::ParamPackage& device) const; - /// Reloads the input devices + /// Returns a string contaning the name of the button from the input engine. + [[nodiscard]] std::string GetButtonName(const Common::ParamPackage& params) const; + + /// Returns true if device is a controller. + [[nodiscard]] bool IsController(const Common::ParamPackage& params) const; + + /// Reloads the input devices. void ReloadInputDevices(); - /// Get all DevicePoller from all backends for a specific device type - [[nodiscard]] std::vector> GetPollers( - Polling::DeviceType type) const; + /// Start polling from all backends for a desired input type. + void BeginMapping(Polling::InputType type); + + /// Returns an input event with mapping information. + [[nodiscard]] const Common::ParamPackage GetNextInput() const; + + /// Stop polling from all backends. + void StopMapping() const; private: struct Impl; std::unique_ptr impl; }; -/// Generates a serialized param package for creating a keyboard button device +/// 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 +/// 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