diff --git a/README.md b/README.md index 1f1f1fb23..057adfcb6 100755 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ yuzu emulator early access ============= -This is the source code for early-access 2198. +This is the source code for early-access 2199. ## Legal Notice diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 919da4a53..23d43a394 100755 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -73,7 +73,6 @@ add_library(common STATIC hex_util.h host_memory.cpp host_memory.h - input.h intrusive_red_black_tree.h literals.h logging/backend.cpp diff --git a/src/common/settings.h b/src/common/settings.h index ca30356bc..c7610ef1c 100755 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -559,15 +560,19 @@ struct Values { Setting enable_accurate_vibrations{false, "enable_accurate_vibrations"}; Setting motion_enabled{true, "motion_enabled"}; + BasicSetting motion_device{"engine:motion_emu,update_period:100,sensitivity:0.01", + "motion_device"}; BasicSetting udp_input_servers{"127.0.0.1:26760", "udp_input_servers"}; BasicSetting pause_tas_on_load{true, "pause_tas_on_load"}; BasicSetting tas_enable{false, "tas_enable"}; BasicSetting tas_loop{false, "tas_loop"}; + BasicSetting tas_swap_controllers{true, "tas_swap_controllers"}; BasicSetting mouse_panning{false, "mouse_panning"}; BasicRangedSetting mouse_panning_sensitivity{10, 1, 100, "mouse_panning_sensitivity"}; BasicSetting mouse_enabled{false, "mouse_enabled"}; + std::string mouse_device; MouseButtonsRaw mouse_buttons; BasicSetting emulate_analog_keyboard{false, "emulate_analog_keyboard"}; @@ -581,11 +586,14 @@ struct Values { TouchscreenInput touchscreen; + BasicSetting use_touch_from_button{false, "use_touch_from_button"}; BasicSetting touch_device{"min_x:100,min_y:50,max_x:1800,max_y:850", "touch_device"}; BasicSetting touch_from_button_map_index{0, "touch_from_button_map"}; std::vector touch_from_button_maps; + std::atomic_bool is_device_reload_pending{true}; + // Data Storage BasicSetting use_virtual_sd{true, "use_virtual_sd"}; BasicSetting gamecard_inserted{false, "gamecard_inserted"}; diff --git a/src/common/settings_input.h b/src/common/settings_input.h index a2982fca4..609600582 100755 --- a/src/common/settings_input.h +++ b/src/common/settings_input.h @@ -62,22 +62,11 @@ enum Values : int { constexpr int STICK_HID_BEGIN = LStick; constexpr int STICK_HID_END = NumAnalogs; +constexpr int NUM_STICKS_HID = NumAnalogs; extern const std::array mapping; } // namespace NativeAnalog -namespace NativeTrigger { -enum Values : int { - LTrigger, - RTrigger, - - NumTriggers, -}; - -constexpr int TRIGGER_HID_BEGIN = LTrigger; -constexpr int TRIGGER_HID_END = NumTriggers; -} // namespace NativeTrigger - namespace NativeVibration { enum Values : int { LeftVibrationDevice, @@ -129,6 +118,7 @@ extern const std::array mapping; namespace NativeKeyboard { enum Keys { None, + Error, A = 4, B, @@ -166,22 +156,22 @@ enum Keys { N8, N9, N0, - Return, + Enter, Escape, Backspace, Tab, Space, Minus, - Plus, - OpenBracket, - CloseBracket, - Pipe, + Equal, + LeftBrace, + RightBrace, + Backslash, Tilde, Semicolon, - Quote, - Backquote, + Apostrophe, + Grave, Comma, - Period, + Dot, Slash, CapsLockKey, @@ -198,7 +188,7 @@ enum Keys { F11, F12, - PrintScreen, + SystemRequest, ScrollLockKey, Pause, Insert, @@ -267,18 +257,8 @@ enum Keys { ScrollLockActive, KPComma, - Ro = 0x87, - KatakanaHiragana, - Yen, - Henkan, - Muhenkan, - NumPadCommaPc98, - - HangulEnglish = 0x90, - Hanja, - KatakanaKey, - HiraganaKey, - ZenkakuHankaku, + KPLeftParenthesis, + KPRightParenthesis, LeftControlKey = 0xE0, LeftShiftKey, @@ -327,8 +307,6 @@ enum Modifiers { CapsLock, ScrollLock, NumLock, - Katakana, - Hiragana, NumKeyboardMods, }; diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 582c15f7e..9f0fbba2d 100755 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -132,23 +132,11 @@ add_library(core STATIC frontend/emu_window.h frontend/framebuffer_layout.cpp frontend/framebuffer_layout.h + frontend/input_interpreter.cpp + frontend/input_interpreter.h + frontend/input.h hardware_interrupt_manager.cpp hardware_interrupt_manager.h - hid/emulated_console.cpp - hid/emulated_console.h - hid/emulated_controller.cpp - hid/emulated_controller.h - hid/emulated_devices.cpp - hid/emulated_devices.h - hid/hid_core.cpp - hid/hid_core.h - hid/hid_types.h - hid/input_converter.cpp - hid/input_converter.h - hid/input_interpreter.cpp - hid/input_interpreter.h - hid/motion_input.cpp - hid/motion_input.h hle/api_version.h hle/ipc.h hle/ipc_helpers.h @@ -414,7 +402,6 @@ add_library(core STATIC hle/service/hid/hid.h hle/service/hid/irs.cpp hle/service/hid/irs.h - hle/service/hid/ring_lifo.h hle/service/hid/xcd.cpp hle/service/hid/xcd.h hle/service/hid/errors.h diff --git a/src/core/core.cpp b/src/core/core.cpp index 473ab9f81..07448fd29 100755 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -27,7 +27,6 @@ #include "core/file_sys/vfs_concat.h" #include "core/file_sys/vfs_real.h" #include "core/hardware_interrupt_manager.h" -#include "core/hid/hid_core.h" #include "core/hle/kernel/k_process.h" #include "core/hle/kernel/k_scheduler.h" #include "core/hle/kernel/kernel.h" @@ -127,7 +126,7 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs, struct System::Impl { explicit Impl(System& system) - : kernel{system}, fs_controller{system}, memory{system}, hid_core{}, + : kernel{system}, fs_controller{system}, memory{system}, cpu_manager{system}, reporter{system}, applet_manager{system}, time_manager{system} {} SystemResultStatus Run() { @@ -392,7 +391,6 @@ struct System::Impl { std::unique_ptr interrupt_manager; std::unique_ptr device_memory; Core::Memory::Memory memory; - Core::HID::HIDCore hid_core; CpuManager cpu_manager; std::atomic_bool is_powered_on{}; bool exit_lock = false; @@ -617,14 +615,6 @@ const Kernel::KernelCore& System::Kernel() const { return impl->kernel; } -HID::HIDCore& System::HIDCore() { - return impl->hid_core; -} - -const HID::HIDCore& System::HIDCore() const { - return impl->hid_core; -} - Timing::CoreTiming& System::CoreTiming() { return impl->core_timing; } @@ -835,6 +825,8 @@ void System::ApplySettings() { if (IsPoweredOn()) { Renderer().RefreshBaseSettings(); } + + Service::HID::ReloadInputDevices(); } } // namespace Core diff --git a/src/core/core.h b/src/core/core.h index 645e5c241..01bc0a2c7 100755 --- a/src/core/core.h +++ b/src/core/core.h @@ -89,10 +89,6 @@ namespace Core::Hardware { class InterruptManager; } -namespace Core::HID { -class HIDCore; -} - namespace Core { class ARM_Interface; @@ -289,12 +285,6 @@ public: /// Provides a constant reference to the kernel instance. [[nodiscard]] const Kernel::KernelCore& Kernel() const; - /// Gets a mutable reference to the HID interface. - [[nodiscard]] HID::HIDCore& HIDCore(); - - /// Gets an immutable reference to the HID interface. - [[nodiscard]] const HID::HIDCore& HIDCore() const; - /// Provides a reference to the internal PerfStats instance. [[nodiscard]] Core::PerfStats& GetPerfStats(); diff --git a/src/core/frontend/applets/controller.cpp b/src/core/frontend/applets/controller.cpp index 6dbd38ffa..03bbedf8b 100755 --- a/src/core/frontend/applets/controller.cpp +++ b/src/core/frontend/applets/controller.cpp @@ -5,15 +5,16 @@ #include "common/assert.h" #include "common/logging/log.h" #include "core/frontend/applets/controller.h" -#include "core/hid/emulated_controller.h" -#include "core/hid/hid_core.h" -#include "core/hid/hid_types.h" +#include "core/hle/service/hid/controllers/npad.h" +#include "core/hle/service/hid/hid.h" +#include "core/hle/service/sm/sm.h" namespace Core::Frontend { ControllerApplet::~ControllerApplet() = default; -DefaultControllerApplet::DefaultControllerApplet(HID::HIDCore& hid_core_) : hid_core{hid_core_} {} +DefaultControllerApplet::DefaultControllerApplet(Service::SM::ServiceManager& service_manager_) + : service_manager{service_manager_} {} DefaultControllerApplet::~DefaultControllerApplet() = default; @@ -21,20 +22,24 @@ void DefaultControllerApplet::ReconfigureControllers(std::function callb const ControllerParameters& parameters) const { LOG_INFO(Service_HID, "called, deducing the best configuration based on the given parameters!"); + auto& npad = + service_manager.GetService("hid") + ->GetAppletResource() + ->GetController(Service::HID::HidController::NPad); + + auto& players = Settings::values.players.GetValue(); + const std::size_t min_supported_players = parameters.enable_single_mode ? 1 : parameters.min_players; // Disconnect Handheld first. - auto* handheld = hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld); - handheld->Disconnect(); + npad.DisconnectNpadAtIndex(8); // Deduce the best configuration based on the input parameters. - for (std::size_t index = 0; index < hid_core.available_controllers - 2; ++index) { - auto* controller = hid_core.GetEmulatedControllerByIndex(index); - + for (std::size_t index = 0; index < players.size() - 2; ++index) { // First, disconnect all controllers regardless of the value of keep_controllers_connected. // This makes it easy to connect the desired controllers. - controller->Disconnect(); + npad.DisconnectNpadAtIndex(index); // Only connect the minimum number of required players. if (index >= min_supported_players) { @@ -44,27 +49,27 @@ void DefaultControllerApplet::ReconfigureControllers(std::function callb // Connect controllers based on the following priority list from highest to lowest priority: // Pro Controller -> Dual Joycons -> Left Joycon/Right Joycon -> Handheld if (parameters.allow_pro_controller) { - controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::ProController); - controller->Connect(); + npad.AddNewControllerAt( + npad.MapSettingsTypeToNPad(Settings::ControllerType::ProController), index); } else if (parameters.allow_dual_joycons) { - controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconDual); - controller->Connect(); + npad.AddNewControllerAt( + npad.MapSettingsTypeToNPad(Settings::ControllerType::DualJoyconDetached), index); } else if (parameters.allow_left_joycon && parameters.allow_right_joycon) { // Assign left joycons to even player indices and right joycons to odd player indices. // We do this since Captain Toad Treasure Tracker expects a left joycon for Player 1 and // a right Joycon for Player 2 in 2 Player Assist mode. if (index % 2 == 0) { - controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconLeft); - controller->Connect(); + npad.AddNewControllerAt( + npad.MapSettingsTypeToNPad(Settings::ControllerType::LeftJoycon), index); } else { - controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconRight); - controller->Connect(); + npad.AddNewControllerAt( + npad.MapSettingsTypeToNPad(Settings::ControllerType::RightJoycon), index); } } else if (index == 0 && parameters.enable_single_mode && parameters.allow_handheld && !Settings::values.use_docked_mode.GetValue()) { // We should *never* reach here under any normal circumstances. - controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Handheld); - controller->Connect(); + npad.AddNewControllerAt(npad.MapSettingsTypeToNPad(Settings::ControllerType::Handheld), + index); } else { UNREACHABLE_MSG("Unable to add a new controller based on the given parameters!"); } diff --git a/src/core/frontend/applets/controller.h b/src/core/frontend/applets/controller.h index 014bc8901..b0626a0f9 100755 --- a/src/core/frontend/applets/controller.h +++ b/src/core/frontend/applets/controller.h @@ -8,8 +8,8 @@ #include "common/common_types.h" -namespace Core::HID { -class HIDCore; +namespace Service::SM { +class ServiceManager; } namespace Core::Frontend { @@ -44,14 +44,14 @@ public: class DefaultControllerApplet final : public ControllerApplet { public: - explicit DefaultControllerApplet(HID::HIDCore& hid_core_); + explicit DefaultControllerApplet(Service::SM::ServiceManager& service_manager_); ~DefaultControllerApplet() override; void ReconfigureControllers(std::function callback, const ControllerParameters& parameters) const override; private: - HID::HIDCore& hid_core; + Service::SM::ServiceManager& service_manager; }; } // namespace Core::Frontend diff --git a/src/core/frontend/emu_window.cpp b/src/core/frontend/emu_window.cpp index 57c6ffc43..e1f7e5886 100755 --- a/src/core/frontend/emu_window.cpp +++ b/src/core/frontend/emu_window.cpp @@ -3,31 +3,66 @@ // Refer to the license.txt file included. #include +#include "common/settings.h" #include "core/frontend/emu_window.h" +#include "core/frontend/input.h" namespace Core::Frontend { GraphicsContext::~GraphicsContext() = default; +class EmuWindow::TouchState : public Input::Factory, + public std::enable_shared_from_this { +public: + std::unique_ptr Create(const Common::ParamPackage&) override { + return std::make_unique(shared_from_this()); + } + + std::mutex mutex; + + Input::TouchStatus status; + +private: + class Device : public Input::TouchDevice { + public: + explicit Device(std::weak_ptr&& touch_state_) : touch_state(touch_state_) {} + Input::TouchStatus GetStatus() const override { + if (auto state = touch_state.lock()) { + std::lock_guard guard{state->mutex}; + return state->status; + } + return {}; + } + + private: + std::weak_ptr touch_state; + }; +}; + EmuWindow::EmuWindow() { // TODO: Find a better place to set this. config.min_client_area_size = std::make_pair(Layout::MinimumSize::Width, Layout::MinimumSize::Height); active_config = config; + touch_state = std::make_shared(); + Input::RegisterFactory("emu_window", touch_state); } -EmuWindow::~EmuWindow() {} +EmuWindow::~EmuWindow() { + Input::UnregisterFactory("emu_window"); +} -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.screen.left) / - static_cast(framebuffer_layout.screen.right - framebuffer_layout.screen.left); - const float y = - static_cast(framebuffer_y - framebuffer_layout.screen.top) / - static_cast(framebuffer_layout.screen.bottom - framebuffer_layout.screen.top); - - return std::make_pair(x, y); +/** + * 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, u32 framebuffer_x, + u32 framebuffer_y) { + return (framebuffer_y >= layout.screen.top && framebuffer_y < layout.screen.bottom && + framebuffer_x >= layout.screen.left && framebuffer_x < layout.screen.right); } std::pair EmuWindow::ClipToTouchScreen(u32 new_x, u32 new_y) const { @@ -40,6 +75,49 @@ std::pair EmuWindow::ClipToTouchScreen(u32 new_x, u32 new_y) const { return std::make_pair(new_x, new_y); } +void EmuWindow::TouchPressed(u32 framebuffer_x, u32 framebuffer_y, size_t id) { + if (!IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y)) { + return; + } + if (id >= touch_state->status.size()) { + return; + } + + std::lock_guard guard{touch_state->mutex}; + const float x = + static_cast(framebuffer_x - framebuffer_layout.screen.left) / + static_cast(framebuffer_layout.screen.right - framebuffer_layout.screen.left); + const float y = + static_cast(framebuffer_y - framebuffer_layout.screen.top) / + static_cast(framebuffer_layout.screen.bottom - framebuffer_layout.screen.top); + + touch_state->status[id] = std::make_tuple(x, y, true); +} + +void EmuWindow::TouchReleased(size_t id) { + if (id >= touch_state->status.size()) { + return; + } + std::lock_guard guard{touch_state->mutex}; + touch_state->status[id] = std::make_tuple(0.0f, 0.0f, false); +} + +void EmuWindow::TouchMoved(u32 framebuffer_x, u32 framebuffer_y, size_t id) { + if (id >= touch_state->status.size()) { + return; + } + + if (!std::get<2>(touch_state->status[id])) { + return; + } + + if (!IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y)) { + std::tie(framebuffer_x, framebuffer_y) = ClipToTouchScreen(framebuffer_x, framebuffer_y); + } + + TouchPressed(framebuffer_x, framebuffer_y, id); +} + void EmuWindow::UpdateCurrentFramebufferLayout(u32 width, u32 height) { NotifyFramebufferLayoutChanged(Layout::DefaultFrameLayout(width, height)); } diff --git a/src/core/frontend/emu_window.h b/src/core/frontend/emu_window.h index e413a520a..8a86a1d27 100755 --- a/src/core/frontend/emu_window.h +++ b/src/core/frontend/emu_window.h @@ -112,6 +112,28 @@ public: /// Returns if window is shown (not minimized) virtual bool IsShown() const = 0; + /** + * Signal that a touch pressed event has occurred (e.g. mouse click pressed) + * @param framebuffer_x Framebuffer x-coordinate that was pressed + * @param framebuffer_y Framebuffer y-coordinate that was pressed + * @param id Touch event ID + */ + void TouchPressed(u32 framebuffer_x, u32 framebuffer_y, size_t id); + + /** + * Signal that a touch released event has occurred (e.g. mouse click released) + * @param id Touch event ID + */ + void TouchReleased(size_t id); + + /** + * Signal that a touch movement event has occurred (e.g. mouse was moved over the emu window) + * @param framebuffer_x Framebuffer x-coordinate + * @param framebuffer_y Framebuffer y-coordinate + * @param id Touch event ID + */ + void TouchMoved(u32 framebuffer_x, u32 framebuffer_y, size_t id); + /** * Returns currently active configuration. * @note Accesses to the returned object need not be consistent because it may be modified in @@ -190,11 +212,6 @@ protected: client_area_height = size.second; } - /** - * Converts a screen postion into the equivalent touchscreen position. - */ - std::pair MapToTouchScreen(u32 framebuffer_x, u32 framebuffer_y) const; - WindowSystemInfo window_info; private: @@ -220,6 +237,9 @@ private: WindowConfig config; ///< Internal configuration (changes pending for being applied in /// ProcessConfigurationChanges) WindowConfig active_config; ///< Internal active configuration + + class TouchState; + std::shared_ptr touch_state; }; } // namespace Core::Frontend diff --git a/src/core/hle/service/am/applets/applet_controller.cpp b/src/core/hle/service/am/applets/applet_controller.cpp index d073f2210..2721679c1 100755 --- a/src/core/hle/service/am/applets/applet_controller.cpp +++ b/src/core/hle/service/am/applets/applet_controller.cpp @@ -10,9 +10,6 @@ #include "common/string_util.h" #include "core/core.h" #include "core/frontend/applets/controller.h" -#include "core/hid/emulated_controller.h" -#include "core/hid/hid_core.h" -#include "core/hid/hid_types.h" #include "core/hle/result.h" #include "core/hle/service/am/am.h" #include "core/hle/service/am/applets/applet_controller.h" @@ -28,7 +25,7 @@ namespace Service::AM::Applets { static Core::Frontend::ControllerParameters ConvertToFrontendParameters( ControllerSupportArgPrivate private_arg, ControllerSupportArgHeader header, bool enable_text, std::vector identification_colors, std::vector text) { - Core::HID::NpadStyleTag npad_style_set; + HID::Controller_NPad::NpadStyleSet npad_style_set; npad_style_set.raw = private_arg.style_set; return { @@ -246,11 +243,19 @@ void Controller::Execute() { void Controller::ConfigurationComplete() { ControllerSupportResultInfo result_info{}; + const auto& players = Settings::values.players.GetValue(); + // If enable_single_mode is enabled, player_count is 1 regardless of any other parameters. // Otherwise, only count connected players from P1-P8. - result_info.player_count = is_single_mode ? 1 : system.HIDCore().GetPlayerCount(); + result_info.player_count = + is_single_mode + ? 1 + : static_cast(std::count_if(players.begin(), players.end() - 2, + [](const auto& player) { return player.connected; })); - result_info.selected_id = static_cast(system.HIDCore().GetFirstNpadId()); + result_info.selected_id = HID::Controller_NPad::IndexToNPad(std::distance( + players.begin(), std::find_if(players.begin(), players.end(), + [](const auto& player) { return player.connected; }))); result_info.result = 0; diff --git a/src/core/hle/service/am/applets/applet_controller.h b/src/core/hle/service/am/applets/applet_controller.h index 1a832505e..0a34c4fc0 100755 --- a/src/core/hle/service/am/applets/applet_controller.h +++ b/src/core/hle/service/am/applets/applet_controller.h @@ -16,10 +16,6 @@ namespace Core { class System; } -namespace Core::HID { -enum class NpadStyleSet : u32; -} - namespace Service::AM::Applets { using IdentificationColor = std::array; @@ -56,7 +52,7 @@ struct ControllerSupportArgPrivate { bool flag_1{}; ControllerSupportMode mode{}; ControllerSupportCaller caller{}; - Core::HID::NpadStyleSet style_set{}; + u32 style_set{}; u32 joy_hold_type{}; }; static_assert(sizeof(ControllerSupportArgPrivate) == 0x14, diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp index 134ac1ee2..7320b1c0f 100755 --- a/src/core/hle/service/am/applets/applets.cpp +++ b/src/core/hle/service/am/applets/applets.cpp @@ -231,7 +231,7 @@ void AppletManager::SetDefaultAppletFrontendSet() { void AppletManager::SetDefaultAppletsIfMissing() { if (frontend.controller == nullptr) { frontend.controller = - std::make_unique(system.HIDCore()); + std::make_unique(system.ServiceManager()); } if (frontend.error == nullptr) { diff --git a/src/core/hle/service/hid/controllers/console_sixaxis.cpp b/src/core/hle/service/hid/controllers/console_sixaxis.cpp index ea7e8f18f..bda6e2557 100755 --- a/src/core/hle/service/hid/controllers/console_sixaxis.cpp +++ b/src/core/hle/service/hid/controllers/console_sixaxis.cpp @@ -4,18 +4,13 @@ #include "common/settings.h" #include "core/core_timing.h" -#include "core/hid/emulated_console.h" -#include "core/hid/hid_core.h" #include "core/hle/service/hid/controllers/console_sixaxis.h" namespace Service::HID { constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3C200; -Controller_ConsoleSixAxis::Controller_ConsoleSixAxis(Core::HID::HIDCore& hid_core_) - : ControllerBase{hid_core_} { - console = hid_core.GetEmulatedConsole(); -} - +Controller_ConsoleSixAxis::Controller_ConsoleSixAxis(Core::System& system_) + : ControllerBase{system_} {} Controller_ConsoleSixAxis::~Controller_ConsoleSixAxis() = default; void Controller_ConsoleSixAxis::OnInit() {} @@ -43,21 +38,25 @@ void Controller_ConsoleSixAxis::OnUpdate(const Core::Timing::CoreTiming& core_ti cur_entry.sampling_number2 = cur_entry.sampling_number; // Try to read sixaxis sensor states - const auto motion_status = console->GetMotion(); + MotionDevice motion_device{}; + const auto& device = motions[0]; + if (device) { + std::tie(motion_device.accel, motion_device.gyro, motion_device.rotation, + motion_device.orientation, motion_device.quaternion) = device->GetStatus(); + console_six_axis.is_seven_six_axis_sensor_at_rest = motion_device.gyro.Length2() < 0.0001f; + } - console_six_axis.is_seven_six_axis_sensor_at_rest = motion_status.is_at_rest; - - cur_entry.accel = motion_status.accel; + cur_entry.accel = motion_device.accel; // Zero gyro values as they just mess up with the camera // Note: Probably a correct sensivity setting must be set cur_entry.gyro = {}; cur_entry.quaternion = { { - motion_status.quaternion.xyz.y, - motion_status.quaternion.xyz.x, - -motion_status.quaternion.w, + motion_device.quaternion.xyz.y, + motion_device.quaternion.xyz.x, + -motion_device.quaternion.w, }, - -motion_status.quaternion.xyz.z, + -motion_device.quaternion.xyz.z, }; console_six_axis.sampling_number++; @@ -71,6 +70,13 @@ void Controller_ConsoleSixAxis::OnUpdate(const Core::Timing::CoreTiming& core_ti std::memcpy(transfer_memory, &seven_six_axis, sizeof(seven_six_axis)); } +void Controller_ConsoleSixAxis::OnLoadInputDevices() { + const auto player = Settings::values.players.GetValue()[0]; + std::transform(player.motions.begin() + Settings::NativeMotion::MOTION_HID_BEGIN, + player.motions.begin() + Settings::NativeMotion::MOTION_HID_END, motions.begin(), + Input::CreateDevice); +} + void Controller_ConsoleSixAxis::SetTransferMemoryPointer(u8* t_mem) { is_transfer_memory_set = true; transfer_memory = t_mem; diff --git a/src/core/hle/service/hid/controllers/console_sixaxis.h b/src/core/hle/service/hid/controllers/console_sixaxis.h index 7c92413e8..fd8a427af 100755 --- a/src/core/hle/service/hid/controllers/console_sixaxis.h +++ b/src/core/hle/service/hid/controllers/console_sixaxis.h @@ -5,20 +5,16 @@ #pragma once #include - +#include "common/bit_field.h" #include "common/common_types.h" #include "common/quaternion.h" -#include "core/hid/hid_types.h" +#include "core/frontend/input.h" #include "core/hle/service/hid/controllers/controller_base.h" -namespace Core::HID { -class EmulatedConsole; -} // namespace Core::HID - namespace Service::HID { class Controller_ConsoleSixAxis final : public ControllerBase { public: - explicit Controller_ConsoleSixAxis(Core::HID::HIDCore& hid_core_); + explicit Controller_ConsoleSixAxis(Core::System& system_); ~Controller_ConsoleSixAxis() override; // Called when the controller is initialized @@ -30,6 +26,9 @@ public: // When the controller is requesting an update for the shared memory void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, size_t size) override; + // Called when input devices should be loaded + void OnLoadInputDevices() override; + // Called on InitializeSevenSixAxisSensor void SetTransferMemoryPointer(u8* t_mem); @@ -39,8 +38,8 @@ public: private: struct SevenSixAxisState { INSERT_PADDING_WORDS(4); // unused - s64 sampling_number{}; - s64 sampling_number2{}; + s64_le sampling_number{}; + s64_le sampling_number2{}; u64 unknown{}; Common::Vec3f accel{}; Common::Vec3f gyro{}; @@ -48,24 +47,14 @@ private: }; static_assert(sizeof(SevenSixAxisState) == 0x50, "SevenSixAxisState is an invalid size"); - struct CommonHeader { - s64 timestamp; - s64 total_entry_count; - s64 last_entry_index; - s64 entry_count; - }; - static_assert(sizeof(CommonHeader) == 0x20, "CommonHeader is an invalid size"); - - // TODO(german77): SevenSixAxisMemory doesn't follow the standard lifo. Investigate struct SevenSixAxisMemory { CommonHeader header{}; std::array sevensixaxis_states{}; }; static_assert(sizeof(SevenSixAxisMemory) == 0xA70, "SevenSixAxisMemory is an invalid size"); - // This is nn::hid::detail::ConsoleSixAxisSensorSharedMemoryFormat struct ConsoleSharedMemory { - u64 sampling_number{}; + u64_le sampling_number{}; bool is_seven_six_axis_sensor_at_rest{}; f32 verticalization_error{}; Common::Vec3f gyro_bias{}; @@ -80,7 +69,9 @@ private: Common::Quaternion quaternion; }; - Core::HID::EmulatedConsole* console; + using MotionArray = + std::array, Settings::NativeMotion::NUM_MOTIONS_HID>; + MotionArray motions; u8* transfer_memory = nullptr; bool is_transfer_memory_set = false; ConsoleSharedMemory console_six_axis{}; diff --git a/src/core/hle/service/hid/controllers/controller_base.cpp b/src/core/hle/service/hid/controllers/controller_base.cpp index 788ae9ae7..9d1e6db6a 100755 --- a/src/core/hle/service/hid/controllers/controller_base.cpp +++ b/src/core/hle/service/hid/controllers/controller_base.cpp @@ -6,12 +6,12 @@ namespace Service::HID { -ControllerBase::ControllerBase(Core::HID::HIDCore& hid_core_) : hid_core(hid_core_) {} +ControllerBase::ControllerBase(Core::System& system_) : system(system_) {} ControllerBase::~ControllerBase() = default; void ControllerBase::ActivateController() { if (is_activated) { - return; + OnRelease(); } is_activated = true; OnInit(); diff --git a/src/core/hle/service/hid/controllers/controller_base.h b/src/core/hle/service/hid/controllers/controller_base.h index 8125bbc84..1556fb08e 100755 --- a/src/core/hle/service/hid/controllers/controller_base.h +++ b/src/core/hle/service/hid/controllers/controller_base.h @@ -11,14 +11,14 @@ namespace Core::Timing { class CoreTiming; } -namespace Core::HID { -class HIDCore; +namespace Core { +class System; } namespace Service::HID { class ControllerBase { public: - explicit ControllerBase(Core::HID::HIDCore& hid_core_); + explicit ControllerBase(Core::System& system_); virtual ~ControllerBase(); // Called when the controller is initialized @@ -35,6 +35,9 @@ public: virtual void OnMotionUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) {} + // Called when input devices should be loaded + virtual void OnLoadInputDevices() = 0; + void ActivateController(); void DeactivateController(); @@ -44,6 +47,14 @@ public: protected: bool is_activated{false}; - Core::HID::HIDCore& hid_core; + struct CommonHeader { + s64_le timestamp; + s64_le total_entry_count; + s64_le last_entry_index; + s64_le entry_count; + }; + static_assert(sizeof(CommonHeader) == 0x20, "CommonHeader is an invalid size"); + + Core::System& system; }; } // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/debug_pad.cpp b/src/core/hle/service/hid/controllers/debug_pad.cpp index 6a6fb9cab..d439b8fb0 100755 --- a/src/core/hle/service/hid/controllers/debug_pad.cpp +++ b/src/core/hle/service/hid/controllers/debug_pad.cpp @@ -6,19 +6,15 @@ #include "common/common_types.h" #include "common/settings.h" #include "core/core_timing.h" -#include "core/hid/emulated_controller.h" -#include "core/hid/hid_core.h" -#include "core/hid/hid_types.h" #include "core/hle/service/hid/controllers/debug_pad.h" namespace Service::HID { -constexpr std::size_t SHARED_MEMORY_OFFSET = 0x00000; -Controller_DebugPad::Controller_DebugPad(Core::HID::HIDCore& hid_core_) - : ControllerBase{hid_core_} { - controller = hid_core.GetEmulatedController(Core::HID::NpadIdType::Other); -} +constexpr s32 HID_JOYSTICK_MAX = 0x7fff; +[[maybe_unused]] constexpr s32 HID_JOYSTICK_MIN = -0x7fff; +enum class JoystickId : std::size_t { Joystick_Left, Joystick_Right }; +Controller_DebugPad::Controller_DebugPad(Core::System& system_) : ControllerBase{system_} {} Controller_DebugPad::~Controller_DebugPad() = default; void Controller_DebugPad::OnInit() {} @@ -27,29 +23,63 @@ void Controller_DebugPad::OnRelease() {} void Controller_DebugPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) { + shared_memory.header.timestamp = core_timing.GetCPUTicks(); + shared_memory.header.total_entry_count = 17; + if (!IsControllerActivated()) { - debug_pad_lifo.buffer_count = 0; - debug_pad_lifo.buffer_tail = 0; - std::memcpy(data + SHARED_MEMORY_OFFSET, &debug_pad_lifo, sizeof(debug_pad_lifo)); + shared_memory.header.entry_count = 0; + shared_memory.header.last_entry_index = 0; return; } + shared_memory.header.entry_count = 16; - const auto& last_entry = debug_pad_lifo.ReadCurrentEntry().state; - next_state.sampling_number = last_entry.sampling_number + 1; + const auto& last_entry = shared_memory.pad_states[shared_memory.header.last_entry_index]; + shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17; + auto& cur_entry = shared_memory.pad_states[shared_memory.header.last_entry_index]; + + cur_entry.sampling_number = last_entry.sampling_number + 1; + cur_entry.sampling_number2 = cur_entry.sampling_number; if (Settings::values.debug_pad_enabled) { - next_state.attribute.connected.Assign(1); + cur_entry.attribute.connected.Assign(1); + auto& pad = cur_entry.pad_state; - const auto& button_state = controller->GetDebugPadButtons(); - const auto& stick_state = controller->GetSticks(); + using namespace Settings::NativeButton; + pad.a.Assign(buttons[A - BUTTON_HID_BEGIN]->GetStatus()); + pad.b.Assign(buttons[B - BUTTON_HID_BEGIN]->GetStatus()); + pad.x.Assign(buttons[X - BUTTON_HID_BEGIN]->GetStatus()); + pad.y.Assign(buttons[Y - BUTTON_HID_BEGIN]->GetStatus()); + pad.l.Assign(buttons[L - BUTTON_HID_BEGIN]->GetStatus()); + pad.r.Assign(buttons[R - BUTTON_HID_BEGIN]->GetStatus()); + pad.zl.Assign(buttons[ZL - BUTTON_HID_BEGIN]->GetStatus()); + pad.zr.Assign(buttons[ZR - BUTTON_HID_BEGIN]->GetStatus()); + pad.plus.Assign(buttons[Plus - BUTTON_HID_BEGIN]->GetStatus()); + pad.minus.Assign(buttons[Minus - BUTTON_HID_BEGIN]->GetStatus()); + pad.d_left.Assign(buttons[DLeft - BUTTON_HID_BEGIN]->GetStatus()); + pad.d_up.Assign(buttons[DUp - BUTTON_HID_BEGIN]->GetStatus()); + pad.d_right.Assign(buttons[DRight - BUTTON_HID_BEGIN]->GetStatus()); + pad.d_down.Assign(buttons[DDown - BUTTON_HID_BEGIN]->GetStatus()); - next_state.pad_state = button_state; - next_state.l_stick = stick_state.left; - next_state.r_stick = stick_state.right; + const auto [stick_l_x_f, stick_l_y_f] = + analogs[static_cast(JoystickId::Joystick_Left)]->GetStatus(); + const auto [stick_r_x_f, stick_r_y_f] = + analogs[static_cast(JoystickId::Joystick_Right)]->GetStatus(); + cur_entry.l_stick.x = static_cast(stick_l_x_f * HID_JOYSTICK_MAX); + cur_entry.l_stick.y = static_cast(stick_l_y_f * HID_JOYSTICK_MAX); + cur_entry.r_stick.x = static_cast(stick_r_x_f * HID_JOYSTICK_MAX); + cur_entry.r_stick.y = static_cast(stick_r_y_f * HID_JOYSTICK_MAX); } - debug_pad_lifo.WriteNextEntry(next_state); - std::memcpy(data + SHARED_MEMORY_OFFSET, &debug_pad_lifo, sizeof(debug_pad_lifo)); + std::memcpy(data, &shared_memory, sizeof(SharedMemory)); } +void Controller_DebugPad::OnLoadInputDevices() { + std::transform(Settings::values.debug_pad_buttons.begin(), + Settings::values.debug_pad_buttons.begin() + + Settings::NativeButton::NUM_BUTTONS_HID, + buttons.begin(), Input::CreateDevice); + std::transform(Settings::values.debug_pad_analogs.begin(), + Settings::values.debug_pad_analogs.end(), analogs.begin(), + Input::CreateDevice); +} } // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/debug_pad.h b/src/core/hle/service/hid/controllers/debug_pad.h index 15b3afb7a..1b1645184 100755 --- a/src/core/hle/service/hid/controllers/debug_pad.h +++ b/src/core/hle/service/hid/controllers/debug_pad.h @@ -8,20 +8,15 @@ #include "common/bit_field.h" #include "common/common_funcs.h" #include "common/common_types.h" +#include "common/settings.h" #include "common/swap.h" +#include "core/frontend/input.h" #include "core/hle/service/hid/controllers/controller_base.h" -#include "core/hle/service/hid/ring_lifo.h" - -namespace Core::HID { -class EmulatedController; -struct DebugPadButton; -struct AnalogStickState; -} // namespace Core::HID namespace Service::HID { class Controller_DebugPad final : public ControllerBase { public: - explicit Controller_DebugPad(Core::HID::HIDCore& hid_core_); + explicit Controller_DebugPad(Core::System& system_); ~Controller_DebugPad() override; // Called when the controller is initialized @@ -33,31 +28,66 @@ public: // When the controller is requesting an update for the shared memory void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override; + // Called when input devices should be loaded + void OnLoadInputDevices() override; + private: - // This is nn::hid::DebugPadAttribute - struct DebugPadAttribute { + struct AnalogStick { + s32_le x; + s32_le y; + }; + static_assert(sizeof(AnalogStick) == 0x8); + + struct PadState { union { - u32 raw{}; + u32_le raw{}; + BitField<0, 1, u32> a; + BitField<1, 1, u32> b; + BitField<2, 1, u32> x; + BitField<3, 1, u32> y; + BitField<4, 1, u32> l; + BitField<5, 1, u32> r; + BitField<6, 1, u32> zl; + BitField<7, 1, u32> zr; + BitField<8, 1, u32> plus; + BitField<9, 1, u32> minus; + BitField<10, 1, u32> d_left; + BitField<11, 1, u32> d_up; + BitField<12, 1, u32> d_right; + BitField<13, 1, u32> d_down; + }; + }; + static_assert(sizeof(PadState) == 0x4, "PadState is an invalid size"); + + struct Attributes { + union { + u32_le raw{}; BitField<0, 1, u32> connected; }; }; - static_assert(sizeof(DebugPadAttribute) == 0x4, "DebugPadAttribute is an invalid size"); + static_assert(sizeof(Attributes) == 0x4, "Attributes is an invalid size"); - // This is nn::hid::DebugPadState - struct DebugPadState { - s64 sampling_number; - DebugPadAttribute attribute; - Core::HID::DebugPadButton pad_state; - Core::HID::AnalogStickState r_stick; - Core::HID::AnalogStickState l_stick; + struct PadStates { + s64_le sampling_number; + s64_le sampling_number2; + Attributes attribute; + PadState pad_state; + AnalogStick r_stick; + AnalogStick l_stick; }; - static_assert(sizeof(DebugPadState) == 0x20, "DebugPadState is an invalid state"); + static_assert(sizeof(PadStates) == 0x28, "PadStates is an invalid state"); - // This is nn::hid::detail::DebugPadLifo - Lifo debug_pad_lifo{}; - static_assert(sizeof(debug_pad_lifo) == 0x2C8, "debug_pad_lifo is an invalid size"); - DebugPadState next_state{}; + struct SharedMemory { + CommonHeader header; + std::array pad_states; + INSERT_PADDING_BYTES(0x138); + }; + static_assert(sizeof(SharedMemory) == 0x400, "SharedMemory is an invalid size"); + SharedMemory shared_memory{}; - Core::HID::EmulatedController* controller; + std::array, Settings::NativeButton::NUM_BUTTONS_HID> + buttons; + std::array, Settings::NativeAnalog::NUM_STICKS_HID> + analogs; }; } // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/gesture.cpp b/src/core/hle/service/hid/controllers/gesture.cpp index fe895c4f6..764abb5b6 100755 --- a/src/core/hle/service/hid/controllers/gesture.cpp +++ b/src/core/hle/service/hid/controllers/gesture.cpp @@ -7,7 +7,6 @@ #include "common/settings.h" #include "core/core_timing.h" #include "core/frontend/emu_window.h" -#include "core/hid/hid_core.h" #include "core/hle/service/hid/controllers/gesture.h" namespace Service::HID { @@ -24,14 +23,16 @@ constexpr f32 Square(s32 num) { return static_cast(num * num); } -Controller_Gesture::Controller_Gesture(Core::HID::HIDCore& hid_core_) : ControllerBase(hid_core_) { - console = hid_core.GetEmulatedConsole(); -} +Controller_Gesture::Controller_Gesture(Core::System& system_) : ControllerBase(system_) {} Controller_Gesture::~Controller_Gesture() = default; void Controller_Gesture::OnInit() { - gesture_lifo.buffer_count = 0; - gesture_lifo.buffer_tail = 0; + for (std::size_t id = 0; id < MAX_FINGERS; ++id) { + mouse_finger_id[id] = MAX_POINTS; + keyboard_finger_id[id] = MAX_POINTS; + udp_finger_id[id] = MAX_POINTS; + } + shared_memory.header.entry_count = 0; force_update = true; } @@ -39,38 +40,50 @@ void Controller_Gesture::OnRelease() {} void Controller_Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) { + shared_memory.header.timestamp = core_timing.GetCPUTicks(); + shared_memory.header.total_entry_count = 17; + if (!IsControllerActivated()) { - gesture_lifo.buffer_count = 0; - gesture_lifo.buffer_tail = 0; - std::memcpy(data + SHARED_MEMORY_OFFSET, &gesture_lifo, sizeof(gesture_lifo)); + shared_memory.header.entry_count = 0; + shared_memory.header.last_entry_index = 0; return; } ReadTouchInput(); GestureProperties gesture = GetGestureProperties(); - f32 time_difference = - static_cast(gesture_lifo.timestamp - last_update_timestamp) / (1000 * 1000 * 1000); + f32 time_difference = static_cast(shared_memory.header.timestamp - last_update_timestamp) / + (1000 * 1000 * 1000); // Only update if necesary if (!ShouldUpdateGesture(gesture, time_difference)) { return; } - last_update_timestamp = gesture_lifo.timestamp; + last_update_timestamp = shared_memory.header.timestamp; UpdateGestureSharedMemory(data, size, gesture, time_difference); } void Controller_Gesture::ReadTouchInput() { - const auto touch_status = console->GetTouch(); - for (std::size_t id = 0; id < fingers.size(); ++id) { - fingers[id] = touch_status[id]; + const Input::TouchStatus& mouse_status = touch_mouse_device->GetStatus(); + const Input::TouchStatus& udp_status = touch_udp_device->GetStatus(); + for (std::size_t id = 0; id < mouse_status.size(); ++id) { + mouse_finger_id[id] = UpdateTouchInputEvent(mouse_status[id], mouse_finger_id[id]); + udp_finger_id[id] = UpdateTouchInputEvent(udp_status[id], udp_finger_id[id]); + } + + if (Settings::values.use_touch_from_button) { + const Input::TouchStatus& keyboard_status = touch_btn_device->GetStatus(); + for (std::size_t id = 0; id < mouse_status.size(); ++id) { + keyboard_finger_id[id] = + UpdateTouchInputEvent(keyboard_status[id], keyboard_finger_id[id]); + } } } bool Controller_Gesture::ShouldUpdateGesture(const GestureProperties& gesture, f32 time_difference) { - const auto& last_entry = GetLastGestureEntry(); + const auto& last_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; if (force_update) { force_update = false; return true; @@ -84,7 +97,7 @@ bool Controller_Gesture::ShouldUpdateGesture(const GestureProperties& gesture, } // Update on press and hold event after 0.5 seconds - if (last_entry.type == GestureType::Touch && last_entry.point_count == 1 && + if (last_entry.type == TouchType::Touch && last_entry.point_count == 1 && time_difference > press_delay) { return enable_press_and_tap; } @@ -95,19 +108,27 @@ bool Controller_Gesture::ShouldUpdateGesture(const GestureProperties& gesture, void Controller_Gesture::UpdateGestureSharedMemory(u8* data, std::size_t size, GestureProperties& gesture, f32 time_difference) { - GestureType type = GestureType::Idle; - GestureAttribute attributes{}; + TouchType type = TouchType::Idle; + Attribute attributes{}; - const auto& last_entry = gesture_lifo.ReadCurrentEntry().state; + const auto& last_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; + shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17; + auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; - // Reset next state to default - next_state.sampling_number = last_entry.sampling_number + 1; - next_state.delta = {}; - next_state.vel_x = 0; - next_state.vel_y = 0; - next_state.direction = GestureDirection::None; - next_state.rotation_angle = 0; - next_state.scale = 0; + if (shared_memory.header.entry_count < 16) { + shared_memory.header.entry_count++; + } + + cur_entry.sampling_number = last_entry.sampling_number + 1; + cur_entry.sampling_number2 = cur_entry.sampling_number; + + // Reset values to default + cur_entry.delta = {}; + cur_entry.vel_x = 0; + cur_entry.vel_y = 0; + cur_entry.direction = Direction::None; + cur_entry.rotation_angle = 0; + cur_entry.scale = 0; if (gesture.active_points > 0) { if (last_gesture.active_points == 0) { @@ -120,47 +141,46 @@ void Controller_Gesture::UpdateGestureSharedMemory(u8* data, std::size_t size, } // Apply attributes - next_state.detection_count = gesture.detection_count; - next_state.type = type; - next_state.attributes = attributes; - next_state.pos = gesture.mid_point; - next_state.point_count = static_cast(gesture.active_points); - next_state.points = gesture.points; + cur_entry.detection_count = gesture.detection_count; + cur_entry.type = type; + cur_entry.attributes = attributes; + cur_entry.pos = gesture.mid_point; + cur_entry.point_count = static_cast(gesture.active_points); + cur_entry.points = gesture.points; last_gesture = gesture; - gesture_lifo.WriteNextEntry(next_state); - std::memcpy(data + SHARED_MEMORY_OFFSET, &gesture_lifo, sizeof(gesture_lifo)); + std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory)); } -void Controller_Gesture::NewGesture(GestureProperties& gesture, GestureType& type, - GestureAttribute& attributes) { +void Controller_Gesture::NewGesture(GestureProperties& gesture, TouchType& type, + Attribute& attributes) { const auto& last_entry = GetLastGestureEntry(); gesture.detection_count++; - type = GestureType::Touch; + type = TouchType::Touch; // New touch after cancel is not considered new - if (last_entry.type != GestureType::Cancel) { + if (last_entry.type != TouchType::Cancel) { attributes.is_new_touch.Assign(1); enable_press_and_tap = true; } } -void Controller_Gesture::UpdateExistingGesture(GestureProperties& gesture, GestureType& type, +void Controller_Gesture::UpdateExistingGesture(GestureProperties& gesture, TouchType& type, f32 time_difference) { const auto& last_entry = GetLastGestureEntry(); // Promote to pan type if touch moved for (size_t id = 0; id < MAX_POINTS; id++) { if (gesture.points[id] != last_gesture.points[id]) { - type = GestureType::Pan; + type = TouchType::Pan; break; } } // Number of fingers changed cancel the last event and clear data if (gesture.active_points != last_gesture.active_points) { - type = GestureType::Cancel; + type = TouchType::Cancel; enable_press_and_tap = false; gesture.active_points = 0; gesture.mid_point = {}; @@ -169,41 +189,41 @@ void Controller_Gesture::UpdateExistingGesture(GestureProperties& gesture, Gestu } // Calculate extra parameters of panning - if (type == GestureType::Pan) { + if (type == TouchType::Pan) { UpdatePanEvent(gesture, last_gesture, type, time_difference); return; } // Promote to press type - if (last_entry.type == GestureType::Touch) { - type = GestureType::Press; + if (last_entry.type == TouchType::Touch) { + type = TouchType::Press; } } void Controller_Gesture::EndGesture(GestureProperties& gesture, - GestureProperties& last_gesture_props, GestureType& type, - GestureAttribute& attributes, f32 time_difference) { + GestureProperties& last_gesture_props, TouchType& type, + Attribute& attributes, f32 time_difference) { const auto& last_entry = GetLastGestureEntry(); if (last_gesture_props.active_points != 0) { switch (last_entry.type) { - case GestureType::Touch: + case TouchType::Touch: if (enable_press_and_tap) { SetTapEvent(gesture, last_gesture_props, type, attributes); return; } - type = GestureType::Cancel; + type = TouchType::Cancel; force_update = true; break; - case GestureType::Press: - case GestureType::Tap: - case GestureType::Swipe: - case GestureType::Pinch: - case GestureType::Rotate: - type = GestureType::Complete; + case TouchType::Press: + case TouchType::Tap: + case TouchType::Swipe: + case TouchType::Pinch: + case TouchType::Rotate: + type = TouchType::Complete; force_update = true; break; - case GestureType::Pan: + case TouchType::Pan: EndPanEvent(gesture, last_gesture_props, type, time_difference); break; default: @@ -211,15 +231,15 @@ void Controller_Gesture::EndGesture(GestureProperties& gesture, } return; } - if (last_entry.type == GestureType::Complete || last_entry.type == GestureType::Cancel) { + if (last_entry.type == TouchType::Complete || last_entry.type == TouchType::Cancel) { gesture.detection_count++; } } void Controller_Gesture::SetTapEvent(GestureProperties& gesture, - GestureProperties& last_gesture_props, GestureType& type, - GestureAttribute& attributes) { - type = GestureType::Tap; + GestureProperties& last_gesture_props, TouchType& type, + Attribute& attributes) { + type = TouchType::Tap; gesture = last_gesture_props; force_update = true; f32 tap_time_difference = @@ -231,42 +251,44 @@ void Controller_Gesture::SetTapEvent(GestureProperties& gesture, } void Controller_Gesture::UpdatePanEvent(GestureProperties& gesture, - GestureProperties& last_gesture_props, GestureType& type, + GestureProperties& last_gesture_props, TouchType& type, f32 time_difference) { + auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; const auto& last_entry = GetLastGestureEntry(); - next_state.delta = gesture.mid_point - last_entry.pos; - next_state.vel_x = static_cast(next_state.delta.x) / time_difference; - next_state.vel_y = static_cast(next_state.delta.y) / time_difference; + cur_entry.delta = gesture.mid_point - last_entry.pos; + cur_entry.vel_x = static_cast(cur_entry.delta.x) / time_difference; + cur_entry.vel_y = static_cast(cur_entry.delta.y) / time_difference; last_pan_time_difference = time_difference; // Promote to pinch type if (std::abs(gesture.average_distance - last_gesture_props.average_distance) > pinch_threshold) { - type = GestureType::Pinch; - next_state.scale = gesture.average_distance / last_gesture_props.average_distance; + type = TouchType::Pinch; + cur_entry.scale = gesture.average_distance / last_gesture_props.average_distance; } const f32 angle_between_two_lines = std::atan((gesture.angle - last_gesture_props.angle) / (1 + (gesture.angle * last_gesture_props.angle))); // Promote to rotate type if (std::abs(angle_between_two_lines) > angle_threshold) { - type = GestureType::Rotate; - next_state.scale = 0; - next_state.rotation_angle = angle_between_two_lines * 180.0f / Common::PI; + type = TouchType::Rotate; + cur_entry.scale = 0; + cur_entry.rotation_angle = angle_between_two_lines * 180.0f / Common::PI; } } void Controller_Gesture::EndPanEvent(GestureProperties& gesture, - GestureProperties& last_gesture_props, GestureType& type, + GestureProperties& last_gesture_props, TouchType& type, f32 time_difference) { + auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; const auto& last_entry = GetLastGestureEntry(); - next_state.vel_x = + cur_entry.vel_x = static_cast(last_entry.delta.x) / (last_pan_time_difference + time_difference); - next_state.vel_y = + cur_entry.vel_y = static_cast(last_entry.delta.y) / (last_pan_time_difference + time_difference); const f32 curr_vel = - std::sqrt((next_state.vel_x * next_state.vel_x) + (next_state.vel_y * next_state.vel_y)); + std::sqrt((cur_entry.vel_x * cur_entry.vel_x) + (cur_entry.vel_y * cur_entry.vel_y)); // Set swipe event with parameters if (curr_vel > swipe_threshold) { @@ -275,50 +297,105 @@ void Controller_Gesture::EndPanEvent(GestureProperties& gesture, } // End panning without swipe - type = GestureType::Complete; - next_state.vel_x = 0; - next_state.vel_y = 0; + type = TouchType::Complete; + cur_entry.vel_x = 0; + cur_entry.vel_y = 0; force_update = true; } void Controller_Gesture::SetSwipeEvent(GestureProperties& gesture, - GestureProperties& last_gesture_props, GestureType& type) { + GestureProperties& last_gesture_props, TouchType& type) { + auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; const auto& last_entry = GetLastGestureEntry(); - type = GestureType::Swipe; + type = TouchType::Swipe; gesture = last_gesture_props; force_update = true; - next_state.delta = last_entry.delta; + cur_entry.delta = last_entry.delta; - if (std::abs(next_state.delta.x) > std::abs(next_state.delta.y)) { - if (next_state.delta.x > 0) { - next_state.direction = GestureDirection::Right; + if (std::abs(cur_entry.delta.x) > std::abs(cur_entry.delta.y)) { + if (cur_entry.delta.x > 0) { + cur_entry.direction = Direction::Right; return; } - next_state.direction = GestureDirection::Left; + cur_entry.direction = Direction::Left; return; } - if (next_state.delta.y > 0) { - next_state.direction = GestureDirection::Down; + if (cur_entry.delta.y > 0) { + cur_entry.direction = Direction::Down; return; } - next_state.direction = GestureDirection::Up; + cur_entry.direction = Direction::Up; +} + +void Controller_Gesture::OnLoadInputDevices() { + touch_mouse_device = Input::CreateDevice("engine:emu_window"); + touch_udp_device = Input::CreateDevice("engine:cemuhookudp"); + touch_btn_device = Input::CreateDevice("engine:touch_from_button"); +} + +std::optional Controller_Gesture::GetUnusedFingerID() const { + // Dont assign any touch input to a point if disabled + if (!Settings::values.touchscreen.enabled) { + return std::nullopt; + } + std::size_t first_free_id = 0; + while (first_free_id < MAX_POINTS) { + if (!fingers[first_free_id].pressed) { + return first_free_id; + } else { + first_free_id++; + } + } + return std::nullopt; +} + +Controller_Gesture::GestureState& Controller_Gesture::GetLastGestureEntry() { + return shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17]; } const Controller_Gesture::GestureState& Controller_Gesture::GetLastGestureEntry() const { - return gesture_lifo.ReadCurrentEntry().state; + return shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17]; +} + +std::size_t Controller_Gesture::UpdateTouchInputEvent( + const std::tuple& touch_input, std::size_t finger_id) { + const auto& [x, y, pressed] = touch_input; + if (finger_id > MAX_POINTS) { + LOG_ERROR(Service_HID, "Invalid finger id {}", finger_id); + return MAX_POINTS; + } + if (pressed) { + if (finger_id == MAX_POINTS) { + const auto first_free_id = GetUnusedFingerID(); + if (!first_free_id) { + // Invalid finger id do nothing + return MAX_POINTS; + } + finger_id = first_free_id.value(); + fingers[finger_id].pressed = true; + } + fingers[finger_id].pos = {x, y}; + return finger_id; + } + + if (finger_id != MAX_POINTS) { + fingers[finger_id].pressed = false; + } + + return MAX_POINTS; } Controller_Gesture::GestureProperties Controller_Gesture::GetGestureProperties() { GestureProperties gesture; - std::array active_fingers; + std::array active_fingers; const auto end_iter = std::copy_if(fingers.begin(), fingers.end(), active_fingers.begin(), [](const auto& finger) { return finger.pressed; }); gesture.active_points = static_cast(std::distance(active_fingers.begin(), end_iter)); for (size_t id = 0; id < gesture.active_points; ++id) { - const auto& [active_x, active_y] = active_fingers[id].position; + const auto& [active_x, active_y] = active_fingers[id].pos; gesture.points[id] = { .x = static_cast(active_x * Layout::ScreenUndocked::Width), .y = static_cast(active_y * Layout::ScreenUndocked::Height), diff --git a/src/core/hle/service/hid/controllers/gesture.h b/src/core/hle/service/hid/controllers/gesture.h index f924464e0..7e7ae6625 100755 --- a/src/core/hle/service/hid/controllers/gesture.h +++ b/src/core/hle/service/hid/controllers/gesture.h @@ -8,14 +8,13 @@ #include "common/bit_field.h" #include "common/common_types.h" #include "common/point.h" -#include "core/hid/emulated_console.h" +#include "core/frontend/input.h" #include "core/hle/service/hid/controllers/controller_base.h" -#include "core/hle/service/hid/ring_lifo.h" namespace Service::HID { class Controller_Gesture final : public ControllerBase { public: - explicit Controller_Gesture(Core::HID::HIDCore& hid_core_); + explicit Controller_Gesture(Core::System& system_); ~Controller_Gesture() override; // Called when the controller is initialized @@ -27,12 +26,14 @@ public: // When the controller is requesting an update for the shared memory void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, size_t size) override; + // Called when input devices should be loaded + void OnLoadInputDevices() override; + private: static constexpr size_t MAX_FINGERS = 16; static constexpr size_t MAX_POINTS = 4; - // This is nn::hid::GestureType - enum class GestureType : u32 { + enum class TouchType : u32 { Idle, // Nothing touching the screen Complete, // Set at the end of a touch event Cancel, // Set when the number of fingers change @@ -45,8 +46,7 @@ private: Rotate, // All points rotating from the midpoint }; - // This is nn::hid::GestureDirection - enum class GestureDirection : u32 { + enum class Direction : u32 { None, Left, Up, @@ -54,41 +54,51 @@ private: Down, }; - // This is nn::hid::GestureAttribute - struct GestureAttribute { + struct Attribute { union { - u32 raw{}; + u32_le raw{}; BitField<4, 1, u32> is_new_touch; BitField<8, 1, u32> is_double_tap; }; }; - static_assert(sizeof(GestureAttribute) == 4, "GestureAttribute is an invalid size"); + static_assert(sizeof(Attribute) == 4, "Attribute is an invalid size"); - // This is nn::hid::GestureState struct GestureState { - s64 sampling_number; - s64 detection_count; - GestureType type; - GestureDirection direction; - Common::Point pos; - Common::Point delta; + s64_le sampling_number; + s64_le sampling_number2; + s64_le detection_count; + TouchType type; + Direction direction; + Common::Point pos; + Common::Point delta; f32 vel_x; f32 vel_y; - GestureAttribute attributes; + Attribute attributes; f32 scale; f32 rotation_angle; - s32 point_count; - std::array, 4> points; + s32_le point_count; + std::array, 4> points; + }; + static_assert(sizeof(GestureState) == 0x68, "GestureState is an invalid size"); + + struct SharedMemory { + CommonHeader header; + std::array gesture_states; + }; + static_assert(sizeof(SharedMemory) == 0x708, "SharedMemory is an invalid size"); + + struct Finger { + Common::Point pos{}; + bool pressed{}; }; - static_assert(sizeof(GestureState) == 0x60, "GestureState is an invalid size"); struct GestureProperties { - std::array, MAX_POINTS> points{}; + std::array, MAX_POINTS> points{}; std::size_t active_points{}; - Common::Point mid_point{}; - s64 detection_count{}; - u64 delta_time{}; + Common::Point mid_point{}; + s64_le detection_count{}; + u64_le delta_time{}; f32 average_distance{}; f32 angle{}; }; @@ -104,48 +114,61 @@ private: f32 time_difference); // Initializes new gesture - void NewGesture(GestureProperties& gesture, GestureType& type, GestureAttribute& attributes); + void NewGesture(GestureProperties& gesture, TouchType& type, Attribute& attributes); // Updates existing gesture state - void UpdateExistingGesture(GestureProperties& gesture, GestureType& type, f32 time_difference); + void UpdateExistingGesture(GestureProperties& gesture, TouchType& type, f32 time_difference); // Terminates exiting gesture void EndGesture(GestureProperties& gesture, GestureProperties& last_gesture_props, - GestureType& type, GestureAttribute& attributes, f32 time_difference); + TouchType& type, Attribute& attributes, f32 time_difference); // Set current event to a tap event void SetTapEvent(GestureProperties& gesture, GestureProperties& last_gesture_props, - GestureType& type, GestureAttribute& attributes); + TouchType& type, Attribute& attributes); // Calculates and set the extra parameters related to a pan event void UpdatePanEvent(GestureProperties& gesture, GestureProperties& last_gesture_props, - GestureType& type, f32 time_difference); + TouchType& type, f32 time_difference); // Terminates the pan event void EndPanEvent(GestureProperties& gesture, GestureProperties& last_gesture_props, - GestureType& type, f32 time_difference); + TouchType& type, f32 time_difference); // Set current event to a swipe event void SetSwipeEvent(GestureProperties& gesture, GestureProperties& last_gesture_props, - GestureType& type); + TouchType& type); + + // Returns an unused finger id, if there is no fingers available std::nullopt is returned. + [[nodiscard]] std::optional GetUnusedFingerID() const; // Retrieves the last gesture entry, as indicated by shared memory indices. + [[nodiscard]] GestureState& GetLastGestureEntry(); [[nodiscard]] const GestureState& GetLastGestureEntry() const; + /** + * If the touch is new it tries to assign a new finger id, if there is no fingers available no + * changes will be made. Updates the coordinates if the finger id it's already set. If the touch + * ends delays the output by one frame to set the end_touch flag before finally freeing the + * finger id + */ + size_t UpdateTouchInputEvent(const std::tuple& touch_input, + size_t finger_id); + // Returns the average distance, angle and middle point of the active fingers GestureProperties GetGestureProperties(); - // This is nn::hid::detail::GestureLifo - Lifo gesture_lifo{}; - static_assert(sizeof(gesture_lifo) == 0x708, "gesture_lifo is an invalid size"); - GestureState next_state{}; - - Core::HID::EmulatedConsole* console; - - std::array fingers{}; + SharedMemory shared_memory{}; + std::unique_ptr touch_mouse_device; + std::unique_ptr touch_udp_device; + std::unique_ptr touch_btn_device; + std::array mouse_finger_id{}; + std::array keyboard_finger_id{}; + std::array udp_finger_id{}; + std::array fingers{}; GestureProperties last_gesture{}; - s64 last_update_timestamp{}; - s64 last_tap_timestamp{}; + s64_le last_update_timestamp{}; + s64_le last_tap_timestamp{}; f32 last_pan_time_difference{}; bool force_update{false}; bool enable_press_and_tap{false}; diff --git a/src/core/hle/service/hid/controllers/keyboard.cpp b/src/core/hle/service/hid/controllers/keyboard.cpp index 0ef8af0e6..c6c620008 100755 --- a/src/core/hle/service/hid/controllers/keyboard.cpp +++ b/src/core/hle/service/hid/controllers/keyboard.cpp @@ -6,18 +6,13 @@ #include "common/common_types.h" #include "common/settings.h" #include "core/core_timing.h" -#include "core/hid/emulated_devices.h" -#include "core/hid/hid_core.h" #include "core/hle/service/hid/controllers/keyboard.h" namespace Service::HID { constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3800; +constexpr u8 KEYS_PER_BYTE = 8; -Controller_Keyboard::Controller_Keyboard(Core::HID::HIDCore& hid_core_) - : ControllerBase{hid_core_} { - emulated_devices = hid_core.GetEmulatedDevices(); -} - +Controller_Keyboard::Controller_Keyboard(Core::System& system_) : ControllerBase{system_} {} Controller_Keyboard::~Controller_Keyboard() = default; void Controller_Keyboard::OnInit() {} @@ -26,28 +21,51 @@ void Controller_Keyboard::OnRelease() {} void Controller_Keyboard::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) { + shared_memory.header.timestamp = core_timing.GetCPUTicks(); + shared_memory.header.total_entry_count = 17; + if (!IsControllerActivated()) { - keyboard_lifo.buffer_count = 0; - keyboard_lifo.buffer_tail = 0; - std::memcpy(data + SHARED_MEMORY_OFFSET, &keyboard_lifo, sizeof(keyboard_lifo)); + shared_memory.header.entry_count = 0; + shared_memory.header.last_entry_index = 0; return; } + shared_memory.header.entry_count = 16; - const auto& last_entry = keyboard_lifo.ReadCurrentEntry().state; - next_state.sampling_number = last_entry.sampling_number + 1; + const auto& last_entry = shared_memory.pad_states[shared_memory.header.last_entry_index]; + shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17; + auto& cur_entry = shared_memory.pad_states[shared_memory.header.last_entry_index]; + cur_entry.sampling_number = last_entry.sampling_number + 1; + cur_entry.sampling_number2 = cur_entry.sampling_number; + + cur_entry.key.fill(0); if (Settings::values.keyboard_enabled) { - const auto& keyboard_state = emulated_devices->GetKeyboard(); - const auto& keyboard_modifier_state = emulated_devices->GetKeyboardModifier(); + for (std::size_t i = 0; i < keyboard_keys.size(); ++i) { + auto& entry = cur_entry.key[i / KEYS_PER_BYTE]; + entry = static_cast(entry | (keyboard_keys[i]->GetStatus() << (i % KEYS_PER_BYTE))); + } - next_state.key = keyboard_state; - next_state.modifier = keyboard_modifier_state; - // This is always enabled on HW. Check what it actually does - next_state.modifier.unknown.Assign(1); + using namespace Settings::NativeKeyboard; + + // TODO: Assign the correct key to all modifiers + cur_entry.modifier.control.Assign(keyboard_mods[LeftControl]->GetStatus()); + cur_entry.modifier.shift.Assign(keyboard_mods[LeftShift]->GetStatus()); + cur_entry.modifier.left_alt.Assign(keyboard_mods[LeftAlt]->GetStatus()); + cur_entry.modifier.right_alt.Assign(keyboard_mods[RightAlt]->GetStatus()); + cur_entry.modifier.gui.Assign(0); + cur_entry.modifier.caps_lock.Assign(keyboard_mods[CapsLock]->GetStatus()); + cur_entry.modifier.scroll_lock.Assign(keyboard_mods[ScrollLock]->GetStatus()); + cur_entry.modifier.num_lock.Assign(keyboard_mods[NumLock]->GetStatus()); + cur_entry.modifier.katakana.Assign(0); + cur_entry.modifier.hiragana.Assign(0); } - - keyboard_lifo.WriteNextEntry(next_state); - std::memcpy(data + SHARED_MEMORY_OFFSET, &keyboard_lifo, sizeof(keyboard_lifo)); + std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory)); } +void Controller_Keyboard::OnLoadInputDevices() { + std::transform(Settings::values.keyboard_keys.begin(), Settings::values.keyboard_keys.end(), + keyboard_keys.begin(), Input::CreateDevice); + std::transform(Settings::values.keyboard_mods.begin(), Settings::values.keyboard_mods.end(), + keyboard_mods.begin(), Input::CreateDevice); +} } // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/keyboard.h b/src/core/hle/service/hid/controllers/keyboard.h index ec5dd607c..172a80e9c 100755 --- a/src/core/hle/service/hid/controllers/keyboard.h +++ b/src/core/hle/service/hid/controllers/keyboard.h @@ -8,20 +8,15 @@ #include "common/bit_field.h" #include "common/common_funcs.h" #include "common/common_types.h" +#include "common/settings.h" #include "common/swap.h" +#include "core/frontend/input.h" #include "core/hle/service/hid/controllers/controller_base.h" -#include "core/hle/service/hid/ring_lifo.h" - -namespace Core::HID { -class EmulatedDevices; -struct KeyboardModifier; -struct KeyboardKey; -} // namespace Core::HID namespace Service::HID { class Controller_Keyboard final : public ControllerBase { public: - explicit Controller_Keyboard(Core::HID::HIDCore& hid_core_); + explicit Controller_Keyboard(Core::System& system_); ~Controller_Keyboard() override; // Called when the controller is initialized @@ -33,20 +28,47 @@ public: // When the controller is requesting an update for the shared memory void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override; + // Called when input devices should be loaded + void OnLoadInputDevices() override; + private: - // This is nn::hid::detail::KeyboardState - struct KeyboardState { - s64 sampling_number; - Core::HID::KeyboardModifier modifier; - Core::HID::KeyboardKey key; + struct Modifiers { + union { + u32_le raw{}; + BitField<0, 1, u32> control; + BitField<1, 1, u32> shift; + BitField<2, 1, u32> left_alt; + BitField<3, 1, u32> right_alt; + BitField<4, 1, u32> gui; + BitField<8, 1, u32> caps_lock; + BitField<9, 1, u32> scroll_lock; + BitField<10, 1, u32> num_lock; + BitField<11, 1, u32> katakana; + BitField<12, 1, u32> hiragana; + }; }; - static_assert(sizeof(KeyboardState) == 0x30, "KeyboardState is an invalid size"); + static_assert(sizeof(Modifiers) == 0x4, "Modifiers is an invalid size"); - // This is nn::hid::detail::KeyboardLifo - Lifo keyboard_lifo{}; - static_assert(sizeof(keyboard_lifo) == 0x3D8, "keyboard_lifo is an invalid size"); - KeyboardState next_state{}; + struct KeyboardState { + s64_le sampling_number; + s64_le sampling_number2; - Core::HID::EmulatedDevices* emulated_devices; + Modifiers modifier; + std::array key; + }; + static_assert(sizeof(KeyboardState) == 0x38, "KeyboardState is an invalid size"); + + struct SharedMemory { + CommonHeader header; + std::array pad_states; + INSERT_PADDING_BYTES(0x28); + }; + static_assert(sizeof(SharedMemory) == 0x400, "SharedMemory is an invalid size"); + SharedMemory shared_memory{}; + + std::array, Settings::NativeKeyboard::NumKeyboardKeys> + keyboard_keys; + std::array, Settings::NativeKeyboard::NumKeyboardMods> + keyboard_mods; }; } // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/mouse.cpp b/src/core/hle/service/hid/controllers/mouse.cpp index 83e69ca94..544a71948 100755 --- a/src/core/hle/service/hid/controllers/mouse.cpp +++ b/src/core/hle/service/hid/controllers/mouse.cpp @@ -6,17 +6,12 @@ #include "common/common_types.h" #include "core/core_timing.h" #include "core/frontend/emu_window.h" -#include "core/hid/emulated_devices.h" -#include "core/hid/hid_core.h" #include "core/hle/service/hid/controllers/mouse.h" namespace Service::HID { constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3400; -Controller_Mouse::Controller_Mouse(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} { - emulated_devices = hid_core.GetEmulatedDevices(); -} - +Controller_Mouse::Controller_Mouse(Core::System& system_) : ControllerBase{system_} {} Controller_Mouse::~Controller_Mouse() = default; void Controller_Mouse::OnInit() {} @@ -24,33 +19,50 @@ void Controller_Mouse::OnRelease() {} void Controller_Mouse::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) { + shared_memory.header.timestamp = core_timing.GetCPUTicks(); + shared_memory.header.total_entry_count = 17; + if (!IsControllerActivated()) { - mouse_lifo.buffer_count = 0; - mouse_lifo.buffer_tail = 0; - std::memcpy(data + SHARED_MEMORY_OFFSET, &mouse_lifo, sizeof(mouse_lifo)); + shared_memory.header.entry_count = 0; + shared_memory.header.last_entry_index = 0; return; } + shared_memory.header.entry_count = 16; - const auto& last_entry = mouse_lifo.ReadCurrentEntry().state; - next_state.sampling_number = last_entry.sampling_number + 1; + auto& last_entry = shared_memory.mouse_states[shared_memory.header.last_entry_index]; + shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17; + auto& cur_entry = shared_memory.mouse_states[shared_memory.header.last_entry_index]; - next_state.attribute.raw = 0; + cur_entry.sampling_number = last_entry.sampling_number + 1; + cur_entry.sampling_number2 = cur_entry.sampling_number; + + cur_entry.attribute.raw = 0; if (Settings::values.mouse_enabled) { - const auto& mouse_button_state = emulated_devices->GetMouseButtons(); - const auto& mouse_position_state = emulated_devices->GetMousePosition(); - next_state.attribute.is_connected.Assign(1); - next_state.x = mouse_position_state.x; - next_state.y = mouse_position_state.y; - next_state.delta_x = next_state.x - last_entry.x; - next_state.delta_y = next_state.y - last_entry.y; - next_state.delta_wheel_x = mouse_position_state.delta_wheel_x; - next_state.delta_wheel_y = mouse_position_state.delta_wheel_y; + const auto [px, py, sx, sy] = mouse_device->GetStatus(); + const auto x = static_cast(px * Layout::ScreenUndocked::Width); + const auto y = static_cast(py * Layout::ScreenUndocked::Height); + cur_entry.x = x; + cur_entry.y = y; + cur_entry.delta_x = x - last_entry.x; + cur_entry.delta_y = y - last_entry.y; + cur_entry.mouse_wheel_x = sx; + cur_entry.mouse_wheel_y = sy; + cur_entry.attribute.is_connected.Assign(1); - next_state.button = mouse_button_state; + using namespace Settings::NativeMouseButton; + cur_entry.button.left.Assign(mouse_button_devices[Left]->GetStatus()); + cur_entry.button.right.Assign(mouse_button_devices[Right]->GetStatus()); + cur_entry.button.middle.Assign(mouse_button_devices[Middle]->GetStatus()); + cur_entry.button.forward.Assign(mouse_button_devices[Forward]->GetStatus()); + cur_entry.button.back.Assign(mouse_button_devices[Back]->GetStatus()); } - mouse_lifo.WriteNextEntry(next_state); - std::memcpy(data + SHARED_MEMORY_OFFSET, &mouse_lifo, sizeof(mouse_lifo)); + std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory)); } +void Controller_Mouse::OnLoadInputDevices() { + mouse_device = Input::CreateDevice(Settings::values.mouse_device); + std::transform(Settings::values.mouse_buttons.begin(), Settings::values.mouse_buttons.end(), + mouse_button_devices.begin(), Input::CreateDevice); +} } // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/mouse.h b/src/core/hle/service/hid/controllers/mouse.h index 25017f117..3d391a798 100755 --- a/src/core/hle/service/hid/controllers/mouse.h +++ b/src/core/hle/service/hid/controllers/mouse.h @@ -7,19 +7,15 @@ #include #include "common/bit_field.h" #include "common/common_types.h" +#include "common/settings.h" #include "common/swap.h" +#include "core/frontend/input.h" #include "core/hle/service/hid/controllers/controller_base.h" -#include "core/hle/service/hid/ring_lifo.h" - -namespace Core::HID { -class EmulatedDevices; -struct MouseState; -} // namespace Core::HID namespace Service::HID { class Controller_Mouse final : public ControllerBase { public: - explicit Controller_Mouse(Core::HID::HIDCore& hid_core_); + explicit Controller_Mouse(Core::System& system_); ~Controller_Mouse() override; // Called when the controller is initialized @@ -31,12 +27,53 @@ public: // When the controller is requesting an update for the shared memory void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override; -private: - // This is nn::hid::detail::MouseLifo - Lifo mouse_lifo{}; - static_assert(sizeof(mouse_lifo) == 0x350, "mouse_lifo is an invalid size"); - Core::HID::MouseState next_state{}; + // Called when input devices should be loaded + void OnLoadInputDevices() override; - Core::HID::EmulatedDevices* emulated_devices; +private: + struct Buttons { + union { + u32_le raw{}; + BitField<0, 1, u32> left; + BitField<1, 1, u32> right; + BitField<2, 1, u32> middle; + BitField<3, 1, u32> forward; + BitField<4, 1, u32> back; + }; + }; + static_assert(sizeof(Buttons) == 0x4, "Buttons is an invalid size"); + + struct Attributes { + union { + u32_le raw{}; + BitField<0, 1, u32> transferable; + BitField<1, 1, u32> is_connected; + }; + }; + static_assert(sizeof(Attributes) == 0x4, "Attributes is an invalid size"); + + struct MouseState { + s64_le sampling_number; + s64_le sampling_number2; + s32_le x; + s32_le y; + s32_le delta_x; + s32_le delta_y; + s32_le mouse_wheel_x; + s32_le mouse_wheel_y; + Buttons button; + Attributes attribute; + }; + static_assert(sizeof(MouseState) == 0x30, "MouseState is an invalid size"); + + struct SharedMemory { + CommonHeader header; + std::array mouse_states; + }; + SharedMemory shared_memory{}; + + std::unique_ptr mouse_device; + std::array, Settings::NativeMouseButton::NumMouseButtons> + mouse_button_devices; }; } // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index eaec79139..196876810 100755 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -10,9 +10,9 @@ #include "common/common_types.h" #include "common/logging/log.h" #include "common/settings.h" +#include "core/core.h" #include "core/core_timing.h" -#include "core/hid/emulated_controller.h" -#include "core/hid/hid_core.h" +#include "core/frontend/input.h" #include "core/hle/kernel/k_event.h" #include "core/hle/kernel/k_readable_event.h" #include "core/hle/kernel/k_writable_event.h" @@ -20,26 +20,120 @@ #include "core/hle/service/kernel_helpers.h" namespace Service::HID { +constexpr s32 HID_JOYSTICK_MAX = 0x7fff; +constexpr s32 HID_TRIGGER_MAX = 0x7fff; +[[maybe_unused]] constexpr s32 HID_JOYSTICK_MIN = -0x7fff; constexpr std::size_t NPAD_OFFSET = 0x9A00; -constexpr std::array npad_id_list{ - Core::HID::NpadIdType::Player1, Core::HID::NpadIdType::Player2, Core::HID::NpadIdType::Player3, - Core::HID::NpadIdType::Player4, Core::HID::NpadIdType::Player5, Core::HID::NpadIdType::Player6, - Core::HID::NpadIdType::Player7, Core::HID::NpadIdType::Player8, Core::HID::NpadIdType::Other, - Core::HID::NpadIdType::Handheld, +constexpr u32 BATTERY_FULL = 2; +constexpr u32 MAX_NPAD_ID = 7; +constexpr std::size_t HANDHELD_INDEX = 8; +constexpr std::array npad_id_list{ + 0, 1, 2, 3, 4, 5, 6, 7, NPAD_HANDHELD, NPAD_UNKNOWN, }; -bool Controller_NPad::IsNpadIdValid(Core::HID::NpadIdType npad_id) { +enum class JoystickId : std::size_t { + Joystick_Left, + Joystick_Right, +}; + +Controller_NPad::NPadControllerType Controller_NPad::MapSettingsTypeToNPad( + Settings::ControllerType type) { + switch (type) { + case Settings::ControllerType::ProController: + return NPadControllerType::ProController; + case Settings::ControllerType::DualJoyconDetached: + return NPadControllerType::JoyDual; + case Settings::ControllerType::LeftJoycon: + return NPadControllerType::JoyLeft; + case Settings::ControllerType::RightJoycon: + return NPadControllerType::JoyRight; + case Settings::ControllerType::Handheld: + return NPadControllerType::Handheld; + case Settings::ControllerType::GameCube: + return NPadControllerType::GameCube; + default: + UNREACHABLE(); + return NPadControllerType::ProController; + } +} + +Settings::ControllerType Controller_NPad::MapNPadToSettingsType( + Controller_NPad::NPadControllerType type) { + switch (type) { + case NPadControllerType::ProController: + return Settings::ControllerType::ProController; + case NPadControllerType::JoyDual: + return Settings::ControllerType::DualJoyconDetached; + case NPadControllerType::JoyLeft: + return Settings::ControllerType::LeftJoycon; + case NPadControllerType::JoyRight: + return Settings::ControllerType::RightJoycon; + case NPadControllerType::Handheld: + return Settings::ControllerType::Handheld; + case NPadControllerType::GameCube: + return Settings::ControllerType::GameCube; + default: + UNREACHABLE(); + return Settings::ControllerType::ProController; + } +} + +std::size_t Controller_NPad::NPadIdToIndex(u32 npad_id) { switch (npad_id) { - case Core::HID::NpadIdType::Player1: - case Core::HID::NpadIdType::Player2: - case Core::HID::NpadIdType::Player3: - case Core::HID::NpadIdType::Player4: - case Core::HID::NpadIdType::Player5: - case Core::HID::NpadIdType::Player6: - case Core::HID::NpadIdType::Player7: - case Core::HID::NpadIdType::Player8: - case Core::HID::NpadIdType::Other: - case Core::HID::NpadIdType::Handheld: + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + return npad_id; + case HANDHELD_INDEX: + case NPAD_HANDHELD: + return HANDHELD_INDEX; + case 9: + case NPAD_UNKNOWN: + return 9; + default: + UNIMPLEMENTED_MSG("Unknown npad id {}", npad_id); + return 0; + } +} + +u32 Controller_NPad::IndexToNPad(std::size_t index) { + switch (index) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + return static_cast(index); + case HANDHELD_INDEX: + return NPAD_HANDHELD; + case 9: + return NPAD_UNKNOWN; + default: + UNIMPLEMENTED_MSG("Unknown npad index {}", index); + return 0; + } +} + +bool Controller_NPad::IsNpadIdValid(u32 npad_id) { + switch (npad_id) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + case NPAD_UNKNOWN: + case NPAD_HANDHELD: return true; default: LOG_ERROR(Service_HID, "Invalid npad id {}", npad_id); @@ -47,213 +141,131 @@ bool Controller_NPad::IsNpadIdValid(Core::HID::NpadIdType npad_id) { } } -bool Controller_NPad::IsDeviceHandleValid(const Core::HID::VibrationDeviceHandle& device_handle) { - return IsNpadIdValid(static_cast(device_handle.npad_id)) && - device_handle.npad_type < Core::HID::NpadStyleIndex::MaxNpadType && - device_handle.device_index < Core::HID::DeviceIndex::MaxDeviceIndex; +bool Controller_NPad::IsDeviceHandleValid(const DeviceHandle& device_handle) { + return IsNpadIdValid(device_handle.npad_id) && + device_handle.npad_type < NpadType::MaxNpadType && + device_handle.device_index < DeviceIndex::MaxDeviceIndex; } -bool Controller_NPad::IsDeviceHandleValid(const Core::HID::SixAxisSensorHandle& device_handle) { - return IsNpadIdValid(static_cast(device_handle.npad_id)) && - device_handle.npad_type < Core::HID::NpadStyleIndex::MaxNpadType && - device_handle.device_index < Core::HID::DeviceIndex::MaxDeviceIndex; -} - -Controller_NPad::Controller_NPad(Core::HID::HIDCore& hid_core_, +Controller_NPad::Controller_NPad(Core::System& system_, KernelHelpers::ServiceContext& service_context_) - : ControllerBase{hid_core_}, service_context{service_context_} { - for (std::size_t i = 0; i < controller_data.size(); ++i) { - auto& controller = controller_data[i]; - controller.device = hid_core.GetEmulatedControllerByIndex(i); - controller.vibration[Core::HID::EmulatedDeviceIndex::LeftIndex].latest_vibration_value = - DEFAULT_VIBRATION_VALUE; - controller.vibration[Core::HID::EmulatedDeviceIndex::RightIndex].latest_vibration_value = - DEFAULT_VIBRATION_VALUE; - Core::HID::ControllerUpdateCallback engine_callback{ - .on_change = [this, - i](Core::HID::ControllerTriggerType type) { ControllerUpdate(type, i); }, - .is_npad_service = true, - }; - controller.callback_key = controller.device->SetCallback(engine_callback); - } + : ControllerBase{system_}, service_context{service_context_} { + latest_vibration_values.fill({DEFAULT_VIBRATION_VALUE, DEFAULT_VIBRATION_VALUE}); } Controller_NPad::~Controller_NPad() { - for (std::size_t i = 0; i < controller_data.size(); ++i) { - auto& controller = controller_data[i]; - controller.device->DeleteCallback(controller.callback_key); - } OnRelease(); } -void Controller_NPad::ControllerUpdate(Core::HID::ControllerTriggerType type, - std::size_t controller_idx) { - if (type == Core::HID::ControllerTriggerType::All) { - ControllerUpdate(Core::HID::ControllerTriggerType::Connected, controller_idx); - ControllerUpdate(Core::HID::ControllerTriggerType::Battery, controller_idx); +void Controller_NPad::InitNewlyAddedController(std::size_t controller_idx) { + const auto controller_type = connected_controllers[controller_idx].type; + auto& controller = shared_memory_entries[controller_idx]; + if (controller_type == NPadControllerType::None) { + styleset_changed_events[controller_idx]->GetWritableEvent().Signal(); return; } - if (controller_idx >= controller_data.size()) { - return; - } - - auto& controller = controller_data[controller_idx]; - const auto is_connected = controller.device->IsConnected(); - const auto npad_type = controller.device->GetNpadStyleIndex(); - const auto npad_id = controller.device->GetNpadIdType(); - switch (type) { - case Core::HID::ControllerTriggerType::Connected: - case Core::HID::ControllerTriggerType::Disconnected: - if (is_connected == controller.is_connected) { - return; - } - UpdateControllerAt(npad_type, npad_id, is_connected); - break; - case Core::HID::ControllerTriggerType::Battery: { - if (!controller.is_connected) { - return; - } - auto& shared_memory = controller.shared_memory_entry; - const auto& battery_level = controller.device->GetBattery(); - shared_memory.battery_level_dual = battery_level.dual.battery_level; - shared_memory.battery_level_left = battery_level.left.battery_level; - shared_memory.battery_level_right = battery_level.right.battery_level; - break; - } - default: - break; - } -} - -void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) { - LOG_DEBUG(Service_HID, "Npad connected {}", npad_id); - auto& controller = GetControllerFromNpadIdType(npad_id); - const auto controller_type = controller.device->GetNpadStyleIndex(); - auto& shared_memory = controller.shared_memory_entry; - if (controller_type == Core::HID::NpadStyleIndex::None) { - controller.styleset_changed_event->GetWritableEvent().Signal(); - return; - } - shared_memory.style_tag.raw = Core::HID::NpadStyleSet::None; - shared_memory.device_type.raw = 0; - shared_memory.system_properties.raw = 0; + controller.style_set.raw = 0; // Zero out + controller.device_type.raw = 0; + controller.system_properties.raw = 0; switch (controller_type) { - case Core::HID::NpadStyleIndex::None: + case NPadControllerType::None: UNREACHABLE(); break; - case Core::HID::NpadStyleIndex::ProController: - shared_memory.style_tag.fullkey.Assign(1); - shared_memory.device_type.fullkey.Assign(1); - shared_memory.system_properties.is_vertical.Assign(1); - shared_memory.system_properties.use_plus.Assign(1); - shared_memory.system_properties.use_minus.Assign(1); - shared_memory.assignment_mode = NpadJoyAssignmentMode::Single; - shared_memory.applet_footer.type = AppletFooterUiType::SwitchProController; + case NPadControllerType::ProController: + controller.style_set.fullkey.Assign(1); + controller.device_type.fullkey.Assign(1); + controller.system_properties.is_vertical.Assign(1); + controller.system_properties.use_plus.Assign(1); + controller.system_properties.use_minus.Assign(1); + controller.assignment_mode = NpadAssignments::Single; + controller.footer_type = AppletFooterUiType::SwitchProController; break; - case Core::HID::NpadStyleIndex::Handheld: - shared_memory.style_tag.handheld.Assign(1); - shared_memory.device_type.handheld_left.Assign(1); - shared_memory.device_type.handheld_right.Assign(1); - shared_memory.system_properties.is_vertical.Assign(1); - shared_memory.system_properties.use_plus.Assign(1); - shared_memory.system_properties.use_minus.Assign(1); - shared_memory.assignment_mode = NpadJoyAssignmentMode::Dual; - shared_memory.applet_footer.type = AppletFooterUiType::HandheldJoyConLeftJoyConRight; + case NPadControllerType::Handheld: + controller.style_set.handheld.Assign(1); + controller.device_type.handheld_left.Assign(1); + controller.device_type.handheld_right.Assign(1); + controller.system_properties.is_vertical.Assign(1); + controller.system_properties.use_plus.Assign(1); + controller.system_properties.use_minus.Assign(1); + controller.assignment_mode = NpadAssignments::Dual; + controller.footer_type = AppletFooterUiType::HandheldJoyConLeftJoyConRight; break; - case Core::HID::NpadStyleIndex::JoyconDual: - shared_memory.style_tag.joycon_dual.Assign(1); - shared_memory.device_type.joycon_left.Assign(1); - shared_memory.device_type.joycon_right.Assign(1); - shared_memory.system_properties.is_vertical.Assign(1); - shared_memory.system_properties.use_plus.Assign(1); - shared_memory.system_properties.use_minus.Assign(1); - shared_memory.assignment_mode = NpadJoyAssignmentMode::Dual; - shared_memory.applet_footer.type = AppletFooterUiType::JoyDual; + case NPadControllerType::JoyDual: + controller.style_set.joycon_dual.Assign(1); + controller.device_type.joycon_left.Assign(1); + controller.device_type.joycon_right.Assign(1); + controller.system_properties.is_vertical.Assign(1); + controller.system_properties.use_plus.Assign(1); + controller.system_properties.use_minus.Assign(1); + controller.assignment_mode = NpadAssignments::Dual; + controller.footer_type = AppletFooterUiType::JoyDual; break; - case Core::HID::NpadStyleIndex::JoyconLeft: - shared_memory.style_tag.joycon_left.Assign(1); - shared_memory.device_type.joycon_left.Assign(1); - shared_memory.system_properties.is_horizontal.Assign(1); - shared_memory.system_properties.use_minus.Assign(1); - shared_memory.assignment_mode = NpadJoyAssignmentMode::Single; - shared_memory.applet_footer.type = AppletFooterUiType::JoyLeftHorizontal; + case NPadControllerType::JoyLeft: + controller.style_set.joycon_left.Assign(1); + controller.device_type.joycon_left.Assign(1); + controller.system_properties.is_horizontal.Assign(1); + controller.system_properties.use_minus.Assign(1); + controller.assignment_mode = NpadAssignments::Single; + controller.footer_type = AppletFooterUiType::JoyLeftHorizontal; break; - case Core::HID::NpadStyleIndex::JoyconRight: - shared_memory.style_tag.joycon_right.Assign(1); - shared_memory.device_type.joycon_right.Assign(1); - shared_memory.system_properties.is_horizontal.Assign(1); - shared_memory.system_properties.use_plus.Assign(1); - shared_memory.assignment_mode = NpadJoyAssignmentMode::Single; - shared_memory.applet_footer.type = AppletFooterUiType::JoyRightHorizontal; + case NPadControllerType::JoyRight: + controller.style_set.joycon_right.Assign(1); + controller.device_type.joycon_right.Assign(1); + controller.system_properties.is_horizontal.Assign(1); + controller.system_properties.use_plus.Assign(1); + controller.assignment_mode = NpadAssignments::Single; + controller.footer_type = AppletFooterUiType::JoyRightHorizontal; break; - case Core::HID::NpadStyleIndex::GameCube: - shared_memory.style_tag.gamecube.Assign(1); - shared_memory.device_type.fullkey.Assign(1); - shared_memory.system_properties.is_vertical.Assign(1); - shared_memory.system_properties.use_plus.Assign(1); + case NPadControllerType::GameCube: + controller.style_set.gamecube.Assign(1); + // The GC Controller behaves like a wired Pro Controller + controller.device_type.fullkey.Assign(1); + controller.system_properties.is_vertical.Assign(1); + controller.system_properties.use_plus.Assign(1); break; - case Core::HID::NpadStyleIndex::Pokeball: - shared_memory.style_tag.palma.Assign(1); - shared_memory.device_type.palma.Assign(1); - shared_memory.assignment_mode = NpadJoyAssignmentMode::Single; - break; - case Core::HID::NpadStyleIndex::NES: - shared_memory.style_tag.lark.Assign(1); - shared_memory.device_type.fullkey.Assign(1); - break; - case Core::HID::NpadStyleIndex::SNES: - shared_memory.style_tag.lucia.Assign(1); - shared_memory.device_type.fullkey.Assign(1); - shared_memory.applet_footer.type = AppletFooterUiType::Lucia; - break; - case Core::HID::NpadStyleIndex::N64: - shared_memory.style_tag.lagoon.Assign(1); - shared_memory.device_type.fullkey.Assign(1); - shared_memory.applet_footer.type = AppletFooterUiType::Lagon; - break; - case Core::HID::NpadStyleIndex::SegaGenesis: - shared_memory.style_tag.lager.Assign(1); - shared_memory.device_type.fullkey.Assign(1); - break; - default: + case NPadControllerType::Pokeball: + controller.style_set.palma.Assign(1); + controller.device_type.palma.Assign(1); + controller.assignment_mode = NpadAssignments::Single; break; } - const auto& body_colors = controller.device->GetColors(); + controller.fullkey_color.attribute = ColorAttributes::Ok; + controller.fullkey_color.fullkey.body = 0; + controller.fullkey_color.fullkey.button = 0; - shared_memory.fullkey_color.attribute = ColorAttribute::Ok; - shared_memory.fullkey_color.fullkey = body_colors.fullkey; - - shared_memory.joycon_color.attribute = ColorAttribute::Ok; - shared_memory.joycon_color.left = body_colors.left; - shared_memory.joycon_color.right = body_colors.right; + controller.joycon_color.attribute = ColorAttributes::Ok; + controller.joycon_color.left.body = + Settings::values.players.GetValue()[controller_idx].body_color_left; + controller.joycon_color.left.button = + Settings::values.players.GetValue()[controller_idx].button_color_left; + controller.joycon_color.right.body = + Settings::values.players.GetValue()[controller_idx].body_color_right; + controller.joycon_color.right.button = + Settings::values.players.GetValue()[controller_idx].button_color_right; // TODO: Investigate when we should report all batery types - const auto& battery_level = controller.device->GetBattery(); - shared_memory.battery_level_dual = battery_level.dual.battery_level; - shared_memory.battery_level_left = battery_level.left.battery_level; - shared_memory.battery_level_right = battery_level.right.battery_level; + controller.battery_level_dual = BATTERY_FULL; + controller.battery_level_left = BATTERY_FULL; + controller.battery_level_right = BATTERY_FULL; - controller.is_connected = true; - controller.device->Connect(); - SignalStyleSetChangedEvent(npad_id); - WriteEmptyEntry(controller.shared_memory_entry); + SignalStyleSetChangedEvent(IndexToNPad(controller_idx)); } void Controller_NPad::OnInit() { + for (std::size_t i = 0; i < styleset_changed_events.size(); ++i) { + styleset_changed_events[i] = + service_context.CreateEvent(fmt::format("npad:NpadStyleSetChanged_{}", i)); + } + if (!IsControllerActivated()) { return; } - for (std::size_t i = 0; i < controller_data.size(); ++i) { - auto& controller = controller_data[i]; - controller.styleset_changed_event = - service_context.CreateEvent(fmt::format("npad:NpadStyleSetChanged_{}", i)); - } + OnLoadInputDevices(); - if (hid_core.GetSupportedStyleTag().raw == Core::HID::NpadStyleSet::None) { + if (style.raw == 0) { // We want to support all controllers - Core::HID::NpadStyleTag style{}; style.handheld.Assign(1); style.joycon_left.Assign(1); style.joycon_right.Assign(1); @@ -261,120 +273,173 @@ void Controller_NPad::OnInit() { style.fullkey.Assign(1); style.gamecube.Assign(1); style.palma.Assign(1); - hid_core.SetSupportedStyleTag(style); + } + + std::transform(Settings::values.players.GetValue().begin(), + Settings::values.players.GetValue().end(), connected_controllers.begin(), + [](const Settings::PlayerInput& player) { + return ControllerHolder{MapSettingsTypeToNPad(player.controller_type), + player.connected}; + }); + + // Connect the Player 1 or Handheld controller if none are connected. + if (std::none_of(connected_controllers.begin(), connected_controllers.end(), + [](const ControllerHolder& controller) { return controller.is_connected; })) { + const auto controller = + MapSettingsTypeToNPad(Settings::values.players.GetValue()[0].controller_type); + if (controller == NPadControllerType::Handheld) { + Settings::values.players.GetValue()[HANDHELD_INDEX].connected = true; + connected_controllers[HANDHELD_INDEX] = {controller, true}; + } else { + Settings::values.players.GetValue()[0].connected = true; + connected_controllers[0] = {controller, true}; + } + } + + // Account for handheld + if (connected_controllers[HANDHELD_INDEX].is_connected) { + connected_controllers[HANDHELD_INDEX].type = NPadControllerType::Handheld; } supported_npad_id_types.resize(npad_id_list.size()); std::memcpy(supported_npad_id_types.data(), npad_id_list.data(), - npad_id_list.size() * sizeof(Core::HID::NpadIdType)); + npad_id_list.size() * sizeof(u32)); - // Prefill controller buffers - for (auto& controller : controller_data) { - auto& npad = controller.shared_memory_entry; - npad.fullkey_color = { - .attribute = ColorAttribute::NoController, - .fullkey = {}, - }; - npad.joycon_color = { - .attribute = ColorAttribute::NoController, - .left = {}, - .right = {}, - }; - // HW seems to initialize the first 19 entries - for (std::size_t i = 0; i < 19; ++i) { - WriteEmptyEntry(npad); - } - } - - // Connect controllers - for (auto& controller : controller_data) { - const auto& device = controller.device; - if (device->IsConnected()) { - AddNewControllerAt(device->GetNpadStyleIndex(), device->GetNpadIdType()); + for (std::size_t i = 0; i < connected_controllers.size(); ++i) { + const auto& controller = connected_controllers[i]; + if (controller.is_connected) { + AddNewControllerAt(controller.type, i); } } } -void Controller_NPad::WriteEmptyEntry(NpadInternalState& npad) { - NPadGenericState dummy_pad_state{}; - NpadGcTriggerState dummy_gc_state{}; - dummy_pad_state.sampling_number = npad.fullkey_lifo.ReadCurrentEntry().sampling_number + 1; - npad.fullkey_lifo.WriteNextEntry(dummy_pad_state); - dummy_pad_state.sampling_number = npad.handheld_lifo.ReadCurrentEntry().sampling_number + 1; - npad.handheld_lifo.WriteNextEntry(dummy_pad_state); - dummy_pad_state.sampling_number = npad.joy_dual_lifo.ReadCurrentEntry().sampling_number + 1; - npad.joy_dual_lifo.WriteNextEntry(dummy_pad_state); - dummy_pad_state.sampling_number = npad.joy_left_lifo.ReadCurrentEntry().sampling_number + 1; - npad.joy_left_lifo.WriteNextEntry(dummy_pad_state); - dummy_pad_state.sampling_number = npad.joy_right_lifo.ReadCurrentEntry().sampling_number + 1; - npad.joy_right_lifo.WriteNextEntry(dummy_pad_state); - dummy_pad_state.sampling_number = npad.palma_lifo.ReadCurrentEntry().sampling_number + 1; - npad.palma_lifo.WriteNextEntry(dummy_pad_state); - dummy_pad_state.sampling_number = npad.system_ext_lifo.ReadCurrentEntry().sampling_number + 1; - npad.system_ext_lifo.WriteNextEntry(dummy_pad_state); - dummy_gc_state.sampling_number = npad.gc_trigger_lifo.ReadCurrentEntry().sampling_number + 1; - npad.gc_trigger_lifo.WriteNextEntry(dummy_gc_state); +void Controller_NPad::OnLoadInputDevices() { + const auto& players = Settings::values.players.GetValue(); + + std::lock_guard lock{mutex}; + for (std::size_t i = 0; i < players.size(); ++i) { + std::transform(players[i].buttons.begin() + Settings::NativeButton::BUTTON_HID_BEGIN, + players[i].buttons.begin() + Settings::NativeButton::BUTTON_HID_END, + buttons[i].begin(), Input::CreateDevice); + std::transform(players[i].analogs.begin() + Settings::NativeAnalog::STICK_HID_BEGIN, + players[i].analogs.begin() + Settings::NativeAnalog::STICK_HID_END, + sticks[i].begin(), Input::CreateDevice); + std::transform(players[i].vibrations.begin() + + Settings::NativeVibration::VIBRATION_HID_BEGIN, + players[i].vibrations.begin() + Settings::NativeVibration::VIBRATION_HID_END, + vibrations[i].begin(), Input::CreateDevice); + std::transform(players[i].motions.begin() + Settings::NativeMotion::MOTION_HID_BEGIN, + players[i].motions.begin() + Settings::NativeMotion::MOTION_HID_END, + motions[i].begin(), Input::CreateDevice); + for (std::size_t device_idx = 0; device_idx < vibrations[i].size(); ++device_idx) { + InitializeVibrationDeviceAtIndex(i, device_idx); + } + } } void Controller_NPad::OnRelease() { - for (std::size_t i = 0; i < controller_data.size(); ++i) { - auto& controller = controller_data[i]; - service_context.CloseEvent(controller.styleset_changed_event); - for (std::size_t device_idx = 0; device_idx < controller.vibration.size(); ++device_idx) { - VibrateControllerAtIndex(controller.device->GetNpadIdType(), device_idx, {}); + for (std::size_t npad_idx = 0; npad_idx < vibrations.size(); ++npad_idx) { + for (std::size_t device_idx = 0; device_idx < vibrations[npad_idx].size(); ++device_idx) { + VibrateControllerAtIndex(npad_idx, device_idx, {}); } } + + for (std::size_t i = 0; i < styleset_changed_events.size(); ++i) { + service_context.CloseEvent(styleset_changed_events[i]); + } } -void Controller_NPad::RequestPadStateUpdate(Core::HID::NpadIdType npad_id) { +void Controller_NPad::RequestPadStateUpdate(u32 npad_id) { std::lock_guard lock{mutex}; - auto& controller = GetControllerFromNpadIdType(npad_id); - const auto controller_type = controller.device->GetNpadStyleIndex(); - if (!controller.device->IsConnected()) { + + const auto controller_idx = NPadIdToIndex(npad_id); + const auto controller_type = connected_controllers[controller_idx].type; + if (!connected_controllers[controller_idx].is_connected) { return; } + auto& pad_state = npad_pad_states[controller_idx].pad_states; + auto& lstick_entry = npad_pad_states[controller_idx].l_stick; + auto& rstick_entry = npad_pad_states[controller_idx].r_stick; + auto& trigger_entry = npad_trigger_states[controller_idx]; + const auto& button_state = buttons[controller_idx]; + const auto& analog_state = sticks[controller_idx]; + const auto [stick_l_x_f, stick_l_y_f] = + analog_state[static_cast(JoystickId::Joystick_Left)]->GetStatus(); + const auto [stick_r_x_f, stick_r_y_f] = + analog_state[static_cast(JoystickId::Joystick_Right)]->GetStatus(); - auto& pad_entry = controller.npad_pad_state; - auto& trigger_entry = controller.npad_trigger_state; - const auto button_state = controller.device->GetNpadButtons(); - const auto stick_state = controller.device->GetSticks(); + using namespace Settings::NativeButton; + if (controller_type != NPadControllerType::JoyLeft) { + pad_state.a.Assign(button_state[A - BUTTON_HID_BEGIN]->GetStatus()); + pad_state.b.Assign(button_state[B - BUTTON_HID_BEGIN]->GetStatus()); + pad_state.x.Assign(button_state[X - BUTTON_HID_BEGIN]->GetStatus()); + pad_state.y.Assign(button_state[Y - BUTTON_HID_BEGIN]->GetStatus()); + pad_state.r_stick.Assign(button_state[RStick - BUTTON_HID_BEGIN]->GetStatus()); + pad_state.r.Assign(button_state[R - BUTTON_HID_BEGIN]->GetStatus()); + pad_state.zr.Assign(button_state[ZR - BUTTON_HID_BEGIN]->GetStatus()); + pad_state.plus.Assign(button_state[Plus - BUTTON_HID_BEGIN]->GetStatus()); - using btn = Core::HID::NpadButton; - pad_entry.npad_buttons.raw = btn::None; - if (controller_type != Core::HID::NpadStyleIndex::JoyconLeft) { - constexpr btn right_button_mask = btn::A | btn::B | btn::X | btn::Y | btn::StickR | btn::R | - btn::ZR | btn::Plus | btn::StickRLeft | btn::StickRUp | - btn::StickRRight | btn::StickRDown; - pad_entry.npad_buttons.raw |= button_state.raw & right_button_mask; - pad_entry.r_stick = stick_state.right; + pad_state.r_stick_right.Assign( + analog_state[static_cast(JoystickId::Joystick_Right)] + ->GetAnalogDirectionStatus(Input::AnalogDirection::RIGHT)); + pad_state.r_stick_left.Assign( + analog_state[static_cast(JoystickId::Joystick_Right)] + ->GetAnalogDirectionStatus(Input::AnalogDirection::LEFT)); + pad_state.r_stick_up.Assign( + analog_state[static_cast(JoystickId::Joystick_Right)] + ->GetAnalogDirectionStatus(Input::AnalogDirection::UP)); + pad_state.r_stick_down.Assign( + analog_state[static_cast(JoystickId::Joystick_Right)] + ->GetAnalogDirectionStatus(Input::AnalogDirection::DOWN)); + rstick_entry.x = static_cast(stick_r_x_f * HID_JOYSTICK_MAX); + rstick_entry.y = static_cast(stick_r_y_f * HID_JOYSTICK_MAX); } - if (controller_type != Core::HID::NpadStyleIndex::JoyconRight) { - constexpr btn left_button_mask = - btn::Left | btn::Up | btn::Right | btn::Down | btn::StickL | btn::L | btn::ZL | - btn::Minus | btn::StickLLeft | btn::StickLUp | btn::StickLRight | btn::StickLDown; - pad_entry.npad_buttons.raw |= button_state.raw & left_button_mask; - pad_entry.l_stick = stick_state.left; + if (controller_type != NPadControllerType::JoyRight) { + pad_state.d_left.Assign(button_state[DLeft - BUTTON_HID_BEGIN]->GetStatus()); + pad_state.d_up.Assign(button_state[DUp - BUTTON_HID_BEGIN]->GetStatus()); + pad_state.d_right.Assign(button_state[DRight - BUTTON_HID_BEGIN]->GetStatus()); + pad_state.d_down.Assign(button_state[DDown - BUTTON_HID_BEGIN]->GetStatus()); + pad_state.l_stick.Assign(button_state[LStick - BUTTON_HID_BEGIN]->GetStatus()); + pad_state.l.Assign(button_state[L - BUTTON_HID_BEGIN]->GetStatus()); + pad_state.zl.Assign(button_state[ZL - BUTTON_HID_BEGIN]->GetStatus()); + pad_state.minus.Assign(button_state[Minus - BUTTON_HID_BEGIN]->GetStatus()); + + pad_state.l_stick_right.Assign( + analog_state[static_cast(JoystickId::Joystick_Left)] + ->GetAnalogDirectionStatus(Input::AnalogDirection::RIGHT)); + pad_state.l_stick_left.Assign( + analog_state[static_cast(JoystickId::Joystick_Left)] + ->GetAnalogDirectionStatus(Input::AnalogDirection::LEFT)); + pad_state.l_stick_up.Assign( + analog_state[static_cast(JoystickId::Joystick_Left)] + ->GetAnalogDirectionStatus(Input::AnalogDirection::UP)); + pad_state.l_stick_down.Assign( + analog_state[static_cast(JoystickId::Joystick_Left)] + ->GetAnalogDirectionStatus(Input::AnalogDirection::DOWN)); + lstick_entry.x = static_cast(stick_l_x_f * HID_JOYSTICK_MAX); + lstick_entry.y = static_cast(stick_l_y_f * HID_JOYSTICK_MAX); } - if (controller_type == Core::HID::NpadStyleIndex::JoyconLeft) { - pad_entry.npad_buttons.left_sl.Assign(button_state.left_sl); - pad_entry.npad_buttons.left_sr.Assign(button_state.left_sr); + if (controller_type == NPadControllerType::JoyLeft) { + pad_state.left_sl.Assign(button_state[SL - BUTTON_HID_BEGIN]->GetStatus()); + pad_state.left_sr.Assign(button_state[SR - BUTTON_HID_BEGIN]->GetStatus()); } - if (controller_type == Core::HID::NpadStyleIndex::JoyconRight) { - pad_entry.npad_buttons.right_sl.Assign(button_state.right_sl); - pad_entry.npad_buttons.right_sr.Assign(button_state.right_sr); + if (controller_type == NPadControllerType::JoyRight) { + pad_state.right_sl.Assign(button_state[SL - BUTTON_HID_BEGIN]->GetStatus()); + pad_state.right_sr.Assign(button_state[SR - BUTTON_HID_BEGIN]->GetStatus()); } - if (controller_type == Core::HID::NpadStyleIndex::GameCube) { - const auto& trigger_state = controller.device->GetTriggers(); - trigger_entry.l_analog = trigger_state.left; - trigger_entry.r_analog = trigger_state.right; - pad_entry.npad_buttons.zl.Assign(false); - pad_entry.npad_buttons.zr.Assign(button_state.r); - pad_entry.npad_buttons.l.Assign(button_state.zl); - pad_entry.npad_buttons.r.Assign(button_state.zr); + if (controller_type == NPadControllerType::GameCube) { + trigger_entry.l_analog = static_cast( + button_state[ZL - BUTTON_HID_BEGIN]->GetStatus() ? HID_TRIGGER_MAX : 0); + trigger_entry.r_analog = static_cast( + button_state[ZR - BUTTON_HID_BEGIN]->GetStatus() ? HID_TRIGGER_MAX : 0); + pad_state.zl.Assign(false); + pad_state.zr.Assign(button_state[R - BUTTON_HID_BEGIN]->GetStatus()); + pad_state.l.Assign(button_state[ZL - BUTTON_HID_BEGIN]->GetStatus()); + pad_state.r.Assign(button_state[ZR - BUTTON_HID_BEGIN]->GetStatus()); } } @@ -383,132 +448,173 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* if (!IsControllerActivated()) { return; } + for (std::size_t i = 0; i < shared_memory_entries.size(); ++i) { + auto& npad = shared_memory_entries[i]; + const std::array controller_npads{ + &npad.fullkey_states, &npad.handheld_states, &npad.joy_dual_states, + &npad.joy_left_states, &npad.joy_right_states, &npad.palma_states, + &npad.system_ext_states}; - for (std::size_t i = 0; i < controller_data.size(); ++i) { - auto& controller = controller_data[i]; - auto& npad = controller.shared_memory_entry; + // There is the posibility to have more controllers with analog triggers + const std::array controller_triggers{ + &npad.gc_trigger_states, + }; - const auto& controller_type = controller.device->GetNpadStyleIndex(); + for (auto* main_controller : controller_npads) { + main_controller->common.entry_count = 16; + main_controller->common.total_entry_count = 17; - if (controller_type == Core::HID::NpadStyleIndex::None || - !controller.device->IsConnected()) { - // Refresh shared memory - std::memcpy(data + NPAD_OFFSET + (i * sizeof(NpadInternalState)), - &controller.shared_memory_entry, sizeof(NpadInternalState)); - continue; + const auto& last_entry = + main_controller->npad[main_controller->common.last_entry_index]; + + main_controller->common.timestamp = core_timing.GetCPUTicks(); + main_controller->common.last_entry_index = + (main_controller->common.last_entry_index + 1) % 17; + + auto& cur_entry = main_controller->npad[main_controller->common.last_entry_index]; + + cur_entry.timestamp = last_entry.timestamp + 1; + cur_entry.timestamp2 = cur_entry.timestamp; } - RequestPadStateUpdate(controller.device->GetNpadIdType()); - auto& pad_state = controller.npad_pad_state; - auto& libnx_state = controller.npad_libnx_state; - auto& trigger_state = controller.npad_trigger_state; + for (auto* analog_trigger : controller_triggers) { + analog_trigger->entry_count = 16; + analog_trigger->total_entry_count = 17; + + const auto& last_entry = analog_trigger->trigger[analog_trigger->last_entry_index]; + + analog_trigger->timestamp = core_timing.GetCPUTicks(); + analog_trigger->last_entry_index = (analog_trigger->last_entry_index + 1) % 17; + + auto& cur_entry = analog_trigger->trigger[analog_trigger->last_entry_index]; + + cur_entry.timestamp = last_entry.timestamp + 1; + cur_entry.timestamp2 = cur_entry.timestamp; + } + + const auto& controller_type = connected_controllers[i].type; + + if (controller_type == NPadControllerType::None || !connected_controllers[i].is_connected) { + continue; + } + const u32 npad_index = static_cast(i); + + RequestPadStateUpdate(npad_index); + auto& pad_state = npad_pad_states[npad_index]; + auto& trigger_state = npad_trigger_states[npad_index]; + + auto& main_controller = + npad.fullkey_states.npad[npad.fullkey_states.common.last_entry_index]; + auto& handheld_entry = + npad.handheld_states.npad[npad.handheld_states.common.last_entry_index]; + auto& dual_entry = npad.joy_dual_states.npad[npad.joy_dual_states.common.last_entry_index]; + auto& left_entry = npad.joy_left_states.npad[npad.joy_left_states.common.last_entry_index]; + auto& right_entry = + npad.joy_right_states.npad[npad.joy_right_states.common.last_entry_index]; + auto& pokeball_entry = npad.palma_states.npad[npad.palma_states.common.last_entry_index]; + auto& libnx_entry = + npad.system_ext_states.npad[npad.system_ext_states.common.last_entry_index]; + auto& trigger_entry = + npad.gc_trigger_states.trigger[npad.gc_trigger_states.last_entry_index]; + + libnx_entry.connection_status.raw = 0; + libnx_entry.connection_status.is_connected.Assign(1); + + switch (controller_type) { + case NPadControllerType::None: + UNREACHABLE(); + break; + case NPadControllerType::ProController: + main_controller.connection_status.raw = 0; + main_controller.connection_status.is_connected.Assign(1); + main_controller.connection_status.is_wired.Assign(1); + main_controller.pad.pad_states.raw = pad_state.pad_states.raw; + main_controller.pad.l_stick = pad_state.l_stick; + main_controller.pad.r_stick = pad_state.r_stick; + + libnx_entry.connection_status.is_wired.Assign(1); + break; + case NPadControllerType::Handheld: + handheld_entry.connection_status.raw = 0; + handheld_entry.connection_status.is_connected.Assign(1); + handheld_entry.connection_status.is_wired.Assign(1); + handheld_entry.connection_status.is_left_connected.Assign(1); + handheld_entry.connection_status.is_right_connected.Assign(1); + handheld_entry.connection_status.is_left_wired.Assign(1); + handheld_entry.connection_status.is_right_wired.Assign(1); + handheld_entry.pad.pad_states.raw = pad_state.pad_states.raw; + handheld_entry.pad.l_stick = pad_state.l_stick; + handheld_entry.pad.r_stick = pad_state.r_stick; + + libnx_entry.connection_status.is_wired.Assign(1); + libnx_entry.connection_status.is_left_connected.Assign(1); + libnx_entry.connection_status.is_right_connected.Assign(1); + libnx_entry.connection_status.is_left_wired.Assign(1); + libnx_entry.connection_status.is_right_wired.Assign(1); + break; + case NPadControllerType::JoyDual: + dual_entry.connection_status.raw = 0; + dual_entry.connection_status.is_connected.Assign(1); + dual_entry.connection_status.is_left_connected.Assign(1); + dual_entry.connection_status.is_right_connected.Assign(1); + dual_entry.pad.pad_states.raw = pad_state.pad_states.raw; + dual_entry.pad.l_stick = pad_state.l_stick; + dual_entry.pad.r_stick = pad_state.r_stick; + + libnx_entry.connection_status.is_left_connected.Assign(1); + libnx_entry.connection_status.is_right_connected.Assign(1); + break; + case NPadControllerType::JoyLeft: + left_entry.connection_status.raw = 0; + left_entry.connection_status.is_connected.Assign(1); + left_entry.connection_status.is_left_connected.Assign(1); + left_entry.pad.pad_states.raw = pad_state.pad_states.raw; + left_entry.pad.l_stick = pad_state.l_stick; + left_entry.pad.r_stick = pad_state.r_stick; + + libnx_entry.connection_status.is_left_connected.Assign(1); + break; + case NPadControllerType::JoyRight: + right_entry.connection_status.raw = 0; + right_entry.connection_status.is_connected.Assign(1); + right_entry.connection_status.is_right_connected.Assign(1); + right_entry.pad.pad_states.raw = pad_state.pad_states.raw; + right_entry.pad.l_stick = pad_state.l_stick; + right_entry.pad.r_stick = pad_state.r_stick; + + libnx_entry.connection_status.is_right_connected.Assign(1); + break; + case NPadControllerType::GameCube: + main_controller.connection_status.raw = 0; + main_controller.connection_status.is_connected.Assign(1); + main_controller.connection_status.is_wired.Assign(1); + main_controller.pad.pad_states.raw = pad_state.pad_states.raw; + main_controller.pad.l_stick = pad_state.l_stick; + main_controller.pad.r_stick = pad_state.r_stick; + trigger_entry.l_analog = trigger_state.l_analog; + trigger_entry.r_analog = trigger_state.r_analog; + + libnx_entry.connection_status.is_wired.Assign(1); + break; + case NPadControllerType::Pokeball: + pokeball_entry.connection_status.raw = 0; + pokeball_entry.connection_status.is_connected.Assign(1); + pokeball_entry.pad.pad_states.raw = pad_state.pad_states.raw; + pokeball_entry.pad.l_stick = pad_state.l_stick; + pokeball_entry.pad.r_stick = pad_state.r_stick; + break; + } // LibNX exclusively uses this section, so we always update it since LibNX doesn't activate // any controllers. - libnx_state.connection_status.raw = 0; - libnx_state.connection_status.is_connected.Assign(1); - switch (controller_type) { - case Core::HID::NpadStyleIndex::None: - UNREACHABLE(); - break; - case Core::HID::NpadStyleIndex::ProController: - case Core::HID::NpadStyleIndex::NES: - case Core::HID::NpadStyleIndex::SNES: - case Core::HID::NpadStyleIndex::N64: - case Core::HID::NpadStyleIndex::SegaGenesis: - pad_state.connection_status.raw = 0; - pad_state.connection_status.is_connected.Assign(1); - pad_state.connection_status.is_wired.Assign(1); + libnx_entry.pad.pad_states.raw = pad_state.pad_states.raw; + libnx_entry.pad.l_stick = pad_state.l_stick; + libnx_entry.pad.r_stick = pad_state.r_stick; - libnx_state.connection_status.is_wired.Assign(1); - pad_state.sampling_number = - npad.fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1; - npad.fullkey_lifo.WriteNextEntry(pad_state); - break; - case Core::HID::NpadStyleIndex::Handheld: - pad_state.connection_status.raw = 0; - pad_state.connection_status.is_connected.Assign(1); - pad_state.connection_status.is_wired.Assign(1); - pad_state.connection_status.is_left_connected.Assign(1); - pad_state.connection_status.is_right_connected.Assign(1); - pad_state.connection_status.is_left_wired.Assign(1); - pad_state.connection_status.is_right_wired.Assign(1); - - libnx_state.connection_status.is_wired.Assign(1); - libnx_state.connection_status.is_left_connected.Assign(1); - libnx_state.connection_status.is_right_connected.Assign(1); - libnx_state.connection_status.is_left_wired.Assign(1); - libnx_state.connection_status.is_right_wired.Assign(1); - pad_state.sampling_number = - npad.handheld_lifo.ReadCurrentEntry().state.sampling_number + 1; - npad.handheld_lifo.WriteNextEntry(pad_state); - break; - case Core::HID::NpadStyleIndex::JoyconDual: - pad_state.connection_status.raw = 0; - pad_state.connection_status.is_connected.Assign(1); - pad_state.connection_status.is_left_connected.Assign(1); - pad_state.connection_status.is_right_connected.Assign(1); - - libnx_state.connection_status.is_left_connected.Assign(1); - libnx_state.connection_status.is_right_connected.Assign(1); - pad_state.sampling_number = - npad.joy_dual_lifo.ReadCurrentEntry().state.sampling_number + 1; - npad.joy_dual_lifo.WriteNextEntry(pad_state); - break; - case Core::HID::NpadStyleIndex::JoyconLeft: - pad_state.connection_status.raw = 0; - pad_state.connection_status.is_connected.Assign(1); - pad_state.connection_status.is_left_connected.Assign(1); - - libnx_state.connection_status.is_left_connected.Assign(1); - pad_state.sampling_number = - npad.joy_left_lifo.ReadCurrentEntry().state.sampling_number + 1; - npad.joy_left_lifo.WriteNextEntry(pad_state); - break; - case Core::HID::NpadStyleIndex::JoyconRight: - pad_state.connection_status.raw = 0; - pad_state.connection_status.is_connected.Assign(1); - pad_state.connection_status.is_right_connected.Assign(1); - - libnx_state.connection_status.is_right_connected.Assign(1); - pad_state.sampling_number = - npad.joy_right_lifo.ReadCurrentEntry().state.sampling_number + 1; - npad.joy_right_lifo.WriteNextEntry(pad_state); - break; - case Core::HID::NpadStyleIndex::GameCube: - pad_state.connection_status.raw = 0; - pad_state.connection_status.is_connected.Assign(1); - pad_state.connection_status.is_wired.Assign(1); - - libnx_state.connection_status.is_wired.Assign(1); - pad_state.sampling_number = - npad.fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1; - trigger_state.sampling_number = - npad.gc_trigger_lifo.ReadCurrentEntry().state.sampling_number + 1; - npad.fullkey_lifo.WriteNextEntry(pad_state); - npad.gc_trigger_lifo.WriteNextEntry(trigger_state); - break; - case Core::HID::NpadStyleIndex::Pokeball: - pad_state.connection_status.raw = 0; - pad_state.connection_status.is_connected.Assign(1); - pad_state.sampling_number = - npad.palma_lifo.ReadCurrentEntry().state.sampling_number + 1; - npad.palma_lifo.WriteNextEntry(pad_state); - break; - default: - break; - } - - libnx_state.npad_buttons.raw = pad_state.npad_buttons.raw; - libnx_state.l_stick = pad_state.l_stick; - libnx_state.r_stick = pad_state.r_stick; - npad.system_ext_lifo.WriteNextEntry(pad_state); - - press_state |= static_cast(pad_state.npad_buttons.raw); - - std::memcpy(data + NPAD_OFFSET + (i * sizeof(NpadInternalState)), - &controller.shared_memory_entry, sizeof(NpadInternalState)); + press_state |= static_cast(pad_state.pad_states.raw); } + std::memcpy(data + NPAD_OFFSET, shared_memory_entries.data(), + shared_memory_entries.size() * sizeof(NPadEntry)); } void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, @@ -516,138 +622,145 @@ void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing if (!IsControllerActivated()) { return; } + for (std::size_t i = 0; i < shared_memory_entries.size(); ++i) { + auto& npad = shared_memory_entries[i]; - for (std::size_t i = 0; i < controller_data.size(); ++i) { - auto& controller = controller_data[i]; + const auto& controller_type = connected_controllers[i].type; - const auto& controller_type = controller.device->GetNpadStyleIndex(); - - if (controller_type == Core::HID::NpadStyleIndex::None || - !controller.device->IsConnected()) { + if (controller_type == NPadControllerType::None || !connected_controllers[i].is_connected) { continue; } - auto& npad = controller.shared_memory_entry; - const auto& motion_state = controller.device->GetMotions(); - auto& sixaxis_fullkey_state = controller.sixaxis_fullkey_state; - auto& sixaxis_handheld_state = controller.sixaxis_handheld_state; - auto& sixaxis_dual_left_state = controller.sixaxis_dual_left_state; - auto& sixaxis_dual_right_state = controller.sixaxis_dual_right_state; - auto& sixaxis_left_lifo_state = controller.sixaxis_left_lifo_state; - auto& sixaxis_right_lifo_state = controller.sixaxis_right_lifo_state; + const std::array controller_sixaxes{ + &npad.sixaxis_fullkey, &npad.sixaxis_handheld, &npad.sixaxis_dual_left, + &npad.sixaxis_dual_right, &npad.sixaxis_left, &npad.sixaxis_right, + }; - if (controller.sixaxis_sensor_enabled && Settings::values.motion_enabled.GetValue()) { - controller.sixaxis_at_rest = true; - for (std::size_t e = 0; e < motion_state.size(); ++e) { - controller.sixaxis_at_rest = - controller.sixaxis_at_rest && motion_state[e].is_at_rest; + for (auto* sixaxis_sensor : controller_sixaxes) { + sixaxis_sensor->common.entry_count = 16; + sixaxis_sensor->common.total_entry_count = 17; + + const auto& last_entry = + sixaxis_sensor->sixaxis[sixaxis_sensor->common.last_entry_index]; + + sixaxis_sensor->common.timestamp = core_timing.GetCPUTicks(); + sixaxis_sensor->common.last_entry_index = + (sixaxis_sensor->common.last_entry_index + 1) % 17; + + auto& cur_entry = sixaxis_sensor->sixaxis[sixaxis_sensor->common.last_entry_index]; + + cur_entry.timestamp = last_entry.timestamp + 1; + cur_entry.timestamp2 = cur_entry.timestamp; + } + + // Try to read sixaxis sensor states + std::array motion_devices; + + if (sixaxis_sensors_enabled && Settings::values.motion_enabled.GetValue()) { + sixaxis_at_rest = true; + for (std::size_t e = 0; e < motion_devices.size(); ++e) { + const auto& device = motions[i][e]; + if (device) { + std::tie(motion_devices[e].accel, motion_devices[e].gyro, + motion_devices[e].rotation, motion_devices[e].orientation, + motion_devices[e].quaternion) = device->GetStatus(); + sixaxis_at_rest = sixaxis_at_rest && motion_devices[e].gyro.Length2() < 0.0001f; + } } } + auto& full_sixaxis_entry = + npad.sixaxis_fullkey.sixaxis[npad.sixaxis_fullkey.common.last_entry_index]; + auto& handheld_sixaxis_entry = + npad.sixaxis_handheld.sixaxis[npad.sixaxis_handheld.common.last_entry_index]; + auto& dual_left_sixaxis_entry = + npad.sixaxis_dual_left.sixaxis[npad.sixaxis_dual_left.common.last_entry_index]; + auto& dual_right_sixaxis_entry = + npad.sixaxis_dual_right.sixaxis[npad.sixaxis_dual_right.common.last_entry_index]; + auto& left_sixaxis_entry = + npad.sixaxis_left.sixaxis[npad.sixaxis_left.common.last_entry_index]; + auto& right_sixaxis_entry = + npad.sixaxis_right.sixaxis[npad.sixaxis_right.common.last_entry_index]; + switch (controller_type) { - case Core::HID::NpadStyleIndex::None: + case NPadControllerType::None: UNREACHABLE(); break; - case Core::HID::NpadStyleIndex::ProController: - sixaxis_fullkey_state.attribute.raw = 0; - if (controller.sixaxis_sensor_enabled) { - sixaxis_fullkey_state.attribute.is_connected.Assign(1); - sixaxis_fullkey_state.accel = motion_state[0].accel; - sixaxis_fullkey_state.gyro = motion_state[0].gyro; - sixaxis_fullkey_state.rotation = motion_state[0].rotation; - sixaxis_fullkey_state.orientation = motion_state[0].orientation; + case NPadControllerType::ProController: + full_sixaxis_entry.attribute.raw = 0; + if (sixaxis_sensors_enabled && motions[i][0]) { + full_sixaxis_entry.attribute.is_connected.Assign(1); + full_sixaxis_entry.accel = motion_devices[0].accel; + full_sixaxis_entry.gyro = motion_devices[0].gyro; + full_sixaxis_entry.rotation = motion_devices[0].rotation; + full_sixaxis_entry.orientation = motion_devices[0].orientation; } break; - case Core::HID::NpadStyleIndex::Handheld: - sixaxis_handheld_state.attribute.raw = 0; - if (controller.sixaxis_sensor_enabled) { - sixaxis_handheld_state.attribute.is_connected.Assign(1); - sixaxis_handheld_state.accel = motion_state[0].accel; - sixaxis_handheld_state.gyro = motion_state[0].gyro; - sixaxis_handheld_state.rotation = motion_state[0].rotation; - sixaxis_handheld_state.orientation = motion_state[0].orientation; + case NPadControllerType::Handheld: + handheld_sixaxis_entry.attribute.raw = 0; + if (sixaxis_sensors_enabled && motions[i][0]) { + handheld_sixaxis_entry.attribute.is_connected.Assign(1); + handheld_sixaxis_entry.accel = motion_devices[0].accel; + handheld_sixaxis_entry.gyro = motion_devices[0].gyro; + handheld_sixaxis_entry.rotation = motion_devices[0].rotation; + handheld_sixaxis_entry.orientation = motion_devices[0].orientation; } break; - case Core::HID::NpadStyleIndex::JoyconDual: - sixaxis_dual_left_state.attribute.raw = 0; - sixaxis_dual_right_state.attribute.raw = 0; - if (controller.sixaxis_sensor_enabled) { + case NPadControllerType::JoyDual: + dual_left_sixaxis_entry.attribute.raw = 0; + dual_right_sixaxis_entry.attribute.raw = 0; + if (sixaxis_sensors_enabled && motions[i][0]) { // Set motion for the left joycon - sixaxis_dual_left_state.attribute.is_connected.Assign(1); - sixaxis_dual_left_state.accel = motion_state[0].accel; - sixaxis_dual_left_state.gyro = motion_state[0].gyro; - sixaxis_dual_left_state.rotation = motion_state[0].rotation; - sixaxis_dual_left_state.orientation = motion_state[0].orientation; + dual_left_sixaxis_entry.attribute.is_connected.Assign(1); + dual_left_sixaxis_entry.accel = motion_devices[0].accel; + dual_left_sixaxis_entry.gyro = motion_devices[0].gyro; + dual_left_sixaxis_entry.rotation = motion_devices[0].rotation; + dual_left_sixaxis_entry.orientation = motion_devices[0].orientation; } - if (controller.sixaxis_sensor_enabled) { + if (sixaxis_sensors_enabled && motions[i][1]) { // Set motion for the right joycon - sixaxis_dual_right_state.attribute.is_connected.Assign(1); - sixaxis_dual_right_state.accel = motion_state[1].accel; - sixaxis_dual_right_state.gyro = motion_state[1].gyro; - sixaxis_dual_right_state.rotation = motion_state[1].rotation; - sixaxis_dual_right_state.orientation = motion_state[1].orientation; + dual_right_sixaxis_entry.attribute.is_connected.Assign(1); + dual_right_sixaxis_entry.accel = motion_devices[1].accel; + dual_right_sixaxis_entry.gyro = motion_devices[1].gyro; + dual_right_sixaxis_entry.rotation = motion_devices[1].rotation; + dual_right_sixaxis_entry.orientation = motion_devices[1].orientation; } break; - case Core::HID::NpadStyleIndex::JoyconLeft: - sixaxis_left_lifo_state.attribute.raw = 0; - if (controller.sixaxis_sensor_enabled) { - sixaxis_left_lifo_state.attribute.is_connected.Assign(1); - sixaxis_left_lifo_state.accel = motion_state[0].accel; - sixaxis_left_lifo_state.gyro = motion_state[0].gyro; - sixaxis_left_lifo_state.rotation = motion_state[0].rotation; - sixaxis_left_lifo_state.orientation = motion_state[0].orientation; + case NPadControllerType::JoyLeft: + left_sixaxis_entry.attribute.raw = 0; + if (sixaxis_sensors_enabled && motions[i][0]) { + left_sixaxis_entry.attribute.is_connected.Assign(1); + left_sixaxis_entry.accel = motion_devices[0].accel; + left_sixaxis_entry.gyro = motion_devices[0].gyro; + left_sixaxis_entry.rotation = motion_devices[0].rotation; + left_sixaxis_entry.orientation = motion_devices[0].orientation; } break; - case Core::HID::NpadStyleIndex::JoyconRight: - sixaxis_right_lifo_state.attribute.raw = 0; - if (controller.sixaxis_sensor_enabled) { - sixaxis_right_lifo_state.attribute.is_connected.Assign(1); - sixaxis_right_lifo_state.accel = motion_state[1].accel; - sixaxis_right_lifo_state.gyro = motion_state[1].gyro; - sixaxis_right_lifo_state.rotation = motion_state[1].rotation; - sixaxis_right_lifo_state.orientation = motion_state[1].orientation; + case NPadControllerType::JoyRight: + right_sixaxis_entry.attribute.raw = 0; + if (sixaxis_sensors_enabled && motions[i][1]) { + right_sixaxis_entry.attribute.is_connected.Assign(1); + right_sixaxis_entry.accel = motion_devices[1].accel; + right_sixaxis_entry.gyro = motion_devices[1].gyro; + right_sixaxis_entry.rotation = motion_devices[1].rotation; + right_sixaxis_entry.orientation = motion_devices[1].orientation; } break; - default: + case NPadControllerType::GameCube: + case NPadControllerType::Pokeball: break; } - - sixaxis_fullkey_state.sampling_number = - npad.sixaxis_fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1; - sixaxis_handheld_state.sampling_number = - npad.sixaxis_handheld_lifo.ReadCurrentEntry().state.sampling_number + 1; - sixaxis_dual_left_state.sampling_number = - npad.sixaxis_dual_left_lifo.ReadCurrentEntry().state.sampling_number + 1; - sixaxis_dual_right_state.sampling_number = - npad.sixaxis_dual_right_lifo.ReadCurrentEntry().state.sampling_number + 1; - sixaxis_left_lifo_state.sampling_number = - npad.sixaxis_left_lifo.ReadCurrentEntry().state.sampling_number + 1; - sixaxis_right_lifo_state.sampling_number = - npad.sixaxis_right_lifo.ReadCurrentEntry().state.sampling_number + 1; - - if (Core::HID::IndexToNpadIdType(i) == Core::HID::NpadIdType::Handheld) { - // This buffer only is updated on handheld on HW - npad.sixaxis_handheld_lifo.WriteNextEntry(sixaxis_handheld_state); - } else { - // Hanheld doesn't update this buffer on HW - npad.sixaxis_fullkey_lifo.WriteNextEntry(sixaxis_fullkey_state); - } - - npad.sixaxis_dual_left_lifo.WriteNextEntry(sixaxis_dual_left_state); - npad.sixaxis_dual_right_lifo.WriteNextEntry(sixaxis_dual_right_state); - npad.sixaxis_left_lifo.WriteNextEntry(sixaxis_left_lifo_state); - npad.sixaxis_right_lifo.WriteNextEntry(sixaxis_right_lifo_state); - std::memcpy(data + NPAD_OFFSET + (i * sizeof(NpadInternalState)), - &controller.shared_memory_entry, sizeof(NpadInternalState)); } + std::memcpy(data + NPAD_OFFSET, shared_memory_entries.data(), + shared_memory_entries.size() * sizeof(NPadEntry)); } -void Controller_NPad::SetSupportedStyleSet(Core::HID::NpadStyleTag style_set) { - hid_core.SetSupportedStyleTag(style_set); +void Controller_NPad::SetSupportedStyleSet(NpadStyleSet style_set) { + style.raw = style_set.raw; } -Core::HID::NpadStyleTag Controller_NPad::GetSupportedStyleSet() const { - return hid_core.GetSupportedStyleTag(); +Controller_NPad::NpadStyleSet Controller_NPad::GetSupportedStyleSet() const { + return style; } void Controller_NPad::SetSupportedNpadIdTypes(u8* data, std::size_t length) { @@ -666,11 +779,11 @@ std::size_t Controller_NPad::GetSupportedNpadIdTypesSize() const { return supported_npad_id_types.size(); } -void Controller_NPad::SetHoldType(NpadJoyHoldType joy_hold_type) { +void Controller_NPad::SetHoldType(NpadHoldType joy_hold_type) { hold_type = joy_hold_type; } -Controller_NPad::NpadJoyHoldType Controller_NPad::GetHoldType() const { +Controller_NPad::NpadHoldType Controller_NPad::GetHoldType() const { return hold_type; } @@ -690,35 +803,29 @@ Controller_NPad::NpadCommunicationMode Controller_NPad::GetNpadCommunicationMode return communication_mode; } -void Controller_NPad::SetNpadMode(Core::HID::NpadIdType npad_id, - NpadJoyAssignmentMode assignment_mode) { - if (!IsNpadIdValid(npad_id)) { - LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); - return; - } - - auto& controller = GetControllerFromNpadIdType(npad_id); - if (controller.shared_memory_entry.assignment_mode != assignment_mode) { - controller.shared_memory_entry.assignment_mode = assignment_mode; +void Controller_NPad::SetNpadMode(u32 npad_id, NpadAssignments assignment_mode) { + const std::size_t npad_index = NPadIdToIndex(npad_id); + ASSERT(npad_index < shared_memory_entries.size()); + if (shared_memory_entries[npad_index].assignment_mode != assignment_mode) { + shared_memory_entries[npad_index].assignment_mode = assignment_mode; } } -bool Controller_NPad::VibrateControllerAtIndex(Core::HID::NpadIdType npad_id, - std::size_t device_index, - const Core::HID::VibrationValue& vibration_value) { - auto& controller = GetControllerFromNpadIdType(npad_id); - if (!controller.device->IsConnected()) { +bool Controller_NPad::VibrateControllerAtIndex(std::size_t npad_index, std::size_t device_index, + const VibrationValue& vibration_value) { + if (!connected_controllers[npad_index].is_connected || !vibrations[npad_index][device_index]) { return false; } - if (!controller.device->IsVibrationEnabled()) { - if (controller.vibration[device_index].latest_vibration_value.low_amplitude != 0.0f || - controller.vibration[device_index].latest_vibration_value.high_amplitude != 0.0f) { + const auto& player = Settings::values.players.GetValue()[npad_index]; + + if (!player.vibration_enabled) { + if (latest_vibration_values[npad_index][device_index].amp_low != 0.0f || + latest_vibration_values[npad_index][device_index].amp_high != 0.0f) { // Send an empty vibration to stop any vibrations. - Core::HID::VibrationValue vibration{0.0f, 160.0f, 0.0f, 320.0f}; - controller.device->SetVibration(device_index, vibration); + vibrations[npad_index][device_index]->SetRumblePlay(0.0f, 160.0f, 0.0f, 320.0f); // Then reset the vibration value to its default value. - controller.vibration[device_index].latest_vibration_value = DEFAULT_VIBRATION_VALUE; + latest_vibration_values[npad_index][device_index] = DEFAULT_VIBRATION_VALUE; } return false; @@ -732,25 +839,27 @@ bool Controller_NPad::VibrateControllerAtIndex(Core::HID::NpadIdType npad_id, const auto now = steady_clock::now(); // Filter out non-zero vibrations that are within 10ms of each other. - if ((vibration_value.low_amplitude != 0.0f || vibration_value.high_amplitude != 0.0f) && - duration_cast( - now - controller.vibration[device_index].last_vibration_timepoint) < + if ((vibration_value.amp_low != 0.0f || vibration_value.amp_high != 0.0f) && + duration_cast(now - last_vibration_timepoints[npad_index][device_index]) < milliseconds(10)) { return false; } - controller.vibration[device_index].last_vibration_timepoint = now; + last_vibration_timepoints[npad_index][device_index] = now; } - Core::HID::VibrationValue vibration{ - vibration_value.low_amplitude, vibration_value.low_frequency, - vibration_value.high_amplitude, vibration_value.high_frequency}; - return controller.device->SetVibration(device_index, vibration); + auto& vibration = vibrations[npad_index][device_index]; + const auto player_vibration_strength = static_cast(player.vibration_strength); + const auto amp_low = + std::min(vibration_value.amp_low * player_vibration_strength / 100.0f, 1.0f); + const auto amp_high = + std::min(vibration_value.amp_high * player_vibration_strength / 100.0f, 1.0f); + return vibration->SetRumblePlay(amp_low, vibration_value.freq_low, amp_high, + vibration_value.freq_high); } -void Controller_NPad::VibrateController( - const Core::HID::VibrationDeviceHandle& vibration_device_handle, - const Core::HID::VibrationValue& vibration_value) { +void Controller_NPad::VibrateController(const DeviceHandle& vibration_device_handle, + const VibrationValue& vibration_value) { if (!IsDeviceHandleValid(vibration_device_handle)) { return; } @@ -759,45 +868,42 @@ void Controller_NPad::VibrateController( return; } - auto& controller = GetControllerFromHandle(vibration_device_handle); + const auto npad_index = NPadIdToIndex(vibration_device_handle.npad_id); const auto device_index = static_cast(vibration_device_handle.device_index); - if (!controller.vibration[device_index].device_mounted || !controller.device->IsConnected()) { + if (!vibration_devices_mounted[npad_index][device_index] || + !connected_controllers[npad_index].is_connected) { return; } - if (vibration_device_handle.device_index == Core::HID::DeviceIndex::None) { + if (vibration_device_handle.device_index == DeviceIndex::None) { UNREACHABLE_MSG("DeviceIndex should never be None!"); return; } // Some games try to send mismatched parameters in the device handle, block these. - if ((controller.device->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconLeft && - (vibration_device_handle.npad_type == Core::HID::NpadStyleIndex::JoyconRight || - vibration_device_handle.device_index == Core::HID::DeviceIndex::Right)) || - (controller.device->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconRight && - (vibration_device_handle.npad_type == Core::HID::NpadStyleIndex::JoyconLeft || - vibration_device_handle.device_index == Core::HID::DeviceIndex::Left))) { + if ((connected_controllers[npad_index].type == NPadControllerType::JoyLeft && + (vibration_device_handle.npad_type == NpadType::JoyconRight || + vibration_device_handle.device_index == DeviceIndex::Right)) || + (connected_controllers[npad_index].type == NPadControllerType::JoyRight && + (vibration_device_handle.npad_type == NpadType::JoyconLeft || + vibration_device_handle.device_index == DeviceIndex::Left))) { return; } // Filter out vibrations with equivalent values to reduce unnecessary state changes. - if (vibration_value.low_amplitude == - controller.vibration[device_index].latest_vibration_value.low_amplitude && - vibration_value.high_amplitude == - controller.vibration[device_index].latest_vibration_value.high_amplitude) { + if (vibration_value.amp_low == latest_vibration_values[npad_index][device_index].amp_low && + vibration_value.amp_high == latest_vibration_values[npad_index][device_index].amp_high) { return; } - if (VibrateControllerAtIndex(controller.device->GetNpadIdType(), device_index, - vibration_value)) { - controller.vibration[device_index].latest_vibration_value = vibration_value; + if (VibrateControllerAtIndex(npad_index, device_index, vibration_value)) { + latest_vibration_values[npad_index][device_index] = vibration_value; } } -void Controller_NPad::VibrateControllers( - const std::vector& vibration_device_handles, - const std::vector& vibration_values) { +void Controller_NPad::VibrateControllers(const std::vector& vibration_device_handles, + const std::vector& vibration_values) { if (!Settings::values.vibration_enabled.GetValue() && !permit_vibration_session_enabled) { return; } @@ -812,231 +918,167 @@ void Controller_NPad::VibrateControllers( } } -Core::HID::VibrationValue Controller_NPad::GetLastVibration( - const Core::HID::VibrationDeviceHandle& vibration_device_handle) const { +Controller_NPad::VibrationValue Controller_NPad::GetLastVibration( + const DeviceHandle& vibration_device_handle) const { if (!IsDeviceHandleValid(vibration_device_handle)) { return {}; } - const auto& controller = GetControllerFromHandle(vibration_device_handle); + const auto npad_index = NPadIdToIndex(vibration_device_handle.npad_id); const auto device_index = static_cast(vibration_device_handle.device_index); - return controller.vibration[device_index].latest_vibration_value; + return latest_vibration_values[npad_index][device_index]; } -void Controller_NPad::InitializeVibrationDevice( - const Core::HID::VibrationDeviceHandle& vibration_device_handle) { +void Controller_NPad::InitializeVibrationDevice(const DeviceHandle& vibration_device_handle) { if (!IsDeviceHandleValid(vibration_device_handle)) { return; } - const auto npad_index = static_cast(vibration_device_handle.npad_id); + const auto npad_index = NPadIdToIndex(vibration_device_handle.npad_id); const auto device_index = static_cast(vibration_device_handle.device_index); InitializeVibrationDeviceAtIndex(npad_index, device_index); } -void Controller_NPad::InitializeVibrationDeviceAtIndex(Core::HID::NpadIdType npad_id, +void Controller_NPad::InitializeVibrationDeviceAtIndex(std::size_t npad_index, std::size_t device_index) { - auto& controller = GetControllerFromNpadIdType(npad_id); if (!Settings::values.vibration_enabled.GetValue()) { - controller.vibration[device_index].device_mounted = false; + vibration_devices_mounted[npad_index][device_index] = false; return; } - controller.vibration[device_index].device_mounted = - controller.device->TestVibration(device_index); + if (vibrations[npad_index][device_index]) { + vibration_devices_mounted[npad_index][device_index] = + vibrations[npad_index][device_index]->GetStatus() == 1; + } else { + vibration_devices_mounted[npad_index][device_index] = false; + } } void Controller_NPad::SetPermitVibrationSession(bool permit_vibration_session) { permit_vibration_session_enabled = permit_vibration_session; } -bool Controller_NPad::IsVibrationDeviceMounted( - const Core::HID::VibrationDeviceHandle& vibration_device_handle) const { +bool Controller_NPad::IsVibrationDeviceMounted(const DeviceHandle& vibration_device_handle) const { if (!IsDeviceHandleValid(vibration_device_handle)) { return false; } - const auto& controller = GetControllerFromHandle(vibration_device_handle); + const auto npad_index = NPadIdToIndex(vibration_device_handle.npad_id); const auto device_index = static_cast(vibration_device_handle.device_index); - return controller.vibration[device_index].device_mounted; + return vibration_devices_mounted[npad_index][device_index]; } -Kernel::KReadableEvent& Controller_NPad::GetStyleSetChangedEvent(Core::HID::NpadIdType npad_id) { - if (!IsNpadIdValid(npad_id)) { - LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); - // Fallback to player 1 - const auto& controller = GetControllerFromNpadIdType(Core::HID::NpadIdType::Player1); - return controller.styleset_changed_event->GetReadableEvent(); - } - - const auto& controller = GetControllerFromNpadIdType(npad_id); - return controller.styleset_changed_event->GetReadableEvent(); +Kernel::KReadableEvent& Controller_NPad::GetStyleSetChangedEvent(u32 npad_id) { + return styleset_changed_events[NPadIdToIndex(npad_id)]->GetReadableEvent(); } -void Controller_NPad::SignalStyleSetChangedEvent(Core::HID::NpadIdType npad_id) const { - const auto& controller = GetControllerFromNpadIdType(npad_id); - controller.styleset_changed_event->GetWritableEvent().Signal(); +void Controller_NPad::SignalStyleSetChangedEvent(u32 npad_id) const { + styleset_changed_events[NPadIdToIndex(npad_id)]->GetWritableEvent().Signal(); } -void Controller_NPad::AddNewControllerAt(Core::HID::NpadStyleIndex controller, - Core::HID::NpadIdType npad_id) { - UpdateControllerAt(controller, npad_id, true); +void Controller_NPad::AddNewControllerAt(NPadControllerType controller, std::size_t npad_index) { + UpdateControllerAt(controller, npad_index, true); } -void Controller_NPad::UpdateControllerAt(Core::HID::NpadStyleIndex type, - Core::HID::NpadIdType npad_id, bool connected) { - auto& controller = GetControllerFromNpadIdType(npad_id); +void Controller_NPad::UpdateControllerAt(NPadControllerType controller, std::size_t npad_index, + bool connected) { if (!connected) { - DisconnectNpad(npad_id); + DisconnectNpadAtIndex(npad_index); return; } - controller.device->SetNpadStyleIndex(type); - InitNewlyAddedController(npad_id); + if (controller == NPadControllerType::Handheld && npad_index == HANDHELD_INDEX) { + Settings::values.players.GetValue()[HANDHELD_INDEX].controller_type = + MapNPadToSettingsType(controller); + Settings::values.players.GetValue()[HANDHELD_INDEX].connected = true; + connected_controllers[HANDHELD_INDEX] = {controller, true}; + InitNewlyAddedController(HANDHELD_INDEX); + return; + } + + Settings::values.players.GetValue()[npad_index].controller_type = + MapNPadToSettingsType(controller); + Settings::values.players.GetValue()[npad_index].connected = true; + connected_controllers[npad_index] = {controller, true}; + InitNewlyAddedController(npad_index); } -void Controller_NPad::DisconnectNpad(Core::HID::NpadIdType npad_id) { - if (!IsNpadIdValid(npad_id)) { - LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); - return; - } +void Controller_NPad::DisconnectNpad(u32 npad_id) { + DisconnectNpadAtIndex(NPadIdToIndex(npad_id)); +} - LOG_DEBUG(Service_HID, "Npad disconnected {}", npad_id); - auto& controller = GetControllerFromNpadIdType(npad_id); - for (std::size_t device_idx = 0; device_idx < controller.vibration.size(); ++device_idx) { +void Controller_NPad::DisconnectNpadAtIndex(std::size_t npad_index) { + for (std::size_t device_idx = 0; device_idx < vibrations[npad_index].size(); ++device_idx) { // Send an empty vibration to stop any vibrations. - VibrateControllerAtIndex(npad_id, device_idx, {}); - controller.vibration[device_idx].device_mounted = false; + VibrateControllerAtIndex(npad_index, device_idx, {}); + vibration_devices_mounted[npad_index][device_idx] = false; } - auto& shared_memory_entry = controller.shared_memory_entry; - shared_memory_entry.style_tag.raw = Core::HID::NpadStyleSet::None; // Zero out - shared_memory_entry.device_type.raw = 0; - shared_memory_entry.system_properties.raw = 0; - shared_memory_entry.button_properties.raw = 0; - shared_memory_entry.battery_level_dual = 0; - shared_memory_entry.battery_level_left = 0; - shared_memory_entry.battery_level_right = 0; - shared_memory_entry.fullkey_color = { - .attribute = ColorAttribute::NoController, - .fullkey = {}, + Settings::values.players.GetValue()[npad_index].connected = false; + connected_controllers[npad_index].is_connected = false; + + auto& controller = shared_memory_entries[npad_index]; + controller.style_set.raw = 0; // Zero out + controller.device_type.raw = 0; + controller.system_properties.raw = 0; + controller.button_properties.raw = 0; + controller.battery_level_dual = 0; + controller.battery_level_left = 0; + controller.battery_level_right = 0; + controller.fullkey_color = {}; + controller.joycon_color = {}; + controller.assignment_mode = NpadAssignments::Dual; + controller.footer_type = AppletFooterUiType::None; + + SignalStyleSetChangedEvent(IndexToNPad(npad_index)); +} + +void Controller_NPad::SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode drift_mode) { + gyroscope_zero_drift_mode = drift_mode; +} + +Controller_NPad::GyroscopeZeroDriftMode Controller_NPad::GetGyroscopeZeroDriftMode() const { + return gyroscope_zero_drift_mode; +} + +bool Controller_NPad::IsSixAxisSensorAtRest() const { + return sixaxis_at_rest; +} + +void Controller_NPad::SetSixAxisEnabled(bool six_axis_status) { + sixaxis_sensors_enabled = six_axis_status; +} + +void Controller_NPad::SetSixAxisFusionParameters(f32 parameter1, f32 parameter2) { + sixaxis_fusion_parameter1 = parameter1; + sixaxis_fusion_parameter2 = parameter2; +} + +std::pair Controller_NPad::GetSixAxisFusionParameters() { + return { + sixaxis_fusion_parameter1, + sixaxis_fusion_parameter2, }; - shared_memory_entry.joycon_color = { - .attribute = ColorAttribute::NoController, - .left = {}, - .right = {}, - }; - shared_memory_entry.assignment_mode = NpadJoyAssignmentMode::Dual; - shared_memory_entry.applet_footer.type = AppletFooterUiType::None; - - controller.is_connected = false; - controller.device->Disconnect(); - SignalStyleSetChangedEvent(npad_id); - WriteEmptyEntry(controller.shared_memory_entry); } -void Controller_NPad::SetGyroscopeZeroDriftMode(Core::HID::SixAxisSensorHandle sixaxis_handle, - GyroscopeZeroDriftMode drift_mode) { - if (!IsDeviceHandleValid(sixaxis_handle)) { - LOG_ERROR(Service_HID, "Invalid handle"); - return; - } - auto& controller = GetControllerFromHandle(sixaxis_handle); - controller.gyroscope_zero_drift_mode = drift_mode; +void Controller_NPad::ResetSixAxisFusionParameters() { + sixaxis_fusion_parameter1 = 0.0f; + sixaxis_fusion_parameter2 = 0.0f; } -Controller_NPad::GyroscopeZeroDriftMode Controller_NPad::GetGyroscopeZeroDriftMode( - Core::HID::SixAxisSensorHandle sixaxis_handle) const { - if (!IsDeviceHandleValid(sixaxis_handle)) { - LOG_ERROR(Service_HID, "Invalid handle"); - // Return the default value - return GyroscopeZeroDriftMode::Standard; - } - const auto& controller = GetControllerFromHandle(sixaxis_handle); - return controller.gyroscope_zero_drift_mode; -} - -bool Controller_NPad::IsSixAxisSensorAtRest(Core::HID::SixAxisSensorHandle sixaxis_handle) const { - if (!IsDeviceHandleValid(sixaxis_handle)) { - LOG_ERROR(Service_HID, "Invalid handle"); - // Return the default value - return true; - } - const auto& controller = GetControllerFromHandle(sixaxis_handle); - return controller.sixaxis_at_rest; -} - -void Controller_NPad::SetSixAxisEnabled(Core::HID::SixAxisSensorHandle sixaxis_handle, - bool sixaxis_status) { - if (!IsDeviceHandleValid(sixaxis_handle)) { - LOG_ERROR(Service_HID, "Invalid handle"); - return; - } - auto& controller = GetControllerFromHandle(sixaxis_handle); - controller.sixaxis_sensor_enabled = sixaxis_status; -} - -void Controller_NPad::SetSixAxisFusionEnabled(Core::HID::SixAxisSensorHandle sixaxis_handle, - bool sixaxis_fusion_status) { - if (!IsDeviceHandleValid(sixaxis_handle)) { - LOG_ERROR(Service_HID, "Invalid handle"); - return; - } - auto& controller = GetControllerFromHandle(sixaxis_handle); - controller.sixaxis_fusion_enabled = sixaxis_fusion_status; -} - -void Controller_NPad::SetSixAxisFusionParameters( - Core::HID::SixAxisSensorHandle sixaxis_handle, - Core::HID::SixAxisSensorFusionParameters sixaxis_fusion_parameters) { - if (!IsDeviceHandleValid(sixaxis_handle)) { - LOG_ERROR(Service_HID, "Invalid handle"); - return; - } - auto& controller = GetControllerFromHandle(sixaxis_handle); - controller.sixaxis_fusion = sixaxis_fusion_parameters; -} - -Core::HID::SixAxisSensorFusionParameters Controller_NPad::GetSixAxisFusionParameters( - Core::HID::SixAxisSensorHandle sixaxis_handle) { - if (!IsDeviceHandleValid(sixaxis_handle)) { - LOG_ERROR(Service_HID, "Invalid handle"); - // Since these parameters are unknow just return zeros - return {}; - } - auto& controller = GetControllerFromHandle(sixaxis_handle); - return controller.sixaxis_fusion; -} - -void Controller_NPad::ResetSixAxisFusionParameters(Core::HID::SixAxisSensorHandle sixaxis_handle) { - if (!IsDeviceHandleValid(sixaxis_handle)) { - LOG_ERROR(Service_HID, "Invalid handle"); - return; - } - auto& controller = GetControllerFromHandle(sixaxis_handle); - // Since these parameters are unknow just fill with zeros - controller.sixaxis_fusion = {}; -} - -void Controller_NPad::MergeSingleJoyAsDualJoy(Core::HID::NpadIdType npad_id_1, - Core::HID::NpadIdType npad_id_2) { - if (!IsNpadIdValid(npad_id_1) || !IsNpadIdValid(npad_id_2)) { - LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id_1:{}, npad_id_2:{}", npad_id_1, - npad_id_2); - return; - } - auto& controller_1 = GetControllerFromNpadIdType(npad_id_1).device; - auto& controller_2 = GetControllerFromNpadIdType(npad_id_2).device; +void Controller_NPad::MergeSingleJoyAsDualJoy(u32 npad_id_1, u32 npad_id_2) { + const auto npad_index_1 = NPadIdToIndex(npad_id_1); + const auto npad_index_2 = NPadIdToIndex(npad_id_2); // If the controllers at both npad indices form a pair of left and right joycons, merge them. // Otherwise, do nothing. - if ((controller_1->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconLeft && - controller_2->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconRight) || - (controller_2->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconLeft && - controller_1->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconRight)) { + if ((connected_controllers[npad_index_1].type == NPadControllerType::JoyLeft && + connected_controllers[npad_index_2].type == NPadControllerType::JoyRight) || + (connected_controllers[npad_index_2].type == NPadControllerType::JoyLeft && + connected_controllers[npad_index_1].type == NPadControllerType::JoyRight)) { // Disconnect the joycon at the second id and connect the dual joycon at the first index. DisconnectNpad(npad_id_2); - AddNewControllerAt(Core::HID::NpadStyleIndex::JoyconDual, npad_id_1); + AddNewControllerAt(NPadControllerType::JoyDual, npad_index_1); } } @@ -1050,61 +1092,61 @@ void Controller_NPad::StopLRAssignmentMode() { is_in_lr_assignment_mode = false; } -bool Controller_NPad::SwapNpadAssignment(Core::HID::NpadIdType npad_id_1, - Core::HID::NpadIdType npad_id_2) { - if (!IsNpadIdValid(npad_id_1) || !IsNpadIdValid(npad_id_2)) { - LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id_1:{}, npad_id_2:{}", npad_id_1, - npad_id_2); - return false; - } - if (npad_id_1 == Core::HID::NpadIdType::Handheld || - npad_id_2 == Core::HID::NpadIdType::Handheld || npad_id_1 == Core::HID::NpadIdType::Other || - npad_id_2 == Core::HID::NpadIdType::Other) { +bool Controller_NPad::SwapNpadAssignment(u32 npad_id_1, u32 npad_id_2) { + if (npad_id_1 == NPAD_HANDHELD || npad_id_2 == NPAD_HANDHELD || npad_id_1 == NPAD_UNKNOWN || + npad_id_2 == NPAD_UNKNOWN) { return true; } - const auto& controller_1 = GetControllerFromNpadIdType(npad_id_1).device; - const auto& controller_2 = GetControllerFromNpadIdType(npad_id_2).device; - const auto type_index_1 = controller_1->GetNpadStyleIndex(); - const auto type_index_2 = controller_2->GetNpadStyleIndex(); + const auto npad_index_1 = NPadIdToIndex(npad_id_1); + const auto npad_index_2 = NPadIdToIndex(npad_id_2); - if (!IsControllerSupported(type_index_1) || !IsControllerSupported(type_index_2)) { + if (!IsControllerSupported(connected_controllers[npad_index_1].type) || + !IsControllerSupported(connected_controllers[npad_index_2].type)) { return false; } - AddNewControllerAt(type_index_2, npad_id_1); - AddNewControllerAt(type_index_1, npad_id_2); + std::swap(connected_controllers[npad_index_1].type, connected_controllers[npad_index_2].type); + + AddNewControllerAt(connected_controllers[npad_index_1].type, npad_index_1); + AddNewControllerAt(connected_controllers[npad_index_2].type, npad_index_2); return true; } -Core::HID::LedPattern Controller_NPad::GetLedPattern(Core::HID::NpadIdType npad_id) { - if (!IsNpadIdValid(npad_id)) { - LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); - return Core::HID::LedPattern{0, 0, 0, 0}; +Controller_NPad::LedPattern Controller_NPad::GetLedPattern(u32 npad_id) { + if (npad_id == npad_id_list.back() || npad_id == npad_id_list[npad_id_list.size() - 2]) { + // These are controllers without led patterns + return LedPattern{0, 0, 0, 0}; + } + switch (npad_id) { + case 0: + return LedPattern{1, 0, 0, 0}; + case 1: + return LedPattern{1, 1, 0, 0}; + case 2: + return LedPattern{1, 1, 1, 0}; + case 3: + return LedPattern{1, 1, 1, 1}; + case 4: + return LedPattern{1, 0, 0, 1}; + case 5: + return LedPattern{1, 0, 1, 0}; + case 6: + return LedPattern{1, 0, 1, 1}; + case 7: + return LedPattern{0, 1, 1, 0}; + default: + return LedPattern{0, 0, 0, 0}; } - const auto& controller = GetControllerFromNpadIdType(npad_id).device; - return controller->GetLedPattern(); } -bool Controller_NPad::IsUnintendedHomeButtonInputProtectionEnabled( - Core::HID::NpadIdType npad_id) const { - if (!IsNpadIdValid(npad_id)) { - LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); - // Return the default value - return false; - } - const auto& controller = GetControllerFromNpadIdType(npad_id); - return controller.unintended_home_button_input_protection; +bool Controller_NPad::IsUnintendedHomeButtonInputProtectionEnabled(u32 npad_id) const { + return unintended_home_button_input_protection[NPadIdToIndex(npad_id)]; } void Controller_NPad::SetUnintendedHomeButtonInputProtectionEnabled(bool is_protection_enabled, - Core::HID::NpadIdType npad_id) { - if (!IsNpadIdValid(npad_id)) { - LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); - return; - } - auto& controller = GetControllerFromNpadIdType(npad_id); - controller.unintended_home_button_input_protection = is_protection_enabled; + u32 npad_id) { + unintended_home_button_input_protection[NPadIdToIndex(npad_id)] = is_protection_enabled; } void Controller_NPad::SetAnalogStickUseCenterClamp(bool use_center_clamp) { @@ -1112,34 +1154,32 @@ void Controller_NPad::SetAnalogStickUseCenterClamp(bool use_center_clamp) { } void Controller_NPad::ClearAllConnectedControllers() { - for (auto& controller : controller_data) { - if (controller.device->IsConnected() && - controller.device->GetNpadStyleIndex() != Core::HID::NpadStyleIndex::None) { - controller.device->Disconnect(); - controller.device->SetNpadStyleIndex(Core::HID::NpadStyleIndex::None); + for (auto& controller : connected_controllers) { + if (controller.is_connected && controller.type != NPadControllerType::None) { + controller.type = NPadControllerType::None; + controller.is_connected = false; } } } void Controller_NPad::DisconnectAllConnectedControllers() { - for (auto& controller : controller_data) { - controller.device->Disconnect(); + for (auto& controller : connected_controllers) { + controller.is_connected = false; } } void Controller_NPad::ConnectAllDisconnectedControllers() { - for (auto& controller : controller_data) { - if (controller.device->GetNpadStyleIndex() != Core::HID::NpadStyleIndex::None && - !controller.device->IsConnected()) { - controller.device->Connect(); + for (auto& controller : connected_controllers) { + if (controller.type != NPadControllerType::None && !controller.is_connected) { + controller.is_connected = true; } } } void Controller_NPad::ClearAllControllers() { - for (auto& controller : controller_data) { - controller.device->Disconnect(); - controller.device->SetNpadStyleIndex(Core::HID::NpadStyleIndex::None); + for (auto& controller : connected_controllers) { + controller.type = NPadControllerType::None; + controller.is_connected = false; } } @@ -1147,16 +1187,16 @@ u32 Controller_NPad::GetAndResetPressState() { return press_state.exchange(0); } -bool Controller_NPad::IsControllerSupported(Core::HID::NpadStyleIndex controller) const { - if (controller == Core::HID::NpadStyleIndex::Handheld) { +bool Controller_NPad::IsControllerSupported(NPadControllerType controller) const { + if (controller == NPadControllerType::Handheld) { const bool support_handheld = std::find(supported_npad_id_types.begin(), supported_npad_id_types.end(), - Core::HID::NpadIdType::Handheld) != supported_npad_id_types.end(); + NPAD_HANDHELD) != supported_npad_id_types.end(); // Handheld is not even a supported type, lets stop here if (!support_handheld) { return false; } - // Handheld shouldn't be supported in docked mode + // Handheld should not be supported in docked mode if (Settings::values.use_docked_mode.GetValue()) { return false; } @@ -1165,31 +1205,20 @@ bool Controller_NPad::IsControllerSupported(Core::HID::NpadStyleIndex controller } if (std::any_of(supported_npad_id_types.begin(), supported_npad_id_types.end(), - [](Core::HID::NpadIdType npad_id) { - return npad_id <= Core::HID::NpadIdType::Player8; - })) { - Core::HID::NpadStyleTag style = GetSupportedStyleSet(); + [](u32 npad_id) { return npad_id <= MAX_NPAD_ID; })) { switch (controller) { - case Core::HID::NpadStyleIndex::ProController: + case NPadControllerType::ProController: return style.fullkey; - case Core::HID::NpadStyleIndex::JoyconDual: + case NPadControllerType::JoyDual: return style.joycon_dual; - case Core::HID::NpadStyleIndex::JoyconLeft: + case NPadControllerType::JoyLeft: return style.joycon_left; - case Core::HID::NpadStyleIndex::JoyconRight: + case NPadControllerType::JoyRight: return style.joycon_right; - case Core::HID::NpadStyleIndex::GameCube: + case NPadControllerType::GameCube: return style.gamecube; - case Core::HID::NpadStyleIndex::Pokeball: + case NPadControllerType::Pokeball: return style.palma; - case Core::HID::NpadStyleIndex::NES: - return style.lark; - case Core::HID::NpadStyleIndex::SNES: - return style.lucia; - case Core::HID::NpadStyleIndex::N64: - return style.lagoon; - case Core::HID::NpadStyleIndex::SegaGenesis: - return style.lager; default: return false; } @@ -1198,48 +1227,4 @@ bool Controller_NPad::IsControllerSupported(Core::HID::NpadStyleIndex controller return false; } -Controller_NPad::NpadControllerData& Controller_NPad::GetControllerFromHandle( - const Core::HID::SixAxisSensorHandle& device_handle) { - const auto npad_id = static_cast(device_handle.npad_id); - return GetControllerFromNpadIdType(npad_id); -} - -const Controller_NPad::NpadControllerData& Controller_NPad::GetControllerFromHandle( - const Core::HID::SixAxisSensorHandle& device_handle) const { - const auto npad_id = static_cast(device_handle.npad_id); - return GetControllerFromNpadIdType(npad_id); -} - -Controller_NPad::NpadControllerData& Controller_NPad::GetControllerFromHandle( - const Core::HID::VibrationDeviceHandle& device_handle) { - const auto npad_id = static_cast(device_handle.npad_id); - return GetControllerFromNpadIdType(npad_id); -} - -const Controller_NPad::NpadControllerData& Controller_NPad::GetControllerFromHandle( - const Core::HID::VibrationDeviceHandle& device_handle) const { - const auto npad_id = static_cast(device_handle.npad_id); - return GetControllerFromNpadIdType(npad_id); -} - -Controller_NPad::NpadControllerData& Controller_NPad::GetControllerFromNpadIdType( - Core::HID::NpadIdType npad_id) { - if (!IsNpadIdValid(npad_id)) { - LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); - npad_id = Core::HID::NpadIdType::Player1; - } - const auto npad_index = Core::HID::NpadIdTypeToIndex(npad_id); - return controller_data[npad_index]; -} - -const Controller_NPad::NpadControllerData& Controller_NPad::GetControllerFromNpadIdType( - Core::HID::NpadIdType npad_id) const { - if (!IsNpadIdValid(npad_id)) { - LOG_ERROR(Service_HID, "Invalid NpadIdType npad_id:{}", npad_id); - npad_id = Core::HID::NpadIdType::Player1; - } - const auto npad_index = Core::HID::NpadIdTypeToIndex(npad_id); - return controller_data[npad_index]; -} - } // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h index 3798c037f..9ee146caf 100755 --- a/src/core/hle/service/hid/controllers/npad.h +++ b/src/core/hle/service/hid/controllers/npad.h @@ -11,14 +11,9 @@ #include "common/bit_field.h" #include "common/common_types.h" #include "common/quaternion.h" -#include "core/hid/hid_types.h" +#include "common/settings.h" +#include "core/frontend/input.h" #include "core/hle/service/hid/controllers/controller_base.h" -#include "core/hle/service/hid/ring_lifo.h" - -namespace Core::HID { -class EmulatedController; -enum class ControllerTriggerType; -} // namespace Core::HID namespace Kernel { class KEvent; @@ -31,9 +26,12 @@ class ServiceContext; namespace Service::HID { +constexpr u32 NPAD_HANDHELD = 32; +constexpr u32 NPAD_UNKNOWN = 16; // TODO(ogniK): What is this? + class Controller_NPad final : public ControllerBase { public: - explicit Controller_NPad(Core::HID::HIDCore& hid_core_, + explicit Controller_NPad(Core::System& system_, KernelHelpers::ServiceContext& service_context_); ~Controller_NPad() override; @@ -50,39 +48,60 @@ public: void OnMotionUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override; - // This is nn::hid::GyroscopeZeroDriftMode + // Called when input devices should be loaded + void OnLoadInputDevices() override; + + enum class NPadControllerType { + None, + ProController, + Handheld, + JoyDual, + JoyLeft, + JoyRight, + GameCube, + Pokeball, + }; + + enum class NpadType : u8 { + ProController = 3, + Handheld = 4, + JoyconDual = 5, + JoyconLeft = 6, + JoyconRight = 7, + GameCube = 8, + Pokeball = 9, + MaxNpadType = 10, + }; + + enum class DeviceIndex : u8 { + Left = 0, + Right = 1, + None = 2, + MaxDeviceIndex = 3, + }; + enum class GyroscopeZeroDriftMode : u32 { Loose = 0, Standard = 1, Tight = 2, }; - // This is nn::hid::NpadJoyHoldType - enum class NpadJoyHoldType : u64 { + enum class NpadHoldType : u64 { Vertical = 0, Horizontal = 1, }; - // This is nn::hid::NpadJoyAssignmentMode - enum class NpadJoyAssignmentMode : u32 { + enum class NpadAssignments : u32 { Dual = 0, Single = 1, }; - // This is nn::hid::NpadJoyDeviceType - enum class NpadJoyDeviceType : s64 { - Left = 0, - Right = 1, - }; - - // This is nn::hid::NpadHandheldActivationMode enum class NpadHandheldActivationMode : u64 { Dual = 0, Single = 1, None = 2, }; - // This is nn::hid::NpadCommunicationMode enum class NpadCommunicationMode : u64 { Mode_5ms = 0, Mode_10ms = 1, @@ -90,22 +109,74 @@ public: Default = 3, }; - static constexpr Core::HID::VibrationValue DEFAULT_VIBRATION_VALUE{ - .low_amplitude = 0.0f, - .low_frequency = 160.0f, - .high_amplitude = 0.0f, - .high_frequency = 320.0f, + struct DeviceHandle { + NpadType npad_type; + u8 npad_id; + DeviceIndex device_index; + INSERT_PADDING_BYTES_NOINIT(1); + }; + static_assert(sizeof(DeviceHandle) == 4, "DeviceHandle is an invalid size"); + + struct NpadStyleSet { + union { + u32_le raw{}; + + BitField<0, 1, u32> fullkey; + BitField<1, 1, u32> handheld; + BitField<2, 1, u32> joycon_dual; + BitField<3, 1, u32> joycon_left; + BitField<4, 1, u32> joycon_right; + BitField<5, 1, u32> gamecube; + BitField<6, 1, u32> palma; + BitField<7, 1, u32> lark; + BitField<8, 1, u32> handheld_lark; + BitField<9, 1, u32> lucia; + BitField<29, 1, u32> system_ext; + BitField<30, 1, u32> system; + }; + }; + static_assert(sizeof(NpadStyleSet) == 4, "NpadStyleSet is an invalid size"); + + struct VibrationValue { + f32 amp_low; + f32 freq_low; + f32 amp_high; + f32 freq_high; + }; + static_assert(sizeof(VibrationValue) == 0x10, "Vibration is an invalid size"); + + static constexpr VibrationValue DEFAULT_VIBRATION_VALUE{ + .amp_low = 0.0f, + .freq_low = 160.0f, + .amp_high = 0.0f, + .freq_high = 320.0f, }; - void SetSupportedStyleSet(Core::HID::NpadStyleTag style_set); - Core::HID::NpadStyleTag GetSupportedStyleSet() const; + struct LedPattern { + explicit LedPattern(u64 light1, u64 light2, u64 light3, u64 light4) { + position1.Assign(light1); + position2.Assign(light2); + position3.Assign(light3); + position4.Assign(light4); + } + union { + u64 raw{}; + BitField<0, 1, u64> position1; + BitField<1, 1, u64> position2; + BitField<2, 1, u64> position3; + BitField<3, 1, u64> position4; + }; + }; + + void SetSupportedStyleSet(NpadStyleSet style_set); + NpadStyleSet GetSupportedStyleSet() const; void SetSupportedNpadIdTypes(u8* data, std::size_t length); void GetSupportedNpadIdTypes(u32* data, std::size_t max_length); std::size_t GetSupportedNpadIdTypesSize() const; - void SetHoldType(NpadJoyHoldType joy_hold_type); - NpadJoyHoldType GetHoldType() const; + void SetHoldType(NpadHoldType joy_hold_type); + NpadHoldType GetHoldType() const; void SetNpadHandheldActivationMode(NpadHandheldActivationMode activation_mode); NpadHandheldActivationMode GetNpadHandheldActivationMode() const; @@ -113,106 +184,162 @@ public: void SetNpadCommunicationMode(NpadCommunicationMode communication_mode_); NpadCommunicationMode GetNpadCommunicationMode() const; - void SetNpadMode(Core::HID::NpadIdType npad_id, NpadJoyAssignmentMode assignment_mode); + void SetNpadMode(u32 npad_id, NpadAssignments assignment_mode); - bool VibrateControllerAtIndex(Core::HID::NpadIdType npad_id, std::size_t device_index, - const Core::HID::VibrationValue& vibration_value); + bool VibrateControllerAtIndex(std::size_t npad_index, std::size_t device_index, + const VibrationValue& vibration_value); - void VibrateController(const Core::HID::VibrationDeviceHandle& vibration_device_handle, - const Core::HID::VibrationValue& vibration_value); + void VibrateController(const DeviceHandle& vibration_device_handle, + const VibrationValue& vibration_value); - void VibrateControllers( - const std::vector& vibration_device_handles, - const std::vector& vibration_values); + void VibrateControllers(const std::vector& vibration_device_handles, + const std::vector& vibration_values); - Core::HID::VibrationValue GetLastVibration( - const Core::HID::VibrationDeviceHandle& vibration_device_handle) const; + VibrationValue GetLastVibration(const DeviceHandle& vibration_device_handle) const; - void InitializeVibrationDevice(const Core::HID::VibrationDeviceHandle& vibration_device_handle); + void InitializeVibrationDevice(const DeviceHandle& vibration_device_handle); - void InitializeVibrationDeviceAtIndex(Core::HID::NpadIdType npad_id, std::size_t device_index); + void InitializeVibrationDeviceAtIndex(std::size_t npad_index, std::size_t device_index); void SetPermitVibrationSession(bool permit_vibration_session); - bool IsVibrationDeviceMounted( - const Core::HID::VibrationDeviceHandle& vibration_device_handle) const; + bool IsVibrationDeviceMounted(const DeviceHandle& vibration_device_handle) const; - Kernel::KReadableEvent& GetStyleSetChangedEvent(Core::HID::NpadIdType npad_id); - void SignalStyleSetChangedEvent(Core::HID::NpadIdType npad_id) const; + Kernel::KReadableEvent& GetStyleSetChangedEvent(u32 npad_id); + void SignalStyleSetChangedEvent(u32 npad_id) const; // Adds a new controller at an index. - void AddNewControllerAt(Core::HID::NpadStyleIndex controller, Core::HID::NpadIdType npad_id); + void AddNewControllerAt(NPadControllerType controller, std::size_t npad_index); // Adds a new controller at an index with connection status. - void UpdateControllerAt(Core::HID::NpadStyleIndex controller, Core::HID::NpadIdType npad_id, - bool connected); + void UpdateControllerAt(NPadControllerType controller, std::size_t npad_index, bool connected); - void DisconnectNpad(Core::HID::NpadIdType npad_id); + void DisconnectNpad(u32 npad_id); + void DisconnectNpadAtIndex(std::size_t index); - void SetGyroscopeZeroDriftMode(Core::HID::SixAxisSensorHandle sixaxis_handle, - GyroscopeZeroDriftMode drift_mode); - GyroscopeZeroDriftMode GetGyroscopeZeroDriftMode( - Core::HID::SixAxisSensorHandle sixaxis_handle) const; - bool IsSixAxisSensorAtRest(Core::HID::SixAxisSensorHandle sixaxis_handle) const; - void SetSixAxisEnabled(Core::HID::SixAxisSensorHandle sixaxis_handle, bool sixaxis_status); - void SetSixAxisFusionEnabled(Core::HID::SixAxisSensorHandle sixaxis_handle, - bool sixaxis_fusion_status); - void SetSixAxisFusionParameters( - Core::HID::SixAxisSensorHandle sixaxis_handle, - Core::HID::SixAxisSensorFusionParameters sixaxis_fusion_parameters); - Core::HID::SixAxisSensorFusionParameters GetSixAxisFusionParameters( - Core::HID::SixAxisSensorHandle sixaxis_handle); - void ResetSixAxisFusionParameters(Core::HID::SixAxisSensorHandle sixaxis_handle); - Core::HID::LedPattern GetLedPattern(Core::HID::NpadIdType npad_id); - bool IsUnintendedHomeButtonInputProtectionEnabled(Core::HID::NpadIdType npad_id) const; - void SetUnintendedHomeButtonInputProtectionEnabled(bool is_protection_enabled, - Core::HID::NpadIdType npad_id); + void SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode drift_mode); + GyroscopeZeroDriftMode GetGyroscopeZeroDriftMode() const; + bool IsSixAxisSensorAtRest() const; + void SetSixAxisEnabled(bool six_axis_status); + void SetSixAxisFusionParameters(f32 parameter1, f32 parameter2); + std::pair GetSixAxisFusionParameters(); + void ResetSixAxisFusionParameters(); + LedPattern GetLedPattern(u32 npad_id); + bool IsUnintendedHomeButtonInputProtectionEnabled(u32 npad_id) const; + void SetUnintendedHomeButtonInputProtectionEnabled(bool is_protection_enabled, u32 npad_id); void SetAnalogStickUseCenterClamp(bool use_center_clamp); void ClearAllConnectedControllers(); void DisconnectAllConnectedControllers(); void ConnectAllDisconnectedControllers(); void ClearAllControllers(); - void MergeSingleJoyAsDualJoy(Core::HID::NpadIdType npad_id_1, Core::HID::NpadIdType npad_id_2); + void MergeSingleJoyAsDualJoy(u32 npad_id_1, u32 npad_id_2); void StartLRAssignmentMode(); void StopLRAssignmentMode(); - bool SwapNpadAssignment(Core::HID::NpadIdType npad_id_1, Core::HID::NpadIdType npad_id_2); + bool SwapNpadAssignment(u32 npad_id_1, u32 npad_id_2); // Logical OR for all buttons presses on all controllers // Specifically for cheat engine and other features. u32 GetAndResetPressState(); - static bool IsNpadIdValid(Core::HID::NpadIdType npad_id); - static bool IsDeviceHandleValid(const Core::HID::SixAxisSensorHandle& device_handle); - static bool IsDeviceHandleValid(const Core::HID::VibrationDeviceHandle& device_handle); + static Controller_NPad::NPadControllerType MapSettingsTypeToNPad(Settings::ControllerType type); + static Settings::ControllerType MapNPadToSettingsType(Controller_NPad::NPadControllerType type); + static std::size_t NPadIdToIndex(u32 npad_id); + static u32 IndexToNPad(std::size_t index); + static bool IsNpadIdValid(u32 npad_id); + static bool IsDeviceHandleValid(const DeviceHandle& device_handle); private: - // This is nn::hid::detail::ColorAttribute - enum class ColorAttribute : u32 { + struct CommonHeader { + s64_le timestamp; + s64_le total_entry_count; + s64_le last_entry_index; + s64_le entry_count; + }; + static_assert(sizeof(CommonHeader) == 0x20, "CommonHeader is an invalid size"); + + enum class ColorAttributes : u32_le { Ok = 0, ReadError = 1, NoController = 2, }; - static_assert(sizeof(ColorAttribute) == 4, "ColorAttribute is an invalid size"); + static_assert(sizeof(ColorAttributes) == 4, "ColorAttributes is an invalid size"); - // This is nn::hid::detail::NpadFullKeyColorState - struct NpadFullKeyColorState { - ColorAttribute attribute; - Core::HID::NpadControllerColor fullkey; + struct ControllerColor { + u32_le body; + u32_le button; }; - static_assert(sizeof(NpadFullKeyColorState) == 0xC, "NpadFullKeyColorState is an invalid size"); + static_assert(sizeof(ControllerColor) == 8, "ControllerColor is an invalid size"); - // This is nn::hid::detail::NpadJoyColorState - struct NpadJoyColorState { - ColorAttribute attribute; - Core::HID::NpadControllerColor left; - Core::HID::NpadControllerColor right; + struct FullKeyColor { + ColorAttributes attribute; + ControllerColor fullkey; }; - static_assert(sizeof(NpadJoyColorState) == 0x14, "NpadJoyColorState is an invalid size"); + static_assert(sizeof(FullKeyColor) == 0xC, "FullKeyColor is an invalid size"); - // This is nn::hid::NpadAttribute - struct NpadAttribute { + struct JoyconColor { + ColorAttributes attribute; + ControllerColor left; + ControllerColor right; + }; + static_assert(sizeof(JoyconColor) == 0x14, "JoyconColor is an invalid size"); + + struct ControllerPadState { union { - u32 raw{}; + u64_le raw{}; + // Button states + BitField<0, 1, u64> a; + BitField<1, 1, u64> b; + BitField<2, 1, u64> x; + BitField<3, 1, u64> y; + BitField<4, 1, u64> l_stick; + BitField<5, 1, u64> r_stick; + BitField<6, 1, u64> l; + BitField<7, 1, u64> r; + BitField<8, 1, u64> zl; + BitField<9, 1, u64> zr; + BitField<10, 1, u64> plus; + BitField<11, 1, u64> minus; + + // D-Pad + BitField<12, 1, u64> d_left; + BitField<13, 1, u64> d_up; + BitField<14, 1, u64> d_right; + BitField<15, 1, u64> d_down; + + // Left JoyStick + BitField<16, 1, u64> l_stick_left; + BitField<17, 1, u64> l_stick_up; + BitField<18, 1, u64> l_stick_right; + BitField<19, 1, u64> l_stick_down; + + // Right JoyStick + BitField<20, 1, u64> r_stick_left; + BitField<21, 1, u64> r_stick_up; + BitField<22, 1, u64> r_stick_right; + BitField<23, 1, u64> r_stick_down; + + // Not always active? + BitField<24, 1, u64> left_sl; + BitField<25, 1, u64> left_sr; + + BitField<26, 1, u64> right_sl; + BitField<27, 1, u64> right_sr; + + BitField<28, 1, u64> palma; + BitField<30, 1, u64> handheld_left_b; + }; + }; + static_assert(sizeof(ControllerPadState) == 8, "ControllerPadState is an invalid size"); + + struct AnalogPosition { + s32_le x; + s32_le y; + }; + static_assert(sizeof(AnalogPosition) == 8, "AnalogPosition is an invalid size"); + + struct ConnectionState { + union { + u32_le raw{}; BitField<0, 1, u32> is_connected; BitField<1, 1, u32> is_wired; BitField<2, 1, u32> is_left_connected; @@ -221,60 +348,79 @@ private: BitField<5, 1, u32> is_right_wired; }; }; - static_assert(sizeof(NpadAttribute) == 4, "NpadAttribute is an invalid size"); + static_assert(sizeof(ConnectionState) == 4, "ConnectionState is an invalid size"); - // This is nn::hid::NpadFullKeyState - // This is nn::hid::NpadHandheldState - // This is nn::hid::NpadJoyDualState - // This is nn::hid::NpadJoyLeftState - // This is nn::hid::NpadJoyRightState - // This is nn::hid::NpadPalmaState - // This is nn::hid::NpadSystemExtState - struct NPadGenericState { - s64_le sampling_number; - Core::HID::NpadButtonState npad_buttons; - Core::HID::AnalogStickState l_stick; - Core::HID::AnalogStickState r_stick; - NpadAttribute connection_status; - INSERT_PADDING_BYTES(4); // Reserved + struct ControllerPad { + ControllerPadState pad_states; + AnalogPosition l_stick; + AnalogPosition r_stick; }; - static_assert(sizeof(NPadGenericState) == 0x28, "NPadGenericState is an invalid size"); + static_assert(sizeof(ControllerPad) == 0x18, "ControllerPad is an invalid size"); - // This is nn::hid::SixAxisSensorAttribute - struct SixAxisSensorAttribute { + struct GenericStates { + s64_le timestamp; + s64_le timestamp2; + ControllerPad pad; + ConnectionState connection_status; + }; + static_assert(sizeof(GenericStates) == 0x30, "NPadGenericStates is an invalid size"); + + struct NPadGeneric { + CommonHeader common; + std::array npad; + }; + static_assert(sizeof(NPadGeneric) == 0x350, "NPadGeneric is an invalid size"); + + struct SixAxisAttributes { union { - u32 raw{}; + u32_le raw{}; BitField<0, 1, u32> is_connected; BitField<1, 1, u32> is_interpolated; }; }; - static_assert(sizeof(SixAxisSensorAttribute) == 4, "SixAxisSensorAttribute is an invalid size"); + static_assert(sizeof(SixAxisAttributes) == 4, "SixAxisAttributes is an invalid size"); - // This is nn::hid::SixAxisSensorState - struct SixAxisSensorState { - s64 delta_time{}; - s64 sampling_number{}; + struct SixAxisStates { + s64_le timestamp{}; + INSERT_PADDING_WORDS(2); + s64_le timestamp2{}; Common::Vec3f accel{}; Common::Vec3f gyro{}; Common::Vec3f rotation{}; std::array orientation{}; - SixAxisSensorAttribute attribute; + SixAxisAttributes attribute; INSERT_PADDING_BYTES(4); // Reserved }; - static_assert(sizeof(SixAxisSensorState) == 0x60, "SixAxisSensorState is an invalid size"); + static_assert(sizeof(SixAxisStates) == 0x68, "SixAxisStates is an invalid size"); - // This is nn::hid::server::NpadGcTriggerState - struct NpadGcTriggerState { - s64 sampling_number{}; - s32 l_analog{}; - s32 r_analog{}; + struct SixAxisGeneric { + CommonHeader common{}; + std::array sixaxis{}; }; - static_assert(sizeof(NpadGcTriggerState) == 0x10, "NpadGcTriggerState is an invalid size"); + static_assert(sizeof(SixAxisGeneric) == 0x708, "SixAxisGeneric is an invalid size"); + + struct TriggerState { + s64_le timestamp{}; + s64_le timestamp2{}; + s32_le l_analog{}; + s32_le r_analog{}; + }; + static_assert(sizeof(TriggerState) == 0x18, "TriggerState is an invalid size"); + + struct TriggerGeneric { + INSERT_PADDING_BYTES(0x4); + s64_le timestamp; + INSERT_PADDING_BYTES(0x4); + s64_le total_entry_count; + s64_le last_entry_index; + s64_le entry_count; + std::array trigger{}; + }; + static_assert(sizeof(TriggerGeneric) == 0x1C8, "TriggerGeneric is an invalid size"); - // This is nn::hid::NpadSystemProperties struct NPadSystemProperties { union { - s64 raw{}; + s64_le raw{}; BitField<0, 1, s64> is_charging_joy_dual; BitField<1, 1, s64> is_charging_joy_left; BitField<2, 1, s64> is_charging_joy_right; @@ -292,20 +438,17 @@ private: }; static_assert(sizeof(NPadSystemProperties) == 0x8, "NPadSystemProperties is an invalid size"); - // This is nn::hid::NpadSystemButtonProperties - struct NpadSystemButtonProperties { + struct NPadButtonProperties { union { - s32 raw{}; + s32_le raw{}; BitField<0, 1, s32> is_home_button_protection_enabled; }; }; - static_assert(sizeof(NpadSystemButtonProperties) == 0x4, - "NPadButtonProperties is an invalid size"); + static_assert(sizeof(NPadButtonProperties) == 0x4, "NPadButtonProperties is an invalid size"); - // This is nn::hid::system::DeviceType - struct DeviceType { + struct NPadDevice { union { - u32 raw{}; + u32_le raw{}; BitField<0, 1, s32> fullkey; BitField<1, 1, s32> debug_pad; BitField<2, 1, s32> handheld_left; @@ -322,49 +465,26 @@ private: BitField<13, 1, s32> handheld_lark_nes_left; BitField<14, 1, s32> handheld_lark_nes_right; BitField<15, 1, s32> lucia; - BitField<16, 1, s32> lagon; - BitField<17, 1, s32> lager; BitField<31, 1, s32> system; }; }; - // This is nn::hid::detail::NfcXcdDeviceHandleStateImpl - struct NfcXcdDeviceHandleStateImpl { - u64 handle; - bool is_available; - bool is_activated; - INSERT_PADDING_BYTES(0x6); // Reserved - u64 sampling_number; + struct MotionDevice { + Common::Vec3f accel; + Common::Vec3f gyro; + Common::Vec3f rotation; + std::array orientation; + Common::Quaternion quaternion; }; - static_assert(sizeof(NfcXcdDeviceHandleStateImpl) == 0x18, - "NfcXcdDeviceHandleStateImpl is an invalid size"); - // nn::hid::detail::NfcXcdDeviceHandleStateImplAtomicStorage - struct NfcXcdDeviceHandleStateImplAtomicStorage { - u64 sampling_number; - NfcXcdDeviceHandleStateImpl nfc_xcd_device_handle_state; + struct NfcXcdHandle { + INSERT_PADDING_BYTES(0x60); }; - static_assert(sizeof(NfcXcdDeviceHandleStateImplAtomicStorage) == 0x20, - "NfcXcdDeviceHandleStateImplAtomicStorage is an invalid size"); - // This is nn::hid::detail::NfcXcdDeviceHandleState - struct NfcXcdDeviceHandleState { - // TODO(german77): Make this struct a ring lifo object - INSERT_PADDING_BYTES(0x8); // Unused - s64 total_buffer_count = max_buffer_size; - s64 buffer_tail{}; - s64 buffer_count{}; - std::array nfc_xcd_device_handle_storage; - }; - static_assert(sizeof(NfcXcdDeviceHandleState) == 0x60, - "NfcXcdDeviceHandleState is an invalid size"); - - // This is nn::hid::system::AppletFooterUiAttributesSet struct AppletFooterUiAttributes { INSERT_PADDING_BYTES(0x4); }; - // This is nn::hid::system::AppletFooterUiType enum class AppletFooterUiType : u8 { None = 0, HandheldNone = 1, @@ -390,150 +510,95 @@ private: Lagon = 21, }; - struct AppletFooterUi { - AppletFooterUiAttributes attributes; - AppletFooterUiType type; - INSERT_PADDING_BYTES(0x5B); // Reserved - }; - static_assert(sizeof(AppletFooterUi) == 0x60, "AppletFooterUi is an invalid size"); + struct NPadEntry { + NpadStyleSet style_set; + NpadAssignments assignment_mode; + FullKeyColor fullkey_color; + JoyconColor joycon_color; - // This is nn::hid::NpadLarkType - enum class NpadLarkType : u32 { - Invalid, - H1, - H2, - NL, - NR, - }; - - // This is nn::hid::NpadLuciaType - enum class NpadLuciaType : u32 { - Invalid, - J, - E, - U, - }; - - // This is nn::hid::NpadLagonType - enum class NpadLagonType : u32 { - Invalid, - }; - - // This is nn::hid::NpadLagerType - enum class NpadLagerType : u32 { - Invalid, - J, - E, - U, - }; - - // This is nn::hid::detail::NpadInternalState - struct NpadInternalState { - Core::HID::NpadStyleTag style_tag; - NpadJoyAssignmentMode assignment_mode; - NpadFullKeyColorState fullkey_color; - NpadJoyColorState joycon_color; - Lifo fullkey_lifo; - Lifo handheld_lifo; - Lifo joy_dual_lifo; - Lifo joy_left_lifo; - Lifo joy_right_lifo; - Lifo palma_lifo; - Lifo system_ext_lifo; - Lifo sixaxis_fullkey_lifo; - Lifo sixaxis_handheld_lifo; - Lifo sixaxis_dual_left_lifo; - Lifo sixaxis_dual_right_lifo; - Lifo sixaxis_left_lifo; - Lifo sixaxis_right_lifo; - DeviceType device_type; - INSERT_PADDING_BYTES(0x4); // Reserved + NPadGeneric fullkey_states; + NPadGeneric handheld_states; + NPadGeneric joy_dual_states; + NPadGeneric joy_left_states; + NPadGeneric joy_right_states; + NPadGeneric palma_states; + NPadGeneric system_ext_states; + SixAxisGeneric sixaxis_fullkey; + SixAxisGeneric sixaxis_handheld; + SixAxisGeneric sixaxis_dual_left; + SixAxisGeneric sixaxis_dual_right; + SixAxisGeneric sixaxis_left; + SixAxisGeneric sixaxis_right; + NPadDevice device_type; + INSERT_PADDING_BYTES(0x4); // reserved NPadSystemProperties system_properties; - NpadSystemButtonProperties button_properties; - Core::HID::BatteryLevel battery_level_dual; - Core::HID::BatteryLevel battery_level_left; - Core::HID::BatteryLevel battery_level_right; - union { - NfcXcdDeviceHandleState nfc_xcd_device_handle; - AppletFooterUi applet_footer; - }; - INSERT_PADDING_BYTES(0x20); // Unknown - Lifo gc_trigger_lifo; - NpadLarkType lark_type_l_and_main; - NpadLarkType lark_type_r; - NpadLuciaType lucia_type; - NpadLagonType lagon_type; - NpadLagerType lager_type; - // FW 13.x Investigate there is some sort of bitflag related to joycons - INSERT_PADDING_BYTES(0x4); - INSERT_PADDING_BYTES(0xc08); // Unknown + NPadButtonProperties button_properties; + u32 battery_level_dual; + u32 battery_level_left; + u32 battery_level_right; + AppletFooterUiAttributes footer_attributes; + AppletFooterUiType footer_type; + // nfc_states needs to be checked switchbrew does not match with HW + NfcXcdHandle nfc_states; + INSERT_PADDING_BYTES(0x8); // Mutex + TriggerGeneric gc_trigger_states; + INSERT_PADDING_BYTES(0xc1f); }; - static_assert(sizeof(NpadInternalState) == 0x5000, "NpadInternalState is an invalid size"); + static_assert(sizeof(NPadEntry) == 0x5000, "NPadEntry is an invalid size"); - struct VibrationData { - bool device_mounted{}; - Core::HID::VibrationValue latest_vibration_value{}; - std::chrono::steady_clock::time_point last_vibration_timepoint{}; + struct ControllerHolder { + NPadControllerType type; + bool is_connected; }; - struct NpadControllerData { - Core::HID::EmulatedController* device; - Kernel::KEvent* styleset_changed_event{}; - NpadInternalState shared_memory_entry{}; - - std::array vibration{}; - bool unintended_home_button_input_protection{}; - bool is_connected{}; - Core::HID::NpadStyleIndex npad_type{Core::HID::NpadStyleIndex::None}; - - // Motion parameters - bool sixaxis_at_rest{true}; - bool sixaxis_sensor_enabled{true}; - bool sixaxis_fusion_enabled{false}; - Core::HID::SixAxisSensorFusionParameters sixaxis_fusion{}; - GyroscopeZeroDriftMode gyroscope_zero_drift_mode{GyroscopeZeroDriftMode::Standard}; - - // Current pad state - NPadGenericState npad_pad_state{}; - NPadGenericState npad_libnx_state{}; - NpadGcTriggerState npad_trigger_state{}; - SixAxisSensorState sixaxis_fullkey_state{}; - SixAxisSensorState sixaxis_handheld_state{}; - SixAxisSensorState sixaxis_dual_left_state{}; - SixAxisSensorState sixaxis_dual_right_state{}; - SixAxisSensorState sixaxis_left_lifo_state{}; - SixAxisSensorState sixaxis_right_lifo_state{}; - int callback_key; - }; - - void ControllerUpdate(Core::HID::ControllerTriggerType type, std::size_t controller_idx); - void InitNewlyAddedController(Core::HID::NpadIdType npad_id); - bool IsControllerSupported(Core::HID::NpadStyleIndex controller) const; - void RequestPadStateUpdate(Core::HID::NpadIdType npad_id); - void WriteEmptyEntry(NpadInternalState& npad); - - NpadControllerData& GetControllerFromHandle( - const Core::HID::SixAxisSensorHandle& device_handle); - const NpadControllerData& GetControllerFromHandle( - const Core::HID::SixAxisSensorHandle& device_handle) const; - NpadControllerData& GetControllerFromHandle( - const Core::HID::VibrationDeviceHandle& device_handle); - const NpadControllerData& GetControllerFromHandle( - const Core::HID::VibrationDeviceHandle& device_handle) const; - NpadControllerData& GetControllerFromNpadIdType(Core::HID::NpadIdType npad_id); - const NpadControllerData& GetControllerFromNpadIdType(Core::HID::NpadIdType npad_id) const; + void InitNewlyAddedController(std::size_t controller_idx); + bool IsControllerSupported(NPadControllerType controller) const; + void RequestPadStateUpdate(u32 npad_id); std::atomic press_state{}; - std::array controller_data{}; + NpadStyleSet style{}; + std::array shared_memory_entries{}; + using ButtonArray = std::array< + std::array, Settings::NativeButton::NUM_BUTTONS_HID>, + 10>; + using StickArray = std::array< + std::array, Settings::NativeAnalog::NUM_STICKS_HID>, + 10>; + using VibrationArray = std::array, + Settings::NativeVibration::NUM_VIBRATIONS_HID>, + 10>; + using MotionArray = std::array< + std::array, Settings::NativeMotion::NUM_MOTIONS_HID>, + 10>; + KernelHelpers::ServiceContext& service_context; std::mutex mutex; - std::vector supported_npad_id_types{}; - NpadJoyHoldType hold_type{NpadJoyHoldType::Vertical}; + ButtonArray buttons; + StickArray sticks; + VibrationArray vibrations; + MotionArray motions; + std::vector supported_npad_id_types{}; + NpadHoldType hold_type{NpadHoldType::Vertical}; NpadHandheldActivationMode handheld_activation_mode{NpadHandheldActivationMode::Dual}; NpadCommunicationMode communication_mode{NpadCommunicationMode::Default}; + // Each controller should have their own styleset changed event + std::array styleset_changed_events{}; + std::array, 10> + last_vibration_timepoints{}; + std::array, 10> latest_vibration_values{}; bool permit_vibration_session_enabled{false}; + std::array, 10> vibration_devices_mounted{}; + std::array connected_controllers{}; + std::array unintended_home_button_input_protection{}; bool analog_stick_use_center_clamp{}; + GyroscopeZeroDriftMode gyroscope_zero_drift_mode{GyroscopeZeroDriftMode::Standard}; + bool sixaxis_sensors_enabled{true}; + f32 sixaxis_fusion_parameter1{}; + f32 sixaxis_fusion_parameter2{}; + bool sixaxis_at_rest{true}; + std::array npad_pad_states{}; + std::array npad_trigger_states{}; bool is_in_lr_assignment_mode{false}; }; } // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/stubbed.cpp b/src/core/hle/service/hid/controllers/stubbed.cpp index b7d7a5756..772c20453 100755 --- a/src/core/hle/service/hid/controllers/stubbed.cpp +++ b/src/core/hle/service/hid/controllers/stubbed.cpp @@ -5,12 +5,11 @@ #include #include "common/common_types.h" #include "core/core_timing.h" -#include "core/hid/hid_core.h" #include "core/hle/service/hid/controllers/stubbed.h" namespace Service::HID { -Controller_Stubbed::Controller_Stubbed(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} {} +Controller_Stubbed::Controller_Stubbed(Core::System& system_) : ControllerBase{system_} {} Controller_Stubbed::~Controller_Stubbed() = default; void Controller_Stubbed::OnInit() {} @@ -32,9 +31,10 @@ void Controller_Stubbed::OnUpdate(const Core::Timing::CoreTiming& core_timing, u std::memcpy(data + common_offset, &header, sizeof(CommonHeader)); } +void Controller_Stubbed::OnLoadInputDevices() {} + void Controller_Stubbed::SetCommonHeaderOffset(std::size_t off) { common_offset = off; smart_update = true; } - } // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/stubbed.h b/src/core/hle/service/hid/controllers/stubbed.h index 0044a4efa..21092af0d 100755 --- a/src/core/hle/service/hid/controllers/stubbed.h +++ b/src/core/hle/service/hid/controllers/stubbed.h @@ -10,7 +10,7 @@ namespace Service::HID { class Controller_Stubbed final : public ControllerBase { public: - explicit Controller_Stubbed(Core::HID::HIDCore& hid_core_); + explicit Controller_Stubbed(Core::System& system_); ~Controller_Stubbed() override; // Called when the controller is initialized @@ -22,17 +22,12 @@ public: // When the controller is requesting an update for the shared memory void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override; + // Called when input devices should be loaded + void OnLoadInputDevices() override; + void SetCommonHeaderOffset(std::size_t off); private: - struct CommonHeader { - s64 timestamp; - s64 total_entry_count; - s64 last_entry_index; - s64 entry_count; - }; - static_assert(sizeof(CommonHeader) == 0x20, "CommonHeader is an invalid size"); - bool smart_update{}; std::size_t common_offset{}; }; diff --git a/src/core/hle/service/hid/controllers/touchscreen.cpp b/src/core/hle/service/hid/controllers/touchscreen.cpp index 48978e5c6..6ef17acc5 100755 --- a/src/core/hle/service/hid/controllers/touchscreen.cpp +++ b/src/core/hle/service/hid/controllers/touchscreen.cpp @@ -7,82 +7,72 @@ #include "common/common_types.h" #include "common/logging/log.h" #include "common/settings.h" -#include "core/core.h" #include "core/core_timing.h" #include "core/frontend/emu_window.h" -#include "core/hid/emulated_console.h" -#include "core/hid/hid_core.h" +#include "core/frontend/input.h" #include "core/hle/service/hid/controllers/touchscreen.h" namespace Service::HID { constexpr std::size_t SHARED_MEMORY_OFFSET = 0x400; -Controller_Touchscreen::Controller_Touchscreen(Core::HID::HIDCore& hid_core_) - : ControllerBase{hid_core_} { - console = hid_core.GetEmulatedConsole(); -} - +Controller_Touchscreen::Controller_Touchscreen(Core::System& system_) : ControllerBase{system_} {} Controller_Touchscreen::~Controller_Touchscreen() = default; -void Controller_Touchscreen::OnInit() {} +void Controller_Touchscreen::OnInit() { + for (std::size_t id = 0; id < MAX_FINGERS; ++id) { + mouse_finger_id[id] = MAX_FINGERS; + keyboard_finger_id[id] = MAX_FINGERS; + udp_finger_id[id] = MAX_FINGERS; + } +} void Controller_Touchscreen::OnRelease() {} void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) { - touch_screen_lifo.timestamp = core_timing.GetCPUTicks(); + shared_memory.header.timestamp = core_timing.GetCPUTicks(); + shared_memory.header.total_entry_count = 17; if (!IsControllerActivated()) { - touch_screen_lifo.buffer_count = 0; - touch_screen_lifo.buffer_tail = 0; - std::memcpy(data, &touch_screen_lifo, sizeof(touch_screen_lifo)); + shared_memory.header.entry_count = 0; + shared_memory.header.last_entry_index = 0; return; } + shared_memory.header.entry_count = 16; - const auto touch_status = console->GetTouch(); - for (std::size_t id = 0; id < MAX_FINGERS; id++) { - const auto& current_touch = touch_status[id]; - auto& finger = fingers[id]; - finger.position = current_touch.position; - finger.id = current_touch.id; + const auto& last_entry = + shared_memory.shared_memory_entries[shared_memory.header.last_entry_index]; + shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17; + auto& cur_entry = shared_memory.shared_memory_entries[shared_memory.header.last_entry_index]; - if (finger.attribute.start_touch) { - finger.attribute.raw = 0; - continue; - } + cur_entry.sampling_number = last_entry.sampling_number + 1; + cur_entry.sampling_number2 = cur_entry.sampling_number; - if (finger.attribute.end_touch) { - finger.attribute.raw = 0; - finger.pressed = false; - continue; - } + const Input::TouchStatus& mouse_status = touch_mouse_device->GetStatus(); + const Input::TouchStatus& udp_status = touch_udp_device->GetStatus(); + for (std::size_t id = 0; id < mouse_status.size(); ++id) { + mouse_finger_id[id] = UpdateTouchInputEvent(mouse_status[id], mouse_finger_id[id]); + udp_finger_id[id] = UpdateTouchInputEvent(udp_status[id], udp_finger_id[id]); + } - if (!finger.pressed && current_touch.pressed) { - finger.attribute.start_touch.Assign(1); - finger.pressed = true; - continue; - } - - if (finger.pressed && !current_touch.pressed) { - finger.attribute.raw = 0; - finger.attribute.end_touch.Assign(1); + if (Settings::values.use_touch_from_button) { + const Input::TouchStatus& keyboard_status = touch_btn_device->GetStatus(); + for (std::size_t id = 0; id < mouse_status.size(); ++id) { + keyboard_finger_id[id] = + UpdateTouchInputEvent(keyboard_status[id], keyboard_finger_id[id]); } } - std::array active_fingers; + std::array active_fingers; const auto end_iter = std::copy_if(fingers.begin(), fingers.end(), active_fingers.begin(), [](const auto& finger) { return finger.pressed; }); const auto active_fingers_count = static_cast(std::distance(active_fingers.begin(), end_iter)); const u64 tick = core_timing.GetCPUTicks(); - const auto& last_entry = touch_screen_lifo.ReadCurrentEntry().state; - - next_state.sampling_number = last_entry.sampling_number + 1; - next_state.entry_count = static_cast(active_fingers_count); - + cur_entry.entry_count = static_cast(active_fingers_count); for (std::size_t id = 0; id < MAX_FINGERS; ++id) { - auto& touch_entry = next_state.states[id]; + auto& touch_entry = cur_entry.states[id]; if (id < active_fingers_count) { const auto& [active_x, active_y] = active_fingers[id].position; touch_entry.position = { @@ -107,9 +97,66 @@ void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timin touch_entry.finger = 0; } } + std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(TouchScreenSharedMemory)); +} - touch_screen_lifo.WriteNextEntry(next_state); - std::memcpy(data + SHARED_MEMORY_OFFSET, &touch_screen_lifo, sizeof(touch_screen_lifo)); +void Controller_Touchscreen::OnLoadInputDevices() { + touch_mouse_device = Input::CreateDevice("engine:emu_window"); + touch_udp_device = Input::CreateDevice("engine:cemuhookudp"); + touch_btn_device = Input::CreateDevice("engine:touch_from_button"); +} + +std::optional Controller_Touchscreen::GetUnusedFingerID() const { + // Dont assign any touch input to a finger if disabled + if (!Settings::values.touchscreen.enabled) { + return std::nullopt; + } + std::size_t first_free_id = 0; + while (first_free_id < MAX_FINGERS) { + if (!fingers[first_free_id].pressed) { + return first_free_id; + } else { + first_free_id++; + } + } + return std::nullopt; +} + +std::size_t Controller_Touchscreen::UpdateTouchInputEvent( + const std::tuple& touch_input, std::size_t finger_id) { + const auto& [x, y, pressed] = touch_input; + if (finger_id > MAX_FINGERS) { + LOG_ERROR(Service_HID, "Invalid finger id {}", finger_id); + return MAX_FINGERS; + } + if (pressed) { + Attributes attribute{}; + if (finger_id == MAX_FINGERS) { + const auto first_free_id = GetUnusedFingerID(); + if (!first_free_id) { + // Invalid finger id do nothing + return MAX_FINGERS; + } + finger_id = first_free_id.value(); + fingers[finger_id].pressed = true; + fingers[finger_id].id = static_cast(finger_id); + attribute.start_touch.Assign(1); + } + fingers[finger_id].position = {x, y}; + fingers[finger_id].attribute = attribute; + return finger_id; + } + + if (finger_id != MAX_FINGERS) { + if (!fingers[finger_id].attribute.end_touch) { + fingers[finger_id].attribute.end_touch.Assign(1); + fingers[finger_id].attribute.start_touch.Assign(0); + return finger_id; + } + fingers[finger_id].pressed = false; + } + + return MAX_FINGERS; } } // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/touchscreen.h b/src/core/hle/service/hid/controllers/touchscreen.h index 135c2bf13..8e9b40c0a 100755 --- a/src/core/hle/service/hid/controllers/touchscreen.h +++ b/src/core/hle/service/hid/controllers/touchscreen.h @@ -9,25 +9,18 @@ #include "common/common_types.h" #include "common/point.h" #include "common/swap.h" -#include "core/hid/hid_types.h" +#include "core/frontend/input.h" #include "core/hle/service/hid/controllers/controller_base.h" -#include "core/hle/service/hid/ring_lifo.h" - -namespace Core::HID { -class EmulatedConsole; -} // namespace Core::HID namespace Service::HID { class Controller_Touchscreen final : public ControllerBase { public: - // This is nn::hid::TouchScreenModeForNx enum class TouchScreenModeForNx : u8 { UseSystemSetting, Finger, Heat2, }; - // This is nn::hid::TouchScreenConfigurationForNx struct TouchScreenConfigurationForNx { TouchScreenModeForNx mode; INSERT_PADDING_BYTES_NOINIT(0x7); @@ -36,7 +29,7 @@ public: static_assert(sizeof(TouchScreenConfigurationForNx) == 0x17, "TouchScreenConfigurationForNx is an invalid size"); - explicit Controller_Touchscreen(Core::HID::HIDCore& hid_core_); + explicit Controller_Touchscreen(Core::System& system_); ~Controller_Touchscreen() override; // Called when the controller is initialized @@ -48,24 +41,73 @@ public: // When the controller is requesting an update for the shared memory void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override; + // Called when input devices should be loaded + void OnLoadInputDevices() override; + private: static constexpr std::size_t MAX_FINGERS = 16; - // This is nn::hid::TouchScreenState - struct TouchScreenState { - s64 sampling_number; - s32 entry_count; - INSERT_PADDING_BYTES(4); // Reserved - std::array states; + // Returns an unused finger id, if there is no fingers available std::nullopt will be returned + std::optional GetUnusedFingerID() const; + + // If the touch is new it tries to assing a new finger id, if there is no fingers avaliable no + // changes will be made. Updates the coordinates if the finger id it's already set. If the touch + // ends delays the output by one frame to set the end_touch flag before finally freeing the + // finger id + std::size_t UpdateTouchInputEvent(const std::tuple& touch_input, + std::size_t finger_id); + + struct Attributes { + union { + u32 raw{}; + BitField<0, 1, u32> start_touch; + BitField<1, 1, u32> end_touch; + }; }; - static_assert(sizeof(TouchScreenState) == 0x290, "TouchScreenState is an invalid size"); + static_assert(sizeof(Attributes) == 0x4, "Attributes is an invalid size"); - // This is nn::hid::detail::TouchScreenLifo - Lifo touch_screen_lifo{}; - static_assert(sizeof(touch_screen_lifo) == 0x2C38, "touch_screen_lifo is an invalid size"); - TouchScreenState next_state{}; + struct TouchState { + u64_le delta_time; + Attributes attribute; + u32_le finger; + Common::Point position; + u32_le diameter_x; + u32_le diameter_y; + u32_le rotation_angle; + }; + static_assert(sizeof(TouchState) == 0x28, "Touchstate is an invalid size"); - std::array fingers; - Core::HID::EmulatedConsole* console; + struct TouchScreenEntry { + s64_le sampling_number; + s64_le sampling_number2; + s32_le entry_count; + std::array states; + }; + static_assert(sizeof(TouchScreenEntry) == 0x298, "TouchScreenEntry is an invalid size"); + + struct TouchScreenSharedMemory { + CommonHeader header; + std::array shared_memory_entries{}; + INSERT_PADDING_BYTES(0x3c8); + }; + static_assert(sizeof(TouchScreenSharedMemory) == 0x3000, + "TouchScreenSharedMemory is an invalid size"); + + struct Finger { + u64_le last_touch{}; + Common::Point position; + u32_le id{}; + bool pressed{}; + Attributes attribute; + }; + + TouchScreenSharedMemory shared_memory{}; + std::unique_ptr touch_mouse_device; + std::unique_ptr touch_udp_device; + std::unique_ptr touch_btn_device; + std::array mouse_finger_id; + std::array keyboard_finger_id; + std::array udp_finger_id; + std::array fingers; }; } // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/xpad.cpp b/src/core/hle/service/hid/controllers/xpad.cpp index e4da16466..41dc22cf9 100755 --- a/src/core/hle/service/hid/controllers/xpad.cpp +++ b/src/core/hle/service/hid/controllers/xpad.cpp @@ -5,13 +5,12 @@ #include #include "common/common_types.h" #include "core/core_timing.h" -#include "core/hid/hid_core.h" #include "core/hle/service/hid/controllers/xpad.h" namespace Service::HID { constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3C00; -Controller_XPad::Controller_XPad(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} {} +Controller_XPad::Controller_XPad(Core::System& system_) : ControllerBase{system_} {} Controller_XPad::~Controller_XPad() = default; void Controller_XPad::OnInit() {} @@ -20,19 +19,28 @@ void Controller_XPad::OnRelease() {} void Controller_XPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) { - if (!IsControllerActivated()) { - basic_xpad_lifo.buffer_count = 0; - basic_xpad_lifo.buffer_tail = 0; - std::memcpy(data + SHARED_MEMORY_OFFSET, &basic_xpad_lifo, sizeof(basic_xpad_lifo)); - return; - } + for (auto& xpad_entry : shared_memory.shared_memory_entries) { + xpad_entry.header.timestamp = core_timing.GetCPUTicks(); + xpad_entry.header.total_entry_count = 17; - const auto& last_entry = basic_xpad_lifo.ReadCurrentEntry().state; - next_state.sampling_number = last_entry.sampling_number + 1; + if (!IsControllerActivated()) { + xpad_entry.header.entry_count = 0; + xpad_entry.header.last_entry_index = 0; + return; + } + xpad_entry.header.entry_count = 16; + + const auto& last_entry = xpad_entry.pad_states[xpad_entry.header.last_entry_index]; + xpad_entry.header.last_entry_index = (xpad_entry.header.last_entry_index + 1) % 17; + auto& cur_entry = xpad_entry.pad_states[xpad_entry.header.last_entry_index]; + + cur_entry.sampling_number = last_entry.sampling_number + 1; + cur_entry.sampling_number2 = cur_entry.sampling_number; + } // TODO(ogniK): Update xpad states - basic_xpad_lifo.WriteNextEntry(next_state); - std::memcpy(data + SHARED_MEMORY_OFFSET, &basic_xpad_lifo, sizeof(basic_xpad_lifo)); + std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory)); } +void Controller_XPad::OnLoadInputDevices() {} } // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/xpad.h b/src/core/hle/service/hid/controllers/xpad.h index 54dae0be1..f9ab5facf 100755 --- a/src/core/hle/service/hid/controllers/xpad.h +++ b/src/core/hle/service/hid/controllers/xpad.h @@ -8,14 +8,12 @@ #include "common/common_funcs.h" #include "common/common_types.h" #include "common/swap.h" -#include "core/hid/hid_types.h" #include "core/hle/service/hid/controllers/controller_base.h" -#include "core/hle/service/hid/ring_lifo.h" namespace Service::HID { class Controller_XPad final : public ControllerBase { public: - explicit Controller_XPad(Core::HID::HIDCore& hid_core_); + explicit Controller_XPad(Core::System& system_); ~Controller_XPad() override; // Called when the controller is initialized @@ -27,11 +25,13 @@ public: // When the controller is requesting an update for the shared memory void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override; + // Called when input devices should be loaded + void OnLoadInputDevices() override; + private: - // This is nn::hid::BasicXpadAttributeSet - struct BasicXpadAttributeSet { + struct Attributes { union { - u32 raw{}; + u32_le raw{}; BitField<0, 1, u32> is_connected; BitField<1, 1, u32> is_wired; BitField<2, 1, u32> is_left_connected; @@ -40,12 +40,11 @@ private: BitField<5, 1, u32> is_right_wired; }; }; - static_assert(sizeof(BasicXpadAttributeSet) == 4, "BasicXpadAttributeSet is an invalid size"); + static_assert(sizeof(Attributes) == 4, "Attributes is an invalid size"); - // This is nn::hid::BasicXpadButtonSet - struct BasicXpadButtonSet { + struct Buttons { union { - u32 raw{}; + u32_le raw{}; // Button states BitField<0, 1, u32> a; BitField<1, 1, u32> b; @@ -89,21 +88,35 @@ private: BitField<30, 1, u32> handheld_left_b; }; }; - static_assert(sizeof(BasicXpadButtonSet) == 4, "BasicXpadButtonSet is an invalid size"); + static_assert(sizeof(Buttons) == 4, "Buttons is an invalid size"); - // This is nn::hid::detail::BasicXpadState - struct BasicXpadState { - s64 sampling_number; - BasicXpadAttributeSet attributes; - BasicXpadButtonSet pad_states; - Core::HID::AnalogStickState l_stick; - Core::HID::AnalogStickState r_stick; + struct AnalogStick { + s32_le x; + s32_le y; }; - static_assert(sizeof(BasicXpadState) == 0x20, "BasicXpadState is an invalid size"); + static_assert(sizeof(AnalogStick) == 0x8, "AnalogStick is an invalid size"); - // This is nn::hid::detail::BasicXpadLifo - Lifo basic_xpad_lifo{}; - static_assert(sizeof(basic_xpad_lifo) == 0x2C8, "basic_xpad_lifo is an invalid size"); - BasicXpadState next_state{}; + struct XPadState { + s64_le sampling_number; + s64_le sampling_number2; + Attributes attributes; + Buttons pad_states; + AnalogStick l_stick; + AnalogStick r_stick; + }; + static_assert(sizeof(XPadState) == 0x28, "XPadState is an invalid size"); + + struct XPadEntry { + CommonHeader header; + std::array pad_states{}; + INSERT_PADDING_BYTES(0x138); + }; + static_assert(sizeof(XPadEntry) == 0x400, "XPadEntry is an invalid size"); + + struct SharedMemory { + std::array shared_memory_entries{}; + }; + static_assert(sizeof(SharedMemory) == 0x1000, "SharedMemory is an invalid size"); + SharedMemory shared_memory{}; }; } // namespace Service::HID diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index e740b4331..10c64d41a 100755 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -8,7 +8,7 @@ #include "common/settings.h" #include "core/core.h" #include "core/core_timing.h" -#include "core/hid/hid_core.h" +#include "core/frontend/input.h" #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/k_readable_event.h" #include "core/hle/kernel/k_shared_memory.h" @@ -34,10 +34,10 @@ namespace Service::HID { // Updating period for each HID device. -// Period time is obtained by measuring the number of samples in a second on HW using a homebrew -constexpr auto pad_update_ns = std::chrono::nanoseconds{4 * 1000 * 1000}; // (4ms, 250Hz) -constexpr auto keyboard_update_ns = std::chrono::nanoseconds{8 * 1000 * 1000}; // (8ms, 125Hz) -constexpr auto motion_update_ns = std::chrono::nanoseconds{5 * 1000 * 1000}; // (5ms, 200Hz) +// HID is polled every 15ms, this value was derived from +// https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering#joy-con-status-data-packet +constexpr auto pad_update_ns = std::chrono::nanoseconds{1000 * 1000}; // (1ms, 1000Hz) +constexpr auto motion_update_ns = std::chrono::nanoseconds{15 * 1000 * 1000}; // (15ms, 66.666Hz) constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000; IAppletResource::IAppletResource(Core::System& system_, @@ -79,24 +79,17 @@ IAppletResource::IAppletResource(Core::System& system_, const auto guard = LockService(); UpdateControllers(user_data, ns_late); }); - keyboard_update_event = Core::Timing::CreateEvent( - "HID::UpdatekeyboardCallback", - [this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { - const auto guard = LockService(); - UpdateKeyboard(user_data, ns_late); - }); motion_update_event = Core::Timing::CreateEvent( - "HID::UpdateMotionCallback", + "HID::MotionPadCallback", [this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { const auto guard = LockService(); UpdateMotion(user_data, ns_late); }); system.CoreTiming().ScheduleEvent(pad_update_ns, pad_update_event); - system.CoreTiming().ScheduleEvent(keyboard_update_ns, keyboard_update_event); system.CoreTiming().ScheduleEvent(motion_update_ns, motion_update_event); - system.HIDCore().ReloadInputDevices(); + ReloadInputDevices(); } void IAppletResource::ActivateController(HidController controller) { @@ -109,7 +102,6 @@ void IAppletResource::DeactivateController(HidController controller) { IAppletResource::~IAppletResource() { system.CoreTiming().UnscheduleEvent(pad_update_event, 0); - system.CoreTiming().UnscheduleEvent(keyboard_update_event, 0); system.CoreTiming().UnscheduleEvent(motion_update_event, 0); } @@ -125,37 +117,23 @@ void IAppletResource::UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { auto& core_timing = system.CoreTiming(); + const bool should_reload = Settings::values.is_device_reload_pending.exchange(false); for (const auto& controller : controllers) { - // Keyboard has it's own update event - if (controller == controllers[static_cast(HidController::Keyboard)]) { - continue; + if (should_reload) { + controller->OnLoadInputDevices(); } controller->OnUpdate(core_timing, system.Kernel().GetHidSharedMem().GetPointer(), SHARED_MEMORY_SIZE); } // If ns_late is higher than the update rate ignore the delay - if (ns_late > pad_update_ns) { + if (ns_late > motion_update_ns) { ns_late = {}; } core_timing.ScheduleEvent(pad_update_ns - ns_late, pad_update_event); } -void IAppletResource::UpdateKeyboard(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { - auto& core_timing = system.CoreTiming(); - - controllers[static_cast(HidController::Keyboard)]->OnUpdate( - core_timing, system.Kernel().GetHidSharedMem().GetPointer(), SHARED_MEMORY_SIZE); - - // If ns_late is higher than the update rate ignore the delay - if (ns_late > keyboard_update_ns) { - ns_late = {}; - } - - core_timing.ScheduleEvent(keyboard_update_ns - ns_late, keyboard_update_event); -} - void IAppletResource::UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { auto& core_timing = system.CoreTiming(); @@ -188,7 +166,7 @@ public: private: void InitializeVibrationDevice(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto vibration_device_handle{rp.PopRaw()}; + const auto vibration_device_handle{rp.PopRaw()}; if (applet_resource != nullptr) { applet_resource->GetController(HidController::NPad) @@ -444,7 +422,6 @@ void Hid::ActivateXpad(Kernel::HLERequestContext& ctx) { INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; }; - static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); const auto parameters{rp.PopRaw()}; @@ -471,18 +448,19 @@ void Hid::GetXpadIDs(Kernel::HLERequestContext& ctx) { void Hid::ActivateSixAxisSensor(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - u32 basic_xpad_id; + Controller_NPad::DeviceHandle sixaxis_handle; INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; }; - static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); const auto parameters{rp.PopRaw()}; - // This function does nothing on 10.0.0+ + applet_resource->GetController(HidController::NPad).SetSixAxisEnabled(true); - LOG_WARNING(Service_HID, "(STUBBED) called, basic_xpad_id={}, applet_resource_user_id={}", - parameters.basic_xpad_id, parameters.applet_resource_user_id); + LOG_DEBUG(Service_HID, + "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", + parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id, + parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -491,18 +469,19 @@ void Hid::ActivateSixAxisSensor(Kernel::HLERequestContext& ctx) { void Hid::DeactivateSixAxisSensor(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - u32 basic_xpad_id; + Controller_NPad::DeviceHandle sixaxis_handle; INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; }; - static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); const auto parameters{rp.PopRaw()}; - // This function does nothing on 10.0.0+ + applet_resource->GetController(HidController::NPad).SetSixAxisEnabled(false); - LOG_WARNING(Service_HID, "(STUBBED) called, basic_xpad_id={}, applet_resource_user_id={}", - parameters.basic_xpad_id, parameters.applet_resource_user_id); + LOG_DEBUG(Service_HID, + "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", + parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id, + parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -511,16 +490,14 @@ void Hid::DeactivateSixAxisSensor(Kernel::HLERequestContext& ctx) { void Hid::StartSixAxisSensor(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - Core::HID::SixAxisSensorHandle sixaxis_handle; + Controller_NPad::DeviceHandle sixaxis_handle; INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; }; - static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); const auto parameters{rp.PopRaw()}; - applet_resource->GetController(HidController::NPad) - .SetSixAxisEnabled(parameters.sixaxis_handle, true); + applet_resource->GetController(HidController::NPad).SetSixAxisEnabled(true); LOG_DEBUG(Service_HID, "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", @@ -534,16 +511,14 @@ void Hid::StartSixAxisSensor(Kernel::HLERequestContext& ctx) { void Hid::StopSixAxisSensor(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - Core::HID::SixAxisSensorHandle sixaxis_handle; + Controller_NPad::DeviceHandle sixaxis_handle; INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; }; - static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); const auto parameters{rp.PopRaw()}; - applet_resource->GetController(HidController::NPad) - .SetSixAxisEnabled(parameters.sixaxis_handle, false); + applet_resource->GetController(HidController::NPad).SetSixAxisEnabled(false); LOG_DEBUG(Service_HID, "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", @@ -559,23 +534,19 @@ void Hid::EnableSixAxisSensorFusion(Kernel::HLERequestContext& ctx) { struct Parameters { bool enable_sixaxis_sensor_fusion; INSERT_PADDING_BYTES_NOINIT(3); - Core::HID::SixAxisSensorHandle sixaxis_handle; + Controller_NPad::DeviceHandle sixaxis_handle; u64 applet_resource_user_id; }; static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); const auto parameters{rp.PopRaw()}; - applet_resource->GetController(HidController::NPad) - .SetSixAxisFusionEnabled(parameters.sixaxis_handle, - parameters.enable_sixaxis_sensor_fusion); - - LOG_DEBUG(Service_HID, - "called, enable_sixaxis_sensor_fusion={}, npad_type={}, npad_id={}, " - "device_index={}, applet_resource_user_id={}", - parameters.enable_sixaxis_sensor_fusion, parameters.sixaxis_handle.npad_type, - parameters.sixaxis_handle.npad_id, parameters.sixaxis_handle.device_index, - parameters.applet_resource_user_id); + LOG_WARNING(Service_HID, + "(STUBBED) called, enable_sixaxis_sensor_fusion={}, npad_type={}, npad_id={}, " + "device_index={}, applet_resource_user_id={}", + parameters.enable_sixaxis_sensor_fusion, parameters.sixaxis_handle.npad_type, + parameters.sixaxis_handle.npad_id, parameters.sixaxis_handle.device_index, + parameters.applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -584,9 +555,9 @@ void Hid::EnableSixAxisSensorFusion(Kernel::HLERequestContext& ctx) { void Hid::SetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - Core::HID::SixAxisSensorHandle sixaxis_handle; - Core::HID::SixAxisSensorFusionParameters sixaxis_fusion; - INSERT_PADDING_WORDS_NOINIT(1); + Controller_NPad::DeviceHandle sixaxis_handle; + f32 parameter1; + f32 parameter2; u64 applet_resource_user_id; }; static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size."); @@ -594,14 +565,14 @@ void Hid::SetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx) { const auto parameters{rp.PopRaw()}; applet_resource->GetController(HidController::NPad) - .SetSixAxisFusionParameters(parameters.sixaxis_handle, parameters.sixaxis_fusion); + .SetSixAxisFusionParameters(parameters.parameter1, parameters.parameter2); - LOG_DEBUG(Service_HID, - "called, npad_type={}, npad_id={}, device_index={}, parameter1={}, " - "parameter2={}, applet_resource_user_id={}", - parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id, - parameters.sixaxis_handle.device_index, parameters.sixaxis_fusion.parameter1, - parameters.sixaxis_fusion.parameter2, parameters.applet_resource_user_id); + LOG_WARNING(Service_HID, + "(STUBBED) called, npad_type={}, npad_id={}, device_index={}, parameter1={}, " + "parameter2={}, applet_resource_user_id={}", + parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id, + parameters.sixaxis_handle.device_index, parameters.parameter1, + parameters.parameter2, parameters.applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -610,33 +581,35 @@ void Hid::SetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx) { void Hid::GetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - Core::HID::SixAxisSensorHandle sixaxis_handle; - INSERT_PADDING_WORDS_NOINIT(1); + Controller_NPad::DeviceHandle sixaxis_handle; u64 applet_resource_user_id; }; static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); + f32 parameter1 = 0; + f32 parameter2 = 0; const auto parameters{rp.PopRaw()}; - const auto sixaxis_fusion_parameters = + std::tie(parameter1, parameter2) = applet_resource->GetController(HidController::NPad) - .GetSixAxisFusionParameters(parameters.sixaxis_handle); + .GetSixAxisFusionParameters(); - LOG_DEBUG(Service_HID, - "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", - parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id, - parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id); + LOG_WARNING( + Service_HID, + "(STUBBED) called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", + parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id, + parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 4}; rb.Push(ResultSuccess); - rb.PushRaw(sixaxis_fusion_parameters); + rb.Push(parameter1); + rb.Push(parameter2); } void Hid::ResetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - Core::HID::SixAxisSensorHandle sixaxis_handle; - INSERT_PADDING_WORDS_NOINIT(1); + Controller_NPad::DeviceHandle sixaxis_handle; u64 applet_resource_user_id; }; static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); @@ -644,12 +617,13 @@ void Hid::ResetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx) { const auto parameters{rp.PopRaw()}; applet_resource->GetController(HidController::NPad) - .ResetSixAxisFusionParameters(parameters.sixaxis_handle); + .ResetSixAxisFusionParameters(); - LOG_DEBUG(Service_HID, - "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", - parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id, - parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id); + LOG_WARNING( + Service_HID, + "(STUBBED) called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", + parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id, + parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -657,12 +631,12 @@ void Hid::ResetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx) { void Hid::SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto sixaxis_handle{rp.PopRaw()}; + const auto sixaxis_handle{rp.PopRaw()}; const auto drift_mode{rp.PopEnum()}; const auto applet_resource_user_id{rp.Pop()}; applet_resource->GetController(HidController::NPad) - .SetGyroscopeZeroDriftMode(sixaxis_handle, drift_mode); + .SetGyroscopeZeroDriftMode(drift_mode); LOG_DEBUG(Service_HID, "called, npad_type={}, npad_id={}, device_index={}, drift_mode={}, " @@ -677,11 +651,10 @@ void Hid::SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { void Hid::GetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - Core::HID::SixAxisSensorHandle sixaxis_handle; + Controller_NPad::DeviceHandle sixaxis_handle; INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; }; - static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); const auto parameters{rp.PopRaw()}; @@ -693,23 +666,21 @@ void Hid::GetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); rb.PushEnum(applet_resource->GetController(HidController::NPad) - .GetGyroscopeZeroDriftMode(parameters.sixaxis_handle)); + .GetGyroscopeZeroDriftMode()); } void Hid::ResetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - Core::HID::SixAxisSensorHandle sixaxis_handle; + Controller_NPad::DeviceHandle sixaxis_handle; INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; }; - static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); const auto parameters{rp.PopRaw()}; - const auto drift_mode{Controller_NPad::GyroscopeZeroDriftMode::Standard}; applet_resource->GetController(HidController::NPad) - .SetGyroscopeZeroDriftMode(parameters.sixaxis_handle, drift_mode); + .SetGyroscopeZeroDriftMode(Controller_NPad::GyroscopeZeroDriftMode::Standard); LOG_DEBUG(Service_HID, "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", @@ -723,11 +694,10 @@ void Hid::ResetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { void Hid::IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - Core::HID::SixAxisSensorHandle sixaxis_handle; + Controller_NPad::DeviceHandle sixaxis_handle; INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; }; - static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); const auto parameters{rp.PopRaw()}; @@ -739,17 +709,16 @@ void Hid::IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); rb.Push(applet_resource->GetController(HidController::NPad) - .IsSixAxisSensorAtRest(parameters.sixaxis_handle)); + .IsSixAxisSensorAtRest()); } void Hid::IsFirmwareUpdateAvailableForSixAxisSensor(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - Core::HID::SixAxisSensorHandle sixaxis_handle; + Controller_NPad::DeviceHandle sixaxis_handle; INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; }; - static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); const auto parameters{rp.PopRaw()}; @@ -771,14 +740,13 @@ void Hid::ActivateGesture(Kernel::HLERequestContext& ctx) { INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; }; - static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); const auto parameters{rp.PopRaw()}; applet_resource->ActivateController(HidController::Gesture); - LOG_WARNING(Service_HID, "(STUBBED) called, unknown={}, applet_resource_user_id={}", - parameters.unknown, parameters.applet_resource_user_id); + LOG_DEBUG(Service_HID, "called, unknown={}, applet_resource_user_id={}", parameters.unknown, + parameters.applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -786,20 +754,12 @@ void Hid::ActivateGesture(Kernel::HLERequestContext& ctx) { void Hid::SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - struct Parameters { - Core::HID::NpadStyleSet supported_styleset; - INSERT_PADDING_WORDS_NOINIT(1); - u64 applet_resource_user_id; - }; - static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); - - const auto parameters{rp.PopRaw()}; + const auto supported_styleset{rp.Pop()}; applet_resource->GetController(HidController::NPad) - .SetSupportedStyleSet({parameters.supported_styleset}); + .SetSupportedStyleSet({supported_styleset}); - LOG_DEBUG(Service_HID, "called, supported_styleset={}, applet_resource_user_id={}", - parameters.supported_styleset, parameters.applet_resource_user_id); + LOG_DEBUG(Service_HID, "called, supported_styleset={}", supported_styleset); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -813,9 +773,9 @@ void Hid::GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) { IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); - rb.PushEnum(applet_resource->GetController(HidController::NPad) - .GetSupportedStyleSet() - .raw); + rb.Push(applet_resource->GetController(HidController::NPad) + .GetSupportedStyleSet() + .raw); } void Hid::SetSupportedNpadIdType(Kernel::HLERequestContext& ctx) { @@ -858,12 +818,11 @@ void Hid::DeactivateNpad(Kernel::HLERequestContext& ctx) { void Hid::AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - Core::HID::NpadIdType npad_id; + u32 npad_id; INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; u64 unknown; }; - static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size."); const auto parameters{rp.PopRaw()}; @@ -879,11 +838,10 @@ void Hid::AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) { void Hid::DisconnectNpad(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - Core::HID::NpadIdType npad_id; + u32 npad_id; INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; }; - static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); const auto parameters{rp.PopRaw()}; @@ -899,7 +857,7 @@ void Hid::DisconnectNpad(Kernel::HLERequestContext& ctx) { void Hid::GetPlayerLedPattern(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto npad_id{rp.PopEnum()}; + const auto npad_id{rp.Pop()}; LOG_DEBUG(Service_HID, "called, npad_id={}", npad_id); @@ -914,17 +872,16 @@ void Hid::ActivateNpadWithRevision(Kernel::HLERequestContext& ctx) { // Should have no effect with how our npad sets up the data IPC::RequestParser rp{ctx}; struct Parameters { - s32 revision; + u32 unknown; INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; }; - static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); const auto parameters{rp.PopRaw()}; applet_resource->ActivateController(HidController::NPad); - LOG_DEBUG(Service_HID, "called, revision={}, applet_resource_user_id={}", parameters.revision, + LOG_DEBUG(Service_HID, "called, unknown={}, applet_resource_user_id={}", parameters.unknown, parameters.applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 2}; @@ -934,7 +891,7 @@ void Hid::ActivateNpadWithRevision(Kernel::HLERequestContext& ctx) { void Hid::SetNpadJoyHoldType(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto applet_resource_user_id{rp.Pop()}; - const auto hold_type{rp.PopEnum()}; + const auto hold_type{rp.PopEnum()}; applet_resource->GetController(HidController::NPad).SetHoldType(hold_type); @@ -959,16 +916,15 @@ void Hid::GetNpadJoyHoldType(Kernel::HLERequestContext& ctx) { void Hid::SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - Core::HID::NpadIdType npad_id; + u32 npad_id; INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; }; - static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); const auto parameters{rp.PopRaw()}; applet_resource->GetController(HidController::NPad) - .SetNpadMode(parameters.npad_id, Controller_NPad::NpadJoyAssignmentMode::Single); + .SetNpadMode(parameters.npad_id, Controller_NPad::NpadAssignments::Single); LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}", parameters.npad_id, parameters.applet_resource_user_id); @@ -981,17 +937,16 @@ void Hid::SetNpadJoyAssignmentModeSingle(Kernel::HLERequestContext& ctx) { // TODO: Check the differences between this and SetNpadJoyAssignmentModeSingleByDefault IPC::RequestParser rp{ctx}; struct Parameters { - Core::HID::NpadIdType npad_id; + u32 npad_id; INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; u64 npad_joy_device_type; }; - static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size."); const auto parameters{rp.PopRaw()}; applet_resource->GetController(HidController::NPad) - .SetNpadMode(parameters.npad_id, Controller_NPad::NpadJoyAssignmentMode::Single); + .SetNpadMode(parameters.npad_id, Controller_NPad::NpadAssignments::Single); LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}", @@ -1005,16 +960,15 @@ void Hid::SetNpadJoyAssignmentModeSingle(Kernel::HLERequestContext& ctx) { void Hid::SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - Core::HID::NpadIdType npad_id; + u32 npad_id; INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; }; - static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); const auto parameters{rp.PopRaw()}; applet_resource->GetController(HidController::NPad) - .SetNpadMode(parameters.npad_id, Controller_NPad::NpadJoyAssignmentMode::Dual); + .SetNpadMode(parameters.npad_id, Controller_NPad::NpadAssignments::Dual); LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}", parameters.npad_id, parameters.applet_resource_user_id); @@ -1025,8 +979,8 @@ void Hid::SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) { void Hid::MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto npad_id_1{rp.PopEnum()}; - const auto npad_id_2{rp.PopEnum()}; + const auto npad_id_1{rp.Pop()}; + const auto npad_id_2{rp.Pop()}; const auto applet_resource_user_id{rp.Pop()}; applet_resource->GetController(HidController::NPad) @@ -1092,8 +1046,8 @@ void Hid::GetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) { void Hid::SwapNpadAssignment(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto npad_id_1{rp.PopEnum()}; - const auto npad_id_2{rp.PopEnum()}; + const auto npad_id_1{rp.Pop()}; + const auto npad_id_2{rp.Pop()}; const auto applet_resource_user_id{rp.Pop()}; const bool res = applet_resource->GetController(HidController::NPad) @@ -1114,11 +1068,10 @@ void Hid::SwapNpadAssignment(Kernel::HLERequestContext& ctx) { void Hid::IsUnintendedHomeButtonInputProtectionEnabled(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - Core::HID::NpadIdType npad_id; + u32 npad_id; INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; }; - static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); const auto parameters{rp.PopRaw()}; @@ -1136,10 +1089,9 @@ void Hid::EnableUnintendedHomeButtonInputProtection(Kernel::HLERequestContext& c struct Parameters { bool unintended_home_button_input_protection; INSERT_PADDING_BYTES_NOINIT(3); - Core::HID::NpadIdType npad_id; + u32 npad_id; u64 applet_resource_user_id; }; - static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); const auto parameters{rp.PopRaw()}; @@ -1161,7 +1113,6 @@ void Hid::SetNpadAnalogStickUseCenterClamp(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { bool analog_stick_use_center_clamp; - INSERT_PADDING_BYTES_NOINIT(7); u64 applet_resource_user_id; }; static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); @@ -1181,38 +1132,38 @@ void Hid::SetNpadAnalogStickUseCenterClamp(Kernel::HLERequestContext& ctx) { void Hid::GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto vibration_device_handle{rp.PopRaw()}; + const auto vibration_device_handle{rp.PopRaw()}; - Core::HID::VibrationDeviceInfo vibration_device_info; + VibrationDeviceInfo vibration_device_info; switch (vibration_device_handle.npad_type) { - case Core::HID::NpadStyleIndex::ProController: - case Core::HID::NpadStyleIndex::Handheld: - case Core::HID::NpadStyleIndex::JoyconDual: - case Core::HID::NpadStyleIndex::JoyconLeft: - case Core::HID::NpadStyleIndex::JoyconRight: + case Controller_NPad::NpadType::ProController: + case Controller_NPad::NpadType::Handheld: + case Controller_NPad::NpadType::JoyconDual: + case Controller_NPad::NpadType::JoyconLeft: + case Controller_NPad::NpadType::JoyconRight: default: - vibration_device_info.type = Core::HID::VibrationDeviceType::LinearResonantActuator; + vibration_device_info.type = VibrationDeviceType::LinearResonantActuator; break; - case Core::HID::NpadStyleIndex::GameCube: - vibration_device_info.type = Core::HID::VibrationDeviceType::GcErm; + case Controller_NPad::NpadType::GameCube: + vibration_device_info.type = VibrationDeviceType::GcErm; break; - case Core::HID::NpadStyleIndex::Pokeball: - vibration_device_info.type = Core::HID::VibrationDeviceType::Unknown; + case Controller_NPad::NpadType::Pokeball: + vibration_device_info.type = VibrationDeviceType::Unknown; break; } switch (vibration_device_handle.device_index) { - case Core::HID::DeviceIndex::Left: - vibration_device_info.position = Core::HID::VibrationDevicePosition::Left; + case Controller_NPad::DeviceIndex::Left: + vibration_device_info.position = VibrationDevicePosition::Left; break; - case Core::HID::DeviceIndex::Right: - vibration_device_info.position = Core::HID::VibrationDevicePosition::Right; + case Controller_NPad::DeviceIndex::Right: + vibration_device_info.position = VibrationDevicePosition::Right; break; - case Core::HID::DeviceIndex::None: + case Controller_NPad::DeviceIndex::None: default: UNREACHABLE_MSG("DeviceIndex should never be None!"); - vibration_device_info.position = Core::HID::VibrationDevicePosition::None; + vibration_device_info.position = VibrationDevicePosition::None; break; } @@ -1227,12 +1178,11 @@ void Hid::GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) { void Hid::SendVibrationValue(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - Core::HID::VibrationDeviceHandle vibration_device_handle; - Core::HID::VibrationValue vibration_value; + Controller_NPad::DeviceHandle vibration_device_handle; + Controller_NPad::VibrationValue vibration_value; INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; }; - static_assert(sizeof(Parameters) == 0x20, "Parameters has incorrect size."); const auto parameters{rp.PopRaw()}; @@ -1252,11 +1202,10 @@ void Hid::SendVibrationValue(Kernel::HLERequestContext& ctx) { void Hid::GetActualVibrationValue(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - Core::HID::VibrationDeviceHandle vibration_device_handle; + Controller_NPad::DeviceHandle vibration_device_handle; INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; }; - static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); const auto parameters{rp.PopRaw()}; @@ -1307,10 +1256,10 @@ void Hid::SendVibrationValues(Kernel::HLERequestContext& ctx) { const auto handles = ctx.ReadBuffer(0); const auto vibrations = ctx.ReadBuffer(1); - std::vector vibration_device_handles( - handles.size() / sizeof(Core::HID::VibrationDeviceHandle)); - std::vector vibration_values(vibrations.size() / - sizeof(Core::HID::VibrationValue)); + std::vector vibration_device_handles( + handles.size() / sizeof(Controller_NPad::DeviceHandle)); + std::vector vibration_values( + vibrations.size() / sizeof(Controller_NPad::VibrationValue)); std::memcpy(vibration_device_handles.data(), handles.data(), handles.size()); std::memcpy(vibration_values.data(), vibrations.data(), vibrations.size()); @@ -1327,10 +1276,9 @@ void Hid::SendVibrationValues(Kernel::HLERequestContext& ctx) { void Hid::SendVibrationGcErmCommand(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - Core::HID::VibrationDeviceHandle vibration_device_handle; - INSERT_PADDING_WORDS_NOINIT(1); + Controller_NPad::DeviceHandle vibration_device_handle; u64 applet_resource_user_id; - Core::HID::VibrationGcErmCommand gc_erm_command; + VibrationGcErmCommand gc_erm_command; }; static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size."); @@ -1344,26 +1292,26 @@ void Hid::SendVibrationGcErmCommand(Kernel::HLERequestContext& ctx) { */ const auto vibration_value = [parameters] { switch (parameters.gc_erm_command) { - case Core::HID::VibrationGcErmCommand::Stop: - return Core::HID::VibrationValue{ - .low_amplitude = 0.0f, - .low_frequency = 160.0f, - .high_amplitude = 0.0f, - .high_frequency = 320.0f, + case VibrationGcErmCommand::Stop: + return Controller_NPad::VibrationValue{ + .amp_low = 0.0f, + .freq_low = 160.0f, + .amp_high = 0.0f, + .freq_high = 320.0f, }; - case Core::HID::VibrationGcErmCommand::Start: - return Core::HID::VibrationValue{ - .low_amplitude = 1.0f, - .low_frequency = 160.0f, - .high_amplitude = 1.0f, - .high_frequency = 320.0f, + case VibrationGcErmCommand::Start: + return Controller_NPad::VibrationValue{ + .amp_low = 1.0f, + .freq_low = 160.0f, + .amp_high = 1.0f, + .freq_high = 320.0f, }; - case Core::HID::VibrationGcErmCommand::StopHard: - return Core::HID::VibrationValue{ - .low_amplitude = 0.0f, - .low_frequency = 0.0f, - .high_amplitude = 0.0f, - .high_frequency = 0.0f, + case VibrationGcErmCommand::StopHard: + return Controller_NPad::VibrationValue{ + .amp_low = 0.0f, + .freq_low = 0.0f, + .amp_high = 0.0f, + .freq_high = 0.0f, }; default: return Controller_NPad::DEFAULT_VIBRATION_VALUE; @@ -1388,7 +1336,7 @@ void Hid::SendVibrationGcErmCommand(Kernel::HLERequestContext& ctx) { void Hid::GetActualVibrationGcErmCommand(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - Core::HID::VibrationDeviceHandle vibration_device_handle; + Controller_NPad::DeviceHandle vibration_device_handle; INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; }; @@ -1399,8 +1347,8 @@ void Hid::GetActualVibrationGcErmCommand(Kernel::HLERequestContext& ctx) { .GetLastVibration(parameters.vibration_device_handle); const auto gc_erm_command = [last_vibration] { - if (last_vibration.low_amplitude != 0.0f || last_vibration.high_amplitude != 0.0f) { - return Core::HID::VibrationGcErmCommand::Start; + if (last_vibration.amp_low != 0.0f || last_vibration.amp_high != 0.0f) { + return VibrationGcErmCommand::Start; } /** @@ -1409,11 +1357,11 @@ void Hid::GetActualVibrationGcErmCommand(Kernel::HLERequestContext& ctx) { * SendVibrationGcErmCommand, in order to differentiate between Stop and StopHard commands. * This is done to reuse the controller vibration functions made for regular controllers. */ - if (last_vibration.low_frequency == 0.0f && last_vibration.high_frequency == 0.0f) { - return Core::HID::VibrationGcErmCommand::StopHard; + if (last_vibration.freq_low == 0.0f && last_vibration.freq_high == 0.0f) { + return VibrationGcErmCommand::StopHard; } - return Core::HID::VibrationGcErmCommand::Stop; + return VibrationGcErmCommand::Stop; }(); LOG_DEBUG(Service_HID, @@ -1453,11 +1401,10 @@ void Hid::EndPermitVibrationSession(Kernel::HLERequestContext& ctx) { void Hid::IsVibrationDeviceMounted(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - Core::HID::VibrationDeviceHandle vibration_device_handle; + Controller_NPad::DeviceHandle vibration_device_handle; INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; }; - static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); const auto parameters{rp.PopRaw()}; @@ -1488,18 +1435,18 @@ void Hid::ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { void Hid::StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - Core::HID::ConsoleSixAxisSensorHandle console_sixaxis_handle; + Controller_NPad::DeviceHandle sixaxis_handle; INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; }; - static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); const auto parameters{rp.PopRaw()}; - LOG_WARNING(Service_HID, - "(STUBBED) called, unknown_1={}, unknown_2={}, applet_resource_user_id={}", - parameters.console_sixaxis_handle.unknown_1, - parameters.console_sixaxis_handle.unknown_2, parameters.applet_resource_user_id); + LOG_WARNING( + Service_HID, + "(STUBBED) called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", + parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id, + parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -1508,18 +1455,18 @@ void Hid::StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { void Hid::StopConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - Core::HID::ConsoleSixAxisSensorHandle console_sixaxis_handle; + Controller_NPad::DeviceHandle sixaxis_handle; INSERT_PADDING_WORDS_NOINIT(1); u64 applet_resource_user_id; }; - static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); const auto parameters{rp.PopRaw()}; - LOG_WARNING(Service_HID, - "(STUBBED) called, unknown_1={}, unknown_2={}, applet_resource_user_id={}", - parameters.console_sixaxis_handle.unknown_1, - parameters.console_sixaxis_handle.unknown_2, parameters.applet_resource_user_id); + LOG_WARNING( + Service_HID, + "(STUBBED) called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", + parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id, + parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -1673,8 +1620,10 @@ void Hid::SetNpadCommunicationMode(Kernel::HLERequestContext& ctx) { void Hid::GetNpadCommunicationMode(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; + const auto applet_resource_user_id{rp.Pop()}; - LOG_WARNING(Service_HID, "(STUBBED) called"); + LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}", + applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 4}; rb.Push(ResultSuccess); @@ -2088,6 +2037,10 @@ public: } }; +void ReloadInputDevices() { + Settings::values.is_device_reload_pending.store(true); +} + void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { std::make_shared(system)->InstallAsService(service_manager); std::make_shared(system)->InstallAsService(service_manager); diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index bbad165f8..b1fe75e94 100755 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h @@ -60,23 +60,21 @@ public: private: template void MakeController(HidController controller) { - controllers[static_cast(controller)] = std::make_unique(system.HIDCore()); + controllers[static_cast(controller)] = std::make_unique(system); } template void MakeControllerWithServiceContext(HidController controller) { controllers[static_cast(controller)] = - std::make_unique(system.HIDCore(), service_context); + std::make_unique(system, service_context); } void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx); void UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); - void UpdateKeyboard(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); void UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); KernelHelpers::ServiceContext& service_context; std::shared_ptr pad_update_event; - std::shared_ptr keyboard_update_event; std::shared_ptr motion_update_event; std::array, static_cast(HidController::MaxControllers)> @@ -163,11 +161,38 @@ private: void GetNpadCommunicationMode(Kernel::HLERequestContext& ctx); void SetTouchScreenConfiguration(Kernel::HLERequestContext& ctx); + enum class VibrationDeviceType : u32 { + Unknown = 0, + LinearResonantActuator = 1, + GcErm = 2, + }; + + enum class VibrationDevicePosition : u32 { + None = 0, + Left = 1, + Right = 2, + }; + + enum class VibrationGcErmCommand : u64 { + Stop = 0, + Start = 1, + StopHard = 2, + }; + + struct VibrationDeviceInfo { + VibrationDeviceType type{}; + VibrationDevicePosition position{}; + }; + static_assert(sizeof(VibrationDeviceInfo) == 0x8, "VibrationDeviceInfo has incorrect size."); + std::shared_ptr applet_resource; KernelHelpers::ServiceContext service_context; }; +/// Reload input devices. Used when input configuration changed +void ReloadInputDevices(); + /// Registers all HID services with the specified service manager. void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system); diff --git a/src/input_common/CMakeLists.txt b/src/input_common/CMakeLists.txt index d4fa69a77..dd13d948f 100755 --- a/src/input_common/CMakeLists.txt +++ b/src/input_common/CMakeLists.txt @@ -1,32 +1,36 @@ add_library(input_common STATIC - drivers/gc_adapter.cpp - drivers/gc_adapter.h - drivers/keyboard.cpp - drivers/keyboard.h - drivers/mouse.cpp - drivers/mouse.h - drivers/sdl_driver.cpp - drivers/sdl_driver.h - drivers/tas_input.cpp - drivers/tas_input.h - drivers/touch_screen.cpp - drivers/touch_screen.h - drivers/udp_client.cpp - drivers/udp_client.h - helpers/stick_from_buttons.cpp - helpers/stick_from_buttons.h - helpers/touch_from_buttons.cpp - helpers/touch_from_buttons.h - helpers/udp_protocol.cpp - helpers/udp_protocol.h - input_engine.cpp - input_engine.h - input_mapping.cpp - input_mapping.h - input_poller.cpp - input_poller.h + analog_from_button.cpp + analog_from_button.h + keyboard.cpp + keyboard.h main.cpp main.h + motion_from_button.cpp + motion_from_button.h + motion_input.cpp + motion_input.h + touch_from_button.cpp + touch_from_button.h + gcadapter/gc_adapter.cpp + gcadapter/gc_adapter.h + gcadapter/gc_poller.cpp + gcadapter/gc_poller.h + mouse/mouse_input.cpp + mouse/mouse_input.h + mouse/mouse_poller.cpp + mouse/mouse_poller.h + sdl/sdl.cpp + sdl/sdl.h + tas/tas_input.cpp + tas/tas_input.h + tas/tas_poller.cpp + tas/tas_poller.h + udp/client.cpp + udp/client.h + udp/protocol.cpp + udp/protocol.h + udp/udp.cpp + udp/udp.h ) if (MSVC) @@ -53,8 +57,8 @@ endif() if (ENABLE_SDL2) target_sources(input_common PRIVATE - drivers/sdl_driver.cpp - drivers/sdl_driver.h + sdl/sdl_impl.cpp + sdl/sdl_impl.h ) target_link_libraries(input_common PRIVATE SDL2) target_compile_definitions(input_common PRIVATE HAVE_SDL2) diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp index ae2518f53..f3907c65a 100755 --- a/src/input_common/main.cpp +++ b/src/input_common/main.cpp @@ -4,164 +4,146 @@ #include #include -#include "common/input.h" #include "common/param_package.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 "common/settings.h" +#include "input_common/analog_from_button.h" +#include "input_common/gcadapter/gc_adapter.h" +#include "input_common/gcadapter/gc_poller.h" +#include "input_common/keyboard.h" #include "input_common/main.h" +#include "input_common/motion_from_button.h" +#include "input_common/mouse/mouse_input.h" +#include "input_common/mouse/mouse_poller.h" +#include "input_common/tas/tas_input.h" +#include "input_common/tas/tas_poller.h" +#include "input_common/touch_from_button.h" +#include "input_common/udp/client.h" +#include "input_common/udp/udp.h" #ifdef HAVE_SDL2 -#include "input_common/drivers/sdl_driver.h" +#include "input_common/sdl/sdl.h" #endif namespace InputCommon { struct InputSubsystem::Impl { void Initialize() { - mapping_factory = std::make_shared(); - MappingCallback mapping_callback{[this](MappingData data) { RegisterInput(data); }}; + gcadapter = std::make_shared(); + gcbuttons = std::make_shared(gcadapter); + Input::RegisterFactory("gcpad", gcbuttons); + gcanalog = std::make_shared(gcadapter); + Input::RegisterFactory("gcpad", gcanalog); + gcvibration = std::make_shared(gcadapter); + Input::RegisterFactory("gcpad", gcvibration); - keyboard = std::make_shared("keyboard"); - keyboard->SetMappingCallback(mapping_callback); - keyboard_factory = std::make_shared(keyboard); - keyboard_output_factory = std::make_shared(keyboard); - Common::Input::RegisterFactory(keyboard->GetEngineName(), - keyboard_factory); - Common::Input::RegisterFactory(keyboard->GetEngineName(), - keyboard_output_factory); - - mouse = std::make_shared("mouse"); - mouse->SetMappingCallback(mapping_callback); - mouse_factory = std::make_shared(mouse); - mouse_output_factory = std::make_shared(mouse); - Common::Input::RegisterFactory(mouse->GetEngineName(), - mouse_factory); - Common::Input::RegisterFactory(mouse->GetEngineName(), - mouse_output_factory); - - touch_screen = std::make_shared("touch"); - touch_screen_factory = std::make_shared(touch_screen); - Common::Input::RegisterFactory(touch_screen->GetEngineName(), - touch_screen_factory); - - gcadapter = std::make_shared("gcpad"); - gcadapter->SetMappingCallback(mapping_callback); - gcadapter_input_factory = std::make_shared(gcadapter); - gcadapter_output_factory = std::make_shared(gcadapter); - Common::Input::RegisterFactory(gcadapter->GetEngineName(), - gcadapter_input_factory); - Common::Input::RegisterFactory(gcadapter->GetEngineName(), - gcadapter_output_factory); - - udp_client = std::make_shared("cemuhookudp"); - udp_client->SetMappingCallback(mapping_callback); - udp_client_factory = std::make_shared(udp_client); - Common::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); - tas_output_factory = std::make_shared(tas_input); - Common::Input::RegisterFactory(tas_input->GetEngineName(), - tas_input_factory); - Common::Input::RegisterFactory(tas_input->GetEngineName(), - tas_output_factory); + keyboard = std::make_shared(); + Input::RegisterFactory("keyboard", keyboard); + Input::RegisterFactory("analog_from_button", + std::make_shared()); + Input::RegisterFactory("keyboard", + std::make_shared()); + Input::RegisterFactory("touch_from_button", + std::make_shared()); #ifdef HAVE_SDL2 - sdl = std::make_shared("sdl"); - sdl->SetMappingCallback(mapping_callback); - sdl_input_factory = std::make_shared(sdl); - sdl_output_factory = std::make_shared(sdl); - Common::Input::RegisterFactory(sdl->GetEngineName(), - sdl_input_factory); - Common::Input::RegisterFactory(sdl->GetEngineName(), - sdl_output_factory); + sdl = SDL::Init(); #endif - Common::Input::RegisterFactory( - "touch_from_button", std::make_shared()); - Common::Input::RegisterFactory( - "analog_from_button", std::make_shared()); + udp = std::make_shared(); + udpmotion = std::make_shared(udp); + Input::RegisterFactory("cemuhookudp", udpmotion); + udptouch = std::make_shared(udp); + Input::RegisterFactory("cemuhookudp", udptouch); + + mouse = std::make_shared(); + mousebuttons = std::make_shared(mouse); + Input::RegisterFactory("mouse", mousebuttons); + mouseanalog = std::make_shared(mouse); + Input::RegisterFactory("mouse", mouseanalog); + mousemotion = std::make_shared(mouse); + Input::RegisterFactory("mouse", mousemotion); + mousetouch = std::make_shared(mouse); + Input::RegisterFactory("mouse", mousetouch); + + tas = std::make_shared(); + tasbuttons = std::make_shared(tas); + Input::RegisterFactory("tas", tasbuttons); + tasanalog = std::make_shared(tas); + Input::RegisterFactory("tas", tasanalog); } void Shutdown() { - Common::Input::UnregisterFactory(keyboard->GetEngineName()); - Common::Input::UnregisterFactory(keyboard->GetEngineName()); + Input::UnregisterFactory("keyboard"); + Input::UnregisterFactory("keyboard"); keyboard.reset(); - - Common::Input::UnregisterFactory(mouse->GetEngineName()); - Common::Input::UnregisterFactory(mouse->GetEngineName()); - mouse.reset(); - - Common::Input::UnregisterFactory(touch_screen->GetEngineName()); - touch_screen.reset(); - - Common::Input::UnregisterFactory(gcadapter->GetEngineName()); - Common::Input::UnregisterFactory(gcadapter->GetEngineName()); - gcadapter.reset(); - - Common::Input::UnregisterFactory(udp_client->GetEngineName()); - udp_client.reset(); - - Common::Input::UnregisterFactory(tas_input->GetEngineName()); - Common::Input::UnregisterFactory(tas_input->GetEngineName()); - tas_input.reset(); - + Input::UnregisterFactory("analog_from_button"); + Input::UnregisterFactory("touch_from_button"); #ifdef HAVE_SDL2 - Common::Input::UnregisterFactory(sdl->GetEngineName()); - Common::Input::UnregisterFactory(sdl->GetEngineName()); sdl.reset(); #endif + Input::UnregisterFactory("gcpad"); + Input::UnregisterFactory("gcpad"); + Input::UnregisterFactory("gcpad"); - Common::Input::UnregisterFactory("touch_from_button"); - Common::Input::UnregisterFactory("analog_from_button"); + gcbuttons.reset(); + gcanalog.reset(); + gcvibration.reset(); + + Input::UnregisterFactory("cemuhookudp"); + Input::UnregisterFactory("cemuhookudp"); + + udpmotion.reset(); + udptouch.reset(); + + Input::UnregisterFactory("mouse"); + Input::UnregisterFactory("mouse"); + Input::UnregisterFactory("mouse"); + Input::UnregisterFactory("mouse"); + + mousebuttons.reset(); + mouseanalog.reset(); + mousemotion.reset(); + mousetouch.reset(); + + Input::UnregisterFactory("tas"); + Input::UnregisterFactory("tas"); + + tasbuttons.reset(); + tasanalog.reset(); } [[nodiscard]] std::vector GetInputDevices() const { std::vector devices = { - Common::ParamPackage{{"display", "Any"}, {"engine", "any"}}, + Common::ParamPackage{{"display", "Any"}, {"class", "any"}}, + Common::ParamPackage{{"display", "Keyboard/Mouse"}, {"class", "keyboard"}}, }; - - 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()); + if (Settings::values.tas_enable) { + devices.emplace_back( + Common::ParamPackage{{"display", "TAS Controller"}, {"class", "tas"}}); + } #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()); + auto gcpad_devices = gcadapter->GetInputDevices(); + devices.insert(devices.end(), gcpad_devices.begin(), gcpad_devices.end()); return devices; } [[nodiscard]] AnalogMapping GetAnalogMappingForDevice( const Common::ParamPackage& params) const { - if (!params.Has("engine") || params.Get("engine", "") == "any") { + if (!params.Has("class") || params.Get("class", "") == "any") { return {}; } - const std::string engine = params.Get("engine", ""); - if (engine == mouse->GetEngineName()) { - return mouse->GetAnalogMappingForDevice(params); - } - if (engine == gcadapter->GetEngineName()) { + if (params.Get("class", "") == "gcpad") { return gcadapter->GetAnalogMappingForDevice(params); } - if (engine == tas_input->GetEngineName()) { - return tas_input->GetAnalogMappingForDevice(params); + if (params.Get("class", "") == "tas") { + return tas->GetAnalogMappingForDevice(params); } #ifdef HAVE_SDL2 - if (engine == sdl->GetEngineName()) { + if (params.Get("class", "") == "sdl") { return sdl->GetAnalogMappingForDevice(params); } #endif @@ -170,18 +152,17 @@ struct InputSubsystem::Impl { [[nodiscard]] ButtonMapping GetButtonMappingForDevice( const Common::ParamPackage& params) const { - if (!params.Has("engine") || params.Get("engine", "") == "any") { + if (!params.Has("class") || params.Get("class", "") == "any") { return {}; } - const std::string engine = params.Get("engine", ""); - if (engine == gcadapter->GetEngineName()) { + if (params.Get("class", "") == "gcpad") { return gcadapter->GetButtonMappingForDevice(params); } - if (engine == tas_input->GetEngineName()) { - return tas_input->GetButtonMappingForDevice(params); + if (params.Get("class", "") == "tas") { + return tas->GetButtonMappingForDevice(params); } #ifdef HAVE_SDL2 - if (engine == sdl->GetEngineName()) { + if (params.Get("class", "") == "sdl") { return sdl->GetButtonMappingForDevice(params); } #endif @@ -190,115 +171,40 @@ struct InputSubsystem::Impl { [[nodiscard]] MotionMapping GetMotionMappingForDevice( const Common::ParamPackage& params) const { - if (!params.Has("engine") || params.Get("engine", "") == "any") { + if (!params.Has("class") || params.Get("class", "") == "any") { return {}; } - const std::string engine = params.Get("engine", ""); - if (engine == gcadapter->GetEngineName()) { - return gcadapter->GetMotionMappingForDevice(params); + if (params.Get("class", "") == "cemuhookudp") { + // TODO return the correct motion device + return {}; } #ifdef HAVE_SDL2 - if (engine == sdl->GetEngineName()) { + if (params.Get("class", "") == "sdl") { 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 mouse; - std::shared_ptr gcadapter; - std::shared_ptr touch_screen; - std::shared_ptr tas_input; - std::shared_ptr udp_client; - - std::shared_ptr keyboard_factory; - std::shared_ptr mouse_factory; - std::shared_ptr gcadapter_input_factory; - std::shared_ptr touch_screen_factory; - std::shared_ptr udp_client_factory; - std::shared_ptr tas_input_factory; - - std::shared_ptr keyboard_output_factory; - std::shared_ptr mouse_output_factory; - std::shared_ptr gcadapter_output_factory; - std::shared_ptr tas_output_factory; - #ifdef HAVE_SDL2 - std::shared_ptr sdl; - std::shared_ptr sdl_input_factory; - std::shared_ptr sdl_output_factory; + std::unique_ptr sdl; #endif + std::shared_ptr gcbuttons; + std::shared_ptr gcanalog; + std::shared_ptr gcvibration; + std::shared_ptr udpmotion; + std::shared_ptr udptouch; + std::shared_ptr mousebuttons; + std::shared_ptr mouseanalog; + std::shared_ptr mousemotion; + std::shared_ptr mousetouch; + std::shared_ptr tasbuttons; + std::shared_ptr tasanalog; + std::shared_ptr udp; + std::shared_ptr gcadapter; + std::shared_ptr mouse; + std::shared_ptr tas; }; InputSubsystem::InputSubsystem() : impl{std::make_unique()} {} @@ -321,28 +227,20 @@ const Keyboard* InputSubsystem::GetKeyboard() const { return impl->keyboard.get(); } -Mouse* InputSubsystem::GetMouse() { +MouseInput::Mouse* InputSubsystem::GetMouse() { return impl->mouse.get(); } -const Mouse* InputSubsystem::GetMouse() const { +const MouseInput::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(); + return impl->tas.get(); } const TasInput::Tas* InputSubsystem::GetTas() const { - return impl->tas_input.get(); + return impl->tas.get(); } std::vector InputSubsystem::GetInputDevices() const { @@ -361,37 +259,100 @@ MotionMapping InputSubsystem::GetMotionMappingForDevice(const Common::ParamPacka return impl->GetMotionMappingForDevice(device); } -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); +GCAnalogFactory* InputSubsystem::GetGCAnalogs() { + return impl->gcanalog.get(); } -bool InputSubsystem::IsController(const Common::ParamPackage& params) const { - return impl->IsController(params); +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(); +} + +UDPMotionFactory* InputSubsystem::GetUDPMotions() { + return impl->udpmotion.get(); +} + +const UDPMotionFactory* InputSubsystem::GetUDPMotions() const { + return impl->udpmotion.get(); +} + +UDPTouchFactory* InputSubsystem::GetUDPTouch() { + return impl->udptouch.get(); +} + +const UDPTouchFactory* InputSubsystem::GetUDPTouch() const { + return impl->udptouch.get(); +} + +MouseButtonFactory* InputSubsystem::GetMouseButtons() { + return impl->mousebuttons.get(); +} + +const MouseButtonFactory* InputSubsystem::GetMouseButtons() const { + return impl->mousebuttons.get(); +} + +MouseAnalogFactory* InputSubsystem::GetMouseAnalogs() { + return impl->mouseanalog.get(); +} + +const MouseAnalogFactory* InputSubsystem::GetMouseAnalogs() const { + return impl->mouseanalog.get(); +} + +MouseMotionFactory* InputSubsystem::GetMouseMotions() { + return impl->mousemotion.get(); +} + +const MouseMotionFactory* InputSubsystem::GetMouseMotions() const { + return impl->mousemotion.get(); +} + +MouseTouchFactory* InputSubsystem::GetMouseTouch() { + return impl->mousetouch.get(); +} + +const MouseTouchFactory* InputSubsystem::GetMouseTouch() const { + return impl->mousetouch.get(); +} + +TasButtonFactory* InputSubsystem::GetTasButtons() { + return impl->tasbuttons.get(); +} + +const TasButtonFactory* InputSubsystem::GetTasButtons() const { + return impl->tasbuttons.get(); +} + +TasAnalogFactory* InputSubsystem::GetTasAnalogs() { + return impl->tasanalog.get(); +} + +const TasAnalogFactory* InputSubsystem::GetTasAnalogs() const { + return impl->tasanalog.get(); } void InputSubsystem::ReloadInputDevices() { - impl->udp_client.get()->ReloadSockets(); + if (!impl->udp) { + return; + } + impl->udp->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::vector> InputSubsystem::GetPollers( + [[maybe_unused]] Polling::DeviceType type) const { +#ifdef HAVE_SDL2 + return impl->sdl->GetPollers(type); +#else + return {}; +#endif } std::string GenerateKeyboardParam(int key_code) { @@ -402,15 +363,6 @@ std::string GenerateKeyboardParam(int key_code) { return param.Serialize(); } -std::string GenerateModdifierKeyboardParam(int key_code) { - Common::ParamPackage param; - param.Set("engine", "keyboard"); - param.Set("code", key_code); - param.Set("toggle", false); - param.Set("pad", 1); - 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{ diff --git a/src/input_common/main.h b/src/input_common/main.h index 9ea395465..6390d3f09 100755 --- a/src/input_common/main.h +++ b/src/input_common/main.h @@ -25,26 +25,56 @@ namespace Settings::NativeMotion { enum Values : int; } -namespace InputCommon { -class Keyboard; +namespace MouseInput { class Mouse; -class TouchScreen; -struct MappingData; -} // namespace InputCommon +} -namespace InputCommon::TasInput { +namespace TasInput { class Tas; -} // namespace InputCommon::TasInput +} namespace InputCommon { namespace Polling { -/// Type of input desired for mapping purposes -enum class InputType { None, Button, Stick, Motion, Touch }; + +enum class DeviceType { Button, AnalogPreferred, Motion }; + +/** + * 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 +class GCAnalogFactory; +class GCButtonFactory; +class UDPMotionFactory; +class UDPTouchFactory; +class MouseButtonFactory; +class MouseAnalogFactory; +class MouseMotionFactory; +class MouseTouchFactory; +class TasButtonFactory; +class TasAnalogFactory; +class Keyboard; + /** * Given a ParamPackage for a Device returned from `GetInputDevices`, attempt to get the default - * mapping for the device. + * mapping for the device. This is currently only implemented for the SDL backend devices. */ using AnalogMapping = std::unordered_map; using ButtonMapping = std::unordered_map; @@ -74,27 +104,20 @@ public: [[nodiscard]] const Keyboard* GetKeyboard() const; /// Retrieves the underlying mouse device. - [[nodiscard]] Mouse* GetMouse(); + [[nodiscard]] MouseInput::Mouse* GetMouse(); /// Retrieves the underlying mouse device. - [[nodiscard]] const Mouse* GetMouse() const; + [[nodiscard]] const MouseInput::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. + /// Retrieves the underlying tas device. [[nodiscard]] TasInput::Tas* GetTas(); - /// Retrieves the underlying tas input device. + /// Retrieves the underlying tas 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 `engine` 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 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 GetInputDevices() const; @@ -108,36 +131,83 @@ public: /// Retrieves the motion mappings for the given device. [[nodiscard]] MotionMapping GetMotionMappingForDevice(const Common::ParamPackage& device) const; - /// Returns a string contaning the name of the button from the input engine. - [[nodiscard]] std::string GetButtonName(const Common::ParamPackage& params) const; + /// Retrieves the underlying GameCube analog handler. + [[nodiscard]] GCAnalogFactory* GetGCAnalogs(); - /// Returns true if device is a controller. - [[nodiscard]] bool IsController(const Common::ParamPackage& params) const; + /// Retrieves the underlying GameCube analog handler. + [[nodiscard]] const GCAnalogFactory* GetGCAnalogs() const; - /// Reloads the input devices. + /// Retrieves the underlying GameCube button handler. + [[nodiscard]] GCButtonFactory* GetGCButtons(); + + /// Retrieves the underlying GameCube button handler. + [[nodiscard]] const GCButtonFactory* GetGCButtons() const; + + /// Retrieves the underlying udp motion handler. + [[nodiscard]] UDPMotionFactory* GetUDPMotions(); + + /// Retrieves the underlying udp motion handler. + [[nodiscard]] const UDPMotionFactory* GetUDPMotions() const; + + /// Retrieves the underlying udp touch handler. + [[nodiscard]] UDPTouchFactory* GetUDPTouch(); + + /// Retrieves the underlying udp touch handler. + [[nodiscard]] const UDPTouchFactory* GetUDPTouch() const; + + /// Retrieves the underlying mouse button handler. + [[nodiscard]] MouseButtonFactory* GetMouseButtons(); + + /// Retrieves the underlying mouse button handler. + [[nodiscard]] const MouseButtonFactory* GetMouseButtons() const; + + /// Retrieves the underlying mouse analog handler. + [[nodiscard]] MouseAnalogFactory* GetMouseAnalogs(); + + /// Retrieves the underlying mouse analog handler. + [[nodiscard]] const MouseAnalogFactory* GetMouseAnalogs() const; + + /// Retrieves the underlying mouse motion handler. + [[nodiscard]] MouseMotionFactory* GetMouseMotions(); + + /// Retrieves the underlying mouse motion handler. + [[nodiscard]] const MouseMotionFactory* GetMouseMotions() const; + + /// Retrieves the underlying mouse touch handler. + [[nodiscard]] MouseTouchFactory* GetMouseTouch(); + + /// Retrieves the underlying mouse touch handler. + [[nodiscard]] const MouseTouchFactory* GetMouseTouch() const; + + /// Retrieves the underlying tas button handler. + [[nodiscard]] TasButtonFactory* GetTasButtons(); + + /// Retrieves the underlying tas button handler. + [[nodiscard]] const TasButtonFactory* GetTasButtons() const; + + /// Retrieves the underlying tas analogs handler. + [[nodiscard]] TasAnalogFactory* GetTasAnalogs(); + + /// Retrieves the underlying tas analogs handler. + [[nodiscard]] const TasAnalogFactory* GetTasAnalogs() const; + + /// Reloads the input devices void ReloadInputDevices(); - /// 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; + /// Get all DevicePoller from all backends for a specific device type + [[nodiscard]] std::vector> GetPollers( + Polling::DeviceType type) 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 a moddifier keyboard button device. -std::string GenerateModdifierKeyboardParam(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 diff --git a/src/yuzu/applets/qt_controller.cpp b/src/yuzu/applets/qt_controller.cpp index 6a2cdda63..bf8445a89 100755 --- a/src/yuzu/applets/qt_controller.cpp +++ b/src/yuzu/applets/qt_controller.cpp @@ -6,12 +6,8 @@ #include #include "common/assert.h" -#include "common/param_package.h" #include "common/string_util.h" #include "core/core.h" -#include "core/hid/emulated_controller.h" -#include "core/hid/hid_core.h" -#include "core/hid/hid_types.h" #include "core/hle/lock.h" #include "core/hle/service/hid/controllers/npad.h" #include "core/hle/service/hid/hid.h" @@ -27,32 +23,49 @@ namespace { -void UpdateController(Core::HID::EmulatedController* controller, - Core::HID::NpadStyleIndex controller_type, bool connected) { - if (controller->IsConnected()) { - controller->Disconnect(); - } - controller->SetNpadStyleIndex(controller_type); - if (connected) { - controller->Connect(); +constexpr std::size_t HANDHELD_INDEX = 8; + +constexpr std::array, 8> led_patterns{{ + {true, false, false, false}, + {true, true, false, false}, + {true, true, true, false}, + {true, true, true, true}, + {true, false, false, true}, + {true, false, true, false}, + {true, false, true, true}, + {false, true, true, false}, +}}; + +void UpdateController(Settings::ControllerType controller_type, std::size_t npad_index, + bool connected, Core::System& system) { + if (!system.IsPoweredOn()) { + return; } + + auto& npad = + system.ServiceManager() + .GetService("hid") + ->GetAppletResource() + ->GetController(Service::HID::HidController::NPad); + + npad.UpdateControllerAt(npad.MapSettingsTypeToNPad(controller_type), npad_index, connected); } // Returns true if the given controller type is compatible with the given parameters. -bool IsControllerCompatible(Core::HID::NpadStyleIndex controller_type, +bool IsControllerCompatible(Settings::ControllerType controller_type, Core::Frontend::ControllerParameters parameters) { switch (controller_type) { - case Core::HID::NpadStyleIndex::ProController: + case Settings::ControllerType::ProController: return parameters.allow_pro_controller; - case Core::HID::NpadStyleIndex::JoyconDual: + case Settings::ControllerType::DualJoyconDetached: return parameters.allow_dual_joycons; - case Core::HID::NpadStyleIndex::JoyconLeft: + case Settings::ControllerType::LeftJoycon: return parameters.allow_left_joycon; - case Core::HID::NpadStyleIndex::JoyconRight: + case Settings::ControllerType::RightJoycon: return parameters.allow_right_joycon; - case Core::HID::NpadStyleIndex::Handheld: + case Settings::ControllerType::Handheld: return parameters.enable_single_mode && parameters.allow_handheld; - case Core::HID::NpadStyleIndex::GameCube: + case Settings::ControllerType::GameCube: return parameters.allow_gamecube_controller; default: return false; @@ -183,7 +196,7 @@ QtControllerSelectorDialog::QtControllerSelectorDialog( connect(emulated_controllers[i], qOverload(&QComboBox::currentIndexChanged), [this, i](int index) { UpdateDockedState(GetControllerTypeFromIndex(index, i) == - Core::HID::NpadStyleIndex::Handheld); + Settings::ControllerType::Handheld); }); } } @@ -236,17 +249,17 @@ void QtControllerSelectorDialog::ApplyConfiguration() { } void QtControllerSelectorDialog::LoadConfiguration() { - const auto* handheld = system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld); for (std::size_t index = 0; index < NUM_PLAYERS; ++index) { - const auto* controller = system.HIDCore().GetEmulatedControllerByIndex(index); - const auto connected = controller->IsConnected() || (index == 0 && handheld->IsConnected()); + const auto connected = + Settings::values.players.GetValue()[index].connected || + (index == 0 && Settings::values.players.GetValue()[HANDHELD_INDEX].connected); player_groupboxes[index]->setChecked(connected); connected_controller_checkboxes[index]->setChecked(connected); - emulated_controllers[index]->setCurrentIndex( - GetIndexFromControllerType(controller->GetNpadStyleIndex(), index)); + emulated_controllers[index]->setCurrentIndex(GetIndexFromControllerType( + Settings::values.players.GetValue()[index].controller_type, index)); } - UpdateDockedState(handheld->IsConnected()); + UpdateDockedState(Settings::values.players.GetValue()[HANDHELD_INDEX].connected); ui->vibrationGroup->setChecked(Settings::values.vibration_enabled.GetValue()); ui->motionGroup->setChecked(Settings::values.motion_enabled.GetValue()); @@ -402,33 +415,33 @@ void QtControllerSelectorDialog::SetEmulatedControllers(std::size_t player_index emulated_controllers[player_index]->clear(); pairs.emplace_back(emulated_controllers[player_index]->count(), - Core::HID::NpadStyleIndex::ProController); + Settings::ControllerType::ProController); emulated_controllers[player_index]->addItem(tr("Pro Controller")); pairs.emplace_back(emulated_controllers[player_index]->count(), - Core::HID::NpadStyleIndex::JoyconDual); + Settings::ControllerType::DualJoyconDetached); emulated_controllers[player_index]->addItem(tr("Dual Joycons")); pairs.emplace_back(emulated_controllers[player_index]->count(), - Core::HID::NpadStyleIndex::JoyconLeft); + Settings::ControllerType::LeftJoycon); emulated_controllers[player_index]->addItem(tr("Left Joycon")); pairs.emplace_back(emulated_controllers[player_index]->count(), - Core::HID::NpadStyleIndex::JoyconRight); + Settings::ControllerType::RightJoycon); emulated_controllers[player_index]->addItem(tr("Right Joycon")); if (player_index == 0) { pairs.emplace_back(emulated_controllers[player_index]->count(), - Core::HID::NpadStyleIndex::Handheld); + Settings::ControllerType::Handheld); emulated_controllers[player_index]->addItem(tr("Handheld")); } pairs.emplace_back(emulated_controllers[player_index]->count(), - Core::HID::NpadStyleIndex::GameCube); + Settings::ControllerType::GameCube); emulated_controllers[player_index]->addItem(tr("GameCube Controller")); } -Core::HID::NpadStyleIndex QtControllerSelectorDialog::GetControllerTypeFromIndex( +Settings::ControllerType QtControllerSelectorDialog::GetControllerTypeFromIndex( int index, std::size_t player_index) const { const auto& pairs = index_controller_type_pairs[player_index]; @@ -436,13 +449,13 @@ Core::HID::NpadStyleIndex QtControllerSelectorDialog::GetControllerTypeFromIndex [index](const auto& pair) { return pair.first == index; }); if (it == pairs.end()) { - return Core::HID::NpadStyleIndex::ProController; + return Settings::ControllerType::ProController; } return it->second; } -int QtControllerSelectorDialog::GetIndexFromControllerType(Core::HID::NpadStyleIndex type, +int QtControllerSelectorDialog::GetIndexFromControllerType(Settings::ControllerType type, std::size_t player_index) const { const auto& pairs = index_controller_type_pairs[player_index]; @@ -466,16 +479,16 @@ void QtControllerSelectorDialog::UpdateControllerIcon(std::size_t player_index) const QString stylesheet = [this, player_index] { switch (GetControllerTypeFromIndex(emulated_controllers[player_index]->currentIndex(), player_index)) { - case Core::HID::NpadStyleIndex::ProController: - case Core::HID::NpadStyleIndex::GameCube: + case Settings::ControllerType::ProController: + case Settings::ControllerType::GameCube: return QStringLiteral("image: url(:/controller/applet_pro_controller%0); "); - case Core::HID::NpadStyleIndex::JoyconDual: + case Settings::ControllerType::DualJoyconDetached: return QStringLiteral("image: url(:/controller/applet_dual_joycon%0); "); - case Core::HID::NpadStyleIndex::JoyconLeft: + case Settings::ControllerType::LeftJoycon: return QStringLiteral("image: url(:/controller/applet_joycon_left%0); "); - case Core::HID::NpadStyleIndex::JoyconRight: + case Settings::ControllerType::RightJoycon: return QStringLiteral("image: url(:/controller/applet_joycon_right%0); "); - case Core::HID::NpadStyleIndex::Handheld: + case Settings::ControllerType::Handheld: return QStringLiteral("image: url(:/controller/applet_handheld%0); "); default: return QString{}; @@ -503,42 +516,54 @@ void QtControllerSelectorDialog::UpdateControllerIcon(std::size_t player_index) } void QtControllerSelectorDialog::UpdateControllerState(std::size_t player_index) { - auto* controller = system.HIDCore().GetEmulatedControllerByIndex(player_index); + auto& player = Settings::values.players.GetValue()[player_index]; const auto controller_type = GetControllerTypeFromIndex( emulated_controllers[player_index]->currentIndex(), player_index); const auto player_connected = player_groupboxes[player_index]->isChecked() && - controller_type != Core::HID::NpadStyleIndex::Handheld; + controller_type != Settings::ControllerType::Handheld; - if (controller->GetNpadStyleIndex() == controller_type && - controller->IsConnected() == player_connected) { + if (player.controller_type == controller_type && player.connected == player_connected) { // Set vibration devices in the event that the input device has changed. ConfigureVibration::SetVibrationDevices(player_index); return; } // Disconnect the controller first. - UpdateController(controller, controller_type, false); + UpdateController(controller_type, player_index, false, system); + + player.controller_type = controller_type; + player.connected = player_connected; ConfigureVibration::SetVibrationDevices(player_index); // Handheld if (player_index == 0) { - if (controller_type == Core::HID::NpadStyleIndex::Handheld) { - auto* handheld = - system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld); - UpdateController(handheld, Core::HID::NpadStyleIndex::Handheld, - player_groupboxes[player_index]->isChecked()); + auto& handheld = Settings::values.players.GetValue()[HANDHELD_INDEX]; + if (controller_type == Settings::ControllerType::Handheld) { + handheld = player; } + handheld.connected = player_groupboxes[player_index]->isChecked() && + controller_type == Settings::ControllerType::Handheld; + UpdateController(Settings::ControllerType::Handheld, 8, handheld.connected, system); } - UpdateController(controller, controller_type, player_connected); + if (!player.connected) { + return; + } + + // This emulates a delay between disconnecting and reconnecting controllers as some games + // do not respond to a change in controller type if it was instantaneous. + using namespace std::chrono_literals; + std::this_thread::sleep_for(60ms); + + UpdateController(controller_type, player_index, player_connected, system); } void QtControllerSelectorDialog::UpdateLEDPattern(std::size_t player_index) { if (!player_groupboxes[player_index]->isChecked() || GetControllerTypeFromIndex(emulated_controllers[player_index]->currentIndex(), - player_index) == Core::HID::NpadStyleIndex::Handheld) { + player_index) == Settings::ControllerType::Handheld) { led_patterns_boxes[player_index][0]->setChecked(false); led_patterns_boxes[player_index][1]->setChecked(false); led_patterns_boxes[player_index][2]->setChecked(false); @@ -546,12 +571,10 @@ void QtControllerSelectorDialog::UpdateLEDPattern(std::size_t player_index) { return; } - const auto* controller = system.HIDCore().GetEmulatedControllerByIndex(player_index); - const auto led_pattern = controller->GetLedPattern(); - led_patterns_boxes[player_index][0]->setChecked(led_pattern.position1); - led_patterns_boxes[player_index][1]->setChecked(led_pattern.position2); - led_patterns_boxes[player_index][2]->setChecked(led_pattern.position3); - led_patterns_boxes[player_index][3]->setChecked(led_pattern.position4); + led_patterns_boxes[player_index][0]->setChecked(led_patterns[player_index][0]); + led_patterns_boxes[player_index][1]->setChecked(led_patterns[player_index][1]); + led_patterns_boxes[player_index][2]->setChecked(led_patterns[player_index][2]); + led_patterns_boxes[player_index][3]->setChecked(led_patterns[player_index][3]); } void QtControllerSelectorDialog::UpdateBorderColor(std::size_t player_index) { @@ -631,9 +654,10 @@ void QtControllerSelectorDialog::DisableUnsupportedPlayers() { } for (std::size_t index = max_supported_players; index < NUM_PLAYERS; ++index) { - auto* controller = system.HIDCore().GetEmulatedControllerByIndex(index); // Disconnect any unsupported players here and disable or hide them if applicable. - UpdateController(controller, controller->GetNpadStyleIndex(), false); + Settings::values.players.GetValue()[index].connected = false; + UpdateController(Settings::values.players.GetValue()[index].controller_type, index, false, + system); // Hide the player widgets when max_supported_controllers is less than or equal to 4. if (max_supported_players <= 4) { player_widgets[index]->hide(); diff --git a/src/yuzu/applets/qt_controller.h b/src/yuzu/applets/qt_controller.h index cc343e5ae..037325f50 100755 --- a/src/yuzu/applets/qt_controller.h +++ b/src/yuzu/applets/qt_controller.h @@ -23,18 +23,14 @@ namespace InputCommon { class InputSubsystem; } +namespace Settings { +enum class ControllerType; +} + namespace Ui { class QtControllerSelectorDialog; } -namespace Core { -class System; -} - -namespace Core::HID { -enum class NpadStyleIndex : u8; -} - class QtControllerSelectorDialog final : public QDialog { Q_OBJECT @@ -74,10 +70,10 @@ private: void SetEmulatedControllers(std::size_t player_index); // Gets the Controller Type for a given controller combobox index per player. - Core::HID::NpadStyleIndex GetControllerTypeFromIndex(int index, std::size_t player_index) const; + Settings::ControllerType GetControllerTypeFromIndex(int index, std::size_t player_index) const; // Gets the controller combobox index for a given Controller Type per player. - int GetIndexFromControllerType(Core::HID::NpadStyleIndex type, std::size_t player_index) const; + int GetIndexFromControllerType(Settings::ControllerType type, std::size_t player_index) const; // Updates the controller icons per player. void UpdateControllerIcon(std::size_t player_index); @@ -139,7 +135,7 @@ private: std::array emulated_controllers; /// Pairs of emulated controller index and Controller Type enum per player. - std::array>, NUM_PLAYERS> + std::array>, NUM_PLAYERS> index_controller_type_pairs; // Labels representing the number of connected controllers diff --git a/src/yuzu/applets/qt_software_keyboard.cpp b/src/yuzu/applets/qt_software_keyboard.cpp index de7f98c4f..a83a11a95 100755 --- a/src/yuzu/applets/qt_software_keyboard.cpp +++ b/src/yuzu/applets/qt_software_keyboard.cpp @@ -10,10 +10,7 @@ #include "common/settings.h" #include "common/string_util.h" #include "core/core.h" -#include "core/hid/emulated_controller.h" -#include "core/hid/hid_core.h" -#include "core/hid/hid_types.h" -#include "core/hid/input_interpreter.h" +#include "core/frontend/input_interpreter.h" #include "ui_qt_software_keyboard.h" #include "yuzu/applets/qt_software_keyboard.h" #include "yuzu/main.h" @@ -487,7 +484,7 @@ void QtSoftwareKeyboardDialog::open() { void QtSoftwareKeyboardDialog::reject() { // Pressing the ESC key in a dialog calls QDialog::reject(). // We will override this behavior to the "Cancel" action on the software keyboard. - TranslateButtonPress(Core::HID::NpadButton::X); + TranslateButtonPress(HIDButton::X); } void QtSoftwareKeyboardDialog::keyPressEvent(QKeyEvent* event) { @@ -725,7 +722,7 @@ void QtSoftwareKeyboardDialog::SetTextDrawType() { connect( ui->line_edit_osk, &QLineEdit::returnPressed, this, - [this] { TranslateButtonPress(Core::HID::NpadButton::Plus); }, Qt::QueuedConnection); + [this] { TranslateButtonPress(HIDButton::Plus); }, Qt::QueuedConnection); ui->line_edit_osk->setPlaceholderText( QString::fromStdU16String(initialize_parameters.guide_text)); @@ -798,10 +795,9 @@ void QtSoftwareKeyboardDialog::SetTextDrawType() { } void QtSoftwareKeyboardDialog::SetControllerImage() { - const auto* handheld = system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld); - const auto* player_1 = system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); - const auto controller_type = - handheld->IsConnected() ? handheld->GetNpadStyleIndex() : player_1->GetNpadStyleIndex(); + const auto controller_type = Settings::values.players.GetValue()[8].connected + ? Settings::values.players.GetValue()[8].controller_type + : Settings::values.players.GetValue()[0].controller_type; const QString theme = [] { if (QIcon::themeName().contains(QStringLiteral("dark")) || @@ -813,8 +809,8 @@ void QtSoftwareKeyboardDialog::SetControllerImage() { }(); switch (controller_type) { - case Core::HID::NpadStyleIndex::ProController: - case Core::HID::NpadStyleIndex::GameCube: + case Settings::ControllerType::ProController: + case Settings::ControllerType::GameCube: ui->icon_controller->setStyleSheet( QStringLiteral("image: url(:/overlay/controller_pro%1.png);").arg(theme)); ui->icon_controller_shift->setStyleSheet( @@ -822,7 +818,7 @@ void QtSoftwareKeyboardDialog::SetControllerImage() { ui->icon_controller_num->setStyleSheet( QStringLiteral("image: url(:/overlay/controller_pro%1.png);").arg(theme)); break; - case Core::HID::NpadStyleIndex::JoyconDual: + case Settings::ControllerType::DualJoyconDetached: ui->icon_controller->setStyleSheet( QStringLiteral("image: url(:/overlay/controller_dual_joycon%1.png);").arg(theme)); ui->icon_controller_shift->setStyleSheet( @@ -830,7 +826,7 @@ void QtSoftwareKeyboardDialog::SetControllerImage() { ui->icon_controller_num->setStyleSheet( QStringLiteral("image: url(:/overlay/controller_dual_joycon%1.png);").arg(theme)); break; - case Core::HID::NpadStyleIndex::JoyconLeft: + case Settings::ControllerType::LeftJoycon: ui->icon_controller->setStyleSheet( QStringLiteral("image: url(:/overlay/controller_single_joycon_left%1.png);") .arg(theme)); @@ -841,7 +837,7 @@ void QtSoftwareKeyboardDialog::SetControllerImage() { QStringLiteral("image: url(:/overlay/controller_single_joycon_left%1.png);") .arg(theme)); break; - case Core::HID::NpadStyleIndex::JoyconRight: + case Settings::ControllerType::RightJoycon: ui->icon_controller->setStyleSheet( QStringLiteral("image: url(:/overlay/controller_single_joycon_right%1.png);") .arg(theme)); @@ -852,7 +848,7 @@ void QtSoftwareKeyboardDialog::SetControllerImage() { QStringLiteral("image: url(:/overlay/controller_single_joycon_right%1.png);") .arg(theme)); break; - case Core::HID::NpadStyleIndex::Handheld: + case Settings::ControllerType::Handheld: ui->icon_controller->setStyleSheet( QStringLiteral("image: url(:/overlay/controller_handheld%1.png);").arg(theme)); ui->icon_controller_shift->setStyleSheet( @@ -1212,9 +1208,9 @@ void QtSoftwareKeyboardDialog::SetupMouseHover() { } } -template +template void QtSoftwareKeyboardDialog::HandleButtonPressedOnce() { - const auto f = [this](Core::HID::NpadButton button) { + const auto f = [this](HIDButton button) { if (input_interpreter->IsButtonPressedOnce(button)) { TranslateButtonPress(button); } @@ -1223,9 +1219,9 @@ void QtSoftwareKeyboardDialog::HandleButtonPressedOnce() { (f(T), ...); } -template +template void QtSoftwareKeyboardDialog::HandleButtonHold() { - const auto f = [this](Core::HID::NpadButton button) { + const auto f = [this](HIDButton button) { if (input_interpreter->IsButtonHeld(button)) { TranslateButtonPress(button); } @@ -1234,9 +1230,9 @@ void QtSoftwareKeyboardDialog::HandleButtonHold() { (f(T), ...); } -void QtSoftwareKeyboardDialog::TranslateButtonPress(Core::HID::NpadButton button) { +void QtSoftwareKeyboardDialog::TranslateButtonPress(HIDButton button) { switch (button) { - case Core::HID::NpadButton::A: + case HIDButton::A: switch (bottom_osk_index) { case BottomOSKIndex::LowerCase: case BottomOSKIndex::UpperCase: @@ -1249,7 +1245,7 @@ void QtSoftwareKeyboardDialog::TranslateButtonPress(Core::HID::NpadButton button break; } break; - case Core::HID::NpadButton::B: + case HIDButton::B: switch (bottom_osk_index) { case BottomOSKIndex::LowerCase: ui->button_backspace->click(); @@ -1264,7 +1260,7 @@ void QtSoftwareKeyboardDialog::TranslateButtonPress(Core::HID::NpadButton button break; } break; - case Core::HID::NpadButton::X: + case HIDButton::X: if (is_inline) { emit SubmitInlineText(SwkbdReplyType::DecidedCancel, current_text, cursor_position); } else { @@ -1275,7 +1271,7 @@ void QtSoftwareKeyboardDialog::TranslateButtonPress(Core::HID::NpadButton button emit SubmitNormalText(SwkbdResult::Cancel, std::move(text)); } break; - case Core::HID::NpadButton::Y: + case HIDButton::Y: switch (bottom_osk_index) { case BottomOSKIndex::LowerCase: ui->button_space->click(); @@ -1288,8 +1284,8 @@ void QtSoftwareKeyboardDialog::TranslateButtonPress(Core::HID::NpadButton button break; } break; - case Core::HID::NpadButton::StickL: - case Core::HID::NpadButton::StickR: + case HIDButton::LStick: + case HIDButton::RStick: switch (bottom_osk_index) { case BottomOSKIndex::LowerCase: ui->button_shift->click(); @@ -1302,13 +1298,13 @@ void QtSoftwareKeyboardDialog::TranslateButtonPress(Core::HID::NpadButton button break; } break; - case Core::HID::NpadButton::L: + case HIDButton::L: MoveTextCursorDirection(Direction::Left); break; - case Core::HID::NpadButton::R: + case HIDButton::R: MoveTextCursorDirection(Direction::Right); break; - case Core::HID::NpadButton::Plus: + case HIDButton::Plus: switch (bottom_osk_index) { case BottomOSKIndex::LowerCase: ui->button_ok->click(); @@ -1323,24 +1319,24 @@ void QtSoftwareKeyboardDialog::TranslateButtonPress(Core::HID::NpadButton button break; } break; - case Core::HID::NpadButton::Left: - case Core::HID::NpadButton::StickLLeft: - case Core::HID::NpadButton::StickRLeft: + case HIDButton::DLeft: + case HIDButton::LStickLeft: + case HIDButton::RStickLeft: MoveButtonDirection(Direction::Left); break; - case Core::HID::NpadButton::Up: - case Core::HID::NpadButton::StickLUp: - case Core::HID::NpadButton::StickRUp: + case HIDButton::DUp: + case HIDButton::LStickUp: + case HIDButton::RStickUp: MoveButtonDirection(Direction::Up); break; - case Core::HID::NpadButton::Right: - case Core::HID::NpadButton::StickLRight: - case Core::HID::NpadButton::StickRRight: + case HIDButton::DRight: + case HIDButton::LStickRight: + case HIDButton::RStickRight: MoveButtonDirection(Direction::Right); break; - case Core::HID::NpadButton::Down: - case Core::HID::NpadButton::StickLDown: - case Core::HID::NpadButton::StickRDown: + case HIDButton::DDown: + case HIDButton::LStickDown: + case HIDButton::RStickDown: MoveButtonDirection(Direction::Down); break; default: @@ -1471,25 +1467,19 @@ void QtSoftwareKeyboardDialog::InputThread() { while (input_thread_running) { input_interpreter->PollInput(); - HandleButtonPressedOnce< - Core::HID::NpadButton::A, Core::HID::NpadButton::B, Core::HID::NpadButton::X, - Core::HID::NpadButton::Y, Core::HID::NpadButton::StickL, Core::HID::NpadButton::StickR, - Core::HID::NpadButton::L, Core::HID::NpadButton::R, Core::HID::NpadButton::Plus, - Core::HID::NpadButton::Left, Core::HID::NpadButton::Up, Core::HID::NpadButton::Right, - Core::HID::NpadButton::Down, Core::HID::NpadButton::StickLLeft, - Core::HID::NpadButton::StickLUp, Core::HID::NpadButton::StickLRight, - Core::HID::NpadButton::StickLDown, Core::HID::NpadButton::StickRLeft, - Core::HID::NpadButton::StickRUp, Core::HID::NpadButton::StickRRight, - Core::HID::NpadButton::StickRDown>(); + HandleButtonPressedOnce(); - HandleButtonHold(); + HandleButtonHold(); std::this_thread::sleep_for(std::chrono::milliseconds(50)); } diff --git a/src/yuzu/applets/qt_software_keyboard.h b/src/yuzu/applets/qt_software_keyboard.h index b030cdcf7..592d9c085 100755 --- a/src/yuzu/applets/qt_software_keyboard.h +++ b/src/yuzu/applets/qt_software_keyboard.h @@ -14,16 +14,14 @@ #include "core/frontend/applets/software_keyboard.h" +enum class HIDButton : u8; + class InputInterpreter; namespace Core { class System; } -namespace Core::HID { -enum class NpadButton : u64; -} - namespace Ui { class QtSoftwareKeyboardDialog; } @@ -148,7 +146,7 @@ private: * * @tparam HIDButton The list of buttons that can be converted into keyboard input. */ - template + template void HandleButtonPressedOnce(); /** @@ -156,7 +154,7 @@ private: * * @tparam HIDButton The list of buttons that can be converted into keyboard input. */ - template + template void HandleButtonHold(); /** @@ -164,7 +162,7 @@ private: * * @param button The button press to process. */ - void TranslateButtonPress(Core::HID::NpadButton button); + void TranslateButtonPress(HIDButton button); /** * Moves the focus of a button in a certain direction. diff --git a/src/yuzu/applets/qt_web_browser.cpp b/src/yuzu/applets/qt_web_browser.cpp index cb3c5d826..da8c6882a 100755 --- a/src/yuzu/applets/qt_web_browser.cpp +++ b/src/yuzu/applets/qt_web_browser.cpp @@ -14,11 +14,9 @@ #endif #include "common/fs/path_util.h" -#include "common/param_package.h" #include "core/core.h" -#include "core/hid/hid_types.h" -#include "core/hid/input_interpreter.h" -#include "input_common/drivers/keyboard.h" +#include "core/frontend/input_interpreter.h" +#include "input_common/keyboard.h" #include "input_common/main.h" #include "yuzu/applets/qt_web_browser.h" #include "yuzu/applets/qt_web_browser_scripts.h" @@ -29,19 +27,19 @@ namespace { -constexpr int HIDButtonToKey(Core::HID::NpadButton button) { +constexpr int HIDButtonToKey(HIDButton button) { switch (button) { - case Core::HID::NpadButton::Left: - case Core::HID::NpadButton::StickLLeft: + case HIDButton::DLeft: + case HIDButton::LStickLeft: return Qt::Key_Left; - case Core::HID::NpadButton::Up: - case Core::HID::NpadButton::StickLUp: + case HIDButton::DUp: + case HIDButton::LStickUp: return Qt::Key_Up; - case Core::HID::NpadButton::Right: - case Core::HID::NpadButton::StickLRight: + case HIDButton::DRight: + case HIDButton::LStickRight: return Qt::Key_Right; - case Core::HID::NpadButton::Down: - case Core::HID::NpadButton::StickLDown: + case HIDButton::DDown: + case HIDButton::LStickDown: return Qt::Key_Down; default: return 0; @@ -210,25 +208,25 @@ void QtNXWebEngineView::keyReleaseEvent(QKeyEvent* event) { } } -template +template void QtNXWebEngineView::HandleWindowFooterButtonPressedOnce() { - const auto f = [this](Core::HID::NpadButton button) { + const auto f = [this](HIDButton button) { if (input_interpreter->IsButtonPressedOnce(button)) { page()->runJavaScript( QStringLiteral("yuzu_key_callbacks[%1] == null;").arg(static_cast(button)), [this, button](const QVariant& variant) { if (variant.toBool()) { switch (button) { - case Core::HID::NpadButton::A: + case HIDButton::A: SendMultipleKeyPressEvents(); break; - case Core::HID::NpadButton::B: + case HIDButton::B: SendKeyPressEvent(Qt::Key_B); break; - case Core::HID::NpadButton::X: + case HIDButton::X: SendKeyPressEvent(Qt::Key_X); break; - case Core::HID::NpadButton::Y: + case HIDButton::Y: SendKeyPressEvent(Qt::Key_Y); break; default: @@ -246,9 +244,9 @@ void QtNXWebEngineView::HandleWindowFooterButtonPressedOnce() { (f(T), ...); } -template +template void QtNXWebEngineView::HandleWindowKeyButtonPressedOnce() { - const auto f = [this](Core::HID::NpadButton button) { + const auto f = [this](HIDButton button) { if (input_interpreter->IsButtonPressedOnce(button)) { SendKeyPressEvent(HIDButtonToKey(button)); } @@ -257,9 +255,9 @@ void QtNXWebEngineView::HandleWindowKeyButtonPressedOnce() { (f(T), ...); } -template +template void QtNXWebEngineView::HandleWindowKeyButtonHold() { - const auto f = [this](Core::HID::NpadButton button) { + const auto f = [this](HIDButton button) { if (input_interpreter->IsButtonHeld(button)) { SendKeyPressEvent(HIDButtonToKey(button)); } @@ -310,21 +308,17 @@ void QtNXWebEngineView::InputThread() { while (input_thread_running) { input_interpreter->PollInput(); - HandleWindowFooterButtonPressedOnce(); + HandleWindowFooterButtonPressedOnce(); - HandleWindowKeyButtonPressedOnce< - Core::HID::NpadButton::Left, Core::HID::NpadButton::Up, Core::HID::NpadButton::Right, - Core::HID::NpadButton::Down, Core::HID::NpadButton::StickLLeft, - Core::HID::NpadButton::StickLUp, Core::HID::NpadButton::StickLRight, - Core::HID::NpadButton::StickLDown>(); + HandleWindowKeyButtonPressedOnce(); - HandleWindowKeyButtonHold< - Core::HID::NpadButton::Left, Core::HID::NpadButton::Up, Core::HID::NpadButton::Right, - Core::HID::NpadButton::Down, Core::HID::NpadButton::StickLLeft, - Core::HID::NpadButton::StickLUp, Core::HID::NpadButton::StickLRight, - Core::HID::NpadButton::StickLDown>(); + HandleWindowKeyButtonHold(); std::this_thread::sleep_for(std::chrono::milliseconds(50)); } diff --git a/src/yuzu/applets/qt_web_browser.h b/src/yuzu/applets/qt_web_browser.h index fa18aecac..7e9f703fc 100755 --- a/src/yuzu/applets/qt_web_browser.h +++ b/src/yuzu/applets/qt_web_browser.h @@ -16,6 +16,8 @@ #include "core/frontend/applets/web_browser.h" +enum class HIDButton : u8; + class GMainWindow; class InputInterpreter; class UrlRequestInterceptor; @@ -24,10 +26,6 @@ namespace Core { class System; } -namespace Core::HID { -enum class NpadButton : u64; -} - namespace InputCommon { class InputSubsystem; } @@ -116,7 +114,7 @@ private: * * @tparam HIDButton The list of buttons contained in yuzu_key_callbacks */ - template + template void HandleWindowFooterButtonPressedOnce(); /** @@ -125,7 +123,7 @@ private: * * @tparam HIDButton The list of buttons that can be converted into keyboard input. */ - template + template void HandleWindowKeyButtonPressedOnce(); /** @@ -134,7 +132,7 @@ private: * * @tparam HIDButton The list of buttons that can be converted into keyboard input. */ - template + template void HandleWindowKeyButtonHold(); /** diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index f12312ab9..976acd176 100755 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -32,11 +32,10 @@ #include "common/settings.h" #include "core/core.h" #include "core/frontend/framebuffer_layout.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/keyboard.h" #include "input_common/main.h" +#include "input_common/mouse/mouse_input.h" +#include "input_common/tas/tas_input.h" #include "video_core/renderer_base.h" #include "video_core/video_core.h" #include "yuzu/bootmanager.h" @@ -297,6 +296,7 @@ GRenderWindow::GRenderWindow(GMainWindow* parent, EmuThread* emu_thread_, layout->setContentsMargins(0, 0, 0, 0); setLayout(layout); input_subsystem->Initialize(); + this->setMouseTracking(true); connect(this, &GRenderWindow::FirstFrameDisplayed, parent, &GMainWindow::OnLoadComplete); @@ -383,306 +383,34 @@ void GRenderWindow::closeEvent(QCloseEvent* event) { QWidget::closeEvent(event); } -int GRenderWindow::QtKeyToSwitchKey(Qt::Key qt_key) { - switch (qt_key) { - case Qt::Key_A: - return Settings::NativeKeyboard::A; - case Qt::Key_B: - return Settings::NativeKeyboard::B; - case Qt::Key_C: - return Settings::NativeKeyboard::C; - case Qt::Key_D: - return Settings::NativeKeyboard::D; - case Qt::Key_E: - return Settings::NativeKeyboard::E; - case Qt::Key_F: - return Settings::NativeKeyboard::F; - case Qt::Key_G: - return Settings::NativeKeyboard::G; - case Qt::Key_H: - return Settings::NativeKeyboard::H; - case Qt::Key_I: - return Settings::NativeKeyboard::I; - case Qt::Key_J: - return Settings::NativeKeyboard::J; - case Qt::Key_K: - return Settings::NativeKeyboard::K; - case Qt::Key_L: - return Settings::NativeKeyboard::L; - case Qt::Key_M: - return Settings::NativeKeyboard::M; - case Qt::Key_N: - return Settings::NativeKeyboard::N; - case Qt::Key_O: - return Settings::NativeKeyboard::O; - case Qt::Key_P: - return Settings::NativeKeyboard::P; - case Qt::Key_Q: - return Settings::NativeKeyboard::Q; - case Qt::Key_R: - return Settings::NativeKeyboard::R; - case Qt::Key_S: - return Settings::NativeKeyboard::S; - case Qt::Key_T: - return Settings::NativeKeyboard::T; - case Qt::Key_U: - return Settings::NativeKeyboard::U; - case Qt::Key_V: - return Settings::NativeKeyboard::V; - case Qt::Key_W: - return Settings::NativeKeyboard::W; - case Qt::Key_X: - return Settings::NativeKeyboard::X; - case Qt::Key_Y: - return Settings::NativeKeyboard::Y; - case Qt::Key_Z: - return Settings::NativeKeyboard::Z; - case Qt::Key_1: - return Settings::NativeKeyboard::N1; - case Qt::Key_2: - return Settings::NativeKeyboard::N2; - case Qt::Key_3: - return Settings::NativeKeyboard::N3; - case Qt::Key_4: - return Settings::NativeKeyboard::N4; - case Qt::Key_5: - return Settings::NativeKeyboard::N5; - case Qt::Key_6: - return Settings::NativeKeyboard::N6; - case Qt::Key_7: - return Settings::NativeKeyboard::N7; - case Qt::Key_8: - return Settings::NativeKeyboard::N8; - case Qt::Key_9: - return Settings::NativeKeyboard::N9; - case Qt::Key_0: - return Settings::NativeKeyboard::N0; - case Qt::Key_Return: - return Settings::NativeKeyboard::Return; - case Qt::Key_Escape: - return Settings::NativeKeyboard::Escape; - case Qt::Key_Backspace: - return Settings::NativeKeyboard::Backspace; - case Qt::Key_Tab: - return Settings::NativeKeyboard::Tab; - case Qt::Key_Space: - return Settings::NativeKeyboard::Space; - case Qt::Key_Minus: - return Settings::NativeKeyboard::Minus; - case Qt::Key_Plus: - case Qt::Key_questiondown: - return Settings::NativeKeyboard::Plus; - case Qt::Key_BracketLeft: - case Qt::Key_BraceLeft: - return Settings::NativeKeyboard::OpenBracket; - case Qt::Key_BracketRight: - case Qt::Key_BraceRight: - return Settings::NativeKeyboard::CloseBracket; - case Qt::Key_Bar: - return Settings::NativeKeyboard::Pipe; - case Qt::Key_Dead_Tilde: - return Settings::NativeKeyboard::Tilde; - case Qt::Key_Ntilde: - case Qt::Key_Semicolon: - return Settings::NativeKeyboard::Semicolon; - case Qt::Key_Apostrophe: - return Settings::NativeKeyboard::Quote; - case Qt::Key_Dead_Grave: - return Settings::NativeKeyboard::Backquote; - case Qt::Key_Comma: - return Settings::NativeKeyboard::Comma; - case Qt::Key_Period: - return Settings::NativeKeyboard::Period; - case Qt::Key_Slash: - return Settings::NativeKeyboard::Slash; - case Qt::Key_CapsLock: - return Settings::NativeKeyboard::CapsLock; - case Qt::Key_F1: - return Settings::NativeKeyboard::F1; - case Qt::Key_F2: - return Settings::NativeKeyboard::F2; - case Qt::Key_F3: - return Settings::NativeKeyboard::F3; - case Qt::Key_F4: - return Settings::NativeKeyboard::F4; - case Qt::Key_F5: - return Settings::NativeKeyboard::F5; - case Qt::Key_F6: - return Settings::NativeKeyboard::F6; - case Qt::Key_F7: - return Settings::NativeKeyboard::F7; - case Qt::Key_F8: - return Settings::NativeKeyboard::F8; - case Qt::Key_F9: - return Settings::NativeKeyboard::F9; - case Qt::Key_F10: - return Settings::NativeKeyboard::F10; - case Qt::Key_F11: - return Settings::NativeKeyboard::F11; - case Qt::Key_F12: - return Settings::NativeKeyboard::F12; - case Qt::Key_Print: - return Settings::NativeKeyboard::PrintScreen; - case Qt::Key_ScrollLock: - return Settings::NativeKeyboard::ScrollLock; - case Qt::Key_Pause: - return Settings::NativeKeyboard::Pause; - case Qt::Key_Insert: - return Settings::NativeKeyboard::Insert; - case Qt::Key_Home: - return Settings::NativeKeyboard::Home; - case Qt::Key_PageUp: - return Settings::NativeKeyboard::PageUp; - case Qt::Key_Delete: - return Settings::NativeKeyboard::Delete; - case Qt::Key_End: - return Settings::NativeKeyboard::End; - case Qt::Key_PageDown: - return Settings::NativeKeyboard::PageDown; - case Qt::Key_Right: - return Settings::NativeKeyboard::Right; - case Qt::Key_Left: - return Settings::NativeKeyboard::Left; - case Qt::Key_Down: - return Settings::NativeKeyboard::Down; - case Qt::Key_Up: - return Settings::NativeKeyboard::Up; - case Qt::Key_NumLock: - return Settings::NativeKeyboard::NumLock; - // Numpad keys are missing here - case Qt::Key_F13: - return Settings::NativeKeyboard::F13; - case Qt::Key_F14: - return Settings::NativeKeyboard::F14; - case Qt::Key_F15: - return Settings::NativeKeyboard::F15; - case Qt::Key_F16: - return Settings::NativeKeyboard::F16; - case Qt::Key_F17: - return Settings::NativeKeyboard::F17; - case Qt::Key_F18: - return Settings::NativeKeyboard::F18; - case Qt::Key_F19: - return Settings::NativeKeyboard::F19; - case Qt::Key_F20: - return Settings::NativeKeyboard::F20; - case Qt::Key_F21: - return Settings::NativeKeyboard::F21; - case Qt::Key_F22: - return Settings::NativeKeyboard::F22; - case Qt::Key_F23: - return Settings::NativeKeyboard::F23; - case Qt::Key_F24: - return Settings::NativeKeyboard::F24; - // case Qt::: - // return Settings::NativeKeyboard::KPComma; - // case Qt::: - // return Settings::NativeKeyboard::Ro; - case Qt::Key_Hiragana_Katakana: - return Settings::NativeKeyboard::KatakanaHiragana; - case Qt::Key_yen: - return Settings::NativeKeyboard::Yen; - case Qt::Key_Henkan: - return Settings::NativeKeyboard::Henkan; - case Qt::Key_Muhenkan: - return Settings::NativeKeyboard::Muhenkan; - // case Qt::: - // return Settings::NativeKeyboard::NumPadCommaPc98; - case Qt::Key_Hangul: - return Settings::NativeKeyboard::HangulEnglish; - case Qt::Key_Hangul_Hanja: - return Settings::NativeKeyboard::Hanja; - case Qt::Key_Katakana: - return Settings::NativeKeyboard::KatakanaKey; - case Qt::Key_Hiragana: - return Settings::NativeKeyboard::HiraganaKey; - case Qt::Key_Zenkaku_Hankaku: - return Settings::NativeKeyboard::ZenkakuHankaku; - // Modifier keys are handled by the modifier property - default: - return 0; - } -} - -int GRenderWindow::QtModifierToSwitchModdifier(quint32 qt_moddifiers) { - int moddifier = 0; - // The values are obtained through testing, Qt doesn't seem to provide a proper enum - if ((qt_moddifiers & 0x1) != 0) { - moddifier |= 1 << Settings::NativeKeyboard::LeftShift; - } - if ((qt_moddifiers & 0x2) != 0) { - moddifier |= 1 << Settings::NativeKeyboard::LeftControl; - } - if ((qt_moddifiers & 0x4) != 0) { - moddifier |= 1 << Settings::NativeKeyboard::LeftAlt; - } - if ((qt_moddifiers & 0x08) != 0) { - moddifier |= 1 << Settings::NativeKeyboard::LeftMeta; - } - if ((qt_moddifiers & 0x10) != 0) { - moddifier |= 1 << Settings::NativeKeyboard::RightShift; - } - if ((qt_moddifiers & 0x20) != 0) { - moddifier |= 1 << Settings::NativeKeyboard::RightControl; - } - if ((qt_moddifiers & 0x40) != 0) { - moddifier |= 1 << Settings::NativeKeyboard::RightAlt; - } - if ((qt_moddifiers & 0x80) != 0) { - moddifier |= 1 << Settings::NativeKeyboard::RightMeta; - } - if ((qt_moddifiers & 0x100) != 0) { - moddifier |= 1 << Settings::NativeKeyboard::CapsLock; - } - if ((qt_moddifiers & 0x200) != 0) { - moddifier |= 1 << Settings::NativeKeyboard::NumLock; - } - // Verify the last two keys - if ((qt_moddifiers & 0x400) != 0) { - moddifier |= 1 << Settings::NativeKeyboard::Katakana; - } - if ((qt_moddifiers & 0x800) != 0) { - moddifier |= 1 << Settings::NativeKeyboard::Hiragana; - } - return moddifier; -} - void GRenderWindow::keyPressEvent(QKeyEvent* event) { if (!event->isAutoRepeat()) { - const auto moddifier = QtModifierToSwitchModdifier(event->nativeModifiers()); - // Replace event->key() with event->nativeVirtualKey() since the second one provides raw key - // buttons - const auto key = QtKeyToSwitchKey(Qt::Key(event->key())); - input_subsystem->GetKeyboard()->SetModifiers(moddifier); - input_subsystem->GetKeyboard()->PressKey(key); + input_subsystem->GetKeyboard()->PressKey(event->key()); } } void GRenderWindow::keyReleaseEvent(QKeyEvent* event) { if (!event->isAutoRepeat()) { - const auto moddifier = QtModifierToSwitchModdifier(event->nativeModifiers()); - const auto key = QtKeyToSwitchKey(Qt::Key(event->key())); - input_subsystem->GetKeyboard()->SetModifiers(moddifier); - input_subsystem->GetKeyboard()->ReleaseKey(key); + input_subsystem->GetKeyboard()->ReleaseKey(event->key()); } } -InputCommon::MouseButton GRenderWindow::QtButtonToMouseButton(Qt::MouseButton button) { +MouseInput::MouseButton GRenderWindow::QtButtonToMouseButton(Qt::MouseButton button) { switch (button) { case Qt::LeftButton: - return InputCommon::MouseButton::Left; + return MouseInput::MouseButton::Left; case Qt::RightButton: - return InputCommon::MouseButton::Right; + return MouseInput::MouseButton::Right; case Qt::MiddleButton: - return InputCommon::MouseButton::Wheel; + return MouseInput::MouseButton::Wheel; case Qt::BackButton: - return InputCommon::MouseButton::Backward; + return MouseInput::MouseButton::Backward; case Qt::ForwardButton: - return InputCommon::MouseButton::Forward; + return MouseInput::MouseButton::Forward; case Qt::TaskButton: - return InputCommon::MouseButton::Task; + return MouseInput::MouseButton::Task; default: - return InputCommon::MouseButton::Extra; + return MouseInput::MouseButton::Extra; } } @@ -695,9 +423,12 @@ void GRenderWindow::mousePressEvent(QMouseEvent* event) { // coordinates and map them to the current render area const auto pos = mapFromGlobal(QCursor::pos()); const auto [x, y] = ScaleTouch(pos); - const auto [touch_x, touch_y] = MapToTouchScreen(x, y); const auto button = QtButtonToMouseButton(event->button()); - input_subsystem->GetMouse()->PressButton(x, y, touch_x, touch_y, button); + input_subsystem->GetMouse()->PressButton(x, y, button); + + if (event->button() == Qt::LeftButton) { + this->TouchPressed(x, y, 0); + } emit MouseActivity(); } @@ -711,10 +442,10 @@ void GRenderWindow::mouseMoveEvent(QMouseEvent* event) { // coordinates and map them to the current render area const auto pos = mapFromGlobal(QCursor::pos()); const auto [x, y] = ScaleTouch(pos); - const auto [touch_x, touch_y] = MapToTouchScreen(x, y); const int center_x = width() / 2; const int center_y = height() / 2; - input_subsystem->GetMouse()->MouseMove(x, y, touch_x, touch_y, center_x, center_y); + input_subsystem->GetMouse()->MouseMove(x, y, center_x, center_y); + this->TouchMoved(x, y, 0); if (Settings::values.mouse_panning) { QCursor::setPos(mapToGlobal({center_x, center_y})); @@ -731,6 +462,10 @@ void GRenderWindow::mouseReleaseEvent(QMouseEvent* event) { const auto button = QtButtonToMouseButton(event->button()); input_subsystem->GetMouse()->ReleaseButton(button); + + if (event->button() == Qt::LeftButton) { + this->TouchReleased(0); + } } void GRenderWindow::TouchBeginEvent(const QTouchEvent* event) { @@ -753,7 +488,7 @@ void GRenderWindow::TouchUpdateEvent(const QTouchEvent* event) { for (std::size_t id = 0; id < touch_ids.size(); ++id) { if (!TouchExist(touch_ids[id], touch_points)) { touch_ids[id] = 0; - input_subsystem->GetTouchScreen()->TouchReleased(id); + this->TouchReleased(id + 1); } } } @@ -762,28 +497,28 @@ void GRenderWindow::TouchEndEvent() { for (std::size_t id = 0; id < touch_ids.size(); ++id) { if (touch_ids[id] != 0) { touch_ids[id] = 0; - input_subsystem->GetTouchScreen()->TouchReleased(id); + this->TouchReleased(id + 1); } } } -void GRenderWindow::TouchStart(const QTouchEvent::TouchPoint& touch_point) { +bool GRenderWindow::TouchStart(const QTouchEvent::TouchPoint& touch_point) { for (std::size_t id = 0; id < touch_ids.size(); ++id) { if (touch_ids[id] == 0) { touch_ids[id] = touch_point.id() + 1; const auto [x, y] = ScaleTouch(touch_point.pos()); - const auto [touch_x, touch_y] = MapToTouchScreen(x, y); - input_subsystem->GetTouchScreen()->TouchPressed(touch_x, touch_y, id); + this->TouchPressed(x, y, id + 1); + return true; } } + return false; } bool GRenderWindow::TouchUpdate(const QTouchEvent::TouchPoint& touch_point) { for (std::size_t id = 0; id < touch_ids.size(); ++id) { if (touch_ids[id] == static_cast(touch_point.id() + 1)) { const auto [x, y] = ScaleTouch(touch_point.pos()); - const auto [touch_x, touch_y] = MapToTouchScreen(x, y); - input_subsystem->GetTouchScreen()->TouchMoved(touch_x, touch_y, id); + this->TouchMoved(x, y, id + 1); return true; } } @@ -816,7 +551,7 @@ void GRenderWindow::focusOutEvent(QFocusEvent* event) { QWidget::focusOutEvent(event); input_subsystem->GetKeyboard()->ReleaseAllKeys(); input_subsystem->GetMouse()->ReleaseAllButtons(); - input_subsystem->GetTouchScreen()->ReleaseAllTouch(); + this->TouchReleased(0); } void GRenderWindow::resizeEvent(QResizeEvent* event) { diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h index 8f8091b71..40fd4a9d6 100755 --- a/src/yuzu/bootmanager.h +++ b/src/yuzu/bootmanager.h @@ -30,8 +30,11 @@ class System; namespace InputCommon { class InputSubsystem; +} + +namespace MouseInput { enum class MouseButton; -} // namespace InputCommon +} namespace VideoCore { enum class LoadCallbackStage; @@ -154,17 +157,11 @@ public: void resizeEvent(QResizeEvent* event) override; - /// Converts a Qt keybard key into NativeKeyboard key - static int QtKeyToSwitchKey(Qt::Key qt_keys); - - /// Converts a Qt modifier keys into NativeKeyboard modifier keys - static int QtModifierToSwitchModdifier(quint32 qt_moddifiers); - void keyPressEvent(QKeyEvent* event) override; void keyReleaseEvent(QKeyEvent* event) override; /// Converts a Qt mouse button into MouseInput mouse button - static InputCommon::MouseButton QtButtonToMouseButton(Qt::MouseButton button); + static MouseInput::MouseButton QtButtonToMouseButton(Qt::MouseButton button); void mousePressEvent(QMouseEvent* event) override; void mouseMoveEvent(QMouseEvent* event) override; @@ -212,7 +209,7 @@ private: void TouchUpdateEvent(const QTouchEvent* event); void TouchEndEvent(); - void TouchStart(const QTouchEvent::TouchPoint& touch_point); + bool TouchStart(const QTouchEvent::TouchPoint& touch_point); bool TouchUpdate(const QTouchEvent::TouchPoint& touch_point); bool TouchExist(std::size_t id, const QList& touch_points) const; diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index 0a63ef51e..8227d06bc 100755 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -11,6 +11,7 @@ #include "core/hle/service/acc/profile_manager.h" #include "core/hle/service/hid/controllers/npad.h" #include "input_common/main.h" +#include "input_common/udp/client.h" #include "yuzu/configuration/config.h" namespace FS = Common::FS; @@ -65,6 +66,157 @@ const std::array Config::defa Qt::Key_BracketLeft, Qt::Key_BracketRight, Qt::Key_Apostrophe, Qt::Key_Minus, Qt::Key_Equal, }; +const std::array Config::default_keyboard_keys = { + 0, + 0, + 0, + 0, + Qt::Key_A, + Qt::Key_B, + Qt::Key_C, + Qt::Key_D, + Qt::Key_E, + Qt::Key_F, + Qt::Key_G, + Qt::Key_H, + Qt::Key_I, + Qt::Key_J, + Qt::Key_K, + Qt::Key_L, + Qt::Key_M, + Qt::Key_N, + Qt::Key_O, + Qt::Key_P, + Qt::Key_Q, + Qt::Key_R, + Qt::Key_S, + Qt::Key_T, + Qt::Key_U, + Qt::Key_V, + Qt::Key_W, + Qt::Key_X, + Qt::Key_Y, + Qt::Key_Z, + Qt::Key_1, + Qt::Key_2, + Qt::Key_3, + Qt::Key_4, + Qt::Key_5, + Qt::Key_6, + Qt::Key_7, + Qt::Key_8, + Qt::Key_9, + Qt::Key_0, + Qt::Key_Enter, + Qt::Key_Escape, + Qt::Key_Backspace, + Qt::Key_Tab, + Qt::Key_Space, + Qt::Key_Minus, + Qt::Key_Equal, + Qt::Key_BracketLeft, + Qt::Key_BracketRight, + Qt::Key_Backslash, + Qt::Key_Dead_Tilde, + Qt::Key_Semicolon, + Qt::Key_Apostrophe, + Qt::Key_Dead_Grave, + Qt::Key_Comma, + Qt::Key_Period, + Qt::Key_Slash, + Qt::Key_CapsLock, + + Qt::Key_F1, + Qt::Key_F2, + Qt::Key_F3, + Qt::Key_F4, + Qt::Key_F5, + Qt::Key_F6, + Qt::Key_F7, + Qt::Key_F8, + Qt::Key_F9, + Qt::Key_F10, + Qt::Key_F11, + Qt::Key_F12, + + Qt::Key_SysReq, + Qt::Key_ScrollLock, + Qt::Key_Pause, + Qt::Key_Insert, + Qt::Key_Home, + Qt::Key_PageUp, + Qt::Key_Delete, + Qt::Key_End, + Qt::Key_PageDown, + Qt::Key_Right, + Qt::Key_Left, + Qt::Key_Down, + Qt::Key_Up, + + Qt::Key_NumLock, + Qt::Key_Slash, + Qt::Key_Asterisk, + Qt::Key_Minus, + Qt::Key_Plus, + Qt::Key_Enter, + Qt::Key_1, + Qt::Key_2, + Qt::Key_3, + Qt::Key_4, + Qt::Key_5, + Qt::Key_6, + Qt::Key_7, + Qt::Key_8, + Qt::Key_9, + Qt::Key_0, + Qt::Key_Period, + + 0, + 0, + Qt::Key_PowerOff, + Qt::Key_Equal, + + Qt::Key_F13, + Qt::Key_F14, + Qt::Key_F15, + Qt::Key_F16, + Qt::Key_F17, + Qt::Key_F18, + Qt::Key_F19, + Qt::Key_F20, + Qt::Key_F21, + Qt::Key_F22, + Qt::Key_F23, + Qt::Key_F24, + + Qt::Key_Open, + Qt::Key_Help, + Qt::Key_Menu, + 0, + Qt::Key_Stop, + Qt::Key_AudioRepeat, + Qt::Key_Undo, + Qt::Key_Cut, + Qt::Key_Copy, + Qt::Key_Paste, + Qt::Key_Find, + Qt::Key_VolumeMute, + Qt::Key_VolumeUp, + Qt::Key_VolumeDown, + Qt::Key_CapsLock, + Qt::Key_NumLock, + Qt::Key_ScrollLock, + Qt::Key_Comma, + + Qt::Key_ParenLeft, + Qt::Key_ParenRight, +}; + +const std::array Config::default_keyboard_mods = { + Qt::Key_Control, Qt::Key_Shift, Qt::Key_Alt, Qt::Key_ApplicationLeft, + Qt::Key_Control, Qt::Key_Shift, Qt::Key_AltGr, Qt::Key_ApplicationRight, +}; + // This shouldn't have anything except static initializers (no functions). So // QKeySequence(...).toString() is NOT ALLOWED HERE. // This must be in alphabetical order according to action name as it must have the same order as @@ -345,14 +497,14 @@ void Config::ReadDebugValues() { void Config::ReadKeyboardValues() { ReadBasicSetting(Settings::values.keyboard_enabled); - for (std::size_t i = 0; i < Settings::values.keyboard_keys.size(); ++i) { - Settings::values.keyboard_keys[i] = InputCommon::GenerateKeyboardParam(static_cast(i)); - } - - for (std::size_t i = 0; i < Settings::values.keyboard_mods.size(); ++i) { - Settings::values.keyboard_mods[i] = - InputCommon::GenerateModdifierKeyboardParam(static_cast(i)); - } + std::transform(default_keyboard_keys.begin(), default_keyboard_keys.end(), + Settings::values.keyboard_keys.begin(), InputCommon::GenerateKeyboardParam); + std::transform(default_keyboard_mods.begin(), default_keyboard_mods.end(), + Settings::values.keyboard_keys.begin() + + Settings::NativeKeyboard::LeftControlKey, + InputCommon::GenerateKeyboardParam); + std::transform(default_keyboard_mods.begin(), default_keyboard_mods.end(), + Settings::values.keyboard_mods.begin(), InputCommon::GenerateKeyboardParam); } void Config::ReadMouseValues() { @@ -422,6 +574,7 @@ void Config::ReadControlValues() { ReadBasicSetting(Settings::values.tas_enable); ReadBasicSetting(Settings::values.tas_loop); + ReadBasicSetting(Settings::values.tas_swap_controllers); ReadBasicSetting(Settings::values.pause_tas_on_load); ReadGlobalSetting(Settings::values.use_docked_mode); @@ -472,7 +625,9 @@ void Config::ReadMotionTouchValues() { } qt_config->endArray(); + ReadBasicSetting(Settings::values.motion_device); ReadBasicSetting(Settings::values.touch_device); + ReadBasicSetting(Settings::values.use_touch_from_button); ReadBasicSetting(Settings::values.touch_from_button_map_index); Settings::values.touch_from_button_map_index = std::clamp( Settings::values.touch_from_button_map_index.GetValue(), 0, num_touch_from_button_maps - 1); @@ -978,7 +1133,9 @@ void Config::SaveTouchscreenValues() { } void Config::SaveMotionTouchValues() { + WriteBasicSetting(Settings::values.motion_device); WriteBasicSetting(Settings::values.touch_device); + WriteBasicSetting(Settings::values.use_touch_from_button); WriteBasicSetting(Settings::values.touch_from_button_map_index); WriteBasicSetting(Settings::values.udp_input_servers); @@ -1053,6 +1210,7 @@ void Config::SaveControlValues() { WriteBasicSetting(Settings::values.tas_enable); WriteBasicSetting(Settings::values.tas_loop); + WriteBasicSetting(Settings::values.tas_swap_controllers); WriteBasicSetting(Settings::values.pause_tas_on_load); qt_config->endGroup(); diff --git a/src/yuzu/configuration/configure_debug_controller.cpp b/src/yuzu/configuration/configure_debug_controller.cpp index 9a8de92a1..31ec48384 100755 --- a/src/yuzu/configuration/configure_debug_controller.cpp +++ b/src/yuzu/configuration/configure_debug_controller.cpp @@ -2,18 +2,17 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. -#include "core/hid/hid_core.h" +#include "core/core.h" #include "ui_configure_debug_controller.h" #include "yuzu/configuration/configure_debug_controller.h" #include "yuzu/configuration/configure_input_player.h" ConfigureDebugController::ConfigureDebugController(QWidget* parent, InputCommon::InputSubsystem* input_subsystem, - InputProfiles* profiles, - Core::HID::HIDCore& hid_core, bool is_powered_on) + InputProfiles* profiles, Core::System& system) : QDialog(parent), ui(std::make_unique()), - debug_controller(new ConfigureInputPlayer(this, 9, nullptr, input_subsystem, profiles, - hid_core, is_powered_on, true)) { + debug_controller( + new ConfigureInputPlayer(this, 9, nullptr, input_subsystem, profiles, system, true)) { ui->setupUi(this); ui->controllerLayout->addWidget(debug_controller); diff --git a/src/yuzu/configuration/configure_debug_controller.h b/src/yuzu/configuration/configure_debug_controller.h index d716edbc2..6e17c5aa0 100755 --- a/src/yuzu/configuration/configure_debug_controller.h +++ b/src/yuzu/configuration/configure_debug_controller.h @@ -13,8 +13,8 @@ class ConfigureInputPlayer; class InputProfiles; -namespace Core::HID { -class HIDCore; +namespace Core { +class System; } namespace InputCommon { @@ -30,8 +30,7 @@ class ConfigureDebugController : public QDialog { public: explicit ConfigureDebugController(QWidget* parent, InputCommon::InputSubsystem* input_subsystem, - InputProfiles* profiles, Core::HID::HIDCore& hid_core, - bool is_powered_on); + InputProfiles* profiles, Core::System& system); ~ConfigureDebugController() override; void ApplyConfiguration(); diff --git a/src/yuzu/configuration/configure_input.cpp b/src/yuzu/configuration/configure_input.cpp index 99450bc7d..1599299db 100755 --- a/src/yuzu/configuration/configure_input.cpp +++ b/src/yuzu/configuration/configure_input.cpp @@ -10,8 +10,6 @@ #include #include "core/core.h" -#include "core/hid/emulated_controller.h" -#include "core/hid/hid_core.h" #include "core/hle/service/am/am.h" #include "core/hle/service/am/applet_ae.h" #include "core/hle/service/am/applet_oe.h" @@ -77,25 +75,23 @@ ConfigureInput::~ConfigureInput() = default; void ConfigureInput::Initialize(InputCommon::InputSubsystem* input_subsystem, std::size_t max_players) { - const bool is_powered_on = system.IsPoweredOn(); - auto& hid_core = system.HIDCore(); player_controllers = { new ConfigureInputPlayer(this, 0, ui->consoleInputSettings, input_subsystem, profiles.get(), - hid_core, is_powered_on), + system), new ConfigureInputPlayer(this, 1, ui->consoleInputSettings, input_subsystem, profiles.get(), - hid_core, is_powered_on), + system), new ConfigureInputPlayer(this, 2, ui->consoleInputSettings, input_subsystem, profiles.get(), - hid_core, is_powered_on), + system), new ConfigureInputPlayer(this, 3, ui->consoleInputSettings, input_subsystem, profiles.get(), - hid_core, is_powered_on), + system), new ConfigureInputPlayer(this, 4, ui->consoleInputSettings, input_subsystem, profiles.get(), - hid_core, is_powered_on), + system), new ConfigureInputPlayer(this, 5, ui->consoleInputSettings, input_subsystem, profiles.get(), - hid_core, is_powered_on), + system), new ConfigureInputPlayer(this, 6, ui->consoleInputSettings, input_subsystem, profiles.get(), - hid_core, is_powered_on), + system), new ConfigureInputPlayer(this, 7, ui->consoleInputSettings, input_subsystem, profiles.get(), - hid_core, is_powered_on), + system), }; player_tabs = { @@ -118,7 +114,6 @@ void ConfigureInput::Initialize(InputCommon::InputSubsystem* input_subsystem, player_tabs[i]->setLayout(new QHBoxLayout(player_tabs[i])); player_tabs[i]->layout()->addWidget(player_controllers[i]); connect(player_controllers[i], &ConfigureInputPlayer::Connected, [&, i](bool is_connected) { - // Ensures that the controllers are always connected in sequential order if (is_connected) { for (std::size_t index = 0; index <= i; ++index) { player_connected[index]->setChecked(is_connected); @@ -151,12 +146,10 @@ void ConfigureInput::Initialize(InputCommon::InputSubsystem* input_subsystem, advanced = new ConfigureInputAdvanced(this); ui->tabAdvanced->setLayout(new QHBoxLayout(ui->tabAdvanced)); ui->tabAdvanced->layout()->addWidget(advanced); - - connect(advanced, &ConfigureInputAdvanced::CallDebugControllerDialog, - [this, input_subsystem, &hid_core, is_powered_on] { - CallConfigureDialog( - *this, input_subsystem, profiles.get(), hid_core, is_powered_on); - }); + connect(advanced, &ConfigureInputAdvanced::CallDebugControllerDialog, [this, input_subsystem] { + CallConfigureDialog(*this, input_subsystem, profiles.get(), + system); + }); connect(advanced, &ConfigureInputAdvanced::CallMouseConfigDialog, [this, input_subsystem] { CallConfigureDialog(*this, input_subsystem); }); @@ -191,8 +184,22 @@ QList ConfigureInput::GetSubTabs() const { void ConfigureInput::ApplyConfiguration() { for (auto* controller : player_controllers) { controller->ApplyConfiguration(); + controller->TryDisconnectSelectedController(); } + // This emulates a delay between disconnecting and reconnecting controllers as some games + // do not respond to a change in controller type if it was instantaneous. + using namespace std::chrono_literals; + std::this_thread::sleep_for(150ms); + + for (auto* controller : player_controllers) { + controller->TryConnectSelectedController(); + } + + // This emulates a delay between disconnecting and reconnecting controllers as some games + // do not respond to a change in controller type if it was instantaneous. + std::this_thread::sleep_for(150ms); + advanced->ApplyConfiguration(); const bool pre_docked_mode = Settings::values.use_docked_mode.GetValue(); @@ -216,10 +223,8 @@ void ConfigureInput::RetranslateUI() { } void ConfigureInput::LoadConfiguration() { - const auto* handheld = system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld); - LoadPlayerControllerIndices(); - UpdateDockedState(handheld->IsConnected()); + UpdateDockedState(Settings::values.players.GetValue()[8].connected); ui->vibrationGroup->setChecked(Settings::values.vibration_enabled.GetValue()); ui->motionGroup->setChecked(Settings::values.motion_enabled.GetValue()); @@ -227,16 +232,9 @@ void ConfigureInput::LoadConfiguration() { void ConfigureInput::LoadPlayerControllerIndices() { for (std::size_t i = 0; i < player_connected.size(); ++i) { - if (i == 0) { - auto* handheld = - system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld); - if (handheld->IsConnected()) { - player_connected[i]->setChecked(true); - continue; - } - } - const auto* controller = system.HIDCore().GetEmulatedControllerByIndex(i); - player_connected[i]->setChecked(controller->IsConnected()); + const auto connected = Settings::values.players.GetValue()[i].connected || + (i == 0 && Settings::values.players.GetValue()[8].connected); + player_connected[i]->setChecked(connected); } } diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index 0254ea6fe..3aab5d5f8 100755 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp @@ -12,12 +12,14 @@ #include #include #include "common/param_package.h" -#include "core/hid/emulated_controller.h" -#include "core/hid/hid_core.h" -#include "core/hid/hid_types.h" -#include "input_common/drivers/keyboard.h" -#include "input_common/drivers/mouse.h" +#include "core/core.h" +#include "core/hle/service/hid/controllers/npad.h" +#include "core/hle/service/hid/hid.h" +#include "core/hle/service/sm/sm.h" +#include "input_common/gcadapter/gc_poller.h" #include "input_common/main.h" +#include "input_common/mouse/mouse_poller.h" +#include "input_common/udp/udp.h" #include "ui_configure_input_player.h" #include "yuzu/bootmanager.h" #include "yuzu/configuration/config.h" @@ -27,6 +29,8 @@ #include "yuzu/configuration/input_profiles.h" #include "yuzu/util/limitable_input_dialog.h" +using namespace Service::HID; + const std::array ConfigureInputPlayer::analog_sub_buttons{{ "up", @@ -37,8 +41,33 @@ const std::array namespace { +constexpr std::size_t HANDHELD_INDEX = 8; + +void UpdateController(Settings::ControllerType controller_type, std::size_t npad_index, + bool connected, Core::System& system) { + if (!system.IsPoweredOn()) { + return; + } + Service::SM::ServiceManager& sm = system.ServiceManager(); + + auto& npad = sm.GetService("hid")->GetAppletResource()->GetController( + HidController::NPad); + + npad.UpdateControllerAt(npad.MapSettingsTypeToNPad(controller_type), npad_index, connected); +} + QString GetKeyName(int key_code) { switch (key_code) { + case Qt::LeftButton: + return QObject::tr("Click 0"); + case Qt::RightButton: + return QObject::tr("Click 1"); + case Qt::MiddleButton: + return QObject::tr("Click 2"); + case Qt::BackButton: + return QObject::tr("Click 3"); + case Qt::ForwardButton: + return QObject::tr("Click 4"); case Qt::Key_Shift: return QObject::tr("Shift"); case Qt::Key_Control: @@ -68,26 +97,95 @@ void SetAnalogParam(const Common::ParamPackage& input_param, Common::ParamPackag } analog_param.Set(button_name, input_param.Serialize()); } -} // namespace -QString ConfigureInputPlayer::ButtonToText(const Common::ParamPackage& param) { +QString ButtonToText(const Common::ParamPackage& param) { if (!param.Has("engine")) { return QObject::tr("[not set]"); } - // Retrieve the names from Qt if (param.Get("engine", "") == "keyboard") { const QString button_str = GetKeyName(param.Get("code", 0)); const QString toggle = QString::fromStdString(param.Get("toggle", false) ? "~" : ""); return QObject::tr("%1%2").arg(toggle, button_str); } - std::string button_name = input_subsystem->GetButtonName(param); - return QString::fromStdString(button_name); + if (param.Get("engine", "") == "gcpad") { + if (param.Has("axis")) { + const QString axis_str = QString::fromStdString(param.Get("axis", "")); + const QString direction_str = QString::fromStdString(param.Get("direction", "")); + + return QObject::tr("GC Axis %1%2").arg(axis_str, direction_str); + } + if (param.Has("button")) { + const QString button_str = QString::number(int(std::log2(param.Get("button", 0)))); + return QObject::tr("GC Button %1").arg(button_str); + } + return GetKeyName(param.Get("code", 0)); + } + + if (param.Get("engine", "") == "tas") { + if (param.Has("axis")) { + const QString axis_str = QString::fromStdString(param.Get("axis", "")); + + return QObject::tr("TAS Axis %1").arg(axis_str); + } + if (param.Has("button")) { + const QString button_str = QString::number(int(std::log2(param.Get("button", 0)))); + return QObject::tr("TAS Btn %1").arg(button_str); + } + return GetKeyName(param.Get("code", 0)); + } + + if (param.Get("engine", "") == "cemuhookudp") { + if (param.Has("pad_index")) { + const QString motion_str = QString::fromStdString(param.Get("pad_index", "")); + return QObject::tr("Motion %1").arg(motion_str); + } + return GetKeyName(param.Get("code", 0)); + } + + if (param.Get("engine", "") == "sdl") { + if (param.Has("hat")) { + const QString hat_str = QString::fromStdString(param.Get("hat", "")); + const QString direction_str = QString::fromStdString(param.Get("direction", "")); + + return QObject::tr("Hat %1 %2").arg(hat_str, direction_str); + } + + if (param.Has("axis")) { + const QString axis_str = QString::fromStdString(param.Get("axis", "")); + const QString direction_str = QString::fromStdString(param.Get("direction", "")); + + return QObject::tr("Axis %1%2").arg(axis_str, direction_str); + } + + if (param.Has("button")) { + const QString button_str = QString::fromStdString(param.Get("button", "")); + const QString toggle = QString::fromStdString(param.Get("toggle", false) ? "~" : ""); + + return QObject::tr("%1Button %2").arg(toggle, button_str); + } + + if (param.Has("motion")) { + return QObject::tr("SDL Motion"); + } + + return {}; + } + + if (param.Get("engine", "") == "mouse") { + if (param.Has("button")) { + const QString button_str = QString::number(int(param.Get("button", 0))); + const QString toggle = QString::fromStdString(param.Get("toggle", false) ? "~" : ""); + return QObject::tr("%1Click %2").arg(toggle, button_str); + } + return GetKeyName(param.Get("code", 0)); + } + + return QObject::tr("[unknown]"); } -QString ConfigureInputPlayer::AnalogToText(const Common::ParamPackage& param, - const std::string& dir) { +QString AnalogToText(const Common::ParamPackage& param, const std::string& dir) { if (!param.Has("engine")) { return QObject::tr("[not set]"); } @@ -96,69 +194,49 @@ QString ConfigureInputPlayer::AnalogToText(const Common::ParamPackage& param, return ButtonToText(Common::ParamPackage{param.Get(dir, "")}); } - if (!param.Has("axis_x") || !param.Has("axis_y")) { - return QObject::tr("[unknown]"); - } - const auto engine_str = param.Get("engine", ""); const QString axis_x_str = QString::fromStdString(param.Get("axis_x", "")); const QString axis_y_str = QString::fromStdString(param.Get("axis_y", "")); const bool invert_x = param.Get("invert_x", "+") == "-"; const bool invert_y = param.Get("invert_y", "+") == "-"; + if (engine_str == "sdl" || engine_str == "gcpad" || engine_str == "mouse" || + engine_str == "tas") { + if (dir == "modifier") { + return QObject::tr("[unused]"); + } - if (dir == "modifier") { - return QObject::tr("[unused]"); - } + if (dir == "left") { + const QString invert_x_str = QString::fromStdString(invert_x ? "+" : "-"); + return QObject::tr("Axis %1%2").arg(axis_x_str, invert_x_str); + } + if (dir == "right") { + const QString invert_x_str = QString::fromStdString(invert_x ? "-" : "+"); + return QObject::tr("Axis %1%2").arg(axis_x_str, invert_x_str); + } + if (dir == "up") { + const QString invert_y_str = QString::fromStdString(invert_y ? "-" : "+"); + return QObject::tr("Axis %1%2").arg(axis_y_str, invert_y_str); + } + if (dir == "down") { + const QString invert_y_str = QString::fromStdString(invert_y ? "+" : "-"); + return QObject::tr("Axis %1%2").arg(axis_y_str, invert_y_str); + } - if (dir == "left") { - const QString invert_x_str = QString::fromStdString(invert_x ? "+" : "-"); - return QObject::tr("Axis %1%2").arg(axis_x_str, invert_x_str); + return {}; } - if (dir == "right") { - const QString invert_x_str = QString::fromStdString(invert_x ? "-" : "+"); - return QObject::tr("Axis %1%2").arg(axis_x_str, invert_x_str); - } - if (dir == "up") { - const QString invert_y_str = QString::fromStdString(invert_y ? "-" : "+"); - return QObject::tr("Axis %1%2").arg(axis_y_str, invert_y_str); - } - if (dir == "down") { - const QString invert_y_str = QString::fromStdString(invert_y ? "+" : "-"); - return QObject::tr("Axis %1%2").arg(axis_y_str, invert_y_str); - } - return QObject::tr("[unknown]"); } +} // namespace ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_index, QWidget* bottom_row, InputCommon::InputSubsystem* input_subsystem_, - InputProfiles* profiles_, Core::HID::HIDCore& hid_core_, - bool is_powered_on_, bool debug) + InputProfiles* profiles_, Core::System& system_, + bool debug) : QWidget(parent), ui(std::make_unique()), player_index(player_index), - debug(debug), is_powered_on{is_powered_on_}, input_subsystem{input_subsystem_}, - profiles(profiles_), timeout_timer(std::make_unique()), - poll_timer(std::make_unique()), bottom_row(bottom_row), hid_core{hid_core_} { - if (player_index == 0) { - auto* emulated_controller_p1 = - hid_core.GetEmulatedController(Core::HID::NpadIdType::Player1); - auto* emulated_controller_hanheld = - hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld); - emulated_controller_p1->SaveCurrentConfig(); - emulated_controller_p1->EnableConfiguration(); - emulated_controller_hanheld->SaveCurrentConfig(); - emulated_controller_hanheld->EnableConfiguration(); - if (emulated_controller_hanheld->IsConnected(true)) { - emulated_controller_p1->Disconnect(); - emulated_controller = emulated_controller_hanheld; - } else { - emulated_controller = emulated_controller_p1; - } - } else { - emulated_controller = hid_core.GetEmulatedControllerByIndex(player_index); - emulated_controller->SaveCurrentConfig(); - emulated_controller->EnableConfiguration(); - } + debug(debug), input_subsystem{input_subsystem_}, profiles(profiles_), + timeout_timer(std::make_unique()), poll_timer(std::make_unique()), + bottom_row(bottom_row), system{system_} { ui->setupUi(this); setFocusPolicy(Qt::ClickFocus); @@ -200,7 +278,31 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i analog_map_range_groupbox = {ui->buttonLStickRangeGroup, ui->buttonRStickRangeGroup}; analog_map_range_spinbox = {ui->spinboxLStickRange, ui->spinboxRStickRange}; - ui->controllerFrame->SetController(emulated_controller); + const auto ConfigureButtonClick = [&](QPushButton* button, std::size_t button_id, + Common::ParamPackage* param, int default_val, + InputCommon::Polling::DeviceType type) { + connect(button, &QPushButton::clicked, [=, this] { + HandleClick( + button, button_id, + [=, this](Common::ParamPackage params) { + // Workaround for ZL & ZR for analog triggers like on XBOX + // controllers. Analog triggers (from controllers like the XBOX + // controller) would not work due to a different range of their + // signals (from 0 to 255 on analog triggers instead of -32768 to + // 32768 on analog joysticks). The SDL driver misinterprets analog + // triggers as analog joysticks. + // TODO: reinterpret the signal range for analog triggers to map the + // values correctly. This is required for the correct emulation of + // the analog triggers of the GameCube controller. + if (button == ui->buttonZL || button == ui->buttonZR) { + params.Set("direction", "+"); + params.Set("threshold", "0.5"); + } + *param = std::move(params); + }, + type); + }); + }; for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; ++button_id) { auto* const button = button_map[button_id]; @@ -209,52 +311,34 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i continue; } - connect(button, &QPushButton::clicked, [=, this] { - HandleClick( - button, button_id, - [=, this](Common::ParamPackage params) { - emulated_controller->SetButtonParam(button_id, params); - }, - InputCommon::Polling::InputType::Button); - }); + ConfigureButtonClick(button_map[button_id], button_id, &buttons_param[button_id], + Config::default_buttons[button_id], + InputCommon::Polling::DeviceType::Button); button->setContextMenuPolicy(Qt::CustomContextMenu); connect(button, &QPushButton::customContextMenuRequested, [=, this](const QPoint& menu_location) { QMenu context_menu; - Common::ParamPackage param = emulated_controller->GetButtonParam(button_id); context_menu.addAction(tr("Clear"), [&] { - emulated_controller->SetButtonParam(button_id, {}); + buttons_param[button_id].Clear(); button_map[button_id]->setText(tr("[not set]")); }); - if (param.Has("button") || param.Has("hat")) { + if (buttons_param[button_id].Has("toggle")) { context_menu.addAction(tr("Toggle button"), [&] { - const bool toggle_value = !param.Get("toggle", false); - param.Set("toggle", toggle_value); - button_map[button_id]->setText(ButtonToText(param)); - emulated_controller->SetButtonParam(button_id, param); - }); - context_menu.addAction(tr("Invert button"), [&] { - const bool toggle_value = !param.Get("inverted", false); - param.Set("inverted", toggle_value); - button_map[button_id]->setText(ButtonToText(param)); - emulated_controller->SetButtonParam(button_id, param); + const bool toggle_value = + !buttons_param[button_id].Get("toggle", false); + buttons_param[button_id].Set("toggle", toggle_value); + button_map[button_id]->setText(ButtonToText(buttons_param[button_id])); }); } - if (param.Has("axis")) { - context_menu.addAction(tr("Invert axis"), [&] { - const bool toggle_value = !(param.Get("invert", "+") == "-"); - param.Set("invert", toggle_value ? "-" : "+"); - button_map[button_id]->setText(ButtonToText(param)); - emulated_controller->SetButtonParam(button_id, param); - }); + if (buttons_param[button_id].Has("threshold")) { context_menu.addAction(tr("Set threshold"), [&] { - const int button_threshold = - static_cast(param.Get("threshold", 0.5f) * 100.0f); + const int button_threshold = static_cast( + buttons_param[button_id].Get("threshold", 0.5f) * 100.0f); const int new_threshold = QInputDialog::getInt( this, tr("Set threshold"), tr("Choose a value between 0% and 100%"), button_threshold, 0, 100); - param.Set("threshold", new_threshold / 100.0f); + buttons_param[button_id].Set("threshold", new_threshold / 100.0f); if (button_id == Settings::NativeButton::ZL) { ui->sliderZLThreshold->setValue(new_threshold); @@ -262,10 +346,11 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i if (button_id == Settings::NativeButton::ZR) { ui->sliderZRThreshold->setValue(new_threshold); } - emulated_controller->SetButtonParam(button_id, param); }); } + context_menu.exec(button_map[button_id]->mapToGlobal(menu_location)); + ui->controllerFrame->SetPlayerInput(player_index, buttons_param, analogs_param); }); } @@ -275,14 +360,9 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i continue; } - connect(button, &QPushButton::clicked, [=, this] { - HandleClick( - button, motion_id, - [=, this](Common::ParamPackage params) { - emulated_controller->SetMotionParam(motion_id, params); - }, - InputCommon::Polling::InputType::Motion); - }); + ConfigureButtonClick(motion_map[motion_id], motion_id, &motions_param[motion_id], + Config::default_motions[motion_id], + InputCommon::Polling::DeviceType::Motion); button->setContextMenuPolicy(Qt::CustomContextMenu); @@ -290,7 +370,7 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i [=, this](const QPoint& menu_location) { QMenu context_menu; context_menu.addAction(tr("Clear"), [&] { - emulated_controller->SetMotionParam(motion_id, {}); + motions_param[motion_id].Clear(); motion_map[motion_id]->setText(tr("[not set]")); }); context_menu.exec(motion_map[motion_id]->mapToGlobal(menu_location)); @@ -298,22 +378,16 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i } connect(ui->sliderZLThreshold, &QSlider::valueChanged, [=, this] { - Common::ParamPackage param = - emulated_controller->GetButtonParam(Settings::NativeButton::ZL); - if (param.Has("threshold")) { + if (buttons_param[Settings::NativeButton::ZL].Has("threshold")) { const auto slider_value = ui->sliderZLThreshold->value(); - param.Set("threshold", slider_value / 100.0f); - emulated_controller->SetButtonParam(Settings::NativeButton::ZL, param); + buttons_param[Settings::NativeButton::ZL].Set("threshold", slider_value / 100.0f); } }); connect(ui->sliderZRThreshold, &QSlider::valueChanged, [=, this] { - Common::ParamPackage param = - emulated_controller->GetButtonParam(Settings::NativeButton::ZR); - if (param.Has("threshold")) { + if (buttons_param[Settings::NativeButton::ZR].Has("threshold")) { const auto slider_value = ui->sliderZRThreshold->value(); - param.Set("threshold", slider_value / 100.0f); - emulated_controller->SetButtonParam(Settings::NativeButton::ZR, param); + buttons_param[Settings::NativeButton::ZR].Set("threshold", slider_value / 100.0f); } }); @@ -341,45 +415,45 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i HandleClick( analog_map_buttons[analog_id][sub_button_id], analog_id, [=, this](const Common::ParamPackage& params) { - Common::ParamPackage param = emulated_controller->GetStickParam(analog_id); - SetAnalogParam(params, param, analog_sub_buttons[sub_button_id]); - emulated_controller->SetStickParam(analog_id, param); + SetAnalogParam(params, analogs_param[analog_id], + analog_sub_buttons[sub_button_id]); }, - InputCommon::Polling::InputType::Stick); + InputCommon::Polling::DeviceType::AnalogPreferred); }); analog_button->setContextMenuPolicy(Qt::CustomContextMenu); - connect(analog_button, &QPushButton::customContextMenuRequested, - [=, this](const QPoint& menu_location) { - QMenu context_menu; - Common::ParamPackage param = emulated_controller->GetStickParam(analog_id); - context_menu.addAction(tr("Clear"), [&] { - emulated_controller->SetStickParam(analog_id, {}); - analog_map_buttons[analog_id][sub_button_id]->setText(tr("[not set]")); - }); - context_menu.addAction(tr("Invert axis"), [&] { - if (sub_button_id == 2 || sub_button_id == 3) { - const bool invert_value = param.Get("invert_x", "+") == "-"; - const std::string invert_str = invert_value ? "+" : "-"; - param.Set("invert_x", invert_str); - emulated_controller->SetStickParam(analog_id, param); - } - if (sub_button_id == 0 || sub_button_id == 1) { - const bool invert_value = param.Get("invert_y", "+") == "-"; - const std::string invert_str = invert_value ? "+" : "-"; - param.Set("invert_y", invert_str); - emulated_controller->SetStickParam(analog_id, param); - } - for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; - ++sub_button_id) { - analog_map_buttons[analog_id][sub_button_id]->setText( - AnalogToText(param, analog_sub_buttons[sub_button_id])); - } - }); - context_menu.exec(analog_map_buttons[analog_id][sub_button_id]->mapToGlobal( - menu_location)); + connect( + analog_button, &QPushButton::customContextMenuRequested, + [=, this](const QPoint& menu_location) { + QMenu context_menu; + context_menu.addAction(tr("Clear"), [&] { + analogs_param[analog_id].Clear(); + analog_map_buttons[analog_id][sub_button_id]->setText(tr("[not set]")); }); + context_menu.addAction(tr("Invert axis"), [&] { + if (sub_button_id == 2 || sub_button_id == 3) { + const bool invert_value = + analogs_param[analog_id].Get("invert_x", "+") == "-"; + const std::string invert_str = invert_value ? "+" : "-"; + analogs_param[analog_id].Set("invert_x", invert_str); + } + if (sub_button_id == 0 || sub_button_id == 1) { + const bool invert_value = + analogs_param[analog_id].Get("invert_y", "+") == "-"; + const std::string invert_str = invert_value ? "+" : "-"; + analogs_param[analog_id].Set("invert_y", invert_str); + } + for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; + ++sub_button_id) { + analog_map_buttons[analog_id][sub_button_id]->setText(AnalogToText( + analogs_param[analog_id], analog_sub_buttons[sub_button_id])); + } + }); + context_menu.exec( + analog_map_buttons[analog_id][sub_button_id]->mapToGlobal(menu_location)); + ui->controllerFrame->SetPlayerInput(player_index, buttons_param, analogs_param); + }); } // Handle clicks for the modifier buttons as well. @@ -387,11 +461,9 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i HandleClick( analog_map_modifier_button[analog_id], analog_id, [=, this](const Common::ParamPackage& params) { - Common::ParamPackage param = emulated_controller->GetStickParam(analog_id); - param.Set("modifier", params.Serialize()); - emulated_controller->SetStickParam(analog_id, param); + analogs_param[analog_id].Set("modifier", params.Serialize()); }, - InputCommon::Polling::InputType::Button); + InputCommon::Polling::DeviceType::Button); }); analog_map_modifier_button[analog_id]->setContextMenuPolicy(Qt::CustomContextMenu); @@ -399,21 +471,18 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i connect(analog_map_modifier_button[analog_id], &QPushButton::customContextMenuRequested, [=, this](const QPoint& menu_location) { QMenu context_menu; - Common::ParamPackage param = emulated_controller->GetStickParam(analog_id); context_menu.addAction(tr("Clear"), [&] { - param.Set("modifier", ""); + analogs_param[analog_id].Set("modifier", ""); analog_map_modifier_button[analog_id]->setText(tr("[not set]")); - emulated_controller->SetStickParam(analog_id, param); }); context_menu.addAction(tr("Toggle button"), [&] { Common::ParamPackage modifier_param = - Common::ParamPackage{param.Get("modifier", "")}; + Common::ParamPackage{analogs_param[analog_id].Get("modifier", "")}; const bool toggle_value = !modifier_param.Get("toggle", false); modifier_param.Set("toggle", toggle_value); - param.Set("modifier", modifier_param.Serialize()); + analogs_param[analog_id].Set("modifier", modifier_param.Serialize()); analog_map_modifier_button[analog_id]->setText( ButtonToText(modifier_param)); - emulated_controller->SetStickParam(analog_id, param); }); context_menu.exec( analog_map_modifier_button[analog_id]->mapToGlobal(menu_location)); @@ -421,39 +490,37 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i connect(analog_map_range_spinbox[analog_id], qOverload(&QSpinBox::valueChanged), [=, this] { - Common::ParamPackage param = emulated_controller->GetStickParam(analog_id); const auto spinbox_value = analog_map_range_spinbox[analog_id]->value(); - param.Set("range", spinbox_value / 100.0f); - emulated_controller->SetStickParam(analog_id, param); + analogs_param[analog_id].Set("range", spinbox_value / 100.0f); + ui->controllerFrame->SetPlayerInput(player_index, buttons_param, analogs_param); }); connect(analog_map_deadzone_slider[analog_id], &QSlider::valueChanged, [=, this] { - Common::ParamPackage param = emulated_controller->GetStickParam(analog_id); const auto slider_value = analog_map_deadzone_slider[analog_id]->value(); analog_map_deadzone_label[analog_id]->setText(tr("Deadzone: %1%").arg(slider_value)); - param.Set("deadzone", slider_value / 100.0f); - emulated_controller->SetStickParam(analog_id, param); + analogs_param[analog_id].Set("deadzone", slider_value / 100.0f); + ui->controllerFrame->SetPlayerInput(player_index, buttons_param, analogs_param); }); connect(analog_map_modifier_slider[analog_id], &QSlider::valueChanged, [=, this] { - Common::ParamPackage param = emulated_controller->GetStickParam(analog_id); const auto slider_value = analog_map_modifier_slider[analog_id]->value(); analog_map_modifier_label[analog_id]->setText( tr("Modifier Range: %1%").arg(slider_value)); - param.Set("modifier_scale", slider_value / 100.0f); - emulated_controller->SetStickParam(analog_id, param); + analogs_param[analog_id].Set("modifier_scale", slider_value / 100.0f); }); } // Player Connected checkbox - connect(ui->groupConnectedController, &QGroupBox::toggled, - [this](bool checked) { emit Connected(checked); }); + connect(ui->groupConnectedController, &QGroupBox::toggled, [this](bool checked) { + emit Connected(checked); + ui->controllerFrame->SetConnectedStatus(checked); + }); if (player_index == 0) { connect(ui->comboControllerType, qOverload(&QComboBox::currentIndexChanged), [this](int index) { emit HandheldStateChanged(GetControllerTypeFromIndex(index) == - Core::HID::NpadStyleIndex::Handheld); + Settings::ControllerType::Handheld); }); } @@ -470,43 +537,18 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i SetConnectableControllers(); } + UpdateControllerIcon(); UpdateControllerAvailableButtons(); UpdateControllerEnabledButtons(); UpdateControllerButtonNames(); UpdateMotionButtons(); - connect(ui->comboControllerType, qOverload(&QComboBox::currentIndexChanged), - [this, player_index](int) { - UpdateControllerAvailableButtons(); - UpdateControllerEnabledButtons(); - UpdateControllerButtonNames(); - UpdateMotionButtons(); - const Core::HID::NpadStyleIndex type = - GetControllerTypeFromIndex(ui->comboControllerType->currentIndex()); - - if (player_index == 0) { - auto* emulated_controller_p1 = - hid_core.GetEmulatedController(Core::HID::NpadIdType::Player1); - auto* emulated_controller_hanheld = - hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld); - bool is_connected = emulated_controller->IsConnected(true); - - emulated_controller_p1->SetNpadStyleIndex(type); - emulated_controller_hanheld->SetNpadStyleIndex(type); - if (is_connected) { - if (type == Core::HID::NpadStyleIndex::Handheld) { - emulated_controller_p1->Disconnect(); - emulated_controller_hanheld->Connect(); - emulated_controller = emulated_controller_hanheld; - } else { - emulated_controller_hanheld->Disconnect(); - emulated_controller_p1->Connect(); - emulated_controller = emulated_controller_p1; - } - } - ui->controllerFrame->SetController(emulated_controller); - } - emulated_controller->SetNpadStyleIndex(type); - }); + connect(ui->comboControllerType, qOverload(&QComboBox::currentIndexChanged), [this](int) { + UpdateControllerIcon(); + UpdateControllerAvailableButtons(); + UpdateControllerEnabledButtons(); + UpdateControllerButtonNames(); + UpdateMotionButtons(); + }); connect(ui->comboDevices, qOverload(&QComboBox::activated), this, &ConfigureInputPlayer::UpdateMappingWithDefaults); @@ -521,10 +563,62 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i connect(timeout_timer.get(), &QTimer::timeout, [this] { SetPollingResult({}, true); }); connect(poll_timer.get(), &QTimer::timeout, [this] { - const auto& params = input_subsystem->GetNextInput(); - if (params.Has("engine") && IsInputAcceptable(params)) { - SetPollingResult(params, false); - return; + Common::ParamPackage params; + if (input_subsystem->GetGCButtons()->IsPolling()) { + params = input_subsystem->GetGCButtons()->GetNextInput(); + if (params.Has("engine") && IsInputAcceptable(params)) { + SetPollingResult(params, false); + return; + } + } + if (input_subsystem->GetGCAnalogs()->IsPolling()) { + params = input_subsystem->GetGCAnalogs()->GetNextInput(); + if (params.Has("engine") && IsInputAcceptable(params)) { + SetPollingResult(params, false); + return; + } + } + if (input_subsystem->GetUDPMotions()->IsPolling()) { + params = input_subsystem->GetUDPMotions()->GetNextInput(); + if (params.Has("engine")) { + SetPollingResult(params, false); + return; + } + } + if (input_subsystem->GetMouseButtons()->IsPolling()) { + params = input_subsystem->GetMouseButtons()->GetNextInput(); + if (params.Has("engine") && IsInputAcceptable(params)) { + SetPollingResult(params, false); + return; + } + } + if (input_subsystem->GetMouseAnalogs()->IsPolling()) { + params = input_subsystem->GetMouseAnalogs()->GetNextInput(); + if (params.Has("engine") && IsInputAcceptable(params)) { + SetPollingResult(params, false); + return; + } + } + if (input_subsystem->GetMouseMotions()->IsPolling()) { + params = input_subsystem->GetMouseMotions()->GetNextInput(); + if (params.Has("engine") && IsInputAcceptable(params)) { + SetPollingResult(params, false); + return; + } + } + if (input_subsystem->GetMouseTouch()->IsPolling()) { + params = input_subsystem->GetMouseTouch()->GetNextInput(); + if (params.Has("engine") && IsInputAcceptable(params)) { + SetPollingResult(params, false); + return; + } + } + for (auto& poller : device_pollers) { + params = poller->GetNextInput(); + if (params.Has("engine") && IsInputAcceptable(params)) { + SetPollingResult(params, false); + return; + } } }); @@ -540,38 +634,110 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i &ConfigureInputPlayer::SaveProfile); LoadConfiguration(); + ui->controllerFrame->SetPlayerInput(player_index, buttons_param, analogs_param); + ui->controllerFrame->SetConnectedStatus(ui->groupConnectedController->isChecked()); } -ConfigureInputPlayer::~ConfigureInputPlayer() { - if (player_index == 0) { - auto* emulated_controller_p1 = - hid_core.GetEmulatedController(Core::HID::NpadIdType::Player1); - auto* emulated_controller_hanheld = - hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld); - emulated_controller_p1->DisableConfiguration(); - emulated_controller_hanheld->DisableConfiguration(); - } else { - emulated_controller->DisableConfiguration(); - } -} +ConfigureInputPlayer::~ConfigureInputPlayer() = default; void ConfigureInputPlayer::ApplyConfiguration() { - if (player_index == 0) { - auto* emulated_controller_p1 = - hid_core.GetEmulatedController(Core::HID::NpadIdType::Player1); - auto* emulated_controller_hanheld = - hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld); - emulated_controller_p1->DisableConfiguration(); - emulated_controller_p1->SaveCurrentConfig(); - emulated_controller_p1->EnableConfiguration(); - emulated_controller_hanheld->DisableConfiguration(); - emulated_controller_hanheld->SaveCurrentConfig(); - emulated_controller_hanheld->EnableConfiguration(); + auto& player = Settings::values.players.GetValue()[player_index]; + auto& buttons = debug ? Settings::values.debug_pad_buttons : player.buttons; + auto& analogs = debug ? Settings::values.debug_pad_analogs : player.analogs; + + std::transform(buttons_param.begin(), buttons_param.end(), buttons.begin(), + [](const Common::ParamPackage& param) { return param.Serialize(); }); + std::transform(analogs_param.begin(), analogs_param.end(), analogs.begin(), + [](const Common::ParamPackage& param) { return param.Serialize(); }); + + if (debug) { return; } - emulated_controller->DisableConfiguration(); - emulated_controller->SaveCurrentConfig(); - emulated_controller->EnableConfiguration(); + + auto& motions = player.motions; + + std::transform(motions_param.begin(), motions_param.end(), motions.begin(), + [](const Common::ParamPackage& param) { return param.Serialize(); }); + + // Apply configuration for handheld + if (player_index == 0) { + auto& handheld = Settings::values.players.GetValue()[HANDHELD_INDEX]; + const auto handheld_connected = handheld.connected; + handheld = player; + handheld.connected = handheld_connected; + } +} + +void ConfigureInputPlayer::TryConnectSelectedController() { + auto& player = Settings::values.players.GetValue()[player_index]; + + const auto controller_type = + GetControllerTypeFromIndex(ui->comboControllerType->currentIndex()); + const auto player_connected = ui->groupConnectedController->isChecked() && + controller_type != Settings::ControllerType::Handheld; + + // Connect Handheld depending on Player 1's controller configuration. + if (player_index == 0) { + auto& handheld = Settings::values.players.GetValue()[HANDHELD_INDEX]; + const auto handheld_connected = ui->groupConnectedController->isChecked() && + controller_type == Settings::ControllerType::Handheld; + // Connect only if handheld is going from disconnected to connected + if (!handheld.connected && handheld_connected) { + UpdateController(controller_type, HANDHELD_INDEX, true, system); + } + handheld.connected = handheld_connected; + } + + if (player.controller_type == controller_type && player.connected == player_connected) { + // Set vibration devices in the event that the input device has changed. + ConfigureVibration::SetVibrationDevices(player_index); + return; + } + + player.controller_type = controller_type; + player.connected = player_connected; + + ConfigureVibration::SetVibrationDevices(player_index); + + if (!player.connected) { + return; + } + + UpdateController(controller_type, player_index, true, system); +} + +void ConfigureInputPlayer::TryDisconnectSelectedController() { + const auto& player = Settings::values.players.GetValue()[player_index]; + + const auto controller_type = + GetControllerTypeFromIndex(ui->comboControllerType->currentIndex()); + const auto player_connected = ui->groupConnectedController->isChecked() && + controller_type != Settings::ControllerType::Handheld; + + // Disconnect Handheld depending on Player 1's controller configuration. + if (player_index == 0 && player.controller_type == Settings::ControllerType::Handheld) { + const auto& handheld = Settings::values.players.GetValue()[HANDHELD_INDEX]; + const auto handheld_connected = ui->groupConnectedController->isChecked() && + controller_type == Settings::ControllerType::Handheld; + // Disconnect only if handheld is going from connected to disconnected + if (handheld.connected && !handheld_connected) { + UpdateController(controller_type, HANDHELD_INDEX, false, system); + } + return; + } + + // Do not do anything if the controller configuration has not changed. + if (player.controller_type == controller_type && player.connected == player_connected) { + return; + } + + // Do not disconnect if the controller is already disconnected + if (!player.connected) { + return; + } + + // Disconnect the controller first. + UpdateController(controller_type, player_index, false, system); } void ConfigureInputPlayer::showEvent(QShowEvent* event) { @@ -596,7 +762,22 @@ void ConfigureInputPlayer::RetranslateUI() { } void ConfigureInputPlayer::LoadConfiguration() { - emulated_controller->ReloadFromSettings(); + auto& player = Settings::values.players.GetValue()[player_index]; + if (debug) { + std::transform(Settings::values.debug_pad_buttons.begin(), + Settings::values.debug_pad_buttons.end(), buttons_param.begin(), + [](const std::string& str) { return Common::ParamPackage(str); }); + std::transform(Settings::values.debug_pad_analogs.begin(), + Settings::values.debug_pad_analogs.end(), analogs_param.begin(), + [](const std::string& str) { return Common::ParamPackage(str); }); + } else { + std::transform(player.buttons.begin(), player.buttons.end(), buttons_param.begin(), + [](const std::string& str) { return Common::ParamPackage(str); }); + std::transform(player.analogs.begin(), player.analogs.end(), analogs_param.begin(), + [](const std::string& str) { return Common::ParamPackage(str); }); + std::transform(player.motions.begin(), player.motions.end(), motions_param.begin(), + [](const std::string& str) { return Common::ParamPackage(str); }); + } UpdateUI(); UpdateInputDeviceCombobox(); @@ -605,19 +786,14 @@ void ConfigureInputPlayer::LoadConfiguration() { return; } - const int comboBoxIndex = - GetIndexFromControllerType(emulated_controller->GetNpadStyleIndex(true)); - ui->comboControllerType->setCurrentIndex(comboBoxIndex); - ui->groupConnectedController->setChecked(emulated_controller->IsConnected(true)); + ui->comboControllerType->setCurrentIndex(GetIndexFromControllerType(player.controller_type)); + ui->groupConnectedController->setChecked( + player.connected || + (player_index == 0 && Settings::values.players.GetValue()[HANDHELD_INDEX].connected)); } void ConfigureInputPlayer::ConnectPlayer(bool connected) { ui->groupConnectedController->setChecked(connected); - if (connected) { - emulated_controller->Connect(); - } else { - emulated_controller->Disconnect(); - } } void ConfigureInputPlayer::UpdateInputDeviceCombobox() { @@ -627,64 +803,48 @@ void ConfigureInputPlayer::UpdateInputDeviceCombobox() { return; } - const auto devices = - emulated_controller->GetMappedDevices(Core::HID::EmulatedDeviceIndex::AllDevices); + // Find the first button that isn't empty. + const auto button_param = + std::find_if(buttons_param.begin(), buttons_param.end(), + [](const Common::ParamPackage param) { return param.Has("engine"); }); + const bool buttons_empty = button_param == buttons_param.end(); + + const auto current_engine = button_param->Get("engine", ""); + const auto current_guid = button_param->Get("guid", ""); + const auto current_port = button_param->Get("port", ""); + + const bool is_keyboard_mouse = current_engine == "keyboard" || current_engine == "mouse"; + UpdateInputDevices(); - if (devices.empty()) { + if (buttons_empty) { return; } - if (devices.size() > 2) { - ui->comboDevices->setCurrentIndex(0); - return; - } + const bool all_one_device = + std::all_of(buttons_param.begin(), buttons_param.end(), + [current_engine, current_guid, current_port, + is_keyboard_mouse](const Common::ParamPackage param) { + if (is_keyboard_mouse) { + return !param.Has("engine") || param.Get("engine", "") == "keyboard" || + param.Get("engine", "") == "mouse"; + } + return !param.Has("engine") || (param.Get("engine", "") == current_engine && + param.Get("guid", "") == current_guid && + param.Get("port", "") == current_port); + }); - const auto first_engine = devices[0].Get("engine", ""); - const auto first_guid = devices[0].Get("guid", ""); - const auto first_port = devices[0].Get("port", 0); - - if (devices.size() == 1) { - const auto devices_it = - std::find_if(input_devices.begin(), input_devices.end(), - [first_engine, first_guid, first_port](const Common::ParamPackage param) { - return param.Get("engine", "") == first_engine && - param.Get("guid", "") == first_guid && - param.Get("port", 0) == first_port; - }); - const int device_index = - devices_it != input_devices.end() - ? static_cast(std::distance(input_devices.begin(), devices_it)) - : 0; - ui->comboDevices->setCurrentIndex(device_index); - return; - } - - const auto second_engine = devices[1].Get("engine", ""); - const auto second_guid = devices[1].Get("guid", ""); - const auto second_port = devices[1].Get("port", 0); - - const bool is_keyboard_mouse = (first_engine == "keyboard" || first_engine == "mouse") && - (second_engine == "keyboard" || second_engine == "mouse"); - - if (is_keyboard_mouse) { - ui->comboDevices->setCurrentIndex(2); - return; - } - - const bool is_engine_equal = first_engine == second_engine; - const bool is_port_equal = first_port == second_port; - - if (is_engine_equal && is_port_equal) { + if (all_one_device) { + if (is_keyboard_mouse) { + ui->comboDevices->setCurrentIndex(1); + return; + } const auto devices_it = std::find_if( input_devices.begin(), input_devices.end(), - [first_engine, first_guid, second_guid, first_port](const Common::ParamPackage param) { - const bool is_guid_valid = - (param.Get("guid", "") == first_guid && - param.Get("guid2", "") == second_guid) || - (param.Get("guid", "") == second_guid && param.Get("guid2", "") == first_guid); - return param.Get("engine", "") == first_engine && is_guid_valid && - param.Get("port", 0) == first_port; + [current_engine, current_guid, current_port](const Common::ParamPackage param) { + return param.Get("class", "") == current_engine && + param.Get("guid", "") == current_guid && + param.Get("port", "") == current_port; }); const int device_index = devices_it != input_devices.end() @@ -706,7 +866,8 @@ void ConfigureInputPlayer::ClearAll() { if (button == nullptr) { continue; } - emulated_controller->SetButtonParam(button_id, {}); + + buttons_param[button_id].Clear(); } for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; ++analog_id) { @@ -715,7 +876,8 @@ void ConfigureInputPlayer::ClearAll() { if (analog_button == nullptr) { continue; } - emulated_controller->SetStickParam(analog_id, {}); + + analogs_param[analog_id].Clear(); } } @@ -724,7 +886,8 @@ void ConfigureInputPlayer::ClearAll() { if (motion_button == nullptr) { continue; } - emulated_controller->SetMotionParam(motion_id, {}); + + motions_param[motion_id].Clear(); } UpdateUI(); @@ -733,31 +896,26 @@ void ConfigureInputPlayer::ClearAll() { void ConfigureInputPlayer::UpdateUI() { for (int button = 0; button < Settings::NativeButton::NumButtons; ++button) { - const Common::ParamPackage param = emulated_controller->GetButtonParam(button); - button_map[button]->setText(ButtonToText(param)); + button_map[button]->setText(ButtonToText(buttons_param[button])); } - const Common::ParamPackage ZL_param = - emulated_controller->GetButtonParam(Settings::NativeButton::ZL); - if (ZL_param.Has("threshold")) { - const int button_threshold = static_cast(ZL_param.Get("threshold", 0.5f) * 100.0f); + if (buttons_param[Settings::NativeButton::ZL].Has("threshold")) { + const int button_threshold = static_cast( + buttons_param[Settings::NativeButton::ZL].Get("threshold", 0.5f) * 100.0f); ui->sliderZLThreshold->setValue(button_threshold); } - const Common::ParamPackage ZR_param = - emulated_controller->GetButtonParam(Settings::NativeButton::ZR); - if (ZR_param.Has("threshold")) { - const int button_threshold = static_cast(ZR_param.Get("threshold", 0.5f) * 100.0f); + if (buttons_param[Settings::NativeButton::ZR].Has("threshold")) { + const int button_threshold = static_cast( + buttons_param[Settings::NativeButton::ZR].Get("threshold", 0.5f) * 100.0f); ui->sliderZRThreshold->setValue(button_threshold); } for (int motion_id = 0; motion_id < Settings::NativeMotion::NumMotions; ++motion_id) { - const Common::ParamPackage param = emulated_controller->GetMotionParam(motion_id); - motion_map[motion_id]->setText(ButtonToText(param)); + motion_map[motion_id]->setText(ButtonToText(motions_param[motion_id])); } for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; ++analog_id) { - const Common::ParamPackage param = emulated_controller->GetStickParam(analog_id); for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; ++sub_button_id) { auto* const analog_button = analog_map_buttons[analog_id][sub_button_id]; @@ -765,11 +923,12 @@ void ConfigureInputPlayer::UpdateUI() { continue; } - analog_button->setText(AnalogToText(param, analog_sub_buttons[sub_button_id])); + analog_button->setText( + AnalogToText(analogs_param[analog_id], analog_sub_buttons[sub_button_id])); } analog_map_modifier_button[analog_id]->setText( - ButtonToText(Common::ParamPackage{param.Get("modifier", "")})); + ButtonToText(Common::ParamPackage{analogs_param[analog_id].Get("modifier", "")})); const auto deadzone_label = analog_map_deadzone_label[analog_id]; const auto deadzone_slider = analog_map_deadzone_slider[analog_id]; @@ -780,14 +939,26 @@ void ConfigureInputPlayer::UpdateUI() { const auto range_spinbox = analog_map_range_spinbox[analog_id]; int slider_value; - const bool is_controller = input_subsystem->IsController(param); + auto& param = analogs_param[analog_id]; + const bool is_controller = + param.Get("engine", "") == "sdl" || param.Get("engine", "") == "gcpad" || + param.Get("engine", "") == "mouse" || param.Get("engine", "") == "tas"; if (is_controller) { - slider_value = static_cast(param.Get("deadzone", 0.15f) * 100); + if (!param.Has("deadzone")) { + param.Set("deadzone", 0.1f); + } + slider_value = static_cast(param.Get("deadzone", 0.1f) * 100); deadzone_label->setText(tr("Deadzone: %1%").arg(slider_value)); deadzone_slider->setValue(slider_value); + if (!param.Has("range")) { + param.Set("range", 1.0f); + } range_spinbox->setValue(static_cast(param.Get("range", 1.0f) * 100)); } else { + if (!param.Has("modifier_scale")) { + param.Set("modifier_scale", 0.5f); + } slider_value = static_cast(param.Get("modifier_scale", 0.5f) * 100); modifier_label->setText(tr("Modifier Range: %1%").arg(slider_value)); modifier_slider->setValue(slider_value); @@ -799,73 +970,79 @@ void ConfigureInputPlayer::UpdateUI() { modifier_label->setVisible(!is_controller); modifier_slider->setVisible(!is_controller); range_groupbox->setVisible(is_controller); + ui->controllerFrame->SetPlayerInput(player_index, buttons_param, analogs_param); } } void ConfigureInputPlayer::SetConnectableControllers() { const auto add_controllers = [this](bool enable_all, - Core::HID::NpadStyleTag npad_style_set = {}) { + Controller_NPad::NpadStyleSet npad_style_set = {}) { index_controller_type_pairs.clear(); ui->comboControllerType->clear(); if (enable_all || npad_style_set.fullkey == 1) { index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), - Core::HID::NpadStyleIndex::ProController); + Settings::ControllerType::ProController); ui->comboControllerType->addItem(tr("Pro Controller")); } if (enable_all || npad_style_set.joycon_dual == 1) { index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), - Core::HID::NpadStyleIndex::JoyconDual); + Settings::ControllerType::DualJoyconDetached); ui->comboControllerType->addItem(tr("Dual Joycons")); } if (enable_all || npad_style_set.joycon_left == 1) { index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), - Core::HID::NpadStyleIndex::JoyconLeft); + Settings::ControllerType::LeftJoycon); ui->comboControllerType->addItem(tr("Left Joycon")); } if (enable_all || npad_style_set.joycon_right == 1) { index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), - Core::HID::NpadStyleIndex::JoyconRight); + Settings::ControllerType::RightJoycon); ui->comboControllerType->addItem(tr("Right Joycon")); } if (player_index == 0 && (enable_all || npad_style_set.handheld == 1)) { index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), - Core::HID::NpadStyleIndex::Handheld); + Settings::ControllerType::Handheld); ui->comboControllerType->addItem(tr("Handheld")); } if (enable_all || npad_style_set.gamecube == 1) { index_controller_type_pairs.emplace_back(ui->comboControllerType->count(), - Core::HID::NpadStyleIndex::GameCube); + Settings::ControllerType::GameCube); ui->comboControllerType->addItem(tr("GameCube Controller")); } }; - if (!is_powered_on) { + if (!system.IsPoweredOn()) { add_controllers(true); return; } - add_controllers(false, hid_core.GetSupportedStyleTag()); + Service::SM::ServiceManager& sm = system.ServiceManager(); + + auto& npad = sm.GetService("hid")->GetAppletResource()->GetController( + HidController::NPad); + + add_controllers(false, npad.GetSupportedStyleSet()); } -Core::HID::NpadStyleIndex ConfigureInputPlayer::GetControllerTypeFromIndex(int index) const { +Settings::ControllerType ConfigureInputPlayer::GetControllerTypeFromIndex(int index) const { const auto it = std::find_if(index_controller_type_pairs.begin(), index_controller_type_pairs.end(), [index](const auto& pair) { return pair.first == index; }); if (it == index_controller_type_pairs.end()) { - return Core::HID::NpadStyleIndex::ProController; + return Settings::ControllerType::ProController; } return it->second; } -int ConfigureInputPlayer::GetIndexFromControllerType(Core::HID::NpadStyleIndex type) const { +int ConfigureInputPlayer::GetIndexFromControllerType(Settings::ControllerType type) const { const auto it = std::find_if(index_controller_type_pairs.begin(), index_controller_type_pairs.end(), [type](const auto& pair) { return pair.second == type; }); @@ -880,15 +1057,52 @@ int ConfigureInputPlayer::GetIndexFromControllerType(Core::HID::NpadStyleIndex t void ConfigureInputPlayer::UpdateInputDevices() { input_devices = input_subsystem->GetInputDevices(); ui->comboDevices->clear(); - for (auto device : input_devices) { - ui->comboDevices->addItem(QString::fromStdString(device.Get("display", "Unknown")), {}); + for (auto& device : input_devices) { + const std::string display = device.Get("display", "Unknown"); + ui->comboDevices->addItem(QString::fromStdString(display), {}); + if (display == "TAS") { + device.Set("pad", static_cast(player_index)); + } } } +void ConfigureInputPlayer::UpdateControllerIcon() { + // We aren't using Qt's built in theme support here since we aren't drawing an icon (and its + // "nonstandard" to use an image through the icon support) + const QString stylesheet = [this] { + switch (GetControllerTypeFromIndex(ui->comboControllerType->currentIndex())) { + case Settings::ControllerType::ProController: + return QStringLiteral("image: url(:/controller/pro_controller%0)"); + case Settings::ControllerType::DualJoyconDetached: + return QStringLiteral("image: url(:/controller/dual_joycon%0)"); + case Settings::ControllerType::LeftJoycon: + return QStringLiteral("image: url(:/controller/single_joycon_left_vertical%0)"); + case Settings::ControllerType::RightJoycon: + return QStringLiteral("image: url(:/controller/single_joycon_right_vertical%0)"); + case Settings::ControllerType::Handheld: + return QStringLiteral("image: url(:/controller/handheld%0)"); + default: + return QString{}; + } + }(); + + const QString theme = [] { + if (QIcon::themeName().contains(QStringLiteral("dark"))) { + return QStringLiteral("_dark"); + } else if (QIcon::themeName().contains(QStringLiteral("midnight"))) { + return QStringLiteral("_midnight"); + } else { + return QString{}; + } + }(); + ui->controllerFrame->SetControllerType( + GetControllerTypeFromIndex(ui->comboControllerType->currentIndex())); +} + void ConfigureInputPlayer::UpdateControllerAvailableButtons() { auto layout = GetControllerTypeFromIndex(ui->comboControllerType->currentIndex()); if (debug) { - layout = Core::HID::NpadStyleIndex::ProController; + layout = Settings::ControllerType::ProController; } // List of all the widgets that will be hidden by any of the following layouts that need @@ -913,15 +1127,15 @@ void ConfigureInputPlayer::UpdateControllerAvailableButtons() { std::vector layout_hidden; switch (layout) { - case Core::HID::NpadStyleIndex::ProController: - case Core::HID::NpadStyleIndex::JoyconDual: - case Core::HID::NpadStyleIndex::Handheld: + case Settings::ControllerType::ProController: + case Settings::ControllerType::DualJoyconDetached: + case Settings::ControllerType::Handheld: layout_hidden = { ui->buttonShoulderButtonsSLSR, ui->horizontalSpacerShoulderButtonsWidget2, }; break; - case Core::HID::NpadStyleIndex::JoyconLeft: + case Settings::ControllerType::LeftJoycon: layout_hidden = { ui->horizontalSpacerShoulderButtonsWidget2, ui->buttonShoulderButtonsRight, @@ -929,7 +1143,7 @@ void ConfigureInputPlayer::UpdateControllerAvailableButtons() { ui->bottomRight, }; break; - case Core::HID::NpadStyleIndex::JoyconRight: + case Settings::ControllerType::RightJoycon: layout_hidden = { ui->horizontalSpacerShoulderButtonsWidget, ui->buttonShoulderButtonsLeft, @@ -937,7 +1151,7 @@ void ConfigureInputPlayer::UpdateControllerAvailableButtons() { ui->bottomLeft, }; break; - case Core::HID::NpadStyleIndex::GameCube: + case Settings::ControllerType::GameCube: layout_hidden = { ui->buttonShoulderButtonsSLSR, ui->horizontalSpacerShoulderButtonsWidget2, @@ -945,8 +1159,6 @@ void ConfigureInputPlayer::UpdateControllerAvailableButtons() { ui->buttonMiscButtonsScreenshotGroup, }; break; - default: - break; } for (auto* widget : layout_hidden) { @@ -957,12 +1169,13 @@ void ConfigureInputPlayer::UpdateControllerAvailableButtons() { void ConfigureInputPlayer::UpdateControllerEnabledButtons() { auto layout = GetControllerTypeFromIndex(ui->comboControllerType->currentIndex()); if (debug) { - layout = Core::HID::NpadStyleIndex::ProController; + layout = Settings::ControllerType::ProController; } // List of all the widgets that will be disabled by any of the following layouts that need // "enabled" after the controller type changes - const std::array layout_enable = { + const std::array layout_enable = { + ui->buttonHome, ui->buttonLStickPressedGroup, ui->groupRStickPressed, ui->buttonShoulderButtonsButtonLGroup, @@ -974,13 +1187,17 @@ void ConfigureInputPlayer::UpdateControllerEnabledButtons() { std::vector layout_disable; switch (layout) { - case Core::HID::NpadStyleIndex::ProController: - case Core::HID::NpadStyleIndex::JoyconDual: - case Core::HID::NpadStyleIndex::Handheld: - case Core::HID::NpadStyleIndex::JoyconLeft: - case Core::HID::NpadStyleIndex::JoyconRight: + case Settings::ControllerType::ProController: + case Settings::ControllerType::DualJoyconDetached: + case Settings::ControllerType::Handheld: + case Settings::ControllerType::LeftJoycon: + case Settings::ControllerType::RightJoycon: + // TODO(wwylele): enable this when we actually emulate it + layout_disable = { + ui->buttonHome, + }; break; - case Core::HID::NpadStyleIndex::GameCube: + case Settings::ControllerType::GameCube: layout_disable = { ui->buttonHome, ui->buttonLStickPressedGroup, @@ -988,8 +1205,6 @@ void ConfigureInputPlayer::UpdateControllerEnabledButtons() { ui->buttonShoulderButtonsButtonLGroup, }; break; - default: - break; } for (auto* widget : layout_disable) { @@ -1007,24 +1222,24 @@ void ConfigureInputPlayer::UpdateMotionButtons() { // Show/hide the "Motion 1/2" groupboxes depending on the currently selected controller. switch (GetControllerTypeFromIndex(ui->comboControllerType->currentIndex())) { - case Core::HID::NpadStyleIndex::ProController: - case Core::HID::NpadStyleIndex::JoyconLeft: - case Core::HID::NpadStyleIndex::Handheld: + case Settings::ControllerType::ProController: + case Settings::ControllerType::LeftJoycon: + case Settings::ControllerType::Handheld: // Show "Motion 1" and hide "Motion 2". ui->buttonMotionLeftGroup->show(); ui->buttonMotionRightGroup->hide(); break; - case Core::HID::NpadStyleIndex::JoyconRight: + case Settings::ControllerType::RightJoycon: // Show "Motion 2" and hide "Motion 1". ui->buttonMotionLeftGroup->hide(); ui->buttonMotionRightGroup->show(); break; - case Core::HID::NpadStyleIndex::GameCube: + case Settings::ControllerType::GameCube: // Hide both "Motion 1/2". ui->buttonMotionLeftGroup->hide(); ui->buttonMotionRightGroup->hide(); break; - case Core::HID::NpadStyleIndex::JoyconDual: + case Settings::ControllerType::DualJoyconDetached: default: // Show both "Motion 1/2". ui->buttonMotionLeftGroup->show(); @@ -1036,15 +1251,15 @@ void ConfigureInputPlayer::UpdateMotionButtons() { void ConfigureInputPlayer::UpdateControllerButtonNames() { auto layout = GetControllerTypeFromIndex(ui->comboControllerType->currentIndex()); if (debug) { - layout = Core::HID::NpadStyleIndex::ProController; + layout = Settings::ControllerType::ProController; } switch (layout) { - case Core::HID::NpadStyleIndex::ProController: - case Core::HID::NpadStyleIndex::JoyconDual: - case Core::HID::NpadStyleIndex::Handheld: - case Core::HID::NpadStyleIndex::JoyconLeft: - case Core::HID::NpadStyleIndex::JoyconRight: + case Settings::ControllerType::ProController: + case Settings::ControllerType::DualJoyconDetached: + case Settings::ControllerType::Handheld: + case Settings::ControllerType::LeftJoycon: + case Settings::ControllerType::RightJoycon: ui->buttonMiscButtonsPlusGroup->setTitle(tr("Plus")); ui->buttonShoulderButtonsButtonZLGroup->setTitle(tr("ZL")); ui->buttonShoulderButtonsZRGroup->setTitle(tr("ZR")); @@ -1052,7 +1267,7 @@ void ConfigureInputPlayer::UpdateControllerButtonNames() { ui->LStick->setTitle(tr("Left Stick")); ui->RStick->setTitle(tr("Right Stick")); break; - case Core::HID::NpadStyleIndex::GameCube: + case Settings::ControllerType::GameCube: ui->buttonMiscButtonsPlusGroup->setTitle(tr("Start / Pause")); ui->buttonShoulderButtonsButtonZLGroup->setTitle(tr("L")); ui->buttonShoulderButtonsZRGroup->setTitle(tr("R")); @@ -1060,8 +1275,6 @@ void ConfigureInputPlayer::UpdateControllerButtonNames() { ui->LStick->setTitle(tr("Control Stick")); ui->RStick->setTitle(tr("C-Stick")); break; - default: - break; } } @@ -1070,82 +1283,45 @@ void ConfigureInputPlayer::UpdateMappingWithDefaults() { return; } - for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; ++button_id) { - const auto* const button = button_map[button_id]; - if (button == nullptr) { - continue; - } - emulated_controller->SetButtonParam(button_id, {}); - } - - for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; ++analog_id) { - for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; ++sub_button_id) { - const auto* const analog_button = analog_map_buttons[analog_id][sub_button_id]; - if (analog_button == nullptr) { - continue; - } - emulated_controller->SetStickParam(analog_id, {}); - } - } - - for (int motion_id = 0; motion_id < Settings::NativeMotion::NumMotions; ++motion_id) { - const auto* const motion_button = motion_map[motion_id]; - if (motion_button == nullptr) { - continue; - } - emulated_controller->SetMotionParam(motion_id, {}); - } - - // Reset keyboard or mouse bindings - if (ui->comboDevices->currentIndex() == 1 || ui->comboDevices->currentIndex() == 2) { + if (ui->comboDevices->currentIndex() == 1) { + // Reset keyboard bindings for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; ++button_id) { - emulated_controller->SetButtonParam( - button_id, Common::ParamPackage{InputCommon::GenerateKeyboardParam( - Config::default_buttons[button_id])}); + buttons_param[button_id] = Common::ParamPackage{ + InputCommon::GenerateKeyboardParam(Config::default_buttons[button_id])}; } for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; ++analog_id) { - Common::ParamPackage analog_param{}; for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; ++sub_button_id) { Common::ParamPackage params{InputCommon::GenerateKeyboardParam( Config::default_analogs[analog_id][sub_button_id])}; - SetAnalogParam(params, analog_param, analog_sub_buttons[sub_button_id]); + SetAnalogParam(params, analogs_param[analog_id], analog_sub_buttons[sub_button_id]); } - analog_param.Set("modifier", InputCommon::GenerateKeyboardParam( - Config::default_stick_mod[analog_id])); - emulated_controller->SetStickParam(analog_id, analog_param); + analogs_param[analog_id].Set("modifier", InputCommon::GenerateKeyboardParam( + Config::default_stick_mod[analog_id])); } for (int motion_id = 0; motion_id < Settings::NativeMotion::NumMotions; ++motion_id) { - emulated_controller->SetMotionParam( - motion_id, Common::ParamPackage{InputCommon::GenerateKeyboardParam( - Config::default_motions[motion_id])}); + motions_param[motion_id] = Common::ParamPackage{ + InputCommon::GenerateKeyboardParam(Config::default_motions[motion_id])}; } - // If mouse is selected we want to override with mappings from the driver - if (ui->comboDevices->currentIndex() == 1) { - UpdateUI(); - return; - } + UpdateUI(); + return; } // Reset controller bindings const auto& device = input_devices[ui->comboDevices->currentIndex()]; - auto button_mappings = input_subsystem->GetButtonMappingForDevice(device); - auto analog_mappings = input_subsystem->GetAnalogMappingForDevice(device); - auto motion_mappings = input_subsystem->GetMotionMappingForDevice(device); - - for (const auto& button_mapping : button_mappings) { - const std::size_t index = button_mapping.first; - emulated_controller->SetButtonParam(index, button_mapping.second); + auto button_mapping = input_subsystem->GetButtonMappingForDevice(device); + auto analog_mapping = input_subsystem->GetAnalogMappingForDevice(device); + auto motion_mapping = input_subsystem->GetMotionMappingForDevice(device); + for (std::size_t i = 0; i < buttons_param.size(); ++i) { + buttons_param[i] = button_mapping[static_cast(i)]; } - for (const auto& analog_mapping : analog_mappings) { - const std::size_t index = analog_mapping.first; - emulated_controller->SetStickParam(index, analog_mapping.second); + for (std::size_t i = 0; i < analogs_param.size(); ++i) { + analogs_param[i] = analog_mapping[static_cast(i)]; } - for (const auto& motion_mapping : motion_mappings) { - const std::size_t index = motion_mapping.first; - emulated_controller->SetMotionParam(index, motion_mapping.second); + for (std::size_t i = 0; i < motions_param.size(); ++i) { + motions_param[i] = motion_mapping[static_cast(i)]; } UpdateUI(); @@ -1154,7 +1330,7 @@ void ConfigureInputPlayer::UpdateMappingWithDefaults() { void ConfigureInputPlayer::HandleClick( QPushButton* button, std::size_t button_id, std::function new_input_setter, - InputCommon::Polling::InputType type) { + InputCommon::Polling::DeviceType type) { if (button == ui->buttonMotionLeft || button == ui->buttonMotionRight) { button->setText(tr("Shake!")); } else { @@ -1162,31 +1338,71 @@ void ConfigureInputPlayer::HandleClick( } button->setFocus(); + // The first two input devices are always Any and Keyboard/Mouse. If the user filtered to a + // controller, then they don't want keyboard/mouse input + want_keyboard_mouse = ui->comboDevices->currentIndex() < 2; + input_setter = new_input_setter; - input_subsystem->BeginMapping(type); + device_pollers = input_subsystem->GetPollers(type); + + for (auto& poller : device_pollers) { + poller->Start(); + } QWidget::grabMouse(); QWidget::grabKeyboard(); - if (type == InputCommon::Polling::InputType::Button) { + if (type == InputCommon::Polling::DeviceType::Button) { + input_subsystem->GetGCButtons()->BeginConfiguration(); + } else { + input_subsystem->GetGCAnalogs()->BeginConfiguration(); + } + + if (type == InputCommon::Polling::DeviceType::Motion) { + input_subsystem->GetUDPMotions()->BeginConfiguration(); + } + + if (type == InputCommon::Polling::DeviceType::Button) { + input_subsystem->GetMouseButtons()->BeginConfiguration(); + } else if (type == InputCommon::Polling::DeviceType::AnalogPreferred) { + input_subsystem->GetMouseAnalogs()->BeginConfiguration(); + } else if (type == InputCommon::Polling::DeviceType::Motion) { + input_subsystem->GetMouseMotions()->BeginConfiguration(); + } else { + input_subsystem->GetMouseTouch()->BeginConfiguration(); + } + + if (type == InputCommon::Polling::DeviceType::Button) { ui->controllerFrame->BeginMappingButton(button_id); - } else if (type == InputCommon::Polling::InputType::Stick) { + } else if (type == InputCommon::Polling::DeviceType::AnalogPreferred) { ui->controllerFrame->BeginMappingAnalog(button_id); } timeout_timer->start(2500); // Cancel after 2.5 seconds - poll_timer->start(25); // Check for new inputs every 25ms + poll_timer->start(50); // Check for new inputs every 50ms } void ConfigureInputPlayer::SetPollingResult(const Common::ParamPackage& params, bool abort) { timeout_timer->stop(); poll_timer->stop(); - input_subsystem->StopMapping(); + for (auto& poller : device_pollers) { + poller->Stop(); + } QWidget::releaseMouse(); QWidget::releaseKeyboard(); + input_subsystem->GetGCButtons()->EndConfiguration(); + input_subsystem->GetGCAnalogs()->EndConfiguration(); + + input_subsystem->GetUDPMotions()->EndConfiguration(); + + input_subsystem->GetMouseButtons()->EndConfiguration(); + input_subsystem->GetMouseAnalogs()->EndConfiguration(); + input_subsystem->GetMouseMotions()->EndConfiguration(); + input_subsystem->GetMouseTouch()->EndConfiguration(); + if (!abort) { (*input_setter)(params); } @@ -1203,20 +1419,15 @@ bool ConfigureInputPlayer::IsInputAcceptable(const Common::ParamPackage& params) return true; } - if (params.Has("motion")) { - return true; - } - // Keyboard/Mouse - if (ui->comboDevices->currentIndex() == 1 || ui->comboDevices->currentIndex() == 2) { + if (ui->comboDevices->currentIndex() == 1) { return params.Get("engine", "") == "keyboard" || params.Get("engine", "") == "mouse"; } const auto current_input_device = input_devices[ui->comboDevices->currentIndex()]; - return params.Get("engine", "") == current_input_device.Get("engine", "") && - (params.Get("guid", "") == current_input_device.Get("guid", "") || - params.Get("guid", "") == current_input_device.Get("guid2", "")) && - params.Get("port", 0) == current_input_device.Get("port", 0); + return params.Get("engine", "") == current_input_device.Get("class", "") && + params.Get("guid", "") == current_input_device.Get("guid", "") && + params.Get("port", "") == current_input_device.Get("port", ""); } void ConfigureInputPlayer::mousePressEvent(QMouseEvent* event) { @@ -1225,17 +1436,25 @@ void ConfigureInputPlayer::mousePressEvent(QMouseEvent* event) { } const auto button = GRenderWindow::QtButtonToMouseButton(event->button()); - input_subsystem->GetMouse()->PressButton(0, 0, 0, 0, button); + input_subsystem->GetMouse()->PressButton(0, 0, button); } void ConfigureInputPlayer::keyPressEvent(QKeyEvent* event) { - event->ignore(); if (!input_setter || !event) { return; } + if (event->key() != Qt::Key_Escape) { - input_subsystem->GetKeyboard()->PressKey(event->key()); + if (want_keyboard_mouse) { + SetPollingResult(Common::ParamPackage{InputCommon::GenerateKeyboardParam(event->key())}, + false); + } else { + // Escape key wasn't pressed and we don't want any keyboard keys, so don't stop polling + return; + } } + + SetPollingResult({}, true); } void ConfigureInputPlayer::CreateProfile() { diff --git a/src/yuzu/configuration/configure_input_player.h b/src/yuzu/configuration/configure_input_player.h index 47df6b3d3..39b44b8a5 100755 --- a/src/yuzu/configuration/configure_input_player.h +++ b/src/yuzu/configuration/configure_input_player.h @@ -29,37 +29,48 @@ class QWidget; class InputProfiles; +namespace Core { +class System; +} + namespace InputCommon { class InputSubsystem; } namespace InputCommon::Polling { -enum class InputType; +class DevicePoller; +enum class DeviceType; } // namespace InputCommon::Polling namespace Ui { class ConfigureInputPlayer; } -namespace Core::HID { -class HIDCore; -class EmulatedController; -enum class NpadStyleIndex : u8; -} // namespace Core::HID - class ConfigureInputPlayer : public QWidget { Q_OBJECT public: explicit ConfigureInputPlayer(QWidget* parent, std::size_t player_index, QWidget* bottom_row, InputCommon::InputSubsystem* input_subsystem_, - InputProfiles* profiles_, Core::HID::HIDCore& hid_core_, - bool is_powered_on_, bool debug = false); + InputProfiles* profiles_, Core::System& system_, + bool debug = false); ~ConfigureInputPlayer() override; /// Save all button configurations to settings file. void ApplyConfiguration(); + /** + * Attempts to connect the currently selected controller in the HID backend. + * This function will not do anything if it is not connected in the frontend. + */ + void TryConnectSelectedController(); + + /** + * Attempts to disconnect the currently selected controller in the HID backend. + * This function will not do anything if the configuration has not changed. + */ + void TryDisconnectSelectedController(); + /// Set the connection state checkbox (used to sync state). void ConnectPlayer(bool connected); @@ -93,10 +104,6 @@ protected: void showEvent(QShowEvent* event) override; private: - QString ButtonToText(const Common::ParamPackage& param); - - QString AnalogToText(const Common::ParamPackage& param, const std::string& dir); - void changeEvent(QEvent* event) override; void RetranslateUI(); @@ -106,7 +113,7 @@ private: /// Called when the button was pressed. void HandleClick(QPushButton* button, std::size_t button_id, std::function new_input_setter, - InputCommon::Polling::InputType type); + InputCommon::Polling::DeviceType type); /// Finish polling and configure input using the input_setter. void SetPollingResult(const Common::ParamPackage& params, bool abort); @@ -127,14 +134,17 @@ private: void SetConnectableControllers(); /// Gets the Controller Type for a given controller combobox index. - Core::HID::NpadStyleIndex GetControllerTypeFromIndex(int index) const; + Settings::ControllerType GetControllerTypeFromIndex(int index) const; /// Gets the controller combobox index for a given Controller Type. - int GetIndexFromControllerType(Core::HID::NpadStyleIndex type) const; + int GetIndexFromControllerType(Settings::ControllerType type) const; /// Update the available input devices. void UpdateInputDevices(); + /// Update the current controller icon. + void UpdateControllerIcon(); + /// Hides and disables controller settings based on the current controller type. void UpdateControllerAvailableButtons(); @@ -166,7 +176,6 @@ private: std::size_t player_index; bool debug; - bool is_powered_on; InputCommon::InputSubsystem* input_subsystem; @@ -176,7 +185,7 @@ private: std::unique_ptr poll_timer; /// Stores a pair of "Connected Controllers" combobox index and Controller Type enum. - std::vector> index_controller_type_pairs; + std::vector> index_controller_type_pairs; static constexpr int PLAYER_COUNT = 8; std::array player_connected_checkbox; @@ -184,7 +193,9 @@ private: /// This will be the the setting function when an input is awaiting configuration. std::optional> input_setter; - Core::HID::EmulatedController* emulated_controller; + std::array buttons_param; + std::array analogs_param; + std::array motions_param; static constexpr int ANALOG_SUB_BUTTONS_NUM = 4; @@ -210,9 +221,15 @@ private: static const std::array analog_sub_buttons; + std::vector> device_pollers; + /// A flag to indicate that the "Map Analog Stick" pop-up has been shown and accepted once. bool map_analog_stick_accepted{}; + /// A flag to indicate if keyboard keys are okay when configuring an input. If this is false, + /// keyboard events are ignored. + bool want_keyboard_mouse{}; + /// List of physical devices users can map with. If a SDL backed device is selected, then you /// can use this device to get a default mapping. std::vector input_devices; @@ -222,5 +239,5 @@ private: /// parent of the widget to this widget (but thats fine). QWidget* bottom_row; - Core::HID::HIDCore& hid_core; + Core::System& system; }; diff --git a/src/yuzu/configuration/configure_input_player.ui b/src/yuzu/configuration/configure_input_player.ui index 756a414b5..e7433912b 100755 --- a/src/yuzu/configuration/configure_input_player.ui +++ b/src/yuzu/configuration/configure_input_player.ui @@ -89,6 +89,31 @@ 21 + + + Pro Controller + + + + + Dual Joycons + + + + + Left Joycon + + + + + Right Joycon + + + + + Handheld + + @@ -117,9 +142,22 @@ - - 60 + + + 0 + 21 + + + + Any + + + + + Keyboard/Mouse + + @@ -304,7 +342,7 @@ 3 - 6 + 0 3 @@ -880,7 +918,7 @@ 3 - 6 + 0 3 @@ -2183,7 +2221,7 @@ 3 - 6 + 0 3 @@ -2532,7 +2570,7 @@ 3 - 6 + 0 3 diff --git a/src/yuzu/configuration/configure_input_player_widget.cpp b/src/yuzu/configuration/configure_input_player_widget.cpp index 6630321cb..f31f86339 100755 --- a/src/yuzu/configuration/configure_input_player_widget.cpp +++ b/src/yuzu/configuration/configure_input_player_widget.cpp @@ -6,12 +6,10 @@ #include #include #include - -#include "core/hid/emulated_controller.h" #include "yuzu/configuration/configure_input_player_widget.h" PlayerControlPreview::PlayerControlPreview(QWidget* parent) : QFrame(parent) { - is_controller_set = false; + UpdateColors(); QTimer* timer = new QTimer(this); connect(timer, &QTimer::timeout, this, QOverload<>::of(&PlayerControlPreview::UpdateInput)); @@ -19,37 +17,91 @@ PlayerControlPreview::PlayerControlPreview(QWidget* parent) : QFrame(parent) { timer->start(16); } -PlayerControlPreview::~PlayerControlPreview() { - UnloadController(); -}; +PlayerControlPreview::~PlayerControlPreview() = default; -void PlayerControlPreview::SetController(Core::HID::EmulatedController* controller_) { - UnloadController(); - is_controller_set = true; - controller = controller_; - Core::HID::ControllerUpdateCallback engine_callback{ - .on_change = [this](Core::HID::ControllerTriggerType type) { ControllerUpdate(type); }, - .is_npad_service = false, - }; - callback_key = controller->SetCallback(engine_callback); - ControllerUpdate(Core::HID::ControllerTriggerType::All); +void PlayerControlPreview::SetPlayerInput(std::size_t index, const ButtonParam& buttons_param, + const AnalogParam& analogs_param) { + player_index = index; + Settings::ButtonsRaw buttonss; + Settings::AnalogsRaw analogs; + std::transform(buttons_param.begin(), buttons_param.end(), buttonss.begin(), + [](const Common::ParamPackage& param) { return param.Serialize(); }); + std::transform(analogs_param.begin(), analogs_param.end(), analogs.begin(), + [](const Common::ParamPackage& param) { return param.Serialize(); }); + + std::transform(buttonss.begin() + Settings::NativeButton::BUTTON_HID_BEGIN, + buttonss.begin() + Settings::NativeButton::BUTTON_NS_END, buttons.begin(), + Input::CreateDevice); + std::transform(analogs.begin() + Settings::NativeAnalog::STICK_HID_BEGIN, + analogs.begin() + Settings::NativeAnalog::STICK_HID_END, sticks.begin(), + Input::CreateDevice); + UpdateColors(); +} +void PlayerControlPreview::SetPlayerInputRaw(std::size_t index, + const Settings::ButtonsRaw& buttons_, + Settings::AnalogsRaw analogs_) { + player_index = index; + std::transform(buttons_.begin() + Settings::NativeButton::BUTTON_HID_BEGIN, + buttons_.begin() + Settings::NativeButton::BUTTON_NS_END, buttons.begin(), + Input::CreateDevice); + std::transform(analogs_.begin() + Settings::NativeAnalog::STICK_HID_BEGIN, + analogs_.begin() + Settings::NativeAnalog::STICK_HID_END, sticks.begin(), + Input::CreateDevice); + UpdateColors(); } -void PlayerControlPreview::UnloadController() { - if (is_controller_set) { - controller->DeleteCallback(callback_key); - is_controller_set = false; +PlayerControlPreview::LedPattern PlayerControlPreview::GetColorPattern(std::size_t index, + bool player_on) { + if (!player_on) { + return {0, 0, 0, 0}; + } + + switch (index) { + case 0: + return {1, 0, 0, 0}; + case 1: + return {1, 1, 0, 0}; + case 2: + return {1, 1, 1, 0}; + case 3: + return {1, 1, 1, 1}; + case 4: + return {1, 0, 0, 1}; + case 5: + return {1, 0, 1, 0}; + case 6: + return {1, 0, 1, 1}; + case 7: + return {0, 1, 1, 0}; + default: + return {0, 0, 0, 0}; } } -void PlayerControlPreview::BeginMappingButton(std::size_t button_id) { - button_mapping_index = button_id; +void PlayerControlPreview::SetConnectedStatus(bool checked) { + LedPattern led_pattern = GetColorPattern(player_index, checked); + + led_color[0] = led_pattern.position1 ? colors.led_on : colors.led_off; + led_color[1] = led_pattern.position2 ? colors.led_on : colors.led_off; + led_color[2] = led_pattern.position3 ? colors.led_on : colors.led_off; + led_color[3] = led_pattern.position4 ? colors.led_on : colors.led_off; + is_enabled = checked; + ResetInputs(); +} + +void PlayerControlPreview::SetControllerType(const Settings::ControllerType type) { + controller_type = type; + UpdateColors(); +} + +void PlayerControlPreview::BeginMappingButton(std::size_t index) { + button_mapping_index = index; mapping_active = true; } -void PlayerControlPreview::BeginMappingAnalog(std::size_t stick_id) { - button_mapping_index = Settings::NativeButton::LStick + stick_id; - analog_mapping_index = stick_id; +void PlayerControlPreview::BeginMappingAnalog(std::size_t index) { + button_mapping_index = Settings::NativeButton::LStick + index; + analog_mapping_index = index; mapping_active = true; } @@ -105,109 +157,84 @@ void PlayerControlPreview::UpdateColors() { colors.left = colors.primary; colors.right = colors.primary; // Possible alternative to set colors from settings - // colors.left = QColor(controller->GetColors().left.body); - // colors.right = QColor(controller->GetColors().right.body); + // colors.left = QColor(Settings::values.players.GetValue()[player_index].body_color_left); + // colors.right = QColor(Settings::values.players.GetValue()[player_index].body_color_right); } void PlayerControlPreview::ResetInputs() { - button_values.fill({ - .value = false, - }); - stick_values.fill({ - .x = {.value = 0, .properties = {0, 1, 0}}, - .y = {.value = 0, .properties = {0, 1, 0}}, - }); - trigger_values.fill({ - .analog = {.value = 0, .properties = {0, 1, 0}}, - .pressed = {.value = false}, - }); + for (std::size_t index = 0; index < button_values.size(); ++index) { + button_values[index] = false; + } + + for (std::size_t index = 0; index < axis_values.size(); ++index) { + axis_values[index].properties = {0, 1, 0}; + axis_values[index].value = {0, 0}; + axis_values[index].raw_value = {0, 0}; + } update(); } -void PlayerControlPreview::ControllerUpdate(Core::HID::ControllerTriggerType type) { - if (type == Core::HID::ControllerTriggerType::All) { - ControllerUpdate(Core::HID::ControllerTriggerType::Color); - ControllerUpdate(Core::HID::ControllerTriggerType::Type); - ControllerUpdate(Core::HID::ControllerTriggerType::Connected); - ControllerUpdate(Core::HID::ControllerTriggerType::Button); - ControllerUpdate(Core::HID::ControllerTriggerType::Stick); - ControllerUpdate(Core::HID::ControllerTriggerType::Trigger); - ControllerUpdate(Core::HID::ControllerTriggerType::Battery); +void PlayerControlPreview::UpdateInput() { + if (!is_enabled && !mapping_active && !Settings::values.tas_enable) { return; } - - switch (type) { - case Core::HID::ControllerTriggerType::Connected: - is_connected = true; - led_pattern = controller->GetLedPattern(); - needs_redraw = true; - break; - case Core::HID::ControllerTriggerType::Disconnected: - is_connected = false; - led_pattern.raw = 0; - needs_redraw = true; - break; - case Core::HID::ControllerTriggerType::Type: - controller_type = controller->GetNpadStyleIndex(true); - needs_redraw = true; - break; - case Core::HID::ControllerTriggerType::Color: - UpdateColors(); - needs_redraw = true; - break; - case Core::HID::ControllerTriggerType::Button: - button_values = controller->GetButtonsValues(); - needs_redraw = true; - break; - case Core::HID::ControllerTriggerType::Stick: - using namespace Settings::NativeAnalog; - stick_values = controller->GetSticksValues(); - // Y axis is inverted - stick_values[LStick].y.value = -stick_values[LStick].y.value; - stick_values[LStick].y.raw_value = -stick_values[LStick].y.raw_value; - stick_values[RStick].y.value = -stick_values[RStick].y.value; - stick_values[RStick].y.raw_value = -stick_values[RStick].y.raw_value; - needs_redraw = true; - break; - case Core::HID::ControllerTriggerType::Trigger: - trigger_values = controller->GetTriggersValues(); - needs_redraw = true; - break; - case Core::HID::ControllerTriggerType::Battery: - battery_values = controller->GetBatteryValues(); - needs_redraw = true; - break; - default: - break; + bool input_changed = false; + const auto& button_state = buttons; + for (std::size_t index = 0; index < button_values.size(); ++index) { + bool value = false; + if (index < Settings::NativeButton::BUTTON_NS_END) { + value = button_state[index]->GetStatus(); + } + bool blink = mapping_active && index == button_mapping_index; + if (analog_mapping_index == Settings::NativeAnalog::NUM_STICKS_HID) { + blink &= blink_counter > 25; + } + if (button_values[index] != value || blink) { + input_changed = true; + } + button_values[index] = value || blink; } -} -void PlayerControlPreview::UpdateInput() { - if (mapping_active) { + const auto& analog_state = sticks; + for (std::size_t index = 0; index < axis_values.size(); ++index) { + const auto [stick_x_f, stick_y_f] = analog_state[index]->GetStatus(); + const auto [stick_x_rf, stick_y_rf] = analog_state[index]->GetRawStatus(); - for (std::size_t index = 0; index < button_values.size(); ++index) { - bool blink = index == button_mapping_index; - if (analog_mapping_index == Settings::NativeAnalog::NumAnalogs) { - blink &= blink_counter > 25; - } - if (button_values[index].value != blink) { - needs_redraw = true; - } - button_values[index].value = blink; + if (static_cast(stick_x_rf * 45) != + static_cast(axis_values[index].raw_value.x() * 45) || + static_cast(-stick_y_rf * 45) != + static_cast(axis_values[index].raw_value.y() * 45)) { + input_changed = true; } - for (std::size_t index = 0; index < stick_values.size(); ++index) { - const bool blink_analog = index == analog_mapping_index; - if (blink_analog) { - needs_redraw = true; - stick_values[index].x.value = blink_counter < 25 ? -blink_counter / 25.0f : 0; - stick_values[index].y.value = - blink_counter > 25 ? -(blink_counter - 25) / 25.0f : 0; - } + axis_values[index].properties = analog_state[index]->GetAnalogProperties(); + axis_values[index].value = QPointF(stick_x_f, -stick_y_f); + axis_values[index].raw_value = QPointF(stick_x_rf, -stick_y_rf); + + const bool blink_analog = mapping_active && index == analog_mapping_index; + if (blink_analog) { + input_changed = true; + axis_values[index].value = + QPointF(blink_counter < 25 ? -blink_counter / 25.0f : 0, + blink_counter > 25 ? -(blink_counter - 25) / 25.0f : 0); } } - if (needs_redraw) { + + if (input_changed) { update(); + if (controller_callback.input != nullptr) { + ControllerInput input{ + .axis_values = {std::pair{ + axis_values[Settings::NativeAnalog::LStick].value.x(), + axis_values[Settings::NativeAnalog::LStick].value.y()}, + std::pair{ + axis_values[Settings::NativeAnalog::RStick].value.x(), + axis_values[Settings::NativeAnalog::RStick].value.y()}}, + .button_values = button_values, + .changed = true, + }; + controller_callback.input(std::move(input)); + } } if (mapping_active) { @@ -215,6 +242,10 @@ void PlayerControlPreview::UpdateInput() { } } +void PlayerControlPreview::SetCallBack(ControllerCallback callback_) { + controller_callback = std::move(callback_); +} + void PlayerControlPreview::paintEvent(QPaintEvent* event) { QFrame::paintEvent(event); QPainter p(this); @@ -222,22 +253,22 @@ void PlayerControlPreview::paintEvent(QPaintEvent* event) { const QPointF center = rect().center(); switch (controller_type) { - case Core::HID::NpadStyleIndex::Handheld: + case Settings::ControllerType::Handheld: DrawHandheldController(p, center); break; - case Core::HID::NpadStyleIndex::JoyconDual: + case Settings::ControllerType::DualJoyconDetached: DrawDualController(p, center); break; - case Core::HID::NpadStyleIndex::JoyconLeft: + case Settings::ControllerType::LeftJoycon: DrawLeftController(p, center); break; - case Core::HID::NpadStyleIndex::JoyconRight: + case Settings::ControllerType::RightJoycon: DrawRightController(p, center); break; - case Core::HID::NpadStyleIndex::GameCube: + case Settings::ControllerType::GameCube: DrawGCController(p, center); break; - case Core::HID::NpadStyleIndex::ProController: + case Settings::ControllerType::ProController: default: DrawProController(p, center); break; @@ -250,7 +281,7 @@ void PlayerControlPreview::DrawLeftController(QPainter& p, const QPointF center) // Sideview left joystick DrawJoystickSideview(p, center + QPoint(142, -69), - -stick_values[Settings::NativeAnalog::LStick].y.value, 1.15f, + -axis_values[Settings::NativeAnalog::LStick].value.y(), 1.15f, button_values[LStick]); // Topview D-pad buttons @@ -261,7 +292,7 @@ void PlayerControlPreview::DrawLeftController(QPainter& p, const QPointF center) // Topview left joystick DrawJoystickSideview(p, center + QPointF(-140.5f, -28), - -stick_values[Settings::NativeAnalog::LStick].x.value + 15.0f, 1.15f, + -axis_values[Settings::NativeAnalog::LStick].value.x() + 15.0f, 1.15f, button_values[LStick]); // Topview minus button @@ -303,10 +334,8 @@ void PlayerControlPreview::DrawLeftController(QPainter& p, const QPointF center) { // Draw joysticks using namespace Settings::NativeAnalog; - DrawJoystick(p, - center + QPointF(9, -69) + - (QPointF(stick_values[LStick].x.value, stick_values[LStick].y.value) * 8), - 1.8f, button_values[Settings::NativeButton::LStick]); + DrawJoystick(p, center + QPointF(9, -69) + (axis_values[LStick].value * 8), 1.8f, + button_values[Settings::NativeButton::LStick]); DrawRawJoystick(p, center + QPointF(-140, 90), QPointF(0, 0)); } @@ -355,10 +384,6 @@ void PlayerControlPreview::DrawLeftController(QPainter& p, const QPointF center) p.setPen(colors.font2); p.setBrush(colors.font2); DrawCircle(p, center + QPoint(26, 71), 5); - - // Draw battery - DrawBattery(p, center + QPoint(-170, -140), - battery_values[Core::HID::EmulatedDeviceIndex::LeftIndex]); } void PlayerControlPreview::DrawRightController(QPainter& p, const QPointF center) { @@ -367,22 +392,20 @@ void PlayerControlPreview::DrawRightController(QPainter& p, const QPointF center // Sideview right joystick DrawJoystickSideview(p, center + QPoint(173 - 315, 11), - stick_values[Settings::NativeAnalog::RStick].y.value + 10.0f, 1.15f, + axis_values[Settings::NativeAnalog::RStick].value.y() + 10.0f, 1.15f, button_values[Settings::NativeButton::RStick]); - // Topview right joystick - DrawJoystickSideview(p, center + QPointF(140, -28), - -stick_values[Settings::NativeAnalog::RStick].x.value + 15.0f, 1.15f, - button_values[RStick]); - // Topview face buttons p.setPen(colors.outline); button_color = colors.button; DrawRoundButton(p, center + QPoint(163, -21), button_values[A], 11, 5, Direction::Up); - DrawRoundButton(p, center + QPoint(140, -21), button_values[B], 11, 5, Direction::Up); - DrawRoundButton(p, center + QPoint(140, -21), button_values[X], 11, 5, Direction::Up); DrawRoundButton(p, center + QPoint(117, -21), button_values[Y], 11, 5, Direction::Up); + // Topview right joystick + DrawJoystickSideview(p, center + QPointF(140, -28), + -axis_values[Settings::NativeAnalog::RStick].value.x() + 15.0f, 1.15f, + button_values[RStick]); + // Topview plus button p.setPen(colors.outline); button_color = colors.button; @@ -425,10 +448,8 @@ void PlayerControlPreview::DrawRightController(QPainter& p, const QPointF center { // Draw joysticks using namespace Settings::NativeAnalog; - DrawJoystick(p, - center + QPointF(-9, 11) + - (QPointF(stick_values[RStick].x.value, stick_values[RStick].y.value) * 8), - 1.8f, button_values[Settings::NativeButton::RStick]); + DrawJoystick(p, center + QPointF(-9, 11) + (axis_values[RStick].value * 8), 1.8f, + button_values[Settings::NativeButton::RStick]); DrawRawJoystick(p, QPointF(0, 0), center + QPointF(140, 90)); } @@ -482,10 +503,6 @@ void PlayerControlPreview::DrawRightController(QPainter& p, const QPointF center p.setPen(colors.transparent); p.setBrush(colors.font2); DrawSymbol(p, center + QPoint(-26, 66), Symbol::House, 5); - - // Draw battery - DrawBattery(p, center + QPoint(110, -140), - battery_values[Core::HID::EmulatedDeviceIndex::RightIndex]); } void PlayerControlPreview::DrawDualController(QPainter& p, const QPointF center) { @@ -495,19 +512,17 @@ void PlayerControlPreview::DrawDualController(QPainter& p, const QPointF center) // Left/Right trigger DrawDualTriggers(p, center, button_values[L], button_values[R]); - // Topview right joystick - DrawJoystickSideview(p, center + QPointF(180, -78), - -stick_values[Settings::NativeAnalog::RStick].x.value + 15.0f, 1, - button_values[RStick]); - // Topview face buttons p.setPen(colors.outline); button_color = colors.button; DrawRoundButton(p, center + QPoint(200, -71), button_values[A], 10, 5, Direction::Up); - DrawRoundButton(p, center + QPoint(180, -71), button_values[B], 10, 5, Direction::Up); - DrawRoundButton(p, center + QPoint(180, -71), button_values[X], 10, 5, Direction::Up); DrawRoundButton(p, center + QPoint(160, -71), button_values[Y], 10, 5, Direction::Up); + // Topview right joystick + DrawJoystickSideview(p, center + QPointF(180, -78), + -axis_values[Settings::NativeAnalog::RStick].value.x() + 15.0f, 1, + button_values[RStick]); + // Topview plus button p.setPen(colors.outline); button_color = colors.button; @@ -523,7 +538,7 @@ void PlayerControlPreview::DrawDualController(QPainter& p, const QPointF center) // Topview left joystick DrawJoystickSideview(p, center + QPointF(-180.5f, -78), - -stick_values[Settings::NativeAnalog::LStick].x.value + 15.0f, 1, + -axis_values[Settings::NativeAnalog::LStick].value.x() + 15.0f, 1, button_values[LStick]); // Topview minus button @@ -542,13 +557,13 @@ void PlayerControlPreview::DrawDualController(QPainter& p, const QPointF center) { // Draw joysticks using namespace Settings::NativeAnalog; - const auto l_stick = QPointF(stick_values[LStick].x.value, stick_values[LStick].y.value); + const auto& l_stick = axis_values[LStick]; const auto l_button = button_values[Settings::NativeButton::LStick]; - const auto r_stick = QPointF(stick_values[RStick].x.value, stick_values[RStick].y.value); + const auto& r_stick = axis_values[RStick]; const auto r_button = button_values[Settings::NativeButton::RStick]; - DrawJoystick(p, center + QPointF(-65, -65) + (l_stick * 7), 1.62f, l_button); - DrawJoystick(p, center + QPointF(65, 12) + (r_stick * 7), 1.62f, r_button); + DrawJoystick(p, center + QPointF(-65, -65) + (l_stick.value * 7), 1.62f, l_button); + DrawJoystick(p, center + QPointF(65, 12) + (r_stick.value * 7), 1.62f, r_button); DrawRawJoystick(p, center + QPointF(-180, 90), center + QPointF(180, 90)); } @@ -619,12 +634,6 @@ void PlayerControlPreview::DrawDualController(QPainter& p, const QPointF center) p.setPen(colors.transparent); p.setBrush(colors.font2); DrawSymbol(p, center + QPoint(50, 60), Symbol::House, 4.2f); - - // Draw battery - DrawBattery(p, center + QPoint(-100, -160), - battery_values[Core::HID::EmulatedDeviceIndex::LeftIndex]); - DrawBattery(p, center + QPoint(40, -160), - battery_values[Core::HID::EmulatedDeviceIndex::RightIndex]); } void PlayerControlPreview::DrawHandheldController(QPainter& p, const QPointF center) { @@ -634,13 +643,13 @@ void PlayerControlPreview::DrawHandheldController(QPainter& p, const QPointF cen { // Draw joysticks using namespace Settings::NativeAnalog; - const auto l_stick = QPointF(stick_values[LStick].x.value, stick_values[LStick].y.value); + const auto& l_stick = axis_values[LStick]; const auto l_button = button_values[Settings::NativeButton::LStick]; - const auto r_stick = QPointF(stick_values[RStick].x.value, stick_values[RStick].y.value); + const auto& r_stick = axis_values[RStick]; const auto r_button = button_values[Settings::NativeButton::RStick]; - DrawJoystick(p, center + QPointF(-171, -41) + (l_stick * 4), 1.0f, l_button); - DrawJoystick(p, center + QPointF(171, 8) + (r_stick * 4), 1.0f, r_button); + DrawJoystick(p, center + QPointF(-171, -41) + (l_stick.value * 4), 1.0f, l_button); + DrawJoystick(p, center + QPointF(171, 8) + (r_stick.value * 4), 1.0f, r_button); DrawRawJoystick(p, center + QPointF(-50, 0), center + QPointF(50, 0)); } @@ -723,12 +732,6 @@ void PlayerControlPreview::DrawHandheldController(QPainter& p, const QPointF cen p.setPen(colors.transparent); p.setBrush(colors.font2); DrawSymbol(p, center + QPoint(161, 37), Symbol::House, 2.75f); - - // Draw battery - DrawBattery(p, center + QPoint(-200, 110), - battery_values[Core::HID::EmulatedDeviceIndex::LeftIndex]); - DrawBattery(p, center + QPoint(130, 110), - battery_values[Core::HID::EmulatedDeviceIndex::RightIndex]); } void PlayerControlPreview::DrawProController(QPainter& p, const QPointF center) { @@ -738,11 +741,9 @@ void PlayerControlPreview::DrawProController(QPainter& p, const QPointF center) { // Draw joysticks using namespace Settings::NativeAnalog; - const auto l_stick = QPointF(stick_values[LStick].x.value, stick_values[LStick].y.value); - const auto r_stick = QPointF(stick_values[RStick].x.value, stick_values[RStick].y.value); - DrawProJoystick(p, center + QPointF(-111, -55), l_stick, 11, + DrawProJoystick(p, center + QPointF(-111, -55), axis_values[LStick].value, 11, button_values[Settings::NativeButton::LStick]); - DrawProJoystick(p, center + QPointF(51, 0), r_stick, 11, + DrawProJoystick(p, center + QPointF(51, 0), axis_values[RStick].value, 11, button_values[Settings::NativeButton::RStick]); DrawRawJoystick(p, center + QPointF(-50, 105), center + QPointF(50, 105)); } @@ -816,27 +817,24 @@ void PlayerControlPreview::DrawProController(QPainter& p, const QPointF center) p.setPen(colors.transparent); p.setBrush(colors.font2); DrawSymbol(p, center + QPoint(29, -56), Symbol::House, 3.9f); - - // Draw battery - DrawBattery(p, center + QPoint(-30, -160), - battery_values[Core::HID::EmulatedDeviceIndex::LeftIndex]); } void PlayerControlPreview::DrawGCController(QPainter& p, const QPointF center) { - DrawGCTriggers(p, center, trigger_values[0], trigger_values[1]); + DrawGCTriggers(p, center, button_values[Settings::NativeButton::ZL], + button_values[Settings::NativeButton::ZR]); DrawGCButtonZ(p, center, button_values[Settings::NativeButton::R]); DrawGCBody(p, center); { // Draw joysticks using namespace Settings::NativeAnalog; - const auto l_stick = QPointF(stick_values[LStick].x.value, stick_values[LStick].y.value); - const auto r_stick = QPointF(stick_values[RStick].x.value, stick_values[RStick].y.value); - DrawGCJoystick(p, center + QPointF(-111, -44) + (l_stick * 10), {}); + DrawGCJoystick(p, center + QPointF(-111, -44) + (axis_values[LStick].value * 10), false); button_color = colors.button2; - DrawCircleButton(p, center + QPointF(61, 37) + (r_stick * 9.5f), {}, 15); + DrawCircleButton(p, center + QPointF(61, 37) + (axis_values[RStick].value * 9.5f), false, + 15); p.setPen(colors.transparent); p.setBrush(colors.font); - DrawSymbol(p, center + QPointF(61, 37) + (r_stick * 9.5f), Symbol::C, 1.0f); + DrawSymbol(p, center + QPointF(61, 37) + (axis_values[RStick].value * 9.5f), Symbol::C, + 1.0f); DrawRawJoystick(p, center + QPointF(-198, -125), center + QPointF(198, -125)); } @@ -873,10 +871,6 @@ void PlayerControlPreview::DrawGCController(QPainter& p, const QPointF center) { // Minus and Plus buttons p.setPen(colors.outline); DrawCircleButton(p, center + QPoint(0, -44), button_values[Plus], 8); - - // Draw battery - DrawBattery(p, center + QPoint(-30, -165), - battery_values[Core::HID::EmulatedDeviceIndex::LeftIndex]); } constexpr std::array symbol_a = { @@ -1843,14 +1837,10 @@ void PlayerControlPreview::DrawLeftBody(QPainter& p, const QPointF center) { const float led_size = 5.0f; const QPointF led_position = sideview_center + QPointF(0, -36); int led_count = 0; - p.setBrush(led_pattern.position1 ? colors.led_on : colors.led_off); - DrawRectangle(p, led_position + QPointF(0, 12 * led_count++), led_size, led_size); - p.setBrush(led_pattern.position2 ? colors.led_on : colors.led_off); - DrawRectangle(p, led_position + QPointF(0, 12 * led_count++), led_size, led_size); - p.setBrush(led_pattern.position3 ? colors.led_on : colors.led_off); - DrawRectangle(p, led_position + QPointF(0, 12 * led_count++), led_size, led_size); - p.setBrush(led_pattern.position4 ? colors.led_on : colors.led_off); - DrawRectangle(p, led_position + QPointF(0, 12 * led_count++), led_size, led_size); + for (const auto& color : led_color) { + p.setBrush(color); + DrawRectangle(p, led_position + QPointF(0, 12 * led_count++), led_size, led_size); + } } void PlayerControlPreview::DrawRightBody(QPainter& p, const QPointF center) { @@ -1943,19 +1933,14 @@ void PlayerControlPreview::DrawRightBody(QPainter& p, const QPointF center) { const float led_size = 5.0f; const QPointF led_position = sideview_center + QPointF(0, -36); int led_count = 0; - p.setBrush(led_pattern.position1 ? colors.led_on : colors.led_off); - DrawRectangle(p, led_position + QPointF(0, 12 * led_count++), led_size, led_size); - p.setBrush(led_pattern.position2 ? colors.led_on : colors.led_off); - DrawRectangle(p, led_position + QPointF(0, 12 * led_count++), led_size, led_size); - p.setBrush(led_pattern.position3 ? colors.led_on : colors.led_off); - DrawRectangle(p, led_position + QPointF(0, 12 * led_count++), led_size, led_size); - p.setBrush(led_pattern.position4 ? colors.led_on : colors.led_off); - DrawRectangle(p, led_position + QPointF(0, 12 * led_count++), led_size, led_size); + for (const auto& color : led_color) { + p.setBrush(color); + DrawRectangle(p, led_position + QPointF(0, 12 * led_count++), led_size, led_size); + } } -void PlayerControlPreview::DrawProTriggers(QPainter& p, const QPointF center, - const Common::Input::ButtonStatus& left_pressed, - const Common::Input::ButtonStatus& right_pressed) { +void PlayerControlPreview::DrawProTriggers(QPainter& p, const QPointF center, bool left_pressed, + bool right_pressed) { std::array qleft_trigger; std::array qright_trigger; std::array qbody_top; @@ -1964,10 +1949,8 @@ void PlayerControlPreview::DrawProTriggers(QPainter& p, const QPointF center, const float trigger_x = pro_left_trigger[point * 2 + 0]; const float trigger_y = pro_left_trigger[point * 2 + 1]; - qleft_trigger[point] = - center + QPointF(trigger_x, trigger_y + (left_pressed.value ? 2 : 0)); - qright_trigger[point] = - center + QPointF(-trigger_x, trigger_y + (right_pressed.value ? 2 : 0)); + qleft_trigger[point] = center + QPointF(trigger_x, trigger_y + (left_pressed ? 2 : 0)); + qright_trigger[point] = center + QPointF(-trigger_x, trigger_y + (right_pressed ? 2 : 0)); } for (std::size_t point = 0; point < pro_body_top.size() / 2; ++point) { @@ -1984,17 +1967,16 @@ void PlayerControlPreview::DrawProTriggers(QPainter& p, const QPointF center, DrawPolygon(p, qbody_top); // Left trigger - p.setBrush(left_pressed.value ? colors.highlight : colors.button); + p.setBrush(left_pressed ? colors.highlight : colors.button); DrawPolygon(p, qleft_trigger); // Right trigger - p.setBrush(right_pressed.value ? colors.highlight : colors.button); + p.setBrush(right_pressed ? colors.highlight : colors.button); DrawPolygon(p, qright_trigger); } -void PlayerControlPreview::DrawGCTriggers(QPainter& p, const QPointF center, - Common::Input::TriggerStatus left_trigger, - Common::Input::TriggerStatus right_trigger) { +void PlayerControlPreview::DrawGCTriggers(QPainter& p, const QPointF center, bool left_pressed, + bool right_pressed) { std::array qleft_trigger; std::array qright_trigger; @@ -2002,37 +1984,32 @@ void PlayerControlPreview::DrawGCTriggers(QPainter& p, const QPointF center, const float trigger_x = left_gc_trigger[point * 2 + 0]; const float trigger_y = left_gc_trigger[point * 2 + 1]; - qleft_trigger[point] = - center + QPointF(trigger_x, trigger_y + (left_trigger.analog.value * 10.0f)); - qright_trigger[point] = - center + QPointF(-trigger_x, trigger_y + (right_trigger.analog.value * 10.0f)); + qleft_trigger[point] = center + QPointF(trigger_x, trigger_y + (left_pressed ? 10 : 0)); + qright_trigger[point] = center + QPointF(-trigger_x, trigger_y + (right_pressed ? 10 : 0)); } // Left trigger p.setPen(colors.outline); - p.setBrush(left_trigger.pressed.value ? colors.highlight : colors.button); + p.setBrush(left_pressed ? colors.highlight : colors.button); DrawPolygon(p, qleft_trigger); // Right trigger - p.setBrush(right_trigger.pressed.value ? colors.highlight : colors.button); + p.setBrush(right_pressed ? colors.highlight : colors.button); DrawPolygon(p, qright_trigger); // Draw L text p.setPen(colors.transparent); p.setBrush(colors.font); - DrawSymbol(p, center + QPointF(-132, -119 + (left_trigger.analog.value * 10.0f)), Symbol::L, - 1.7f); + DrawSymbol(p, center + QPointF(-132, -119 + (left_pressed ? 10 : 0)), Symbol::L, 1.7f); // Draw R text p.setPen(colors.transparent); p.setBrush(colors.font); - DrawSymbol(p, center + QPointF(121.5f, -119 + (right_trigger.analog.value * 10.0f)), Symbol::R, - 1.7f); + DrawSymbol(p, center + QPointF(121.5f, -119 + (right_pressed ? 10 : 0)), Symbol::R, 1.7f); } void PlayerControlPreview::DrawHandheldTriggers(QPainter& p, const QPointF center, - const Common::Input::ButtonStatus& left_pressed, - const Common::Input::ButtonStatus& right_pressed) { + bool left_pressed, bool right_pressed) { std::array qleft_trigger; std::array qright_trigger; @@ -2041,24 +2018,23 @@ void PlayerControlPreview::DrawHandheldTriggers(QPainter& p, const QPointF cente const float left_trigger_y = left_joycon_trigger[point * 2 + 1]; qleft_trigger[point] = - center + QPointF(left_trigger_x, left_trigger_y + (left_pressed.value ? 0.5f : 0)); + center + QPointF(left_trigger_x, left_trigger_y + (left_pressed ? 0.5f : 0)); qright_trigger[point] = - center + QPointF(-left_trigger_x, left_trigger_y + (right_pressed.value ? 0.5f : 0)); + center + QPointF(-left_trigger_x, left_trigger_y + (right_pressed ? 0.5f : 0)); } // Left trigger p.setPen(colors.outline); - p.setBrush(left_pressed.value ? colors.highlight : colors.button); + p.setBrush(left_pressed ? colors.highlight : colors.button); DrawPolygon(p, qleft_trigger); // Right trigger - p.setBrush(right_pressed.value ? colors.highlight : colors.button); + p.setBrush(right_pressed ? colors.highlight : colors.button); DrawPolygon(p, qright_trigger); } -void PlayerControlPreview::DrawDualTriggers(QPainter& p, const QPointF center, - const Common::Input::ButtonStatus& left_pressed, - const Common::Input::ButtonStatus& right_pressed) { +void PlayerControlPreview::DrawDualTriggers(QPainter& p, const QPointF center, bool left_pressed, + bool right_pressed) { std::array qleft_trigger; std::array qright_trigger; constexpr float size = 1.62f; @@ -2067,27 +2043,25 @@ void PlayerControlPreview::DrawDualTriggers(QPainter& p, const QPointF center, const float left_trigger_x = left_joycon_trigger[point * 2 + 0]; const float left_trigger_y = left_joycon_trigger[point * 2 + 1]; - qleft_trigger[point] = - center + QPointF(left_trigger_x * size + offset, - left_trigger_y * size + (left_pressed.value ? 0.5f : 0)); + qleft_trigger[point] = center + QPointF(left_trigger_x * size + offset, + left_trigger_y * size + (left_pressed ? 0.5f : 0)); qright_trigger[point] = center + QPointF(-left_trigger_x * size - offset, - left_trigger_y * size + (right_pressed.value ? 0.5f : 0)); + left_trigger_y * size + (right_pressed ? 0.5f : 0)); } // Left trigger p.setPen(colors.outline); - p.setBrush(left_pressed.value ? colors.highlight : colors.button); + p.setBrush(left_pressed ? colors.highlight : colors.button); DrawPolygon(p, qleft_trigger); // Right trigger - p.setBrush(right_pressed.value ? colors.highlight : colors.button); + p.setBrush(right_pressed ? colors.highlight : colors.button); DrawPolygon(p, qright_trigger); } -void PlayerControlPreview::DrawDualTriggersTopView( - QPainter& p, const QPointF center, const Common::Input::ButtonStatus& left_pressed, - const Common::Input::ButtonStatus& right_pressed) { +void PlayerControlPreview::DrawDualTriggersTopView(QPainter& p, const QPointF center, + bool left_pressed, bool right_pressed) { std::array qleft_trigger; std::array qright_trigger; constexpr float size = 0.9f; @@ -2106,9 +2080,9 @@ void PlayerControlPreview::DrawDualTriggersTopView( } p.setPen(colors.outline); - p.setBrush(left_pressed.value ? colors.highlight : colors.button); + p.setBrush(left_pressed ? colors.highlight : colors.button); DrawPolygon(p, qleft_trigger); - p.setBrush(right_pressed.value ? colors.highlight : colors.button); + p.setBrush(right_pressed ? colors.highlight : colors.button); DrawPolygon(p, qright_trigger); // Draw L text @@ -2122,9 +2096,8 @@ void PlayerControlPreview::DrawDualTriggersTopView( DrawSymbol(p, center + QPointF(177, -84), Symbol::R, 1.0f); } -void PlayerControlPreview::DrawDualZTriggersTopView( - QPainter& p, const QPointF center, const Common::Input::ButtonStatus& left_pressed, - const Common::Input::ButtonStatus& right_pressed) { +void PlayerControlPreview::DrawDualZTriggersTopView(QPainter& p, const QPointF center, + bool left_pressed, bool right_pressed) { std::array qleft_trigger; std::array qright_trigger; constexpr float size = 0.9f; @@ -2141,9 +2114,9 @@ void PlayerControlPreview::DrawDualZTriggersTopView( } p.setPen(colors.outline); - p.setBrush(left_pressed.value ? colors.highlight : colors.button); + p.setBrush(left_pressed ? colors.highlight : colors.button); DrawPolygon(p, qleft_trigger); - p.setBrush(right_pressed.value ? colors.highlight : colors.button); + p.setBrush(right_pressed ? colors.highlight : colors.button); DrawPolygon(p, qright_trigger); // Draw ZL text @@ -2157,8 +2130,7 @@ void PlayerControlPreview::DrawDualZTriggersTopView( DrawSymbol(p, center + QPointF(180, -113), Symbol::ZR, 1.0f); } -void PlayerControlPreview::DrawLeftTriggers(QPainter& p, const QPointF center, - const Common::Input::ButtonStatus& left_pressed) { +void PlayerControlPreview::DrawLeftTriggers(QPainter& p, const QPointF center, bool left_pressed) { std::array qleft_trigger; constexpr float size = 1.78f; constexpr float offset = 311.5f; @@ -2166,16 +2138,15 @@ void PlayerControlPreview::DrawLeftTriggers(QPainter& p, const QPointF center, for (std::size_t point = 0; point < left_joycon_trigger.size() / 2; ++point) { qleft_trigger[point] = center + QPointF(left_joycon_trigger[point * 2] * size + offset, left_joycon_trigger[point * 2 + 1] * size - - (left_pressed.value ? 0.5f : 1.0f)); + (left_pressed ? 0.5f : 1.0f)); } p.setPen(colors.outline); - p.setBrush(left_pressed.value ? colors.highlight : colors.button); + p.setBrush(left_pressed ? colors.highlight : colors.button); DrawPolygon(p, qleft_trigger); } -void PlayerControlPreview::DrawLeftZTriggers(QPainter& p, const QPointF center, - const Common::Input::ButtonStatus& left_pressed) { +void PlayerControlPreview::DrawLeftZTriggers(QPainter& p, const QPointF center, bool left_pressed) { std::array qleft_trigger; constexpr float size = 1.1115f; constexpr float offset2 = 335; @@ -2183,18 +2154,18 @@ void PlayerControlPreview::DrawLeftZTriggers(QPainter& p, const QPointF center, for (std::size_t point = 0; point < left_joycon_sideview_zl.size() / 2; ++point) { qleft_trigger[point] = center + QPointF(left_joycon_sideview_zl[point * 2] * size + offset2, left_joycon_sideview_zl[point * 2 + 1] * size + - (left_pressed.value ? 1.5f : 1.0f)); + (left_pressed ? 1.5f : 1.0f)); } p.setPen(colors.outline); - p.setBrush(left_pressed.value ? colors.highlight : colors.button); + p.setBrush(left_pressed ? colors.highlight : colors.button); DrawPolygon(p, qleft_trigger); - p.drawArc(center.x() + 158, center.y() + (left_pressed.value ? -203.5f : -204.0f), 77, 77, - 225 * 16, 44 * 16); + p.drawArc(center.x() + 158, center.y() + (left_pressed ? -203.5f : -204.0f), 77, 77, 225 * 16, + 44 * 16); } -void PlayerControlPreview::DrawLeftTriggersTopView( - QPainter& p, const QPointF center, const Common::Input::ButtonStatus& left_pressed) { +void PlayerControlPreview::DrawLeftTriggersTopView(QPainter& p, const QPointF center, + bool left_pressed) { std::array qleft_trigger; for (std::size_t point = 0; point < left_joystick_L_topview.size() / 2; ++point) { @@ -2203,7 +2174,7 @@ void PlayerControlPreview::DrawLeftTriggersTopView( } p.setPen(colors.outline); - p.setBrush(left_pressed.value ? colors.highlight : colors.button); + p.setBrush(left_pressed ? colors.highlight : colors.button); DrawPolygon(p, qleft_trigger); // Draw L text @@ -2212,8 +2183,8 @@ void PlayerControlPreview::DrawLeftTriggersTopView( DrawSymbol(p, center + QPointF(-143, -36), Symbol::L, 1.0f); } -void PlayerControlPreview::DrawLeftZTriggersTopView( - QPainter& p, const QPointF center, const Common::Input::ButtonStatus& left_pressed) { +void PlayerControlPreview::DrawLeftZTriggersTopView(QPainter& p, const QPointF center, + bool left_pressed) { std::array qleft_trigger; for (std::size_t point = 0; point < left_joystick_ZL_topview.size() / 2; ++point) { @@ -2222,7 +2193,7 @@ void PlayerControlPreview::DrawLeftZTriggersTopView( } p.setPen(colors.outline); - p.setBrush(left_pressed.value ? colors.highlight : colors.button); + p.setBrush(left_pressed ? colors.highlight : colors.button); DrawPolygon(p, qleft_trigger); // Draw ZL text @@ -2232,7 +2203,7 @@ void PlayerControlPreview::DrawLeftZTriggersTopView( } void PlayerControlPreview::DrawRightTriggers(QPainter& p, const QPointF center, - const Common::Input::ButtonStatus& right_pressed) { + bool right_pressed) { std::array qright_trigger; constexpr float size = 1.78f; constexpr float offset = 311.5f; @@ -2240,36 +2211,36 @@ void PlayerControlPreview::DrawRightTriggers(QPainter& p, const QPointF center, for (std::size_t point = 0; point < left_joycon_trigger.size() / 2; ++point) { qright_trigger[point] = center + QPointF(-left_joycon_trigger[point * 2] * size - offset, left_joycon_trigger[point * 2 + 1] * size - - (right_pressed.value ? 0.5f : 1.0f)); + (right_pressed ? 0.5f : 1.0f)); } p.setPen(colors.outline); - p.setBrush(right_pressed.value ? colors.highlight : colors.button); + p.setBrush(right_pressed ? colors.highlight : colors.button); DrawPolygon(p, qright_trigger); } void PlayerControlPreview::DrawRightZTriggers(QPainter& p, const QPointF center, - const Common::Input::ButtonStatus& right_pressed) { + bool right_pressed) { std::array qright_trigger; constexpr float size = 1.1115f; constexpr float offset2 = 335; for (std::size_t point = 0; point < left_joycon_sideview_zl.size() / 2; ++point) { qright_trigger[point] = - center + QPointF(-left_joycon_sideview_zl[point * 2] * size - offset2, - left_joycon_sideview_zl[point * 2 + 1] * size + - (right_pressed.value ? 0.5f : 0) + 1); + center + + QPointF(-left_joycon_sideview_zl[point * 2] * size - offset2, + left_joycon_sideview_zl[point * 2 + 1] * size + (right_pressed ? 0.5f : 0) + 1); } p.setPen(colors.outline); - p.setBrush(right_pressed.value ? colors.highlight : colors.button); + p.setBrush(right_pressed ? colors.highlight : colors.button); DrawPolygon(p, qright_trigger); - p.drawArc(center.x() - 236, center.y() + (right_pressed.value ? -203.5f : -204.0f), 77, 77, - 271 * 16, 44 * 16); + p.drawArc(center.x() - 236, center.y() + (right_pressed ? -203.5f : -204.0f), 77, 77, 271 * 16, + 44 * 16); } -void PlayerControlPreview::DrawRightTriggersTopView( - QPainter& p, const QPointF center, const Common::Input::ButtonStatus& right_pressed) { +void PlayerControlPreview::DrawRightTriggersTopView(QPainter& p, const QPointF center, + bool right_pressed) { std::array qright_trigger; for (std::size_t point = 0; point < left_joystick_L_topview.size() / 2; ++point) { @@ -2278,7 +2249,7 @@ void PlayerControlPreview::DrawRightTriggersTopView( } p.setPen(colors.outline); - p.setBrush(right_pressed.value ? colors.highlight : colors.button); + p.setBrush(right_pressed ? colors.highlight : colors.button); DrawPolygon(p, qright_trigger); // Draw R text @@ -2287,8 +2258,8 @@ void PlayerControlPreview::DrawRightTriggersTopView( DrawSymbol(p, center + QPointF(137, -36), Symbol::R, 1.0f); } -void PlayerControlPreview::DrawRightZTriggersTopView( - QPainter& p, const QPointF center, const Common::Input::ButtonStatus& right_pressed) { +void PlayerControlPreview::DrawRightZTriggersTopView(QPainter& p, const QPointF center, + bool right_pressed) { std::array qright_trigger; for (std::size_t point = 0; point < left_joystick_ZL_topview.size() / 2; ++point) { @@ -2297,7 +2268,7 @@ void PlayerControlPreview::DrawRightZTriggersTopView( } p.setPen(colors.outline); - p.setBrush(right_pressed.value ? colors.highlight : colors.button); + p.setBrush(right_pressed ? colors.highlight : colors.button); DrawPolygon(p, qright_trigger); // Draw ZR text @@ -2307,13 +2278,13 @@ void PlayerControlPreview::DrawRightZTriggersTopView( } void PlayerControlPreview::DrawJoystick(QPainter& p, const QPointF center, float size, - const Common::Input::ButtonStatus& pressed) { + bool pressed) { const float radius1 = 13.0f * size; const float radius2 = 9.0f * size; // Outer circle p.setPen(colors.outline); - p.setBrush(pressed.value ? colors.highlight : colors.button); + p.setBrush(pressed ? colors.highlight : colors.button); DrawCircle(p, center, radius1); // Cross @@ -2321,18 +2292,17 @@ void PlayerControlPreview::DrawJoystick(QPainter& p, const QPointF center, float p.drawLine(center - QPoint(0, radius1), center + QPoint(0, radius1)); // Inner circle - p.setBrush(pressed.value ? colors.highlight2 : colors.button2); + p.setBrush(pressed ? colors.highlight2 : colors.button2); DrawCircle(p, center, radius2); } void PlayerControlPreview::DrawJoystickSideview(QPainter& p, const QPointF center, float angle, - float size, - const Common::Input::ButtonStatus& pressed) { + float size, bool pressed) { QVector joystick; joystick.reserve(static_cast(left_joystick_sideview.size() / 2)); for (std::size_t point = 0; point < left_joystick_sideview.size() / 2; ++point) { - joystick.append(QPointF(left_joystick_sideview[point * 2] * size + (pressed.value ? 1 : 0), + joystick.append(QPointF(left_joystick_sideview[point * 2] * size + (pressed ? 1 : 0), left_joystick_sideview[point * 2 + 1] * size - 1)); } @@ -2344,15 +2314,14 @@ void PlayerControlPreview::DrawJoystickSideview(QPainter& p, const QPointF cente // Draw joystick p.setPen(colors.outline); - p.setBrush(pressed.value ? colors.highlight : colors.button); + p.setBrush(pressed ? colors.highlight : colors.button); p.drawPolygon(p2); p.drawLine(p2.at(1), p2.at(30)); p.drawLine(p2.at(32), p2.at(71)); } void PlayerControlPreview::DrawProJoystick(QPainter& p, const QPointF center, const QPointF offset, - float offset_scalar, - const Common::Input::ButtonStatus& pressed) { + float offset_scalar, bool pressed) { const float radius1 = 24.0f; const float radius2 = 17.0f; @@ -2370,11 +2339,11 @@ void PlayerControlPreview::DrawProJoystick(QPainter& p, const QPointF center, co // Outer circle p.setPen(colors.outline); - p.setBrush(pressed.value ? colors.highlight : colors.button); + p.setBrush(pressed ? colors.highlight : colors.button); p.drawEllipse(QPointF(0, 0), radius1 * amplitude, radius1); // Inner circle - p.setBrush(pressed.value ? colors.highlight2 : colors.button2); + p.setBrush(pressed ? colors.highlight2 : colors.button2); const float inner_offset = (radius1 - radius2) * 0.4f * ((offset.x() == 0 && offset.y() < 0) ? -1.0f : 1.0f); @@ -2386,15 +2355,14 @@ void PlayerControlPreview::DrawProJoystick(QPainter& p, const QPointF center, co p.restore(); } -void PlayerControlPreview::DrawGCJoystick(QPainter& p, const QPointF center, - const Common::Input::ButtonStatus& pressed) { +void PlayerControlPreview::DrawGCJoystick(QPainter& p, const QPointF center, bool pressed) { // Outer circle p.setPen(colors.outline); - p.setBrush(pressed.value ? colors.highlight : colors.button); + p.setBrush(pressed ? colors.highlight : colors.button); DrawCircle(p, center, 26.0f); // Inner circle - p.setBrush(pressed.value ? colors.highlight2 : colors.button2); + p.setBrush(pressed ? colors.highlight2 : colors.button2); DrawCircle(p, center, 19.0f); p.setBrush(colors.transparent); DrawCircle(p, center, 13.5f); @@ -2403,29 +2371,31 @@ void PlayerControlPreview::DrawGCJoystick(QPainter& p, const QPointF center, void PlayerControlPreview::DrawRawJoystick(QPainter& p, QPointF center_left, QPointF center_right) { using namespace Settings::NativeAnalog; - if (center_right != QPointF(0, 0)) { - DrawJoystickProperties(p, center_right, stick_values[RStick].x.properties); + if (controller_type != Settings::ControllerType::LeftJoycon) { + DrawJoystickProperties(p, center_right, axis_values[RStick].properties); p.setPen(colors.indicator); p.setBrush(colors.indicator); - DrawJoystickDot(p, center_right, stick_values[RStick], true); + DrawJoystickDot(p, center_right, axis_values[RStick].raw_value, + axis_values[RStick].properties); p.setPen(colors.indicator2); p.setBrush(colors.indicator2); - DrawJoystickDot(p, center_right, stick_values[RStick], false); + DrawJoystickDot(p, center_right, axis_values[RStick].value, axis_values[RStick].properties); } - if (center_left != QPointF(0, 0)) { - DrawJoystickProperties(p, center_left, stick_values[LStick].x.properties); + if (controller_type != Settings::ControllerType::RightJoycon) { + DrawJoystickProperties(p, center_left, axis_values[LStick].properties); p.setPen(colors.indicator); p.setBrush(colors.indicator); - DrawJoystickDot(p, center_left, stick_values[LStick], true); + DrawJoystickDot(p, center_left, axis_values[LStick].raw_value, + axis_values[LStick].properties); p.setPen(colors.indicator2); p.setBrush(colors.indicator2); - DrawJoystickDot(p, center_left, stick_values[LStick], false); + DrawJoystickDot(p, center_left, axis_values[LStick].value, axis_values[LStick].properties); } } -void PlayerControlPreview::DrawJoystickProperties( - QPainter& p, const QPointF center, const Common::Input::AnalogProperties& properties) { +void PlayerControlPreview::DrawJoystickProperties(QPainter& p, const QPointF center, + const Input::AnalogProperties& properties) { constexpr float size = 45.0f; const float range = size * properties.range; const float deadzone = size * properties.deadzone; @@ -2444,26 +2414,19 @@ void PlayerControlPreview::DrawJoystickProperties( DrawCircle(p, center, deadzone); } -void PlayerControlPreview::DrawJoystickDot(QPainter& p, const QPointF center, - const Common::Input::StickStatus& stick, bool raw) { +void PlayerControlPreview::DrawJoystickDot(QPainter& p, const QPointF center, const QPointF value, + const Input::AnalogProperties& properties) { constexpr float size = 45.0f; - const float range = size * stick.x.properties.range; + const float range = size * properties.range; - if (raw) { - const QPointF value = QPointF(stick.x.raw_value, stick.y.raw_value) * size; - DrawCircle(p, center + value, 2); - return; - } - - const QPointF value = QPointF(stick.x.value, stick.y.value) * range; - DrawCircle(p, center + value, 2); + // Dot pointer + DrawCircle(p, center + (value * range), 2); } -void PlayerControlPreview::DrawRoundButton(QPainter& p, QPointF center, - const Common::Input::ButtonStatus& pressed, float width, +void PlayerControlPreview::DrawRoundButton(QPainter& p, QPointF center, bool pressed, float width, float height, Direction direction, float radius) { p.setBrush(button_color); - if (pressed.value) { + if (pressed) { switch (direction) { case Direction::Left: center.setX(center.x() - 1); @@ -2485,19 +2448,17 @@ void PlayerControlPreview::DrawRoundButton(QPainter& p, QPointF center, QRectF rect = {center.x() - width, center.y() - height, width * 2.0f, height * 2.0f}; p.drawRoundedRect(rect, radius, radius); } -void PlayerControlPreview::DrawMinusButton(QPainter& p, const QPointF center, - const Common::Input::ButtonStatus& pressed, +void PlayerControlPreview::DrawMinusButton(QPainter& p, const QPointF center, bool pressed, int button_size) { p.setPen(colors.outline); - p.setBrush(pressed.value ? colors.highlight : colors.button); + p.setBrush(pressed ? colors.highlight : colors.button); DrawRectangle(p, center, button_size, button_size / 3.0f); } -void PlayerControlPreview::DrawPlusButton(QPainter& p, const QPointF center, - const Common::Input::ButtonStatus& pressed, +void PlayerControlPreview::DrawPlusButton(QPainter& p, const QPointF center, bool pressed, int button_size) { // Draw outer line p.setPen(colors.outline); - p.setBrush(pressed.value ? colors.highlight : colors.button); + p.setBrush(pressed ? colors.highlight : colors.button); DrawRectangle(p, center, button_size, button_size / 3.0f); DrawRectangle(p, center, button_size / 3.0f, button_size); @@ -2510,8 +2471,7 @@ void PlayerControlPreview::DrawPlusButton(QPainter& p, const QPointF center, DrawRectangle(p, center, button_size / 3.0f, button_size); } -void PlayerControlPreview::DrawGCButtonX(QPainter& p, const QPointF center, - const Common::Input::ButtonStatus& pressed) { +void PlayerControlPreview::DrawGCButtonX(QPainter& p, const QPointF center, bool pressed) { std::array button_x; for (std::size_t point = 0; point < gc_button_x.size() / 2; ++point) { @@ -2519,12 +2479,11 @@ void PlayerControlPreview::DrawGCButtonX(QPainter& p, const QPointF center, } p.setPen(colors.outline); - p.setBrush(pressed.value ? colors.highlight : colors.button); + p.setBrush(pressed ? colors.highlight : colors.button); DrawPolygon(p, button_x); } -void PlayerControlPreview::DrawGCButtonY(QPainter& p, const QPointF center, - const Common::Input::ButtonStatus& pressed) { +void PlayerControlPreview::DrawGCButtonY(QPainter& p, const QPointF center, bool pressed) { std::array button_x; for (std::size_t point = 0; point < gc_button_y.size() / 2; ++point) { @@ -2532,29 +2491,27 @@ void PlayerControlPreview::DrawGCButtonY(QPainter& p, const QPointF center, } p.setPen(colors.outline); - p.setBrush(pressed.value ? colors.highlight : colors.button); + p.setBrush(pressed ? colors.highlight : colors.button); DrawPolygon(p, button_x); } -void PlayerControlPreview::DrawGCButtonZ(QPainter& p, const QPointF center, - const Common::Input::ButtonStatus& pressed) { +void PlayerControlPreview::DrawGCButtonZ(QPainter& p, const QPointF center, bool pressed) { std::array button_x; for (std::size_t point = 0; point < gc_button_z.size() / 2; ++point) { button_x[point] = center + QPointF(gc_button_z[point * 2], - gc_button_z[point * 2 + 1] + (pressed.value ? 1 : 0)); + gc_button_z[point * 2 + 1] + (pressed ? 1 : 0)); } p.setPen(colors.outline); - p.setBrush(pressed.value ? colors.highlight : colors.button2); + p.setBrush(pressed ? colors.highlight : colors.button2); DrawPolygon(p, button_x); } -void PlayerControlPreview::DrawCircleButton(QPainter& p, const QPointF center, - const Common::Input::ButtonStatus& pressed, +void PlayerControlPreview::DrawCircleButton(QPainter& p, const QPointF center, bool pressed, float button_size) { p.setBrush(button_color); - if (pressed.value) { + if (pressed) { p.setBrush(colors.highlight); } p.drawEllipse(center, button_size, button_size); @@ -2583,8 +2540,7 @@ void PlayerControlPreview::DrawArrowButtonOutline(QPainter& p, const QPointF cen } void PlayerControlPreview::DrawArrowButton(QPainter& p, const QPointF center, - const Direction direction, - const Common::Input::ButtonStatus& pressed, float size) { + const Direction direction, bool pressed, float size) { std::array arrow_button; QPoint offset; @@ -2596,39 +2552,38 @@ void PlayerControlPreview::DrawArrowButton(QPainter& p, const QPointF center, case Direction::Up: arrow_button[point] = center + QPointF(up_arrow_x * size, up_arrow_y * size); break; + case Direction::Left: + arrow_button[point] = center + QPointF(up_arrow_y * size, up_arrow_x * size); + break; case Direction::Right: arrow_button[point] = center + QPointF(-up_arrow_y * size, up_arrow_x * size); break; case Direction::Down: arrow_button[point] = center + QPointF(up_arrow_x * size, -up_arrow_y * size); break; - case Direction::Left: - // Compiler doesn't optimize this correctly check why - arrow_button[point] = center + QPointF(up_arrow_y * size, up_arrow_x * size); - break; case Direction::None: break; } } // Draw arrow button - p.setPen(pressed.value ? colors.highlight : colors.button); - p.setBrush(pressed.value ? colors.highlight : colors.button); + p.setPen(pressed ? colors.highlight : colors.button); + p.setBrush(pressed ? colors.highlight : colors.button); DrawPolygon(p, arrow_button); switch (direction) { case Direction::Up: offset = QPoint(0, -20 * size); break; + case Direction::Left: + offset = QPoint(-20 * size, 0); + break; case Direction::Right: offset = QPoint(20 * size, 0); break; case Direction::Down: offset = QPoint(0, 20 * size); break; - case Direction::Left: - offset = QPoint(-20 * size, 0); - break; case Direction::None: offset = QPoint(0, 0); break; @@ -2641,8 +2596,7 @@ void PlayerControlPreview::DrawArrowButton(QPainter& p, const QPointF center, } void PlayerControlPreview::DrawTriggerButton(QPainter& p, const QPointF center, - const Direction direction, - const Common::Input::ButtonStatus& pressed) { + const Direction direction, bool pressed) { std::array qtrigger_button; for (std::size_t point = 0; point < trigger_button.size() / 2; ++point) { @@ -2665,51 +2619,10 @@ void PlayerControlPreview::DrawTriggerButton(QPainter& p, const QPointF center, // Draw arrow button p.setPen(colors.outline); - p.setBrush(pressed.value ? colors.highlight : colors.button); + p.setBrush(pressed ? colors.highlight : colors.button); DrawPolygon(p, qtrigger_button); } -void PlayerControlPreview::DrawBattery(QPainter& p, QPointF center, - Common::Input::BatteryLevel battery) { - if (battery == Common::Input::BatteryLevel::None) { - return; - } - p.setPen(colors.outline); - p.setBrush(colors.transparent); - p.drawRect(center.x(), center.y(), 56, 20); - p.drawRect(center.x() + 56, center.y() + 6, 3, 8); - p.setBrush(colors.deadzone); - switch (battery) { - case Common::Input::BatteryLevel::Charging: - p.setBrush(colors.indicator2); - p.drawText(center + QPoint(2, 14), tr("Charging")); - break; - case Common::Input::BatteryLevel::Full: - p.drawRect(center.x() + 42, center.y(), 14, 20); - p.drawRect(center.x() + 28, center.y(), 14, 20); - p.drawRect(center.x() + 14, center.y(), 14, 20); - p.drawRect(center.x(), center.y(), 14, 20); - break; - case Common::Input::BatteryLevel::Medium: - p.drawRect(center.x() + 28, center.y(), 14, 20); - p.drawRect(center.x() + 14, center.y(), 14, 20); - p.drawRect(center.x(), center.y(), 14, 20); - break; - case Common::Input::BatteryLevel::Low: - p.drawRect(center.x() + 14, center.y(), 14, 20); - p.drawRect(center.x(), center.y(), 14, 20); - break; - case Common::Input::BatteryLevel::Critical: - p.drawRect(center.x(), center.y(), 14, 20); - break; - case Common::Input::BatteryLevel::Empty: - p.drawRect(center.x(), center.y(), 5, 20); - break; - default: - break; - } -} - void PlayerControlPreview::DrawSymbol(QPainter& p, const QPointF center, Symbol symbol, float icon_size) { std::array house_icon; diff --git a/src/yuzu/configuration/configure_input_player_widget.h b/src/yuzu/configuration/configure_input_player_widget.h index 4cd5c3be0..f4bbfa528 100755 --- a/src/yuzu/configuration/configure_input_player_widget.h +++ b/src/yuzu/configuration/configure_input_player_widget.h @@ -7,11 +7,9 @@ #include #include #include - -#include "common/input.h" -#include "common/settings_input.h" -#include "core/hid/emulated_controller.h" -#include "core/hid/hid_types.h" +#include "common/settings.h" +#include "core/frontend/input.h" +#include "yuzu/debugger/controller.h" class QLabel; @@ -26,26 +24,17 @@ public: explicit PlayerControlPreview(QWidget* parent); ~PlayerControlPreview() override; - // Sets the emulated controller to be displayed - void SetController(Core::HID::EmulatedController* controller); - - // Disables events from the emulated controller - void UnloadController(); - - // Starts blinking animation at the button specified + void SetPlayerInput(std::size_t index, const ButtonParam& buttons_param, + const AnalogParam& analogs_param); + void SetPlayerInputRaw(std::size_t index, const Settings::ButtonsRaw& buttons_, + Settings::AnalogsRaw analogs_); + void SetConnectedStatus(bool checked); + void SetControllerType(Settings::ControllerType type); void BeginMappingButton(std::size_t button_id); - - // Starts moving animation at the stick specified - void BeginMappingAnalog(std::size_t stick_id); - - // Stops any ongoing animation + void BeginMappingAnalog(std::size_t button_id); void EndMapping(); - - // Handles emulated controller events - void ControllerUpdate(Core::HID::ControllerTriggerType type); - - // Updates input on sheduled interval void UpdateInput(); + void SetCallBack(ControllerCallback callback_); protected: void paintEvent(QPaintEvent* event) override; @@ -74,6 +63,22 @@ private: SR, }; + struct AxisValue { + QPointF value{}; + QPointF raw_value{}; + Input::AnalogProperties properties{}; + int size{}; + QPoint offset{}; + bool active{}; + }; + + struct LedPattern { + bool position1; + bool position2; + bool position3; + bool position4; + }; + struct ColorMapping { QColor outline{}; QColor primary{}; @@ -96,6 +101,7 @@ private: QColor deadzone{}; }; + static LedPattern GetColorPattern(std::size_t index, bool player_on); void UpdateColors(); void ResetInputs(); @@ -116,75 +122,47 @@ private: void DrawGCBody(QPainter& p, QPointF center); // Draw triggers functions - void DrawProTriggers(QPainter& p, QPointF center, - const Common::Input::ButtonStatus& left_pressed, - const Common::Input::ButtonStatus& right_pressed); - void DrawGCTriggers(QPainter& p, QPointF center, Common::Input::TriggerStatus left_trigger, - Common::Input::TriggerStatus right_trigger); - void DrawHandheldTriggers(QPainter& p, QPointF center, - const Common::Input::ButtonStatus& left_pressed, - const Common::Input::ButtonStatus& right_pressed); - void DrawDualTriggers(QPainter& p, QPointF center, - const Common::Input::ButtonStatus& left_pressed, - const Common::Input::ButtonStatus& right_pressed); - void DrawDualTriggersTopView(QPainter& p, QPointF center, - const Common::Input::ButtonStatus& left_pressed, - const Common::Input::ButtonStatus& right_pressed); - void DrawDualZTriggersTopView(QPainter& p, QPointF center, - const Common::Input::ButtonStatus& left_pressed, - const Common::Input::ButtonStatus& right_pressed); - void DrawLeftTriggers(QPainter& p, QPointF center, - const Common::Input::ButtonStatus& left_pressed); - void DrawLeftZTriggers(QPainter& p, QPointF center, - const Common::Input::ButtonStatus& left_pressed); - void DrawLeftTriggersTopView(QPainter& p, QPointF center, - const Common::Input::ButtonStatus& left_pressed); - void DrawLeftZTriggersTopView(QPainter& p, QPointF center, - const Common::Input::ButtonStatus& left_pressed); - void DrawRightTriggers(QPainter& p, QPointF center, - const Common::Input::ButtonStatus& right_pressed); - void DrawRightZTriggers(QPainter& p, QPointF center, - const Common::Input::ButtonStatus& right_pressed); - void DrawRightTriggersTopView(QPainter& p, QPointF center, - const Common::Input::ButtonStatus& right_pressed); - void DrawRightZTriggersTopView(QPainter& p, QPointF center, - const Common::Input::ButtonStatus& right_pressed); + void DrawProTriggers(QPainter& p, QPointF center, bool left_pressed, bool right_pressed); + void DrawGCTriggers(QPainter& p, QPointF center, bool left_pressed, bool right_pressed); + void DrawHandheldTriggers(QPainter& p, QPointF center, bool left_pressed, bool right_pressed); + void DrawDualTriggers(QPainter& p, QPointF center, bool left_pressed, bool right_pressed); + void DrawDualTriggersTopView(QPainter& p, QPointF center, bool left_pressed, + bool right_pressed); + void DrawDualZTriggersTopView(QPainter& p, QPointF center, bool left_pressed, + bool right_pressed); + void DrawLeftTriggers(QPainter& p, QPointF center, bool left_pressed); + void DrawLeftZTriggers(QPainter& p, QPointF center, bool left_pressed); + void DrawLeftTriggersTopView(QPainter& p, QPointF center, bool left_pressed); + void DrawLeftZTriggersTopView(QPainter& p, QPointF center, bool left_pressed); + void DrawRightTriggers(QPainter& p, QPointF center, bool right_pressed); + void DrawRightZTriggers(QPainter& p, QPointF center, bool right_pressed); + void DrawRightTriggersTopView(QPainter& p, QPointF center, bool right_pressed); + void DrawRightZTriggersTopView(QPainter& p, QPointF center, bool right_pressed); // Draw joystick functions - void DrawJoystick(QPainter& p, QPointF center, float size, - const Common::Input::ButtonStatus& pressed); - void DrawJoystickSideview(QPainter& p, QPointF center, float angle, float size, - const Common::Input::ButtonStatus& pressed); + void DrawJoystick(QPainter& p, QPointF center, float size, bool pressed); + void DrawJoystickSideview(QPainter& p, QPointF center, float angle, float size, bool pressed); void DrawRawJoystick(QPainter& p, QPointF center_left, QPointF center_right); void DrawJoystickProperties(QPainter& p, QPointF center, - const Common::Input::AnalogProperties& properties); - void DrawJoystickDot(QPainter& p, QPointF center, const Common::Input::StickStatus& stick, - bool raw); - void DrawProJoystick(QPainter& p, QPointF center, QPointF offset, float scalar, - const Common::Input::ButtonStatus& pressed); - void DrawGCJoystick(QPainter& p, QPointF center, const Common::Input::ButtonStatus& pressed); + const Input::AnalogProperties& properties); + void DrawJoystickDot(QPainter& p, QPointF center, QPointF value, + const Input::AnalogProperties& properties); + void DrawProJoystick(QPainter& p, QPointF center, QPointF offset, float scalar, bool pressed); + void DrawGCJoystick(QPainter& p, QPointF center, bool pressed); // Draw button functions - void DrawCircleButton(QPainter& p, QPointF center, const Common::Input::ButtonStatus& pressed, - float button_size); - void DrawRoundButton(QPainter& p, QPointF center, const Common::Input::ButtonStatus& pressed, - float width, float height, Direction direction = Direction::None, - float radius = 2); - void DrawMinusButton(QPainter& p, QPointF center, const Common::Input::ButtonStatus& pressed, - int button_size); - void DrawPlusButton(QPainter& p, QPointF center, const Common::Input::ButtonStatus& pressed, - int button_size); - void DrawGCButtonX(QPainter& p, QPointF center, const Common::Input::ButtonStatus& pressed); - void DrawGCButtonY(QPainter& p, QPointF center, const Common::Input::ButtonStatus& pressed); - void DrawGCButtonZ(QPainter& p, QPointF center, const Common::Input::ButtonStatus& pressed); + void DrawCircleButton(QPainter& p, QPointF center, bool pressed, float button_size); + void DrawRoundButton(QPainter& p, QPointF center, bool pressed, float width, float height, + Direction direction = Direction::None, float radius = 2); + void DrawMinusButton(QPainter& p, QPointF center, bool pressed, int button_size); + void DrawPlusButton(QPainter& p, QPointF center, bool pressed, int button_size); + void DrawGCButtonX(QPainter& p, QPointF center, bool pressed); + void DrawGCButtonY(QPainter& p, QPointF center, bool pressed); + void DrawGCButtonZ(QPainter& p, QPointF center, bool pressed); void DrawArrowButtonOutline(QPainter& p, const QPointF center, float size = 1.0f); - void DrawArrowButton(QPainter& p, QPointF center, Direction direction, - const Common::Input::ButtonStatus& pressed, float size = 1.0f); - void DrawTriggerButton(QPainter& p, QPointF center, Direction direction, - const Common::Input::ButtonStatus& pressed); - - // Draw battery functions - void DrawBattery(QPainter& p, QPointF center, Common::Input::BatteryLevel battery); + void DrawArrowButton(QPainter& p, QPointF center, Direction direction, bool pressed, + float size = 1.0f); + void DrawTriggerButton(QPainter& p, QPointF center, Direction direction, bool pressed); // Draw icon functions void DrawSymbol(QPainter& p, QPointF center, Symbol symbol, float icon_size); @@ -200,23 +178,24 @@ private: void SetTextFont(QPainter& p, float text_size, const QString& font_family = QStringLiteral("sans-serif")); - bool is_controller_set{}; - bool is_connected{}; - bool needs_redraw{}; - Core::HID::NpadStyleIndex controller_type; + using ButtonArray = + std::array, Settings::NativeButton::BUTTON_NS_END>; + using StickArray = + std::array, Settings::NativeAnalog::NUM_STICKS_HID>; + ControllerCallback controller_callback; + bool is_enabled{}; bool mapping_active{}; int blink_counter{}; - int callback_key; QColor button_color{}; ColorMapping colors{}; - Core::HID::LedPattern led_pattern{0, 0, 0, 0}; + std::array led_color{}; + ButtonArray buttons{}; + StickArray sticks{}; std::size_t player_index{}; - Core::HID::EmulatedController* controller; - std::size_t button_mapping_index{Settings::NativeButton::NumButtons}; - std::size_t analog_mapping_index{Settings::NativeAnalog::NumAnalogs}; - Core::HID::ButtonValues button_values{}; - Core::HID::SticksValues stick_values{}; - Core::HID::TriggerValues trigger_values{}; - Core::HID::BatteryValues battery_values{}; + std::size_t button_mapping_index{Settings::NativeButton::BUTTON_NS_END}; + std::size_t analog_mapping_index{Settings::NativeAnalog::NUM_STICKS_HID}; + std::array axis_values{}; + std::array button_values{}; + Settings::ControllerType controller_type{Settings::ControllerType::ProController}; }; diff --git a/src/yuzu/configuration/configure_input_profile_dialog.cpp b/src/yuzu/configuration/configure_input_profile_dialog.cpp index 17bbe6b61..cd5a88cea 100755 --- a/src/yuzu/configuration/configure_input_profile_dialog.cpp +++ b/src/yuzu/configuration/configure_input_profile_dialog.cpp @@ -11,8 +11,8 @@ ConfigureInputProfileDialog::ConfigureInputProfileDialog( QWidget* parent, InputCommon::InputSubsystem* input_subsystem, InputProfiles* profiles, Core::System& system) : QDialog(parent), ui(std::make_unique()), - profile_widget(new ConfigureInputPlayer(this, 9, nullptr, input_subsystem, profiles, - system.HIDCore(), system.IsPoweredOn(), false)) { + profile_widget( + new ConfigureInputPlayer(this, 9, nullptr, input_subsystem, profiles, system, false)) { ui->setupUi(this); ui->controllerLayout->addWidget(profile_widget); diff --git a/src/yuzu/configuration/configure_motion_touch.cpp b/src/yuzu/configuration/configure_motion_touch.cpp index 8539a5c8b..f8e08c422 100755 --- a/src/yuzu/configuration/configure_motion_touch.cpp +++ b/src/yuzu/configuration/configure_motion_touch.cpp @@ -15,9 +15,9 @@ #include "common/logging/log.h" #include "common/settings.h" -#include "input_common/drivers/udp_client.h" -#include "input_common/helpers/udp_protocol.h" #include "input_common/main.h" +#include "input_common/udp/client.h" +#include "input_common/udp/udp.h" #include "ui_configure_motion_touch.h" #include "yuzu/configuration/configure_motion_touch.h" #include "yuzu/configuration/configure_touch_from_button.h" @@ -93,7 +93,6 @@ ConfigureMotionTouch::ConfigureMotionTouch(QWidget* parent, "using-a-controller-or-android-phone-for-motion-or-touch-input'>Learn More")); - setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); SetConfiguration(); UpdateUiDisplay(); ConnectEvents(); @@ -102,14 +101,17 @@ ConfigureMotionTouch::ConfigureMotionTouch(QWidget* parent, ConfigureMotionTouch::~ConfigureMotionTouch() = default; void ConfigureMotionTouch::SetConfiguration() { + const Common::ParamPackage motion_param(Settings::values.motion_device.GetValue()); const Common::ParamPackage touch_param(Settings::values.touch_device.GetValue()); + ui->touch_from_button_checkbox->setChecked(Settings::values.use_touch_from_button.GetValue()); touch_from_button_maps = Settings::values.touch_from_button_maps; for (const auto& touch_map : touch_from_button_maps) { ui->touch_from_button_map->addItem(QString::fromStdString(touch_map.name)); } ui->touch_from_button_map->setCurrentIndex( Settings::values.touch_from_button_map_index.GetValue()); + ui->motion_sensitivity->setValue(motion_param.Get("sensitivity", 0.01f)); min_x = touch_param.Get("min_x", 100); min_y = touch_param.Get("min_y", 50); @@ -137,6 +139,9 @@ void ConfigureMotionTouch::SetConfiguration() { void ConfigureMotionTouch::UpdateUiDisplay() { const QString cemuhook_udp = QStringLiteral("cemuhookudp"); + ui->motion_sensitivity_label->setVisible(true); + ui->motion_sensitivity->setVisible(true); + ui->touch_calibration->setVisible(true); ui->touch_calibration_config->setVisible(true); ui->touch_calibration_label->setVisible(true); @@ -307,6 +312,7 @@ void ConfigureMotionTouch::ApplyConfiguration() { touch_param.Set("max_y", max_y); Settings::values.touch_device = touch_param.Serialize(); + Settings::values.use_touch_from_button = ui->touch_from_button_checkbox->isChecked(); Settings::values.touch_from_button_map_index = ui->touch_from_button_map->currentIndex(); Settings::values.touch_from_button_maps = touch_from_button_maps; Settings::values.udp_input_servers = GetUDPServerString(); diff --git a/src/yuzu/configuration/configure_motion_touch.ui b/src/yuzu/configuration/configure_motion_touch.ui index c75a84ae4..1e35ea946 100755 --- a/src/yuzu/configuration/configure_motion_touch.ui +++ b/src/yuzu/configuration/configure_motion_touch.ui @@ -2,6 +2,14 @@ ConfigureMotionTouch + + + 0 + 0 + 500 + 482 + + Configure Motion / Touch @@ -9,6 +17,48 @@ + + + + Mouse Motion + + + + + + + + Sensitivity: + + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 4 + + + 0.010000000000000 + + + 10.000000000000000 + + + 0.001000000000000 + + + 0.010000000000000 + + + + + + + + @@ -51,13 +101,19 @@ - - - - Touch from button profile: - - - + + + + + 0 + 0 + + + + Use button mapping: + + + diff --git a/src/yuzu/configuration/configure_mouse_advanced.cpp b/src/yuzu/configuration/configure_mouse_advanced.cpp index 1e7a3751d..2af3afda8 100755 --- a/src/yuzu/configuration/configure_mouse_advanced.cpp +++ b/src/yuzu/configuration/configure_mouse_advanced.cpp @@ -11,11 +11,8 @@ #include "common/assert.h" #include "common/param_package.h" -#include "input_common/drivers/keyboard.h" -#include "input_common/drivers/mouse.h" #include "input_common/main.h" #include "ui_configure_mouse_advanced.h" -#include "yuzu/bootmanager.h" #include "yuzu/configuration/config.h" #include "yuzu/configuration/configure_mouse_advanced.h" @@ -104,7 +101,7 @@ ConfigureMouseAdvanced::ConfigureMouseAdvanced(QWidget* parent, [=, this](const Common::ParamPackage& params) { buttons_param[button_id] = params; }, - InputCommon::Polling::InputType::Button); + InputCommon::Polling::DeviceType::Button); }); connect(button, &QPushButton::customContextMenuRequested, [=, this](const QPoint& menu_location) { @@ -130,10 +127,13 @@ ConfigureMouseAdvanced::ConfigureMouseAdvanced(QWidget* parent, connect(timeout_timer.get(), &QTimer::timeout, [this] { SetPollingResult({}, true); }); connect(poll_timer.get(), &QTimer::timeout, [this] { - const auto& params = input_subsystem->GetNextInput(); - if (params.Has("engine")) { - SetPollingResult(params, false); - return; + Common::ParamPackage params; + for (auto& poller : device_pollers) { + params = poller->GetNextInput(); + if (params.Has("engine")) { + SetPollingResult(params, false); + return; + } } }); @@ -196,13 +196,26 @@ void ConfigureMouseAdvanced::UpdateButtonLabels() { void ConfigureMouseAdvanced::HandleClick( QPushButton* button, std::function new_input_setter, - InputCommon::Polling::InputType type) { + InputCommon::Polling::DeviceType type) { button->setText(tr("[press key]")); button->setFocus(); + // Keyboard keys or mouse buttons can only be used as button devices + want_keyboard_mouse = type == InputCommon::Polling::DeviceType::Button; + if (want_keyboard_mouse) { + const auto iter = std::find(button_map.begin(), button_map.end(), button); + ASSERT(iter != button_map.end()); + const auto index = std::distance(button_map.begin(), iter); + ASSERT(index < Settings::NativeButton::NumButtons && index >= 0); + } + input_setter = new_input_setter; - input_subsystem->BeginMapping(type); + device_pollers = input_subsystem->GetPollers(type); + + for (auto& poller : device_pollers) { + poller->Start(); + } QWidget::grabMouse(); QWidget::grabKeyboard(); @@ -214,7 +227,9 @@ void ConfigureMouseAdvanced::HandleClick( void ConfigureMouseAdvanced::SetPollingResult(const Common::ParamPackage& params, bool abort) { timeout_timer->stop(); poll_timer->stop(); - input_subsystem->StopMapping(); + for (auto& poller : device_pollers) { + poller->Stop(); + } QWidget::releaseMouse(); QWidget::releaseKeyboard(); @@ -232,8 +247,15 @@ void ConfigureMouseAdvanced::mousePressEvent(QMouseEvent* event) { return; } - const auto button = GRenderWindow::QtButtonToMouseButton(event->button()); - input_subsystem->GetMouse()->PressButton(0, 0, 0, 0, button); + if (want_keyboard_mouse) { + SetPollingResult(Common::ParamPackage{InputCommon::GenerateKeyboardParam(event->button())}, + false); + } else { + // We don't want any mouse buttons, so don't stop polling + return; + } + + SetPollingResult({}, true); } void ConfigureMouseAdvanced::keyPressEvent(QKeyEvent* event) { @@ -242,6 +264,13 @@ void ConfigureMouseAdvanced::keyPressEvent(QKeyEvent* event) { } if (event->key() != Qt::Key_Escape) { - input_subsystem->GetKeyboard()->PressKey(event->key()); + if (want_keyboard_mouse) { + SetPollingResult(Common::ParamPackage{InputCommon::GenerateKeyboardParam(event->key())}, + false); + } else { + // Escape key wasn't pressed and we don't want any keyboard keys, so don't stop polling + return; + } } + SetPollingResult({}, true); } diff --git a/src/yuzu/configuration/configure_mouse_advanced.h b/src/yuzu/configuration/configure_mouse_advanced.h index 5fa534eaf..65b6fca9a 100755 --- a/src/yuzu/configuration/configure_mouse_advanced.h +++ b/src/yuzu/configuration/configure_mouse_advanced.h @@ -46,7 +46,7 @@ private: /// Called when the button was pressed. void HandleClick(QPushButton* button, std::function new_input_setter, - InputCommon::Polling::InputType type); + InputCommon::Polling::DeviceType type); /// Finish polling and configure input using the input_setter void SetPollingResult(const Common::ParamPackage& params, bool abort); @@ -67,6 +67,12 @@ private: std::array button_map; std::array buttons_param; + std::vector> device_pollers; + std::unique_ptr timeout_timer; std::unique_ptr poll_timer; + + /// A flag to indicate if keyboard keys are okay when configuring an input. If this is false, + /// keyboard events are ignored. + bool want_keyboard_mouse = false; }; diff --git a/src/yuzu/configuration/configure_tas.cpp b/src/yuzu/configuration/configure_tas.cpp index 979a8db61..8e5a4c72d 100755 --- a/src/yuzu/configuration/configure_tas.cpp +++ b/src/yuzu/configuration/configure_tas.cpp @@ -32,6 +32,7 @@ void ConfigureTasDialog::LoadConfiguration() { ui->tas_path_edit->setText( QString::fromStdString(Common::FS::GetYuzuPathString(Common::FS::YuzuPath::TASDir))); ui->tas_enable->setChecked(Settings::values.tas_enable.GetValue()); + ui->tas_control_swap->setChecked(Settings::values.tas_swap_controllers.GetValue()); ui->tas_loop_script->setChecked(Settings::values.tas_loop.GetValue()); ui->tas_pause_on_load->setChecked(Settings::values.pause_tas_on_load.GetValue()); } @@ -39,6 +40,7 @@ void ConfigureTasDialog::LoadConfiguration() { void ConfigureTasDialog::ApplyConfiguration() { Common::FS::SetYuzuPath(Common::FS::YuzuPath::TASDir, ui->tas_path_edit->text().toStdString()); Settings::values.tas_enable.SetValue(ui->tas_enable->isChecked()); + Settings::values.tas_swap_controllers.SetValue(ui->tas_control_swap->isChecked()); Settings::values.tas_loop.SetValue(ui->tas_loop_script->isChecked()); Settings::values.pause_tas_on_load.SetValue(ui->tas_pause_on_load->isChecked()); } diff --git a/src/yuzu/configuration/configure_tas.ui b/src/yuzu/configuration/configure_tas.ui index cf88a5bf0..7d44895c4 100755 --- a/src/yuzu/configuration/configure_tas.ui +++ b/src/yuzu/configuration/configure_tas.ui @@ -59,13 +59,20 @@ + + + Automatic controller profile swapping + + + + Loop script - + false diff --git a/src/yuzu/configuration/configure_touch_from_button.cpp b/src/yuzu/configuration/configure_touch_from_button.cpp index bde0a08c4..40129f228 100755 --- a/src/yuzu/configuration/configure_touch_from_button.cpp +++ b/src/yuzu/configuration/configure_touch_from_button.cpp @@ -163,10 +163,13 @@ void ConfigureTouchFromButton::ConnectEvents() { connect(timeout_timer.get(), &QTimer::timeout, [this]() { SetPollingResult({}, true); }); connect(poll_timer.get(), &QTimer::timeout, [this]() { - const auto& params = input_subsystem->GetNextInput(); - if (params.Has("engine")) { - SetPollingResult(params, false); - return; + Common::ParamPackage params; + for (auto& poller : device_pollers) { + params = poller->GetNextInput(); + if (params.Has("engine")) { + SetPollingResult(params, false); + return; + } } }); } @@ -245,7 +248,11 @@ void ConfigureTouchFromButton::GetButtonInput(const int row_index, const bool is } }; - input_subsystem->BeginMapping(InputCommon::Polling::InputType::Button); + device_pollers = input_subsystem->GetPollers(InputCommon::Polling::DeviceType::Button); + + for (auto& poller : device_pollers) { + poller->Start(); + } grabKeyboard(); grabMouse(); @@ -358,14 +365,14 @@ void ConfigureTouchFromButton::SetCoordinates(const int dot_id, const QPoint& po void ConfigureTouchFromButton::SetPollingResult(const Common::ParamPackage& params, const bool cancel) { - timeout_timer->stop(); - poll_timer->stop(); - input_subsystem->StopMapping(); - releaseKeyboard(); releaseMouse(); qApp->restoreOverrideCursor(); - + timeout_timer->stop(); + poll_timer->stop(); + for (auto& poller : device_pollers) { + poller->Stop(); + } if (input_setter) { (*input_setter)(params, cancel); input_setter.reset(); diff --git a/src/yuzu/configuration/configure_touch_from_button.h b/src/yuzu/configuration/configure_touch_from_button.h index e1400481a..d9513e3bc 100755 --- a/src/yuzu/configuration/configure_touch_from_button.h +++ b/src/yuzu/configuration/configure_touch_from_button.h @@ -24,6 +24,10 @@ namespace InputCommon { class InputSubsystem; } +namespace InputCommon::Polling { +class DevicePoller; +} + namespace Settings { struct TouchFromButtonMap; } @@ -81,6 +85,7 @@ private: std::unique_ptr timeout_timer; std::unique_ptr poll_timer; + std::vector> device_pollers; std::optional> input_setter; static constexpr int DataRoleDot = Qt::ItemDataRole::UserRole + 2; diff --git a/src/yuzu/configuration/configure_vibration.cpp b/src/yuzu/configuration/configure_vibration.cpp index f1ce7205d..46a0f3025 100755 --- a/src/yuzu/configuration/configure_vibration.cpp +++ b/src/yuzu/configuration/configure_vibration.cpp @@ -97,7 +97,7 @@ void ConfigureVibration::SetVibrationDevices(std::size_t player_index) { const auto engine = param.Get("engine", ""); const auto guid = param.Get("guid", ""); - const auto port = param.Get("port", 0); + const auto port = param.Get("port", ""); if (engine.empty() || engine == "keyboard" || engine == "mouse" || engine == "tas") { continue; @@ -105,7 +105,7 @@ void ConfigureVibration::SetVibrationDevices(std::size_t player_index) { vibration_param_str += fmt::format("engine:{}", engine); - if (port != 0) { + if (!port.empty()) { vibration_param_str += fmt::format(",port:{}", port); } if (!guid.empty()) { diff --git a/src/yuzu/debugger/controller.cpp b/src/yuzu/debugger/controller.cpp index 6b834c42e..5a844409b 100755 --- a/src/yuzu/debugger/controller.cpp +++ b/src/yuzu/debugger/controller.cpp @@ -6,17 +6,13 @@ #include #include #include "common/settings.h" -#include "core/hid/emulated_controller.h" -#include "core/hid/hid_core.h" -#include "input_common/drivers/tas_input.h" #include "input_common/main.h" +#include "input_common/tas/tas_input.h" #include "yuzu/configuration/configure_input_player_widget.h" #include "yuzu/debugger/controller.h" -ControllerDialog::ControllerDialog(Core::HID::HIDCore& hid_core_, - std::shared_ptr input_subsystem_, - QWidget* parent) - : QWidget(parent, Qt::Dialog), hid_core{hid_core_}, input_subsystem{input_subsystem_} { +ControllerDialog::ControllerDialog(QWidget* parent, InputCommon::InputSubsystem* input_subsystem_) + : QWidget(parent, Qt::Dialog), input_subsystem{input_subsystem_} { setObjectName(QStringLiteral("Controller")); setWindowTitle(tr("Controller P1")); resize(500, 350); @@ -35,24 +31,20 @@ ControllerDialog::ControllerDialog(Core::HID::HIDCore& hid_core_, // Configure focus so that widget is focusable and the dialog automatically forwards focus to // it. setFocusProxy(widget); + widget->SetConnectedStatus(false); widget->setFocusPolicy(Qt::StrongFocus); widget->setFocus(); } void ControllerDialog::refreshConfiguration() { - UnloadController(); - auto* player_1 = hid_core.GetEmulatedController(Core::HID::NpadIdType::Player1); - auto* handheld = hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld); - // Display the correct controller - controller = handheld->IsConnected() ? handheld : player_1; - - Core::HID::ControllerUpdateCallback engine_callback{ - .on_change = [this](Core::HID::ControllerTriggerType type) { ControllerUpdate(type); }, - .is_npad_service = true, - }; - callback_key = controller->SetCallback(engine_callback); - widget->SetController(controller); - is_controller_set = true; + const auto& players = Settings::values.players.GetValue(); + constexpr std::size_t player = 0; + widget->SetPlayerInputRaw(player, players[player].buttons, players[player].analogs); + widget->SetControllerType(players[player].controller_type); + ControllerCallback callback{[this](ControllerInput input) { InputController(input); }}; + widget->SetCallBack(callback); + widget->repaint(); + widget->SetConnectedStatus(players[player].connected); } QAction* ControllerDialog::toggleViewAction() { @@ -66,18 +58,11 @@ QAction* ControllerDialog::toggleViewAction() { return toggle_view_action; } -void ControllerDialog::UnloadController() { - widget->UnloadController(); - if (is_controller_set) { - controller->DeleteCallback(callback_key); - is_controller_set = false; - } -} - void ControllerDialog::showEvent(QShowEvent* ev) { if (toggle_view_action) { toggle_view_action->setChecked(isVisible()); } + refreshConfiguration(); QWidget::showEvent(ev); } @@ -85,34 +70,16 @@ void ControllerDialog::hideEvent(QHideEvent* ev) { if (toggle_view_action) { toggle_view_action->setChecked(isVisible()); } + widget->SetConnectedStatus(false); QWidget::hideEvent(ev); } -void ControllerDialog::ControllerUpdate(Core::HID::ControllerTriggerType type) { - // TODO(german77): Remove TAS from here - switch (type) { - case Core::HID::ControllerTriggerType::Button: - case Core::HID::ControllerTriggerType::Stick: { - const auto buttons_values = controller->GetButtonsValues(); - const auto stick_values = controller->GetSticksValues(); - u64 buttons = 0; - std::size_t index = 0; - for (const auto& button : buttons_values) { - buttons |= button.value ? 1LLU << index : 0; - index++; - } - const InputCommon::TasInput::TasAnalog left_axis = { - .x = stick_values[Settings::NativeAnalog::LStick].x.value, - .y = stick_values[Settings::NativeAnalog::LStick].y.value, - }; - const InputCommon::TasInput::TasAnalog right_axis = { - .x = stick_values[Settings::NativeAnalog::RStick].x.value, - .y = stick_values[Settings::NativeAnalog::RStick].y.value, - }; - input_subsystem->GetTas()->RecordInput(buttons, left_axis, right_axis); - break; - } - default: - break; +void ControllerDialog::InputController(ControllerInput input) { + u32 buttons = 0; + int index = 0; + for (bool btn : input.button_values) { + buttons |= (btn ? 1U : 0U) << index; + index++; } + input_subsystem->GetTas()->RecordInput(buttons, input.axis_values); } diff --git a/src/yuzu/debugger/controller.h b/src/yuzu/debugger/controller.h index 52cea3326..7742db58b 100755 --- a/src/yuzu/debugger/controller.h +++ b/src/yuzu/debugger/controller.h @@ -4,7 +4,9 @@ #pragma once +#include #include +#include "common/settings.h" class QAction; class QHideEvent; @@ -15,43 +17,35 @@ namespace InputCommon { class InputSubsystem; } -namespace Core::HID { -class HIDCore; -class EmulatedController; -enum class ControllerTriggerType; -} // namespace Core::HID +struct ControllerInput { + std::array, Settings::NativeAnalog::NUM_STICKS_HID> axis_values{}; + std::array button_values{}; + bool changed{}; +}; + +struct ControllerCallback { + std::function input; +}; class ControllerDialog : public QWidget { Q_OBJECT public: - explicit ControllerDialog(Core::HID::HIDCore& hid_core_, - std::shared_ptr input_subsystem_, - QWidget* parent = nullptr); + explicit ControllerDialog(QWidget* parent = nullptr, + InputCommon::InputSubsystem* input_subsystem_ = nullptr); /// Returns a QAction that can be used to toggle visibility of this dialog. QAction* toggleViewAction(); - - /// Reloads the widget to apply any changes in the configuration void refreshConfiguration(); - /// Disables events from the emulated controller - void UnloadController(); - protected: void showEvent(QShowEvent* ev) override; void hideEvent(QHideEvent* ev) override; private: - /// Redirects input from the widget to the TAS driver - void ControllerUpdate(Core::HID::ControllerTriggerType type); - - int callback_key; - bool is_controller_set{}; - Core::HID::EmulatedController* controller; - + void InputController(ControllerInput input); QAction* toggle_view_action = nullptr; + QFileSystemWatcher* watcher = nullptr; PlayerControlPreview* widget; - Core::HID::HIDCore& hid_core; - std::shared_ptr input_subsystem; + InputCommon::InputSubsystem* input_subsystem; }; diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 5ffa0a27a..d057dc889 100755 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -26,8 +26,6 @@ #include "core/frontend/applets/controller.h" #include "core/frontend/applets/general_frontend.h" #include "core/frontend/applets/software_keyboard.h" -#include "core/hid/emulated_controller.h" -#include "core/hid/hid_core.h" #include "core/hle/service/acc/profile_manager.h" #include "core/hle/service/am/applet_ae.h" #include "core/hle/service/am/applet_oe.h" @@ -108,8 +106,8 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual #include "core/loader/loader.h" #include "core/perf_stats.h" #include "core/telemetry_session.h" -#include "input_common/drivers/tas_input.h" #include "input_common/main.h" +#include "input_common/tas/tas_input.h" #include "ui_main.h" #include "util/overlay_dialog.h" #include "video_core/gpu.h" @@ -229,9 +227,6 @@ GMainWindow::GMainWindow() ConnectMenuEvents(); ConnectWidgetEvents(); - system->HIDCore().ReloadInputDevices(); - controller_dialog->refreshConfiguration(); - const auto branch_name = std::string(Common::g_scm_branch); const auto description = std::string(Common::g_scm_desc); const auto build_id = std::string(Common::g_build_id); @@ -834,16 +829,15 @@ void GMainWindow::InitializeWidgets() { dock_status_button->setFocusPolicy(Qt::NoFocus); connect(dock_status_button, &QPushButton::clicked, [&] { const bool is_docked = Settings::values.use_docked_mode.GetValue(); - auto* player_1 = system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); - auto* handheld = system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld); + auto& controller_type = Settings::values.players.GetValue()[0].controller_type; - if (!is_docked && handheld->IsConnected()) { + if (!is_docked && controller_type == Settings::ControllerType::Handheld) { QMessageBox::warning(this, tr("Invalid config detected"), tr("Handheld controller can't be used on docked mode. Pro " "controller will be selected.")); - handheld->Disconnect(); - player_1->SetNpadStyleIndex(Core::HID::NpadStyleIndex::ProController); - player_1->Connect(); + controller_type = Settings::ControllerType::ProController; + ConfigureDialog configure_dialog(this, hotkey_registry, input_subsystem.get(), *system); + configure_dialog.ApplyConfiguration(); controller_dialog->refreshConfiguration(); } @@ -928,7 +922,7 @@ void GMainWindow::InitializeDebugWidgets() { waitTreeWidget->hide(); debug_menu->addAction(waitTreeWidget->toggleViewAction()); - controller_dialog = new ControllerDialog(system->HIDCore(), input_subsystem, this); + controller_dialog = new ControllerDialog(this, input_subsystem.get()); controller_dialog->hide(); debug_menu->addAction(controller_dialog->toggleViewAction()); @@ -2780,6 +2774,7 @@ void GMainWindow::OnConfigure() { ShowTelemetryCallout(); } + controller_dialog->refreshConfiguration(); InitializeHotkeys(); if (UISettings::values.theme != old_theme) { @@ -2812,7 +2807,6 @@ void GMainWindow::OnConfigure() { } UpdateStatusButtons(); - controller_dialog->refreshConfiguration(); } void GMainWindow::OnConfigureTas() { @@ -3009,11 +3003,11 @@ void GMainWindow::UpdateWindowTitle(std::string_view title_name, std::string_vie QString GMainWindow::GetTasStateDescription() const { auto [tas_status, current_tas_frame, total_tas_frames] = input_subsystem->GetTas()->GetStatus(); switch (tas_status) { - case InputCommon::TasInput::TasState::Running: + case TasInput::TasState::Running: return tr("TAS state: Running %1/%2").arg(current_tas_frame).arg(total_tas_frames); - case InputCommon::TasInput::TasState::Recording: + case TasInput::TasState::Recording: return tr("TAS state: Recording %1").arg(total_tas_frames); - case InputCommon::TasInput::TasState::Stopped: + case TasInput::TasState::Stopped: return tr("TAS state: Idle %1/%2").arg(current_tas_frame).arg(total_tas_frames); default: return tr("TAS State: Invalid"); @@ -3392,8 +3386,6 @@ void GMainWindow::closeEvent(QCloseEvent* event) { UpdateUISettings(); game_list->SaveInterfaceLayout(); hotkey_registry.SaveHotkeys(); - controller_dialog->UnloadController(); - system->HIDCore().UnloadInputDevices(); // Shutdown session if the emu thread is active... if (emu_thread != nullptr) { diff --git a/src/yuzu/util/overlay_dialog.cpp b/src/yuzu/util/overlay_dialog.cpp index c66dfbdff..95b148545 100755 --- a/src/yuzu/util/overlay_dialog.cpp +++ b/src/yuzu/util/overlay_dialog.cpp @@ -6,8 +6,7 @@ #include #include "core/core.h" -#include "core/hid/hid_types.h" -#include "core/hid/input_interpreter.h" +#include "core/frontend/input_interpreter.h" #include "ui_overlay_dialog.h" #include "yuzu/util/overlay_dialog.h" @@ -180,9 +179,9 @@ void OverlayDialog::MoveAndResizeWindow() { QDialog::resize(width, height); } -template +template void OverlayDialog::HandleButtonPressedOnce() { - const auto f = [this](Core::HID::NpadButton button) { + const auto f = [this](HIDButton button) { if (input_interpreter->IsButtonPressedOnce(button)) { TranslateButtonPress(button); } @@ -191,7 +190,7 @@ void OverlayDialog::HandleButtonPressedOnce() { (f(T), ...); } -void OverlayDialog::TranslateButtonPress(Core::HID::NpadButton button) { +void OverlayDialog::TranslateButtonPress(HIDButton button) { QPushButton* left_button = use_rich_text ? ui->button_cancel_rich : ui->button_cancel; QPushButton* right_button = use_rich_text ? ui->button_ok_rich : ui->button_ok_label; @@ -199,20 +198,20 @@ void OverlayDialog::TranslateButtonPress(Core::HID::NpadButton button) { // TODO (Morph): focusPrevious/NextChild() doesn't work well with the rich text dialog, fix it switch (button) { - case Core::HID::NpadButton::A: - case Core::HID::NpadButton::B: + case HIDButton::A: + case HIDButton::B: if (left_button->hasFocus()) { left_button->click(); } else if (right_button->hasFocus()) { right_button->click(); } break; - case Core::HID::NpadButton::Left: - case Core::HID::NpadButton::StickLLeft: + case HIDButton::DLeft: + case HIDButton::LStickLeft: focusPreviousChild(); break; - case Core::HID::NpadButton::Right: - case Core::HID::NpadButton::StickLRight: + case HIDButton::DRight: + case HIDButton::LStickRight: focusNextChild(); break; default: @@ -242,10 +241,8 @@ void OverlayDialog::InputThread() { while (input_thread_running) { input_interpreter->PollInput(); - HandleButtonPressedOnce(); + HandleButtonPressedOnce(); std::this_thread::sleep_for(std::chrono::milliseconds(50)); } diff --git a/src/yuzu/util/overlay_dialog.h b/src/yuzu/util/overlay_dialog.h index d8a140ff3..e8c388bd0 100755 --- a/src/yuzu/util/overlay_dialog.h +++ b/src/yuzu/util/overlay_dialog.h @@ -13,16 +13,14 @@ #include "common/common_types.h" +enum class HIDButton : u8; + class InputInterpreter; namespace Core { class System; } -namespace Core::HID { -enum class NpadButton : u64; -} - namespace Ui { class OverlayDialog; } @@ -81,7 +79,7 @@ private: * * @tparam HIDButton The list of buttons that can be converted into keyboard input. */ - template + template void HandleButtonPressedOnce(); /** @@ -89,7 +87,7 @@ private: * * @param button The button press to process. */ - void TranslateButtonPress(Core::HID::NpadButton button); + void TranslateButtonPress(HIDButton button); void StartInputThread(); void StopInputThread(); diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp index 7ca09a635..33241ea98 100755 --- a/src/yuzu_cmd/config.cpp +++ b/src/yuzu_cmd/config.cpp @@ -24,6 +24,7 @@ #include "common/settings.h" #include "core/hle/service/acc/profile_manager.h" #include "input_common/main.h" +#include "input_common/udp/client.h" #include "yuzu_cmd/config.h" #include "yuzu_cmd/default_ini.h" @@ -292,6 +293,8 @@ void Config::ReadValues() { Settings::values.mouse_buttons[i] = default_param; } + ReadSetting("ControlsGeneral", Settings::values.motion_device); + ReadSetting("ControlsGeneral", Settings::values.touch_device); ReadSetting("ControlsGeneral", Settings::values.keyboard_enabled); @@ -360,6 +363,7 @@ void Config::ReadValues() { Settings::TouchFromButtonMap{"default", {}}); num_touch_from_button_maps = 1; } + ReadSetting("ControlsGeneral", Settings::values.use_touch_from_button); Settings::values.touch_from_button_map_index = std::clamp( Settings::values.touch_from_button_map_index.GetValue(), 0, num_touch_from_button_maps - 1); diff --git a/src/yuzu_cmd/default_ini.h b/src/yuzu_cmd/default_ini.h index 6d613bf7a..ecdc271a8 100755 --- a/src/yuzu_cmd/default_ini.h +++ b/src/yuzu_cmd/default_ini.h @@ -84,10 +84,23 @@ enable_accurate_vibrations= # 0: Disabled, 1 (default): Enabled motion_enabled = -# Defines the udp device's touch screen coordinate system for cemuhookudp devices -# - "min_x", "min_y", "max_x", "max_y" +# for motion input, the following devices are available: +# - "motion_emu" (default) for emulating motion input from mouse input. Required parameters: +# - "update_period": update period in milliseconds (default to 100) +# - "sensitivity": the coefficient converting mouse movement to tilting angle (default to 0.01) +# - "cemuhookudp" reads motion input from a udp server that uses cemuhook's udp protocol +motion_device= + +# for touch input, the following devices are available: +# - "emu_window" (default) for emulating touch input from mouse input to the emulation window. No parameters required +# - "cemuhookudp" reads touch input from a udp server that uses cemuhook's udp protocol +# - "min_x", "min_y", "max_x", "max_y": defines the udp device's touch screen coordinate system touch_device= +# Whether to enable or disable touch input from button +# 0 (default): Disabled, 1: Enabled +use_touch_from_button= + # for mapping buttons to touch inputs. #touch_from_button_map=1 #touch_from_button_maps_0_name=default diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp index 57f807826..87fce0c23 100755 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp @@ -9,10 +9,10 @@ #include "common/settings.h" #include "core/core.h" #include "core/perf_stats.h" -#include "input_common/drivers/keyboard.h" -#include "input_common/drivers/mouse.h" -#include "input_common/drivers/touch_screen.h" +#include "input_common/keyboard.h" #include "input_common/main.h" +#include "input_common/mouse/mouse_input.h" +#include "input_common/sdl/sdl.h" #include "yuzu_cmd/emu_window/emu_window_sdl2.h" #include "yuzu_cmd/yuzu_icon.h" @@ -32,32 +32,42 @@ EmuWindow_SDL2::~EmuWindow_SDL2() { } void EmuWindow_SDL2::OnMouseMotion(s32 x, s32 y) { - input_subsystem->GetMouse()->MouseMove(x, y, 0, 0, 0, 0); + TouchMoved((unsigned)std::max(x, 0), (unsigned)std::max(y, 0), 0); + + input_subsystem->GetMouse()->MouseMove(x, y, 0, 0); } -InputCommon::MouseButton EmuWindow_SDL2::SDLButtonToMouseButton(u32 button) const { +MouseInput::MouseButton EmuWindow_SDL2::SDLButtonToMouseButton(u32 button) const { switch (button) { case SDL_BUTTON_LEFT: - return InputCommon::MouseButton::Left; + return MouseInput::MouseButton::Left; case SDL_BUTTON_RIGHT: - return InputCommon::MouseButton::Right; + return MouseInput::MouseButton::Right; case SDL_BUTTON_MIDDLE: - return InputCommon::MouseButton::Wheel; + return MouseInput::MouseButton::Wheel; case SDL_BUTTON_X1: - return InputCommon::MouseButton::Backward; + return MouseInput::MouseButton::Backward; case SDL_BUTTON_X2: - return InputCommon::MouseButton::Forward; + return MouseInput::MouseButton::Forward; default: - return InputCommon::MouseButton::Undefined; + return MouseInput::MouseButton::Undefined; } } void EmuWindow_SDL2::OnMouseButton(u32 button, u8 state, s32 x, s32 y) { const auto mouse_button = SDLButtonToMouseButton(button); - if (state == SDL_PRESSED) { - input_subsystem->GetMouse()->PressButton(x, y, 0, 0, mouse_button); + if (button == SDL_BUTTON_LEFT) { + if (state == SDL_PRESSED) { + TouchPressed((unsigned)std::max(x, 0), (unsigned)std::max(y, 0), 0); + } else { + TouchReleased(0); + } } else { - input_subsystem->GetMouse()->ReleaseButton(mouse_button); + if (state == SDL_PRESSED) { + input_subsystem->GetMouse()->PressButton(x, y, mouse_button); + } else { + input_subsystem->GetMouse()->ReleaseButton(mouse_button); + } } } @@ -72,35 +82,29 @@ std::pair EmuWindow_SDL2::TouchToPixelPos(float touch_x, flo static_cast(std::max(std::round(touch_y), 0.0f))}; } -void EmuWindow_SDL2::OnFingerDown(float x, float y, std::size_t id) { - int width, height; - SDL_GetWindowSize(render_window, &width, &height); - const auto [px, py] = TouchToPixelPos(x, y); - const float fx = px * 1.0f / width; - const float fy = py * 1.0f / height; +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 - input_subsystem->GetTouchScreen()->TouchPressed(fx, fy, id); + const auto [px, py] = TouchToPixelPos(x, y); + TouchPressed(px, py, 0); } -void EmuWindow_SDL2::OnFingerMotion(float x, float y, std::size_t id) { - int width, height; - SDL_GetWindowSize(render_window, &width, &height); +void EmuWindow_SDL2::OnFingerMotion(float x, float y) { const auto [px, py] = TouchToPixelPos(x, y); - const float fx = px * 1.0f / width; - const float fy = py * 1.0f / height; - - input_subsystem->GetTouchScreen()->TouchMoved(fx, fy, id); + TouchMoved(px, py, 0); } void EmuWindow_SDL2::OnFingerUp() { - input_subsystem->GetTouchScreen()->TouchReleased(0); + TouchReleased(0); } void EmuWindow_SDL2::OnKeyEvent(int key, u8 state) { if (state == SDL_PRESSED) { - input_subsystem->GetKeyboard()->PressKey(static_cast(key)); + input_subsystem->GetKeyboard()->PressKey(key); } else if (state == SDL_RELEASED) { - input_subsystem->GetKeyboard()->ReleaseKey(static_cast(key)); + input_subsystem->GetKeyboard()->ReleaseKey(key); } } @@ -201,12 +205,10 @@ void EmuWindow_SDL2::WaitEvent() { } break; case SDL_FINGERDOWN: - OnFingerDown(event.tfinger.x, event.tfinger.y, - static_cast(event.tfinger.touchId)); + OnFingerDown(event.tfinger.x, event.tfinger.y); break; case SDL_FINGERMOTION: - OnFingerMotion(event.tfinger.x, event.tfinger.y, - static_cast(event.tfinger.touchId)); + OnFingerMotion(event.tfinger.x, event.tfinger.y); break; case SDL_FINGERUP: OnFingerUp(); diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.h b/src/yuzu_cmd/emu_window/emu_window_sdl2.h index 0af002693..4810f8775 100755 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2.h +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.h @@ -16,8 +16,11 @@ class System; namespace InputCommon { class InputSubsystem; +} + +namespace MouseInput { enum class MouseButton; -} // namespace InputCommon +} class EmuWindow_SDL2 : public Core::Frontend::EmuWindow { public: @@ -44,7 +47,7 @@ protected: void OnMouseMotion(s32 x, s32 y); /// Converts a SDL mouse button into MouseInput mouse button - InputCommon::MouseButton SDLButtonToMouseButton(u32 button) const; + MouseInput::MouseButton SDLButtonToMouseButton(u32 button) const; /// Called by WaitEvent when a mouse button is pressed or released void OnMouseButton(u32 button, u8 state, s32 x, s32 y); @@ -53,10 +56,10 @@ protected: std::pair TouchToPixelPos(float touch_x, float touch_y) const; /// Called by WaitEvent when a finger starts touching the touchscreen - void OnFingerDown(float x, float y, std::size_t id); + void OnFingerDown(float x, float y); /// Called by WaitEvent when a finger moves while touching the touchscreen - void OnFingerMotion(float x, float y, std::size_t id); + void OnFingerMotion(float x, float y); /// Called by WaitEvent when a finger stops touching the touchscreen void OnFingerUp(); diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp index 70db865ec..a075ad08a 100755 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2_gl.cpp @@ -17,6 +17,7 @@ #include "common/settings.h" #include "common/string_util.h" #include "core/core.h" +#include "input_common/keyboard.h" #include "input_common/main.h" #include "video_core/renderer_base.h" #include "yuzu_cmd/emu_window/emu_window_sdl2_gl.h"