diff --git a/src/citra/citra.cpp b/src/citra/citra.cpp index b2b447a03..8a17affd0 100644 --- a/src/citra/citra.cpp +++ b/src/citra/citra.cpp @@ -358,18 +358,18 @@ int main(int argc, char** argv) { // Register frontend applets Frontend::RegisterDefaultApplets(); - EmuWindow_SDL2::InitializeSDL2(); + InputCommon::InputSubsystem input_subsystem{}; - const auto create_emu_window = [](bool fullscreen, + const auto create_emu_window = [&](bool fullscreen, bool is_secondary) -> std::unique_ptr { switch (Settings::values.graphics_api.GetValue()) { case Settings::GraphicsAPI::OpenGL: - return std::make_unique(fullscreen, is_secondary); + return std::make_unique(&input_subsystem, fullscreen, is_secondary); case Settings::GraphicsAPI::Software: - return std::make_unique(fullscreen, is_secondary); + return std::make_unique(&input_subsystem, fullscreen, is_secondary); } LOG_ERROR(Frontend, "Invalid Graphics API, using OpenGL"); - return std::make_unique(fullscreen, is_secondary); + return std::make_unique(&input_subsystem, fullscreen, is_secondary); }; const auto emu_window{create_emu_window(fullscreen, false)}; @@ -496,7 +496,6 @@ int main(int argc, char** argv) { } Network::Shutdown(); - InputCommon::Shutdown(); system.Shutdown(); diff --git a/src/citra/config.cpp b/src/citra/config.cpp index 6a0df05fc..fa7e7795a 100644 --- a/src/citra/config.cpp +++ b/src/citra/config.cpp @@ -97,7 +97,7 @@ void Config::ReadSetting(const std::string& group, Settings::SettingGetString("Controls", Settings::NativeButton::mapping[i], default_param); @@ -124,7 +124,7 @@ void Config::ReadValues() { "Controls", "udp_input_address", InputCommon::CemuhookUDP::DEFAULT_ADDR); Settings::values.current_input_profile.udp_input_port = static_cast(sdl2_config->GetInteger("Controls", "udp_input_port", - InputCommon::CemuhookUDP::DEFAULT_PORT)); + InputCommon::CemuhookUDP::DEFAULT_PORT));*/ // Core ReadSetting("Core", Settings::values.use_cpu_jit); diff --git a/src/citra/emu_window/emu_window_sdl2.cpp b/src/citra/emu_window/emu_window_sdl2.cpp index f8fe7135d..46ead9c1e 100644 --- a/src/citra/emu_window/emu_window_sdl2.cpp +++ b/src/citra/emu_window/emu_window_sdl2.cpp @@ -2,131 +2,38 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include + #include #include #include -#define SDL_MAIN_HANDLED -#include #include "citra/emu_window/emu_window_sdl2.h" #include "common/logging/log.h" #include "common/scm_rev.h" #include "core/core.h" -#include "input_common/keyboard.h" +#include "input_common/drivers/keyboard.h" +#include "input_common/drivers/mouse.h" +#include "input_common/drivers/touch_screen.h" #include "input_common/main.h" -#include "input_common/motion_emu.h" #include "network/network.h" -void EmuWindow_SDL2::OnMouseMotion(s32 x, s32 y) { - TouchMoved((unsigned)std::max(x, 0), (unsigned)std::max(y, 0)); - InputCommon::GetMotionEmu()->Tilt(x, y); -} - -void EmuWindow_SDL2::OnMouseButton(u32 button, u8 state, s32 x, s32 y) { - if (button == SDL_BUTTON_LEFT) { - if (state == SDL_PRESSED) { - TouchPressed((unsigned)std::max(x, 0), (unsigned)std::max(y, 0)); - } else { - TouchReleased(); - } - } else if (button == SDL_BUTTON_RIGHT) { - if (state == SDL_PRESSED) { - InputCommon::GetMotionEmu()->BeginTilt(x, y); - } else { - InputCommon::GetMotionEmu()->EndTilt(); - } - } -} - -std::pair EmuWindow_SDL2::TouchToPixelPos(float touch_x, float touch_y) const { - int w, h; - SDL_GetWindowSize(render_window, &w, &h); - - touch_x *= w; - touch_y *= h; - - return {static_cast(std::max(std::round(touch_x), 0.0f)), - static_cast(std::max(std::round(touch_y), 0.0f))}; -} - -void EmuWindow_SDL2::OnFingerDown(float x, float y) { - // TODO(NeatNit): keep track of multitouch using the fingerID and a dictionary of some kind - // This isn't critical because the best we can do when we have that is to average them, like the - // 3DS does - - const auto [px, py] = TouchToPixelPos(x, y); - TouchPressed(px, py); -} - -void EmuWindow_SDL2::OnFingerMotion(float x, float y) { - const auto [px, py] = TouchToPixelPos(x, y); - TouchMoved(px, py); -} - -void EmuWindow_SDL2::OnFingerUp() { - TouchReleased(); -} - -void EmuWindow_SDL2::OnKeyEvent(int key, u8 state) { - if (state == SDL_PRESSED) { - InputCommon::GetKeyboard()->PressKey(key); - } else if (state == SDL_RELEASED) { - InputCommon::GetKeyboard()->ReleaseKey(key); - } -} - -bool EmuWindow_SDL2::IsOpen() const { - return is_open; -} - -void EmuWindow_SDL2::RequestClose() { - is_open = false; -} - -void EmuWindow_SDL2::OnResize() { - int width, height; - SDL_GL_GetDrawableSize(render_window, &width, &height); - UpdateCurrentFramebufferLayout(width, height); -} - -void EmuWindow_SDL2::Fullscreen() { - if (SDL_SetWindowFullscreen(render_window, SDL_WINDOW_FULLSCREEN) == 0) { - return; - } - - LOG_ERROR(Frontend, "Fullscreening failed: {}", SDL_GetError()); - - // Try a different fullscreening method - LOG_INFO(Frontend, "Attempting to use borderless fullscreen..."); - if (SDL_SetWindowFullscreen(render_window, SDL_WINDOW_FULLSCREEN_DESKTOP) == 0) { - return; - } - - LOG_ERROR(Frontend, "Borderless fullscreening failed: {}", SDL_GetError()); - - // Fallback algorithm: Maximise window. - // Works on all systems (unless something is seriously wrong), so no fallback for this one. - LOG_INFO(Frontend, "Falling back on a maximised window..."); - SDL_MaximizeWindow(render_window); -} - -EmuWindow_SDL2::EmuWindow_SDL2(bool is_secondary) : EmuWindow(is_secondary) {} - -EmuWindow_SDL2::~EmuWindow_SDL2() { - SDL_Quit(); -} - -void EmuWindow_SDL2::InitializeSDL2() { +EmuWindow_SDL2::EmuWindow_SDL2(InputCommon::InputSubsystem* input_subsystem_, bool is_secondary) + : EmuWindow(is_secondary), input_subsystem{input_subsystem_} { if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMECONTROLLER) < 0) { LOG_CRITICAL(Frontend, "Failed to initialize SDL2: {}! Exiting...", SDL_GetError()); exit(1); } - InputCommon::Init(); + input_subsystem->Initialize(); Network::Init(); SDL_SetMainReady(); } +EmuWindow_SDL2::~EmuWindow_SDL2() { + SDL_Quit(); +} + void EmuWindow_SDL2::PollEvents() { SDL_Event event; std::vector other_window_events; @@ -170,10 +77,12 @@ void EmuWindow_SDL2::PollEvents() { } break; case SDL_FINGERDOWN: - OnFingerDown(event.tfinger.x, event.tfinger.y); + OnFingerDown(event.tfinger.x, event.tfinger.y, + static_cast(event.tfinger.touchId)); break; case SDL_FINGERMOTION: - OnFingerMotion(event.tfinger.x, event.tfinger.y); + OnFingerMotion(event.tfinger.x, event.tfinger.y, + static_cast(event.tfinger.touchId)); break; case SDL_FINGERUP: OnFingerUp(); @@ -195,6 +104,106 @@ void EmuWindow_SDL2::PollEvents() { } } +void EmuWindow_SDL2::OnMouseMotion(s32 x, s32 y) { + const auto [touch_x, touch_y] = MouseToTouchPos(x, y); + input_subsystem->GetMouse()->Move(x, y, 0, 0); + input_subsystem->GetMouse()->MouseMove(touch_x, touch_y); + input_subsystem->GetMouse()->TouchMove(touch_x, touch_y); +} + +InputCommon::MouseButton EmuWindow_SDL2::SDLButtonToMouseButton(u32 button) const { + switch (button) { + case SDL_BUTTON_LEFT: + return InputCommon::MouseButton::Left; + case SDL_BUTTON_RIGHT: + return InputCommon::MouseButton::Right; + case SDL_BUTTON_MIDDLE: + return InputCommon::MouseButton::Wheel; + case SDL_BUTTON_X1: + return InputCommon::MouseButton::Backward; + case SDL_BUTTON_X2: + return InputCommon::MouseButton::Forward; + default: + return InputCommon::MouseButton::Undefined; + } +} + +std::pair EmuWindow_SDL2::MouseToTouchPos(s32 touch_x, s32 touch_y) const { + int w, h; + SDL_GetWindowSize(render_window, &w, &h); + const float fx = static_cast(touch_x) / w; + const float fy = static_cast(touch_y) / h; + + return {std::clamp(fx, 0.0f, 1.0f), std::clamp(fy, 0.0f, 1.0f)}; +} + +void EmuWindow_SDL2::OnMouseButton(u32 button, u8 state, s32 x, s32 y) { + const auto mouse_button = SDLButtonToMouseButton(button); + if (state == SDL_PRESSED) { + const auto [touch_x, touch_y] = MouseToTouchPos(x, y); + input_subsystem->GetMouse()->PressButton(x, y, mouse_button); + input_subsystem->GetMouse()->PressMouseButton(mouse_button); + input_subsystem->GetMouse()->PressTouchButton(touch_x, touch_y, mouse_button); + } else { + input_subsystem->GetMouse()->ReleaseButton(mouse_button); + } +} + +void EmuWindow_SDL2::OnFingerDown(float x, float y, std::size_t id) { + input_subsystem->GetTouchScreen()->TouchPressed(x, y, id); +} + +void EmuWindow_SDL2::OnFingerMotion(float x, float y, std::size_t id) { + input_subsystem->GetTouchScreen()->TouchMoved(x, y, id); +} + +void EmuWindow_SDL2::OnFingerUp() { + input_subsystem->GetTouchScreen()->ReleaseAllTouch(); +} + +void EmuWindow_SDL2::OnKeyEvent(int key, u8 state) { + if (state == SDL_PRESSED) { + input_subsystem->GetKeyboard()->PressKey(static_cast(key)); + } else if (state == SDL_RELEASED) { + input_subsystem->GetKeyboard()->ReleaseKey(static_cast(key)); + } +} + +bool EmuWindow_SDL2::IsOpen() const { + return is_open; +} + +void EmuWindow_SDL2::RequestClose() { + is_open = false; +} + +void EmuWindow_SDL2::OnResize() { + int width, height; + SDL_GL_GetDrawableSize(render_window, &width, &height); + UpdateCurrentFramebufferLayout(width, height); +} + +void EmuWindow_SDL2::Fullscreen() { + if (SDL_SetWindowFullscreen(render_window, SDL_WINDOW_FULLSCREEN) == 0) { + return; + } + + LOG_ERROR(Frontend, "Fullscreening failed: {}", SDL_GetError()); + + // Try a different fullscreening method + LOG_INFO(Frontend, "Attempting to use borderless fullscreen..."); + if (SDL_SetWindowFullscreen(render_window, SDL_WINDOW_FULLSCREEN_DESKTOP) == 0) { + return; + } + + LOG_ERROR(Frontend, "Borderless fullscreening failed: {}", SDL_GetError()); + + // Fallback algorithm: Maximise window. + // Works on all systems (unless something is seriously wrong), so no fallback for this one. + LOG_INFO(Frontend, "Falling back on a maximised window..."); + SDL_MaximizeWindow(render_window); +} + void EmuWindow_SDL2::OnMinimalClientAreaChangeRequest(std::pair minimal_size) { SDL_SetWindowMinimumSize(render_window, minimal_size.first, minimal_size.second); } diff --git a/src/citra/emu_window/emu_window_sdl2.h b/src/citra/emu_window/emu_window_sdl2.h index b74c70731..728265751 100644 --- a/src/citra/emu_window/emu_window_sdl2.h +++ b/src/citra/emu_window/emu_window_sdl2.h @@ -10,14 +10,16 @@ struct SDL_Window; +namespace InputCommon { +class InputSubsystem; +enum class MouseButton; +} // namespace InputCommon + class EmuWindow_SDL2 : public Frontend::EmuWindow { public: - explicit EmuWindow_SDL2(bool is_secondary); + explicit EmuWindow_SDL2(InputCommon::InputSubsystem* input_subsystem, bool is_secondary); ~EmuWindow_SDL2(); - /// Initializes SDL2 - static void InitializeSDL2(); - /// Presents the most recent frame from the video backend virtual void Present() {} @@ -37,17 +39,20 @@ protected: /// Called by PollEvents when the mouse moves. void OnMouseMotion(s32 x, s32 y); + /// Converts a SDL mouse button into MouseInput mouse button + InputCommon::MouseButton SDLButtonToMouseButton(u32 button) const; + + /// Translates pixel position to float position + std::pair MouseToTouchPos(s32 touch_x, s32 touch_y) const; + /// Called by PollEvents when a mouse button is pressed or released void OnMouseButton(u32 button, u8 state, s32 x, s32 y); - /// Translates pixel position (0..1) to pixel positions - std::pair TouchToPixelPos(float touch_x, float touch_y) const; - /// Called by PollEvents when a finger starts touching the touchscreen - void OnFingerDown(float x, float y); + void OnFingerDown(float x, float y, std::size_t id); /// Called by PollEvents when a finger moves while touching the touchscreen - void OnFingerMotion(float x, float y); + void OnFingerMotion(float x, float y, std::size_t id); /// Called by PollEvents when a finger stops touching the touchscreen void OnFingerUp(); @@ -78,4 +83,7 @@ protected: /// Keeps track of how often to update the title bar during gameplay u32 last_time = 0; + + /// Input subsystem to use with this window. + InputCommon::InputSubsystem* input_subsystem; }; diff --git a/src/citra/emu_window/emu_window_sdl2_gl.cpp b/src/citra/emu_window/emu_window_sdl2_gl.cpp index 090050ef9..f45e241b5 100644 --- a/src/citra/emu_window/emu_window_sdl2_gl.cpp +++ b/src/citra/emu_window/emu_window_sdl2_gl.cpp @@ -42,8 +42,8 @@ private: SDL_GLContext context; }; -EmuWindow_SDL2_GL::EmuWindow_SDL2_GL(bool fullscreen, bool is_secondary) - : EmuWindow_SDL2{is_secondary} { +EmuWindow_SDL2_GL::EmuWindow_SDL2_GL(InputCommon::InputSubsystem* input_subsystem, bool fullscreen, bool is_secondary) + : EmuWindow_SDL2{input_subsystem, is_secondary} { // Initialize the window if (Settings::values.use_gles) { SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); diff --git a/src/citra/emu_window/emu_window_sdl2_gl.h b/src/citra/emu_window/emu_window_sdl2_gl.h index e56cd2c42..1d4a34f31 100644 --- a/src/citra/emu_window/emu_window_sdl2_gl.h +++ b/src/citra/emu_window/emu_window_sdl2_gl.h @@ -11,7 +11,7 @@ struct SDL_Window; class EmuWindow_SDL2_GL : public EmuWindow_SDL2 { public: - explicit EmuWindow_SDL2_GL(bool fullscreen, bool is_secondary); + explicit EmuWindow_SDL2_GL(InputCommon::InputSubsystem* input_subsystem, bool fullscreen, bool is_secondary); ~EmuWindow_SDL2_GL(); void Present() override; diff --git a/src/citra/emu_window/emu_window_sdl2_sw.cpp b/src/citra/emu_window/emu_window_sdl2_sw.cpp index e9d047bb9..8d76aa8e4 100644 --- a/src/citra/emu_window/emu_window_sdl2_sw.cpp +++ b/src/citra/emu_window/emu_window_sdl2_sw.cpp @@ -19,8 +19,8 @@ class DummyContext : public Frontend::GraphicsContext {}; -EmuWindow_SDL2_SW::EmuWindow_SDL2_SW(bool fullscreen, bool is_secondary) - : EmuWindow_SDL2{is_secondary} { +EmuWindow_SDL2_SW::EmuWindow_SDL2_SW(InputCommon::InputSubsystem* input_subsystem, bool fullscreen, bool is_secondary) + : EmuWindow_SDL2{input_subsystem, is_secondary} { std::string window_title = fmt::format("Citra {} | {}-{}", Common::g_build_fullname, Common::g_scm_branch, Common::g_scm_desc); render_window = diff --git a/src/citra/emu_window/emu_window_sdl2_sw.h b/src/citra/emu_window/emu_window_sdl2_sw.h index e1d35f687..caab45896 100644 --- a/src/citra/emu_window/emu_window_sdl2_sw.h +++ b/src/citra/emu_window/emu_window_sdl2_sw.h @@ -12,7 +12,7 @@ struct SDL_Surface; class EmuWindow_SDL2_SW : public EmuWindow_SDL2 { public: - explicit EmuWindow_SDL2_SW(bool fullscreen, bool is_secondary); + explicit EmuWindow_SDL2_SW(InputCommon::InputSubsystem* input_subsystem, bool fullscreen, bool is_secondary); ~EmuWindow_SDL2_SW(); void Present() override; diff --git a/src/citra_qt/configuration/configure_motion_touch.cpp b/src/citra_qt/configuration/configure_motion_touch.cpp index 28448f812..3399e770a 100644 --- a/src/citra_qt/configuration/configure_motion_touch.cpp +++ b/src/citra_qt/configuration/configure_motion_touch.cpp @@ -37,7 +37,7 @@ CalibrationConfigurationDialog::CalibrationConfigurationDialog(QWidget* parent, using namespace InputCommon::CemuhookUDP; job = std::make_unique( - host, port, + host, port, pad_index, [this](CalibrationConfigurationJob::Status status) { QMetaObject::invokeMethod(this, [status, this] { QString text; @@ -203,6 +203,7 @@ void ConfigureMotionTouch::OnCemuhookUDPTest() { udp_test_in_progress = true; InputCommon::CemuhookUDP::TestCommunication( ui->udp_server->text().toStdString(), static_cast(ui->udp_port->text().toInt()), + static_cast(ui->udp_pad_index->currentIndex()), [this] { LOG_INFO(Frontend, "UDP input test success"); QMetaObject::invokeMethod(this, "ShowUDPTestResult", Q_ARG(bool, true)); diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 21fa8314e..1e0bf1f9e 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -101,6 +101,7 @@ add_library(citra_common STATIC scope_exit.h settings.cpp settings.h + settings_input.h slot_vector.h serialization/atomic.h serialization/boost_discrete_interval.hpp diff --git a/src/common/input.h b/src/common/input.h index 48b1616e2..d428f720c 100644 --- a/src/common/input.h +++ b/src/common/input.h @@ -39,6 +39,28 @@ enum class PollingError { Unknown, }; +// Different results that can happen from a device request +enum class DriverResult { + Success, + WrongReply, + Timeout, + UnsupportedControllerType, + HandleInUse, + ErrorReadingData, + ErrorWritingData, + NoDeviceDetected, + InvalidHandle, + NotSupported, + Disabled, + Unknown, +}; + +// Hint for amplification curve to be used +enum class VibrationAmplificationType { + Linear, + Exponential, +}; + // Analog properties for calibration struct AnalogProperties { // Anything below this value will be detected as zero @@ -119,6 +141,15 @@ struct TouchStatus { int id{}; }; +// HD rumble data +struct VibrationStatus { + f32 low_amplitude{}; + f32 low_frequency{}; + f32 high_amplitude{}; + f32 high_frequency{}; + VibrationAmplificationType type; +}; + // List of buttons to be passed to Qt that can be translated enum class ButtonNames { Undefined, diff --git a/src/common/settings.cpp b/src/common/settings.cpp index 6c000fb58..a90d19fd6 100644 --- a/src/common/settings.cpp +++ b/src/common/settings.cpp @@ -101,24 +101,6 @@ void Apply() { Core::DSP().SetSink(values.output_type.GetValue(), values.output_device.GetValue()); Core::DSP().EnableStretching(values.enable_audio_stretching.GetValue()); - auto hid = Service::HID::GetModule(system); - if (hid) { - hid->ReloadInputDevices(); - } - - auto apt = Service::APT::GetModule(system); - if (apt) { - apt->GetAppletManager()->ReloadInputDevices(); - } - - auto sm = system.ServiceManager(); - auto ir_user = sm.GetService("ir:USER"); - if (ir_user) - ir_user->ReloadInputDevices(); - auto ir_rst = sm.GetService("ir:rst"); - if (ir_rst) - ir_rst->ReloadInputDevices(); - auto cam = Service::CAM::GetModule(system); if (cam) { cam->ReloadCameraDevices(); diff --git a/src/common/settings.h b/src/common/settings.h index 8f4ebb105..123e7bed4 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -13,6 +13,7 @@ #include "audio_core/input_details.h" #include "audio_core/sink_details.h" #include "common/common_types.h" +#include "common/settings_input.h" #include "core/hle/service/cam/cam_params.h" namespace Settings { @@ -53,8 +54,8 @@ enum class StereoRenderOption : u32 { CardboardVR = 5 }; -// Which eye to render when 3d is off. 800px wide mode could be added here in the future, when -// implemented +// Which eye to render when 3d is off. 800px wide mode +// could be added here in the future, when implemented. enum class MonoRenderOption : u32 { LeftEye = 0, RightEye = 1, @@ -75,109 +76,6 @@ enum class TextureFilter : u32 { xBRZ = 5, }; -namespace NativeButton { - -enum Values { - A, - B, - X, - Y, - DUp, - DDown, - DLeft, - DRight, - L, - R, - Start, - Select, - Debug, - Gpio14, - - ZL, - ZR, - - Home, - - NumButtons, -}; - -constexpr int BUTTON_HID_BEGIN = A; -constexpr int BUTTON_IR_BEGIN = ZL; -constexpr int BUTTON_NS_BEGIN = Home; - -constexpr int BUTTON_HID_END = BUTTON_IR_BEGIN; -constexpr int BUTTON_IR_END = BUTTON_NS_BEGIN; -constexpr int BUTTON_NS_END = NumButtons; - -constexpr int NUM_BUTTONS_HID = BUTTON_HID_END - BUTTON_HID_BEGIN; -constexpr int NUM_BUTTONS_IR = BUTTON_IR_END - BUTTON_IR_BEGIN; -constexpr int NUM_BUTTONS_NS = BUTTON_NS_END - BUTTON_NS_BEGIN; - -constexpr std::array mapping = {{ - "button_a", - "button_b", - "button_x", - "button_y", - "button_up", - "button_down", - "button_left", - "button_right", - "button_l", - "button_r", - "button_start", - "button_select", - "button_debug", - "button_gpio14", - "button_zl", - "button_zr", - "button_home", -}}; -} // namespace NativeButton - -namespace NativeAnalog { -enum Values { - CirclePad, - CStick, - - NumAnalogs, -}; - -constexpr std::array mapping = {{ - "circle_pad", - "c_stick", -}}; -} // namespace NativeAnalog - -namespace NativeMotion { -enum Values : int { - MotionLeft, - MotionRight, - - NumMotions, -}; - -constexpr int MOTION_HID_BEGIN = MotionLeft; -constexpr int MOTION_HID_END = NumMotions; -constexpr int NUM_MOTIONS_HID = NumMotions; - -constexpr std::array mapping = {{ - "motionleft", - "motionright", -}}; -} // namespace NativeMotion - -using AnalogsRaw = std::array; -using ButtonsRaw = std::array; -using MotionsRaw = std::array; - -struct PlayerInput { - ButtonsRaw buttons; - AnalogsRaw analogs; - MotionsRaw motions; - - std::string profile_name; -}; - /** The Setting class is a simple resource manager. It defines a label and default value alongside * the actual value of the setting for simpler and less-error prone use with frontend * configurations. Specifying a default value and label is required. A minimum and maximum range can @@ -440,11 +338,6 @@ private: Type custom{}; ///< The custom setting value }; -struct TouchFromButtonMap { - std::string name; - std::vector buttons; -}; - /// A special region value indicating that citra will automatically select a region /// value to fit the region lockout info of the game static constexpr s32 REGION_VALUE_AUTO_SELECT = -1; @@ -461,6 +354,9 @@ struct Values { Setting udp_input_port{26760, "udp_input_port"}; Setting udp_pad_index{0, "udp_pad_index"}; + Setting emulate_analog_keyboard{false, "emulate_analog_keyboard"}; + Setting keyboard_enabled{false, "keyboard_enabled"}; + // Core Setting use_cpu_jit{true, "use_cpu_jit"}; SwitchableSetting cpu_clock_percentage{100, 5, 400, "cpu_clock_percentage"}; diff --git a/src/common/settings_input.h b/src/common/settings_input.h new file mode 100644 index 000000000..14090b2fa --- /dev/null +++ b/src/common/settings_input.h @@ -0,0 +1,119 @@ +// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include +#include + +#include "common/common_types.h" + +namespace Settings { +namespace NativeButton { +enum Values : int { + A, + B, + X, + Y, + DUp, + DDown, + DLeft, + DRight, + L, + R, + Start, + Select, + Debug, + Gpio14, + + ZL, + ZR, + + Home, + + NumButtons, +}; + +constexpr int BUTTON_HID_BEGIN = A; +constexpr int BUTTON_IR_BEGIN = ZL; +constexpr int BUTTON_NS_BEGIN = Home; + +constexpr int BUTTON_HID_END = BUTTON_IR_BEGIN; +constexpr int BUTTON_IR_END = BUTTON_NS_BEGIN; +constexpr int BUTTON_NS_END = NumButtons; + +constexpr int NUM_BUTTONS_HID = BUTTON_HID_END - BUTTON_HID_BEGIN; +constexpr int NUM_BUTTONS_IR = BUTTON_IR_END - BUTTON_IR_BEGIN; +constexpr int NUM_BUTTONS_NS = BUTTON_NS_END - BUTTON_NS_BEGIN; + +constexpr std::array mapping = {{ + "button_a", + "button_b", + "button_x", + "button_y", + "button_up", + "button_down", + "button_left", + "button_right", + "button_l", + "button_r", + "button_start", + "button_select", + "button_debug", + "button_gpio14", + "button_zl", + "button_zr", + "button_home", +}}; +} // namespace NativeButton + +namespace NativeAnalog { +enum Values : int { + CirclePad, + CStick, + + NumAnalogs, +}; + +constexpr std::array mapping = {{ + "circle_pad", + "c_stick", +}}; +} // namespace NativeAnalog + +namespace NativeMotion { +enum Values : int { + MotionLeft, + MotionRight, + + NumMotions, +}; + +constexpr int MOTION_HID_BEGIN = MotionLeft; +constexpr int MOTION_HID_END = NumMotions; +constexpr int NUM_MOTIONS_HID = NumMotions; + +constexpr std::array mapping = {{ + "motionleft", + "motionright", +}}; +} // namespace NativeMotion + +using AnalogsRaw = std::array; +using ButtonsRaw = std::array; +using MotionsRaw = std::array; + +struct PlayerInput { + ButtonsRaw buttons; + AnalogsRaw analogs; + MotionsRaw motions; + + std::string profile_name; +}; + +struct TouchFromButtonMap { + std::string name; + std::vector buttons; +}; + +} // namespace Settings diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 98db8052a..1325e34a7 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -113,10 +113,6 @@ add_library(citra_core STATIC gdbstub/gdbstub.h gdbstub/hio.cpp gdbstub/hio.h - frontend/mic.cpp - frontend/mic.h - frontend/scope_acquire_context.cpp - frontend/scope_acquire_context.h gdbstub/gdbstub.cpp gdbstub/gdbstub.h hid/emulated_console.cpp diff --git a/src/core/frontend/emu_window.cpp b/src/core/frontend/emu_window.cpp index 115de32ff..7680f4dd4 100644 --- a/src/core/frontend/emu_window.cpp +++ b/src/core/frontend/emu_window.cpp @@ -19,38 +19,6 @@ EmuWindow::EmuWindow(bool is_secondary_) : is_secondary{is_secondary_} {} EmuWindow::~EmuWindow() = default; -/** - * Check if the given x/y coordinates are within the touchpad specified by the framebuffer layout - * @param layout FramebufferLayout object describing the framebuffer size and screen positions - * @param framebuffer_x Framebuffer x-coordinate to check - * @param framebuffer_y Framebuffer y-coordinate to check - * @return True if the coordinates are within the touchpad, otherwise false - */ -static bool IsWithinTouchscreen(const Layout::FramebufferLayout& layout, unsigned framebuffer_x, - unsigned framebuffer_y) { - if (Settings::values.render_3d.GetValue() == Settings::StereoRenderOption::SideBySide) { - return (framebuffer_y >= layout.bottom_screen.top && - framebuffer_y < layout.bottom_screen.bottom && - ((framebuffer_x >= layout.bottom_screen.left / 2 && - framebuffer_x < layout.bottom_screen.right / 2) || - (framebuffer_x >= (layout.bottom_screen.left / 2) + (layout.width / 2) && - framebuffer_x < (layout.bottom_screen.right / 2) + (layout.width / 2)))); - } else if (Settings::values.render_3d.GetValue() == Settings::StereoRenderOption::CardboardVR) { - return (framebuffer_y >= layout.bottom_screen.top && - framebuffer_y < layout.bottom_screen.bottom && - ((framebuffer_x >= layout.bottom_screen.left && - framebuffer_x < layout.bottom_screen.right) || - (framebuffer_x >= layout.cardboard.bottom_screen_right_eye + (layout.width / 2) && - framebuffer_x < layout.cardboard.bottom_screen_right_eye + - layout.bottom_screen.GetWidth() + (layout.width / 2)))); - } else { - return (framebuffer_y >= layout.bottom_screen.top && - framebuffer_y < layout.bottom_screen.bottom && - framebuffer_x >= layout.bottom_screen.left && - framebuffer_x < layout.bottom_screen.right); - } -} - std::pair EmuWindow::MapToTouchScreen(u32 framebuffer_x, u32 framebuffer_y) const { std::tie(framebuffer_x, framebuffer_y) = ClipToTouchScreen(framebuffer_x, framebuffer_y); const float x = static_cast(framebuffer_x - framebuffer_layout.bottom_screen.left) / diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index d15e4af54..bca48cf93 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -134,7 +134,7 @@ void EmulatedController::ReloadInput() { } motion_devices[index]->SetCallback({ .on_change = - [this, index](const Common::Input::CallbackStatus& callback) { + [/*this, index*/](const Common::Input::CallbackStatus& callback) { // SetMotion(callback, index); }, }); diff --git a/src/core/hle/service/apt/applet_manager.cpp b/src/core/hle/service/apt/applet_manager.cpp index d52d1e5c9..e37523389 100644 --- a/src/core/hle/service/apt/applet_manager.cpp +++ b/src/core/hle/service/apt/applet_manager.cpp @@ -4,7 +4,8 @@ #include "common/settings.h" #include "core/core.h" -#include "core/frontend/input.h" +#include "core/hid/emulated_controller.h" +#include "core/hid/hid_core.h" #include "core/hle/applets/applet.h" #include "core/hle/service/am/am.h" #include "core/hle/service/apt/applet_manager.h" @@ -1230,33 +1231,25 @@ void AppletManager::CaptureFrameBuffers() { } } -void AppletManager::LoadInputDevices() { - home_button = Input::CreateDevice( - Settings::values.current_input_profile.buttons[Settings::NativeButton::Home]); -} - void AppletManager::HomeButtonUpdateEvent(std::uintptr_t user_data, s64 cycles_late) { - if (is_device_reload_pending.exchange(false)) { - LoadInputDevices(); - } - - const bool state = home_button->GetStatus(); + //const auto& controller = hid_core.GetEmulatedController(); + //const bool state = home_button->GetStatus(); // NOTE: We technically do support loading and jumping to home menu even if it isn't // initially registered. However since the home menu suspend is not bug-free, we don't // want normal users who didn't launch the home menu accidentally pressing the home // button binding and freezing their game, so for now, gate it to only environments // where the home menu was already loaded by the user (last condition). - if (state && !last_home_button_state && GetAppletSlot(AppletSlot::HomeMenu)->registered) { + if (/*state &&*/ !last_home_button_state && GetAppletSlot(AppletSlot::HomeMenu)->registered) { SendNotification(Notification::HomeButtonSingle); } - last_home_button_state = state; + //last_home_button_state = state; // Reschedule recurrent event - Core::System::GetInstance().CoreTiming().ScheduleEvent( + system.CoreTiming().ScheduleEvent( usToCycles(home_button_update_interval_us) - cycles_late, home_button_update_event); } -AppletManager::AppletManager(Core::System& system) : system(system) { +AppletManager::AppletManager(Core::System& system) : system(system), hid_core(system.HIDCore()) { lock = system.Kernel().CreateMutex(false, "APT_U:Lock"); for (std::size_t slot = 0; slot < applet_slots.size(); ++slot) { auto& slot_data = applet_slots[slot]; @@ -1283,8 +1276,4 @@ AppletManager::~AppletManager() { HLE::Applets::Shutdown(); } -void AppletManager::ReloadInputDevices() { - is_device_reload_pending.store(true); -} - } // namespace Service::APT diff --git a/src/core/hle/service/apt/applet_manager.h b/src/core/hle/service/apt/applet_manager.h index 1f7b041de..fc94f0569 100644 --- a/src/core/hle/service/apt/applet_manager.h +++ b/src/core/hle/service/apt/applet_manager.h @@ -23,6 +23,10 @@ namespace Core { class System; } +namespace Core::HID { +class HIDCore; +}; + namespace Service::APT { /// Signals used by APT functions @@ -228,8 +232,6 @@ public: explicit AppletManager(Core::System& system); ~AppletManager(); - void ReloadInputDevices(); - /** * Clears any existing parameter and places a new one. This function is currently only used by * HLE Applets and should be likely removed in the future @@ -428,11 +430,10 @@ private: AppletSlot application_close_target = AppletSlot::Error; Core::TimingEventType* home_button_update_event; - std::atomic is_device_reload_pending{true}; - std::unique_ptr home_button; bool last_home_button_state = false; Core::System& system; + Core::HID::HIDCore& hid_core; AppletSlotData* GetAppletSlot(AppletSlot slot) { return &applet_slots[static_cast(slot)]; @@ -454,7 +455,6 @@ private: void CaptureFrameBuffers(); - void LoadInputDevices(); void HomeButtonUpdateEvent(std::uintptr_t user_data, s64 cycles_late); template @@ -479,10 +479,6 @@ private: } ar& applet_slots; ar& library_applet_closing_command; - - if (Archive::is_loading::value) { - LoadInputDevices(); - } } friend class boost::serialization::access; }; diff --git a/src/input_common/CMakeLists.txt b/src/input_common/CMakeLists.txt index 1b0a35608..e03507bb6 100644 --- a/src/input_common/CMakeLists.txt +++ b/src/input_common/CMakeLists.txt @@ -54,7 +54,8 @@ if (ENABLE_LIBUSB) drivers/gc_adapter.cpp drivers/gc_adapter.h ) - target_link_libraries(input_common PRIVATE libusb::usb) + target_include_directories(input_common PRIVATE ${LIBUSB_INCLUDE_DIR}) + target_link_libraries(input_common PRIVATE ${LIBUSB_LIBRARIES}) target_compile_definitions(input_common PRIVATE HAVE_LIBUSB) endif() diff --git a/src/input_common/drivers/gc_adapter.cpp b/src/input_common/drivers/gc_adapter.cpp index 826fa2109..a26777dba 100644 --- a/src/input_common/drivers/gc_adapter.cpp +++ b/src/input_common/drivers/gc_adapter.cpp @@ -15,7 +15,7 @@ namespace InputCommon { class LibUSBContext { public: explicit LibUSBContext() { - init_result = libusb_init(&ctx); + init_result = libusb_init_context(&ctx, nullptr, 0); } ~LibUSBContext() { @@ -324,7 +324,7 @@ bool GCAdapter::GetGCEndpoint(libusb_device* device) { return true; } -Common::Input::VibrationError GCAdapter::SetVibration( +Common::Input::DriverResult GCAdapter::SetVibration( const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) { const auto mean_amplitude = (vibration.low_amplitude + vibration.high_amplitude) * 0.5f; const auto processed_amplitude = @@ -333,9 +333,9 @@ Common::Input::VibrationError GCAdapter::SetVibration( pads[identifier.port].rumble_amplitude = processed_amplitude; if (!rumble_enabled) { - return Common::Input::VibrationError::Disabled; + return Common::Input::DriverResult::Disabled; } - return Common::Input::VibrationError::None; + return Common::Input::DriverResult::Success; } bool GCAdapter::IsVibrationEnabled([[maybe_unused]] const PadIdentifier& identifier) { @@ -421,14 +421,14 @@ ButtonMapping GCAdapter::GetButtonMappingForDevice(const Common::ParamPackage& p {Settings::NativeButton::B, PadButton::ButtonB}, {Settings::NativeButton::X, PadButton::ButtonX}, {Settings::NativeButton::Y, PadButton::ButtonY}, - {Settings::NativeButton::Plus, PadButton::ButtonStart}, + {Settings::NativeButton::Start, PadButton::ButtonStart}, + {Settings::NativeButton::Select, PadButton::ButtonSelect}, {Settings::NativeButton::DLeft, PadButton::ButtonLeft}, {Settings::NativeButton::DUp, PadButton::ButtonUp}, {Settings::NativeButton::DRight, PadButton::ButtonRight}, {Settings::NativeButton::DDown, PadButton::ButtonDown}, - {Settings::NativeButton::SL, PadButton::TriggerL}, - {Settings::NativeButton::SR, PadButton::TriggerR}, - {Settings::NativeButton::R, PadButton::TriggerZ}, + {Settings::NativeButton::L, PadButton::TriggerL}, + {Settings::NativeButton::R, PadButton::TriggerR}, }; if (!params.Has("port")) { return {}; @@ -474,13 +474,13 @@ AnalogMapping GCAdapter::GetAnalogMappingForDevice(const Common::ParamPackage& p left_analog_params.Set("port", params.Get("port", 0)); left_analog_params.Set("axis_x", static_cast(PadAxes::StickX)); left_analog_params.Set("axis_y", static_cast(PadAxes::StickY)); - mapping.insert_or_assign(Settings::NativeAnalog::LStick, std::move(left_analog_params)); + mapping.insert_or_assign(Settings::NativeAnalog::CirclePad, std::move(left_analog_params)); Common::ParamPackage right_analog_params; right_analog_params.Set("engine", GetEngineName()); right_analog_params.Set("port", params.Get("port", 0)); right_analog_params.Set("axis_x", static_cast(PadAxes::SubstickX)); right_analog_params.Set("axis_y", static_cast(PadAxes::SubstickY)); - mapping.insert_or_assign(Settings::NativeAnalog::RStick, std::move(right_analog_params)); + mapping.insert_or_assign(Settings::NativeAnalog::CStick, std::move(right_analog_params)); return mapping; } diff --git a/src/input_common/drivers/gc_adapter.h b/src/input_common/drivers/gc_adapter.h index b5270fd0b..605d53176 100644 --- a/src/input_common/drivers/gc_adapter.h +++ b/src/input_common/drivers/gc_adapter.h @@ -25,7 +25,7 @@ public: explicit GCAdapter(std::string input_engine_); ~GCAdapter() override; - Common::Input::VibrationError SetVibration( + Common::Input::DriverResult SetVibration( const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) override; bool IsVibrationEnabled(const PadIdentifier& identifier) override; @@ -53,6 +53,7 @@ private: ButtonX = 0x0400, ButtonY = 0x0800, ButtonStart = 0x1000, + ButtonSelect = 0x2000, }; enum class PadAxes : u8 { diff --git a/src/input_common/drivers/mouse.cpp b/src/input_common/drivers/mouse.cpp index c65bb3351..20c05b15d 100644 --- a/src/input_common/drivers/mouse.cpp +++ b/src/input_common/drivers/mouse.cpp @@ -54,6 +54,21 @@ void Mouse::UpdateThread(std::stop_token stop_token) { } } +void Mouse::Move(int x, int y, int, int) { + if (button_pressed) { + const auto mouse_move = Common::MakeVec(x, y) - mouse_origin; + const float sensitivity = /*Settings::values.mouse_panning_sensitivity.GetValue()*/50 * 0.0012f; + SetAxis(identifier, mouse_axis_x, static_cast(mouse_move.x) * sensitivity); + SetAxis(identifier, mouse_axis_y, static_cast(-mouse_move.y) * sensitivity); + + last_motion_change = { + static_cast(-mouse_move.y) / 50.0f, + static_cast(-mouse_move.x) / 50.0f, + last_motion_change.z, + }; + } +} + void Mouse::MouseMove(f32 touch_x, f32 touch_y) { SetAxis(real_mouse_identifier, mouse_axis_x, touch_x); SetAxis(real_mouse_identifier, mouse_axis_y, touch_y); diff --git a/src/input_common/drivers/mouse.h b/src/input_common/drivers/mouse.h index 5c6e20a46..eacb0484f 100644 --- a/src/input_common/drivers/mouse.h +++ b/src/input_common/drivers/mouse.h @@ -101,6 +101,7 @@ private: Common::Vec2 mouse_origin; Common::Vec2 last_mouse_position; Common::Vec2 last_mouse_change; + Common::Vec3 last_motion_change; Common::Vec2 wheel_position; bool button_pressed; std::jthread update_thread; diff --git a/src/input_common/drivers/udp_client.cpp b/src/input_common/drivers/udp_client.cpp index e04a054c7..7969c6f63 100644 --- a/src/input_common/drivers/udp_client.cpp +++ b/src/input_common/drivers/udp_client.cpp @@ -25,9 +25,10 @@ class Socket { public: using clock = std::chrono::system_clock; - explicit Socket(const std::string& host, u16 port, SocketCallback callback_) + explicit Socket(const std::string& host, u16 port, u8 pad_index, SocketCallback callback_) : callback(std::move(callback_)), timer(io_service), - socket(io_service, udp::endpoint(udp::v4(), 0)), client_id(GenerateRandomClientId()) { + socket(io_service, udp::endpoint(udp::v4(), 0)), client_id(GenerateRandomClientId()), + pad_index(pad_index) { boost::system::error_code ec{}; auto ipv4 = boost::asio::ip::make_address_v4(host, ec); if (ec.value() != boost::system::errc::success) { @@ -95,17 +96,13 @@ private: void HandleSend(const boost::system::error_code&) { boost::system::error_code _ignored{}; // Send a request for getting port info for the pad - const Request::PortInfo port_info{4, {0, 1, 2, 3}}; + const Request::PortInfo port_info{1, {pad_index, 0, 0, 0}}; const auto port_message = Request::Create(port_info, client_id); std::memcpy(&send_buffer1, &port_message, PORT_INFO_SIZE); socket.send_to(boost::asio::buffer(send_buffer1), send_endpoint, {}, _ignored); // Send a request for getting pad data for the pad - const Request::PadData pad_data{ - Request::RegisterFlags::AllPads, - 0, - EMPTY_MAC_ADDRESS, - }; + const Request::PadData pad_data{Request::RegisterFlags::PadID, pad_index, EMPTY_MAC_ADDRESS}; const auto pad_message = Request::Create(pad_data, client_id); std::memcpy(send_buffer2.data(), &pad_message, PAD_DATA_SIZE); socket.send_to(boost::asio::buffer(send_buffer2), send_endpoint, {}, _ignored); @@ -118,6 +115,7 @@ private: udp::socket socket; const u32 client_id; + const u8 pad_index; static constexpr std::size_t PORT_INFO_SIZE = sizeof(Message); static constexpr std::size_t PAD_DATA_SIZE = sizeof(Message); @@ -161,7 +159,7 @@ void UDPClient::ReloadSockets() { LOG_ERROR(Input, "Duplicated UDP servers found"); return; } - StartCommunication(0, host, udp_input_port); + StartCommunication(0, host, udp_input_port, pad_index); } std::size_t UDPClient::GetClientNumber(std::string_view host, u16 port) const { @@ -239,7 +237,7 @@ void UDPClient::OnPadData(Response::PadData data, std::size_t client) { static_cast(id == 0 ? PadButton::Touch1 : PadButton::Touch2); // TODO: Use custom calibration per device - /* const Common::ParamPackage touch_param(Settings::values.touch_device.GetValue()); + const Common::ParamPackage touch_param(Settings::values.touch_device.GetValue()); const u16 min_x = static_cast(touch_param.Get("min_x", 100)); const u16 min_y = static_cast(touch_param.Get("min_y", 50)); const u16 max_x = static_cast(touch_param.Get("max_x", 1800)); @@ -260,7 +258,7 @@ void UDPClient::OnPadData(Response::PadData data, std::size_t client) { } SetAxis(identifier, touch_axis_x_id, 0); SetAxis(identifier, touch_axis_y_id, 0); - SetButton(identifier, touch_button_id, false);*/ + SetButton(identifier, touch_button_id, false); } SetAxis(identifier, static_cast(PadAxes::LeftStickX), @@ -288,7 +286,7 @@ void UDPClient::OnPadData(Response::PadData data, std::size_t client) { SetButton(identifier, static_cast(PadButton::TouchHardPress), data.touch_hard_press != 0); } -void UDPClient::StartCommunication(std::size_t client, const std::string& host, u16 port) { +void UDPClient::StartCommunication(std::size_t client, const std::string& host, u16 port, u8 pad_index) { SocketCallback callback{[this](Response::Version version) { OnVersion(version); }, [this](Response::PortInfo info) { OnPortInfo(info); }, [this, client](Response::PadData data) { OnPadData(data, client); }}; @@ -297,7 +295,7 @@ void UDPClient::StartCommunication(std::size_t client, const std::string& host, clients[client].host = host; clients[client].port = port; clients[client].active = 0; - clients[client].socket = std::make_unique(host, port, callback); + clients[client].socket = std::make_unique(host, port, pad_index, callback); clients[client].thread = std::thread{SocketLoop, clients[client].socket.get()}; for (std::size_t index = 0; index < PADS_PER_CLIENT; ++index) { const PadIdentifier identifier = GetPadIdentifier(client * PADS_PER_CLIENT + index); @@ -502,7 +500,7 @@ bool UDPClient::IsStickInverted(const Common::ParamPackage& params) { return true; } -void TestCommunication(const std::string& host, u16 port, +void TestCommunication(const std::string& host, u16 port, u8 pad_index, const std::function& success_callback, const std::function& failure_callback) { std::thread([=] { @@ -512,7 +510,7 @@ void TestCommunication(const std::string& host, u16 port, .port_info = [](Response::PortInfo) {}, .pad_data = [&](Response::PadData) { success_event.Set(); }, }; - Socket socket{host, port, std::move(callback)}; + Socket socket{host, port, pad_index, std::move(callback)}; std::thread worker_thread{SocketLoop, &socket}; const bool result = success_event.WaitUntil(std::chrono::steady_clock::now() + std::chrono::seconds(10)); @@ -527,7 +525,7 @@ void TestCommunication(const std::string& host, u16 port, } CalibrationConfigurationJob::CalibrationConfigurationJob( - const std::string& host, u16 port, std::function status_callback, + const std::string& host, u16 port, u8 pad_index, std::function status_callback, std::function data_callback) { std::thread([=, this] { @@ -571,7 +569,7 @@ CalibrationConfigurationJob::CalibrationConfigurationJob( complete_event.Set(); } }}; - Socket socket{host, port, std::move(callback)}; + Socket socket{host, port, pad_index, std::move(callback)}; std::thread worker_thread{SocketLoop, &socket}; complete_event.Wait(); socket.Stop(); diff --git a/src/input_common/drivers/udp_client.h b/src/input_common/drivers/udp_client.h index ce6c72d92..27df62f96 100644 --- a/src/input_common/drivers/udp_client.h +++ b/src/input_common/drivers/udp_client.h @@ -144,7 +144,7 @@ private: void OnVersion(Response::Version); void OnPortInfo(Response::PortInfo); void OnPadData(Response::PadData, std::size_t client); - void StartCommunication(std::size_t client, const std::string& host, u16 port); + void StartCommunication(std::size_t client, const std::string& host, u16 port, u8 pad_index); PadIdentifier GetPadIdentifier(std::size_t pad_index) const; Common::UUID GetHostUUID(const std::string& host) const; @@ -172,7 +172,7 @@ public: * @param status_callback Callback for job status updates * @param data_callback Called when calibration data is ready */ - explicit CalibrationConfigurationJob(const std::string& host, u16 port, + explicit CalibrationConfigurationJob(const std::string& host, u16 port, u8 pad_index, std::function status_callback, std::function data_callback); ~CalibrationConfigurationJob(); @@ -182,7 +182,7 @@ private: Common::Event complete_event; }; -void TestCommunication(const std::string& host, u16 port, +void TestCommunication(const std::string& host, u16 port, u8 pad_index, const std::function& success_callback, const std::function& failure_callback); diff --git a/src/input_common/helpers/stick_from_buttons.cpp b/src/input_common/helpers/stick_from_buttons.cpp index 94fc53f28..c186e481b 100644 --- a/src/input_common/helpers/stick_from_buttons.cpp +++ b/src/input_common/helpers/stick_from_buttons.cpp @@ -11,6 +11,14 @@ namespace InputCommon { class Stick final : public Common::Input::InputDevice { public: + // Some games such as EARTH DEFENSE FORCE: WORLD BROTHERS + // do not play nicely with the theoretical maximum range. + // Using a value one lower from the maximum emulates real stick behavior. + static constexpr float MAX_RANGE = 32766.0f / 32767.0f; + static constexpr float TAU = Common::PI * 2.0f; + // Use wider angle to ease the transition. + static constexpr float APERTURE = TAU * 0.15f; + using Button = std::unique_ptr; Stick(Button up_, Button down_, Button left_, Button right_, Button modifier_, diff --git a/src/input_common/helpers/udp_protocol.h b/src/input_common/helpers/udp_protocol.h index d9643ffe0..c1fc8fffd 100644 --- a/src/input_common/helpers/udp_protocol.h +++ b/src/input_common/helpers/udp_protocol.h @@ -84,7 +84,7 @@ enum RegisterFlags : u8 { struct Version {}; /** * Requests the server to send information about what controllers are plugged into the ports - * In yuzu's case, we only have one controller, so for simplicity's sake, we can just send a + * In citra's case, we only have one controller, so for simplicity's sake, we can just send a * request explicitly for the first controller port and leave it at that. In the future it would be * nice to make this configurable */ diff --git a/src/input_common/input_engine.h b/src/input_common/input_engine.h index 2ece9c7ca..c361b7cef 100644 --- a/src/input_common/input_engine.h +++ b/src/input_common/input_engine.h @@ -100,6 +100,18 @@ public: // Disable configuring mode for mapping void EndConfiguration(); + // Sets rumble to a controller + virtual Common::Input::DriverResult SetVibration( + [[maybe_unused]] const PadIdentifier& identifier, + [[maybe_unused]] const Common::Input::VibrationStatus& vibration) { + return Common::Input::DriverResult::NotSupported; + } + + // Returns true if device supports vibrations + virtual bool IsVibrationEnabled([[maybe_unused]] const PadIdentifier& identifier) { + return false; + } + // Sets polling mode to a controller virtual Common::Input::PollingError SetPollingMode( [[maybe_unused]] const PadIdentifier& identifier, diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp index ba56727c8..a9ed5f564 100644 --- a/src/input_common/main.cpp +++ b/src/input_common/main.cpp @@ -4,14 +4,6 @@ #include #include "common/input.h" #include "common/param_package.h" -<<<<<<< HEAD -#include "input_common/analog_from_button.h" -#ifdef ENABLE_GCADAPTER -#include "input_common/gcadapter/gc_adapter.h" -#include "input_common/gcadapter/gc_poller.h" -#endif -#include "input_common/keyboard.h" - == == == = #include "input_common/drivers/keyboard.h" #include "input_common/drivers/mouse.h" #include "input_common/drivers/touch_screen.h" @@ -22,8 +14,7 @@ #include "input_common/input_engine.h" #include "input_common/input_mapping.h" #include "input_common/input_poller.h" ->>>>>>> 6e5fec9fe (add input common changes) - #include "input_common/main.h" +#include "input_common/main.h" #ifdef HAVE_LIBUSB #include "input_common/drivers/gc_adapter.h" @@ -32,490 +23,365 @@ #include "input_common/drivers/sdl_driver.h" #endif - namespace InputCommon { +namespace InputCommon { -<<<<<<< HEAD -#ifdef ENABLE_GCADAPTER std::shared_ptr < GCButtonFactory> gcbuttons; - std::shared_ptr gcanalog; - std::shared_ptr gcadapter; -#endif - static std::shared_ptr keyboard; - static std::shared_ptr motion_emu; - static std::unique_ptr udp; - static std::unique_ptr sdl; +struct InputSubsystem::Impl { + template + void RegisterEngine(std::string name, std::shared_ptr& engine) { + MappingCallback mapping_callback{[this](const MappingData& data) { RegisterInput(data); }}; - void Init() { -#ifdef ENABLE_GCADAPTER - gcadapter = std::make_shared(); - gcbuttons = std::make_shared(gcadapter); - Input::RegisterFactory("gcpad", gcbuttons); - gcanalog = std::make_shared(gcadapter); - Input::RegisterFactory("gcpad", gcanalog); -#endif - keyboard = std::make_shared(); - Input::RegisterFactory("keyboard", keyboard); - Input::RegisterFactory("analog_from_button", - std::make_shared()); - motion_emu = std::make_shared(); - Input::RegisterFactory("motion_emu", motion_emu); - Input::RegisterFactory("touch_from_button", - std::make_shared()); - == == == = struct InputSubsystem::Impl { - template - void RegisterEngine(std::string name, std::shared_ptr& engine) { - MappingCallback mapping_callback{ - [this](const MappingData& data) { RegisterInput(data); }}; + engine = std::make_shared(name); + engine->SetMappingCallback(mapping_callback); - engine = std::make_shared(name); - engine->SetMappingCallback(mapping_callback); ->>>>>>> 6e5fec9fe (add input common changes) + std::shared_ptr input_factory = std::make_shared(engine); + std::shared_ptr output_factory = std::make_shared(engine); + Common::Input::RegisterInputFactory(engine->GetEngineName(), std::move(input_factory)); + Common::Input::RegisterOutputFactory(engine->GetEngineName(), std::move(output_factory)); + } - std::shared_ptr input_factory = - std::make_shared(engine); - std::shared_ptr output_factory = - std::make_shared(engine); - Common::Input::RegisterInputFactory(engine->GetEngineName(), - std::move(input_factory)); - Common::Input::RegisterOutputFactory(engine->GetEngineName(), - std::move(output_factory)); - } + void Initialize() { + mapping_factory = std::make_shared(); - void Initialize() { - mapping_factory = std::make_shared(); - - RegisterEngine("keyboard", keyboard); - RegisterEngine("mouse", mouse); - RegisterEngine("touch", touch_screen); + RegisterEngine("keyboard", keyboard); + RegisterEngine("mouse", mouse); + RegisterEngine("touch", touch_screen); #ifdef HAVE_LIBUSB - RegisterEngine("gcpad", gcadapter); + RegisterEngine("gcpad", gcadapter); #endif - RegisterEngine("cemuhookudp", udp_client); - RegisterEngine("virtual_gamepad", virtual_gamepad); + RegisterEngine("cemuhookudp", udp_client); + RegisterEngine("virtual_gamepad", virtual_gamepad); #ifdef HAVE_SDL2 - RegisterEngine("sdl", sdl); + RegisterEngine("sdl", sdl); #endif - Common::Input::RegisterInputFactory("touch_from_button", - std::make_shared()); - Common::Input::RegisterInputFactory("analog_from_button", - std::make_shared()); - } + Common::Input::RegisterInputFactory("touch_from_button", + std::make_shared()); + Common::Input::RegisterInputFactory("analog_from_button", + std::make_shared()); + } - template - void UnregisterEngine(std::shared_ptr& engine) { - Common::Input::UnregisterInputFactory(engine->GetEngineName()); - Common::Input::UnregisterOutputFactory(engine->GetEngineName()); - engine.reset(); - } + template + void UnregisterEngine(std::shared_ptr& engine) { + Common::Input::UnregisterInputFactory(engine->GetEngineName()); + Common::Input::UnregisterOutputFactory(engine->GetEngineName()); + engine.reset(); + } - void Shutdown() { - UnregisterEngine(keyboard); - UnregisterEngine(mouse); - UnregisterEngine(touch_screen); + void Shutdown() { + UnregisterEngine(keyboard); + UnregisterEngine(mouse); + UnregisterEngine(touch_screen); #ifdef HAVE_LIBUSB - UnregisterEngine(gcadapter); + UnregisterEngine(gcadapter); #endif - UnregisterEngine(udp_client); - UnregisterEngine(virtual_gamepad); + UnregisterEngine(udp_client); + UnregisterEngine(virtual_gamepad); #ifdef HAVE_SDL2 - UnregisterEngine(sdl); + UnregisterEngine(sdl); #endif - Common::Input::UnregisterInputFactory("touch_from_button"); - Common::Input::UnregisterInputFactory("analog_from_button"); - } + Common::Input::UnregisterInputFactory("touch_from_button"); + Common::Input::UnregisterInputFactory("analog_from_button"); + } - [[nodiscard]] std::vector GetInputDevices() const { - std::vector devices = { - Common::ParamPackage{{"display", "Any"}, {"engine", "any"}}, - }; + [[nodiscard]] std::vector GetInputDevices() const { + std::vector devices = { + Common::ParamPackage{{"display", "Any"}, {"engine", "any"}}, + }; - 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 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()); #ifdef HAVE_LIBUSB - auto gcadapter_devices = gcadapter->GetInputDevices(); - devices.insert(devices.end(), gcadapter_devices.begin(), gcadapter_devices.end()); + auto gcadapter_devices = gcadapter->GetInputDevices(); + devices.insert(devices.end(), gcadapter_devices.begin(), gcadapter_devices.end()); #endif - auto udp_devices = udp_client->GetInputDevices(); - devices.insert(devices.end(), udp_devices.begin(), udp_devices.end()); + auto udp_devices = udp_client->GetInputDevices(); + devices.insert(devices.end(), udp_devices.begin(), udp_devices.end()); #ifdef HAVE_SDL2 - auto sdl_devices = sdl->GetInputDevices(); - devices.insert(devices.end(), sdl_devices.begin(), sdl_devices.end()); + auto sdl_devices = sdl->GetInputDevices(); + devices.insert(devices.end(), sdl_devices.begin(), sdl_devices.end()); #endif - return devices; - } + return devices; + } - [[nodiscard]] std::shared_ptr GetInputEngine( - const Common::ParamPackage& params) const { - if (!params.Has("engine") || params.Get("engine", "") == "any") { - return nullptr; - } - const std::string engine = params.Get("engine", ""); - if (engine == keyboard->GetEngineName()) { - return keyboard; - } - if (engine == mouse->GetEngineName()) { - return mouse; - } + [[nodiscard]] std::shared_ptr GetInputEngine( + const Common::ParamPackage& params) const { + if (!params.Has("engine") || params.Get("engine", "") == "any") { + return nullptr; + } + const std::string engine = params.Get("engine", ""); + if (engine == keyboard->GetEngineName()) { + return keyboard; + } + if (engine == mouse->GetEngineName()) { + return mouse; + } #ifdef HAVE_LIBUSB - if (engine == gcadapter->GetEngineName()) { - return gcadapter; - } + if (engine == gcadapter->GetEngineName()) { + return gcadapter; + } #endif - if (engine == udp_client->GetEngineName()) { - return udp_client; - } + if (engine == udp_client->GetEngineName()) { + return udp_client; + } #ifdef HAVE_SDL2 - if (engine == sdl->GetEngineName()) { - return sdl; - } + if (engine == sdl->GetEngineName()) { + return sdl; + } #endif - return nullptr; - } + return nullptr; + } - [[nodiscard]] AnalogMapping GetAnalogMappingForDevice( - const Common::ParamPackage& params) const { - const auto input_engine = GetInputEngine(params); + [[nodiscard]] AnalogMapping GetAnalogMappingForDevice( + const Common::ParamPackage& params) const { + const auto input_engine = GetInputEngine(params); - if (input_engine == nullptr) { - return {}; - } - - return input_engine->GetAnalogMappingForDevice(params); - } - - [[nodiscard]] ButtonMapping GetButtonMappingForDevice( - const Common::ParamPackage& params) const { - const auto input_engine = GetInputEngine(params); - - if (input_engine == nullptr) { - return {}; - } - - return input_engine->GetButtonMappingForDevice(params); - } - - [[nodiscard]] MotionMapping GetMotionMappingForDevice( - const Common::ParamPackage& params) const { - const auto input_engine = GetInputEngine(params); - - if (input_engine == nullptr) { - return {}; - } - - return input_engine->GetMotionMappingForDevice(params); - } - - Common::Input::ButtonNames GetButtonName(const Common::ParamPackage& params) const { - if (!params.Has("engine") || params.Get("engine", "") == "any") { - return Common::Input::ButtonNames::Undefined; - } - const auto input_engine = GetInputEngine(params); - - if (input_engine == nullptr) { - return Common::Input::ButtonNames::Invalid; - } - - return input_engine->GetUIName(params); - } - - bool IsStickInverted(const Common::ParamPackage& params) { - const auto input_engine = GetInputEngine(params); - - if (input_engine == nullptr) { - return false; - } - - return input_engine->IsStickInverted(params); - } - - bool IsController(const Common::ParamPackage& params) { - const std::string engine = params.Get("engine", ""); - if (engine == mouse->GetEngineName()) { - return true; - } -#ifdef HAVE_LIBUSB - if (engine == gcadapter->GetEngineName()) { - return true; - } -#endif - if (engine == udp_client->GetEngineName()) { - return true; - } - if (engine == virtual_gamepad->GetEngineName()) { - return true; - } -#ifdef HAVE_SDL2 - if (engine == sdl->GetEngineName()) { - return true; - } -#endif - return false; - } - - void BeginConfiguration() { - keyboard->BeginConfiguration(); - mouse->BeginConfiguration(); -#ifdef HAVE_LIBUSB - gcadapter->BeginConfiguration(); -#endif - udp_client->BeginConfiguration(); -#ifdef HAVE_SDL2 - sdl->BeginConfiguration(); -#endif - } - - void EndConfiguration() { - keyboard->EndConfiguration(); - mouse->EndConfiguration(); -#ifdef HAVE_LIBUSB - gcadapter->EndConfiguration(); -#endif - udp_client->EndConfiguration(); -#ifdef HAVE_SDL2 - sdl->EndConfiguration(); -#endif - } - - void PumpEvents() const { -#ifdef HAVE_SDL2 - sdl->PumpEvents(); -#endif - } - - void RegisterInput(const MappingData& data) { - mapping_factory->RegisterInput(data); - } - - std::shared_ptr mapping_factory; - - std::shared_ptr keyboard; - std::shared_ptr mouse; - std::shared_ptr touch_screen; - std::shared_ptr udp_client; - std::shared_ptr virtual_gamepad; - -#ifdef HAVE_LIBUSB - std::shared_ptr gcadapter; -#endif - -#ifdef HAVE_SDL2 - std::shared_ptr sdl; -#endif - }; - - InputSubsystem::InputSubsystem() : impl{std::make_unique()} {} - - InputSubsystem::~InputSubsystem() = default; - - void InputSubsystem::Initialize() { - impl->Initialize(); + if (input_engine == nullptr) { + return {}; } -<<<<<<< HEAD - void Shutdown() { -#ifdef ENABLE_GCADAPTER - Input::UnregisterFactory("gcpad"); - Input::UnregisterFactory("gcpad"); - gcbuttons.reset(); - gcanalog.reset(); + return input_engine->GetAnalogMappingForDevice(params); + } + + [[nodiscard]] ButtonMapping GetButtonMappingForDevice( + const Common::ParamPackage& params) const { + const auto input_engine = GetInputEngine(params); + + if (input_engine == nullptr) { + return {}; + } + + return input_engine->GetButtonMappingForDevice(params); + } + + [[nodiscard]] MotionMapping GetMotionMappingForDevice( + const Common::ParamPackage& params) const { + const auto input_engine = GetInputEngine(params); + + if (input_engine == nullptr) { + return {}; + } + + return input_engine->GetMotionMappingForDevice(params); + } + + Common::Input::ButtonNames GetButtonName(const Common::ParamPackage& params) const { + if (!params.Has("engine") || params.Get("engine", "") == "any") { + return Common::Input::ButtonNames::Undefined; + } + const auto input_engine = GetInputEngine(params); + + if (input_engine == nullptr) { + return Common::Input::ButtonNames::Invalid; + } + + return input_engine->GetUIName(params); + } + + bool IsStickInverted(const Common::ParamPackage& params) { + const auto input_engine = GetInputEngine(params); + + if (input_engine == nullptr) { + return false; + } + + return input_engine->IsStickInverted(params); + } + + bool IsController(const Common::ParamPackage& params) { + const std::string engine = params.Get("engine", ""); + if (engine == mouse->GetEngineName()) { + return true; + } +#ifdef HAVE_LIBUSB + if (engine == gcadapter->GetEngineName()) { + return true; + } #endif - Input::UnregisterFactory("keyboard"); - keyboard.reset(); - Input::UnregisterFactory("analog_from_button"); - Input::UnregisterFactory("motion_emu"); - motion_emu.reset(); - Input::UnregisterFactory("emu_window"); - Input::UnregisterFactory("touch_from_button"); - sdl.reset(); - udp.reset(); - == == == = void InputSubsystem::Shutdown() { - impl->Shutdown(); ->>>>>>> 6e5fec9fe (add input common changes) - } - - 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(); - } - - VirtualGamepad* InputSubsystem::GetVirtualGamepad() { - return impl->virtual_gamepad.get(); - } - - const VirtualGamepad* InputSubsystem::GetVirtualGamepad() const { - return impl->virtual_gamepad.get(); - } - - std::vector InputSubsystem::GetInputDevices() const { - return impl->GetInputDevices(); - } - - AnalogMapping InputSubsystem::GetAnalogMappingForDevice( - const Common::ParamPackage& device) const { - return impl->GetAnalogMappingForDevice(device); - } - - ButtonMapping InputSubsystem::GetButtonMappingForDevice( - const Common::ParamPackage& device) const { - return impl->GetButtonMappingForDevice(device); - } - - MotionMapping InputSubsystem::GetMotionMappingForDevice( - const Common::ParamPackage& device) const { - return impl->GetMotionMappingForDevice(device); - } - - Common::Input::ButtonNames InputSubsystem::GetButtonName( - const Common::ParamPackage& params) const { - return impl->GetButtonName(params); - } - - bool InputSubsystem::IsController(const Common::ParamPackage& params) const { - return impl->IsController(params); - } - - bool InputSubsystem::IsStickInverted(const Common::ParamPackage& params) const { - if (params.Has("axis_x") && params.Has("axis_y")) { - return impl->IsStickInverted(params); - } - return false; - } - - void InputSubsystem::ReloadInputDevices() { - impl->udp_client.get()->ReloadSockets(); - } - - void InputSubsystem::BeginMapping(Polling::InputType type) { - impl->BeginConfiguration(); - impl->mapping_factory->BeginMapping(type); - } - - Common::ParamPackage InputSubsystem::GetNextInput() const { - return impl->mapping_factory->GetNextInput(); - } - - void InputSubsystem::StopMapping() const { - impl->EndConfiguration(); - impl->mapping_factory->StopMapping(); - } - - void InputSubsystem::PumpEvents() const { - impl->PumpEvents(); - } - - std::string GenerateKeyboardParam(int key_code) { - Common::ParamPackage param; - param.Set("engine", "keyboard"); - param.Set("code", key_code); - param.Set("toggle", false); - return param.Serialize(); - } - - std::string GenerateAnalogParamFromKeys(int key_up, int key_down, int key_left, - int key_right, int key_modifier, - float modifier_scale) { - Common::ParamPackage circle_pad_param{ - {"engine", "analog_from_button"}, - {"up", GenerateKeyboardParam(key_up)}, - {"down", GenerateKeyboardParam(key_down)}, - {"left", GenerateKeyboardParam(key_left)}, - {"right", GenerateKeyboardParam(key_right)}, - {"modifier", GenerateKeyboardParam(key_modifier)}, - {"modifier_scale", std::to_string(modifier_scale)}, - }; - return circle_pad_param.Serialize(); - } -<<<<<<< HEAD - - Common::ParamPackage GetControllerButtonBinds(const Common::ParamPackage& params, - int button) { - const auto native_button{static_cast(button)}; - const auto engine{params.Get("engine", "")}; - if (engine == "sdl") { - return dynamic_cast(sdl.get()) - ->GetSDLControllerButtonBindByGUID(params.Get("guid", "0"), - params.Get("port", 0), native_button); - } -#ifdef ENABLE_GCADAPTER - if (engine == "gcpad") { - return gcbuttons->GetGcTo3DSMappedButton(params.Get("port", 0), native_button); - } + if (engine == udp_client->GetEngineName()) { + return true; + } + if (engine == virtual_gamepad->GetEngineName()) { + return true; + } +#ifdef HAVE_SDL2 + if (engine == sdl->GetEngineName()) { + return true; + } #endif - return {}; - } + return false; + } - Common::ParamPackage GetControllerAnalogBinds(const Common::ParamPackage& params, - int analog) { - const auto native_analog{static_cast(analog)}; - const auto engine{params.Get("engine", "")}; - if (engine == "sdl") { - return dynamic_cast(sdl.get()) - ->GetSDLControllerAnalogBindByGUID(params.Get("guid", "0"), - params.Get("port", 0), native_analog); - } -#ifdef ENABLE_GCADAPTER - if (engine == "gcpad") { - return gcanalog->GetGcTo3DSMappedAnalog(params.Get("port", 0), native_analog); - } + void BeginConfiguration() { + keyboard->BeginConfiguration(); + mouse->BeginConfiguration(); +#ifdef HAVE_LIBUSB + gcadapter->BeginConfiguration(); #endif - return {}; - } + udp_client->BeginConfiguration(); +#ifdef HAVE_SDL2 + sdl->BeginConfiguration(); +#endif + } - void ReloadInputDevices() { - if (!udp) { - return; - } - udp->ReloadUDPClient(); - } + void EndConfiguration() { + keyboard->EndConfiguration(); + mouse->EndConfiguration(); +#ifdef HAVE_LIBUSB + gcadapter->EndConfiguration(); +#endif + udp_client->EndConfiguration(); +#ifdef HAVE_SDL2 + sdl->EndConfiguration(); +#endif + } - namespace Polling { + void PumpEvents() const { +#ifdef HAVE_SDL2 + sdl->PumpEvents(); +#endif + } - std::vector> GetPollers(DeviceType type) { - std::vector> pollers; + void RegisterInput(const MappingData& data) { + mapping_factory->RegisterInput(data); + } + + std::shared_ptr mapping_factory; + + std::shared_ptr keyboard; + std::shared_ptr mouse; + std::shared_ptr touch_screen; + std::shared_ptr udp_client; + std::shared_ptr virtual_gamepad; + +#ifdef HAVE_LIBUSB + std::shared_ptr gcadapter; +#endif #ifdef HAVE_SDL2 - pollers = sdl->GetPollers(type); -#endif -#ifdef ENABLE_GCADAPTER - switch (type) { - case DeviceType::Analog: - pollers.push_back(std::make_unique(*gcanalog)); - break; - case DeviceType::Button: - pollers.push_back(std::make_unique(*gcbuttons)); - break; - default: - break; - } + std::shared_ptr sdl; #endif +}; - return pollers; - } +InputSubsystem::InputSubsystem() : impl{std::make_unique()} {} - } // namespace Polling - == == == = ->>>>>>> 6e5fec9fe (add input common changes) - } // namespace InputCommon +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(); +} + +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(); +} + +VirtualGamepad* InputSubsystem::GetVirtualGamepad() { + return impl->virtual_gamepad.get(); +} + +const VirtualGamepad* InputSubsystem::GetVirtualGamepad() const { + return impl->virtual_gamepad.get(); +} + +std::vector InputSubsystem::GetInputDevices() const { + return impl->GetInputDevices(); +} + +AnalogMapping InputSubsystem::GetAnalogMappingForDevice(const Common::ParamPackage& device) const { + return impl->GetAnalogMappingForDevice(device); +} + +ButtonMapping InputSubsystem::GetButtonMappingForDevice(const Common::ParamPackage& device) const { + return impl->GetButtonMappingForDevice(device); +} + +MotionMapping InputSubsystem::GetMotionMappingForDevice(const Common::ParamPackage& device) const { + return impl->GetMotionMappingForDevice(device); +} + +Common::Input::ButtonNames InputSubsystem::GetButtonName(const Common::ParamPackage& params) const { + return impl->GetButtonName(params); +} + +bool InputSubsystem::IsController(const Common::ParamPackage& params) const { + return impl->IsController(params); +} + +bool InputSubsystem::IsStickInverted(const Common::ParamPackage& params) const { + if (params.Has("axis_x") && params.Has("axis_y")) { + return impl->IsStickInverted(params); + } + return false; +} + +void InputSubsystem::ReloadInputDevices() { + impl->udp_client.get()->ReloadSockets(); +} + +void InputSubsystem::BeginMapping(Polling::InputType type) { + impl->BeginConfiguration(); + impl->mapping_factory->BeginMapping(type); +} + +Common::ParamPackage InputSubsystem::GetNextInput() const { + return impl->mapping_factory->GetNextInput(); +} + +void InputSubsystem::StopMapping() const { + impl->EndConfiguration(); + impl->mapping_factory->StopMapping(); +} + +void InputSubsystem::PumpEvents() const { + impl->PumpEvents(); +} + +std::string GenerateKeyboardParam(int key_code) { + Common::ParamPackage param; + param.Set("engine", "keyboard"); + param.Set("code", key_code); + param.Set("toggle", false); + return param.Serialize(); +} + +std::string GenerateAnalogParamFromKeys(int key_up, int key_down, int key_left, int key_right, + int key_modifier, float modifier_scale) { + Common::ParamPackage circle_pad_param{ + {"engine", "analog_from_button"}, + {"up", GenerateKeyboardParam(key_up)}, + {"down", GenerateKeyboardParam(key_down)}, + {"left", GenerateKeyboardParam(key_left)}, + {"right", GenerateKeyboardParam(key_right)}, + {"modifier", GenerateKeyboardParam(key_modifier)}, + {"modifier_scale", std::to_string(modifier_scale)}, + }; + return circle_pad_param.Serialize(); +} +} // namespace InputCommon