From 5a785ed794fff8c944283271bf25cb835c11700a Mon Sep 17 00:00:00 2001 From: german77 Date: Mon, 20 Sep 2021 17:18:40 -0500 Subject: input_common: Rewrite keyboard --- src/input_common/drivers/keyboard.cpp | 35 ++++++++++++++++++++++++++++ src/input_common/drivers/keyboard.h | 44 +++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 src/input_common/drivers/keyboard.cpp create mode 100644 src/input_common/drivers/keyboard.h (limited to 'src/input_common/drivers') diff --git a/src/input_common/drivers/keyboard.cpp b/src/input_common/drivers/keyboard.cpp new file mode 100644 index 000000000..b00a4b8d9 --- /dev/null +++ b/src/input_common/drivers/keyboard.cpp @@ -0,0 +1,35 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included + +#include "common/param_package.h" +#include "input_common/drivers/keyboard.h" + +namespace InputCommon { + +Keyboard::Keyboard(const std::string& input_engine_) : InputEngine(input_engine_) { + PreSetController(identifier); +} + +void Keyboard::PressKey(int key_code) { + SetButton(identifier, key_code, true); +} + +void Keyboard::ReleaseKey(int key_code) { + SetButton(identifier, key_code, false); +} + +void Keyboard::ReleaseAllKeys() { + ResetButtonState(); +} + +std::vector Keyboard::GetInputDevices() const { + std::vector devices; + devices.emplace_back(Common::ParamPackage{ + {"engine", "keyboard"}, + {"display", "Keyboard Only"}, + }); + return devices; +} + +} // namespace InputCommon diff --git a/src/input_common/drivers/keyboard.h b/src/input_common/drivers/keyboard.h new file mode 100644 index 000000000..a3e0d8a61 --- /dev/null +++ b/src/input_common/drivers/keyboard.h @@ -0,0 +1,44 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included + +#pragma once + +#include "input_common/input_engine.h" + +namespace InputCommon { + +/** + * A button device factory representing a keyboard. It receives keyboard events and forward them + * to all button devices it created. + */ +class Keyboard final : public InputCommon::InputEngine { +public: + explicit Keyboard(const std::string& input_engine_); + + /** + * Sets the status of all buttons bound with the key to pressed + * @param key_code the code of the key to press + */ + void PressKey(int key_code); + + /** + * Sets the status of all buttons bound with the key to released + * @param key_code the code of the key to release + */ + void ReleaseKey(int key_code); + + void ReleaseAllKeys(); + + /// Used for automapping features + std::vector GetInputDevices() const override; + +private: + const PadIdentifier identifier = { + .guid = Common::UUID{""}, + .port = 0, + .pad = 0, + }; +}; + +} // namespace InputCommon -- cgit v1.2.3 From 00834b84dd954f6aea2354e07de2054a99f53fa4 Mon Sep 17 00:00:00 2001 From: german77 Date: Mon, 20 Sep 2021 17:19:55 -0500 Subject: input_common: Rewrite mouse --- src/input_common/CMakeLists.txt | 6 +- src/input_common/drivers/mouse.cpp | 138 +++++++++++++++ src/input_common/drivers/mouse.h | 77 ++++++++ src/input_common/mouse/mouse_input.cpp | 223 ------------------------ src/input_common/mouse/mouse_input.h | 116 ------------- src/input_common/mouse/mouse_poller.cpp | 299 -------------------------------- src/input_common/mouse/mouse_poller.h | 109 ------------ 7 files changed, 217 insertions(+), 751 deletions(-) create mode 100644 src/input_common/drivers/mouse.cpp create mode 100644 src/input_common/drivers/mouse.h delete mode 100644 src/input_common/mouse/mouse_input.cpp delete mode 100644 src/input_common/mouse/mouse_input.h delete mode 100644 src/input_common/mouse/mouse_poller.cpp delete mode 100644 src/input_common/mouse/mouse_poller.h (limited to 'src/input_common/drivers') diff --git a/src/input_common/CMakeLists.txt b/src/input_common/CMakeLists.txt index 0fcf7a9d7..34b41ce01 100644 --- a/src/input_common/CMakeLists.txt +++ b/src/input_common/CMakeLists.txt @@ -1,6 +1,8 @@ add_library(input_common STATIC drivers/keyboard.cpp drivers/keyboard.h + drivers/mouse.cpp + drivers/mouse.h helpers/stick_from_buttons.cpp helpers/stick_from_buttons.h helpers/touch_from_buttons.cpp @@ -23,10 +25,6 @@ add_library(input_common STATIC 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 diff --git a/src/input_common/drivers/mouse.cpp b/src/input_common/drivers/mouse.cpp new file mode 100644 index 000000000..2c2432fb7 --- /dev/null +++ b/src/input_common/drivers/mouse.cpp @@ -0,0 +1,138 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included + +#include +#include +#include + +#include "common/param_package.h" +#include "common/settings.h" +#include "common/thread.h" +#include "input_common/drivers/mouse.h" + +namespace InputCommon { +constexpr int touch_axis_x = 10; +constexpr int touch_axis_y = 11; + +Mouse::Mouse(const std::string input_engine_) : InputEngine(input_engine_) { + PreSetController(identifier); + update_thread = std::jthread([this](std::stop_token stop_token) { UpdateThread(stop_token); }); +} + +void Mouse::UpdateThread(std::stop_token stop_token) { + Common::SetCurrentThreadName("yuzu:input:Mouse"); + constexpr int update_time = 10; + while (!stop_token.stop_requested()) { + if (Settings::values.mouse_panning) { + // Slow movement by 4% + last_mouse_change *= 0.96f; + const float sensitivity = + Settings::values.mouse_panning_sensitivity.GetValue() * 0.022f; + SetAxis(identifier, 0, last_mouse_change.x * sensitivity); + SetAxis(identifier, 1, -last_mouse_change.y * sensitivity); + } + + if (mouse_panning_timout++ > 20) { + StopPanning(); + } + std::this_thread::sleep_for(std::chrono::milliseconds(update_time)); + } +} + +void Mouse::MouseMove(int x, int y, f32 touch_x, f32 touch_y, int center_x, int center_y) { + SetAxis(identifier, touch_axis_x, touch_x); + SetAxis(identifier, touch_axis_y, touch_y); + + if (Settings::values.mouse_panning) { + auto mouse_change = + (Common::MakeVec(x, y) - Common::MakeVec(center_x, center_y)).Cast(); + mouse_panning_timout = 0; + + const auto move_distance = mouse_change.Length(); + if (move_distance == 0) { + return; + } + + // Make slow movements at least 3 units on lenght + if (move_distance < 3.0f) { + // Normalize value + mouse_change /= move_distance; + mouse_change *= 3.0f; + } + + // Average mouse movements + last_mouse_change = (last_mouse_change * 0.91f) + (mouse_change * 0.09f); + + const auto last_move_distance = last_mouse_change.Length(); + + // Make fast movements clamp to 8 units on lenght + if (last_move_distance > 8.0f) { + // Normalize value + last_mouse_change /= last_move_distance; + last_mouse_change *= 8.0f; + } + + // Ignore average if it's less than 1 unit and use current movement value + if (last_move_distance < 1.0f) { + last_mouse_change = mouse_change / mouse_change.Length(); + } + + return; + } + + if (button_pressed) { + const auto mouse_move = Common::MakeVec(x, y) - mouse_origin; + const float sensitivity = Settings::values.mouse_panning_sensitivity.GetValue() * 0.0012f; + SetAxis(identifier, 0, static_cast(mouse_move.x) * sensitivity); + SetAxis(identifier, 1, static_cast(-mouse_move.y) * sensitivity); + } +} + +void Mouse::PressButton(int x, int y, f32 touch_x, f32 touch_y, MouseButton button) { + SetAxis(identifier, touch_axis_x, touch_x); + SetAxis(identifier, touch_axis_y, touch_y); + SetButton(identifier, static_cast(button), true); + // Set initial analog parameters + mouse_origin = {x, y}; + last_mouse_position = {x, y}; + button_pressed = true; +} + +void Mouse::ReleaseButton(MouseButton button) { + SetButton(identifier, static_cast(button), false); + + if (!Settings::values.mouse_panning) { + SetAxis(identifier, 0, 0); + SetAxis(identifier, 1, 0); + } + button_pressed = false; +} + +void Mouse::ReleaseAllButtons() { + ResetButtonState(); + button_pressed = false; +} + +void Mouse::StopPanning() { + last_mouse_change = {}; +} + +std::vector Mouse::GetInputDevices() const { + std::vector devices; + devices.emplace_back(Common::ParamPackage{ + {"engine", "keyboard"}, + {"display", "Keyboard/Mouse"}, + }); + return devices; +} + +std::string Mouse::GetUIName(const Common::ParamPackage& params) const { + if (params.Has("button")) { + return fmt::format("Mouse {}", params.Get("button", 0)); + } + + return "Bad Mouse"; +} + +} // namespace InputCommon diff --git a/src/input_common/drivers/mouse.h b/src/input_common/drivers/mouse.h new file mode 100644 index 000000000..e8355751a --- /dev/null +++ b/src/input_common/drivers/mouse.h @@ -0,0 +1,77 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included + +#pragma once + +#include +#include + +#include "common/vector_math.h" +#include "input_common/input_engine.h" + +namespace InputCommon { + +enum class MouseButton { + Left, + Right, + Wheel, + Backward, + Forward, + Task, + Extra, + Undefined, +}; + +/** + * A button device factory representing a keyboard. It receives keyboard events and forward them + * to all button devices it created. + */ +class Mouse final : public InputCommon::InputEngine { +public: + explicit Mouse(const std::string input_engine_); + + /** + * Signals that mouse has moved. + * @param x the x-coordinate of the cursor + * @param y the y-coordinate of the cursor + * @param center_x the x-coordinate of the middle of the screen + * @param center_y the y-coordinate of the middle of the screen + */ + void MouseMove(int x, int y, f32 touch_x, f32 touch_y, int center_x, int center_y); + + /** + * Sets the status of all buttons bound with the key to pressed + * @param key_code the code of the key to press + */ + void PressButton(int x, int y, f32 touch_x, f32 touch_y, MouseButton button); + + /** + * Sets the status of all buttons bound with the key to released + * @param key_code the code of the key to release + */ + void ReleaseButton(MouseButton button); + + void ReleaseAllButtons(); + + std::vector GetInputDevices() const override; + std::string GetUIName(const Common::ParamPackage& params) const override; + +private: + void UpdateThread(std::stop_token stop_token); + void StopPanning(); + + const PadIdentifier identifier = { + .guid = Common::UUID{""}, + .port = 0, + .pad = 0, + }; + Common::Vec2 mouse_origin; + Common::Vec2 last_mouse_position; + Common::Vec2 last_mouse_change; + bool button_pressed; + int mouse_panning_timout{}; + std::jthread update_thread; +}; + +} // namespace InputCommon diff --git a/src/input_common/mouse/mouse_input.cpp b/src/input_common/mouse/mouse_input.cpp deleted file mode 100644 index 3b052ffb2..000000000 --- a/src/input_common/mouse/mouse_input.cpp +++ /dev/null @@ -1,223 +0,0 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2+ -// Refer to the license.txt file included. - -#include -#include - -#include "common/settings.h" -#include "input_common/mouse/mouse_input.h" - -namespace MouseInput { - -Mouse::Mouse() { - update_thread = std::jthread([this](std::stop_token stop_token) { UpdateThread(stop_token); }); -} - -Mouse::~Mouse() = default; - -void Mouse::UpdateThread(std::stop_token stop_token) { - constexpr int update_time = 10; - while (!stop_token.stop_requested()) { - for (MouseInfo& info : mouse_info) { - const Common::Vec3f angular_direction{ - -info.tilt_direction.y, - 0.0f, - -info.tilt_direction.x, - }; - - info.motion.SetGyroscope(angular_direction * info.tilt_speed); - info.motion.UpdateRotation(update_time * 1000); - info.motion.UpdateOrientation(update_time * 1000); - info.tilt_speed = 0; - info.data.motion = info.motion.GetMotion(); - if (Settings::values.mouse_panning) { - info.last_mouse_change *= 0.96f; - info.data.axis = {static_cast(16 * info.last_mouse_change.x), - static_cast(16 * -info.last_mouse_change.y)}; - } - } - if (configuring) { - UpdateYuzuSettings(); - } - if (mouse_panning_timout++ > 20) { - StopPanning(); - } - std::this_thread::sleep_for(std::chrono::milliseconds(update_time)); - } -} - -void Mouse::UpdateYuzuSettings() { - if (buttons == 0) { - return; - } - - mouse_queue.Push(MouseStatus{ - .button = last_button, - }); -} - -void Mouse::PressButton(int x, int y, MouseButton button_) { - const auto button_index = static_cast(button_); - if (button_index >= mouse_info.size()) { - return; - } - - const auto button = 1U << button_index; - buttons |= static_cast(button); - last_button = button_; - - mouse_info[button_index].mouse_origin = Common::MakeVec(x, y); - mouse_info[button_index].last_mouse_position = Common::MakeVec(x, y); - mouse_info[button_index].data.pressed = true; -} - -void Mouse::StopPanning() { - for (MouseInfo& info : mouse_info) { - if (Settings::values.mouse_panning) { - info.data.axis = {}; - info.tilt_speed = 0; - info.last_mouse_change = {}; - } - } -} - -void Mouse::MouseMove(int x, int y, int center_x, int center_y) { - for (MouseInfo& info : mouse_info) { - if (Settings::values.mouse_panning) { - auto mouse_change = - (Common::MakeVec(x, y) - Common::MakeVec(center_x, center_y)).Cast(); - mouse_panning_timout = 0; - - if (mouse_change.y == 0 && mouse_change.x == 0) { - continue; - } - const auto mouse_change_length = mouse_change.Length(); - if (mouse_change_length < 3.0f) { - mouse_change /= mouse_change_length / 3.0f; - } - - info.last_mouse_change = (info.last_mouse_change * 0.91f) + (mouse_change * 0.09f); - - const auto last_mouse_change_length = info.last_mouse_change.Length(); - if (last_mouse_change_length > 8.0f) { - info.last_mouse_change /= last_mouse_change_length / 8.0f; - } else if (last_mouse_change_length < 1.0f) { - info.last_mouse_change = mouse_change / mouse_change.Length(); - } - - info.tilt_direction = info.last_mouse_change; - info.tilt_speed = info.tilt_direction.Normalize() * info.sensitivity; - continue; - } - - if (info.data.pressed) { - const auto mouse_move = Common::MakeVec(x, y) - info.mouse_origin; - const auto mouse_change = Common::MakeVec(x, y) - info.last_mouse_position; - info.last_mouse_position = Common::MakeVec(x, y); - info.data.axis = {mouse_move.x, -mouse_move.y}; - - if (mouse_change.x == 0 && mouse_change.y == 0) { - info.tilt_speed = 0; - } else { - info.tilt_direction = mouse_change.Cast(); - info.tilt_speed = info.tilt_direction.Normalize() * info.sensitivity; - } - } - } -} - -void Mouse::ReleaseButton(MouseButton button_) { - const auto button_index = static_cast(button_); - if (button_index >= mouse_info.size()) { - return; - } - - const auto button = 1U << button_index; - buttons &= static_cast(0xFF - button); - - mouse_info[button_index].tilt_speed = 0; - mouse_info[button_index].data.pressed = false; - mouse_info[button_index].data.axis = {0, 0}; -} - -void Mouse::ReleaseAllButtons() { - buttons = 0; - for (auto& info : mouse_info) { - info.tilt_speed = 0; - info.data.pressed = false; - info.data.axis = {0, 0}; - } -} - -void Mouse::BeginConfiguration() { - buttons = 0; - last_button = MouseButton::Undefined; - mouse_queue.Clear(); - configuring = true; -} - -void Mouse::EndConfiguration() { - buttons = 0; - for (MouseInfo& info : mouse_info) { - info.tilt_speed = 0; - info.data.pressed = false; - info.data.axis = {0, 0}; - } - last_button = MouseButton::Undefined; - mouse_queue.Clear(); - configuring = false; -} - -bool Mouse::ToggleButton(std::size_t button_) { - if (button_ >= mouse_info.size()) { - return false; - } - const auto button = 1U << button_; - const bool button_state = (toggle_buttons & button) != 0; - const bool button_lock = (lock_buttons & button) != 0; - - if (button_lock) { - return button_state; - } - - lock_buttons |= static_cast(button); - - if (button_state) { - toggle_buttons &= static_cast(0xFF - button); - } else { - toggle_buttons |= static_cast(button); - } - - return !button_state; -} - -bool Mouse::UnlockButton(std::size_t button_) { - if (button_ >= mouse_info.size()) { - return false; - } - - const auto button = 1U << button_; - const bool button_state = (toggle_buttons & button) != 0; - - lock_buttons &= static_cast(0xFF - button); - - return button_state; -} - -Common::SPSCQueue& Mouse::GetMouseQueue() { - return mouse_queue; -} - -const Common::SPSCQueue& Mouse::GetMouseQueue() const { - return mouse_queue; -} - -MouseData& Mouse::GetMouseState(std::size_t button) { - return mouse_info[button].data; -} - -const MouseData& Mouse::GetMouseState(std::size_t button) const { - return mouse_info[button].data; -} -} // namespace MouseInput diff --git a/src/input_common/mouse/mouse_input.h b/src/input_common/mouse/mouse_input.h deleted file mode 100644 index c8bae99c1..000000000 --- a/src/input_common/mouse/mouse_input.h +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include -#include -#include -#include - -#include "common/common_types.h" -#include "common/threadsafe_queue.h" -#include "common/vector_math.h" -#include "core/frontend/input.h" -#include "input_common/motion_input.h" - -namespace MouseInput { - -enum class MouseButton { - Left, - Right, - Wheel, - Backward, - Forward, - Task, - Extra, - Undefined, -}; - -struct MouseStatus { - MouseButton button{MouseButton::Undefined}; -}; - -struct MouseData { - bool pressed{}; - std::array axis{}; - Input::MotionStatus motion{}; - Input::TouchStatus touch{}; -}; - -class Mouse { -public: - Mouse(); - ~Mouse(); - - /// Used for polling - void BeginConfiguration(); - void EndConfiguration(); - - /** - * Signals that a button is pressed. - * @param x the x-coordinate of the cursor - * @param y the y-coordinate of the cursor - * @param button_ the button pressed - */ - void PressButton(int x, int y, MouseButton button_); - - /** - * Signals that mouse has moved. - * @param x the x-coordinate of the cursor - * @param y the y-coordinate of the cursor - * @param center_x the x-coordinate of the middle of the screen - * @param center_y the y-coordinate of the middle of the screen - */ - void MouseMove(int x, int y, int center_x, int center_y); - - /** - * Signals that a button is released. - * @param button_ the button pressed - */ - void ReleaseButton(MouseButton button_); - - /** - * Signals that all buttons are released - */ - void ReleaseAllButtons(); - - [[nodiscard]] bool ToggleButton(std::size_t button_); - [[nodiscard]] bool UnlockButton(std::size_t button_); - - [[nodiscard]] Common::SPSCQueue& GetMouseQueue(); - [[nodiscard]] const Common::SPSCQueue& GetMouseQueue() const; - - [[nodiscard]] MouseData& GetMouseState(std::size_t button); - [[nodiscard]] const MouseData& GetMouseState(std::size_t button) const; - -private: - void UpdateThread(std::stop_token stop_token); - void UpdateYuzuSettings(); - void StopPanning(); - - struct MouseInfo { - InputCommon::MotionInput motion{0.0f, 0.0f, 0.0f}; - Common::Vec2 mouse_origin; - Common::Vec2 last_mouse_position; - Common::Vec2 last_mouse_change; - bool is_tilting = false; - float sensitivity{0.120f}; - - float tilt_speed = 0; - Common::Vec2 tilt_direction; - MouseData data; - }; - - u16 buttons{}; - u16 toggle_buttons{}; - u16 lock_buttons{}; - std::jthread update_thread; - MouseButton last_button{MouseButton::Undefined}; - std::array mouse_info; - Common::SPSCQueue mouse_queue; - bool configuring{false}; - int mouse_panning_timout{}; -}; -} // namespace MouseInput diff --git a/src/input_common/mouse/mouse_poller.cpp b/src/input_common/mouse/mouse_poller.cpp deleted file mode 100644 index 090b26972..000000000 --- a/src/input_common/mouse/mouse_poller.cpp +++ /dev/null @@ -1,299 +0,0 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include -#include -#include -#include - -#include "common/settings.h" -#include "common/threadsafe_queue.h" -#include "input_common/mouse/mouse_input.h" -#include "input_common/mouse/mouse_poller.h" - -namespace InputCommon { - -class MouseButton final : public Input::ButtonDevice { -public: - explicit MouseButton(u32 button_, bool toggle_, MouseInput::Mouse* mouse_input_) - : button(button_), toggle(toggle_), mouse_input(mouse_input_) {} - - bool GetStatus() const override { - const bool button_state = mouse_input->GetMouseState(button).pressed; - if (!toggle) { - return button_state; - } - - if (button_state) { - return mouse_input->ToggleButton(button); - } - return mouse_input->UnlockButton(button); - } - -private: - const u32 button; - const bool toggle; - MouseInput::Mouse* mouse_input; -}; - -MouseButtonFactory::MouseButtonFactory(std::shared_ptr mouse_input_) - : mouse_input(std::move(mouse_input_)) {} - -std::unique_ptr MouseButtonFactory::Create( - const Common::ParamPackage& params) { - const auto button_id = params.Get("button", 0); - const auto toggle = params.Get("toggle", false); - - return std::make_unique(button_id, toggle, mouse_input.get()); -} - -Common::ParamPackage MouseButtonFactory::GetNextInput() const { - MouseInput::MouseStatus pad; - Common::ParamPackage params; - auto& queue = mouse_input->GetMouseQueue(); - while (queue.Pop(pad)) { - // This while loop will break on the earliest detected button - if (pad.button != MouseInput::MouseButton::Undefined) { - params.Set("engine", "mouse"); - params.Set("button", static_cast(pad.button)); - params.Set("toggle", false); - return params; - } - } - return params; -} - -void MouseButtonFactory::BeginConfiguration() { - polling = true; - mouse_input->BeginConfiguration(); -} - -void MouseButtonFactory::EndConfiguration() { - polling = false; - mouse_input->EndConfiguration(); -} - -class MouseAnalog final : public Input::AnalogDevice { -public: - explicit MouseAnalog(u32 port_, u32 axis_x_, u32 axis_y_, bool invert_x_, bool invert_y_, - float deadzone_, float range_, const MouseInput::Mouse* mouse_input_) - : button(port_), axis_x(axis_x_), axis_y(axis_y_), invert_x(invert_x_), invert_y(invert_y_), - deadzone(deadzone_), range(range_), mouse_input(mouse_input_) {} - - float GetAxis(u32 axis) const { - std::lock_guard lock{mutex}; - const auto axis_value = - static_cast(mouse_input->GetMouseState(button).axis.at(axis)); - const float sensitivity = Settings::values.mouse_panning_sensitivity.GetValue() * 0.10f; - return axis_value * sensitivity / (100.0f * range); - } - - std::pair GetAnalog(u32 analog_axis_x, u32 analog_axis_y) const { - float x = GetAxis(analog_axis_x); - float y = GetAxis(analog_axis_y); - if (invert_x) { - x = -x; - } - if (invert_y) { - y = -y; - } - - // Make sure the coordinates are in the unit circle, - // otherwise normalize it. - float r = x * x + y * y; - if (r > 1.0f) { - r = std::sqrt(r); - x /= r; - y /= r; - } - - return {x, y}; - } - - std::tuple GetStatus() const override { - const auto [x, y] = GetAnalog(axis_x, axis_y); - const float r = std::sqrt((x * x) + (y * y)); - if (r > deadzone) { - return {x / r * (r - deadzone) / (1 - deadzone), - y / r * (r - deadzone) / (1 - deadzone)}; - } - return {0.0f, 0.0f}; - } - - std::tuple GetRawStatus() const override { - const float x = GetAxis(axis_x); - const float y = GetAxis(axis_y); - return {x, y}; - } - - Input::AnalogProperties GetAnalogProperties() const override { - return {deadzone, range, 0.5f}; - } - -private: - const u32 button; - const u32 axis_x; - const u32 axis_y; - const bool invert_x; - const bool invert_y; - const float deadzone; - const float range; - const MouseInput::Mouse* mouse_input; - mutable std::mutex mutex; -}; - -/// An analog device factory that creates analog devices from GC Adapter -MouseAnalogFactory::MouseAnalogFactory(std::shared_ptr mouse_input_) - : mouse_input(std::move(mouse_input_)) {} - -/** - * Creates analog device from joystick axes - * @param params contains parameters for creating the device: - * - "port": the nth gcpad on the adapter - * - "axis_x": the index of the axis to be bind as x-axis - * - "axis_y": the index of the axis to be bind as y-axis - */ -std::unique_ptr MouseAnalogFactory::Create( - const Common::ParamPackage& params) { - const auto port = static_cast(params.Get("port", 0)); - const auto axis_x = static_cast(params.Get("axis_x", 0)); - const auto axis_y = static_cast(params.Get("axis_y", 1)); - const auto deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, 1.0f); - const auto range = std::clamp(params.Get("range", 1.0f), 0.50f, 1.50f); - const std::string invert_x_value = params.Get("invert_x", "+"); - const std::string invert_y_value = params.Get("invert_y", "+"); - const bool invert_x = invert_x_value == "-"; - const bool invert_y = invert_y_value == "-"; - - return std::make_unique(port, axis_x, axis_y, invert_x, invert_y, deadzone, range, - mouse_input.get()); -} - -void MouseAnalogFactory::BeginConfiguration() { - polling = true; - mouse_input->BeginConfiguration(); -} - -void MouseAnalogFactory::EndConfiguration() { - polling = false; - mouse_input->EndConfiguration(); -} - -Common::ParamPackage MouseAnalogFactory::GetNextInput() const { - MouseInput::MouseStatus pad; - Common::ParamPackage params; - auto& queue = mouse_input->GetMouseQueue(); - while (queue.Pop(pad)) { - // This while loop will break on the earliest detected button - if (pad.button != MouseInput::MouseButton::Undefined) { - params.Set("engine", "mouse"); - params.Set("port", static_cast(pad.button)); - params.Set("axis_x", 0); - params.Set("axis_y", 1); - params.Set("invert_x", "+"); - params.Set("invert_y", "+"); - return params; - } - } - return params; -} - -class MouseMotion final : public Input::MotionDevice { -public: - explicit MouseMotion(u32 button_, const MouseInput::Mouse* mouse_input_) - : button(button_), mouse_input(mouse_input_) {} - - Input::MotionStatus GetStatus() const override { - return mouse_input->GetMouseState(button).motion; - } - -private: - const u32 button; - const MouseInput::Mouse* mouse_input; -}; - -MouseMotionFactory::MouseMotionFactory(std::shared_ptr mouse_input_) - : mouse_input(std::move(mouse_input_)) {} - -std::unique_ptr MouseMotionFactory::Create( - const Common::ParamPackage& params) { - const auto button_id = params.Get("button", 0); - - return std::make_unique(button_id, mouse_input.get()); -} - -Common::ParamPackage MouseMotionFactory::GetNextInput() const { - MouseInput::MouseStatus pad; - Common::ParamPackage params; - auto& queue = mouse_input->GetMouseQueue(); - while (queue.Pop(pad)) { - // This while loop will break on the earliest detected button - if (pad.button != MouseInput::MouseButton::Undefined) { - params.Set("engine", "mouse"); - params.Set("button", static_cast(pad.button)); - return params; - } - } - return params; -} - -void MouseMotionFactory::BeginConfiguration() { - polling = true; - mouse_input->BeginConfiguration(); -} - -void MouseMotionFactory::EndConfiguration() { - polling = false; - mouse_input->EndConfiguration(); -} - -class MouseTouch final : public Input::TouchDevice { -public: - explicit MouseTouch(u32 button_, const MouseInput::Mouse* mouse_input_) - : button(button_), mouse_input(mouse_input_) {} - - Input::TouchStatus GetStatus() const override { - return mouse_input->GetMouseState(button).touch; - } - -private: - const u32 button; - const MouseInput::Mouse* mouse_input; -}; - -MouseTouchFactory::MouseTouchFactory(std::shared_ptr mouse_input_) - : mouse_input(std::move(mouse_input_)) {} - -std::unique_ptr MouseTouchFactory::Create(const Common::ParamPackage& params) { - const auto button_id = params.Get("button", 0); - - return std::make_unique(button_id, mouse_input.get()); -} - -Common::ParamPackage MouseTouchFactory::GetNextInput() const { - MouseInput::MouseStatus pad; - Common::ParamPackage params; - auto& queue = mouse_input->GetMouseQueue(); - while (queue.Pop(pad)) { - // This while loop will break on the earliest detected button - if (pad.button != MouseInput::MouseButton::Undefined) { - params.Set("engine", "mouse"); - params.Set("button", static_cast(pad.button)); - return params; - } - } - return params; -} - -void MouseTouchFactory::BeginConfiguration() { - polling = true; - mouse_input->BeginConfiguration(); -} - -void MouseTouchFactory::EndConfiguration() { - polling = false; - mouse_input->EndConfiguration(); -} - -} // namespace InputCommon diff --git a/src/input_common/mouse/mouse_poller.h b/src/input_common/mouse/mouse_poller.h deleted file mode 100644 index cf331293b..000000000 --- a/src/input_common/mouse/mouse_poller.h +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include -#include "core/frontend/input.h" -#include "input_common/mouse/mouse_input.h" - -namespace InputCommon { - -/** - * A button device factory representing a mouse. It receives mouse events and forward them - * to all button devices it created. - */ -class MouseButtonFactory final : public Input::Factory { -public: - explicit MouseButtonFactory(std::shared_ptr mouse_input_); - - /** - * Creates a button device from a button press - * @param params contains parameters for creating the device: - * - "code": the code of the key to bind with the button - */ - std::unique_ptr Create(const Common::ParamPackage& params) override; - - Common::ParamPackage GetNextInput() const; - - /// For device input configuration/polling - void BeginConfiguration(); - void EndConfiguration(); - - bool IsPolling() const { - return polling; - } - -private: - std::shared_ptr mouse_input; - bool polling = false; -}; - -/// An analog device factory that creates analog devices from mouse -class MouseAnalogFactory final : public Input::Factory { -public: - explicit MouseAnalogFactory(std::shared_ptr mouse_input_); - - std::unique_ptr Create(const Common::ParamPackage& params) override; - - Common::ParamPackage GetNextInput() const; - - /// For device input configuration/polling - void BeginConfiguration(); - void EndConfiguration(); - - bool IsPolling() const { - return polling; - } - -private: - std::shared_ptr mouse_input; - bool polling = false; -}; - -/// A motion device factory that creates motion devices from mouse -class MouseMotionFactory final : public Input::Factory { -public: - explicit MouseMotionFactory(std::shared_ptr mouse_input_); - - std::unique_ptr Create(const Common::ParamPackage& params) override; - - Common::ParamPackage GetNextInput() const; - - /// For device input configuration/polling - void BeginConfiguration(); - void EndConfiguration(); - - bool IsPolling() const { - return polling; - } - -private: - std::shared_ptr mouse_input; - bool polling = false; -}; - -/// An touch device factory that creates touch devices from mouse -class MouseTouchFactory final : public Input::Factory { -public: - explicit MouseTouchFactory(std::shared_ptr mouse_input_); - - std::unique_ptr Create(const Common::ParamPackage& params) override; - - Common::ParamPackage GetNextInput() const; - - /// For device input configuration/polling - void BeginConfiguration(); - void EndConfiguration(); - - bool IsPolling() const { - return polling; - } - -private: - std::shared_ptr mouse_input; - bool polling = false; -}; - -} // namespace InputCommon -- cgit v1.2.3 From fa8e23b84281022bf6b4e8916231a17e9997e5aa Mon Sep 17 00:00:00 2001 From: german77 Date: Mon, 20 Sep 2021 17:20:56 -0500 Subject: input_common: Rewrite touch --- src/input_common/CMakeLists.txt | 2 ++ src/input_common/drivers/touch_screen.cpp | 47 +++++++++++++++++++++++++++++ src/input_common/drivers/touch_screen.h | 50 +++++++++++++++++++++++++++++++ 3 files changed, 99 insertions(+) create mode 100644 src/input_common/drivers/touch_screen.cpp create mode 100644 src/input_common/drivers/touch_screen.h (limited to 'src/input_common/drivers') diff --git a/src/input_common/CMakeLists.txt b/src/input_common/CMakeLists.txt index 34b41ce01..71091767d 100644 --- a/src/input_common/CMakeLists.txt +++ b/src/input_common/CMakeLists.txt @@ -3,6 +3,8 @@ add_library(input_common STATIC drivers/keyboard.h drivers/mouse.cpp drivers/mouse.h + drivers/touch_screen.cpp + drivers/touch_screen.h helpers/stick_from_buttons.cpp helpers/stick_from_buttons.h helpers/touch_from_buttons.cpp diff --git a/src/input_common/drivers/touch_screen.cpp b/src/input_common/drivers/touch_screen.cpp new file mode 100644 index 000000000..e13835e9f --- /dev/null +++ b/src/input_common/drivers/touch_screen.cpp @@ -0,0 +1,47 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included + +#include "common/param_package.h" +#include "input_common/drivers/touch_screen.h" + +namespace InputCommon { + +TouchScreen::TouchScreen(const std::string input_engine_) : InputEngine(input_engine_) { + PreSetController(identifier); +} + +void TouchScreen::TouchMoved(float x, float y, std::size_t finger) { + if (finger >= 16) { + return; + } + TouchPressed(x, y, finger); +} + +void TouchScreen::TouchPressed(float x, float y, std::size_t finger) { + if (finger >= 16) { + return; + } + SetButton(identifier, static_cast(finger), true); + SetAxis(identifier, static_cast(finger * 2), x); + SetAxis(identifier, static_cast(finger * 2 + 1), y); +} + +void TouchScreen::TouchReleased(std::size_t finger) { + if (finger >= 16) { + return; + } + SetButton(identifier, static_cast(finger), false); + SetAxis(identifier, static_cast(finger * 2), 0.0f); + SetAxis(identifier, static_cast(finger * 2 + 1), 0.0f); +} + +void TouchScreen::ReleaseAllTouch() { + for (int index = 0; index < 16; ++index) { + SetButton(identifier, index, false); + SetAxis(identifier, index * 2, 0.0f); + SetAxis(identifier, index * 2 + 1, 0.0f); + } +} + +} // namespace InputCommon diff --git a/src/input_common/drivers/touch_screen.h b/src/input_common/drivers/touch_screen.h new file mode 100644 index 000000000..5fbb2f47f --- /dev/null +++ b/src/input_common/drivers/touch_screen.h @@ -0,0 +1,50 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included + +#pragma once + +#include "input_common/input_engine.h" + +namespace InputCommon { + +/** + * A button device factory representing a keyboard. It receives keyboard events and forward them + * to all button devices it created. + */ +class TouchScreen final : public InputCommon::InputEngine { +public: + explicit TouchScreen(const std::string input_engine_); + + /** + * Signals that mouse has moved. + * @param x the x-coordinate of the cursor + * @param y the y-coordinate of the cursor + * @param center_x the x-coordinate of the middle of the screen + * @param center_y the y-coordinate of the middle of the screen + */ + void TouchMoved(float x, float y, std::size_t finger); + + /** + * Sets the status of all buttons bound with the key to pressed + * @param key_code the code of the key to press + */ + void TouchPressed(float x, float y, std::size_t finger); + + /** + * Sets the status of all buttons bound with the key to released + * @param key_code the code of the key to release + */ + void TouchReleased(std::size_t finger); + + void ReleaseAllTouch(); + +private: + const PadIdentifier identifier = { + .guid = Common::UUID{""}, + .port = 0, + .pad = 0, + }; +}; + +} // namespace InputCommon -- cgit v1.2.3 From 395e9a449d338e56ade9ea88ffeed297a7d86b10 Mon Sep 17 00:00:00 2001 From: german77 Date: Mon, 20 Sep 2021 17:22:07 -0500 Subject: input_common: Rewrite gc_adapter --- src/input_common/CMakeLists.txt | 6 +- src/input_common/drivers/gc_adapter.cpp | 483 ++++++++++++++++++++++++++++ src/input_common/drivers/gc_adapter.h | 128 ++++++++ src/input_common/drivers/tas_input.cpp | 320 +++++++++++++++++++ src/input_common/drivers/tas_input.h | 200 ++++++++++++ src/input_common/gcadapter/gc_adapter.cpp | 506 ------------------------------ src/input_common/gcadapter/gc_adapter.h | 168 ---------- src/input_common/gcadapter/gc_poller.cpp | 356 --------------------- src/input_common/gcadapter/gc_poller.h | 78 ----- 9 files changed, 1133 insertions(+), 1112 deletions(-) create mode 100644 src/input_common/drivers/gc_adapter.cpp create mode 100644 src/input_common/drivers/gc_adapter.h create mode 100644 src/input_common/drivers/tas_input.cpp create mode 100644 src/input_common/drivers/tas_input.h delete mode 100644 src/input_common/gcadapter/gc_adapter.cpp delete mode 100644 src/input_common/gcadapter/gc_adapter.h delete mode 100644 src/input_common/gcadapter/gc_poller.cpp delete mode 100644 src/input_common/gcadapter/gc_poller.h (limited to 'src/input_common/drivers') diff --git a/src/input_common/CMakeLists.txt b/src/input_common/CMakeLists.txt index 71091767d..c8871513c 100644 --- a/src/input_common/CMakeLists.txt +++ b/src/input_common/CMakeLists.txt @@ -1,4 +1,6 @@ add_library(input_common STATIC + drivers/gc_adapter.cpp + drivers/gc_adapter.h drivers/keyboard.cpp drivers/keyboard.h drivers/mouse.cpp @@ -23,10 +25,6 @@ add_library(input_common STATIC motion_from_button.h motion_input.cpp motion_input.h - gcadapter/gc_adapter.cpp - gcadapter/gc_adapter.h - gcadapter/gc_poller.cpp - gcadapter/gc_poller.h sdl/sdl.cpp sdl/sdl.h tas/tas_input.cpp diff --git a/src/input_common/drivers/gc_adapter.cpp b/src/input_common/drivers/gc_adapter.cpp new file mode 100644 index 000000000..6721ba4f7 --- /dev/null +++ b/src/input_common/drivers/gc_adapter.cpp @@ -0,0 +1,483 @@ +// Copyright 2014 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include +#include + +#include "common/logging/log.h" +#include "common/param_package.h" +#include "common/settings_input.h" +#include "common/thread.h" +#include "input_common/drivers/gc_adapter.h" + +namespace InputCommon { + +class LibUSBContext { +public: + explicit LibUSBContext() { + init_result = libusb_init(&ctx); + } + + ~LibUSBContext() { + libusb_exit(ctx); + } + + LibUSBContext& operator=(const LibUSBContext&) = delete; + LibUSBContext(const LibUSBContext&) = delete; + + LibUSBContext& operator=(LibUSBContext&&) noexcept = delete; + LibUSBContext(LibUSBContext&&) noexcept = delete; + + [[nodiscard]] int InitResult() const noexcept { + return init_result; + } + + [[nodiscard]] libusb_context* get() noexcept { + return ctx; + } + +private: + libusb_context* ctx; + int init_result{}; +}; + +class LibUSBDeviceHandle { +public: + explicit LibUSBDeviceHandle(libusb_context* ctx, uint16_t vid, uint16_t pid) noexcept { + handle = libusb_open_device_with_vid_pid(ctx, vid, pid); + } + + ~LibUSBDeviceHandle() noexcept { + if (handle) { + libusb_release_interface(handle, 1); + libusb_close(handle); + } + } + + LibUSBDeviceHandle& operator=(const LibUSBDeviceHandle&) = delete; + LibUSBDeviceHandle(const LibUSBDeviceHandle&) = delete; + + LibUSBDeviceHandle& operator=(LibUSBDeviceHandle&&) noexcept = delete; + LibUSBDeviceHandle(LibUSBDeviceHandle&&) noexcept = delete; + + [[nodiscard]] libusb_device_handle* get() noexcept { + return handle; + } + +private: + libusb_device_handle* handle{}; +}; + +GCAdapter::GCAdapter(const std::string input_engine_) : InputEngine(input_engine_) { + if (usb_adapter_handle) { + return; + } + LOG_INFO(Input, "GC Adapter Initialization started"); + + libusb_ctx = std::make_unique(); + const int init_res = libusb_ctx->InitResult(); + if (init_res == LIBUSB_SUCCESS) { + adapter_scan_thread = + std::jthread([this](std::stop_token stop_token) { AdapterScanThread(stop_token); }); + } else { + LOG_ERROR(Input, "libusb could not be initialized. failed with error = {}", init_res); + } +} + +GCAdapter::~GCAdapter() { + Reset(); +} + +void GCAdapter::AdapterInputThread(std::stop_token stop_token) { + LOG_DEBUG(Input, "GC Adapter input thread started"); + Common::SetCurrentThreadName("yuzu:input:GCAdapter"); + s32 payload_size{}; + AdapterPayload adapter_payload{}; + + adapter_scan_thread = {}; + + while (!stop_token.stop_requested()) { + libusb_interrupt_transfer(usb_adapter_handle->get(), input_endpoint, adapter_payload.data(), + static_cast(adapter_payload.size()), &payload_size, 16); + if (IsPayloadCorrect(adapter_payload, payload_size)) { + UpdateControllers(adapter_payload); + UpdateVibrations(); + } + std::this_thread::yield(); + } + + if (restart_scan_thread) { + adapter_scan_thread = + std::jthread([this](std::stop_token token) { AdapterScanThread(token); }); + restart_scan_thread = false; + } +} + +bool GCAdapter::IsPayloadCorrect(const AdapterPayload& adapter_payload, s32 payload_size) { + if (payload_size != static_cast(adapter_payload.size()) || + adapter_payload[0] != LIBUSB_DT_HID) { + LOG_DEBUG(Input, "Error reading payload (size: {}, type: {:02x})", payload_size, + adapter_payload[0]); + if (input_error_counter++ > 20) { + LOG_ERROR(Input, "GC adapter timeout, Is the adapter connected?"); + adapter_input_thread.request_stop(); + restart_scan_thread = true; + } + return false; + } + + input_error_counter = 0; + return true; +} + +void GCAdapter::UpdateControllers(const AdapterPayload& adapter_payload) { + for (std::size_t port = 0; port < pads.size(); ++port) { + const std::size_t offset = 1 + (9 * port); + const auto type = static_cast(adapter_payload[offset] >> 4); + UpdatePadType(port, type); + if (DeviceConnected(port)) { + const u8 b1 = adapter_payload[offset + 1]; + const u8 b2 = adapter_payload[offset + 2]; + UpdateStateButtons(port, b1, b2); + UpdateStateAxes(port, adapter_payload); + } + } +} + +void GCAdapter::UpdatePadType(std::size_t port, ControllerTypes pad_type) { + if (pads[port].type == pad_type) { + return; + } + // Device changed reset device and set new type + pads[port] = {}; + pads[port].type = pad_type; +} + +void GCAdapter::UpdateStateButtons(std::size_t port, [[maybe_unused]] u8 b1, + [[maybe_unused]] u8 b2) { + if (port >= pads.size()) { + return; + } + + static constexpr std::array b1_buttons{ + PadButton::ButtonA, PadButton::ButtonB, PadButton::ButtonX, PadButton::ButtonY, + PadButton::ButtonLeft, PadButton::ButtonRight, PadButton::ButtonDown, PadButton::ButtonUp, + }; + + static constexpr std::array b2_buttons{ + PadButton::ButtonStart, + PadButton::TriggerZ, + PadButton::TriggerR, + PadButton::TriggerL, + }; + + for (std::size_t i = 0; i < b1_buttons.size(); ++i) { + const bool button_status = (b1 & (1U << i)) != 0; + const int button = static_cast(b1_buttons[i]); + SetButton(pads[port].identifier, button, button_status); + } + + for (std::size_t j = 0; j < b2_buttons.size(); ++j) { + const bool button_status = (b2 & (1U << j)) != 0; + const int button = static_cast(b2_buttons[j]); + SetButton(pads[port].identifier, button, button_status); + } +} + +void GCAdapter::UpdateStateAxes(std::size_t port, const AdapterPayload& adapter_payload) { + if (port >= pads.size()) { + return; + } + + const std::size_t offset = 1 + (9 * port); + static constexpr std::array axes{ + PadAxes::StickX, PadAxes::StickY, PadAxes::SubstickX, + PadAxes::SubstickY, PadAxes::TriggerLeft, PadAxes::TriggerRight, + }; + + for (const PadAxes axis : axes) { + const auto index = static_cast(axis); + const u8 axis_value = adapter_payload[offset + 3 + index]; + if (pads[port].reset_origin_counter <= 18) { + if (pads[port].axis_origin[index] != axis_value) { + pads[port].reset_origin_counter = 0; + } + pads[port].axis_origin[index] = axis_value; + pads[port].reset_origin_counter++; + } + const f32 axis_status = (axis_value - pads[port].axis_origin[index]) / 110.0f; + SetAxis(pads[port].identifier, static_cast(index), axis_status); + } +} + +void GCAdapter::AdapterScanThread(std::stop_token stop_token) { + Common::SetCurrentThreadName("yuzu:input:ScanGCAdapter"); + usb_adapter_handle = nullptr; + pads = {}; + while (!stop_token.stop_requested() && !Setup()) { + std::this_thread::sleep_for(std::chrono::seconds(2)); + } +} + +bool GCAdapter::Setup() { + constexpr u16 nintendo_vid = 0x057e; + constexpr u16 gc_adapter_pid = 0x0337; + usb_adapter_handle = + std::make_unique(libusb_ctx->get(), nintendo_vid, gc_adapter_pid); + if (!usb_adapter_handle->get()) { + return false; + } + if (!CheckDeviceAccess()) { + usb_adapter_handle = nullptr; + return false; + } + + libusb_device* const device = libusb_get_device(usb_adapter_handle->get()); + + LOG_INFO(Input, "GC adapter is now connected"); + // GC Adapter found and accessible, registering it + if (GetGCEndpoint(device)) { + rumble_enabled = true; + input_error_counter = 0; + output_error_counter = 0; + + std::size_t port = 0; + for (GCController& pad : pads) { + pad.identifier = { + .guid = Common::UUID{""}, + .port = port++, + .pad = 0, + }; + PreSetController(pad.identifier); + } + + adapter_input_thread = + std::jthread([this](std::stop_token stop_token) { AdapterInputThread(stop_token); }); + return true; + } + return false; +} + +bool GCAdapter::CheckDeviceAccess() { + // This fixes payload problems from offbrand GCAdapters + const s32 control_transfer_error = + libusb_control_transfer(usb_adapter_handle->get(), 0x21, 11, 0x0001, 0, nullptr, 0, 1000); + if (control_transfer_error < 0) { + LOG_ERROR(Input, "libusb_control_transfer failed with error= {}", control_transfer_error); + } + + s32 kernel_driver_error = libusb_kernel_driver_active(usb_adapter_handle->get(), 0); + if (kernel_driver_error == 1) { + kernel_driver_error = libusb_detach_kernel_driver(usb_adapter_handle->get(), 0); + if (kernel_driver_error != 0 && kernel_driver_error != LIBUSB_ERROR_NOT_SUPPORTED) { + LOG_ERROR(Input, "libusb_detach_kernel_driver failed with error = {}", + kernel_driver_error); + } + } + + if (kernel_driver_error && kernel_driver_error != LIBUSB_ERROR_NOT_SUPPORTED) { + usb_adapter_handle = nullptr; + return false; + } + + const int interface_claim_error = libusb_claim_interface(usb_adapter_handle->get(), 0); + if (interface_claim_error) { + LOG_ERROR(Input, "libusb_claim_interface failed with error = {}", interface_claim_error); + usb_adapter_handle = nullptr; + return false; + } + + return true; +} + +bool GCAdapter::GetGCEndpoint(libusb_device* device) { + libusb_config_descriptor* config = nullptr; + const int config_descriptor_return = libusb_get_config_descriptor(device, 0, &config); + if (config_descriptor_return != LIBUSB_SUCCESS) { + LOG_ERROR(Input, "libusb_get_config_descriptor failed with error = {}", + config_descriptor_return); + return false; + } + + for (u8 ic = 0; ic < config->bNumInterfaces; ic++) { + const libusb_interface* interfaceContainer = &config->interface[ic]; + for (int i = 0; i < interfaceContainer->num_altsetting; i++) { + const libusb_interface_descriptor* interface = &interfaceContainer->altsetting[i]; + for (u8 e = 0; e < interface->bNumEndpoints; e++) { + const libusb_endpoint_descriptor* endpoint = &interface->endpoint[e]; + if ((endpoint->bEndpointAddress & LIBUSB_ENDPOINT_IN) != 0) { + input_endpoint = endpoint->bEndpointAddress; + } else { + output_endpoint = endpoint->bEndpointAddress; + } + } + } + } + // This transfer seems to be responsible for clearing the state of the adapter + // Used to clear the "busy" state of when the device is unexpectedly unplugged + unsigned char clear_payload = 0x13; + libusb_interrupt_transfer(usb_adapter_handle->get(), output_endpoint, &clear_payload, + sizeof(clear_payload), nullptr, 16); + return true; +} + +bool GCAdapter::SetRumble(const PadIdentifier& identifier, const Input::VibrationStatus vibration) { + const auto mean_amplitude = (vibration.low_amplitude + vibration.high_amplitude) * 0.5f; + const auto processed_amplitude = + static_cast((mean_amplitude + std::pow(mean_amplitude, 0.3f)) * 0.5f * 0x8); + + pads[identifier.port].rumble_amplitude = processed_amplitude; + return rumble_enabled; +} + +void GCAdapter::UpdateVibrations() { + // Use 8 states to keep the switching between on/off fast enough for + // a human to feel different vibration strenght + // More states == more rumble strengths == slower update time + constexpr u8 vibration_states = 8; + + vibration_counter = (vibration_counter + 1) % vibration_states; + + for (GCController& pad : pads) { + const bool vibrate = pad.rumble_amplitude > vibration_counter; + vibration_changed |= vibrate != pad.enable_vibration; + pad.enable_vibration = vibrate; + } + SendVibrations(); +} + +void GCAdapter::SendVibrations() { + if (!rumble_enabled || !vibration_changed) { + return; + } + s32 size{}; + constexpr u8 rumble_command = 0x11; + const u8 p1 = pads[0].enable_vibration; + const u8 p2 = pads[1].enable_vibration; + const u8 p3 = pads[2].enable_vibration; + const u8 p4 = pads[3].enable_vibration; + std::array payload = {rumble_command, p1, p2, p3, p4}; + const int err = + libusb_interrupt_transfer(usb_adapter_handle->get(), output_endpoint, payload.data(), + static_cast(payload.size()), &size, 16); + if (err) { + LOG_DEBUG(Input, "Adapter libusb write failed: {}", libusb_error_name(err)); + if (output_error_counter++ > 5) { + LOG_ERROR(Input, "GC adapter output timeout, Rumble disabled"); + rumble_enabled = false; + } + return; + } + output_error_counter = 0; + vibration_changed = false; +} + +bool GCAdapter::DeviceConnected(std::size_t port) const { + return pads[port].type != ControllerTypes::None; +} + +void GCAdapter::Reset() { + adapter_scan_thread = {}; + adapter_input_thread = {}; + usb_adapter_handle = nullptr; + pads = {}; + libusb_ctx = nullptr; +} + +std::vector GCAdapter::GetInputDevices() const { + std::vector devices; + for (std::size_t port = 0; port < pads.size(); ++port) { + if (!DeviceConnected(port)) { + continue; + } + const std::string name = fmt::format("Gamecube Controller {}", port + 1); + devices.emplace_back(Common::ParamPackage{ + {"engine", "gcpad"}, + {"display", std::move(name)}, + {"port", std::to_string(port)}, + }); + } + return devices; +} + +ButtonMapping GCAdapter::GetButtonMappingForDevice(const Common::ParamPackage& params) { + // This list is missing ZL/ZR since those are not considered buttons. + // We will add those afterwards + // This list also excludes any button that can't be really mapped + static constexpr std::array, 12> + switch_to_gcadapter_button = { + std::pair{Settings::NativeButton::A, PadButton::ButtonA}, + {Settings::NativeButton::B, PadButton::ButtonB}, + {Settings::NativeButton::X, PadButton::ButtonX}, + {Settings::NativeButton::Y, PadButton::ButtonY}, + {Settings::NativeButton::Plus, PadButton::ButtonStart}, + {Settings::NativeButton::DLeft, PadButton::ButtonLeft}, + {Settings::NativeButton::DUp, PadButton::ButtonUp}, + {Settings::NativeButton::DRight, PadButton::ButtonRight}, + {Settings::NativeButton::DDown, PadButton::ButtonDown}, + {Settings::NativeButton::SL, PadButton::TriggerL}, + {Settings::NativeButton::SR, PadButton::TriggerR}, + {Settings::NativeButton::R, PadButton::TriggerZ}, + }; + if (!params.Has("port")) { + return {}; + } + + ButtonMapping mapping{}; + for (const auto& [switch_button, gcadapter_button] : switch_to_gcadapter_button) { + Common::ParamPackage button_params({{"engine", "gcpad"}}); + button_params.Set("port", params.Get("port", 0)); + button_params.Set("button", static_cast(gcadapter_button)); + mapping.insert_or_assign(switch_button, std::move(button_params)); + } + + // Add the missing bindings for ZL/ZR + static constexpr std::array, 2> + switch_to_gcadapter_axis = { + std::tuple{Settings::NativeButton::ZL, PadButton::TriggerL, PadAxes::TriggerLeft}, + {Settings::NativeButton::ZR, PadButton::TriggerR, PadAxes::TriggerRight}, + }; + for (const auto& [switch_button, gcadapter_buton, gcadapter_axis] : switch_to_gcadapter_axis) { + Common::ParamPackage button_params({{"engine", "gcpad"}}); + button_params.Set("port", params.Get("port", 0)); + button_params.Set("button", static_cast(gcadapter_buton)); + button_params.Set("axis", static_cast(gcadapter_axis)); + button_params.Set("threshold", 0.5f); + button_params.Set("range", 1.9f); + button_params.Set("direction", "+"); + mapping.insert_or_assign(switch_button, std::move(button_params)); + } + return mapping; +} + +AnalogMapping GCAdapter::GetAnalogMappingForDevice(const Common::ParamPackage& params) { + if (!params.Has("port")) { + return {}; + } + + AnalogMapping mapping = {}; + Common::ParamPackage left_analog_params; + left_analog_params.Set("engine", "gcpad"); + left_analog_params.Set("port", params.Get("port", 0)); + left_analog_params.Set("axis_x", static_cast(PadAxes::StickX)); + left_analog_params.Set("axis_y", static_cast(PadAxes::StickY)); + mapping.insert_or_assign(Settings::NativeAnalog::LStick, std::move(left_analog_params)); + Common::ParamPackage right_analog_params; + right_analog_params.Set("engine", "gcpad"); + right_analog_params.Set("port", params.Get("port", 0)); + right_analog_params.Set("axis_x", static_cast(PadAxes::SubstickX)); + right_analog_params.Set("axis_y", static_cast(PadAxes::SubstickY)); + mapping.insert_or_assign(Settings::NativeAnalog::RStick, std::move(right_analog_params)); + return mapping; +} + +std::string GCAdapter::GetUIName(const Common::ParamPackage& params) const { + if (params.Has("button")) { + return fmt::format("Button {}", params.Get("button", 0)); + } + + return "Bad GC Adapter"; +} + +} // namespace InputCommon diff --git a/src/input_common/drivers/gc_adapter.h b/src/input_common/drivers/gc_adapter.h new file mode 100644 index 000000000..c0bf1ed7a --- /dev/null +++ b/src/input_common/drivers/gc_adapter.h @@ -0,0 +1,128 @@ +// Copyright 2014 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include + +#include "input_common/input_engine.h" + +struct libusb_context; +struct libusb_device; +struct libusb_device_handle; + +namespace InputCommon { + +class LibUSBContext; +class LibUSBDeviceHandle; + +class GCAdapter : public InputCommon::InputEngine { +public: + explicit GCAdapter(const std::string input_engine_); + ~GCAdapter(); + + bool SetRumble(const PadIdentifier& identifier, + const Input::VibrationStatus vibration) override; + + /// Used for automapping features + std::vector GetInputDevices() const override; + ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage& params) override; + AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage& params) override; + std::string GetUIName(const Common::ParamPackage& params) const override; + +private: + enum class PadButton { + Undefined = 0x0000, + ButtonLeft = 0x0001, + ButtonRight = 0x0002, + ButtonDown = 0x0004, + ButtonUp = 0x0008, + TriggerZ = 0x0010, + TriggerR = 0x0020, + TriggerL = 0x0040, + ButtonA = 0x0100, + ButtonB = 0x0200, + ButtonX = 0x0400, + ButtonY = 0x0800, + ButtonStart = 0x1000, + }; + + enum class PadAxes : u8 { + StickX, + StickY, + SubstickX, + SubstickY, + TriggerLeft, + TriggerRight, + Undefined, + }; + + enum class ControllerTypes { + None, + Wired, + Wireless, + }; + + struct GCController { + ControllerTypes type = ControllerTypes::None; + PadIdentifier identifier{}; + bool enable_vibration = false; + u8 rumble_amplitude{}; + std::array axis_origin{}; + u8 reset_origin_counter{}; + }; + + using AdapterPayload = std::array; + + void UpdatePadType(std::size_t port, ControllerTypes pad_type); + void UpdateControllers(const AdapterPayload& adapter_payload); + void UpdateStateButtons(std::size_t port, u8 b1, u8 b2); + void UpdateStateAxes(std::size_t port, const AdapterPayload& adapter_payload); + + void AdapterInputThread(std::stop_token stop_token); + + void AdapterScanThread(std::stop_token stop_token); + + bool IsPayloadCorrect(const AdapterPayload& adapter_payload, s32 payload_size); + + /// For use in initialization, querying devices to find the adapter + bool Setup(); + + /// Returns true if we successfully gain access to GC Adapter + bool CheckDeviceAccess(); + + /// Captures GC Adapter endpoint address + /// Returns true if the endpoint was set correctly + bool GetGCEndpoint(libusb_device* device); + + /// Returns true if there is a device connected to port + bool DeviceConnected(std::size_t port) const; + + /// For shutting down, clear all data, join all threads, release usb + void Reset(); + + void UpdateVibrations(); + // Updates vibration state of all controllers + void SendVibrations(); + std::unique_ptr usb_adapter_handle; + std::array pads; + + std::jthread adapter_input_thread; + std::jthread adapter_scan_thread; + bool restart_scan_thread{}; + + std::unique_ptr libusb_ctx; + + u8 input_endpoint{0}; + u8 output_endpoint{0}; + u8 input_error_counter{0}; + u8 output_error_counter{0}; + int vibration_counter{0}; + + bool rumble_enabled{true}; + bool vibration_changed{true}; +}; +} // namespace InputCommon diff --git a/src/input_common/drivers/tas_input.cpp b/src/input_common/drivers/tas_input.cpp new file mode 100644 index 000000000..5e2101b27 --- /dev/null +++ b/src/input_common/drivers/tas_input.cpp @@ -0,0 +1,320 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include +#include +#include + +#include "common/fs/file.h" +#include "common/fs/fs_types.h" +#include "common/fs/path_util.h" +#include "common/logging/log.h" +#include "common/settings.h" +#include "input_common/drivers/tas_input.h" + +namespace InputCommon::TasInput { + +enum TasAxes : u8 { + StickX, + StickY, + SubstickX, + SubstickY, + Undefined, +}; + +// Supported keywords and buttons from a TAS file +constexpr std::array, 20> text_to_tas_button = { + std::pair{"KEY_A", TasButton::BUTTON_A}, + {"KEY_B", TasButton::BUTTON_B}, + {"KEY_X", TasButton::BUTTON_X}, + {"KEY_Y", TasButton::BUTTON_Y}, + {"KEY_LSTICK", TasButton::STICK_L}, + {"KEY_RSTICK", TasButton::STICK_R}, + {"KEY_L", TasButton::TRIGGER_L}, + {"KEY_R", TasButton::TRIGGER_R}, + {"KEY_PLUS", TasButton::BUTTON_PLUS}, + {"KEY_MINUS", TasButton::BUTTON_MINUS}, + {"KEY_DLEFT", TasButton::BUTTON_LEFT}, + {"KEY_DUP", TasButton::BUTTON_UP}, + {"KEY_DRIGHT", TasButton::BUTTON_RIGHT}, + {"KEY_DDOWN", TasButton::BUTTON_DOWN}, + {"KEY_SL", TasButton::BUTTON_SL}, + {"KEY_SR", TasButton::BUTTON_SR}, + {"KEY_CAPTURE", TasButton::BUTTON_CAPTURE}, + {"KEY_HOME", TasButton::BUTTON_HOME}, + {"KEY_ZL", TasButton::TRIGGER_ZL}, + {"KEY_ZR", TasButton::TRIGGER_ZR}, +}; + +Tas::Tas(const std::string input_engine_) : InputCommon::InputEngine(input_engine_) { + for (size_t player_index = 0; player_index < PLAYER_NUMBER; player_index++) { + PadIdentifier identifier{ + .guid = Common::UUID{}, + .port = player_index, + .pad = 0, + }; + PreSetController(identifier); + } + ClearInput(); + if (!Settings::values.tas_enable) { + needs_reset = true; + return; + } + LoadTasFiles(); +} + +Tas::~Tas() { + Stop(); +}; + +void Tas::LoadTasFiles() { + script_length = 0; + for (size_t i = 0; i < commands.size(); i++) { + LoadTasFile(i); + if (commands[i].size() > script_length) { + script_length = commands[i].size(); + } + } +} + +void Tas::LoadTasFile(size_t player_index) { + if (!commands[player_index].empty()) { + commands[player_index].clear(); + } + std::string file = + Common::FS::ReadStringFromFile(Common::FS::GetYuzuPath(Common::FS::YuzuPath::TASDir) / + fmt::format("script0-{}.txt", player_index + 1), + Common::FS::FileType::BinaryFile); + std::stringstream command_line(file); + std::string line; + int frame_no = 0; + while (std::getline(command_line, line, '\n')) { + if (line.empty()) { + continue; + } + std::smatch m; + + std::stringstream linestream(line); + std::string segment; + std::vector seglist; + + while (std::getline(linestream, segment, ' ')) { + seglist.push_back(segment); + } + + if (seglist.size() < 4) { + continue; + } + + while (frame_no < std::stoi(seglist.at(0))) { + commands[player_index].push_back({}); + frame_no++; + } + + TASCommand command = { + .buttons = ReadCommandButtons(seglist.at(1)), + .l_axis = ReadCommandAxis(seglist.at(2)), + .r_axis = ReadCommandAxis(seglist.at(3)), + }; + commands[player_index].push_back(command); + frame_no++; + } + LOG_INFO(Input, "TAS file loaded! {} frames", frame_no); +} + +void Tas::WriteTasFile(std::u8string file_name) { + std::string output_text; + for (size_t frame = 0; frame < record_commands.size(); frame++) { + const TASCommand& line = record_commands[frame]; + output_text += fmt::format("{} {} {} {} {}\n", frame, WriteCommandButtons(line.buttons), + WriteCommandAxis(line.l_axis), WriteCommandAxis(line.r_axis)); + } + const auto bytes_written = Common::FS::WriteStringToFile( + Common::FS::GetYuzuPath(Common::FS::YuzuPath::TASDir) / file_name, + Common::FS::FileType::TextFile, output_text); + if (bytes_written == output_text.size()) { + LOG_INFO(Input, "TAS file written to file!"); + } else { + LOG_ERROR(Input, "Writing the TAS-file has failed! {} / {} bytes written", bytes_written, + output_text.size()); + } +} + +void Tas::RecordInput(u32 buttons, TasAnalog left_axis, TasAnalog right_axis) { + last_input = { + .buttons = buttons, + .l_axis = FlipAxisY(left_axis), + .r_axis = FlipAxisY(right_axis), + }; +} + +TasAnalog Tas::FlipAxisY(TasAnalog old) { + return { + .x = old.x, + .y = -old.y, + }; +} + +std::tuple Tas::GetStatus() const { + TasState state; + if (is_recording) { + return {TasState::Recording, 0, record_commands.size()}; + } + + if (is_running) { + state = TasState::Running; + } else { + state = TasState::Stopped; + } + + return {state, current_command, script_length}; +} + +void Tas::UpdateThread() { + if (!Settings::values.tas_enable) { + if (is_running) { + Stop(); + } + return; + } + + if (is_recording) { + record_commands.push_back(last_input); + } + if (needs_reset) { + current_command = 0; + needs_reset = false; + LoadTasFiles(); + LOG_DEBUG(Input, "tas_reset done"); + } + + if (!is_running) { + ClearInput(); + return; + } + if (current_command < script_length) { + LOG_DEBUG(Input, "Playing TAS {}/{}", current_command, script_length); + size_t frame = current_command++; + for (size_t player_index = 0; player_index < commands.size(); player_index++) { + TASCommand command{}; + if (frame < commands[player_index].size()) { + command = commands[player_index][frame]; + } + + PadIdentifier identifier{ + .guid = Common::UUID{}, + .port = player_index, + .pad = 0, + }; + for (std::size_t i = 0; i < sizeof(command.buttons); ++i) { + const bool button_status = (command.buttons & (1U << i)) != 0; + const int button = static_cast(i); + SetButton(identifier, button, button_status); + } + SetAxis(identifier, TasAxes::StickX, command.l_axis.x); + SetAxis(identifier, TasAxes::StickY, command.l_axis.y); + SetAxis(identifier, TasAxes::SubstickX, command.r_axis.x); + SetAxis(identifier, TasAxes::SubstickY, command.r_axis.y); + } + } else { + is_running = Settings::values.tas_loop.GetValue(); + current_command = 0; + ClearInput(); + } +} + +void Tas::ClearInput() { + ResetButtonState(); + ResetAnalogState(); +} + +TasAnalog Tas::ReadCommandAxis(const std::string& line) const { + std::stringstream linestream(line); + std::string segment; + std::vector seglist; + + while (std::getline(linestream, segment, ';')) { + seglist.push_back(segment); + } + + const float x = std::stof(seglist.at(0)) / 32767.0f; + const float y = std::stof(seglist.at(1)) / 32767.0f; + + return {x, y}; +} + +u32 Tas::ReadCommandButtons(const std::string& data) const { + std::stringstream button_text(data); + std::string line; + u32 buttons = 0; + while (std::getline(button_text, line, ';')) { + for (auto [text, tas_button] : text_to_tas_button) { + if (text == line) { + buttons |= static_cast(tas_button); + break; + } + } + } + return buttons; +} + +std::string Tas::WriteCommandButtons(u32 buttons) const { + std::string returns = ""; + for (auto [text_button, tas_button] : text_to_tas_button) { + if ((buttons & static_cast(tas_button)) != 0) + returns += fmt::format("{};", text_button.substr(4)); + } + return returns.empty() ? "NONE" : returns.substr(2); +} + +std::string Tas::WriteCommandAxis(TasAnalog analog) const { + return fmt::format("{};{}", analog.x * 32767, analog.y * 32767); +} + +void Tas::StartStop() { + if (!Settings::values.tas_enable) { + return; + } + if (is_running) { + Stop(); + } else { + is_running = true; + } +} + +void Tas::Stop() { + is_running = false; +} + +void Tas::Reset() { + if (!Settings::values.tas_enable) { + return; + } + needs_reset = true; +} + +bool Tas::Record() { + if (!Settings::values.tas_enable) { + return true; + } + is_recording = !is_recording; + return is_recording; +} + +void Tas::SaveRecording(bool overwrite_file) { + if (is_recording) { + return; + } + if (record_commands.empty()) { + return; + } + WriteTasFile(u8"record.txt"); + if (overwrite_file) { + WriteTasFile(u8"script0-1.txt"); + } + needs_reset = true; + record_commands.clear(); +} + +} // namespace InputCommon::TasInput diff --git a/src/input_common/drivers/tas_input.h b/src/input_common/drivers/tas_input.h new file mode 100644 index 000000000..9fadc118b --- /dev/null +++ b/src/input_common/drivers/tas_input.h @@ -0,0 +1,200 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include + +#include "common/common_types.h" +#include "common/settings_input.h" +#include "input_common/input_engine.h" +#include "input_common/main.h" + +/* +To play back TAS scripts on Yuzu, select the folder with scripts in the configuration menu below +Tools -> Configure TAS. The file itself has normal text format and has to be called script0-1.txt +for controller 1, script0-2.txt for controller 2 and so forth (with max. 8 players). + +A script file has the same format as TAS-nx uses, so final files will look like this: + +1 KEY_B 0;0 0;0 +6 KEY_ZL 0;0 0;0 +41 KEY_ZL;KEY_Y 0;0 0;0 +43 KEY_X;KEY_A 32767;0 0;0 +44 KEY_A 32767;0 0;0 +45 KEY_A 32767;0 0;0 +46 KEY_A 32767;0 0;0 +47 KEY_A 32767;0 0;0 + +After placing the file at the correct location, it can be read into Yuzu with the (default) hotkey +CTRL+F6 (refresh). In the bottom left corner, it will display the amount of frames the script file +has. Playback can be started or stopped using CTRL+F5. + +However, for playback to actually work, the correct input device has to be selected: In the Controls +menu, select TAS from the device list for the controller that the script should be played on. + +Recording a new script file is really simple: Just make sure that the proper device (not TAS) is +connected on P1, and press CTRL+F7 to start recording. When done, just press the same keystroke +again (CTRL+F7). The new script will be saved at the location previously selected, as the filename +record.txt. + +For debugging purposes, the common controller debugger can be used (View -> Debugging -> Controller +P1). +*/ + +namespace InputCommon::TasInput { + +constexpr size_t PLAYER_NUMBER = 10; + +enum class TasButton : u32 { + BUTTON_A = 1U << 0, + BUTTON_B = 1U << 1, + BUTTON_X = 1U << 2, + BUTTON_Y = 1U << 3, + STICK_L = 1U << 4, + STICK_R = 1U << 5, + TRIGGER_L = 1U << 6, + TRIGGER_R = 1U << 7, + TRIGGER_ZL = 1U << 8, + TRIGGER_ZR = 1U << 9, + BUTTON_PLUS = 1U << 10, + BUTTON_MINUS = 1U << 11, + BUTTON_LEFT = 1U << 12, + BUTTON_UP = 1U << 13, + BUTTON_RIGHT = 1U << 14, + BUTTON_DOWN = 1U << 15, + BUTTON_SL = 1U << 16, + BUTTON_SR = 1U << 17, + BUTTON_HOME = 1U << 18, + BUTTON_CAPTURE = 1U << 19, +}; + +struct TasAnalog { + float x{}; + float y{}; +}; + +enum class TasState { + Running, + Recording, + Stopped, +}; + +class Tas final : public InputCommon::InputEngine { +public: + explicit Tas(const std::string input_engine_); + ~Tas(); + + /** + * Changes the input status that will be stored in each frame + * @param buttons: bitfield with the status of the buttons + * @param left_axis: value of the left axis + * @param right_axis: value of the right axis + */ + void RecordInput(u32 buttons, TasAnalog left_axis, TasAnalog right_axis); + + // Main loop that records or executes input + void UpdateThread(); + + // Sets the flag to start or stop the TAS command excecution and swaps controllers profiles + void StartStop(); + + // Stop the TAS and reverts any controller profile + void Stop(); + + // Sets the flag to reload the file and start from the begining in the next update + void Reset(); + + /** + * Sets the flag to enable or disable recording of inputs + * @return Returns true if the current recording status is enabled + */ + bool Record(); + + /** + * Saves contents of record_commands on a file + * @param overwrite_file: Indicates if player 1 should be overwritten + */ + void SaveRecording(bool overwrite_file); + + /** + * Returns the current status values of TAS playback/recording + * @return Tuple of + * TasState indicating the current state out of Running ; + * Current playback progress ; + * Total length of script file currently loaded or being recorded + */ + std::tuple GetStatus() const; + +private: + struct TASCommand { + u32 buttons{}; + TasAnalog l_axis{}; + TasAnalog r_axis{}; + }; + + /// Loads TAS files from all players + void LoadTasFiles(); + + /** Loads TAS file from the specified player + * @param player_index: player number where data is going to be stored + */ + void LoadTasFile(size_t player_index); + + /** Writes a TAS file from the recorded commands + * @param file_name: name of the file to be written + */ + void WriteTasFile(std::u8string file_name); + + /** Inverts the Y axis polarity + * @param old: value of the axis + * @return new value of the axis + */ + TasAnalog FlipAxisY(TasAnalog old); + + /** + * Parses a string containing the axis values. X and Y have a range from -32767 to 32767 + * @param line: string containing axis values with the following format "x;y" + * @return Returns a TAS analog object with axis values with range from -1.0 to 1.0 + */ + TasAnalog ReadCommandAxis(const std::string& line) const; + + /** + * Parses a string containing the button values. Each button is represented by it's text format + * specified in text_to_tas_button array + * @param line: string containing button name with the following format "a;b;c;d..." + * @return Returns a u32 with each bit representing the status of a button + */ + u32 ReadCommandButtons(const std::string& line) const; + + /** + * Reset state of all players + */ + void ClearInput(); + + /** + * Converts an u32 containing the button status into the text equivalent + * @param buttons: bitfield with the status of the buttons + * @return Returns a string with the name of the buttons to be written to the file + */ + std::string WriteCommandButtons(u32 buttons) const; + + /** + * Converts an TAS analog object containing the axis status into the text equivalent + * @param data: value of the axis + * @return A string with the value of the axis to be written to the file + */ + std::string WriteCommandAxis(TasAnalog data) const; + + size_t script_length{0}; + bool is_old_input_saved{false}; + bool is_recording{false}; + bool is_running{false}; + bool needs_reset{false}; + std::array, PLAYER_NUMBER> commands{}; + std::vector record_commands{}; + size_t current_command{0}; + TASCommand last_input{}; // only used for recording +}; +} // namespace InputCommon::TasInput diff --git a/src/input_common/gcadapter/gc_adapter.cpp b/src/input_common/gcadapter/gc_adapter.cpp deleted file mode 100644 index a2f1bb67c..000000000 --- a/src/input_common/gcadapter/gc_adapter.cpp +++ /dev/null @@ -1,506 +0,0 @@ -// Copyright 2014 Dolphin Emulator Project -// Licensed under GPLv2+ -// Refer to the license.txt file included. - -#include -#include - -#include - -#include "common/logging/log.h" -#include "common/param_package.h" -#include "common/settings_input.h" -#include "input_common/gcadapter/gc_adapter.h" - -namespace GCAdapter { - -Adapter::Adapter() { - if (usb_adapter_handle != nullptr) { - return; - } - LOG_INFO(Input, "GC Adapter Initialization started"); - - const int init_res = libusb_init(&libusb_ctx); - if (init_res == LIBUSB_SUCCESS) { - adapter_scan_thread = std::thread(&Adapter::AdapterScanThread, this); - } else { - LOG_ERROR(Input, "libusb could not be initialized. failed with error = {}", init_res); - } -} - -Adapter::~Adapter() { - Reset(); -} - -void Adapter::AdapterInputThread() { - LOG_DEBUG(Input, "GC Adapter input thread started"); - s32 payload_size{}; - AdapterPayload adapter_payload{}; - - if (adapter_scan_thread.joinable()) { - adapter_scan_thread.join(); - } - - while (adapter_input_thread_running) { - libusb_interrupt_transfer(usb_adapter_handle, input_endpoint, adapter_payload.data(), - static_cast(adapter_payload.size()), &payload_size, 16); - if (IsPayloadCorrect(adapter_payload, payload_size)) { - UpdateControllers(adapter_payload); - UpdateVibrations(); - } - std::this_thread::yield(); - } - - if (restart_scan_thread) { - adapter_scan_thread = std::thread(&Adapter::AdapterScanThread, this); - restart_scan_thread = false; - } -} - -bool Adapter::IsPayloadCorrect(const AdapterPayload& adapter_payload, s32 payload_size) { - if (payload_size != static_cast(adapter_payload.size()) || - adapter_payload[0] != LIBUSB_DT_HID) { - LOG_DEBUG(Input, "Error reading payload (size: {}, type: {:02x})", payload_size, - adapter_payload[0]); - if (input_error_counter++ > 20) { - LOG_ERROR(Input, "GC adapter timeout, Is the adapter connected?"); - adapter_input_thread_running = false; - restart_scan_thread = true; - } - return false; - } - - input_error_counter = 0; - return true; -} - -void Adapter::UpdateControllers(const AdapterPayload& adapter_payload) { - for (std::size_t port = 0; port < pads.size(); ++port) { - const std::size_t offset = 1 + (9 * port); - const auto type = static_cast(adapter_payload[offset] >> 4); - UpdatePadType(port, type); - if (DeviceConnected(port)) { - const u8 b1 = adapter_payload[offset + 1]; - const u8 b2 = adapter_payload[offset + 2]; - UpdateStateButtons(port, b1, b2); - UpdateStateAxes(port, adapter_payload); - if (configuring) { - UpdateYuzuSettings(port); - } - } - } -} - -void Adapter::UpdatePadType(std::size_t port, ControllerTypes pad_type) { - if (pads[port].type == pad_type) { - return; - } - // Device changed reset device and set new type - ResetDevice(port); - pads[port].type = pad_type; -} - -void Adapter::UpdateStateButtons(std::size_t port, u8 b1, u8 b2) { - if (port >= pads.size()) { - return; - } - - static constexpr std::array b1_buttons{ - PadButton::ButtonA, PadButton::ButtonB, PadButton::ButtonX, PadButton::ButtonY, - PadButton::ButtonLeft, PadButton::ButtonRight, PadButton::ButtonDown, PadButton::ButtonUp, - }; - - static constexpr std::array b2_buttons{ - PadButton::ButtonStart, - PadButton::TriggerZ, - PadButton::TriggerR, - PadButton::TriggerL, - }; - pads[port].buttons = 0; - for (std::size_t i = 0; i < b1_buttons.size(); ++i) { - if ((b1 & (1U << i)) != 0) { - pads[port].buttons = - static_cast(pads[port].buttons | static_cast(b1_buttons[i])); - pads[port].last_button = b1_buttons[i]; - } - } - - for (std::size_t j = 0; j < b2_buttons.size(); ++j) { - if ((b2 & (1U << j)) != 0) { - pads[port].buttons = - static_cast(pads[port].buttons | static_cast(b2_buttons[j])); - pads[port].last_button = b2_buttons[j]; - } - } -} - -void Adapter::UpdateStateAxes(std::size_t port, const AdapterPayload& adapter_payload) { - if (port >= pads.size()) { - return; - } - - const std::size_t offset = 1 + (9 * port); - static constexpr std::array axes{ - PadAxes::StickX, PadAxes::StickY, PadAxes::SubstickX, - PadAxes::SubstickY, PadAxes::TriggerLeft, PadAxes::TriggerRight, - }; - - for (const PadAxes axis : axes) { - const auto index = static_cast(axis); - const u8 axis_value = adapter_payload[offset + 3 + index]; - if (pads[port].reset_origin_counter <= 18) { - if (pads[port].axis_origin[index] != axis_value) { - pads[port].reset_origin_counter = 0; - } - pads[port].axis_origin[index] = axis_value; - pads[port].reset_origin_counter++; - } - pads[port].axis_values[index] = - static_cast(axis_value - pads[port].axis_origin[index]); - } -} - -void Adapter::UpdateYuzuSettings(std::size_t port) { - if (port >= pads.size()) { - return; - } - - constexpr u8 axis_threshold = 50; - GCPadStatus pad_status = {.port = port}; - - if (pads[port].buttons != 0) { - pad_status.button = pads[port].last_button; - pad_queue.Push(pad_status); - } - - // Accounting for a threshold here to ensure an intentional press - for (std::size_t i = 0; i < pads[port].axis_values.size(); ++i) { - const s16 value = pads[port].axis_values[i]; - - if (value > axis_threshold || value < -axis_threshold) { - pad_status.axis = static_cast(i); - pad_status.axis_value = value; - pad_status.axis_threshold = axis_threshold; - pad_queue.Push(pad_status); - } - } -} - -void Adapter::UpdateVibrations() { - // Use 8 states to keep the switching between on/off fast enough for - // a human to not notice the difference between switching from on/off - // More states = more rumble strengths = slower update time - constexpr u8 vibration_states = 8; - - vibration_counter = (vibration_counter + 1) % vibration_states; - - for (GCController& pad : pads) { - const bool vibrate = pad.rumble_amplitude > vibration_counter; - vibration_changed |= vibrate != pad.enable_vibration; - pad.enable_vibration = vibrate; - } - SendVibrations(); -} - -void Adapter::SendVibrations() { - if (!rumble_enabled || !vibration_changed) { - return; - } - s32 size{}; - constexpr u8 rumble_command = 0x11; - const u8 p1 = pads[0].enable_vibration; - const u8 p2 = pads[1].enable_vibration; - const u8 p3 = pads[2].enable_vibration; - const u8 p4 = pads[3].enable_vibration; - std::array payload = {rumble_command, p1, p2, p3, p4}; - const int err = libusb_interrupt_transfer(usb_adapter_handle, output_endpoint, payload.data(), - static_cast(payload.size()), &size, 16); - if (err) { - LOG_DEBUG(Input, "Adapter libusb write failed: {}", libusb_error_name(err)); - if (output_error_counter++ > 5) { - LOG_ERROR(Input, "GC adapter output timeout, Rumble disabled"); - rumble_enabled = false; - } - return; - } - output_error_counter = 0; - vibration_changed = false; -} - -bool Adapter::RumblePlay(std::size_t port, u8 amplitude) { - pads[port].rumble_amplitude = amplitude; - - return rumble_enabled; -} - -void Adapter::AdapterScanThread() { - adapter_scan_thread_running = true; - adapter_input_thread_running = false; - if (adapter_input_thread.joinable()) { - adapter_input_thread.join(); - } - ClearLibusbHandle(); - ResetDevices(); - while (adapter_scan_thread_running && !adapter_input_thread_running) { - Setup(); - std::this_thread::sleep_for(std::chrono::seconds(1)); - } -} - -void Adapter::Setup() { - usb_adapter_handle = libusb_open_device_with_vid_pid(libusb_ctx, 0x057e, 0x0337); - - if (usb_adapter_handle == NULL) { - return; - } - if (!CheckDeviceAccess()) { - ClearLibusbHandle(); - return; - } - - libusb_device* device = libusb_get_device(usb_adapter_handle); - - LOG_INFO(Input, "GC adapter is now connected"); - // GC Adapter found and accessible, registering it - if (GetGCEndpoint(device)) { - adapter_scan_thread_running = false; - adapter_input_thread_running = true; - rumble_enabled = true; - input_error_counter = 0; - output_error_counter = 0; - adapter_input_thread = std::thread(&Adapter::AdapterInputThread, this); - } -} - -bool Adapter::CheckDeviceAccess() { - // This fixes payload problems from offbrand GCAdapters - const s32 control_transfer_error = - libusb_control_transfer(usb_adapter_handle, 0x21, 11, 0x0001, 0, nullptr, 0, 1000); - if (control_transfer_error < 0) { - LOG_ERROR(Input, "libusb_control_transfer failed with error= {}", control_transfer_error); - } - - s32 kernel_driver_error = libusb_kernel_driver_active(usb_adapter_handle, 0); - if (kernel_driver_error == 1) { - kernel_driver_error = libusb_detach_kernel_driver(usb_adapter_handle, 0); - if (kernel_driver_error != 0 && kernel_driver_error != LIBUSB_ERROR_NOT_SUPPORTED) { - LOG_ERROR(Input, "libusb_detach_kernel_driver failed with error = {}", - kernel_driver_error); - } - } - - if (kernel_driver_error && kernel_driver_error != LIBUSB_ERROR_NOT_SUPPORTED) { - libusb_close(usb_adapter_handle); - usb_adapter_handle = nullptr; - return false; - } - - const int interface_claim_error = libusb_claim_interface(usb_adapter_handle, 0); - if (interface_claim_error) { - LOG_ERROR(Input, "libusb_claim_interface failed with error = {}", interface_claim_error); - libusb_close(usb_adapter_handle); - usb_adapter_handle = nullptr; - return false; - } - - return true; -} - -bool Adapter::GetGCEndpoint(libusb_device* device) { - libusb_config_descriptor* config = nullptr; - const int config_descriptor_return = libusb_get_config_descriptor(device, 0, &config); - if (config_descriptor_return != LIBUSB_SUCCESS) { - LOG_ERROR(Input, "libusb_get_config_descriptor failed with error = {}", - config_descriptor_return); - return false; - } - - for (u8 ic = 0; ic < config->bNumInterfaces; ic++) { - const libusb_interface* interfaceContainer = &config->interface[ic]; - for (int i = 0; i < interfaceContainer->num_altsetting; i++) { - const libusb_interface_descriptor* interface = &interfaceContainer->altsetting[i]; - for (u8 e = 0; e < interface->bNumEndpoints; e++) { - const libusb_endpoint_descriptor* endpoint = &interface->endpoint[e]; - if ((endpoint->bEndpointAddress & LIBUSB_ENDPOINT_IN) != 0) { - input_endpoint = endpoint->bEndpointAddress; - } else { - output_endpoint = endpoint->bEndpointAddress; - } - } - } - } - // This transfer seems to be responsible for clearing the state of the adapter - // Used to clear the "busy" state of when the device is unexpectedly unplugged - unsigned char clear_payload = 0x13; - libusb_interrupt_transfer(usb_adapter_handle, output_endpoint, &clear_payload, - sizeof(clear_payload), nullptr, 16); - return true; -} - -void Adapter::JoinThreads() { - restart_scan_thread = false; - adapter_input_thread_running = false; - adapter_scan_thread_running = false; - - if (adapter_scan_thread.joinable()) { - adapter_scan_thread.join(); - } - - if (adapter_input_thread.joinable()) { - adapter_input_thread.join(); - } -} - -void Adapter::ClearLibusbHandle() { - if (usb_adapter_handle) { - libusb_release_interface(usb_adapter_handle, 1); - libusb_close(usb_adapter_handle); - usb_adapter_handle = nullptr; - } -} - -void Adapter::ResetDevices() { - for (std::size_t i = 0; i < pads.size(); ++i) { - ResetDevice(i); - } -} - -void Adapter::ResetDevice(std::size_t port) { - pads[port].type = ControllerTypes::None; - pads[port].enable_vibration = false; - pads[port].rumble_amplitude = 0; - pads[port].buttons = 0; - pads[port].last_button = PadButton::Undefined; - pads[port].axis_values.fill(0); - pads[port].reset_origin_counter = 0; -} - -void Adapter::Reset() { - JoinThreads(); - ClearLibusbHandle(); - ResetDevices(); - - if (libusb_ctx) { - libusb_exit(libusb_ctx); - } -} - -std::vector Adapter::GetInputDevices() const { - std::vector devices; - for (std::size_t port = 0; port < pads.size(); ++port) { - if (!DeviceConnected(port)) { - continue; - } - std::string name = fmt::format("Gamecube Controller {}", port + 1); - devices.emplace_back(Common::ParamPackage{ - {"class", "gcpad"}, - {"display", std::move(name)}, - {"port", std::to_string(port)}, - }); - } - return devices; -} - -InputCommon::ButtonMapping Adapter::GetButtonMappingForDevice( - const Common::ParamPackage& params) const { - // This list is missing ZL/ZR since those are not considered buttons. - // We will add those afterwards - // This list also excludes any button that can't be really mapped - static constexpr std::array, 12> - switch_to_gcadapter_button = { - std::pair{Settings::NativeButton::A, PadButton::ButtonA}, - {Settings::NativeButton::B, PadButton::ButtonB}, - {Settings::NativeButton::X, PadButton::ButtonX}, - {Settings::NativeButton::Y, PadButton::ButtonY}, - {Settings::NativeButton::Plus, PadButton::ButtonStart}, - {Settings::NativeButton::DLeft, PadButton::ButtonLeft}, - {Settings::NativeButton::DUp, PadButton::ButtonUp}, - {Settings::NativeButton::DRight, PadButton::ButtonRight}, - {Settings::NativeButton::DDown, PadButton::ButtonDown}, - {Settings::NativeButton::SL, PadButton::TriggerL}, - {Settings::NativeButton::SR, PadButton::TriggerR}, - {Settings::NativeButton::R, PadButton::TriggerZ}, - }; - if (!params.Has("port")) { - return {}; - } - - InputCommon::ButtonMapping mapping{}; - for (const auto& [switch_button, gcadapter_button] : switch_to_gcadapter_button) { - Common::ParamPackage button_params({{"engine", "gcpad"}}); - button_params.Set("port", params.Get("port", 0)); - button_params.Set("button", static_cast(gcadapter_button)); - mapping.insert_or_assign(switch_button, std::move(button_params)); - } - - // Add the missing bindings for ZL/ZR - static constexpr std::array, 2> - switch_to_gcadapter_axis = { - std::pair{Settings::NativeButton::ZL, PadAxes::TriggerLeft}, - {Settings::NativeButton::ZR, PadAxes::TriggerRight}, - }; - for (const auto& [switch_button, gcadapter_axis] : switch_to_gcadapter_axis) { - Common::ParamPackage button_params({{"engine", "gcpad"}}); - button_params.Set("port", params.Get("port", 0)); - button_params.Set("button", static_cast(PadButton::Stick)); - button_params.Set("axis", static_cast(gcadapter_axis)); - button_params.Set("threshold", 0.5f); - button_params.Set("direction", "+"); - mapping.insert_or_assign(switch_button, std::move(button_params)); - } - return mapping; -} - -InputCommon::AnalogMapping Adapter::GetAnalogMappingForDevice( - const Common::ParamPackage& params) const { - if (!params.Has("port")) { - return {}; - } - - InputCommon::AnalogMapping mapping = {}; - Common::ParamPackage left_analog_params; - left_analog_params.Set("engine", "gcpad"); - left_analog_params.Set("port", params.Get("port", 0)); - left_analog_params.Set("axis_x", static_cast(PadAxes::StickX)); - left_analog_params.Set("axis_y", static_cast(PadAxes::StickY)); - mapping.insert_or_assign(Settings::NativeAnalog::LStick, std::move(left_analog_params)); - Common::ParamPackage right_analog_params; - right_analog_params.Set("engine", "gcpad"); - right_analog_params.Set("port", params.Get("port", 0)); - right_analog_params.Set("axis_x", static_cast(PadAxes::SubstickX)); - right_analog_params.Set("axis_y", static_cast(PadAxes::SubstickY)); - mapping.insert_or_assign(Settings::NativeAnalog::RStick, std::move(right_analog_params)); - return mapping; -} - -bool Adapter::DeviceConnected(std::size_t port) const { - return pads[port].type != ControllerTypes::None; -} - -void Adapter::BeginConfiguration() { - pad_queue.Clear(); - configuring = true; -} - -void Adapter::EndConfiguration() { - pad_queue.Clear(); - configuring = false; -} - -Common::SPSCQueue& Adapter::GetPadQueue() { - return pad_queue; -} - -const Common::SPSCQueue& Adapter::GetPadQueue() const { - return pad_queue; -} - -GCController& Adapter::GetPadState(std::size_t port) { - return pads.at(port); -} - -const GCController& Adapter::GetPadState(std::size_t port) const { - return pads.at(port); -} - -} // namespace GCAdapter diff --git a/src/input_common/gcadapter/gc_adapter.h b/src/input_common/gcadapter/gc_adapter.h deleted file mode 100644 index e5de5e94f..000000000 --- a/src/input_common/gcadapter/gc_adapter.h +++ /dev/null @@ -1,168 +0,0 @@ -// Copyright 2014 Dolphin Emulator Project -// Licensed under GPLv2+ -// Refer to the license.txt file included. - -#pragma once -#include -#include -#include -#include -#include -#include "common/common_types.h" -#include "common/threadsafe_queue.h" -#include "input_common/main.h" - -struct libusb_context; -struct libusb_device; -struct libusb_device_handle; - -namespace GCAdapter { - -enum class PadButton { - Undefined = 0x0000, - ButtonLeft = 0x0001, - ButtonRight = 0x0002, - ButtonDown = 0x0004, - ButtonUp = 0x0008, - TriggerZ = 0x0010, - TriggerR = 0x0020, - TriggerL = 0x0040, - ButtonA = 0x0100, - ButtonB = 0x0200, - ButtonX = 0x0400, - ButtonY = 0x0800, - ButtonStart = 0x1000, - // Below is for compatibility with "AxisButton" type - Stick = 0x2000, -}; - -enum class PadAxes : u8 { - StickX, - StickY, - SubstickX, - SubstickY, - TriggerLeft, - TriggerRight, - Undefined, -}; - -enum class ControllerTypes { - None, - Wired, - Wireless, -}; - -struct GCPadStatus { - std::size_t port{}; - - PadButton button{PadButton::Undefined}; // Or-ed PAD_BUTTON_* and PAD_TRIGGER_* bits - - PadAxes axis{PadAxes::Undefined}; - s16 axis_value{}; - u8 axis_threshold{50}; -}; - -struct GCController { - ControllerTypes type{}; - bool enable_vibration{}; - u8 rumble_amplitude{}; - u16 buttons{}; - PadButton last_button{}; - std::array axis_values{}; - std::array axis_origin{}; - u8 reset_origin_counter{}; -}; - -class Adapter { -public: - Adapter(); - ~Adapter(); - - /// Request a vibration for a controller - bool RumblePlay(std::size_t port, u8 amplitude); - - /// Used for polling - void BeginConfiguration(); - void EndConfiguration(); - - Common::SPSCQueue& GetPadQueue(); - const Common::SPSCQueue& GetPadQueue() const; - - GCController& GetPadState(std::size_t port); - const GCController& GetPadState(std::size_t port) const; - - /// Returns true if there is a device connected to port - bool DeviceConnected(std::size_t port) const; - - /// Used for automapping features - std::vector GetInputDevices() const; - InputCommon::ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage& params) const; - InputCommon::AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage& params) const; - -private: - using AdapterPayload = std::array; - - void UpdatePadType(std::size_t port, ControllerTypes pad_type); - void UpdateControllers(const AdapterPayload& adapter_payload); - void UpdateYuzuSettings(std::size_t port); - void UpdateStateButtons(std::size_t port, u8 b1, u8 b2); - void UpdateStateAxes(std::size_t port, const AdapterPayload& adapter_payload); - void UpdateVibrations(); - - void AdapterInputThread(); - - void AdapterScanThread(); - - bool IsPayloadCorrect(const AdapterPayload& adapter_payload, s32 payload_size); - - // Updates vibration state of all controllers - void SendVibrations(); - - /// For use in initialization, querying devices to find the adapter - void Setup(); - - /// Resets status of all GC controller devices to a disconnected state - void ResetDevices(); - - /// Resets status of device connected to a disconnected state - void ResetDevice(std::size_t port); - - /// Returns true if we successfully gain access to GC Adapter - bool CheckDeviceAccess(); - - /// Captures GC Adapter endpoint address - /// Returns true if the endpoint was set correctly - bool GetGCEndpoint(libusb_device* device); - - /// For shutting down, clear all data, join all threads, release usb - void Reset(); - - // Join all threads - void JoinThreads(); - - // Release usb handles - void ClearLibusbHandle(); - - libusb_device_handle* usb_adapter_handle = nullptr; - std::array pads; - Common::SPSCQueue pad_queue; - - std::thread adapter_input_thread; - std::thread adapter_scan_thread; - bool adapter_input_thread_running; - bool adapter_scan_thread_running; - bool restart_scan_thread; - - libusb_context* libusb_ctx; - - u8 input_endpoint{0}; - u8 output_endpoint{0}; - u8 input_error_counter{0}; - u8 output_error_counter{0}; - int vibration_counter{0}; - - bool configuring{false}; - bool rumble_enabled{true}; - bool vibration_changed{true}; -}; -} // namespace GCAdapter diff --git a/src/input_common/gcadapter/gc_poller.cpp b/src/input_common/gcadapter/gc_poller.cpp deleted file mode 100644 index 1b6ded8d6..000000000 --- a/src/input_common/gcadapter/gc_poller.cpp +++ /dev/null @@ -1,356 +0,0 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include -#include -#include -#include -#include "common/assert.h" -#include "common/threadsafe_queue.h" -#include "input_common/gcadapter/gc_adapter.h" -#include "input_common/gcadapter/gc_poller.h" - -namespace InputCommon { - -class GCButton final : public Input::ButtonDevice { -public: - explicit GCButton(u32 port_, s32 button_, const GCAdapter::Adapter* adapter) - : port(port_), button(button_), gcadapter(adapter) {} - - ~GCButton() override; - - bool GetStatus() const override { - if (gcadapter->DeviceConnected(port)) { - return (gcadapter->GetPadState(port).buttons & button) != 0; - } - return false; - } - -private: - const u32 port; - const s32 button; - const GCAdapter::Adapter* gcadapter; -}; - -class GCAxisButton final : public Input::ButtonDevice { -public: - explicit GCAxisButton(u32 port_, u32 axis_, float threshold_, bool trigger_if_greater_, - const GCAdapter::Adapter* adapter) - : port(port_), axis(axis_), threshold(threshold_), trigger_if_greater(trigger_if_greater_), - gcadapter(adapter) {} - - bool GetStatus() const override { - if (gcadapter->DeviceConnected(port)) { - const float current_axis_value = gcadapter->GetPadState(port).axis_values.at(axis); - const float axis_value = current_axis_value / 128.0f; - if (trigger_if_greater) { - // TODO: Might be worthwile to set a slider for the trigger threshold. It is - // currently always set to 0.5 in configure_input_player.cpp ZL/ZR HandleClick - return axis_value > threshold; - } - return axis_value < -threshold; - } - return false; - } - -private: - const u32 port; - const u32 axis; - float threshold; - bool trigger_if_greater; - const GCAdapter::Adapter* gcadapter; -}; - -GCButtonFactory::GCButtonFactory(std::shared_ptr adapter_) - : adapter(std::move(adapter_)) {} - -GCButton::~GCButton() = default; - -std::unique_ptr GCButtonFactory::Create(const Common::ParamPackage& params) { - const auto button_id = params.Get("button", 0); - const auto port = static_cast(params.Get("port", 0)); - - constexpr s32 PAD_STICK_ID = static_cast(GCAdapter::PadButton::Stick); - - // button is not an axis/stick button - if (button_id != PAD_STICK_ID) { - return std::make_unique(port, button_id, adapter.get()); - } - - // For Axis buttons, used by the binary sticks. - if (button_id == PAD_STICK_ID) { - const int axis = params.Get("axis", 0); - const float threshold = params.Get("threshold", 0.25f); - const std::string direction_name = params.Get("direction", ""); - bool trigger_if_greater; - if (direction_name == "+") { - trigger_if_greater = true; - } else if (direction_name == "-") { - trigger_if_greater = false; - } else { - trigger_if_greater = true; - LOG_ERROR(Input, "Unknown direction {}", direction_name); - } - return std::make_unique(port, axis, threshold, trigger_if_greater, - adapter.get()); - } - - return nullptr; -} - -Common::ParamPackage GCButtonFactory::GetNextInput() const { - Common::ParamPackage params; - GCAdapter::GCPadStatus pad; - auto& queue = adapter->GetPadQueue(); - while (queue.Pop(pad)) { - // This while loop will break on the earliest detected button - params.Set("engine", "gcpad"); - params.Set("port", static_cast(pad.port)); - if (pad.button != GCAdapter::PadButton::Undefined) { - params.Set("button", static_cast(pad.button)); - } - - // For Axis button implementation - if (pad.axis != GCAdapter::PadAxes::Undefined) { - params.Set("axis", static_cast(pad.axis)); - params.Set("button", static_cast(GCAdapter::PadButton::Stick)); - params.Set("threshold", "0.25"); - if (pad.axis_value > 0) { - params.Set("direction", "+"); - } else { - params.Set("direction", "-"); - } - break; - } - } - return params; -} - -void GCButtonFactory::BeginConfiguration() { - polling = true; - adapter->BeginConfiguration(); -} - -void GCButtonFactory::EndConfiguration() { - polling = false; - adapter->EndConfiguration(); -} - -class GCAnalog final : public Input::AnalogDevice { -public: - explicit GCAnalog(u32 port_, u32 axis_x_, u32 axis_y_, bool invert_x_, bool invert_y_, - float deadzone_, float range_, const GCAdapter::Adapter* adapter) - : port(port_), axis_x(axis_x_), axis_y(axis_y_), invert_x(invert_x_), invert_y(invert_y_), - deadzone(deadzone_), range(range_), gcadapter(adapter) {} - - float GetAxis(u32 axis) const { - if (gcadapter->DeviceConnected(port)) { - std::lock_guard lock{mutex}; - const auto axis_value = - static_cast(gcadapter->GetPadState(port).axis_values.at(axis)); - return (axis_value) / (100.0f * range); - } - return 0.0f; - } - - std::pair GetAnalog(u32 analog_axis_x, u32 analog_axis_y) const { - float x = GetAxis(analog_axis_x); - float y = GetAxis(analog_axis_y); - if (invert_x) { - x = -x; - } - if (invert_y) { - y = -y; - } - // Make sure the coordinates are in the unit circle, - // otherwise normalize it. - float r = x * x + y * y; - if (r > 1.0f) { - r = std::sqrt(r); - x /= r; - y /= r; - } - - return {x, y}; - } - - std::tuple GetStatus() const override { - const auto [x, y] = GetAnalog(axis_x, axis_y); - const float r = std::sqrt((x * x) + (y * y)); - if (r > deadzone) { - return {x / r * (r - deadzone) / (1 - deadzone), - y / r * (r - deadzone) / (1 - deadzone)}; - } - return {0.0f, 0.0f}; - } - - std::tuple GetRawStatus() const override { - const float x = GetAxis(axis_x); - const float y = GetAxis(axis_y); - return {x, y}; - } - - Input::AnalogProperties GetAnalogProperties() const override { - return {deadzone, range, 0.5f}; - } - - bool GetAnalogDirectionStatus(Input::AnalogDirection direction) const override { - const auto [x, y] = GetStatus(); - const float directional_deadzone = 0.5f; - switch (direction) { - case Input::AnalogDirection::RIGHT: - return x > directional_deadzone; - case Input::AnalogDirection::LEFT: - return x < -directional_deadzone; - case Input::AnalogDirection::UP: - return y > directional_deadzone; - case Input::AnalogDirection::DOWN: - return y < -directional_deadzone; - } - return false; - } - -private: - const u32 port; - const u32 axis_x; - const u32 axis_y; - const bool invert_x; - const bool invert_y; - const float deadzone; - const float range; - const GCAdapter::Adapter* gcadapter; - mutable std::mutex mutex; -}; - -/// An analog device factory that creates analog devices from GC Adapter -GCAnalogFactory::GCAnalogFactory(std::shared_ptr adapter_) - : adapter(std::move(adapter_)) {} - -/** - * Creates analog device from joystick axes - * @param params contains parameters for creating the device: - * - "port": the nth gcpad on the adapter - * - "axis_x": the index of the axis to be bind as x-axis - * - "axis_y": the index of the axis to be bind as y-axis - */ -std::unique_ptr GCAnalogFactory::Create(const Common::ParamPackage& params) { - const auto port = static_cast(params.Get("port", 0)); - const auto axis_x = static_cast(params.Get("axis_x", 0)); - const auto axis_y = static_cast(params.Get("axis_y", 1)); - const auto deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, 1.0f); - const auto range = std::clamp(params.Get("range", 1.0f), 0.50f, 1.50f); - const std::string invert_x_value = params.Get("invert_x", "+"); - const std::string invert_y_value = params.Get("invert_y", "+"); - const bool invert_x = invert_x_value == "-"; - const bool invert_y = invert_y_value == "-"; - - return std::make_unique(port, axis_x, axis_y, invert_x, invert_y, deadzone, range, - adapter.get()); -} - -void GCAnalogFactory::BeginConfiguration() { - polling = true; - adapter->BeginConfiguration(); -} - -void GCAnalogFactory::EndConfiguration() { - polling = false; - adapter->EndConfiguration(); -} - -Common::ParamPackage GCAnalogFactory::GetNextInput() { - GCAdapter::GCPadStatus pad; - Common::ParamPackage params; - auto& queue = adapter->GetPadQueue(); - while (queue.Pop(pad)) { - if (pad.button != GCAdapter::PadButton::Undefined) { - params.Set("engine", "gcpad"); - params.Set("port", static_cast(pad.port)); - params.Set("button", static_cast(pad.button)); - return params; - } - if (pad.axis == GCAdapter::PadAxes::Undefined || - std::abs(static_cast(pad.axis_value) / 128.0f) < 0.1f) { - continue; - } - // An analog device needs two axes, so we need to store the axis for later and wait for - // a second input event. The axes also must be from the same joystick. - const u8 axis = static_cast(pad.axis); - if (axis == 0 || axis == 1) { - analog_x_axis = 0; - analog_y_axis = 1; - controller_number = static_cast(pad.port); - break; - } - if (axis == 2 || axis == 3) { - analog_x_axis = 2; - analog_y_axis = 3; - controller_number = static_cast(pad.port); - break; - } - - if (analog_x_axis == -1) { - analog_x_axis = axis; - controller_number = static_cast(pad.port); - } else if (analog_y_axis == -1 && analog_x_axis != axis && - controller_number == static_cast(pad.port)) { - analog_y_axis = axis; - break; - } - } - if (analog_x_axis != -1 && analog_y_axis != -1) { - params.Set("engine", "gcpad"); - params.Set("port", controller_number); - params.Set("axis_x", analog_x_axis); - params.Set("axis_y", analog_y_axis); - params.Set("invert_x", "+"); - params.Set("invert_y", "+"); - analog_x_axis = -1; - analog_y_axis = -1; - controller_number = -1; - return params; - } - return params; -} - -class GCVibration final : public Input::VibrationDevice { -public: - explicit GCVibration(u32 port_, GCAdapter::Adapter* adapter) - : port(port_), gcadapter(adapter) {} - - u8 GetStatus() const override { - return gcadapter->RumblePlay(port, 0); - } - - bool SetRumblePlay(f32 amp_low, [[maybe_unused]] f32 freq_low, f32 amp_high, - [[maybe_unused]] f32 freq_high) const override { - const auto mean_amplitude = (amp_low + amp_high) * 0.5f; - const auto processed_amplitude = - static_cast((mean_amplitude + std::pow(mean_amplitude, 0.3f)) * 0.5f * 0x8); - - return gcadapter->RumblePlay(port, processed_amplitude); - } - -private: - const u32 port; - GCAdapter::Adapter* gcadapter; -}; - -/// An vibration device factory that creates vibration devices from GC Adapter -GCVibrationFactory::GCVibrationFactory(std::shared_ptr adapter_) - : adapter(std::move(adapter_)) {} - -/** - * Creates a vibration device from a joystick - * @param params contains parameters for creating the device: - * - "port": the nth gcpad on the adapter - */ -std::unique_ptr GCVibrationFactory::Create( - const Common::ParamPackage& params) { - const auto port = static_cast(params.Get("port", 0)); - - return std::make_unique(port, adapter.get()); -} - -} // namespace InputCommon diff --git a/src/input_common/gcadapter/gc_poller.h b/src/input_common/gcadapter/gc_poller.h deleted file mode 100644 index d1271e3ea..000000000 --- a/src/input_common/gcadapter/gc_poller.h +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include -#include "core/frontend/input.h" -#include "input_common/gcadapter/gc_adapter.h" - -namespace InputCommon { - -/** - * A button device factory representing a gcpad. It receives gcpad events and forward them - * to all button devices it created. - */ -class GCButtonFactory final : public Input::Factory { -public: - explicit GCButtonFactory(std::shared_ptr adapter_); - - /** - * Creates a button device from a button press - * @param params contains parameters for creating the device: - * - "code": the code of the key to bind with the button - */ - std::unique_ptr Create(const Common::ParamPackage& params) override; - - Common::ParamPackage GetNextInput() const; - - /// For device input configuration/polling - void BeginConfiguration(); - void EndConfiguration(); - - bool IsPolling() const { - return polling; - } - -private: - std::shared_ptr adapter; - bool polling = false; -}; - -/// An analog device factory that creates analog devices from GC Adapter -class GCAnalogFactory final : public Input::Factory { -public: - explicit GCAnalogFactory(std::shared_ptr adapter_); - - std::unique_ptr Create(const Common::ParamPackage& params) override; - Common::ParamPackage GetNextInput(); - - /// For device input configuration/polling - void BeginConfiguration(); - void EndConfiguration(); - - bool IsPolling() const { - return polling; - } - -private: - std::shared_ptr adapter; - int analog_x_axis = -1; - int analog_y_axis = -1; - int controller_number = -1; - bool polling = false; -}; - -/// A vibration device factory creates vibration devices from GC Adapter -class GCVibrationFactory final : public Input::Factory { -public: - explicit GCVibrationFactory(std::shared_ptr adapter_); - - std::unique_ptr Create(const Common::ParamPackage& params) override; - -private: - std::shared_ptr adapter; -}; - -} // namespace InputCommon -- cgit v1.2.3 From 10241886ddbead1a24a5924debf83a4fad0ade0d Mon Sep 17 00:00:00 2001 From: german77 Date: Mon, 20 Sep 2021 17:33:19 -0500 Subject: input_common: Rewrite udp client --- src/input_common/CMakeLists.txt | 6 +- src/input_common/drivers/udp_client.cpp | 364 ++++++++++++++++++++++ src/input_common/drivers/udp_client.h | 127 ++++++++ src/input_common/udp/client.cpp | 526 -------------------------------- src/input_common/udp/client.h | 183 ----------- src/input_common/udp/udp.cpp | 110 ------- src/input_common/udp/udp.h | 57 ---- 7 files changed, 493 insertions(+), 880 deletions(-) create mode 100644 src/input_common/drivers/udp_client.cpp create mode 100644 src/input_common/drivers/udp_client.h delete mode 100644 src/input_common/udp/client.cpp delete mode 100644 src/input_common/udp/client.h delete mode 100644 src/input_common/udp/udp.cpp delete mode 100644 src/input_common/udp/udp.h (limited to 'src/input_common/drivers') diff --git a/src/input_common/CMakeLists.txt b/src/input_common/CMakeLists.txt index 19270dc84..9c0c82138 100644 --- a/src/input_common/CMakeLists.txt +++ b/src/input_common/CMakeLists.txt @@ -9,6 +9,8 @@ add_library(input_common STATIC 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 @@ -29,10 +31,6 @@ add_library(input_common STATIC motion_input.h sdl/sdl.cpp sdl/sdl.h - udp/client.cpp - udp/client.h - udp/udp.cpp - udp/udp.h ) if (MSVC) diff --git a/src/input_common/drivers/udp_client.cpp b/src/input_common/drivers/udp_client.cpp new file mode 100644 index 000000000..6fcc3a01b --- /dev/null +++ b/src/input_common/drivers/udp_client.cpp @@ -0,0 +1,364 @@ +// Copyright 2018 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include +#include + +#include "common/logging/log.h" +#include "common/param_package.h" +#include "common/settings.h" +#include "input_common/drivers/udp_client.h" +#include "input_common/helpers/udp_protocol.h" + +using boost::asio::ip::udp; + +namespace InputCommon::CemuhookUDP { + +struct SocketCallback { + std::function version; + std::function port_info; + std::function pad_data; +}; + +class Socket { +public: + using clock = std::chrono::system_clock; + + explicit Socket(const std::string& host, u16 port, SocketCallback callback_) + : callback(std::move(callback_)), timer(io_service), + socket(io_service, udp::endpoint(udp::v4(), 0)), client_id(GenerateRandomClientId()) { + boost::system::error_code ec{}; + auto ipv4 = boost::asio::ip::make_address_v4(host, ec); + if (ec.value() != boost::system::errc::success) { + LOG_ERROR(Input, "Invalid IPv4 address \"{}\" provided to socket", host); + ipv4 = boost::asio::ip::address_v4{}; + } + + send_endpoint = {udp::endpoint(ipv4, port)}; + } + + void Stop() { + io_service.stop(); + } + + void Loop() { + io_service.run(); + } + + void StartSend(const clock::time_point& from) { + timer.expires_at(from + std::chrono::seconds(3)); + timer.async_wait([this](const boost::system::error_code& error) { HandleSend(error); }); + } + + void StartReceive() { + socket.async_receive_from( + boost::asio::buffer(receive_buffer), receive_endpoint, + [this](const boost::system::error_code& error, std::size_t bytes_transferred) { + HandleReceive(error, bytes_transferred); + }); + } + +private: + u32 GenerateRandomClientId() const { + std::random_device device; + return device(); + } + + void HandleReceive(const boost::system::error_code&, std::size_t bytes_transferred) { + if (auto type = Response::Validate(receive_buffer.data(), bytes_transferred)) { + switch (*type) { + case Type::Version: { + Response::Version version; + std::memcpy(&version, &receive_buffer[sizeof(Header)], sizeof(Response::Version)); + callback.version(std::move(version)); + break; + } + case Type::PortInfo: { + Response::PortInfo port_info; + std::memcpy(&port_info, &receive_buffer[sizeof(Header)], + sizeof(Response::PortInfo)); + callback.port_info(std::move(port_info)); + break; + } + case Type::PadData: { + Response::PadData pad_data; + std::memcpy(&pad_data, &receive_buffer[sizeof(Header)], sizeof(Response::PadData)); + callback.pad_data(std::move(pad_data)); + break; + } + } + } + StartReceive(); + } + + void HandleSend(const boost::system::error_code&) { + boost::system::error_code _ignored{}; + // Send a request for getting port info for the pad + const Request::PortInfo port_info{4, {0, 1, 2, 3}}; + const auto port_message = Request::Create(port_info, client_id); + std::memcpy(&send_buffer1, &port_message, PORT_INFO_SIZE); + socket.send_to(boost::asio::buffer(send_buffer1), send_endpoint, {}, _ignored); + + // Send a request for getting pad data for the pad + const Request::PadData pad_data{ + Request::PadData::Flags::AllPorts, + 0, + EMPTY_MAC_ADDRESS, + }; + const auto pad_message = Request::Create(pad_data, client_id); + std::memcpy(send_buffer2.data(), &pad_message, PAD_DATA_SIZE); + socket.send_to(boost::asio::buffer(send_buffer2), send_endpoint, {}, _ignored); + StartSend(timer.expiry()); + } + + SocketCallback callback; + boost::asio::io_service io_service; + boost::asio::basic_waitable_timer timer; + udp::socket socket; + + const u32 client_id; + + static constexpr std::size_t PORT_INFO_SIZE = sizeof(Message); + static constexpr std::size_t PAD_DATA_SIZE = sizeof(Message); + std::array send_buffer1; + std::array send_buffer2; + udp::endpoint send_endpoint; + + std::array receive_buffer; + udp::endpoint receive_endpoint; +}; + +static void SocketLoop(Socket* socket) { + socket->StartReceive(); + socket->StartSend(Socket::clock::now()); + socket->Loop(); +} + +UDPClient::UDPClient(const std::string& input_engine_) : InputEngine(input_engine_) { + LOG_INFO(Input, "Udp Initialization started"); + ReloadSockets(); +} + +UDPClient::~UDPClient() { + Reset(); +} + +UDPClient::ClientConnection::ClientConnection() = default; + +UDPClient::ClientConnection::~ClientConnection() = default; + +void UDPClient::ReloadSockets() { + Reset(); + + std::stringstream servers_ss(Settings::values.udp_input_servers.GetValue()); + std::string server_token; + std::size_t client = 0; + while (std::getline(servers_ss, server_token, ',')) { + if (client == MAX_UDP_CLIENTS) { + break; + } + std::stringstream server_ss(server_token); + std::string token; + std::getline(server_ss, token, ':'); + std::string udp_input_address = token; + std::getline(server_ss, token, ':'); + char* temp; + const u16 udp_input_port = static_cast(std::strtol(token.c_str(), &temp, 0)); + if (*temp != '\0') { + LOG_ERROR(Input, "Port number is not valid {}", token); + continue; + } + + const std::size_t client_number = GetClientNumber(udp_input_address, udp_input_port); + if (client_number != MAX_UDP_CLIENTS) { + LOG_ERROR(Input, "Duplicated UDP servers found"); + continue; + } + StartCommunication(client++, udp_input_address, udp_input_port); + } +} + +std::size_t UDPClient::GetClientNumber(std::string_view host, u16 port) const { + for (std::size_t client = 0; client < clients.size(); client++) { + if (clients[client].active == -1) { + continue; + } + if (clients[client].host == host && clients[client].port == port) { + return client; + } + } + return MAX_UDP_CLIENTS; +} + +void UDPClient::OnVersion([[maybe_unused]] Response::Version data) { + LOG_TRACE(Input, "Version packet received: {}", data.version); +} + +void UDPClient::OnPortInfo([[maybe_unused]] Response::PortInfo data) { + LOG_TRACE(Input, "PortInfo packet received: {}", data.model); +} + +void UDPClient::OnPadData(Response::PadData data, std::size_t client) { + const std::size_t pad_index = (client * PADS_PER_CLIENT) + data.info.id; + + if (pad_index >= pads.size()) { + LOG_ERROR(Input, "Invalid pad id {}", data.info.id); + return; + } + + LOG_TRACE(Input, "PadData packet received"); + if (data.packet_counter == pads[pad_index].packet_sequence) { + LOG_WARNING( + Input, + "PadData packet dropped because its stale info. Current count: {} Packet count: {}", + pads[pad_index].packet_sequence, data.packet_counter); + pads[pad_index].connected = false; + return; + } + + clients[client].active = 1; + pads[pad_index].connected = true; + pads[pad_index].packet_sequence = data.packet_counter; + + const auto now = std::chrono::steady_clock::now(); + const auto time_difference = static_cast( + std::chrono::duration_cast(now - pads[pad_index].last_update) + .count()); + pads[pad_index].last_update = now; + + // Gyroscope values are not it the correct scale from better joy. + // Dividing by 312 allows us to make one full turn = 1 turn + // This must be a configurable valued called sensitivity + const float gyro_scale = 1.0f / 312.0f; + + const BasicMotion motion{ + .gyro_x = data.gyro.pitch * gyro_scale, + .gyro_y = data.gyro.roll * gyro_scale, + .gyro_z = -data.gyro.yaw * gyro_scale, + .accel_x = data.accel.x, + .accel_y = -data.accel.z, + .accel_z = data.accel.y, + .delta_timestamp = time_difference, + }; + const PadIdentifier identifier = GetPadIdentifier(pad_index); + SetMotion(identifier, 0, motion); +} + +void UDPClient::StartCommunication(std::size_t client, const std::string& host, u16 port) { + SocketCallback callback{[this](Response::Version version) { OnVersion(version); }, + [this](Response::PortInfo info) { OnPortInfo(info); }, + [this, client](Response::PadData data) { OnPadData(data, client); }}; + LOG_INFO(Input, "Starting communication with UDP input server on {}:{}", host, port); + clients[client].host = host; + clients[client].port = port; + clients[client].active = 0; + clients[client].socket = std::make_unique(host, port, callback); + clients[client].thread = std::thread{SocketLoop, clients[client].socket.get()}; + for (std::size_t index = 0; index < PADS_PER_CLIENT; ++index) { + const PadIdentifier identifier = GetPadIdentifier(client * PADS_PER_CLIENT + index); + PreSetController(identifier); + } +} + +const PadIdentifier UDPClient::GetPadIdentifier(std::size_t pad_index) const { + const std::size_t client = pad_index / PADS_PER_CLIENT; + return { + .guid = Common::UUID{clients[client].host}, + .port = static_cast(clients[client].port), + .pad = pad_index, + }; +} + +void UDPClient::Reset() { + for (auto& client : clients) { + if (client.thread.joinable()) { + client.active = -1; + client.socket->Stop(); + client.thread.join(); + } + } +} + +void TestCommunication(const std::string& host, u16 port, + const std::function& success_callback, + const std::function& failure_callback) { + std::thread([=] { + Common::Event success_event; + SocketCallback callback{ + .version = [](Response::Version) {}, + .port_info = [](Response::PortInfo) {}, + .pad_data = [&](Response::PadData) { success_event.Set(); }, + }; + Socket socket{host, port, std::move(callback)}; + std::thread worker_thread{SocketLoop, &socket}; + const bool result = + success_event.WaitUntil(std::chrono::steady_clock::now() + std::chrono::seconds(10)); + socket.Stop(); + worker_thread.join(); + if (result) { + success_callback(); + } else { + failure_callback(); + } + }).detach(); +} + +CalibrationConfigurationJob::CalibrationConfigurationJob( + const std::string& host, u16 port, std::function status_callback, + std::function data_callback) { + + std::thread([=, this] { + Status current_status{Status::Initialized}; + SocketCallback callback{ + [](Response::Version) {}, [](Response::PortInfo) {}, + [&](Response::PadData data) { + static constexpr u16 CALIBRATION_THRESHOLD = 100; + static constexpr u16 MAX_VALUE = UINT16_MAX; + + if (current_status == Status::Initialized) { + // Receiving data means the communication is ready now + current_status = Status::Ready; + status_callback(current_status); + } + const auto& touchpad_0 = data.touch[0]; + if (touchpad_0.is_active == 0) { + return; + } + LOG_DEBUG(Input, "Current touch: {} {}", touchpad_0.x, touchpad_0.y); + const u16 min_x = std::min(MAX_VALUE, static_cast(touchpad_0.x)); + const u16 min_y = std::min(MAX_VALUE, static_cast(touchpad_0.y)); + if (current_status == Status::Ready) { + // First touch - min data (min_x/min_y) + current_status = Status::Stage1Completed; + status_callback(current_status); + } + if (touchpad_0.x - min_x > CALIBRATION_THRESHOLD && + touchpad_0.y - min_y > CALIBRATION_THRESHOLD) { + // Set the current position as max value and finishes configuration + const u16 max_x = touchpad_0.x; + const u16 max_y = touchpad_0.y; + current_status = Status::Completed; + data_callback(min_x, min_y, max_x, max_y); + status_callback(current_status); + + complete_event.Set(); + } + }}; + Socket socket{host, port, std::move(callback)}; + std::thread worker_thread{SocketLoop, &socket}; + complete_event.Wait(); + socket.Stop(); + worker_thread.join(); + }).detach(); +} + +CalibrationConfigurationJob::~CalibrationConfigurationJob() { + Stop(); +} + +void CalibrationConfigurationJob::Stop() { + complete_event.Set(); +} + +} // namespace InputCommon::CemuhookUDP diff --git a/src/input_common/drivers/udp_client.h b/src/input_common/drivers/udp_client.h new file mode 100644 index 000000000..58b2e921d --- /dev/null +++ b/src/input_common/drivers/udp_client.h @@ -0,0 +1,127 @@ +// Copyright 2021 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included + +#pragma once + +#include + +#include "common/common_types.h" +#include "common/thread.h" +#include "input_common/input_engine.h" + +namespace InputCommon::CemuhookUDP { + +class Socket; + +namespace Response { +struct PadData; +struct PortInfo; +struct TouchPad; +struct Version; +} // namespace Response + +enum class PadTouch { + Click, + Undefined, +}; + +struct UDPPadStatus { + std::string host{"127.0.0.1"}; + u16 port{26760}; + std::size_t pad_index{}; +}; + +struct DeviceStatus { + std::mutex update_mutex; + + // calibration data for scaling the device's touch area to 3ds + struct CalibrationData { + u16 min_x{}; + u16 min_y{}; + u16 max_x{}; + u16 max_y{}; + }; + std::optional touch_calibration; +}; + +/** + * A button device factory representing a keyboard. It receives keyboard events and forward them + * to all button devices it created. + */ +class UDPClient final : public InputCommon::InputEngine { +public: + explicit UDPClient(const std::string& input_engine_); + ~UDPClient(); + + void ReloadSockets(); + +private: + struct PadData { + std::size_t pad_index{}; + bool connected{}; + DeviceStatus status; + u64 packet_sequence{}; + + std::chrono::time_point last_update; + }; + + struct ClientConnection { + ClientConnection(); + ~ClientConnection(); + std::string host{"127.0.0.1"}; + u16 port{26760}; + s8 active{-1}; + std::unique_ptr socket; + std::thread thread; + }; + + // For shutting down, clear all data, join all threads, release usb + void Reset(); + + // Translates configuration to client number + std::size_t GetClientNumber(std::string_view host, u16 port) const; + + void OnVersion(Response::Version); + void OnPortInfo(Response::PortInfo); + void OnPadData(Response::PadData, std::size_t client); + void StartCommunication(std::size_t client, const std::string& host, u16 port); + const PadIdentifier GetPadIdentifier(std::size_t pad_index) const; + + // Allocate clients for 8 udp servers + static constexpr std::size_t MAX_UDP_CLIENTS = 8; + static constexpr std::size_t PADS_PER_CLIENT = 4; + std::array pads{}; + std::array clients{}; +}; + +/// An async job allowing configuration of the touchpad calibration. +class CalibrationConfigurationJob { +public: + enum class Status { + Initialized, + Ready, + Stage1Completed, + Completed, + }; + /** + * Constructs and starts the job with the specified parameter. + * + * @param status_callback Callback for job status updates + * @param data_callback Called when calibration data is ready + */ + explicit CalibrationConfigurationJob(const std::string& host, u16 port, + std::function status_callback, + std::function data_callback); + ~CalibrationConfigurationJob(); + void Stop(); + +private: + Common::Event complete_event; +}; + +void TestCommunication(const std::string& host, u16 port, + const std::function& success_callback, + const std::function& failure_callback); + +} // namespace InputCommon::CemuhookUDP diff --git a/src/input_common/udp/client.cpp b/src/input_common/udp/client.cpp deleted file mode 100644 index bcc29c4e0..000000000 --- a/src/input_common/udp/client.cpp +++ /dev/null @@ -1,526 +0,0 @@ -// Copyright 2018 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include -#include -#include -#include -#include -#include -#include "common/logging/log.h" -#include "common/settings.h" -#include "input_common/udp/client.h" -#include "input_common/helpers/udp_protocol.h" - -using boost::asio::ip::udp; - -namespace InputCommon::CemuhookUDP { - -struct SocketCallback { - std::function version; - std::function port_info; - std::function pad_data; -}; - -class Socket { -public: - using clock = std::chrono::system_clock; - - explicit Socket(const std::string& host, u16 port, SocketCallback callback_) - : callback(std::move(callback_)), timer(io_service), - socket(io_service, udp::endpoint(udp::v4(), 0)), client_id(GenerateRandomClientId()) { - boost::system::error_code ec{}; - auto ipv4 = boost::asio::ip::make_address_v4(host, ec); - if (ec.value() != boost::system::errc::success) { - LOG_ERROR(Input, "Invalid IPv4 address \"{}\" provided to socket", host); - ipv4 = boost::asio::ip::address_v4{}; - } - - send_endpoint = {udp::endpoint(ipv4, port)}; - } - - void Stop() { - io_service.stop(); - } - - void Loop() { - io_service.run(); - } - - void StartSend(const clock::time_point& from) { - timer.expires_at(from + std::chrono::seconds(3)); - timer.async_wait([this](const boost::system::error_code& error) { HandleSend(error); }); - } - - void StartReceive() { - socket.async_receive_from( - boost::asio::buffer(receive_buffer), receive_endpoint, - [this](const boost::system::error_code& error, std::size_t bytes_transferred) { - HandleReceive(error, bytes_transferred); - }); - } - -private: - u32 GenerateRandomClientId() const { - std::random_device device; - return device(); - } - - void HandleReceive(const boost::system::error_code&, std::size_t bytes_transferred) { - if (auto type = Response::Validate(receive_buffer.data(), bytes_transferred)) { - switch (*type) { - case Type::Version: { - Response::Version version; - std::memcpy(&version, &receive_buffer[sizeof(Header)], sizeof(Response::Version)); - callback.version(std::move(version)); - break; - } - case Type::PortInfo: { - Response::PortInfo port_info; - std::memcpy(&port_info, &receive_buffer[sizeof(Header)], - sizeof(Response::PortInfo)); - callback.port_info(std::move(port_info)); - break; - } - case Type::PadData: { - Response::PadData pad_data; - std::memcpy(&pad_data, &receive_buffer[sizeof(Header)], sizeof(Response::PadData)); - SanitizeMotion(pad_data); - callback.pad_data(std::move(pad_data)); - break; - } - } - } - StartReceive(); - } - - void HandleSend(const boost::system::error_code&) { - boost::system::error_code _ignored{}; - // Send a request for getting port info for the pad - const Request::PortInfo port_info{4, {0, 1, 2, 3}}; - const auto port_message = Request::Create(port_info, client_id); - std::memcpy(&send_buffer1, &port_message, PORT_INFO_SIZE); - socket.send_to(boost::asio::buffer(send_buffer1), send_endpoint, {}, _ignored); - - // Send a request for getting pad data for the pad - const Request::PadData pad_data{ - Request::PadData::Flags::AllPorts, - 0, - EMPTY_MAC_ADDRESS, - }; - const auto pad_message = Request::Create(pad_data, client_id); - std::memcpy(send_buffer2.data(), &pad_message, PAD_DATA_SIZE); - socket.send_to(boost::asio::buffer(send_buffer2), send_endpoint, {}, _ignored); - StartSend(timer.expiry()); - } - - void SanitizeMotion(Response::PadData& data) { - // Zero out any non number value - if (!std::isnormal(data.gyro.pitch)) { - data.gyro.pitch = 0; - } - if (!std::isnormal(data.gyro.roll)) { - data.gyro.roll = 0; - } - if (!std::isnormal(data.gyro.yaw)) { - data.gyro.yaw = 0; - } - if (!std::isnormal(data.accel.x)) { - data.accel.x = 0; - } - if (!std::isnormal(data.accel.y)) { - data.accel.y = 0; - } - if (!std::isnormal(data.accel.z)) { - data.accel.z = 0; - } - } - - SocketCallback callback; - boost::asio::io_service io_service; - boost::asio::basic_waitable_timer timer; - udp::socket socket; - - const u32 client_id; - - static constexpr std::size_t PORT_INFO_SIZE = sizeof(Message); - static constexpr std::size_t PAD_DATA_SIZE = sizeof(Message); - std::array send_buffer1; - std::array send_buffer2; - udp::endpoint send_endpoint; - - std::array receive_buffer; - udp::endpoint receive_endpoint; -}; - -static void SocketLoop(Socket* socket) { - socket->StartReceive(); - socket->StartSend(Socket::clock::now()); - socket->Loop(); -} - -Client::Client() { - LOG_INFO(Input, "Udp Initialization started"); - finger_id.fill(MAX_TOUCH_FINGERS); - ReloadSockets(); -} - -Client::~Client() { - Reset(); -} - -Client::ClientConnection::ClientConnection() = default; - -Client::ClientConnection::~ClientConnection() = default; - -std::vector Client::GetInputDevices() const { - std::vector devices; - for (std::size_t pad = 0; pad < pads.size(); pad++) { - if (!DeviceConnected(pad)) { - continue; - } - std::string name = fmt::format("UDP Controller {}", pad); - devices.emplace_back(Common::ParamPackage{ - {"class", "cemuhookudp"}, - {"display", std::move(name)}, - {"port", std::to_string(pad)}, - }); - } - return devices; -} - -bool Client::DeviceConnected(std::size_t pad) const { - // Use last timestamp to detect if the socket has stopped sending data - const auto now = std::chrono::steady_clock::now(); - const auto time_difference = static_cast( - std::chrono::duration_cast(now - pads[pad].last_update).count()); - return time_difference < 1000 && pads[pad].connected; -} - -void Client::ReloadSockets() { - Reset(); - - std::stringstream servers_ss(static_cast(Settings::values.udp_input_servers)); - std::string server_token; - std::size_t client = 0; - while (std::getline(servers_ss, server_token, ',')) { - if (client == MAX_UDP_CLIENTS) { - break; - } - std::stringstream server_ss(server_token); - std::string token; - std::getline(server_ss, token, ':'); - std::string udp_input_address = token; - std::getline(server_ss, token, ':'); - char* temp; - const u16 udp_input_port = static_cast(std::strtol(token.c_str(), &temp, 0)); - if (*temp != '\0') { - LOG_ERROR(Input, "Port number is not valid {}", token); - continue; - } - - const std::size_t client_number = GetClientNumber(udp_input_address, udp_input_port); - if (client_number != MAX_UDP_CLIENTS) { - LOG_ERROR(Input, "Duplicated UDP servers found"); - continue; - } - StartCommunication(client++, udp_input_address, udp_input_port); - } -} - -std::size_t Client::GetClientNumber(std::string_view host, u16 port) const { - for (std::size_t client = 0; client < clients.size(); client++) { - if (clients[client].active == -1) { - continue; - } - if (clients[client].host == host && clients[client].port == port) { - return client; - } - } - return MAX_UDP_CLIENTS; -} - -void Client::OnVersion([[maybe_unused]] Response::Version data) { - LOG_TRACE(Input, "Version packet received: {}", data.version); -} - -void Client::OnPortInfo([[maybe_unused]] Response::PortInfo data) { - LOG_TRACE(Input, "PortInfo packet received: {}", data.model); -} - -void Client::OnPadData(Response::PadData data, std::size_t client) { - const std::size_t pad_index = (client * PADS_PER_CLIENT) + data.info.id; - - if (pad_index >= pads.size()) { - LOG_ERROR(Input, "Invalid pad id {}", data.info.id); - return; - } - - LOG_TRACE(Input, "PadData packet received"); - if (data.packet_counter == pads[pad_index].packet_sequence) { - LOG_WARNING( - Input, - "PadData packet dropped because its stale info. Current count: {} Packet count: {}", - pads[pad_index].packet_sequence, data.packet_counter); - pads[pad_index].connected = false; - return; - } - - clients[client].active = 1; - pads[pad_index].connected = true; - pads[pad_index].packet_sequence = data.packet_counter; - - const auto now = std::chrono::steady_clock::now(); - const auto time_difference = static_cast( - std::chrono::duration_cast(now - pads[pad_index].last_update) - .count()); - pads[pad_index].last_update = now; - - const Common::Vec3f raw_gyroscope = {data.gyro.pitch, data.gyro.roll, -data.gyro.yaw}; - pads[pad_index].motion.SetAcceleration({data.accel.x, -data.accel.z, data.accel.y}); - // Gyroscope values are not it the correct scale from better joy. - // Dividing by 312 allows us to make one full turn = 1 turn - // This must be a configurable valued called sensitivity - pads[pad_index].motion.SetGyroscope(raw_gyroscope / 312.0f); - pads[pad_index].motion.UpdateRotation(time_difference); - pads[pad_index].motion.UpdateOrientation(time_difference); - - { - std::lock_guard guard(pads[pad_index].status.update_mutex); - pads[pad_index].status.motion_status = pads[pad_index].motion.GetMotion(); - - for (std::size_t id = 0; id < data.touch.size(); ++id) { - UpdateTouchInput(data.touch[id], client, id); - } - - if (configuring) { - const Common::Vec3f gyroscope = pads[pad_index].motion.GetGyroscope(); - const Common::Vec3f accelerometer = pads[pad_index].motion.GetAcceleration(); - UpdateYuzuSettings(client, data.info.id, accelerometer, gyroscope); - } - } -} - -void Client::StartCommunication(std::size_t client, const std::string& host, u16 port) { - SocketCallback callback{[this](Response::Version version) { OnVersion(version); }, - [this](Response::PortInfo info) { OnPortInfo(info); }, - [this, client](Response::PadData data) { OnPadData(data, client); }}; - LOG_INFO(Input, "Starting communication with UDP input server on {}:{}", host, port); - clients[client].host = host; - clients[client].port = port; - clients[client].active = 0; - clients[client].socket = std::make_unique(host, port, callback); - clients[client].thread = std::thread{SocketLoop, clients[client].socket.get()}; - - // Set motion parameters - // SetGyroThreshold value should be dependent on GyroscopeZeroDriftMode - // Real HW values are unknown, 0.0001 is an approximate to Standard - for (std::size_t pad = 0; pad < PADS_PER_CLIENT; pad++) { - pads[client * PADS_PER_CLIENT + pad].motion.SetGyroThreshold(0.0001f); - } -} - -void Client::Reset() { - for (auto& client : clients) { - if (client.thread.joinable()) { - client.active = -1; - client.socket->Stop(); - client.thread.join(); - } - } -} - -void Client::UpdateYuzuSettings(std::size_t client, std::size_t pad_index, - const Common::Vec3& acc, const Common::Vec3& gyro) { - if (gyro.Length() > 0.2f) { - LOG_DEBUG(Input, "UDP Controller {}: gyro=({}, {}, {}), accel=({}, {}, {})", client, - gyro[0], gyro[1], gyro[2], acc[0], acc[1], acc[2]); - } - UDPPadStatus pad{ - .host = clients[client].host, - .port = clients[client].port, - .pad_index = pad_index, - }; - for (std::size_t i = 0; i < 3; ++i) { - if (gyro[i] > 5.0f || gyro[i] < -5.0f) { - pad.motion = static_cast(i); - pad.motion_value = gyro[i]; - pad_queue.Push(pad); - } - if (acc[i] > 1.75f || acc[i] < -1.75f) { - pad.motion = static_cast(i + 3); - pad.motion_value = acc[i]; - pad_queue.Push(pad); - } - } -} - -std::optional Client::GetUnusedFingerID() const { - std::size_t first_free_id = 0; - while (first_free_id < MAX_TOUCH_FINGERS) { - if (!std::get<2>(touch_status[first_free_id])) { - return first_free_id; - } else { - first_free_id++; - } - } - return std::nullopt; -} - -void Client::UpdateTouchInput(Response::TouchPad& touch_pad, std::size_t client, std::size_t id) { - // TODO: Use custom calibration per device - const Common::ParamPackage touch_param(Settings::values.touch_device.GetValue()); - const u16 min_x = static_cast(touch_param.Get("min_x", 100)); - const u16 min_y = static_cast(touch_param.Get("min_y", 50)); - const u16 max_x = static_cast(touch_param.Get("max_x", 1800)); - const u16 max_y = static_cast(touch_param.Get("max_y", 850)); - const std::size_t touch_id = client * 2 + id; - if (touch_pad.is_active) { - if (finger_id[touch_id] == MAX_TOUCH_FINGERS) { - const auto first_free_id = GetUnusedFingerID(); - if (!first_free_id) { - // Invalid finger id skip to next input - return; - } - finger_id[touch_id] = *first_free_id; - } - auto& [x, y, pressed] = touch_status[finger_id[touch_id]]; - x = static_cast(std::clamp(static_cast(touch_pad.x), min_x, max_x) - min_x) / - static_cast(max_x - min_x); - y = static_cast(std::clamp(static_cast(touch_pad.y), min_y, max_y) - min_y) / - static_cast(max_y - min_y); - pressed = true; - return; - } - - if (finger_id[touch_id] != MAX_TOUCH_FINGERS) { - touch_status[finger_id[touch_id]] = {}; - finger_id[touch_id] = MAX_TOUCH_FINGERS; - } -} - -void Client::BeginConfiguration() { - pad_queue.Clear(); - configuring = true; -} - -void Client::EndConfiguration() { - pad_queue.Clear(); - configuring = false; -} - -DeviceStatus& Client::GetPadState(const std::string& host, u16 port, std::size_t pad) { - const std::size_t client_number = GetClientNumber(host, port); - if (client_number == MAX_UDP_CLIENTS || pad >= PADS_PER_CLIENT) { - return pads[0].status; - } - return pads[(client_number * PADS_PER_CLIENT) + pad].status; -} - -const DeviceStatus& Client::GetPadState(const std::string& host, u16 port, std::size_t pad) const { - const std::size_t client_number = GetClientNumber(host, port); - if (client_number == MAX_UDP_CLIENTS || pad >= PADS_PER_CLIENT) { - return pads[0].status; - } - return pads[(client_number * PADS_PER_CLIENT) + pad].status; -} - -Input::TouchStatus& Client::GetTouchState() { - return touch_status; -} - -const Input::TouchStatus& Client::GetTouchState() const { - return touch_status; -} - -Common::SPSCQueue& Client::GetPadQueue() { - return pad_queue; -} - -const Common::SPSCQueue& Client::GetPadQueue() const { - return pad_queue; -} - -void TestCommunication(const std::string& host, u16 port, - const std::function& success_callback, - const std::function& failure_callback) { - std::thread([=] { - Common::Event success_event; - SocketCallback callback{ - .version = [](Response::Version) {}, - .port_info = [](Response::PortInfo) {}, - .pad_data = [&](Response::PadData) { success_event.Set(); }, - }; - Socket socket{host, port, std::move(callback)}; - std::thread worker_thread{SocketLoop, &socket}; - const bool result = - success_event.WaitUntil(std::chrono::steady_clock::now() + std::chrono::seconds(10)); - socket.Stop(); - worker_thread.join(); - if (result) { - success_callback(); - } else { - failure_callback(); - } - }).detach(); -} - -CalibrationConfigurationJob::CalibrationConfigurationJob( - const std::string& host, u16 port, std::function status_callback, - std::function data_callback) { - - std::thread([=, this] { - Status current_status{Status::Initialized}; - SocketCallback callback{ - [](Response::Version) {}, [](Response::PortInfo) {}, - [&](Response::PadData data) { - static constexpr u16 CALIBRATION_THRESHOLD = 100; - static constexpr u16 MAX_VALUE = UINT16_MAX; - - if (current_status == Status::Initialized) { - // Receiving data means the communication is ready now - current_status = Status::Ready; - status_callback(current_status); - } - const auto& touchpad_0 = data.touch[0]; - if (touchpad_0.is_active == 0) { - return; - } - LOG_DEBUG(Input, "Current touch: {} {}", touchpad_0.x, touchpad_0.y); - const u16 min_x = std::min(MAX_VALUE, static_cast(touchpad_0.x)); - const u16 min_y = std::min(MAX_VALUE, static_cast(touchpad_0.y)); - if (current_status == Status::Ready) { - // First touch - min data (min_x/min_y) - current_status = Status::Stage1Completed; - status_callback(current_status); - } - if (touchpad_0.x - min_x > CALIBRATION_THRESHOLD && - touchpad_0.y - min_y > CALIBRATION_THRESHOLD) { - // Set the current position as max value and finishes configuration - const u16 max_x = touchpad_0.x; - const u16 max_y = touchpad_0.y; - current_status = Status::Completed; - data_callback(min_x, min_y, max_x, max_y); - status_callback(current_status); - - complete_event.Set(); - } - }}; - Socket socket{host, port, std::move(callback)}; - std::thread worker_thread{SocketLoop, &socket}; - complete_event.Wait(); - socket.Stop(); - worker_thread.join(); - }).detach(); -} - -CalibrationConfigurationJob::~CalibrationConfigurationJob() { - Stop(); -} - -void CalibrationConfigurationJob::Stop() { - complete_event.Set(); -} - -} // namespace InputCommon::CemuhookUDP diff --git a/src/input_common/udp/client.h b/src/input_common/udp/client.h deleted file mode 100644 index 380f9bb76..000000000 --- a/src/input_common/udp/client.h +++ /dev/null @@ -1,183 +0,0 @@ -// Copyright 2018 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include "common/common_types.h" -#include "common/param_package.h" -#include "common/thread.h" -#include "common/threadsafe_queue.h" -#include "common/vector_math.h" -#include "core/frontend/input.h" -#include "input_common/motion_input.h" - -namespace InputCommon::CemuhookUDP { - -class Socket; - -namespace Response { -struct PadData; -struct PortInfo; -struct TouchPad; -struct Version; -} // namespace Response - -enum class PadMotion { - GyroX, - GyroY, - GyroZ, - AccX, - AccY, - AccZ, - Undefined, -}; - -enum class PadTouch { - Click, - Undefined, -}; - -struct UDPPadStatus { - std::string host{"127.0.0.1"}; - u16 port{26760}; - std::size_t pad_index{}; - PadMotion motion{PadMotion::Undefined}; - f32 motion_value{0.0f}; -}; - -struct DeviceStatus { - std::mutex update_mutex; - Input::MotionStatus motion_status; - std::tuple touch_status; - - // calibration data for scaling the device's touch area to 3ds - struct CalibrationData { - u16 min_x{}; - u16 min_y{}; - u16 max_x{}; - u16 max_y{}; - }; - std::optional touch_calibration; -}; - -class Client { -public: - // Initialize the UDP client capture and read sequence - Client(); - - // Close and release the client - ~Client(); - - // Used for polling - void BeginConfiguration(); - void EndConfiguration(); - - std::vector GetInputDevices() const; - - bool DeviceConnected(std::size_t pad) const; - void ReloadSockets(); - - Common::SPSCQueue& GetPadQueue(); - const Common::SPSCQueue& GetPadQueue() const; - - DeviceStatus& GetPadState(const std::string& host, u16 port, std::size_t pad); - const DeviceStatus& GetPadState(const std::string& host, u16 port, std::size_t pad) const; - - Input::TouchStatus& GetTouchState(); - const Input::TouchStatus& GetTouchState() const; - -private: - struct PadData { - std::size_t pad_index{}; - bool connected{}; - DeviceStatus status; - u64 packet_sequence{}; - - // Realtime values - // motion is initalized with PID values for drift correction on joycons - InputCommon::MotionInput motion{0.3f, 0.005f, 0.0f}; - std::chrono::time_point last_update; - }; - - struct ClientConnection { - ClientConnection(); - ~ClientConnection(); - std::string host{"127.0.0.1"}; - u16 port{26760}; - s8 active{-1}; - std::unique_ptr socket; - std::thread thread; - }; - - // For shutting down, clear all data, join all threads, release usb - void Reset(); - - // Translates configuration to client number - std::size_t GetClientNumber(std::string_view host, u16 port) const; - - void OnVersion(Response::Version); - void OnPortInfo(Response::PortInfo); - void OnPadData(Response::PadData, std::size_t client); - void StartCommunication(std::size_t client, const std::string& host, u16 port); - void UpdateYuzuSettings(std::size_t client, std::size_t pad_index, - const Common::Vec3& acc, const Common::Vec3& gyro); - - // Returns an unused finger id, if there is no fingers available std::nullopt will be - // returned - std::optional GetUnusedFingerID() const; - - // Merges and updates all touch inputs into the touch_status array - void UpdateTouchInput(Response::TouchPad& touch_pad, std::size_t client, std::size_t id); - - bool configuring = false; - - // Allocate clients for 8 udp servers - static constexpr std::size_t MAX_UDP_CLIENTS = 8; - static constexpr std::size_t PADS_PER_CLIENT = 4; - // Each client can have up 2 touch inputs - static constexpr std::size_t MAX_TOUCH_FINGERS = MAX_UDP_CLIENTS * 2; - std::array pads{}; - std::array clients{}; - Common::SPSCQueue pad_queue{}; - Input::TouchStatus touch_status{}; - std::array finger_id{}; -}; - -/// An async job allowing configuration of the touchpad calibration. -class CalibrationConfigurationJob { -public: - enum class Status { - Initialized, - Ready, - Stage1Completed, - Completed, - }; - /** - * Constructs and starts the job with the specified parameter. - * - * @param status_callback Callback for job status updates - * @param data_callback Called when calibration data is ready - */ - explicit CalibrationConfigurationJob(const std::string& host, u16 port, - std::function status_callback, - std::function data_callback); - ~CalibrationConfigurationJob(); - void Stop(); - -private: - Common::Event complete_event; -}; - -void TestCommunication(const std::string& host, u16 port, - const std::function& success_callback, - const std::function& failure_callback); - -} // namespace InputCommon::CemuhookUDP diff --git a/src/input_common/udp/udp.cpp b/src/input_common/udp/udp.cpp deleted file mode 100644 index 9829da6f0..000000000 --- a/src/input_common/udp/udp.cpp +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include -#include -#include "common/assert.h" -#include "common/threadsafe_queue.h" -#include "input_common/udp/client.h" -#include "input_common/udp/udp.h" - -namespace InputCommon { - -class UDPMotion final : public Input::MotionDevice { -public: - explicit UDPMotion(std::string ip_, u16 port_, u16 pad_, CemuhookUDP::Client* client_) - : ip(std::move(ip_)), port(port_), pad(pad_), client(client_) {} - - Input::MotionStatus GetStatus() const override { - return client->GetPadState(ip, port, pad).motion_status; - } - -private: - const std::string ip; - const u16 port; - const u16 pad; - CemuhookUDP::Client* client; - mutable std::mutex mutex; -}; - -/// A motion device factory that creates motion devices from a UDP client -UDPMotionFactory::UDPMotionFactory(std::shared_ptr client_) - : client(std::move(client_)) {} - -/** - * Creates motion device - * @param params contains parameters for creating the device: - * - "port": the UDP port number - */ -std::unique_ptr UDPMotionFactory::Create(const Common::ParamPackage& params) { - auto ip = params.Get("ip", "127.0.0.1"); - const auto port = static_cast(params.Get("port", 26760)); - const auto pad = static_cast(params.Get("pad_index", 0)); - - return std::make_unique(std::move(ip), port, pad, client.get()); -} - -void UDPMotionFactory::BeginConfiguration() { - polling = true; - client->BeginConfiguration(); -} - -void UDPMotionFactory::EndConfiguration() { - polling = false; - client->EndConfiguration(); -} - -Common::ParamPackage UDPMotionFactory::GetNextInput() { - Common::ParamPackage params; - CemuhookUDP::UDPPadStatus pad; - auto& queue = client->GetPadQueue(); - while (queue.Pop(pad)) { - if (pad.motion == CemuhookUDP::PadMotion::Undefined || std::abs(pad.motion_value) < 1) { - continue; - } - params.Set("engine", "cemuhookudp"); - params.Set("ip", pad.host); - params.Set("port", static_cast(pad.port)); - params.Set("pad_index", static_cast(pad.pad_index)); - params.Set("motion", static_cast(pad.motion)); - return params; - } - return params; -} - -class UDPTouch final : public Input::TouchDevice { -public: - explicit UDPTouch(std::string ip_, u16 port_, u16 pad_, CemuhookUDP::Client* client_) - : ip(std::move(ip_)), port(port_), pad(pad_), client(client_) {} - - Input::TouchStatus GetStatus() const override { - return client->GetTouchState(); - } - -private: - const std::string ip; - [[maybe_unused]] const u16 port; - [[maybe_unused]] const u16 pad; - CemuhookUDP::Client* client; - mutable std::mutex mutex; -}; - -/// A motion device factory that creates motion devices from a UDP client -UDPTouchFactory::UDPTouchFactory(std::shared_ptr client_) - : client(std::move(client_)) {} - -/** - * Creates motion device - * @param params contains parameters for creating the device: - * - "port": the UDP port number - */ -std::unique_ptr UDPTouchFactory::Create(const Common::ParamPackage& params) { - auto ip = params.Get("ip", "127.0.0.1"); - const auto port = static_cast(params.Get("port", 26760)); - const auto pad = static_cast(params.Get("pad_index", 0)); - - return std::make_unique(std::move(ip), port, pad, client.get()); -} - -} // namespace InputCommon diff --git a/src/input_common/udp/udp.h b/src/input_common/udp/udp.h deleted file mode 100644 index ea3fd4175..000000000 --- a/src/input_common/udp/udp.h +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2020 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include -#include "core/frontend/input.h" -#include "input_common/udp/client.h" - -namespace InputCommon { - -/// A motion device factory that creates motion devices from udp clients -class UDPMotionFactory final : public Input::Factory { -public: - explicit UDPMotionFactory(std::shared_ptr client_); - - std::unique_ptr Create(const Common::ParamPackage& params) override; - - Common::ParamPackage GetNextInput(); - - /// For device input configuration/polling - void BeginConfiguration(); - void EndConfiguration(); - - bool IsPolling() const { - return polling; - } - -private: - std::shared_ptr client; - bool polling = false; -}; - -/// A touch device factory that creates touch devices from udp clients -class UDPTouchFactory final : public Input::Factory { -public: - explicit UDPTouchFactory(std::shared_ptr client_); - - std::unique_ptr Create(const Common::ParamPackage& params) override; - - Common::ParamPackage GetNextInput(); - - /// For device input configuration/polling - void BeginConfiguration(); - void EndConfiguration(); - - bool IsPolling() const { - return polling; - } - -private: - std::shared_ptr client; - bool polling = false; -}; - -} // namespace InputCommon -- cgit v1.2.3 From 59b995a9e53f09b9831b03608cfe5ce27c3e3485 Mon Sep 17 00:00:00 2001 From: german77 Date: Mon, 20 Sep 2021 17:36:23 -0500 Subject: input_common: Rewrite SDL --- src/input_common/CMakeLists.txt | 8 +- src/input_common/drivers/sdl_driver.cpp | 915 +++++++++++++++++ src/input_common/drivers/sdl_driver.h | 120 +++ src/input_common/sdl/sdl.cpp | 19 - src/input_common/sdl/sdl.h | 51 - src/input_common/sdl/sdl_impl.cpp | 1658 ------------------------------- src/input_common/sdl/sdl_impl.h | 114 --- 7 files changed, 1039 insertions(+), 1846 deletions(-) create mode 100644 src/input_common/drivers/sdl_driver.cpp create mode 100644 src/input_common/drivers/sdl_driver.h delete mode 100644 src/input_common/sdl/sdl.cpp delete mode 100644 src/input_common/sdl/sdl.h delete mode 100644 src/input_common/sdl/sdl_impl.cpp delete mode 100644 src/input_common/sdl/sdl_impl.h (limited to 'src/input_common/drivers') diff --git a/src/input_common/CMakeLists.txt b/src/input_common/CMakeLists.txt index 9c0c82138..8cdcd315b 100644 --- a/src/input_common/CMakeLists.txt +++ b/src/input_common/CMakeLists.txt @@ -5,6 +5,8 @@ add_library(input_common STATIC 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 @@ -29,8 +31,6 @@ add_library(input_common STATIC motion_from_button.h motion_input.cpp motion_input.h - sdl/sdl.cpp - sdl/sdl.h ) if (MSVC) @@ -57,8 +57,8 @@ endif() if (ENABLE_SDL2) target_sources(input_common PRIVATE - sdl/sdl_impl.cpp - sdl/sdl_impl.h + drivers/sdl_driver.cpp + drivers/sdl_driver.h ) target_link_libraries(input_common PRIVATE SDL2) target_compile_definitions(input_common PRIVATE HAVE_SDL2) diff --git a/src/input_common/drivers/sdl_driver.cpp b/src/input_common/drivers/sdl_driver.cpp new file mode 100644 index 000000000..efb4a2106 --- /dev/null +++ b/src/input_common/drivers/sdl_driver.cpp @@ -0,0 +1,915 @@ +// Copyright 2018 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/logging/log.h" +#include "common/math_util.h" +#include "common/param_package.h" +#include "common/settings.h" +#include "common/thread.h" +#include "common/vector_math.h" +#include "input_common/drivers/sdl_driver.h" + +namespace InputCommon { + +namespace { +std::string GetGUID(SDL_Joystick* joystick) { + const SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick); + char guid_str[33]; + SDL_JoystickGetGUIDString(guid, guid_str, sizeof(guid_str)); + return guid_str; +} +} // Anonymous namespace + +static int SDLEventWatcher(void* user_data, SDL_Event* event) { + auto* const sdl_state = static_cast(user_data); + + sdl_state->HandleGameControllerEvent(*event); + + return 0; +} + +class SDLJoystick { +public: + SDLJoystick(std::string guid_, int port_, SDL_Joystick* joystick, + SDL_GameController* game_controller) + : guid{std::move(guid_)}, port{port_}, sdl_joystick{joystick, &SDL_JoystickClose}, + sdl_controller{game_controller, &SDL_GameControllerClose} { + EnableMotion(); + } + + void EnableMotion() { + if (sdl_controller) { + SDL_GameController* controller = sdl_controller.get(); + if (SDL_GameControllerHasSensor(controller, SDL_SENSOR_ACCEL) && !has_accel) { + SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_ACCEL, SDL_TRUE); + has_accel = true; + } + if (SDL_GameControllerHasSensor(controller, SDL_SENSOR_GYRO) && !has_gyro) { + SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_GYRO, SDL_TRUE); + has_gyro = true; + } + } + } + + bool HasGyro() const { + return has_gyro; + } + + bool HasAccel() const { + return has_accel; + } + + bool UpdateMotion(SDL_ControllerSensorEvent event) { + constexpr float gravity_constant = 9.80665f; + std::lock_guard lock{mutex}; + const u64 time_difference = event.timestamp - last_motion_update; + last_motion_update = event.timestamp; + switch (event.sensor) { + case SDL_SENSOR_ACCEL: { + motion.accel_x = -event.data[0] / gravity_constant; + motion.accel_y = event.data[2] / gravity_constant; + motion.accel_z = -event.data[1] / gravity_constant; + break; + } + case SDL_SENSOR_GYRO: { + motion.gyro_x = event.data[0] / (Common::PI * 2); + motion.gyro_y = -event.data[2] / (Common::PI * 2); + motion.gyro_z = event.data[1] / (Common::PI * 2); + break; + } + } + + // Ignore duplicated timestamps + if (time_difference == 0) { + return false; + } + motion.delta_timestamp = time_difference * 1000; + return true; + } + + BasicMotion GetMotion() { + return motion; + } + + bool RumblePlay(const Input::VibrationStatus vibration) { + constexpr u32 rumble_max_duration_ms = 1000; + + if (sdl_controller) { + return SDL_GameControllerRumble( + sdl_controller.get(), static_cast(vibration.low_amplitude), + static_cast(vibration.high_amplitude), rumble_max_duration_ms) != -1; + } else if (sdl_joystick) { + return SDL_JoystickRumble(sdl_joystick.get(), static_cast(vibration.low_amplitude), + static_cast(vibration.high_amplitude), + rumble_max_duration_ms) != -1; + } + + return false; + } + /** + * The Pad identifier of the joystick + */ + const PadIdentifier GetPadIdentifier() const { + return { + .guid = Common::UUID{guid}, + .port = static_cast(port), + .pad = 0, + }; + } + + /** + * The guid of the joystick + */ + const std::string& GetGUID() const { + return guid; + } + + /** + * The number of joystick from the same type that were connected before this joystick + */ + int GetPort() const { + return port; + } + + SDL_Joystick* GetSDLJoystick() const { + return sdl_joystick.get(); + } + + SDL_GameController* GetSDLGameController() const { + return sdl_controller.get(); + } + + void SetSDLJoystick(SDL_Joystick* joystick, SDL_GameController* controller) { + sdl_joystick.reset(joystick); + sdl_controller.reset(controller); + } + + bool IsJoyconLeft() const { + const std::string controller_name = GetControllerName(); + if (std::strstr(controller_name.c_str(), "Joy-Con Left") != nullptr) { + return true; + } + if (std::strstr(controller_name.c_str(), "Joy-Con (L)") != nullptr) { + return true; + } + return false; + } + + bool IsJoyconRight() const { + const std::string controller_name = GetControllerName(); + if (std::strstr(controller_name.c_str(), "Joy-Con Right") != nullptr) { + return true; + } + if (std::strstr(controller_name.c_str(), "Joy-Con (R)") != nullptr) { + return true; + } + return false; + } + + BatteryLevel GetBatteryLevel() { + const auto level = SDL_JoystickCurrentPowerLevel(sdl_joystick.get()); + switch (level) { + case SDL_JOYSTICK_POWER_EMPTY: + return BatteryLevel::Empty; + case SDL_JOYSTICK_POWER_LOW: + return BatteryLevel::Critical; + case SDL_JOYSTICK_POWER_MEDIUM: + return BatteryLevel::Low; + case SDL_JOYSTICK_POWER_FULL: + return BatteryLevel::Medium; + case SDL_JOYSTICK_POWER_MAX: + return BatteryLevel::Full; + case SDL_JOYSTICK_POWER_UNKNOWN: + case SDL_JOYSTICK_POWER_WIRED: + default: + return BatteryLevel::Charging; + } + } + + std::string GetControllerName() const { + if (sdl_controller) { + switch (SDL_GameControllerGetType(sdl_controller.get())) { + case SDL_CONTROLLER_TYPE_XBOX360: + return "XBox 360 Controller"; + case SDL_CONTROLLER_TYPE_XBOXONE: + return "XBox One Controller"; + default: + break; + } + const auto name = SDL_GameControllerName(sdl_controller.get()); + if (name) { + return name; + } + } + + if (sdl_joystick) { + const auto name = SDL_JoystickName(sdl_joystick.get()); + if (name) { + return name; + } + } + + return "Unknown"; + } + + bool IsYAxis(u8 index) { + if (!sdl_controller) { + return false; + } + + const auto& binding_left_y = + SDL_GameControllerGetBindForAxis(sdl_controller.get(), SDL_CONTROLLER_AXIS_LEFTY); + const auto& binding_right_y = + SDL_GameControllerGetBindForAxis(sdl_controller.get(), SDL_CONTROLLER_AXIS_RIGHTY); + if (index == binding_left_y.value.axis) { + return true; + } + if (index == binding_right_y.value.axis) { + return true; + } + return false; + } + +private: + std::string guid; + int port; + std::unique_ptr sdl_joystick; + std::unique_ptr sdl_controller; + mutable std::mutex mutex; + + u64 last_motion_update{}; + bool has_gyro{false}; + bool has_accel{false}; + BasicMotion motion; +}; + +std::shared_ptr SDLDriver::GetSDLJoystickByGUID(const std::string& guid, int port) { + std::lock_guard lock{joystick_map_mutex}; + const auto it = joystick_map.find(guid); + + if (it != joystick_map.end()) { + while (it->second.size() <= static_cast(port)) { + auto joystick = std::make_shared(guid, static_cast(it->second.size()), + nullptr, nullptr); + it->second.emplace_back(std::move(joystick)); + } + + return it->second[static_cast(port)]; + } + + auto joystick = std::make_shared(guid, 0, nullptr, nullptr); + + return joystick_map[guid].emplace_back(std::move(joystick)); +} + +std::shared_ptr SDLDriver::GetSDLJoystickBySDLID(SDL_JoystickID sdl_id) { + auto sdl_joystick = SDL_JoystickFromInstanceID(sdl_id); + const std::string guid = GetGUID(sdl_joystick); + + std::lock_guard lock{joystick_map_mutex}; + const auto map_it = joystick_map.find(guid); + + if (map_it == joystick_map.end()) { + return nullptr; + } + + const auto vec_it = std::find_if(map_it->second.begin(), map_it->second.end(), + [&sdl_joystick](const auto& joystick) { + return joystick->GetSDLJoystick() == sdl_joystick; + }); + + if (vec_it == map_it->second.end()) { + return nullptr; + } + + return *vec_it; +} + +void SDLDriver::InitJoystick(int joystick_index) { + SDL_Joystick* sdl_joystick = SDL_JoystickOpen(joystick_index); + SDL_GameController* sdl_gamecontroller = nullptr; + + if (SDL_IsGameController(joystick_index)) { + sdl_gamecontroller = SDL_GameControllerOpen(joystick_index); + } + + if (!sdl_joystick) { + LOG_ERROR(Input, "Failed to open joystick {}", joystick_index); + return; + } + + const std::string guid = GetGUID(sdl_joystick); + + std::lock_guard lock{joystick_map_mutex}; + if (joystick_map.find(guid) == joystick_map.end()) { + auto joystick = std::make_shared(guid, 0, sdl_joystick, sdl_gamecontroller); + PreSetController(joystick->GetPadIdentifier()); + joystick_map[guid].emplace_back(std::move(joystick)); + return; + } + + auto& joystick_guid_list = joystick_map[guid]; + const auto joystick_it = + std::find_if(joystick_guid_list.begin(), joystick_guid_list.end(), + [](const auto& joystick) { return !joystick->GetSDLJoystick(); }); + + if (joystick_it != joystick_guid_list.end()) { + (*joystick_it)->SetSDLJoystick(sdl_joystick, sdl_gamecontroller); + return; + } + + const int port = static_cast(joystick_guid_list.size()); + auto joystick = std::make_shared(guid, port, sdl_joystick, sdl_gamecontroller); + PreSetController(joystick->GetPadIdentifier()); + joystick_guid_list.emplace_back(std::move(joystick)); +} + +void SDLDriver::CloseJoystick(SDL_Joystick* sdl_joystick) { + const std::string guid = GetGUID(sdl_joystick); + + std::lock_guard lock{joystick_map_mutex}; + // This call to guid is safe since the joystick is guaranteed to be in the map + const auto& joystick_guid_list = joystick_map[guid]; + const auto joystick_it = std::find_if(joystick_guid_list.begin(), joystick_guid_list.end(), + [&sdl_joystick](const auto& joystick) { + return joystick->GetSDLJoystick() == sdl_joystick; + }); + + if (joystick_it != joystick_guid_list.end()) { + (*joystick_it)->SetSDLJoystick(nullptr, nullptr); + } +} + +void SDLDriver::HandleGameControllerEvent(const SDL_Event& event) { + switch (event.type) { + case SDL_JOYBUTTONUP: { + if (const auto joystick = GetSDLJoystickBySDLID(event.jbutton.which)) { + const PadIdentifier identifier = joystick->GetPadIdentifier(); + SetButton(identifier, event.jbutton.button, false); + } + break; + } + case SDL_JOYBUTTONDOWN: { + if (const auto joystick = GetSDLJoystickBySDLID(event.jbutton.which)) { + const PadIdentifier identifier = joystick->GetPadIdentifier(); + SetButton(identifier, event.jbutton.button, true); + } + break; + } + case SDL_JOYHATMOTION: { + if (const auto joystick = GetSDLJoystickBySDLID(event.jhat.which)) { + const PadIdentifier identifier = joystick->GetPadIdentifier(); + SetHatButton(identifier, event.jhat.hat, event.jhat.value); + } + break; + } + case SDL_JOYAXISMOTION: { + if (const auto joystick = GetSDLJoystickBySDLID(event.jaxis.which)) { + const PadIdentifier identifier = joystick->GetPadIdentifier(); + // Vertical axis is inverted on nintendo compared to SDL + if (joystick->IsYAxis(event.jaxis.axis)) { + SetAxis(identifier, event.jaxis.axis, -event.jaxis.value / 32767.0f); + break; + } + SetAxis(identifier, event.jaxis.axis, event.jaxis.value / 32767.0f); + } + break; + } + case SDL_CONTROLLERSENSORUPDATE: { + if (auto joystick = GetSDLJoystickBySDLID(event.csensor.which)) { + if (joystick->UpdateMotion(event.csensor)) { + const PadIdentifier identifier = joystick->GetPadIdentifier(); + SetMotion(identifier, 0, joystick->GetMotion()); + }; + } + break; + } + case SDL_JOYDEVICEREMOVED: + LOG_DEBUG(Input, "Controller removed with Instance_ID {}", event.jdevice.which); + CloseJoystick(SDL_JoystickFromInstanceID(event.jdevice.which)); + break; + case SDL_JOYDEVICEADDED: + LOG_DEBUG(Input, "Controller connected with device index {}", event.jdevice.which); + InitJoystick(event.jdevice.which); + break; + } +} + +void SDLDriver::CloseJoysticks() { + std::lock_guard lock{joystick_map_mutex}; + joystick_map.clear(); +} + +SDLDriver::SDLDriver(const std::string& input_engine_) : InputEngine(input_engine_) { + Common::SetCurrentThreadName("yuzu:input:SDL"); + + if (!Settings::values.enable_raw_input) { + // Disable raw input. When enabled this setting causes SDL to die when a web applet opens + SDL_SetHint(SDL_HINT_JOYSTICK_RAWINPUT, "0"); + } + + // Prevent SDL from adding undesired axis + SDL_SetHint(SDL_HINT_ACCELEROMETER_AS_JOYSTICK, "0"); + + // Enable HIDAPI rumble. This prevents SDL from disabling motion on PS4 and PS5 controllers + SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, "1"); + SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, "1"); + SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1"); + + // Use hidapi driver for joycons. This will allow joycons to be detected as a GameController and + // not a generic one + SDL_SetHint("SDL_JOYSTICK_HIDAPI_JOY_CONS", "1"); + + // Turn off Pro controller home led + SDL_SetHint("SDL_JOYSTICK_HIDAPI_SWITCH_HOME_LED", "0"); + + // If the frontend is going to manage the event loop, then we don't start one here + start_thread = SDL_WasInit(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER) == 0; + if (start_thread && SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER) < 0) { + LOG_CRITICAL(Input, "SDL_Init failed with: {}", SDL_GetError()); + return; + } + + SDL_AddEventWatch(&SDLEventWatcher, this); + + initialized = true; + if (start_thread) { + poll_thread = std::thread([this] { + using namespace std::chrono_literals; + while (initialized) { + SDL_PumpEvents(); + std::this_thread::sleep_for(1ms); + } + }); + } + // Because the events for joystick connection happens before we have our event watcher added, we + // can just open all the joysticks right here + for (int i = 0; i < SDL_NumJoysticks(); ++i) { + InitJoystick(i); + } +} + +SDLDriver::~SDLDriver() { + CloseJoysticks(); + SDL_DelEventWatch(&SDLEventWatcher, this); + + initialized = false; + if (start_thread) { + poll_thread.join(); + SDL_QuitSubSystem(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER); + } +} + +std::vector SDLDriver::GetInputDevices() const { + std::vector devices; + std::unordered_map> joycon_pairs; + for (const auto& [key, value] : joystick_map) { + for (const auto& joystick : value) { + if (!joystick->GetSDLJoystick()) { + continue; + } + const std::string name = + fmt::format("{} {}", joystick->GetControllerName(), joystick->GetPort()); + devices.emplace_back(Common::ParamPackage{ + {"engine", "sdl"}, + {"display", std::move(name)}, + {"guid", joystick->GetGUID()}, + {"port", std::to_string(joystick->GetPort())}, + }); + if (joystick->IsJoyconLeft()) { + joycon_pairs.insert_or_assign(joystick->GetPort(), joystick); + } + } + } + + // Add dual controllers + for (const auto& [key, value] : joystick_map) { + for (const auto& joystick : value) { + if (joystick->IsJoyconRight()) { + if (!joycon_pairs.contains(joystick->GetPort())) { + continue; + } + const auto joystick2 = joycon_pairs.at(joystick->GetPort()); + + const std::string name = + fmt::format("{} {}", "Nintendo Dual Joy-Con", joystick->GetPort()); + devices.emplace_back(Common::ParamPackage{ + {"engine", "sdl"}, + {"display", std::move(name)}, + {"guid", joystick->GetGUID()}, + {"guid2", joystick2->GetGUID()}, + {"port", std::to_string(joystick->GetPort())}, + }); + } + } + } + return devices; +} +bool SDLDriver::SetRumble(const PadIdentifier& identifier, const Input::VibrationStatus vibration) { + const auto joystick = + GetSDLJoystickByGUID(identifier.guid.Format(), static_cast(identifier.port)); + const auto process_amplitude = [](f32 amplitude) { + return (amplitude + std::pow(amplitude, 0.3f)) * 0.5f * 0xFFFF; + }; + const Input::VibrationStatus new_vibration{ + .low_amplitude = process_amplitude(vibration.low_amplitude), + .low_frequency = vibration.low_frequency, + .high_amplitude = process_amplitude(vibration.high_amplitude), + .high_frequency = vibration.high_frequency, + }; + + return joystick->RumblePlay(new_vibration); +} +Common::ParamPackage SDLDriver::BuildAnalogParamPackageForButton(int port, std::string guid, + s32 axis, float value) const { + Common::ParamPackage params({{"engine", "sdl"}}); + params.Set("port", port); + params.Set("guid", std::move(guid)); + params.Set("axis", axis); + params.Set("threshold", "0.5"); + params.Set("invert", value < 0 ? "-" : "+"); + return params; +} + +Common::ParamPackage SDLDriver::BuildButtonParamPackageForButton(int port, std::string guid, + s32 button) const { + Common::ParamPackage params({{"engine", "sdl"}}); + params.Set("port", port); + params.Set("guid", std::move(guid)); + params.Set("button", button); + return params; +} + +Common::ParamPackage SDLDriver::BuildHatParamPackageForButton(int port, std::string guid, s32 hat, + u8 value) const { + Common::ParamPackage params({{"engine", "sdl"}}); + + params.Set("port", port); + params.Set("guid", std::move(guid)); + params.Set("hat", hat); + params.Set("direction", GetHatButtonName(value)); + return params; +} + +Common::ParamPackage SDLDriver::BuildMotionParam(int port, std::string guid) const { + Common::ParamPackage params({{"engine", "sdl"}, {"motion", "0"}}); + params.Set("port", port); + params.Set("guid", std::move(guid)); + return params; +} + +Common::ParamPackage SDLDriver::BuildParamPackageForBinding( + int port, const std::string& guid, const SDL_GameControllerButtonBind& binding) const { + switch (binding.bindType) { + case SDL_CONTROLLER_BINDTYPE_NONE: + break; + case SDL_CONTROLLER_BINDTYPE_AXIS: + return BuildAnalogParamPackageForButton(port, guid, binding.value.axis); + case SDL_CONTROLLER_BINDTYPE_BUTTON: + return BuildButtonParamPackageForButton(port, guid, binding.value.button); + case SDL_CONTROLLER_BINDTYPE_HAT: + return BuildHatParamPackageForButton(port, guid, binding.value.hat.hat, + static_cast(binding.value.hat.hat_mask)); + } + return {}; +} + +Common::ParamPackage SDLDriver::BuildParamPackageForAnalog(PadIdentifier identifier, int axis_x, + int axis_y, float offset_x, + float offset_y) const { + Common::ParamPackage params; + params.Set("engine", "sdl"); + params.Set("port", static_cast(identifier.port)); + params.Set("guid", identifier.guid.Format()); + params.Set("axis_x", axis_x); + params.Set("axis_y", axis_y); + params.Set("offset_x", offset_x); + params.Set("offset_y", offset_y); + params.Set("invert_x", "+"); + params.Set("invert_y", "+"); + return params; +} + +ButtonMapping SDLDriver::GetButtonMappingForDevice(const Common::ParamPackage& params) { + if (!params.Has("guid") || !params.Has("port")) { + return {}; + } + const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0)); + + auto* controller = joystick->GetSDLGameController(); + if (controller == nullptr) { + return {}; + } + + // This list is missing ZL/ZR since those are not considered buttons in SDL GameController. + // We will add those afterwards + // This list also excludes Screenshot since theres not really a mapping for that + ButtonBindings switch_to_sdl_button; + + if (SDL_GameControllerGetType(controller) == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO) { + switch_to_sdl_button = GetNintendoButtonBinding(joystick); + } else { + switch_to_sdl_button = GetDefaultButtonBinding(); + } + + // Add the missing bindings for ZL/ZR + static constexpr ZButtonBindings switch_to_sdl_axis{{ + {Settings::NativeButton::ZL, SDL_CONTROLLER_AXIS_TRIGGERLEFT}, + {Settings::NativeButton::ZR, SDL_CONTROLLER_AXIS_TRIGGERRIGHT}, + }}; + + // Parameters contain two joysticks return dual + if (params.Has("guid2")) { + const auto joystick2 = GetSDLJoystickByGUID(params.Get("guid2", ""), params.Get("port", 0)); + + if (joystick2->GetSDLGameController() != nullptr) { + return GetDualControllerMapping(joystick, joystick2, switch_to_sdl_button, + switch_to_sdl_axis); + } + } + + return GetSingleControllerMapping(joystick, switch_to_sdl_button, switch_to_sdl_axis); +} + +ButtonBindings SDLDriver::GetDefaultButtonBinding() const { + return { + std::pair{Settings::NativeButton::A, SDL_CONTROLLER_BUTTON_B}, + {Settings::NativeButton::B, SDL_CONTROLLER_BUTTON_A}, + {Settings::NativeButton::X, SDL_CONTROLLER_BUTTON_Y}, + {Settings::NativeButton::Y, SDL_CONTROLLER_BUTTON_X}, + {Settings::NativeButton::LStick, SDL_CONTROLLER_BUTTON_LEFTSTICK}, + {Settings::NativeButton::RStick, SDL_CONTROLLER_BUTTON_RIGHTSTICK}, + {Settings::NativeButton::L, SDL_CONTROLLER_BUTTON_LEFTSHOULDER}, + {Settings::NativeButton::R, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER}, + {Settings::NativeButton::Plus, SDL_CONTROLLER_BUTTON_START}, + {Settings::NativeButton::Minus, SDL_CONTROLLER_BUTTON_BACK}, + {Settings::NativeButton::DLeft, SDL_CONTROLLER_BUTTON_DPAD_LEFT}, + {Settings::NativeButton::DUp, SDL_CONTROLLER_BUTTON_DPAD_UP}, + {Settings::NativeButton::DRight, SDL_CONTROLLER_BUTTON_DPAD_RIGHT}, + {Settings::NativeButton::DDown, SDL_CONTROLLER_BUTTON_DPAD_DOWN}, + {Settings::NativeButton::SL, SDL_CONTROLLER_BUTTON_LEFTSHOULDER}, + {Settings::NativeButton::SR, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER}, + {Settings::NativeButton::Home, SDL_CONTROLLER_BUTTON_GUIDE}, + }; +} + +ButtonBindings SDLDriver::GetNintendoButtonBinding( + const std::shared_ptr& joystick) const { + // Default SL/SR mapping for pro controllers + auto sl_button = SDL_CONTROLLER_BUTTON_LEFTSHOULDER; + auto sr_button = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER; + + if (joystick->IsJoyconLeft()) { + sl_button = SDL_CONTROLLER_BUTTON_PADDLE2; + sr_button = SDL_CONTROLLER_BUTTON_PADDLE4; + } + if (joystick->IsJoyconRight()) { + sl_button = SDL_CONTROLLER_BUTTON_PADDLE3; + sr_button = SDL_CONTROLLER_BUTTON_PADDLE1; + } + + return { + std::pair{Settings::NativeButton::A, SDL_CONTROLLER_BUTTON_A}, + {Settings::NativeButton::B, SDL_CONTROLLER_BUTTON_B}, + {Settings::NativeButton::X, SDL_CONTROLLER_BUTTON_X}, + {Settings::NativeButton::Y, SDL_CONTROLLER_BUTTON_Y}, + {Settings::NativeButton::LStick, SDL_CONTROLLER_BUTTON_LEFTSTICK}, + {Settings::NativeButton::RStick, SDL_CONTROLLER_BUTTON_RIGHTSTICK}, + {Settings::NativeButton::L, SDL_CONTROLLER_BUTTON_LEFTSHOULDER}, + {Settings::NativeButton::R, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER}, + {Settings::NativeButton::Plus, SDL_CONTROLLER_BUTTON_START}, + {Settings::NativeButton::Minus, SDL_CONTROLLER_BUTTON_BACK}, + {Settings::NativeButton::DLeft, SDL_CONTROLLER_BUTTON_DPAD_LEFT}, + {Settings::NativeButton::DUp, SDL_CONTROLLER_BUTTON_DPAD_UP}, + {Settings::NativeButton::DRight, SDL_CONTROLLER_BUTTON_DPAD_RIGHT}, + {Settings::NativeButton::DDown, SDL_CONTROLLER_BUTTON_DPAD_DOWN}, + {Settings::NativeButton::SL, sl_button}, + {Settings::NativeButton::SR, sr_button}, + {Settings::NativeButton::Home, SDL_CONTROLLER_BUTTON_GUIDE}, + }; +} + +ButtonMapping SDLDriver::GetSingleControllerMapping( + const std::shared_ptr& joystick, const ButtonBindings& switch_to_sdl_button, + const ZButtonBindings& switch_to_sdl_axis) const { + ButtonMapping mapping; + mapping.reserve(switch_to_sdl_button.size() + switch_to_sdl_axis.size()); + auto* controller = joystick->GetSDLGameController(); + + for (const auto& [switch_button, sdl_button] : switch_to_sdl_button) { + const auto& binding = SDL_GameControllerGetBindForButton(controller, sdl_button); + mapping.insert_or_assign( + switch_button, + BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding)); + } + for (const auto& [switch_button, sdl_axis] : switch_to_sdl_axis) { + const auto& binding = SDL_GameControllerGetBindForAxis(controller, sdl_axis); + mapping.insert_or_assign( + switch_button, + BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding)); + } + + return mapping; +} + +ButtonMapping SDLDriver::GetDualControllerMapping(const std::shared_ptr& joystick, + const std::shared_ptr& joystick2, + const ButtonBindings& switch_to_sdl_button, + const ZButtonBindings& switch_to_sdl_axis) const { + ButtonMapping mapping; + mapping.reserve(switch_to_sdl_button.size() + switch_to_sdl_axis.size()); + auto* controller = joystick->GetSDLGameController(); + auto* controller2 = joystick2->GetSDLGameController(); + + for (const auto& [switch_button, sdl_button] : switch_to_sdl_button) { + if (IsButtonOnLeftSide(switch_button)) { + const auto& binding = SDL_GameControllerGetBindForButton(controller2, sdl_button); + mapping.insert_or_assign( + switch_button, + BuildParamPackageForBinding(joystick2->GetPort(), joystick2->GetGUID(), binding)); + continue; + } + const auto& binding = SDL_GameControllerGetBindForButton(controller, sdl_button); + mapping.insert_or_assign( + switch_button, + BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding)); + } + for (const auto& [switch_button, sdl_axis] : switch_to_sdl_axis) { + if (IsButtonOnLeftSide(switch_button)) { + const auto& binding = SDL_GameControllerGetBindForAxis(controller2, sdl_axis); + mapping.insert_or_assign( + switch_button, + BuildParamPackageForBinding(joystick2->GetPort(), joystick2->GetGUID(), binding)); + continue; + } + const auto& binding = SDL_GameControllerGetBindForAxis(controller, sdl_axis); + mapping.insert_or_assign( + switch_button, + BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding)); + } + + return mapping; +} + +bool SDLDriver::IsButtonOnLeftSide(Settings::NativeButton::Values button) const { + switch (button) { + case Settings::NativeButton::DDown: + case Settings::NativeButton::DLeft: + case Settings::NativeButton::DRight: + case Settings::NativeButton::DUp: + case Settings::NativeButton::L: + case Settings::NativeButton::LStick: + case Settings::NativeButton::Minus: + case Settings::NativeButton::Screenshot: + case Settings::NativeButton::ZL: + return true; + default: + return false; + } +} + +AnalogMapping SDLDriver::GetAnalogMappingForDevice(const Common::ParamPackage& params) { + if (!params.Has("guid") || !params.Has("port")) { + return {}; + } + const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0)); + const auto joystick2 = GetSDLJoystickByGUID(params.Get("guid2", ""), params.Get("port", 0)); + auto* controller = joystick->GetSDLGameController(); + if (controller == nullptr) { + return {}; + } + + AnalogMapping mapping = {}; + const auto& binding_left_x = + SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTX); + const auto& binding_left_y = + SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTY); + if (params.Has("guid2")) { + const auto identifier = joystick2->GetPadIdentifier(); + PreSetController(identifier); + PreSetAxis(identifier, binding_left_x.value.axis); + PreSetAxis(identifier, binding_left_y.value.axis); + const auto left_offset_x = -GetAxis(identifier, binding_left_x.value.axis); + const auto left_offset_y = -GetAxis(identifier, binding_left_y.value.axis); + mapping.insert_or_assign(Settings::NativeAnalog::LStick, + BuildParamPackageForAnalog(identifier, binding_left_x.value.axis, + binding_left_y.value.axis, + left_offset_x, left_offset_y)); + } else { + const auto identifier = joystick->GetPadIdentifier(); + PreSetController(identifier); + PreSetAxis(identifier, binding_left_x.value.axis); + PreSetAxis(identifier, binding_left_y.value.axis); + const auto left_offset_x = -GetAxis(identifier, binding_left_x.value.axis); + const auto left_offset_y = -GetAxis(identifier, binding_left_y.value.axis); + mapping.insert_or_assign(Settings::NativeAnalog::LStick, + BuildParamPackageForAnalog(identifier, binding_left_x.value.axis, + binding_left_y.value.axis, + left_offset_x, left_offset_y)); + } + const auto& binding_right_x = + SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX); + const auto& binding_right_y = + SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY); + const auto identifier = joystick->GetPadIdentifier(); + PreSetController(identifier); + PreSetAxis(identifier, binding_right_x.value.axis); + PreSetAxis(identifier, binding_right_y.value.axis); + const auto right_offset_x = -GetAxis(identifier, binding_right_x.value.axis); + const auto right_offset_y = -GetAxis(identifier, binding_right_y.value.axis); + mapping.insert_or_assign(Settings::NativeAnalog::RStick, + BuildParamPackageForAnalog(identifier, binding_right_x.value.axis, + binding_right_y.value.axis, right_offset_x, + right_offset_y)); + return mapping; +} + +MotionMapping SDLDriver::GetMotionMappingForDevice(const Common::ParamPackage& params) { + if (!params.Has("guid") || !params.Has("port")) { + return {}; + } + const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0)); + const auto joystick2 = GetSDLJoystickByGUID(params.Get("guid2", ""), params.Get("port", 0)); + auto* controller = joystick->GetSDLGameController(); + if (controller == nullptr) { + return {}; + } + + MotionMapping mapping = {}; + joystick->EnableMotion(); + + if (joystick->HasGyro() || joystick->HasAccel()) { + mapping.insert_or_assign(Settings::NativeMotion::MotionRight, + BuildMotionParam(joystick->GetPort(), joystick->GetGUID())); + } + if (params.Has("guid2")) { + joystick2->EnableMotion(); + if (joystick2->HasGyro() || joystick2->HasAccel()) { + mapping.insert_or_assign(Settings::NativeMotion::MotionLeft, + BuildMotionParam(joystick2->GetPort(), joystick2->GetGUID())); + } + } else { + if (joystick->HasGyro() || joystick->HasAccel()) { + mapping.insert_or_assign(Settings::NativeMotion::MotionLeft, + BuildMotionParam(joystick->GetPort(), joystick->GetGUID())); + } + } + + return mapping; +} + +std::string SDLDriver::GetUIName(const Common::ParamPackage& params) const { + if (params.Has("button")) { + // TODO(German77): Find how to substitue the values for real button names + return fmt::format("Button {}", params.Get("button", 0)); + } + if (params.Has("hat")) { + return fmt::format("Hat {}", params.Get("direction", "")); + } + if (params.Has("axis")) { + return fmt::format("Axis {}", params.Get("axis", "")); + } + if (params.Has("axis_x") && params.Has("axis_y") && params.Has("axis_z")) { + return fmt::format("Axis {},{},{}", params.Get("axis_x", ""), params.Get("axis_y", ""), + params.Get("axis_z", "")); + } + if (params.Has("motion")) { + return "SDL motion"; + } + + return "Bad SDL"; +} + +std::string SDLDriver::GetHatButtonName(u8 direction_value) const { + switch (direction_value) { + case SDL_HAT_UP: + return "up"; + case SDL_HAT_DOWN: + return "down"; + case SDL_HAT_LEFT: + return "left"; + case SDL_HAT_RIGHT: + return "right"; + default: + return {}; + } +} + +u8 SDLDriver::GetHatButtonId(const std::string direction_name) const { + Uint8 direction; + if (direction_name == "up") { + direction = SDL_HAT_UP; + } else if (direction_name == "down") { + direction = SDL_HAT_DOWN; + } else if (direction_name == "left") { + direction = SDL_HAT_LEFT; + } else if (direction_name == "right") { + direction = SDL_HAT_RIGHT; + } else { + direction = 0; + } + return direction; +} + +} // namespace InputCommon diff --git a/src/input_common/drivers/sdl_driver.h b/src/input_common/drivers/sdl_driver.h new file mode 100644 index 000000000..d8d350184 --- /dev/null +++ b/src/input_common/drivers/sdl_driver.h @@ -0,0 +1,120 @@ +// Copyright 2018 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include +#include + +#include + +#include "common/common_types.h" +#include "input_common/input_engine.h" + +union SDL_Event; +using SDL_GameController = struct _SDL_GameController; +using SDL_Joystick = struct _SDL_Joystick; +using SDL_JoystickID = s32; + +using ButtonBindings = + std::array, 17>; +using ZButtonBindings = + std::array, 2>; + +namespace InputCommon { + +class SDLJoystick; + +class SDLDriver : public InputCommon::InputEngine { +public: + /// Initializes and registers SDL device factories + SDLDriver(const std::string& input_engine_); + + /// Unregisters SDL device factories and shut them down. + ~SDLDriver() override; + + /// Handle SDL_Events for joysticks from SDL_PollEvent + void HandleGameControllerEvent(const SDL_Event& event); + + /// Get the nth joystick with the corresponding GUID + std::shared_ptr GetSDLJoystickBySDLID(SDL_JoystickID sdl_id); + + /** + * Check how many identical joysticks (by guid) were connected before the one with sdl_id and so + * tie it to a SDLJoystick with the same guid and that port + */ + std::shared_ptr GetSDLJoystickByGUID(const std::string& guid, int port); + + std::vector GetInputDevices() const override; + + ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage& params) override; + AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage& params) override; + MotionMapping GetMotionMappingForDevice(const Common::ParamPackage& params) override; + std::string GetUIName(const Common::ParamPackage& params) const override; + + std::string GetHatButtonName(u8 direction_value) const override; + u8 GetHatButtonId(const std::string direction_name) const override; + + bool SetRumble(const PadIdentifier& identifier, + const Input::VibrationStatus vibration) override; + +private: + void InitJoystick(int joystick_index); + void CloseJoystick(SDL_Joystick* sdl_joystick); + + /// Needs to be called before SDL_QuitSubSystem. + void CloseJoysticks(); + + Common::ParamPackage BuildAnalogParamPackageForButton(int port, std::string guid, s32 axis, + float value = 0.1f) const; + Common::ParamPackage BuildButtonParamPackageForButton(int port, std::string guid, + s32 button) const; + + Common::ParamPackage BuildHatParamPackageForButton(int port, std::string guid, s32 hat, + u8 value) const; + + Common::ParamPackage BuildMotionParam(int port, std::string guid) const; + + Common::ParamPackage BuildParamPackageForBinding( + int port, const std::string& guid, const SDL_GameControllerButtonBind& binding) const; + + Common::ParamPackage BuildParamPackageForAnalog(PadIdentifier identifier, int axis_x, + int axis_y, float offset_x, + float offset_y) const; + + /// Returns the default button bindings list for generic controllers + ButtonBindings GetDefaultButtonBinding() const; + + /// Returns the default button bindings list for nintendo controllers + ButtonBindings GetNintendoButtonBinding(const std::shared_ptr& joystick) const; + + /// Returns the button mappings from a single controller + ButtonMapping GetSingleControllerMapping(const std::shared_ptr& joystick, + const ButtonBindings& switch_to_sdl_button, + const ZButtonBindings& switch_to_sdl_axis) const; + + /// Returns the button mappings from two different controllers + ButtonMapping GetDualControllerMapping(const std::shared_ptr& joystick, + const std::shared_ptr& joystick2, + const ButtonBindings& switch_to_sdl_button, + const ZButtonBindings& switch_to_sdl_axis) const; + + /// Returns true if the button is on the left joycon + bool IsButtonOnLeftSide(Settings::NativeButton::Values button) const; + + // Set to true if SDL supports game controller subsystem + bool has_gamecontroller = false; + + /// Map of GUID of a list of corresponding virtual Joysticks + std::unordered_map>> joystick_map; + std::mutex joystick_map_mutex; + + bool start_thread = false; + std::atomic initialized = false; + + std::thread poll_thread; +}; +} // namespace InputCommon diff --git a/src/input_common/sdl/sdl.cpp b/src/input_common/sdl/sdl.cpp deleted file mode 100644 index 644db3448..000000000 --- a/src/input_common/sdl/sdl.cpp +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2018 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "input_common/sdl/sdl.h" -#ifdef HAVE_SDL2 -#include "input_common/sdl/sdl_impl.h" -#endif - -namespace InputCommon::SDL { - -std::unique_ptr Init() { -#ifdef HAVE_SDL2 - return std::make_unique(); -#else - return std::make_unique(); -#endif -} -} // namespace InputCommon::SDL diff --git a/src/input_common/sdl/sdl.h b/src/input_common/sdl/sdl.h deleted file mode 100644 index b5d41bba4..000000000 --- a/src/input_common/sdl/sdl.h +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2018 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include -#include -#include "common/param_package.h" -#include "input_common/main.h" - -namespace InputCommon::Polling { -class DevicePoller; -enum class DeviceType; -} // namespace InputCommon::Polling - -namespace InputCommon::SDL { - -class State { -public: - using Pollers = std::vector>; - - /// Unregisters SDL device factories and shut them down. - virtual ~State() = default; - - virtual Pollers GetPollers(Polling::DeviceType) { - return {}; - } - - virtual std::vector GetInputDevices() { - return {}; - } - - virtual ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage&) { - return {}; - } - virtual AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage&) { - return {}; - } - virtual MotionMapping GetMotionMappingForDevice(const Common::ParamPackage&) { - return {}; - } -}; - -class NullState : public State { -public: -}; - -std::unique_ptr Init(); - -} // namespace InputCommon::SDL diff --git a/src/input_common/sdl/sdl_impl.cpp b/src/input_common/sdl/sdl_impl.cpp deleted file mode 100644 index ecb00d428..000000000 --- a/src/input_common/sdl/sdl_impl.cpp +++ /dev/null @@ -1,1658 +0,0 @@ -// Copyright 2018 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "common/logging/log.h" -#include "common/math_util.h" -#include "common/param_package.h" -#include "common/settings.h" -#include "common/threadsafe_queue.h" -#include "core/frontend/input.h" -#include "input_common/motion_input.h" -#include "input_common/sdl/sdl_impl.h" - -namespace InputCommon::SDL { - -namespace { -std::string GetGUID(SDL_Joystick* joystick) { - const SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick); - char guid_str[33]; - SDL_JoystickGetGUIDString(guid, guid_str, sizeof(guid_str)); - return guid_str; -} - -/// Creates a ParamPackage from an SDL_Event that can directly be used to create a ButtonDevice -Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event); -} // Anonymous namespace - -static int SDLEventWatcher(void* user_data, SDL_Event* event) { - auto* const sdl_state = static_cast(user_data); - - // Don't handle the event if we are configuring - if (sdl_state->polling) { - sdl_state->event_queue.Push(*event); - } else { - sdl_state->HandleGameControllerEvent(*event); - } - - return 0; -} - -class SDLJoystick { -public: - SDLJoystick(std::string guid_, int port_, SDL_Joystick* joystick, - SDL_GameController* game_controller) - : guid{std::move(guid_)}, port{port_}, sdl_joystick{joystick, &SDL_JoystickClose}, - sdl_controller{game_controller, &SDL_GameControllerClose} { - EnableMotion(); - } - - void EnableMotion() { - if (sdl_controller) { - SDL_GameController* controller = sdl_controller.get(); - if (SDL_GameControllerHasSensor(controller, SDL_SENSOR_ACCEL) && !has_accel) { - SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_ACCEL, SDL_TRUE); - has_accel = true; - } - if (SDL_GameControllerHasSensor(controller, SDL_SENSOR_GYRO) && !has_gyro) { - SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_GYRO, SDL_TRUE); - has_gyro = true; - } - } - } - - void SetButton(int button, bool value) { - std::lock_guard lock{mutex}; - state.buttons.insert_or_assign(button, value); - } - - void PreSetButton(int button) { - if (!state.buttons.contains(button)) { - SetButton(button, false); - } - } - - void SetMotion(SDL_ControllerSensorEvent event) { - constexpr float gravity_constant = 9.80665f; - std::lock_guard lock{mutex}; - u64 time_difference = event.timestamp - last_motion_update; - last_motion_update = event.timestamp; - switch (event.sensor) { - case SDL_SENSOR_ACCEL: { - const Common::Vec3f acceleration = {-event.data[0], event.data[2], -event.data[1]}; - motion.SetAcceleration(acceleration / gravity_constant); - break; - } - case SDL_SENSOR_GYRO: { - const Common::Vec3f gyroscope = {event.data[0], -event.data[2], event.data[1]}; - motion.SetGyroscope(gyroscope / (Common::PI * 2)); - break; - } - } - - // Ignore duplicated timestamps - if (time_difference == 0) { - return; - } - - motion.SetGyroThreshold(0.0001f); - motion.UpdateRotation(time_difference * 1000); - motion.UpdateOrientation(time_difference * 1000); - } - - bool GetButton(int button) const { - std::lock_guard lock{mutex}; - return state.buttons.at(button); - } - - bool ToggleButton(int button) { - std::lock_guard lock{mutex}; - - if (!state.toggle_buttons.contains(button) || !state.lock_buttons.contains(button)) { - state.toggle_buttons.insert_or_assign(button, false); - state.lock_buttons.insert_or_assign(button, false); - } - - const bool button_state = state.toggle_buttons.at(button); - const bool button_lock = state.lock_buttons.at(button); - - if (button_lock) { - return button_state; - } - - state.lock_buttons.insert_or_assign(button, true); - - if (button_state) { - state.toggle_buttons.insert_or_assign(button, false); - } else { - state.toggle_buttons.insert_or_assign(button, true); - } - - return !button_state; - } - - bool UnlockButton(int button) { - std::lock_guard lock{mutex}; - if (!state.toggle_buttons.contains(button)) { - return false; - } - state.lock_buttons.insert_or_assign(button, false); - return state.toggle_buttons.at(button); - } - - void SetAxis(int axis, Sint16 value) { - std::lock_guard lock{mutex}; - state.axes.insert_or_assign(axis, value); - } - - void PreSetAxis(int axis) { - if (!state.axes.contains(axis)) { - SetAxis(axis, 0); - } - } - - float GetAxis(int axis, float range, float offset) const { - std::lock_guard lock{mutex}; - const float value = static_cast(state.axes.at(axis)) / 32767.0f; - const float offset_scale = (value + offset) > 0.0f ? 1.0f + offset : 1.0f - offset; - return (value + offset) / range / offset_scale; - } - - bool RumblePlay(u16 amp_low, u16 amp_high) { - constexpr u32 rumble_max_duration_ms = 1000; - - if (sdl_controller) { - return SDL_GameControllerRumble(sdl_controller.get(), amp_low, amp_high, - rumble_max_duration_ms) != -1; - } else if (sdl_joystick) { - return SDL_JoystickRumble(sdl_joystick.get(), amp_low, amp_high, - rumble_max_duration_ms) != -1; - } - - return false; - } - - std::tuple GetAnalog(int axis_x, int axis_y, float range, float offset_x, - float offset_y) const { - float x = GetAxis(axis_x, range, offset_x); - float y = GetAxis(axis_y, range, offset_y); - y = -y; // 3DS uses an y-axis inverse from SDL - - // Make sure the coordinates are in the unit circle, - // otherwise normalize it. - float r = x * x + y * y; - if (r > 1.0f) { - r = std::sqrt(r); - x /= r; - y /= r; - } - - return std::make_tuple(x, y); - } - - bool HasGyro() const { - return has_gyro; - } - - bool HasAccel() const { - return has_accel; - } - - const MotionInput& GetMotion() const { - return motion; - } - - void SetHat(int hat, Uint8 direction) { - std::lock_guard lock{mutex}; - state.hats.insert_or_assign(hat, direction); - } - - bool GetHatDirection(int hat, Uint8 direction) const { - std::lock_guard lock{mutex}; - return (state.hats.at(hat) & direction) != 0; - } - /** - * The guid of the joystick - */ - const std::string& GetGUID() const { - return guid; - } - - /** - * The number of joystick from the same type that were connected before this joystick - */ - int GetPort() const { - return port; - } - - SDL_Joystick* GetSDLJoystick() const { - return sdl_joystick.get(); - } - - SDL_GameController* GetSDLGameController() const { - return sdl_controller.get(); - } - - void SetSDLJoystick(SDL_Joystick* joystick, SDL_GameController* controller) { - sdl_joystick.reset(joystick); - sdl_controller.reset(controller); - } - - bool IsJoyconLeft() const { - const std::string controller_name = GetControllerName(); - if (std::strstr(controller_name.c_str(), "Joy-Con Left") != nullptr) { - return true; - } - if (std::strstr(controller_name.c_str(), "Joy-Con (L)") != nullptr) { - return true; - } - return false; - } - - bool IsJoyconRight() const { - const std::string controller_name = GetControllerName(); - if (std::strstr(controller_name.c_str(), "Joy-Con Right") != nullptr) { - return true; - } - if (std::strstr(controller_name.c_str(), "Joy-Con (R)") != nullptr) { - return true; - } - return false; - } - - std::string GetControllerName() const { - if (sdl_controller) { - switch (SDL_GameControllerGetType(sdl_controller.get())) { - case SDL_CONTROLLER_TYPE_XBOX360: - return "XBox 360 Controller"; - case SDL_CONTROLLER_TYPE_XBOXONE: - return "XBox One Controller"; - default: - break; - } - const auto name = SDL_GameControllerName(sdl_controller.get()); - if (name) { - return name; - } - } - - if (sdl_joystick) { - const auto name = SDL_JoystickName(sdl_joystick.get()); - if (name) { - return name; - } - } - - return "Unknown"; - } - -private: - struct State { - std::unordered_map buttons; - std::unordered_map toggle_buttons{}; - std::unordered_map lock_buttons{}; - std::unordered_map axes; - std::unordered_map hats; - } state; - std::string guid; - int port; - std::unique_ptr sdl_joystick; - std::unique_ptr sdl_controller; - mutable std::mutex mutex; - - // Motion is initialized with the PID values - MotionInput motion{0.3f, 0.005f, 0.0f}; - u64 last_motion_update{}; - bool has_gyro{false}; - bool has_accel{false}; -}; - -std::shared_ptr SDLState::GetSDLJoystickByGUID(const std::string& guid, int port) { - std::lock_guard lock{joystick_map_mutex}; - const auto it = joystick_map.find(guid); - - if (it != joystick_map.end()) { - while (it->second.size() <= static_cast(port)) { - auto joystick = std::make_shared(guid, static_cast(it->second.size()), - nullptr, nullptr); - it->second.emplace_back(std::move(joystick)); - } - - return it->second[static_cast(port)]; - } - - auto joystick = std::make_shared(guid, 0, nullptr, nullptr); - - return joystick_map[guid].emplace_back(std::move(joystick)); -} - -std::shared_ptr SDLState::GetSDLJoystickBySDLID(SDL_JoystickID sdl_id) { - auto sdl_joystick = SDL_JoystickFromInstanceID(sdl_id); - const std::string guid = GetGUID(sdl_joystick); - - std::lock_guard lock{joystick_map_mutex}; - const auto map_it = joystick_map.find(guid); - - if (map_it == joystick_map.end()) { - return nullptr; - } - - const auto vec_it = std::find_if(map_it->second.begin(), map_it->second.end(), - [&sdl_joystick](const auto& joystick) { - return joystick->GetSDLJoystick() == sdl_joystick; - }); - - if (vec_it == map_it->second.end()) { - return nullptr; - } - - return *vec_it; -} - -void SDLState::InitJoystick(int joystick_index) { - SDL_Joystick* sdl_joystick = SDL_JoystickOpen(joystick_index); - SDL_GameController* sdl_gamecontroller = nullptr; - - if (SDL_IsGameController(joystick_index)) { - sdl_gamecontroller = SDL_GameControllerOpen(joystick_index); - } - - if (!sdl_joystick) { - LOG_ERROR(Input, "Failed to open joystick {}", joystick_index); - return; - } - - const std::string guid = GetGUID(sdl_joystick); - - std::lock_guard lock{joystick_map_mutex}; - if (joystick_map.find(guid) == joystick_map.end()) { - auto joystick = std::make_shared(guid, 0, sdl_joystick, sdl_gamecontroller); - joystick_map[guid].emplace_back(std::move(joystick)); - return; - } - - auto& joystick_guid_list = joystick_map[guid]; - const auto joystick_it = - std::find_if(joystick_guid_list.begin(), joystick_guid_list.end(), - [](const auto& joystick) { return !joystick->GetSDLJoystick(); }); - - if (joystick_it != joystick_guid_list.end()) { - (*joystick_it)->SetSDLJoystick(sdl_joystick, sdl_gamecontroller); - return; - } - - const int port = static_cast(joystick_guid_list.size()); - auto joystick = std::make_shared(guid, port, sdl_joystick, sdl_gamecontroller); - joystick_guid_list.emplace_back(std::move(joystick)); -} - -void SDLState::CloseJoystick(SDL_Joystick* sdl_joystick) { - const std::string guid = GetGUID(sdl_joystick); - - std::lock_guard lock{joystick_map_mutex}; - // This call to guid is safe since the joystick is guaranteed to be in the map - const auto& joystick_guid_list = joystick_map[guid]; - const auto joystick_it = std::find_if(joystick_guid_list.begin(), joystick_guid_list.end(), - [&sdl_joystick](const auto& joystick) { - return joystick->GetSDLJoystick() == sdl_joystick; - }); - - if (joystick_it != joystick_guid_list.end()) { - (*joystick_it)->SetSDLJoystick(nullptr, nullptr); - } -} - -void SDLState::HandleGameControllerEvent(const SDL_Event& event) { - switch (event.type) { - case SDL_JOYBUTTONUP: { - if (auto joystick = GetSDLJoystickBySDLID(event.jbutton.which)) { - joystick->SetButton(event.jbutton.button, false); - } - break; - } - case SDL_JOYBUTTONDOWN: { - if (auto joystick = GetSDLJoystickBySDLID(event.jbutton.which)) { - joystick->SetButton(event.jbutton.button, true); - } - break; - } - case SDL_JOYHATMOTION: { - if (auto joystick = GetSDLJoystickBySDLID(event.jhat.which)) { - joystick->SetHat(event.jhat.hat, event.jhat.value); - } - break; - } - case SDL_JOYAXISMOTION: { - if (auto joystick = GetSDLJoystickBySDLID(event.jaxis.which)) { - joystick->SetAxis(event.jaxis.axis, event.jaxis.value); - } - break; - } - case SDL_CONTROLLERSENSORUPDATE: { - if (auto joystick = GetSDLJoystickBySDLID(event.csensor.which)) { - joystick->SetMotion(event.csensor); - } - break; - } - case SDL_JOYDEVICEREMOVED: - LOG_DEBUG(Input, "Controller removed with Instance_ID {}", event.jdevice.which); - CloseJoystick(SDL_JoystickFromInstanceID(event.jdevice.which)); - break; - case SDL_JOYDEVICEADDED: - LOG_DEBUG(Input, "Controller connected with device index {}", event.jdevice.which); - InitJoystick(event.jdevice.which); - break; - } -} - -void SDLState::CloseJoysticks() { - std::lock_guard lock{joystick_map_mutex}; - joystick_map.clear(); -} - -class SDLButton final : public Input::ButtonDevice { -public: - explicit SDLButton(std::shared_ptr joystick_, int button_, bool toggle_) - : joystick(std::move(joystick_)), button(button_), toggle(toggle_) {} - - bool GetStatus() const override { - const bool button_state = joystick->GetButton(button); - if (!toggle) { - return button_state; - } - - if (button_state) { - return joystick->ToggleButton(button); - } - return joystick->UnlockButton(button); - } - -private: - std::shared_ptr joystick; - int button; - bool toggle; -}; - -class SDLDirectionButton final : public Input::ButtonDevice { -public: - explicit SDLDirectionButton(std::shared_ptr joystick_, int hat_, Uint8 direction_) - : joystick(std::move(joystick_)), hat(hat_), direction(direction_) {} - - bool GetStatus() const override { - return joystick->GetHatDirection(hat, direction); - } - -private: - std::shared_ptr joystick; - int hat; - Uint8 direction; -}; - -class SDLAxisButton final : public Input::ButtonDevice { -public: - explicit SDLAxisButton(std::shared_ptr joystick_, int axis_, float threshold_, - bool trigger_if_greater_) - : joystick(std::move(joystick_)), axis(axis_), threshold(threshold_), - trigger_if_greater(trigger_if_greater_) {} - - bool GetStatus() const override { - const float axis_value = joystick->GetAxis(axis, 1.0f, 0.0f); - if (trigger_if_greater) { - return axis_value > threshold; - } - return axis_value < threshold; - } - -private: - std::shared_ptr joystick; - int axis; - float threshold; - bool trigger_if_greater; -}; - -class SDLAnalog final : public Input::AnalogDevice { -public: - explicit SDLAnalog(std::shared_ptr joystick_, int axis_x_, int axis_y_, - bool invert_x_, bool invert_y_, float deadzone_, float range_, - float offset_x_, float offset_y_) - : joystick(std::move(joystick_)), axis_x(axis_x_), axis_y(axis_y_), invert_x(invert_x_), - invert_y(invert_y_), deadzone(deadzone_), range(range_), offset_x(offset_x_), - offset_y(offset_y_) {} - - std::tuple GetStatus() const override { - auto [x, y] = joystick->GetAnalog(axis_x, axis_y, range, offset_x, offset_y); - const float r = std::sqrt((x * x) + (y * y)); - if (invert_x) { - x = -x; - } - if (invert_y) { - y = -y; - } - - if (r > deadzone) { - return std::make_tuple(x / r * (r - deadzone) / (1 - deadzone), - y / r * (r - deadzone) / (1 - deadzone)); - } - return {}; - } - - std::tuple GetRawStatus() const override { - const float x = joystick->GetAxis(axis_x, range, offset_x); - const float y = joystick->GetAxis(axis_y, range, offset_y); - return {x, -y}; - } - - Input::AnalogProperties GetAnalogProperties() const override { - return {deadzone, range, 0.5f}; - } - - bool GetAnalogDirectionStatus(Input::AnalogDirection direction) const override { - const auto [x, y] = GetStatus(); - const float directional_deadzone = 0.5f; - switch (direction) { - case Input::AnalogDirection::RIGHT: - return x > directional_deadzone; - case Input::AnalogDirection::LEFT: - return x < -directional_deadzone; - case Input::AnalogDirection::UP: - return y > directional_deadzone; - case Input::AnalogDirection::DOWN: - return y < -directional_deadzone; - } - return false; - } - -private: - std::shared_ptr joystick; - const int axis_x; - const int axis_y; - const bool invert_x; - const bool invert_y; - const float deadzone; - const float range; - const float offset_x; - const float offset_y; -}; - -class SDLVibration final : public Input::VibrationDevice { -public: - explicit SDLVibration(std::shared_ptr joystick_) - : joystick(std::move(joystick_)) {} - - u8 GetStatus() const override { - joystick->RumblePlay(1, 1); - return joystick->RumblePlay(0, 0); - } - - bool SetRumblePlay(f32 amp_low, [[maybe_unused]] f32 freq_low, f32 amp_high, - [[maybe_unused]] f32 freq_high) const override { - const auto process_amplitude = [](f32 amplitude) { - return static_cast((amplitude + std::pow(amplitude, 0.3f)) * 0.5f * 0xFFFF); - }; - - const auto processed_amp_low = process_amplitude(amp_low); - const auto processed_amp_high = process_amplitude(amp_high); - - return joystick->RumblePlay(processed_amp_low, processed_amp_high); - } - -private: - std::shared_ptr joystick; -}; - -class SDLMotion final : public Input::MotionDevice { -public: - explicit SDLMotion(std::shared_ptr joystick_) : joystick(std::move(joystick_)) {} - - Input::MotionStatus GetStatus() const override { - return joystick->GetMotion().GetMotion(); - } - -private: - std::shared_ptr joystick; -}; - -class SDLDirectionMotion final : public Input::MotionDevice { -public: - explicit SDLDirectionMotion(std::shared_ptr joystick_, int hat_, Uint8 direction_) - : joystick(std::move(joystick_)), hat(hat_), direction(direction_) {} - - Input::MotionStatus GetStatus() const override { - if (joystick->GetHatDirection(hat, direction)) { - return joystick->GetMotion().GetRandomMotion(2, 6); - } - return joystick->GetMotion().GetRandomMotion(0, 0); - } - -private: - std::shared_ptr joystick; - int hat; - Uint8 direction; -}; - -class SDLAxisMotion final : public Input::MotionDevice { -public: - explicit SDLAxisMotion(std::shared_ptr joystick_, int axis_, float threshold_, - bool trigger_if_greater_) - : joystick(std::move(joystick_)), axis(axis_), threshold(threshold_), - trigger_if_greater(trigger_if_greater_) {} - - Input::MotionStatus GetStatus() const override { - const float axis_value = joystick->GetAxis(axis, 1.0f, 0.0f); - bool trigger = axis_value < threshold; - if (trigger_if_greater) { - trigger = axis_value > threshold; - } - - if (trigger) { - return joystick->GetMotion().GetRandomMotion(2, 6); - } - return joystick->GetMotion().GetRandomMotion(0, 0); - } - -private: - std::shared_ptr joystick; - int axis; - float threshold; - bool trigger_if_greater; -}; - -class SDLButtonMotion final : public Input::MotionDevice { -public: - explicit SDLButtonMotion(std::shared_ptr joystick_, int button_) - : joystick(std::move(joystick_)), button(button_) {} - - Input::MotionStatus GetStatus() const override { - if (joystick->GetButton(button)) { - return joystick->GetMotion().GetRandomMotion(2, 6); - } - return joystick->GetMotion().GetRandomMotion(0, 0); - } - -private: - std::shared_ptr joystick; - int button; -}; - -/// A button device factory that creates button devices from SDL joystick -class SDLButtonFactory final : public Input::Factory { -public: - explicit SDLButtonFactory(SDLState& state_) : state(state_) {} - - /** - * Creates a button device from a joystick button - * @param params contains parameters for creating the device: - * - "guid": the guid of the joystick to bind - * - "port": the nth joystick of the same type to bind - * - "button"(optional): the index of the button to bind - * - "hat"(optional): the index of the hat to bind as direction buttons - * - "axis"(optional): the index of the axis to bind - * - "direction"(only used for hat): the direction name of the hat to bind. Can be "up", - * "down", "left" or "right" - * - "threshold"(only used for axis): a float value in (-1.0, 1.0) which the button is - * triggered if the axis value crosses - * - "direction"(only used for axis): "+" means the button is triggered when the axis - * value is greater than the threshold; "-" means the button is triggered when the axis - * value is smaller than the threshold - */ - std::unique_ptr Create(const Common::ParamPackage& params) override { - const std::string guid = params.Get("guid", "0"); - const int port = params.Get("port", 0); - const auto toggle = params.Get("toggle", false); - - auto joystick = state.GetSDLJoystickByGUID(guid, port); - - if (params.Has("hat")) { - const int hat = params.Get("hat", 0); - const std::string direction_name = params.Get("direction", ""); - Uint8 direction; - if (direction_name == "up") { - direction = SDL_HAT_UP; - } else if (direction_name == "down") { - direction = SDL_HAT_DOWN; - } else if (direction_name == "left") { - direction = SDL_HAT_LEFT; - } else if (direction_name == "right") { - direction = SDL_HAT_RIGHT; - } else { - direction = 0; - } - // This is necessary so accessing GetHat with hat won't crash - joystick->SetHat(hat, SDL_HAT_CENTERED); - return std::make_unique(joystick, hat, direction); - } - - if (params.Has("axis")) { - const int axis = params.Get("axis", 0); - // Convert range from (0.0, 1.0) to (-1.0, 1.0) - const float threshold = (params.Get("threshold", 0.5f) - 0.5f) * 2.0f; - const std::string direction_name = params.Get("direction", ""); - bool trigger_if_greater; - if (direction_name == "+") { - trigger_if_greater = true; - } else if (direction_name == "-") { - trigger_if_greater = false; - } else { - trigger_if_greater = true; - LOG_ERROR(Input, "Unknown direction {}", direction_name); - } - // This is necessary so accessing GetAxis with axis won't crash - joystick->PreSetAxis(axis); - return std::make_unique(joystick, axis, threshold, trigger_if_greater); - } - - const int button = params.Get("button", 0); - // This is necessary so accessing GetButton with button won't crash - joystick->PreSetButton(button); - return std::make_unique(joystick, button, toggle); - } - -private: - SDLState& state; -}; - -/// An analog device factory that creates analog devices from SDL joystick -class SDLAnalogFactory final : public Input::Factory { -public: - explicit SDLAnalogFactory(SDLState& state_) : state(state_) {} - /** - * Creates an analog device from joystick axes - * @param params contains parameters for creating the device: - * - "guid": the guid of the joystick to bind - * - "port": the nth joystick of the same type - * - "axis_x": the index of the axis to be bind as x-axis - * - "axis_y": the index of the axis to be bind as y-axis - */ - std::unique_ptr Create(const Common::ParamPackage& params) override { - const std::string guid = params.Get("guid", "0"); - const int port = params.Get("port", 0); - const int axis_x = params.Get("axis_x", 0); - const int axis_y = params.Get("axis_y", 1); - const float deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, 1.0f); - const float range = std::clamp(params.Get("range", 1.0f), 0.50f, 1.50f); - const std::string invert_x_value = params.Get("invert_x", "+"); - const std::string invert_y_value = params.Get("invert_y", "+"); - const bool invert_x = invert_x_value == "-"; - const bool invert_y = invert_y_value == "-"; - const float offset_x = std::clamp(params.Get("offset_x", 0.0f), -0.99f, 0.99f); - const float offset_y = std::clamp(params.Get("offset_y", 0.0f), -0.99f, 0.99f); - auto joystick = state.GetSDLJoystickByGUID(guid, port); - - // This is necessary so accessing GetAxis with axis_x and axis_y won't crash - joystick->PreSetAxis(axis_x); - joystick->PreSetAxis(axis_y); - return std::make_unique(joystick, axis_x, axis_y, invert_x, invert_y, deadzone, - range, offset_x, offset_y); - } - -private: - SDLState& state; -}; - -/// An vibration device factory that creates vibration devices from SDL joystick -class SDLVibrationFactory final : public Input::Factory { -public: - explicit SDLVibrationFactory(SDLState& state_) : state(state_) {} - /** - * Creates a vibration device from a joystick - * @param params contains parameters for creating the device: - * - "guid": the guid of the joystick to bind - * - "port": the nth joystick of the same type - */ - std::unique_ptr Create(const Common::ParamPackage& params) override { - const std::string guid = params.Get("guid", "0"); - const int port = params.Get("port", 0); - return std::make_unique(state.GetSDLJoystickByGUID(guid, port)); - } - -private: - SDLState& state; -}; - -/// A motion device factory that creates motion devices from SDL joystick -class SDLMotionFactory final : public Input::Factory { -public: - explicit SDLMotionFactory(SDLState& state_) : state(state_) {} - /** - * Creates motion device from joystick axes - * @param params contains parameters for creating the device: - * - "guid": the guid of the joystick to bind - * - "port": the nth joystick of the same type - */ - std::unique_ptr Create(const Common::ParamPackage& params) override { - const std::string guid = params.Get("guid", "0"); - const int port = params.Get("port", 0); - - auto joystick = state.GetSDLJoystickByGUID(guid, port); - - if (params.Has("motion")) { - return std::make_unique(joystick); - } - - if (params.Has("hat")) { - const int hat = params.Get("hat", 0); - const std::string direction_name = params.Get("direction", ""); - Uint8 direction; - if (direction_name == "up") { - direction = SDL_HAT_UP; - } else if (direction_name == "down") { - direction = SDL_HAT_DOWN; - } else if (direction_name == "left") { - direction = SDL_HAT_LEFT; - } else if (direction_name == "right") { - direction = SDL_HAT_RIGHT; - } else { - direction = 0; - } - // This is necessary so accessing GetHat with hat won't crash - joystick->SetHat(hat, SDL_HAT_CENTERED); - return std::make_unique(joystick, hat, direction); - } - - if (params.Has("axis")) { - const int axis = params.Get("axis", 0); - const float threshold = params.Get("threshold", 0.5f); - const std::string direction_name = params.Get("direction", ""); - bool trigger_if_greater; - if (direction_name == "+") { - trigger_if_greater = true; - } else if (direction_name == "-") { - trigger_if_greater = false; - } else { - trigger_if_greater = true; - LOG_ERROR(Input, "Unknown direction {}", direction_name); - } - // This is necessary so accessing GetAxis with axis won't crash - joystick->PreSetAxis(axis); - return std::make_unique(joystick, axis, threshold, trigger_if_greater); - } - - const int button = params.Get("button", 0); - // This is necessary so accessing GetButton with button won't crash - joystick->PreSetButton(button); - return std::make_unique(joystick, button); - } - -private: - SDLState& state; -}; - -SDLState::SDLState() { - using namespace Input; - button_factory = std::make_shared(*this); - analog_factory = std::make_shared(*this); - vibration_factory = std::make_shared(*this); - motion_factory = std::make_shared(*this); - RegisterFactory("sdl", button_factory); - RegisterFactory("sdl", analog_factory); - RegisterFactory("sdl", vibration_factory); - RegisterFactory("sdl", motion_factory); - - if (!Settings::values.enable_raw_input) { - // Disable raw input. When enabled this setting causes SDL to die when a web applet opens - SDL_SetHint(SDL_HINT_JOYSTICK_RAWINPUT, "0"); - } - - // Enable HIDAPI rumble. This prevents SDL from disabling motion on PS4 and PS5 controllers - SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, "1"); - SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, "1"); - - // Tell SDL2 to use the hidapi driver. This will allow joycons to be detected as a - // GameController and not a generic one - SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, "1"); - - // Turn off Pro controller home led - SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_SWITCH_HOME_LED, "0"); - - // If the frontend is going to manage the event loop, then we don't start one here - start_thread = SDL_WasInit(SDL_INIT_JOYSTICK) == 0; - if (start_thread && SDL_Init(SDL_INIT_JOYSTICK) < 0) { - LOG_CRITICAL(Input, "SDL_Init(SDL_INIT_JOYSTICK) failed with: {}", SDL_GetError()); - return; - } - has_gamecontroller = SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER) != 0; - if (SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1") == SDL_FALSE) { - LOG_ERROR(Input, "Failed to set hint for background events with: {}", SDL_GetError()); - } - - SDL_AddEventWatch(&SDLEventWatcher, this); - - initialized = true; - if (start_thread) { - poll_thread = std::thread([this] { - using namespace std::chrono_literals; - while (initialized) { - SDL_PumpEvents(); - std::this_thread::sleep_for(1ms); - } - }); - } - // Because the events for joystick connection happens before we have our event watcher added, we - // can just open all the joysticks right here - for (int i = 0; i < SDL_NumJoysticks(); ++i) { - InitJoystick(i); - } -} - -SDLState::~SDLState() { - using namespace Input; - UnregisterFactory("sdl"); - UnregisterFactory("sdl"); - UnregisterFactory("sdl"); - UnregisterFactory("sdl"); - - CloseJoysticks(); - SDL_DelEventWatch(&SDLEventWatcher, this); - - initialized = false; - if (start_thread) { - poll_thread.join(); - SDL_QuitSubSystem(SDL_INIT_JOYSTICK); - } -} - -std::vector SDLState::GetInputDevices() { - std::scoped_lock lock(joystick_map_mutex); - std::vector devices; - std::unordered_map> joycon_pairs; - for (const auto& [key, value] : joystick_map) { - for (const auto& joystick : value) { - if (!joystick->GetSDLJoystick()) { - continue; - } - std::string name = - fmt::format("{} {}", joystick->GetControllerName(), joystick->GetPort()); - devices.emplace_back(Common::ParamPackage{ - {"class", "sdl"}, - {"display", std::move(name)}, - {"guid", joystick->GetGUID()}, - {"port", std::to_string(joystick->GetPort())}, - }); - if (joystick->IsJoyconLeft()) { - joycon_pairs.insert_or_assign(joystick->GetPort(), joystick); - } - } - } - - // Add dual controllers - for (const auto& [key, value] : joystick_map) { - for (const auto& joystick : value) { - if (joystick->IsJoyconRight()) { - if (!joycon_pairs.contains(joystick->GetPort())) { - continue; - } - const auto joystick2 = joycon_pairs.at(joystick->GetPort()); - - std::string name = - fmt::format("{} {}", "Nintendo Dual Joy-Con", joystick->GetPort()); - devices.emplace_back(Common::ParamPackage{ - {"class", "sdl"}, - {"display", std::move(name)}, - {"guid", joystick->GetGUID()}, - {"guid2", joystick2->GetGUID()}, - {"port", std::to_string(joystick->GetPort())}, - }); - } - } - } - return devices; -} - -namespace { -Common::ParamPackage BuildAnalogParamPackageForButton(int port, std::string guid, s32 axis, - float value = 0.1f) { - Common::ParamPackage params({{"engine", "sdl"}}); - params.Set("port", port); - params.Set("guid", std::move(guid)); - params.Set("axis", axis); - params.Set("threshold", "0.5"); - if (value > 0) { - params.Set("direction", "+"); - } else { - params.Set("direction", "-"); - } - return params; -} - -Common::ParamPackage BuildButtonParamPackageForButton(int port, std::string guid, s32 button) { - Common::ParamPackage params({{"engine", "sdl"}}); - params.Set("port", port); - params.Set("guid", std::move(guid)); - params.Set("button", button); - params.Set("toggle", false); - return params; -} - -Common::ParamPackage BuildHatParamPackageForButton(int port, std::string guid, s32 hat, s32 value) { - Common::ParamPackage params({{"engine", "sdl"}}); - - params.Set("port", port); - params.Set("guid", std::move(guid)); - params.Set("hat", hat); - switch (value) { - case SDL_HAT_UP: - params.Set("direction", "up"); - break; - case SDL_HAT_DOWN: - params.Set("direction", "down"); - break; - case SDL_HAT_LEFT: - params.Set("direction", "left"); - break; - case SDL_HAT_RIGHT: - params.Set("direction", "right"); - break; - default: - return {}; - } - return params; -} - -Common::ParamPackage BuildMotionParam(int port, std::string guid) { - Common::ParamPackage params({{"engine", "sdl"}, {"motion", "0"}}); - params.Set("port", port); - params.Set("guid", std::move(guid)); - return params; -} - -Common::ParamPackage SDLEventToButtonParamPackage(SDLState& state, const SDL_Event& event) { - switch (event.type) { - case SDL_JOYAXISMOTION: { - if (const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which)) { - return BuildAnalogParamPackageForButton(joystick->GetPort(), joystick->GetGUID(), - static_cast(event.jaxis.axis), - event.jaxis.value); - } - break; - } - case SDL_JOYBUTTONUP: { - if (const auto joystick = state.GetSDLJoystickBySDLID(event.jbutton.which)) { - return BuildButtonParamPackageForButton(joystick->GetPort(), joystick->GetGUID(), - static_cast(event.jbutton.button)); - } - break; - } - case SDL_JOYHATMOTION: { - if (const auto joystick = state.GetSDLJoystickBySDLID(event.jhat.which)) { - return BuildHatParamPackageForButton(joystick->GetPort(), joystick->GetGUID(), - static_cast(event.jhat.hat), - static_cast(event.jhat.value)); - } - break; - } - } - return {}; -} - -Common::ParamPackage SDLEventToMotionParamPackage(SDLState& state, const SDL_Event& event) { - switch (event.type) { - case SDL_JOYAXISMOTION: { - if (const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which)) { - return BuildAnalogParamPackageForButton(joystick->GetPort(), joystick->GetGUID(), - static_cast(event.jaxis.axis), - event.jaxis.value); - } - break; - } - case SDL_JOYBUTTONUP: { - if (const auto joystick = state.GetSDLJoystickBySDLID(event.jbutton.which)) { - return BuildButtonParamPackageForButton(joystick->GetPort(), joystick->GetGUID(), - static_cast(event.jbutton.button)); - } - break; - } - case SDL_JOYHATMOTION: { - if (const auto joystick = state.GetSDLJoystickBySDLID(event.jhat.which)) { - return BuildHatParamPackageForButton(joystick->GetPort(), joystick->GetGUID(), - static_cast(event.jhat.hat), - static_cast(event.jhat.value)); - } - break; - } - case SDL_CONTROLLERSENSORUPDATE: { - bool is_motion_shaking = false; - constexpr float gyro_threshold = 5.0f; - constexpr float accel_threshold = 11.0f; - if (event.csensor.sensor == SDL_SENSOR_ACCEL) { - const Common::Vec3f acceleration = {-event.csensor.data[0], event.csensor.data[2], - -event.csensor.data[1]}; - if (acceleration.Length() > accel_threshold) { - is_motion_shaking = true; - } - } - - if (event.csensor.sensor == SDL_SENSOR_GYRO) { - const Common::Vec3f gyroscope = {event.csensor.data[0], -event.csensor.data[2], - event.csensor.data[1]}; - if (gyroscope.Length() > gyro_threshold) { - is_motion_shaking = true; - } - } - - if (!is_motion_shaking) { - break; - } - - if (const auto joystick = state.GetSDLJoystickBySDLID(event.csensor.which)) { - return BuildMotionParam(joystick->GetPort(), joystick->GetGUID()); - } - break; - } - } - return {}; -} - -Common::ParamPackage BuildParamPackageForBinding(int port, const std::string& guid, - const SDL_GameControllerButtonBind& binding) { - switch (binding.bindType) { - case SDL_CONTROLLER_BINDTYPE_NONE: - break; - case SDL_CONTROLLER_BINDTYPE_AXIS: - return BuildAnalogParamPackageForButton(port, guid, binding.value.axis); - case SDL_CONTROLLER_BINDTYPE_BUTTON: - return BuildButtonParamPackageForButton(port, guid, binding.value.button); - case SDL_CONTROLLER_BINDTYPE_HAT: - return BuildHatParamPackageForButton(port, guid, binding.value.hat.hat, - binding.value.hat.hat_mask); - } - return {}; -} - -Common::ParamPackage BuildParamPackageForAnalog(int port, const std::string& guid, int axis_x, - int axis_y, float offset_x, float offset_y) { - Common::ParamPackage params; - params.Set("engine", "sdl"); - params.Set("port", port); - params.Set("guid", guid); - params.Set("axis_x", axis_x); - params.Set("axis_y", axis_y); - params.Set("offset_x", offset_x); - params.Set("offset_y", offset_y); - params.Set("invert_x", "+"); - params.Set("invert_y", "+"); - return params; -} -} // Anonymous namespace - -ButtonMapping SDLState::GetButtonMappingForDevice(const Common::ParamPackage& params) { - if (!params.Has("guid") || !params.Has("port")) { - return {}; - } - const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0)); - - auto* controller = joystick->GetSDLGameController(); - if (controller == nullptr) { - return {}; - } - - // This list is missing ZL/ZR since those are not considered buttons in SDL GameController. - // We will add those afterwards - // This list also excludes Screenshot since theres not really a mapping for that - ButtonBindings switch_to_sdl_button; - - if (SDL_GameControllerGetType(controller) == SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO) { - switch_to_sdl_button = GetNintendoButtonBinding(joystick); - } else { - switch_to_sdl_button = GetDefaultButtonBinding(); - } - - // Add the missing bindings for ZL/ZR - static constexpr ZButtonBindings switch_to_sdl_axis{{ - {Settings::NativeButton::ZL, SDL_CONTROLLER_AXIS_TRIGGERLEFT}, - {Settings::NativeButton::ZR, SDL_CONTROLLER_AXIS_TRIGGERRIGHT}, - }}; - - // Parameters contain two joysticks return dual - if (params.Has("guid2")) { - const auto joystick2 = GetSDLJoystickByGUID(params.Get("guid2", ""), params.Get("port", 0)); - - if (joystick2->GetSDLGameController() != nullptr) { - return GetDualControllerMapping(joystick, joystick2, switch_to_sdl_button, - switch_to_sdl_axis); - } - } - - return GetSingleControllerMapping(joystick, switch_to_sdl_button, switch_to_sdl_axis); -} - -ButtonBindings SDLState::GetDefaultButtonBinding() const { - return { - std::pair{Settings::NativeButton::A, SDL_CONTROLLER_BUTTON_B}, - {Settings::NativeButton::B, SDL_CONTROLLER_BUTTON_A}, - {Settings::NativeButton::X, SDL_CONTROLLER_BUTTON_Y}, - {Settings::NativeButton::Y, SDL_CONTROLLER_BUTTON_X}, - {Settings::NativeButton::LStick, SDL_CONTROLLER_BUTTON_LEFTSTICK}, - {Settings::NativeButton::RStick, SDL_CONTROLLER_BUTTON_RIGHTSTICK}, - {Settings::NativeButton::L, SDL_CONTROLLER_BUTTON_LEFTSHOULDER}, - {Settings::NativeButton::R, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER}, - {Settings::NativeButton::Plus, SDL_CONTROLLER_BUTTON_START}, - {Settings::NativeButton::Minus, SDL_CONTROLLER_BUTTON_BACK}, - {Settings::NativeButton::DLeft, SDL_CONTROLLER_BUTTON_DPAD_LEFT}, - {Settings::NativeButton::DUp, SDL_CONTROLLER_BUTTON_DPAD_UP}, - {Settings::NativeButton::DRight, SDL_CONTROLLER_BUTTON_DPAD_RIGHT}, - {Settings::NativeButton::DDown, SDL_CONTROLLER_BUTTON_DPAD_DOWN}, - {Settings::NativeButton::SL, SDL_CONTROLLER_BUTTON_LEFTSHOULDER}, - {Settings::NativeButton::SR, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER}, - {Settings::NativeButton::Home, SDL_CONTROLLER_BUTTON_GUIDE}, - }; -} - -ButtonBindings SDLState::GetNintendoButtonBinding( - const std::shared_ptr& joystick) const { - // Default SL/SR mapping for pro controllers - auto sl_button = SDL_CONTROLLER_BUTTON_LEFTSHOULDER; - auto sr_button = SDL_CONTROLLER_BUTTON_RIGHTSHOULDER; - - if (joystick->IsJoyconLeft()) { - sl_button = SDL_CONTROLLER_BUTTON_PADDLE2; - sr_button = SDL_CONTROLLER_BUTTON_PADDLE4; - } - if (joystick->IsJoyconRight()) { - sl_button = SDL_CONTROLLER_BUTTON_PADDLE3; - sr_button = SDL_CONTROLLER_BUTTON_PADDLE1; - } - - return { - std::pair{Settings::NativeButton::A, SDL_CONTROLLER_BUTTON_A}, - {Settings::NativeButton::B, SDL_CONTROLLER_BUTTON_B}, - {Settings::NativeButton::X, SDL_CONTROLLER_BUTTON_X}, - {Settings::NativeButton::Y, SDL_CONTROLLER_BUTTON_Y}, - {Settings::NativeButton::LStick, SDL_CONTROLLER_BUTTON_LEFTSTICK}, - {Settings::NativeButton::RStick, SDL_CONTROLLER_BUTTON_RIGHTSTICK}, - {Settings::NativeButton::L, SDL_CONTROLLER_BUTTON_LEFTSHOULDER}, - {Settings::NativeButton::R, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER}, - {Settings::NativeButton::Plus, SDL_CONTROLLER_BUTTON_START}, - {Settings::NativeButton::Minus, SDL_CONTROLLER_BUTTON_BACK}, - {Settings::NativeButton::DLeft, SDL_CONTROLLER_BUTTON_DPAD_LEFT}, - {Settings::NativeButton::DUp, SDL_CONTROLLER_BUTTON_DPAD_UP}, - {Settings::NativeButton::DRight, SDL_CONTROLLER_BUTTON_DPAD_RIGHT}, - {Settings::NativeButton::DDown, SDL_CONTROLLER_BUTTON_DPAD_DOWN}, - {Settings::NativeButton::SL, sl_button}, - {Settings::NativeButton::SR, sr_button}, - {Settings::NativeButton::Home, SDL_CONTROLLER_BUTTON_GUIDE}, - }; -} - -ButtonMapping SDLState::GetSingleControllerMapping( - const std::shared_ptr& joystick, const ButtonBindings& switch_to_sdl_button, - const ZButtonBindings& switch_to_sdl_axis) const { - ButtonMapping mapping; - mapping.reserve(switch_to_sdl_button.size() + switch_to_sdl_axis.size()); - auto* controller = joystick->GetSDLGameController(); - - for (const auto& [switch_button, sdl_button] : switch_to_sdl_button) { - const auto& binding = SDL_GameControllerGetBindForButton(controller, sdl_button); - mapping.insert_or_assign( - switch_button, - BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding)); - } - for (const auto& [switch_button, sdl_axis] : switch_to_sdl_axis) { - const auto& binding = SDL_GameControllerGetBindForAxis(controller, sdl_axis); - mapping.insert_or_assign( - switch_button, - BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding)); - } - - return mapping; -} - -ButtonMapping SDLState::GetDualControllerMapping(const std::shared_ptr& joystick, - const std::shared_ptr& joystick2, - const ButtonBindings& switch_to_sdl_button, - const ZButtonBindings& switch_to_sdl_axis) const { - ButtonMapping mapping; - mapping.reserve(switch_to_sdl_button.size() + switch_to_sdl_axis.size()); - auto* controller = joystick->GetSDLGameController(); - auto* controller2 = joystick2->GetSDLGameController(); - - for (const auto& [switch_button, sdl_button] : switch_to_sdl_button) { - if (IsButtonOnLeftSide(switch_button)) { - const auto& binding = SDL_GameControllerGetBindForButton(controller2, sdl_button); - mapping.insert_or_assign( - switch_button, - BuildParamPackageForBinding(joystick2->GetPort(), joystick2->GetGUID(), binding)); - continue; - } - const auto& binding = SDL_GameControllerGetBindForButton(controller, sdl_button); - mapping.insert_or_assign( - switch_button, - BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding)); - } - for (const auto& [switch_button, sdl_axis] : switch_to_sdl_axis) { - if (IsButtonOnLeftSide(switch_button)) { - const auto& binding = SDL_GameControllerGetBindForAxis(controller2, sdl_axis); - mapping.insert_or_assign( - switch_button, - BuildParamPackageForBinding(joystick2->GetPort(), joystick2->GetGUID(), binding)); - continue; - } - const auto& binding = SDL_GameControllerGetBindForAxis(controller, sdl_axis); - mapping.insert_or_assign( - switch_button, - BuildParamPackageForBinding(joystick->GetPort(), joystick->GetGUID(), binding)); - } - - return mapping; -} - -bool SDLState::IsButtonOnLeftSide(Settings::NativeButton::Values button) const { - switch (button) { - case Settings::NativeButton::DDown: - case Settings::NativeButton::DLeft: - case Settings::NativeButton::DRight: - case Settings::NativeButton::DUp: - case Settings::NativeButton::L: - case Settings::NativeButton::LStick: - case Settings::NativeButton::Minus: - case Settings::NativeButton::Screenshot: - case Settings::NativeButton::ZL: - return true; - default: - return false; - } -} - -AnalogMapping SDLState::GetAnalogMappingForDevice(const Common::ParamPackage& params) { - if (!params.Has("guid") || !params.Has("port")) { - return {}; - } - const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0)); - const auto joystick2 = GetSDLJoystickByGUID(params.Get("guid2", ""), params.Get("port", 0)); - auto* controller = joystick->GetSDLGameController(); - if (controller == nullptr) { - return {}; - } - - AnalogMapping mapping = {}; - const auto& binding_left_x = - SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTX); - const auto& binding_left_y = - SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_LEFTY); - if (params.Has("guid2")) { - joystick2->PreSetAxis(binding_left_x.value.axis); - joystick2->PreSetAxis(binding_left_y.value.axis); - const auto left_offset_x = -joystick2->GetAxis(binding_left_x.value.axis, 1.0f, 0); - const auto left_offset_y = -joystick2->GetAxis(binding_left_y.value.axis, 1.0f, 0); - mapping.insert_or_assign( - Settings::NativeAnalog::LStick, - BuildParamPackageForAnalog(joystick2->GetPort(), joystick2->GetGUID(), - binding_left_x.value.axis, binding_left_y.value.axis, - left_offset_x, left_offset_y)); - } else { - joystick->PreSetAxis(binding_left_x.value.axis); - joystick->PreSetAxis(binding_left_y.value.axis); - const auto left_offset_x = -joystick->GetAxis(binding_left_x.value.axis, 1.0f, 0); - const auto left_offset_y = -joystick->GetAxis(binding_left_y.value.axis, 1.0f, 0); - mapping.insert_or_assign( - Settings::NativeAnalog::LStick, - BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(), - binding_left_x.value.axis, binding_left_y.value.axis, - left_offset_x, left_offset_y)); - } - const auto& binding_right_x = - SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTX); - const auto& binding_right_y = - SDL_GameControllerGetBindForAxis(controller, SDL_CONTROLLER_AXIS_RIGHTY); - joystick->PreSetAxis(binding_right_x.value.axis); - joystick->PreSetAxis(binding_right_y.value.axis); - const auto right_offset_x = -joystick->GetAxis(binding_right_x.value.axis, 1.0f, 0); - const auto right_offset_y = -joystick->GetAxis(binding_right_y.value.axis, 1.0f, 0); - mapping.insert_or_assign(Settings::NativeAnalog::RStick, - BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(), - binding_right_x.value.axis, - binding_right_y.value.axis, right_offset_x, - right_offset_y)); - return mapping; -} - -MotionMapping SDLState::GetMotionMappingForDevice(const Common::ParamPackage& params) { - if (!params.Has("guid") || !params.Has("port")) { - return {}; - } - const auto joystick = GetSDLJoystickByGUID(params.Get("guid", ""), params.Get("port", 0)); - const auto joystick2 = GetSDLJoystickByGUID(params.Get("guid2", ""), params.Get("port", 0)); - auto* controller = joystick->GetSDLGameController(); - if (controller == nullptr) { - return {}; - } - - MotionMapping mapping = {}; - joystick->EnableMotion(); - - if (joystick->HasGyro() || joystick->HasAccel()) { - mapping.insert_or_assign(Settings::NativeMotion::MotionRight, - BuildMotionParam(joystick->GetPort(), joystick->GetGUID())); - } - if (params.Has("guid2")) { - joystick2->EnableMotion(); - if (joystick2->HasGyro() || joystick2->HasAccel()) { - mapping.insert_or_assign(Settings::NativeMotion::MotionLeft, - BuildMotionParam(joystick2->GetPort(), joystick2->GetGUID())); - } - } else { - if (joystick->HasGyro() || joystick->HasAccel()) { - mapping.insert_or_assign(Settings::NativeMotion::MotionLeft, - BuildMotionParam(joystick->GetPort(), joystick->GetGUID())); - } - } - - return mapping; -} -namespace Polling { -class SDLPoller : public InputCommon::Polling::DevicePoller { -public: - explicit SDLPoller(SDLState& state_) : state(state_) {} - - void Start([[maybe_unused]] const std::string& device_id) override { - state.event_queue.Clear(); - state.polling = true; - } - - void Stop() override { - state.polling = false; - } - -protected: - SDLState& state; -}; - -class SDLButtonPoller final : public SDLPoller { -public: - explicit SDLButtonPoller(SDLState& state_) : SDLPoller(state_) {} - - Common::ParamPackage GetNextInput() override { - SDL_Event event; - while (state.event_queue.Pop(event)) { - const auto package = FromEvent(event); - if (package) { - return *package; - } - } - return {}; - } - [[nodiscard]] std::optional FromEvent(SDL_Event& event) { - switch (event.type) { - case SDL_JOYAXISMOTION: - if (!axis_memory.count(event.jaxis.which) || - !axis_memory[event.jaxis.which].count(event.jaxis.axis)) { - axis_memory[event.jaxis.which][event.jaxis.axis] = event.jaxis.value; - axis_event_count[event.jaxis.which][event.jaxis.axis] = 1; - break; - } else { - axis_event_count[event.jaxis.which][event.jaxis.axis]++; - // The joystick and axis exist in our map if we take this branch, so no checks - // needed - if (std::abs( - (event.jaxis.value - axis_memory[event.jaxis.which][event.jaxis.axis]) / - 32767.0) < 0.5) { - break; - } else { - if (axis_event_count[event.jaxis.which][event.jaxis.axis] == 2 && - IsAxisAtPole(event.jaxis.value) && - IsAxisAtPole(axis_memory[event.jaxis.which][event.jaxis.axis])) { - // If we have exactly two events and both are near a pole, this is - // likely a digital input masquerading as an analog axis; Instead of - // trying to look at the direction the axis travelled, assume the first - // event was press and the second was release; This should handle most - // digital axes while deferring to the direction of travel for analog - // axes - event.jaxis.value = static_cast( - std::copysign(32767, axis_memory[event.jaxis.which][event.jaxis.axis])); - } else { - // There are more than two events, so this is likely a true analog axis, - // check the direction it travelled - event.jaxis.value = static_cast(std::copysign( - 32767, - event.jaxis.value - axis_memory[event.jaxis.which][event.jaxis.axis])); - } - axis_memory.clear(); - axis_event_count.clear(); - } - } - [[fallthrough]]; - case SDL_JOYBUTTONUP: - case SDL_JOYHATMOTION: - return {SDLEventToButtonParamPackage(state, event)}; - } - return std::nullopt; - } - -private: - // Determine whether an axis value is close to an extreme or center - // Some controllers have a digital D-Pad as a pair of analog sticks, with 3 possible values per - // axis, which is why the center must be considered a pole - bool IsAxisAtPole(int16_t value) const { - return std::abs(value) >= 32767 || std::abs(value) < 327; - } - std::unordered_map> axis_memory; - std::unordered_map> axis_event_count; -}; - -class SDLMotionPoller final : public SDLPoller { -public: - explicit SDLMotionPoller(SDLState& state_) : SDLPoller(state_) {} - - Common::ParamPackage GetNextInput() override { - SDL_Event event; - while (state.event_queue.Pop(event)) { - const auto package = FromEvent(event); - if (package) { - return *package; - } - } - return {}; - } - [[nodiscard]] std::optional FromEvent(const SDL_Event& event) const { - switch (event.type) { - case SDL_JOYAXISMOTION: - if (std::abs(event.jaxis.value / 32767.0) < 0.5) { - break; - } - [[fallthrough]]; - case SDL_JOYBUTTONUP: - case SDL_JOYHATMOTION: - case SDL_CONTROLLERSENSORUPDATE: - return {SDLEventToMotionParamPackage(state, event)}; - } - return std::nullopt; - } -}; - -/** - * Attempts to match the press to a controller joy axis (left/right stick) and if a match - * isn't found, checks if the event matches anything from SDLButtonPoller and uses that - * instead - */ -class SDLAnalogPreferredPoller final : public SDLPoller { -public: - explicit SDLAnalogPreferredPoller(SDLState& state_) - : SDLPoller(state_), button_poller(state_) {} - - void Start(const std::string& device_id) override { - SDLPoller::Start(device_id); - // Reset stored axes - first_axis = -1; - } - - Common::ParamPackage GetNextInput() override { - SDL_Event event; - while (state.event_queue.Pop(event)) { - if (event.type != SDL_JOYAXISMOTION) { - // Check for a button press - auto button_press = button_poller.FromEvent(event); - if (button_press) { - return *button_press; - } - continue; - } - const auto axis = event.jaxis.axis; - - // Filter out axis events that are below a threshold - if (std::abs(event.jaxis.value / 32767.0) < 0.5) { - continue; - } - - // Filter out axis events that are the same - if (first_axis == axis) { - continue; - } - - // In order to return a complete analog param, we need inputs for both axes. - // If the first axis isn't set we set the value then wait till next event - if (first_axis == -1) { - first_axis = axis; - continue; - } - - if (const auto joystick = state.GetSDLJoystickBySDLID(event.jaxis.which)) { - // Set offset to zero since the joystick is not on center - auto params = BuildParamPackageForAnalog(joystick->GetPort(), joystick->GetGUID(), - first_axis, axis, 0, 0); - first_axis = -1; - return params; - } - } - return {}; - } - -private: - int first_axis = -1; - SDLButtonPoller button_poller; -}; -} // namespace Polling - -SDLState::Pollers SDLState::GetPollers(InputCommon::Polling::DeviceType type) { - Pollers pollers; - - switch (type) { - case InputCommon::Polling::DeviceType::AnalogPreferred: - pollers.emplace_back(std::make_unique(*this)); - break; - case InputCommon::Polling::DeviceType::Button: - pollers.emplace_back(std::make_unique(*this)); - break; - case InputCommon::Polling::DeviceType::Motion: - pollers.emplace_back(std::make_unique(*this)); - break; - } - - return pollers; -} - -} // namespace InputCommon::SDL diff --git a/src/input_common/sdl/sdl_impl.h b/src/input_common/sdl/sdl_impl.h deleted file mode 100644 index 7a9ad6346..000000000 --- a/src/input_common/sdl/sdl_impl.h +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright 2018 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include -#include -#include -#include -#include - -#include - -#include "common/common_types.h" -#include "common/threadsafe_queue.h" -#include "input_common/sdl/sdl.h" - -union SDL_Event; -using SDL_GameController = struct _SDL_GameController; -using SDL_Joystick = struct _SDL_Joystick; -using SDL_JoystickID = s32; - -using ButtonBindings = - std::array, 17>; -using ZButtonBindings = - std::array, 2>; - -namespace InputCommon::SDL { - -class SDLAnalogFactory; -class SDLButtonFactory; -class SDLMotionFactory; -class SDLVibrationFactory; -class SDLJoystick; - -class SDLState : public State { -public: - /// Initializes and registers SDL device factories - SDLState(); - - /// Unregisters SDL device factories and shut them down. - ~SDLState() override; - - /// Handle SDL_Events for joysticks from SDL_PollEvent - void HandleGameControllerEvent(const SDL_Event& event); - - /// Get the nth joystick with the corresponding GUID - std::shared_ptr GetSDLJoystickBySDLID(SDL_JoystickID sdl_id); - - /** - * Check how many identical joysticks (by guid) were connected before the one with sdl_id and so - * tie it to a SDLJoystick with the same guid and that port - */ - std::shared_ptr GetSDLJoystickByGUID(const std::string& guid, int port); - - /// Get all DevicePoller that use the SDL backend for a specific device type - Pollers GetPollers(Polling::DeviceType type) override; - - /// Used by the Pollers during config - std::atomic polling = false; - Common::SPSCQueue event_queue; - - std::vector GetInputDevices() override; - - ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage& params) override; - AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage& params) override; - MotionMapping GetMotionMappingForDevice(const Common::ParamPackage& params) override; - -private: - void InitJoystick(int joystick_index); - void CloseJoystick(SDL_Joystick* sdl_joystick); - - /// Needs to be called before SDL_QuitSubSystem. - void CloseJoysticks(); - - /// Returns the default button bindings list for generic controllers - ButtonBindings GetDefaultButtonBinding() const; - - /// Returns the default button bindings list for nintendo controllers - ButtonBindings GetNintendoButtonBinding(const std::shared_ptr& joystick) const; - - /// Returns the button mappings from a single controller - ButtonMapping GetSingleControllerMapping(const std::shared_ptr& joystick, - const ButtonBindings& switch_to_sdl_button, - const ZButtonBindings& switch_to_sdl_axis) const; - - /// Returns the button mappings from two different controllers - ButtonMapping GetDualControllerMapping(const std::shared_ptr& joystick, - const std::shared_ptr& joystick2, - const ButtonBindings& switch_to_sdl_button, - const ZButtonBindings& switch_to_sdl_axis) const; - - /// Returns true if the button is on the left joycon - bool IsButtonOnLeftSide(Settings::NativeButton::Values button) const; - - // Set to true if SDL supports game controller subsystem - bool has_gamecontroller = false; - - /// Map of GUID of a list of corresponding virtual Joysticks - std::unordered_map>> joystick_map; - std::mutex joystick_map_mutex; - - std::shared_ptr button_factory; - std::shared_ptr analog_factory; - std::shared_ptr vibration_factory; - std::shared_ptr motion_factory; - - bool start_thread = false; - std::atomic initialized = false; - - std::thread poll_thread; -}; -} // namespace InputCommon::SDL -- cgit v1.2.3 From 06a5ef5874144a70e30e577a83ba68d1dad79e78 Mon Sep 17 00:00:00 2001 From: german77 Date: Mon, 11 Oct 2021 00:43:11 -0500 Subject: core/hid: Add output devices --- src/common/input.h | 39 +++++++ src/core/hid/emulated_controller.cpp | 119 ++++++++++++++++----- src/core/hid/emulated_controller.h | 13 ++- src/core/hid/hid_types.h | 18 ++++ src/core/hle/service/hid/controllers/npad.cpp | 27 +---- src/core/hle/service/hid/controllers/npad.h | 18 +--- src/input_common/drivers/gc_adapter.cpp | 8 +- src/input_common/drivers/gc_adapter.h | 2 +- src/input_common/drivers/sdl_driver.cpp | 8 +- src/input_common/drivers/sdl_driver.h | 2 +- src/input_common/helpers/stick_from_buttons.cpp | 3 +- src/input_common/helpers/stick_from_buttons.h | 3 +- src/input_common/helpers/touch_from_buttons.cpp | 4 +- src/input_common/input_engine.h | 18 ++-- src/input_common/input_poller.cpp | 40 ++++++- src/input_common/input_poller.h | 28 ++++- src/input_common/main.cpp | 30 ++++-- src/yuzu/configuration/configure_input_player.cpp | 7 ++ .../configure_input_player_widget.cpp | 59 ++++------ .../configuration/configure_input_player_widget.h | 10 +- 20 files changed, 312 insertions(+), 144 deletions(-) (limited to 'src/input_common/drivers') diff --git a/src/common/input.h b/src/common/input.h index 6eefc55f9..3a28b77a7 100644 --- a/src/common/input.h +++ b/src/common/input.h @@ -38,6 +38,27 @@ enum class BatteryLevel { Charging, }; +enum class PollingMode { + Active, + Pasive, + Camera, + NCF, + IR, +}; + +enum class VibrationError { + None, + NotSupported, + Disabled, + Unknown, +}; + +enum class PollingError { + None, + NotSupported, + Unknown, +}; + struct AnalogProperties { float deadzone{}; float range{1.0f}; @@ -149,6 +170,24 @@ private: InputCallback callback; }; +/// An abstract class template for an output device (rumble, LED pattern, polling mode). +class OutputDevice { +public: + virtual ~OutputDevice() = default; + + virtual void SetLED([[maybe_unused]] LedStatus led_status) { + return; + } + + virtual VibrationError SetVibration([[maybe_unused]] VibrationStatus vibration_status) { + return VibrationError::NotSupported; + } + + virtual PollingError SetPollingMode([[maybe_unused]] PollingMode polling_mode) { + return PollingError::NotSupported; + } +}; + /// An abstract class template for a factory that can create input devices. template class Factory { diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index 4eb5d99bc..b9d16657a 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -66,12 +66,32 @@ void EmulatedController::ReloadFromSettings() { for (std::size_t index = 0; index < player.motions.size(); ++index) { motion_params[index] = Common::ParamPackage(player.motions[index]); } + + controller.colors_state.left = { + .body = player.body_color_left, + .button = player.button_color_left, + }; + + controller.colors_state.right = { + .body = player.body_color_right, + .button = player.button_color_right, + }; + + controller.colors_state.fullkey = controller.colors_state.left; + + SetNpadType(MapSettingsTypeToNPad(player.controller_type)); + + if (player.connected) { + Connect(); + } else { + Disconnect(); + } + ReloadInput(); } void EmulatedController::ReloadInput() { const auto player_index = NpadIdTypeToIndex(npad_id_type); - const auto& player = Settings::values.players.GetValue()[player_index]; const auto left_side = button_params[Settings::NativeButton::ZL]; const auto right_side = button_params[Settings::NativeButton::ZR]; @@ -90,21 +110,13 @@ void EmulatedController::ReloadInput() { trigger_devices[1] = Input::CreateDevice(button_params[Settings::NativeButton::ZR]); - controller.colors_state.left = { - .body = player.body_color_left, - .button = player.button_color_left, - }; - - controller.colors_state.right = { - .body = player.body_color_right, - .button = player.button_color_right, - }; - - controller.colors_state.fullkey = controller.colors_state.left; - battery_devices[0] = Input::CreateDevice(left_side); battery_devices[1] = Input::CreateDevice(right_side); + button_params[Settings::NativeButton::ZL].Set("output",true); + output_devices[0] = + Input::CreateDevice(button_params[Settings::NativeButton::ZL]); + for (std::size_t index = 0; index < button_devices.size(); ++index) { if (!button_devices[index]) { continue; @@ -149,14 +161,6 @@ void EmulatedController::ReloadInput() { [this, index](Input::CallbackStatus callback) { SetMotion(callback, index); }}; motion_devices[index]->SetCallback(motion_callback); } - - SetNpadType(MapSettingsTypeToNPad(player.controller_type)); - - if (player.connected) { - Connect(); - } else { - Disconnect(); - } } void EmulatedController::UnloadInput() { @@ -197,7 +201,8 @@ void EmulatedController::SaveCurrentConfig() { const auto player_index = NpadIdTypeToIndex(npad_id_type); auto& player = Settings::values.players.GetValue()[player_index]; - + player.connected = is_connected; + player.controller_type = MapNPadToSettingsType(npad_type); for (std::size_t index = 0; index < player.buttons.size(); ++index) { player.buttons[index] = button_params[index].Serialize(); } @@ -601,13 +606,50 @@ void EmulatedController::SetBattery(Input::CallbackStatus callback, std::size_t TriggerOnChange(ControllerTriggerType::Battery); } -bool EmulatedController::SetVibration([[maybe_unused]] std::size_t device_index, - [[maybe_unused]] VibrationValue vibration) { - return false; +bool EmulatedController::SetVibration(std::size_t device_index, VibrationValue vibration) { + if (!output_devices[device_index]) { + return false; + } + + const Input::VibrationStatus status = { + .low_amplitude = vibration.high_amplitude, + .low_frequency = vibration.high_amplitude, + .high_amplitude = vibration.high_amplitude, + .high_frequency = vibration.high_amplitude, + }; + return output_devices[device_index]->SetVibration(status) == Input::VibrationError::None; +} + +bool EmulatedController::TestVibration(std::size_t device_index) { + if (!output_devices[device_index]) { + return false; + } + + // Send a slight vibration to test for rumble support + constexpr Input::VibrationStatus status = { + .low_amplitude = 0.001f, + .low_frequency = 160.0f, + .high_amplitude = 0.001f, + .high_frequency = 320.0f, + }; + return output_devices[device_index]->SetVibration(status) == Input::VibrationError::None; } -int EmulatedController::TestVibration(std::size_t device_index) { - return 1; +void EmulatedController::SetLedPattern() { + for (auto& device : output_devices) { + if (!device) { + continue; + } + + const LedPattern pattern = GetLedPattern(); + const Input::LedStatus status = { + .led_1 = pattern.position1 != 0, + .led_2 = pattern.position2 != 0, + .led_3 = pattern.position3 != 0, + .led_4 = pattern.position4 != 0, + }; + device->SetLED(status); + } } void EmulatedController::Connect() { @@ -655,6 +697,29 @@ void EmulatedController::SetNpadType(NpadType npad_type_) { TriggerOnChange(ControllerTriggerType::Type); } +LedPattern EmulatedController::GetLedPattern() const { + switch (npad_id_type) { + case NpadIdType::Player1: + return LedPattern{1, 0, 0, 0}; + case NpadIdType::Player2: + return LedPattern{1, 1, 0, 0}; + case NpadIdType::Player3: + return LedPattern{1, 1, 1, 0}; + case NpadIdType::Player4: + return LedPattern{1, 1, 1, 1}; + case NpadIdType::Player5: + return LedPattern{1, 0, 0, 1}; + case NpadIdType::Player6: + return LedPattern{1, 0, 1, 0}; + case NpadIdType::Player7: + return LedPattern{1, 0, 1, 1}; + case NpadIdType::Player8: + return LedPattern{0, 1, 1, 0}; + default: + return LedPattern{0, 0, 0, 0}; + } +} + ButtonValues EmulatedController::GetButtonsValues() const { return controller.button_values; } diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h index 94db9b00b..322d2cab0 100644 --- a/src/core/hid/emulated_controller.h +++ b/src/core/hid/emulated_controller.h @@ -33,12 +33,14 @@ using ControllerMotionDevices = using TriggerDevices = std::array, Settings::NativeTrigger::NumTriggers>; using BatteryDevices = std::array, 2>; +using OutputDevices = std::array, 2>; using ButtonParams = std::array; using StickParams = std::array; using ControllerMotionParams = std::array; using TriggerParams = std::array; using BatteryParams = std::array; +using OutputParams = std::array; using ButtonValues = std::array; using SticksValues = std::array; @@ -94,6 +96,7 @@ struct ControllerStatus { ControllerColors colors_state{}; BatteryLevelState battery_state{}; }; + enum class ControllerTriggerType { Button, Stick, @@ -137,6 +140,9 @@ public: /// Gets the NpadType for this controller. NpadType GetNpadType() const; + /// Gets the NpadType for this controller. + LedPattern GetLedPattern() const; + void Connect(); void Disconnect(); @@ -179,7 +185,9 @@ public: BatteryLevelState GetBattery() const; bool SetVibration(std::size_t device_index, VibrationValue vibration); - int TestVibration(std::size_t device_index); + bool TestVibration(std::size_t device_index); + + void SetLedPattern(); int SetCallback(ControllerUpdateCallback update_callback); void DeleteCallback(int key); @@ -215,13 +223,14 @@ private: ControllerMotionParams motion_params; TriggerParams trigger_params; BatteryParams battery_params; + OutputParams output_params; ButtonDevices button_devices; StickDevices stick_devices; ControllerMotionDevices motion_devices; TriggerDevices trigger_devices; BatteryDevices battery_devices; - // VibrationDevices vibration_devices; + OutputDevices output_devices; mutable std::mutex mutex; std::unordered_map callback_list; diff --git a/src/core/hid/hid_types.h b/src/core/hid/hid_types.h index d3f7930c9..f12a14cb8 100644 --- a/src/core/hid/hid_types.h +++ b/src/core/hid/hid_types.h @@ -112,6 +112,8 @@ struct NpadStyleTag { BitField<7, 1, u32> lark; BitField<8, 1, u32> handheld_lark; BitField<9, 1, u32> lucia; + BitField<10, 1, u32> lagoon; + BitField<11, 1, u32> lager; BitField<29, 1, u32> system_ext; BitField<30, 1, u32> system; }; @@ -175,6 +177,22 @@ struct NpadPowerInfo { }; static_assert(sizeof(NpadPowerInfo) == 0xC, "NpadPowerInfo is an invalid size"); +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; + }; +}; + // This is nn::hid::NpadButton enum class NpadButton : u64 { None = 0, diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index 03cbd42f4..a2e9ddf4d 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -796,7 +796,7 @@ void Controller_NPad::InitializeVibrationDeviceAtIndex(std::size_t npad_index, } controller.vibration[device_index].device_mounted = - controller.device->TestVibration(device_index) == 1; + controller.device->TestVibration(device_index); } void Controller_NPad::SetPermitVibrationSession(bool permit_vibration_session) { @@ -954,31 +954,12 @@ bool Controller_NPad::SwapNpadAssignment(u32 npad_id_1, u32 npad_id_2) { return true; } -Controller_NPad::LedPattern Controller_NPad::GetLedPattern(u32 npad_id) { +Core::HID::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}; + return Core::HID::LedPattern{0, 0, 0, 0}; } + return controller_data[npad_id].device->GetLedPattern(); } bool Controller_NPad::IsUnintendedHomeButtonInputProtectionEnabled(u32 npad_id) const { diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h index 483cae5b6..b0e2f8430 100644 --- a/src/core/hle/service/hid/controllers/npad.h +++ b/src/core/hle/service/hid/controllers/npad.h @@ -115,22 +115,6 @@ public: .freq_high = 320.0f, }; - 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(Core::HID::NpadStyleTag style_set); Core::HID::NpadStyleTag GetSupportedStyleSet() const; @@ -186,7 +170,7 @@ public: void SetSixAxisFusionParameters(f32 parameter1, f32 parameter2); std::pair GetSixAxisFusionParameters(); void ResetSixAxisFusionParameters(); - LedPattern GetLedPattern(u32 npad_id); + Core::HID::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); diff --git a/src/input_common/drivers/gc_adapter.cpp b/src/input_common/drivers/gc_adapter.cpp index 6721ba4f7..2aa5a16a6 100644 --- a/src/input_common/drivers/gc_adapter.cpp +++ b/src/input_common/drivers/gc_adapter.cpp @@ -322,13 +322,17 @@ bool GCAdapter::GetGCEndpoint(libusb_device* device) { return true; } -bool GCAdapter::SetRumble(const PadIdentifier& identifier, const Input::VibrationStatus vibration) { +Input::VibrationError GCAdapter::SetRumble(const PadIdentifier& identifier, const Input::VibrationStatus vibration) { const auto mean_amplitude = (vibration.low_amplitude + vibration.high_amplitude) * 0.5f; const auto processed_amplitude = static_cast((mean_amplitude + std::pow(mean_amplitude, 0.3f)) * 0.5f * 0x8); pads[identifier.port].rumble_amplitude = processed_amplitude; - return rumble_enabled; + + if (!rumble_enabled) { + return Input::VibrationError::Disabled; + } + return Input::VibrationError::None; } void GCAdapter::UpdateVibrations() { diff --git a/src/input_common/drivers/gc_adapter.h b/src/input_common/drivers/gc_adapter.h index c0bf1ed7a..dd23dd9f3 100644 --- a/src/input_common/drivers/gc_adapter.h +++ b/src/input_common/drivers/gc_adapter.h @@ -24,7 +24,7 @@ public: explicit GCAdapter(const std::string input_engine_); ~GCAdapter(); - bool SetRumble(const PadIdentifier& identifier, + Input::VibrationError SetRumble(const PadIdentifier& identifier, const Input::VibrationStatus vibration) override; /// Used for automapping features diff --git a/src/input_common/drivers/sdl_driver.cpp b/src/input_common/drivers/sdl_driver.cpp index efb4a2106..f7f03c5f2 100644 --- a/src/input_common/drivers/sdl_driver.cpp +++ b/src/input_common/drivers/sdl_driver.cpp @@ -506,7 +506,8 @@ std::vector SDLDriver::GetInputDevices() const { } return devices; } -bool SDLDriver::SetRumble(const PadIdentifier& identifier, const Input::VibrationStatus vibration) { +Input::VibrationError SDLDriver::SetRumble(const PadIdentifier& identifier, + const Input::VibrationStatus vibration) { const auto joystick = GetSDLJoystickByGUID(identifier.guid.Format(), static_cast(identifier.port)); const auto process_amplitude = [](f32 amplitude) { @@ -519,7 +520,10 @@ bool SDLDriver::SetRumble(const PadIdentifier& identifier, const Input::Vibratio .high_frequency = vibration.high_frequency, }; - return joystick->RumblePlay(new_vibration); + if (!joystick->RumblePlay(new_vibration)) { + return Input::VibrationError::Unknown; + } + return Input::VibrationError::None; } Common::ParamPackage SDLDriver::BuildAnalogParamPackageForButton(int port, std::string guid, s32 axis, float value) const { diff --git a/src/input_common/drivers/sdl_driver.h b/src/input_common/drivers/sdl_driver.h index d8d350184..f66b33c77 100644 --- a/src/input_common/drivers/sdl_driver.h +++ b/src/input_common/drivers/sdl_driver.h @@ -58,7 +58,7 @@ public: std::string GetHatButtonName(u8 direction_value) const override; u8 GetHatButtonId(const std::string direction_name) const override; - bool SetRumble(const PadIdentifier& identifier, + Input::VibrationError SetRumble(const PadIdentifier& identifier, const Input::VibrationStatus vibration) override; private: diff --git a/src/input_common/helpers/stick_from_buttons.cpp b/src/input_common/helpers/stick_from_buttons.cpp index 38f150746..89ba4aeb1 100644 --- a/src/input_common/helpers/stick_from_buttons.cpp +++ b/src/input_common/helpers/stick_from_buttons.cpp @@ -251,7 +251,8 @@ private: std::chrono::time_point last_update; }; -std::unique_ptr StickFromButton::Create(const Common::ParamPackage& params) { +std::unique_ptr StickFromButton::Create( + const Common::ParamPackage& params) { const std::string null_engine = Common::ParamPackage{{"engine", "null"}}.Serialize(); auto up = Input::CreateDeviceFromString(params.Get("up", null_engine)); auto down = Input::CreateDeviceFromString(params.Get("down", null_engine)); diff --git a/src/input_common/helpers/stick_from_buttons.h b/src/input_common/helpers/stick_from_buttons.h index 1d6e24c98..87165e022 100644 --- a/src/input_common/helpers/stick_from_buttons.h +++ b/src/input_common/helpers/stick_from_buttons.h @@ -25,7 +25,8 @@ public: * - "modifier": a serialized ParamPackage for creating a button device as the modifier * - "modifier_scale": a float for the multiplier the modifier gives to the position */ - std::unique_ptr Create(const Common::ParamPackage& params) override; + std::unique_ptr Create( + const Common::ParamPackage& params) override; }; } // namespace InputCommon diff --git a/src/input_common/helpers/touch_from_buttons.cpp b/src/input_common/helpers/touch_from_buttons.cpp index 2abfaf841..6c9046ffb 100644 --- a/src/input_common/helpers/touch_from_buttons.cpp +++ b/src/input_common/helpers/touch_from_buttons.cpp @@ -57,7 +57,9 @@ private: const Input::AnalogProperties properties{0.0f, 1.0f, 0.5f, 0.0f, false}; }; -std::unique_ptr TouchFromButton::Create(const Common::ParamPackage& params) { + +std::unique_ptr TouchFromButton::Create( + const Common::ParamPackage& params) { const std::string null_engine = Common::ParamPackage{{"engine", "null"}}.Serialize(); auto button = Input::CreateDeviceFromString(params.Get("button", null_engine)); diff --git a/src/input_common/input_engine.h b/src/input_common/input_engine.h index 86a8e00d8..8a953c382 100644 --- a/src/input_common/input_engine.h +++ b/src/input_common/input_engine.h @@ -114,18 +114,24 @@ public: // Disable configuring mode for mapping void EndConfiguration(); - // Sets rumble to a controller - virtual bool SetRumble([[maybe_unused]] const PadIdentifier& identifier, - [[maybe_unused]] const Input::VibrationStatus vibration) { - return false; - } - // Sets a led pattern for a controller virtual void SetLeds([[maybe_unused]] const PadIdentifier& identifier, [[maybe_unused]] const Input::LedStatus led_status) { return; } + // Sets rumble to a controller + virtual Input::VibrationError SetRumble([[maybe_unused]] const PadIdentifier& identifier, + [[maybe_unused]] const Input::VibrationStatus vibration) { + return Input::VibrationError::NotSupported; + } + + // Sets polling mode to a controller + virtual Input::PollingError SetPollingMode([[maybe_unused]] const PadIdentifier& identifier, + [[maybe_unused]] const Input::PollingMode vibration) { + return Input::PollingError::NotSupported; + } + // Returns the engine name [[nodiscard]] const std::string& GetEngineName() const; diff --git a/src/input_common/input_poller.cpp b/src/input_common/input_poller.cpp index 46a7dd276..781012886 100644 --- a/src/input_common/input_poller.cpp +++ b/src/input_common/input_poller.cpp @@ -592,6 +592,28 @@ private: InputEngine* input_engine; }; +class OutputFromIdentifier final : public Input::OutputDevice { +public: + explicit OutputFromIdentifier(PadIdentifier identifier_, InputEngine* input_engine_) + : identifier(identifier_), input_engine(input_engine_) {} + + virtual void SetLED( Input::LedStatus led_status) { + input_engine->SetLeds(identifier, led_status); + } + + virtual Input::VibrationError SetVibration(Input::VibrationStatus vibration_status) { + return input_engine->SetRumble(identifier, vibration_status); + } + + virtual Input::PollingError SetPollingMode(Input::PollingMode polling_mode) { + return input_engine->SetPollingMode(identifier, polling_mode); + } + +private: + const PadIdentifier identifier; + InputEngine* input_engine; +}; + std::unique_ptr InputFactory::CreateButtonDevice( const Common::ParamPackage& params) { const PadIdentifier identifier = { @@ -825,7 +847,8 @@ std::unique_ptr InputFactory::CreateMotionDevice(Common::Par InputFactory::InputFactory(std::shared_ptr input_engine_) : input_engine(std::move(input_engine_)) {} -std::unique_ptr InputFactory::Create(const Common::ParamPackage& params) { +std::unique_ptr InputFactory::Create( + const Common::ParamPackage& params) { if (params.Has("button") && params.Has("axis")) { return CreateTriggerDevice(params); } @@ -857,4 +880,19 @@ std::unique_ptr InputFactory::Create(const Common::ParamPack return std::make_unique(); } +OutputFactory::OutputFactory(std::shared_ptr input_engine_) + : input_engine(std::move(input_engine_)) {} + +std::unique_ptr OutputFactory::Create( + const Common::ParamPackage& params) { + const PadIdentifier identifier = { + .guid = Common::UUID{params.Get("guid", "")}, + .port = static_cast(params.Get("port", 0)), + .pad = static_cast(params.Get("pad", 0)), + }; + + input_engine->PreSetController(identifier); + return std::make_unique(identifier, input_engine.get()); +} + } // namespace InputCommon diff --git a/src/input_common/input_poller.h b/src/input_common/input_poller.h index 3c1e5b541..16cade5fa 100644 --- a/src/input_common/input_poller.h +++ b/src/input_common/input_poller.h @@ -16,12 +16,32 @@ class InputEngine; /** * An Input factory. It receives input events and forward them to all input devices it created. */ + +class OutputFactory final : public Input::Factory { +public: + explicit OutputFactory(std::shared_ptr input_engine_); + + /** + * Creates an output device from the parameters given. + * @param params contains parameters for creating the device: + * @param - "guid": text string for identifing controllers + * @param - "port": port of the connected device + * @param - "pad": slot of the connected controller + * @return an unique ouput device with the parameters specified + */ + std::unique_ptr Create( + const Common::ParamPackage& params) override; + +private: + std::shared_ptr input_engine; +}; + class InputFactory final : public Input::Factory { public: explicit InputFactory(std::shared_ptr input_engine_); /** - * Creates a input device from the parameters given. Identifies the type of input to be returned + * Creates an input device from the parameters given. Identifies the type of input to be returned * if it contains the following parameters: * - button: Contains "button" or "code" * - hat_button: Contains "hat" @@ -32,6 +52,7 @@ public: * - motion: Contains "motion" * - touch: Contains "button", "axis_x" and "axis_y" * - battery: Contains "battery" + * - output: Contains "output" * @param params contains parameters for creating the device: * @param - "code": the code of the keyboard key to bind with the input * @param - "button": same as "code" but for controller buttons @@ -41,10 +62,11 @@ public: * @param - "axis_x": same as axis but specifing horizontal direction * @param - "axis_y": same as axis but specifing vertical direction * @param - "axis_z": same as axis but specifing forward direction - * @param - "battery": Only used as a placeholder to set the input type + * @param - "battery": Only used as a placeholder to set the input type * @return an unique input device with the parameters specified */ - std::unique_ptr Create(const Common::ParamPackage& params) override; + std::unique_ptr Create( + const Common::ParamPackage& params) override; private: /** diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp index 46ca6b76c..b7fe9cb37 100644 --- a/src/input_common/main.cpp +++ b/src/input_common/main.cpp @@ -46,8 +46,10 @@ struct InputSubsystem::Impl { gcadapter = std::make_shared("gcpad"); gcadapter->SetMappingCallback(mapping_callback); - gcadapter_factory = std::make_shared(gcadapter); - Input::RegisterFactory(gcadapter->GetEngineName(), gcadapter_factory); + gcadapter_input_factory = std::make_shared(gcadapter); + gcadapter_output_factory = std::make_shared(gcadapter); + Input::RegisterFactory(gcadapter->GetEngineName(), gcadapter_input_factory); + Input::RegisterFactory(gcadapter->GetEngineName(), gcadapter_output_factory); udp_client = std::make_shared("cemuhookudp"); udp_client->SetMappingCallback(mapping_callback); @@ -62,8 +64,10 @@ struct InputSubsystem::Impl { #ifdef HAVE_SDL2 sdl = std::make_shared("sdl"); sdl->SetMappingCallback(mapping_callback); - sdl_factory = std::make_shared(sdl); - Input::RegisterFactory(sdl->GetEngineName(), sdl_factory); + sdl_input_factory = std::make_shared(sdl); + sdl_output_factory = std::make_shared(sdl); + Input::RegisterFactory(sdl->GetEngineName(), sdl_input_factory); + Input::RegisterFactory(sdl->GetEngineName(), sdl_output_factory); #endif Input::RegisterFactory("touch_from_button", @@ -247,21 +251,27 @@ struct InputSubsystem::Impl { } std::shared_ptr mapping_factory; + std::shared_ptr keyboard; - std::shared_ptr keyboard_factory; std::shared_ptr mouse; - std::shared_ptr mouse_factory; std::shared_ptr gcadapter; - std::shared_ptr gcadapter_factory; std::shared_ptr touch_screen; - std::shared_ptr touch_screen_factory; + std::shared_ptr 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; std::shared_ptr tas_input_factory; + + std::shared_ptr gcadapter_output_factory; + #ifdef HAVE_SDL2 std::shared_ptr sdl; - std::shared_ptr sdl_factory; + std::shared_ptr sdl_input_factory; + std::shared_ptr sdl_output_factory; #endif }; diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index adc9706f1..ed9c3facf 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp @@ -465,6 +465,8 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i UpdateControllerEnabledButtons(); UpdateControllerButtonNames(); UpdateMotionButtons(); + emulated_controller->SetNpadType( + GetControllerTypeFromIndex(ui->comboControllerType->currentIndex())); }); connect(ui->comboDevices, qOverload(&QComboBox::activated), this, @@ -540,6 +542,11 @@ void ConfigureInputPlayer::LoadConfiguration() { void ConfigureInputPlayer::ConnectPlayer(bool connected) { ui->groupConnectedController->setChecked(connected); + if (connected) { + emulated_controller->Connect(); + } else { + emulated_controller->Disconnect(); + } } void ConfigureInputPlayer::UpdateInputDeviceCombobox() { diff --git a/src/yuzu/configuration/configure_input_player_widget.cpp b/src/yuzu/configuration/configure_input_player_widget.cpp index 03d29f194..2ba9d7290 100644 --- a/src/yuzu/configuration/configure_input_player_widget.cpp +++ b/src/yuzu/configuration/configure_input_player_widget.cpp @@ -24,34 +24,6 @@ PlayerControlPreview::~PlayerControlPreview() { } }; -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::SetController(Core::HID::EmulatedController* controller_) { if (is_controller_set) { controller->DeleteCallback(callback_key); @@ -160,8 +132,13 @@ void PlayerControlPreview::ControllerUpdate(Core::HID::ControllerTriggerType typ 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 = controller->IsConnected(); + is_connected = false; + led_pattern.raw = 0; needs_redraw = true; break; case Core::HID::ControllerTriggerType::Type: @@ -1853,10 +1830,14 @@ 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; - for (const auto& color : led_color) { - p.setBrush(color); - DrawRectangle(p, led_position + QPointF(0, 12 * led_count++), led_size, led_size); - } + 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); } void PlayerControlPreview::DrawRightBody(QPainter& p, const QPointF center) { @@ -1949,10 +1930,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; - for (const auto& color : led_color) { - p.setBrush(color); - DrawRectangle(p, led_position + QPointF(0, 12 * led_count++), led_size, led_size); - } + 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); } void PlayerControlPreview::DrawProTriggers(QPainter& p, const QPointF center, diff --git a/src/yuzu/configuration/configure_input_player_widget.h b/src/yuzu/configuration/configure_input_player_widget.h index b44a2e347..16f9748f5 100644 --- a/src/yuzu/configuration/configure_input_player_widget.h +++ b/src/yuzu/configuration/configure_input_player_widget.h @@ -59,13 +59,6 @@ private: SR, }; - struct LedPattern { - bool position1; - bool position2; - bool position3; - bool position4; - }; - struct ColorMapping { QColor outline{}; QColor primary{}; @@ -88,7 +81,6 @@ private: QColor deadzone{}; }; - static LedPattern GetColorPattern(std::size_t index, bool player_on); void UpdateColors(); void ResetInputs(); @@ -194,7 +186,7 @@ private: int callback_key; QColor button_color{}; ColorMapping colors{}; - std::array led_color{}; + Core::HID::LedPattern led_pattern{0, 0, 0, 0}; std::size_t player_index{}; Core::HID::EmulatedController* controller; std::size_t button_mapping_index{Settings::NativeButton::NumButtons}; -- cgit v1.2.3 From e0da5c1bbcdf85676f968b63c8ae2587f0464193 Mon Sep 17 00:00:00 2001 From: german77 Date: Fri, 15 Oct 2021 19:07:47 -0500 Subject: kraken: Fix errors from rebase and format files --- src/core/hid/emulated_controller.cpp | 6 +++++- src/core/hle/service/hid/hid.cpp | 1 - src/input_common/drivers/gc_adapter.cpp | 3 ++- src/input_common/drivers/gc_adapter.h | 2 +- src/input_common/drivers/sdl_driver.h | 2 +- src/input_common/helpers/stick_from_buttons.cpp | 3 +-- src/input_common/helpers/stick_from_buttons.h | 3 +-- src/input_common/helpers/touch_from_buttons.cpp | 4 +--- src/input_common/input_engine.h | 10 +++++---- src/input_common/input_poller.cpp | 8 +++---- src/input_common/input_poller.h | 10 ++++----- src/input_common/main.cpp | 6 ++++-- src/yuzu/applets/qt_controller.h | 1 - src/yuzu/configuration/configure_dialog.cpp | 2 +- src/yuzu/configuration/configure_input.cpp | 9 ++++---- .../configure_input_player_widget.cpp | 25 ++++++++++++---------- .../configuration/configure_input_player_widget.h | 16 +++++++++++++- src/yuzu/debugger/controller.cpp | 9 ++++++-- src/yuzu/debugger/controller.h | 9 +++++++- src/yuzu/main.cpp | 7 +++--- 20 files changed, 83 insertions(+), 53 deletions(-) (limited to 'src/input_common/drivers') diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index b9d16657a..b04ab4cd8 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -91,6 +91,7 @@ void EmulatedController::ReloadFromSettings() { } void EmulatedController::ReloadInput() { + // If you load any device here add the equivalent to the UnloadInput() function const auto player_index = NpadIdTypeToIndex(npad_id_type); const auto left_side = button_params[Settings::NativeButton::ZL]; const auto right_side = button_params[Settings::NativeButton::ZR]; @@ -113,7 +114,7 @@ void EmulatedController::ReloadInput() { battery_devices[0] = Input::CreateDevice(left_side); battery_devices[1] = Input::CreateDevice(right_side); - button_params[Settings::NativeButton::ZL].Set("output",true); + button_params[Settings::NativeButton::ZL].Set("output", true); output_devices[0] = Input::CreateDevice(button_params[Settings::NativeButton::ZL]); @@ -179,6 +180,9 @@ void EmulatedController::UnloadInput() { for (auto& battery : battery_devices) { battery.reset(); } + for (auto& output : output_devices) { + output.reset(); + } } void EmulatedController::EnableConfiguration() { diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 18f29bb78..5391334f4 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -8,7 +8,6 @@ #include "common/settings.h" #include "core/core.h" #include "core/core_timing.h" -#include "core/frontend/input.h" #include "core/hardware_properties.h" #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/k_readable_event.h" diff --git a/src/input_common/drivers/gc_adapter.cpp b/src/input_common/drivers/gc_adapter.cpp index 2aa5a16a6..4a56abb99 100644 --- a/src/input_common/drivers/gc_adapter.cpp +++ b/src/input_common/drivers/gc_adapter.cpp @@ -322,7 +322,8 @@ bool GCAdapter::GetGCEndpoint(libusb_device* device) { return true; } -Input::VibrationError GCAdapter::SetRumble(const PadIdentifier& identifier, const Input::VibrationStatus vibration) { +Input::VibrationError GCAdapter::SetRumble(const PadIdentifier& identifier, + const Input::VibrationStatus vibration) { const auto mean_amplitude = (vibration.low_amplitude + vibration.high_amplitude) * 0.5f; const auto processed_amplitude = static_cast((mean_amplitude + std::pow(mean_amplitude, 0.3f)) * 0.5f * 0x8); diff --git a/src/input_common/drivers/gc_adapter.h b/src/input_common/drivers/gc_adapter.h index dd23dd9f3..dd0e4aa1d 100644 --- a/src/input_common/drivers/gc_adapter.h +++ b/src/input_common/drivers/gc_adapter.h @@ -25,7 +25,7 @@ public: ~GCAdapter(); Input::VibrationError SetRumble(const PadIdentifier& identifier, - const Input::VibrationStatus vibration) override; + const Input::VibrationStatus vibration) override; /// Used for automapping features std::vector GetInputDevices() const override; diff --git a/src/input_common/drivers/sdl_driver.h b/src/input_common/drivers/sdl_driver.h index f66b33c77..1ff85f48d 100644 --- a/src/input_common/drivers/sdl_driver.h +++ b/src/input_common/drivers/sdl_driver.h @@ -59,7 +59,7 @@ public: u8 GetHatButtonId(const std::string direction_name) const override; Input::VibrationError SetRumble(const PadIdentifier& identifier, - const Input::VibrationStatus vibration) override; + const Input::VibrationStatus vibration) override; private: void InitJoystick(int joystick_index); diff --git a/src/input_common/helpers/stick_from_buttons.cpp b/src/input_common/helpers/stick_from_buttons.cpp index 89ba4aeb1..38f150746 100644 --- a/src/input_common/helpers/stick_from_buttons.cpp +++ b/src/input_common/helpers/stick_from_buttons.cpp @@ -251,8 +251,7 @@ private: std::chrono::time_point last_update; }; -std::unique_ptr StickFromButton::Create( - const Common::ParamPackage& params) { +std::unique_ptr StickFromButton::Create(const Common::ParamPackage& params) { const std::string null_engine = Common::ParamPackage{{"engine", "null"}}.Serialize(); auto up = Input::CreateDeviceFromString(params.Get("up", null_engine)); auto down = Input::CreateDeviceFromString(params.Get("down", null_engine)); diff --git a/src/input_common/helpers/stick_from_buttons.h b/src/input_common/helpers/stick_from_buttons.h index 87165e022..1d6e24c98 100644 --- a/src/input_common/helpers/stick_from_buttons.h +++ b/src/input_common/helpers/stick_from_buttons.h @@ -25,8 +25,7 @@ public: * - "modifier": a serialized ParamPackage for creating a button device as the modifier * - "modifier_scale": a float for the multiplier the modifier gives to the position */ - std::unique_ptr Create( - const Common::ParamPackage& params) override; + std::unique_ptr Create(const Common::ParamPackage& params) override; }; } // namespace InputCommon diff --git a/src/input_common/helpers/touch_from_buttons.cpp b/src/input_common/helpers/touch_from_buttons.cpp index 6c9046ffb..2abfaf841 100644 --- a/src/input_common/helpers/touch_from_buttons.cpp +++ b/src/input_common/helpers/touch_from_buttons.cpp @@ -57,9 +57,7 @@ private: const Input::AnalogProperties properties{0.0f, 1.0f, 0.5f, 0.0f, false}; }; - -std::unique_ptr TouchFromButton::Create( - const Common::ParamPackage& params) { +std::unique_ptr TouchFromButton::Create(const Common::ParamPackage& params) { const std::string null_engine = Common::ParamPackage{{"engine", "null"}}.Serialize(); auto button = Input::CreateDeviceFromString(params.Get("button", null_engine)); diff --git a/src/input_common/input_engine.h b/src/input_common/input_engine.h index 8a953c382..31ce900d7 100644 --- a/src/input_common/input_engine.h +++ b/src/input_common/input_engine.h @@ -121,14 +121,16 @@ public: } // Sets rumble to a controller - virtual Input::VibrationError SetRumble([[maybe_unused]] const PadIdentifier& identifier, - [[maybe_unused]] const Input::VibrationStatus vibration) { + virtual Input::VibrationError SetRumble( + [[maybe_unused]] const PadIdentifier& identifier, + [[maybe_unused]] const Input::VibrationStatus vibration) { return Input::VibrationError::NotSupported; } // Sets polling mode to a controller - virtual Input::PollingError SetPollingMode([[maybe_unused]] const PadIdentifier& identifier, - [[maybe_unused]] const Input::PollingMode vibration) { + virtual Input::PollingError SetPollingMode( + [[maybe_unused]] const PadIdentifier& identifier, + [[maybe_unused]] const Input::PollingMode vibration) { return Input::PollingError::NotSupported; } diff --git a/src/input_common/input_poller.cpp b/src/input_common/input_poller.cpp index 781012886..62ade951c 100644 --- a/src/input_common/input_poller.cpp +++ b/src/input_common/input_poller.cpp @@ -597,7 +597,7 @@ public: explicit OutputFromIdentifier(PadIdentifier identifier_, InputEngine* input_engine_) : identifier(identifier_), input_engine(input_engine_) {} - virtual void SetLED( Input::LedStatus led_status) { + virtual void SetLED(Input::LedStatus led_status) { input_engine->SetLeds(identifier, led_status); } @@ -847,8 +847,7 @@ std::unique_ptr InputFactory::CreateMotionDevice(Common::Par InputFactory::InputFactory(std::shared_ptr input_engine_) : input_engine(std::move(input_engine_)) {} -std::unique_ptr InputFactory::Create( - const Common::ParamPackage& params) { +std::unique_ptr InputFactory::Create(const Common::ParamPackage& params) { if (params.Has("button") && params.Has("axis")) { return CreateTriggerDevice(params); } @@ -883,8 +882,7 @@ std::unique_ptr InputFactory::Create( OutputFactory::OutputFactory(std::shared_ptr input_engine_) : input_engine(std::move(input_engine_)) {} -std::unique_ptr OutputFactory::Create( - const Common::ParamPackage& params) { +std::unique_ptr OutputFactory::Create(const Common::ParamPackage& params) { const PadIdentifier identifier = { .guid = Common::UUID{params.Get("guid", "")}, .port = static_cast(params.Get("port", 0)), diff --git a/src/input_common/input_poller.h b/src/input_common/input_poller.h index 16cade5fa..1357e104b 100644 --- a/src/input_common/input_poller.h +++ b/src/input_common/input_poller.h @@ -29,8 +29,7 @@ public: * @param - "pad": slot of the connected controller * @return an unique ouput device with the parameters specified */ - std::unique_ptr Create( - const Common::ParamPackage& params) override; + std::unique_ptr Create(const Common::ParamPackage& params) override; private: std::shared_ptr input_engine; @@ -41,8 +40,8 @@ public: explicit InputFactory(std::shared_ptr input_engine_); /** - * Creates an input device from the parameters given. Identifies the type of input to be returned - * if it contains the following parameters: + * Creates an input device from the parameters given. Identifies the type of input to be + * returned if it contains the following parameters: * - button: Contains "button" or "code" * - hat_button: Contains "hat" * - analog: Contains "axis" @@ -65,8 +64,7 @@ public: * @param - "battery": Only used as a placeholder to set the input type * @return an unique input device with the parameters specified */ - std::unique_ptr Create( - const Common::ParamPackage& params) override; + std::unique_ptr Create(const Common::ParamPackage& params) override; private: /** diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp index b7fe9cb37..7807dd38f 100644 --- a/src/input_common/main.cpp +++ b/src/input_common/main.cpp @@ -48,8 +48,10 @@ struct InputSubsystem::Impl { gcadapter->SetMappingCallback(mapping_callback); gcadapter_input_factory = std::make_shared(gcadapter); gcadapter_output_factory = std::make_shared(gcadapter); - Input::RegisterFactory(gcadapter->GetEngineName(), gcadapter_input_factory); - Input::RegisterFactory(gcadapter->GetEngineName(), gcadapter_output_factory); + Input::RegisterFactory(gcadapter->GetEngineName(), + gcadapter_input_factory); + Input::RegisterFactory(gcadapter->GetEngineName(), + gcadapter_output_factory); udp_client = std::make_shared("cemuhookudp"); udp_client->SetMappingCallback(mapping_callback); diff --git a/src/yuzu/applets/qt_controller.h b/src/yuzu/applets/qt_controller.h index 98060e6f8..ca09fde04 100644 --- a/src/yuzu/applets/qt_controller.h +++ b/src/yuzu/applets/qt_controller.h @@ -106,7 +106,6 @@ private: Core::Frontend::ControllerParameters parameters; InputCommon::InputSubsystem* input_subsystem; - Core::System& system; std::unique_ptr input_profiles; diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp index 642a5f966..1eb9d70e5 100644 --- a/src/yuzu/configuration/configure_dialog.cpp +++ b/src/yuzu/configuration/configure_dialog.cpp @@ -74,7 +74,7 @@ ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry, hotkeys_tab->Populate(registry); setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); - input_tab->Initialize(input_subsystem); + input_tab->Initialize(input_subsystem, system_); general_tab->SetResetCallback([&] { this->close(); }); diff --git a/src/yuzu/configuration/configure_input.cpp b/src/yuzu/configuration/configure_input.cpp index 61513865f..a8611f77f 100644 --- a/src/yuzu/configuration/configure_input.cpp +++ b/src/yuzu/configuration/configure_input.cpp @@ -146,10 +146,11 @@ void ConfigureInput::Initialize(InputCommon::InputSubsystem* input_subsystem, Co advanced = new ConfigureInputAdvanced(this); ui->tabAdvanced->setLayout(new QHBoxLayout(ui->tabAdvanced)); ui->tabAdvanced->layout()->addWidget(advanced); - connect(advanced, &ConfigureInputAdvanced::CallDebugControllerDialog, [this, input_subsystem] { - CallConfigureDialog(*this, input_subsystem, profiles.get(), - system); - }); + connect(advanced, &ConfigureInputAdvanced::CallDebugControllerDialog, + [this, input_subsystem, &system] { + CallConfigureDialog(*this, input_subsystem, + profiles.get(), system); + }); connect(advanced, &ConfigureInputAdvanced::CallMouseConfigDialog, [this, input_subsystem] { CallConfigureDialog(*this, input_subsystem); }); diff --git a/src/yuzu/configuration/configure_input_player_widget.cpp b/src/yuzu/configuration/configure_input_player_widget.cpp index 2ba9d7290..446b72e55 100644 --- a/src/yuzu/configuration/configure_input_player_widget.cpp +++ b/src/yuzu/configuration/configure_input_player_widget.cpp @@ -19,15 +19,11 @@ PlayerControlPreview::PlayerControlPreview(QWidget* parent) : QFrame(parent) { } PlayerControlPreview::~PlayerControlPreview() { - if (is_controller_set) { - controller->DeleteCallback(callback_key); - } + UnloadController(); }; void PlayerControlPreview::SetController(Core::HID::EmulatedController* controller_) { - if (is_controller_set) { - controller->DeleteCallback(callback_key); - } + UnloadController(); is_controller_set = true; controller = controller_; Core::HID::ControllerUpdateCallback engine_callback{ @@ -36,14 +32,21 @@ void PlayerControlPreview::SetController(Core::HID::EmulatedController* controll ControllerUpdate(Core::HID::ControllerTriggerType::All); } -void PlayerControlPreview::BeginMappingButton(std::size_t index) { - button_mapping_index = index; +void PlayerControlPreview::UnloadController() { + if (is_controller_set) { + controller->DeleteCallback(callback_key); + is_controller_set = false; + } +} + +void PlayerControlPreview::BeginMappingButton(std::size_t button_id) { + button_mapping_index = button_id; mapping_active = true; } -void PlayerControlPreview::BeginMappingAnalog(std::size_t index) { - button_mapping_index = Settings::NativeButton::LStick + index; - analog_mapping_index = index; +void PlayerControlPreview::BeginMappingAnalog(std::size_t stick_id) { + button_mapping_index = Settings::NativeButton::LStick + stick_id; + analog_mapping_index = stick_id; mapping_active = true; } diff --git a/src/yuzu/configuration/configure_input_player_widget.h b/src/yuzu/configuration/configure_input_player_widget.h index 16f9748f5..333c3fc56 100644 --- a/src/yuzu/configuration/configure_input_player_widget.h +++ b/src/yuzu/configuration/configure_input_player_widget.h @@ -25,11 +25,25 @@ 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 BeginMappingButton(std::size_t button_id); - void BeginMappingAnalog(std::size_t button_id); + + // Starts moving animation at the stick specified + void BeginMappingAnalog(std::size_t stick_id); + + // Stops any ongoing animation void EndMapping(); + + // Handles emulated controller events void ControllerUpdate(Core::HID::ControllerTriggerType type); + + // Updates input on sheduled interval void UpdateInput(); protected: diff --git a/src/yuzu/debugger/controller.cpp b/src/yuzu/debugger/controller.cpp index d8e41f8b6..3619aed26 100644 --- a/src/yuzu/debugger/controller.cpp +++ b/src/yuzu/debugger/controller.cpp @@ -10,7 +10,8 @@ #include "yuzu/configuration/configure_input_player_widget.h" #include "yuzu/debugger/controller.h" -ControllerDialog::ControllerDialog(QWidget* parent) : QWidget(parent, Qt::Dialog) { +ControllerDialog::ControllerDialog(Core::System& system, QWidget* parent) + : QWidget(parent, Qt::Dialog) { setObjectName(QStringLiteral("Controller")); setWindowTitle(tr("Controller P1")); resize(500, 350); @@ -20,7 +21,7 @@ ControllerDialog::ControllerDialog(QWidget* parent) : QWidget(parent, Qt::Dialog Qt::WindowMaximizeButtonHint); widget = new PlayerControlPreview(this); - widget->SetController(Core::System::GetInstance().HIDCore().GetEmulatedController( + widget->SetController(system.HIDCore().GetEmulatedController( Core::HID::NpadIdType::Player1)); QLayout* layout = new QVBoxLayout(this); layout->setContentsMargins(0, 0, 0, 0); @@ -45,6 +46,10 @@ QAction* ControllerDialog::toggleViewAction() { return toggle_view_action; } +void ControllerDialog::UnloadController() { + widget->UnloadController(); +} + void ControllerDialog::showEvent(QShowEvent* ev) { if (toggle_view_action) { toggle_view_action->setChecked(isVisible()); diff --git a/src/yuzu/debugger/controller.h b/src/yuzu/debugger/controller.h index 697489cbb..33f617b9b 100644 --- a/src/yuzu/debugger/controller.h +++ b/src/yuzu/debugger/controller.h @@ -11,6 +11,10 @@ class QHideEvent; class QShowEvent; class PlayerControlPreview; +namespace Core { +class System; +} + namespace InputCommon { class InputSubsystem; } @@ -19,11 +23,14 @@ class ControllerDialog : public QWidget { Q_OBJECT public: - explicit ControllerDialog(QWidget* parent = nullptr); + explicit ControllerDialog(Core::System& system, QWidget* parent = nullptr); /// Returns a QAction that can be used to toggle visibility of this dialog. QAction* toggleViewAction(); + // Disables events from the emulated controller + void UnloadController(); + protected: void showEvent(QShowEvent* ev) override; void hideEvent(QHideEvent* ev) override; diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 19cb5313f..ae997ccfa 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -228,7 +228,7 @@ GMainWindow::GMainWindow() ConnectMenuEvents(); ConnectWidgetEvents(); - Core::System::GetInstance().HIDCore().ReloadInputDevices(); + system->HIDCore().ReloadInputDevices(); const auto branch_name = std::string(Common::g_scm_branch); const auto description = std::string(Common::g_scm_desc); @@ -924,7 +924,7 @@ void GMainWindow::InitializeDebugWidgets() { waitTreeWidget->hide(); debug_menu->addAction(waitTreeWidget->toggleViewAction()); - controller_dialog = new ControllerDialog(this); + controller_dialog = new ControllerDialog(*system, this); controller_dialog->hide(); debug_menu->addAction(controller_dialog->toggleViewAction()); @@ -3372,7 +3372,8 @@ void GMainWindow::closeEvent(QCloseEvent* event) { UpdateUISettings(); game_list->SaveInterfaceLayout(); hotkey_registry.SaveHotkeys(); - Core::System::GetInstance().HIDCore().UnloadInputDevices(); + controller_dialog->UnloadController(); + system->HIDCore().UnloadInputDevices(); // Shutdown session if the emu thread is active... if (emu_thread != nullptr) { -- cgit v1.2.3 From 601ac43495904f3f7666d79a800a8b4eda5a8461 Mon Sep 17 00:00:00 2001 From: german77 Date: Tue, 19 Oct 2021 00:12:24 -0500 Subject: core/hid: Only signal when needed --- src/common/input.h | 1 + src/core/hid/emulated_controller.cpp | 259 +++++++++++---------- src/core/hid/emulated_controller.h | 6 +- src/core/hid/input_converter.cpp | 2 +- src/core/hle/service/hid/controllers/npad.cpp | 6 +- src/input_common/drivers/gc_adapter.cpp | 75 +++++- src/input_common/drivers/gc_adapter.h | 6 +- src/input_common/drivers/keyboard.cpp | 2 +- src/input_common/drivers/sdl_driver.cpp | 22 +- src/input_common/drivers/tas_input.cpp | 2 +- .../configure_input_player_widget.cpp | 12 +- 11 files changed, 240 insertions(+), 153 deletions(-) (limited to 'src/input_common/drivers') diff --git a/src/common/input.h b/src/common/input.h index 3a28b77a7..8871a9d07 100644 --- a/src/common/input.h +++ b/src/common/input.h @@ -30,6 +30,7 @@ enum class InputType { }; enum class BatteryLevel { + None, Empty, Critical, Low, diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index 7ef6ef118..e102c9437 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -94,7 +94,6 @@ void EmulatedController::ReloadFromSettings() { void EmulatedController::ReloadInput() { //LOG_ERROR(Service_HID, "reload config {}", NpadIdTypeToIndex(npad_id_type)); // If you load any device here add the equivalent to the UnloadInput() function - const auto player_index = NpadIdTypeToIndex(npad_id_type); const auto left_side = button_params[Settings::NativeButton::ZL]; const auto right_side = button_params[Settings::NativeButton::ZR]; @@ -337,120 +336,130 @@ void EmulatedController::SetButton(Input::CallbackStatus callback, std::size_t i if (index >= controller.button_values.size()) { return; } - std::lock_guard lock{mutex}; - bool value_changed = false; - const auto new_status = TransformToButton(callback); - auto& current_status = controller.button_values[index]; - current_status.toggle = new_status.toggle; - - // Update button status with current - if (!current_status.toggle) { - current_status.locked = false; - if (current_status.value != new_status.value) { - current_status.value = new_status.value; - value_changed = true; - } - } else { - // Toggle button and lock status - if (new_status.value && !current_status.locked) { - current_status.locked = true; - current_status.value = !current_status.value; - value_changed = true; - } + { + std::lock_guard lock{mutex}; + bool value_changed = false; + const auto new_status = TransformToButton(callback); + auto& current_status = controller.button_values[index]; + current_status.toggle = new_status.toggle; - // Unlock button ready for next press - if (!new_status.value && current_status.locked) { + // Update button status with current + if (!current_status.toggle) { current_status.locked = false; + if (current_status.value != new_status.value) { + current_status.value = new_status.value; + value_changed = true; + } + } else { + // Toggle button and lock status + if (new_status.value && !current_status.locked) { + current_status.locked = true; + current_status.value = !current_status.value; + value_changed = true; + } + + // Unlock button ready for next press + if (!new_status.value && current_status.locked) { + current_status.locked = false; + } } - } - if (!value_changed) { - return; - } + if (!value_changed) { + return; + } - if (is_configuring) { - controller.npad_button_state.raw = NpadButton::None; - controller.debug_pad_button_state.raw = 0; - TriggerOnChange(ControllerTriggerType::Button); - return; - } + if (is_configuring) { + controller.npad_button_state.raw = NpadButton::None; + controller.debug_pad_button_state.raw = 0; + TriggerOnChange(ControllerTriggerType::Button, false); + return; + } - switch (index) { - case Settings::NativeButton::A: - controller.npad_button_state.a.Assign(current_status.value); - controller.debug_pad_button_state.a.Assign(current_status.value); - break; - case Settings::NativeButton::B: - controller.npad_button_state.b.Assign(current_status.value); - controller.debug_pad_button_state.b.Assign(current_status.value); - break; - case Settings::NativeButton::X: - controller.npad_button_state.x.Assign(current_status.value); - controller.debug_pad_button_state.x.Assign(current_status.value); - break; - case Settings::NativeButton::Y: - controller.npad_button_state.y.Assign(current_status.value); - controller.debug_pad_button_state.y.Assign(current_status.value); - break; - case Settings::NativeButton::LStick: - controller.npad_button_state.stick_l.Assign(current_status.value); - break; - case Settings::NativeButton::RStick: - controller.npad_button_state.stick_r.Assign(current_status.value); - break; - case Settings::NativeButton::L: - controller.npad_button_state.l.Assign(current_status.value); - controller.debug_pad_button_state.l.Assign(current_status.value); - break; - case Settings::NativeButton::R: - controller.npad_button_state.r.Assign(current_status.value); - controller.debug_pad_button_state.r.Assign(current_status.value); - break; - case Settings::NativeButton::ZL: - controller.npad_button_state.zl.Assign(current_status.value); - controller.debug_pad_button_state.zl.Assign(current_status.value); - break; - case Settings::NativeButton::ZR: - controller.npad_button_state.zr.Assign(current_status.value); - controller.debug_pad_button_state.zr.Assign(current_status.value); - break; - case Settings::NativeButton::Plus: - controller.npad_button_state.plus.Assign(current_status.value); - controller.debug_pad_button_state.plus.Assign(current_status.value); - break; - case Settings::NativeButton::Minus: - controller.npad_button_state.minus.Assign(current_status.value); - controller.debug_pad_button_state.minus.Assign(current_status.value); - break; - case Settings::NativeButton::DLeft: - controller.npad_button_state.left.Assign(current_status.value); - controller.debug_pad_button_state.d_left.Assign(current_status.value); - break; - case Settings::NativeButton::DUp: - controller.npad_button_state.up.Assign(current_status.value); - controller.debug_pad_button_state.d_up.Assign(current_status.value); - break; - case Settings::NativeButton::DRight: - controller.npad_button_state.right.Assign(current_status.value); - controller.debug_pad_button_state.d_right.Assign(current_status.value); - break; - case Settings::NativeButton::DDown: - controller.npad_button_state.down.Assign(current_status.value); - controller.debug_pad_button_state.d_down.Assign(current_status.value); - break; - case Settings::NativeButton::SL: - controller.npad_button_state.left_sl.Assign(current_status.value); - controller.npad_button_state.right_sl.Assign(current_status.value); - break; - case Settings::NativeButton::SR: - controller.npad_button_state.left_sr.Assign(current_status.value); - controller.npad_button_state.right_sr.Assign(current_status.value); - break; - case Settings::NativeButton::Home: - case Settings::NativeButton::Screenshot: - break; + switch (index) { + case Settings::NativeButton::A: + controller.npad_button_state.a.Assign(current_status.value); + controller.debug_pad_button_state.a.Assign(current_status.value); + break; + case Settings::NativeButton::B: + controller.npad_button_state.b.Assign(current_status.value); + controller.debug_pad_button_state.b.Assign(current_status.value); + break; + case Settings::NativeButton::X: + controller.npad_button_state.x.Assign(current_status.value); + controller.debug_pad_button_state.x.Assign(current_status.value); + break; + case Settings::NativeButton::Y: + controller.npad_button_state.y.Assign(current_status.value); + controller.debug_pad_button_state.y.Assign(current_status.value); + break; + case Settings::NativeButton::LStick: + controller.npad_button_state.stick_l.Assign(current_status.value); + break; + case Settings::NativeButton::RStick: + controller.npad_button_state.stick_r.Assign(current_status.value); + break; + case Settings::NativeButton::L: + controller.npad_button_state.l.Assign(current_status.value); + controller.debug_pad_button_state.l.Assign(current_status.value); + break; + case Settings::NativeButton::R: + controller.npad_button_state.r.Assign(current_status.value); + controller.debug_pad_button_state.r.Assign(current_status.value); + break; + case Settings::NativeButton::ZL: + controller.npad_button_state.zl.Assign(current_status.value); + controller.debug_pad_button_state.zl.Assign(current_status.value); + break; + case Settings::NativeButton::ZR: + controller.npad_button_state.zr.Assign(current_status.value); + controller.debug_pad_button_state.zr.Assign(current_status.value); + break; + case Settings::NativeButton::Plus: + controller.npad_button_state.plus.Assign(current_status.value); + controller.debug_pad_button_state.plus.Assign(current_status.value); + break; + case Settings::NativeButton::Minus: + controller.npad_button_state.minus.Assign(current_status.value); + controller.debug_pad_button_state.minus.Assign(current_status.value); + break; + case Settings::NativeButton::DLeft: + controller.npad_button_state.left.Assign(current_status.value); + controller.debug_pad_button_state.d_left.Assign(current_status.value); + break; + case Settings::NativeButton::DUp: + controller.npad_button_state.up.Assign(current_status.value); + controller.debug_pad_button_state.d_up.Assign(current_status.value); + break; + case Settings::NativeButton::DRight: + controller.npad_button_state.right.Assign(current_status.value); + controller.debug_pad_button_state.d_right.Assign(current_status.value); + break; + case Settings::NativeButton::DDown: + controller.npad_button_state.down.Assign(current_status.value); + controller.debug_pad_button_state.d_down.Assign(current_status.value); + break; + case Settings::NativeButton::SL: + controller.npad_button_state.left_sl.Assign(current_status.value); + controller.npad_button_state.right_sl.Assign(current_status.value); + break; + case Settings::NativeButton::SR: + controller.npad_button_state.left_sr.Assign(current_status.value); + controller.npad_button_state.right_sr.Assign(current_status.value); + break; + case Settings::NativeButton::Home: + case Settings::NativeButton::Screenshot: + break; + } + } + if (!is_connected) { + if (npad_id_type == NpadIdType::Player1 && npad_type != NpadType::Handheld) { + Connect(); + } + if (npad_id_type == NpadIdType::Handheld && npad_type == NpadType::Handheld) { + Connect(); + } } - TriggerOnChange(ControllerTriggerType::Button); + TriggerOnChange(ControllerTriggerType::Button, true); } void EmulatedController::SetStick(Input::CallbackStatus callback, std::size_t index) { @@ -463,7 +472,7 @@ void EmulatedController::SetStick(Input::CallbackStatus callback, std::size_t in if (is_configuring) { controller.analog_stick_state.left = {}; controller.analog_stick_state.right = {}; - TriggerOnChange(ControllerTriggerType::Stick); + TriggerOnChange(ControllerTriggerType::Stick, false); return; } @@ -489,7 +498,7 @@ void EmulatedController::SetStick(Input::CallbackStatus callback, std::size_t in break; } - TriggerOnChange(ControllerTriggerType::Stick); + TriggerOnChange(ControllerTriggerType::Stick, true); } void EmulatedController::SetTrigger(Input::CallbackStatus callback, std::size_t index) { @@ -502,7 +511,7 @@ void EmulatedController::SetTrigger(Input::CallbackStatus callback, std::size_t if (is_configuring) { controller.gc_trigger_state.left = 0; controller.gc_trigger_state.right = 0; - TriggerOnChange(ControllerTriggerType::Trigger); + TriggerOnChange(ControllerTriggerType::Trigger, false); return; } @@ -520,7 +529,7 @@ void EmulatedController::SetTrigger(Input::CallbackStatus callback, std::size_t break; } - TriggerOnChange(ControllerTriggerType::Trigger); + TriggerOnChange(ControllerTriggerType::Trigger, true); } void EmulatedController::SetMotion(Input::CallbackStatus callback, std::size_t index) { @@ -546,7 +555,7 @@ void EmulatedController::SetMotion(Input::CallbackStatus callback, std::size_t i emulated.UpdateOrientation(raw_status.delta_timestamp); if (is_configuring) { - TriggerOnChange(ControllerTriggerType::Motion); + TriggerOnChange(ControllerTriggerType::Motion, false); return; } @@ -557,7 +566,7 @@ void EmulatedController::SetMotion(Input::CallbackStatus callback, std::size_t i motion.orientation = emulated.GetOrientation(); motion.is_at_rest = emulated.IsMoving(motion_sensitivity); - TriggerOnChange(ControllerTriggerType::Motion); + TriggerOnChange(ControllerTriggerType::Motion, true); } void EmulatedController::SetBattery(Input::CallbackStatus callback, std::size_t index) { @@ -568,7 +577,7 @@ void EmulatedController::SetBattery(Input::CallbackStatus callback, std::size_t controller.battery_values[index] = TransformToBattery(callback); if (is_configuring) { - TriggerOnChange(ControllerTriggerType::Battery); + TriggerOnChange(ControllerTriggerType::Battery, false); return; } @@ -593,6 +602,7 @@ void EmulatedController::SetBattery(Input::CallbackStatus callback, std::size_t case Input::BatteryLevel::Empty: battery_level = 0; break; + case Input::BatteryLevel::None: case Input::BatteryLevel::Full: default: is_powered = true; @@ -623,7 +633,7 @@ void EmulatedController::SetBattery(Input::CallbackStatus callback, std::size_t }; break; } - TriggerOnChange(ControllerTriggerType::Battery); + TriggerOnChange(ControllerTriggerType::Battery, true); } bool EmulatedController::SetVibration(std::size_t device_index, VibrationValue vibration) { @@ -677,7 +687,7 @@ void EmulatedController::Connect() { std::lock_guard lock{mutex}; if (is_configuring) { temporary_is_connected = true; - TriggerOnChange(ControllerTriggerType::Connected); + TriggerOnChange(ControllerTriggerType::Connected,false); return; } @@ -687,7 +697,7 @@ void EmulatedController::Connect() { is_connected = true; } LOG_ERROR(Service_HID, "Connected controller {}", NpadIdTypeToIndex(npad_id_type)); - TriggerOnChange(ControllerTriggerType::Connected); + TriggerOnChange(ControllerTriggerType::Connected,true); } void EmulatedController::Disconnect() { @@ -697,7 +707,7 @@ void EmulatedController::Disconnect() { temporary_is_connected = false; LOG_ERROR(Service_HID, "Disconnected temporal controller {}", NpadIdTypeToIndex(npad_id_type)); - TriggerOnChange(ControllerTriggerType::Disconnected); + TriggerOnChange(ControllerTriggerType::Disconnected,false); return; } @@ -707,7 +717,7 @@ void EmulatedController::Disconnect() { is_connected = false; } LOG_ERROR(Service_HID, "Disconnected controller {}", NpadIdTypeToIndex(npad_id_type)); - TriggerOnChange(ControllerTriggerType::Disconnected); + TriggerOnChange(ControllerTriggerType::Disconnected,true); } bool EmulatedController::IsConnected(bool temporary) const { @@ -741,7 +751,7 @@ void EmulatedController::SetNpadType(NpadType npad_type_) { return; } temporary_npad_type = npad_type_; - TriggerOnChange(ControllerTriggerType::Type); + TriggerOnChange(ControllerTriggerType::Type,false); return; } @@ -754,7 +764,7 @@ void EmulatedController::SetNpadType(NpadType npad_type_) { } npad_type = npad_type_; } - TriggerOnChange(ControllerTriggerType::Type); + TriggerOnChange(ControllerTriggerType::Type,true); } LedPattern EmulatedController::GetLedPattern() const { @@ -844,9 +854,12 @@ BatteryLevelState EmulatedController::GetBattery() const { return controller.battery_state; } -void EmulatedController::TriggerOnChange(ControllerTriggerType type) { +void EmulatedController::TriggerOnChange(ControllerTriggerType type, bool is_service_update) { for (const std::pair poller_pair : callback_list) { const ControllerUpdateCallback& poller = poller_pair.second; + if (!is_service_update && poller.is_service) { + continue; + } if (poller.on_change) { poller.on_change(type); } diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h index 6a6dc1892..3a0b20cf8 100644 --- a/src/core/hid/emulated_controller.h +++ b/src/core/hid/emulated_controller.h @@ -113,6 +113,7 @@ enum class ControllerTriggerType { struct ControllerUpdateCallback { std::function on_change; + bool is_service; }; class EmulatedController { @@ -325,9 +326,10 @@ private: /** * Triggers a callback that something has changed on the controller status - * @param Input type of the event to trigger + * @param type: Input type of the event to trigger + * @param is_service_update: indicates if this event should be sended to only services */ - void TriggerOnChange(ControllerTriggerType type); + void TriggerOnChange(ControllerTriggerType type, bool is_service_update); NpadIdType npad_id_type; NpadType npad_type{NpadType::None}; diff --git a/src/core/hid/input_converter.cpp b/src/core/hid/input_converter.cpp index 5834622e9..128a48ec9 100644 --- a/src/core/hid/input_converter.cpp +++ b/src/core/hid/input_converter.cpp @@ -10,7 +10,7 @@ namespace Core::HID { Input::BatteryStatus TransformToBattery(const Input::CallbackStatus& callback) { - Input::BatteryStatus battery{}; + Input::BatteryStatus battery{Input::BatteryStatus::None}; switch (callback.type) { case Input::InputType::Analog: case Input::InputType::Trigger: { diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index 144abab65..6b9d6d11c 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -104,7 +104,10 @@ Controller_NPad::Controller_NPad(Core::System& system_, controller.vibration[0].latest_vibration_value = DEFAULT_VIBRATION_VALUE; controller.vibration[1].latest_vibration_value = DEFAULT_VIBRATION_VALUE; Core::HID::ControllerUpdateCallback engine_callback{ - [this, i](Core::HID::ControllerTriggerType type) { ControllerUpdate(type, i); }}; + .on_change = [this, + i](Core::HID::ControllerTriggerType type) { ControllerUpdate(type, i); }, + .is_service = true, + }; controller.callback_key = controller.device->SetCallback(engine_callback); } } @@ -283,7 +286,6 @@ void Controller_NPad::OnInit() { // Prefill controller buffers for (auto& controller : controller_data) { - NPadGenericState dummy_pad_state{}; auto& npad = controller.shared_memory_entry; for (std::size_t i = 0; i < 19; ++i) { WriteEmptyEntry(npad); diff --git a/src/input_common/drivers/gc_adapter.cpp b/src/input_common/drivers/gc_adapter.cpp index 4a56abb99..4fb6ab5af 100644 --- a/src/input_common/drivers/gc_adapter.cpp +++ b/src/input_common/drivers/gc_adapter.cpp @@ -150,7 +150,10 @@ void GCAdapter::UpdatePadType(std::size_t port, ControllerTypes pad_type) { return; } // Device changed reset device and set new type - pads[port] = {}; + pads[port].axis_origin = {}; + pads[port].reset_origin_counter = {}; + pads[port].enable_vibration = {}; + pads[port].rumble_amplitude = {}; pads[port].type = pad_type; } @@ -396,12 +399,11 @@ std::vector GCAdapter::GetInputDevices() const { if (!DeviceConnected(port)) { continue; } - const std::string name = fmt::format("Gamecube Controller {}", port + 1); - devices.emplace_back(Common::ParamPackage{ - {"engine", "gcpad"}, - {"display", std::move(name)}, - {"port", std::to_string(port)}, - }); + Common::ParamPackage identifier{}; + identifier.Set("engine", GetEngineName()); + identifier.Set("display", fmt::format("Gamecube Controller {}", port + 1)); + identifier.Set("port", static_cast(port)); + devices.emplace_back(identifier); } return devices; } @@ -431,7 +433,8 @@ ButtonMapping GCAdapter::GetButtonMappingForDevice(const Common::ParamPackage& p ButtonMapping mapping{}; for (const auto& [switch_button, gcadapter_button] : switch_to_gcadapter_button) { - Common::ParamPackage button_params({{"engine", "gcpad"}}); + Common::ParamPackage button_params{}; + button_params.Set("engine", GetEngineName()); button_params.Set("port", params.Get("port", 0)); button_params.Set("button", static_cast(gcadapter_button)); mapping.insert_or_assign(switch_button, std::move(button_params)); @@ -444,7 +447,8 @@ ButtonMapping GCAdapter::GetButtonMappingForDevice(const Common::ParamPackage& p {Settings::NativeButton::ZR, PadButton::TriggerR, PadAxes::TriggerRight}, }; for (const auto& [switch_button, gcadapter_buton, gcadapter_axis] : switch_to_gcadapter_axis) { - Common::ParamPackage button_params({{"engine", "gcpad"}}); + Common::ParamPackage button_params{}; + button_params.Set("engine", GetEngineName()); button_params.Set("port", params.Get("port", 0)); button_params.Set("button", static_cast(gcadapter_buton)); button_params.Set("axis", static_cast(gcadapter_axis)); @@ -463,13 +467,13 @@ AnalogMapping GCAdapter::GetAnalogMappingForDevice(const Common::ParamPackage& p AnalogMapping mapping = {}; Common::ParamPackage left_analog_params; - left_analog_params.Set("engine", "gcpad"); + left_analog_params.Set("engine", GetEngineName()); left_analog_params.Set("port", params.Get("port", 0)); left_analog_params.Set("axis_x", static_cast(PadAxes::StickX)); left_analog_params.Set("axis_y", static_cast(PadAxes::StickY)); mapping.insert_or_assign(Settings::NativeAnalog::LStick, std::move(left_analog_params)); Common::ParamPackage right_analog_params; - right_analog_params.Set("engine", "gcpad"); + right_analog_params.Set("engine", GetEngineName()); right_analog_params.Set("port", params.Get("port", 0)); right_analog_params.Set("axis_x", static_cast(PadAxes::SubstickX)); right_analog_params.Set("axis_y", static_cast(PadAxes::SubstickY)); @@ -477,9 +481,56 @@ AnalogMapping GCAdapter::GetAnalogMappingForDevice(const Common::ParamPackage& p return mapping; } +std::string GCAdapter::GetUIButtonName(const Common::ParamPackage& params) const { + PadButton button = static_cast(params.Get("button", 0)); + switch (button) { + case PadButton::ButtonLeft: + return "left"; + break; + case PadButton::ButtonRight: + return "right"; + break; + case PadButton::ButtonDown: + return "down"; + break; + case PadButton::ButtonUp: + return "up"; + break; + case PadButton::TriggerZ: + return "Z"; + break; + case PadButton::TriggerR: + return "R"; + break; + case PadButton::TriggerL: + return "L"; + break; + case PadButton::ButtonA: + return "A"; + break; + case PadButton::ButtonB: + return "B"; + break; + case PadButton::ButtonX: + return "X"; + break; + case PadButton::ButtonY: + return "Y"; + break; + case PadButton::ButtonStart: + return "start"; + break; + default: + return "Unkown GC"; + } +} + std::string GCAdapter::GetUIName(const Common::ParamPackage& params) const { if (params.Has("button")) { - return fmt::format("Button {}", params.Get("button", 0)); + return fmt::format("Button {}", GetUIButtonName(params)); + } + if (params.Has("axis")) { + return fmt::format("Axis {}", params.Get("axis",0)); } return "Bad GC Adapter"; diff --git a/src/input_common/drivers/gc_adapter.h b/src/input_common/drivers/gc_adapter.h index dd0e4aa1d..b82e4803d 100644 --- a/src/input_common/drivers/gc_adapter.h +++ b/src/input_common/drivers/gc_adapter.h @@ -105,8 +105,12 @@ private: void Reset(); void UpdateVibrations(); - // Updates vibration state of all controllers + + /// Updates vibration state of all controllers void SendVibrations(); + + std::string GetUIButtonName(const Common::ParamPackage& params) const; + std::unique_ptr usb_adapter_handle; std::array pads; diff --git a/src/input_common/drivers/keyboard.cpp b/src/input_common/drivers/keyboard.cpp index b00a4b8d9..85a781a30 100644 --- a/src/input_common/drivers/keyboard.cpp +++ b/src/input_common/drivers/keyboard.cpp @@ -26,7 +26,7 @@ void Keyboard::ReleaseAllKeys() { std::vector Keyboard::GetInputDevices() const { std::vector devices; devices.emplace_back(Common::ParamPackage{ - {"engine", "keyboard"}, + {"engine", GetEngineName()}, {"display", "Keyboard Only"}, }); return devices; diff --git a/src/input_common/drivers/sdl_driver.cpp b/src/input_common/drivers/sdl_driver.cpp index f7f03c5f2..cee2d965f 100644 --- a/src/input_common/drivers/sdl_driver.cpp +++ b/src/input_common/drivers/sdl_driver.cpp @@ -305,6 +305,7 @@ void SDLDriver::InitJoystick(int joystick_index) { if (joystick_map.find(guid) == joystick_map.end()) { auto joystick = std::make_shared(guid, 0, sdl_joystick, sdl_gamecontroller); PreSetController(joystick->GetPadIdentifier()); + SetBattery(joystick->GetPadIdentifier(), joystick->GetBatteryLevel()); joystick_map[guid].emplace_back(std::move(joystick)); return; } @@ -322,6 +323,7 @@ void SDLDriver::InitJoystick(int joystick_index) { const int port = static_cast(joystick_guid_list.size()); auto joystick = std::make_shared(guid, port, sdl_joystick, sdl_gamecontroller); PreSetController(joystick->GetPadIdentifier()); + SetBattery(joystick->GetPadIdentifier(), joystick->GetBatteryLevel()); joystick_guid_list.emplace_back(std::move(joystick)); } @@ -472,7 +474,7 @@ std::vector SDLDriver::GetInputDevices() const { const std::string name = fmt::format("{} {}", joystick->GetControllerName(), joystick->GetPort()); devices.emplace_back(Common::ParamPackage{ - {"engine", "sdl"}, + {"engine", GetEngineName()}, {"display", std::move(name)}, {"guid", joystick->GetGUID()}, {"port", std::to_string(joystick->GetPort())}, @@ -495,7 +497,7 @@ std::vector SDLDriver::GetInputDevices() const { const std::string name = fmt::format("{} {}", "Nintendo Dual Joy-Con", joystick->GetPort()); devices.emplace_back(Common::ParamPackage{ - {"engine", "sdl"}, + {"engine", GetEngineName()}, {"display", std::move(name)}, {"guid", joystick->GetGUID()}, {"guid2", joystick2->GetGUID()}, @@ -527,7 +529,8 @@ Input::VibrationError SDLDriver::SetRumble(const PadIdentifier& identifier, } Common::ParamPackage SDLDriver::BuildAnalogParamPackageForButton(int port, std::string guid, s32 axis, float value) const { - Common::ParamPackage params({{"engine", "sdl"}}); + Common::ParamPackage params{}; + params.Set("engine", GetEngineName()); params.Set("port", port); params.Set("guid", std::move(guid)); params.Set("axis", axis); @@ -538,7 +541,8 @@ Common::ParamPackage SDLDriver::BuildAnalogParamPackageForButton(int port, std:: Common::ParamPackage SDLDriver::BuildButtonParamPackageForButton(int port, std::string guid, s32 button) const { - Common::ParamPackage params({{"engine", "sdl"}}); + Common::ParamPackage params{}; + params.Set("engine", GetEngineName()); params.Set("port", port); params.Set("guid", std::move(guid)); params.Set("button", button); @@ -547,8 +551,8 @@ Common::ParamPackage SDLDriver::BuildButtonParamPackageForButton(int port, std:: Common::ParamPackage SDLDriver::BuildHatParamPackageForButton(int port, std::string guid, s32 hat, u8 value) const { - Common::ParamPackage params({{"engine", "sdl"}}); - + Common::ParamPackage params{}; + params.Set("engine", GetEngineName()); params.Set("port", port); params.Set("guid", std::move(guid)); params.Set("hat", hat); @@ -557,7 +561,9 @@ Common::ParamPackage SDLDriver::BuildHatParamPackageForButton(int port, std::str } Common::ParamPackage SDLDriver::BuildMotionParam(int port, std::string guid) const { - Common::ParamPackage params({{"engine", "sdl"}, {"motion", "0"}}); + Common::ParamPackage params{}; + params.Set("engine", GetEngineName()); + params.Set("motion", 0); params.Set("port", port); params.Set("guid", std::move(guid)); return params; @@ -583,7 +589,7 @@ Common::ParamPackage SDLDriver::BuildParamPackageForAnalog(PadIdentifier identif int axis_y, float offset_x, float offset_y) const { Common::ParamPackage params; - params.Set("engine", "sdl"); + params.Set("engine", GetEngineName()); params.Set("port", static_cast(identifier.port)); params.Set("guid", identifier.guid.Format()); params.Set("axis_x", axis_x); diff --git a/src/input_common/drivers/tas_input.cpp b/src/input_common/drivers/tas_input.cpp index 5e2101b27..7e7a1d58f 100644 --- a/src/input_common/drivers/tas_input.cpp +++ b/src/input_common/drivers/tas_input.cpp @@ -127,7 +127,7 @@ void Tas::WriteTasFile(std::u8string file_name) { std::string output_text; for (size_t frame = 0; frame < record_commands.size(); frame++) { const TASCommand& line = record_commands[frame]; - output_text += fmt::format("{} {} {} {} {}\n", frame, WriteCommandButtons(line.buttons), + output_text += fmt::format("{} {} {} {}\n", frame, WriteCommandButtons(line.buttons), WriteCommandAxis(line.l_axis), WriteCommandAxis(line.r_axis)); } const auto bytes_written = Common::FS::WriteStringToFile( diff --git a/src/yuzu/configuration/configure_input_player_widget.cpp b/src/yuzu/configuration/configure_input_player_widget.cpp index 3b79b6076..93f7eddc9 100644 --- a/src/yuzu/configuration/configure_input_player_widget.cpp +++ b/src/yuzu/configuration/configure_input_player_widget.cpp @@ -27,7 +27,9 @@ void PlayerControlPreview::SetController(Core::HID::EmulatedController* controll is_controller_set = true; controller = controller_; Core::HID::ControllerUpdateCallback engine_callback{ - [this](Core::HID::ControllerTriggerType type) { ControllerUpdate(type); }}; + .on_change = [this](Core::HID::ControllerTriggerType type) { ControllerUpdate(type); }, + .is_service = false, + }; callback_key = controller->SetCallback(engine_callback); ControllerUpdate(Core::HID::ControllerTriggerType::All); } @@ -810,7 +812,7 @@ void PlayerControlPreview::DrawProController(QPainter& p, const QPointF center) DrawSymbol(p, center + QPoint(29, -56), Symbol::House, 3.9f); // Draw battery - DrawBattery(p, center + QPoint(-30, -165), battery_values[0]); + DrawBattery(p, center + QPoint(-30, -160), battery_values[0]); } void PlayerControlPreview::DrawGCController(QPainter& p, const QPointF center) { @@ -2655,6 +2657,9 @@ void PlayerControlPreview::DrawTriggerButton(QPainter& p, const QPointF center, } void PlayerControlPreview::DrawBattery(QPainter& p, QPointF center, Input::BatteryLevel battery) { + if (battery == Input::BatteryLevel::None) { + return; + } p.setPen(colors.outline); p.setBrush(colors.transparent); p.drawRect(center.x(), center.y(), 56, 20); @@ -2669,6 +2674,7 @@ void PlayerControlPreview::DrawBattery(QPainter& p, QPointF center, Input::Batte 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 Input::BatteryLevel::Medium: p.drawRect(center.x() + 28, center.y(), 14, 20); @@ -2685,6 +2691,8 @@ void PlayerControlPreview::DrawBattery(QPainter& p, QPointF center, Input::Batte case Input::BatteryLevel::Empty: p.drawRect(center.x(), center.y(), 5, 20); break; + default: + break; } } -- cgit v1.2.3 From c3ff0a8ac0d1c3f9c0791b5263dae53c06ad6048 Mon Sep 17 00:00:00 2001 From: german77 Date: Wed, 20 Oct 2021 14:41:56 -0500 Subject: core/hid: Fix rumble too strong at 1% --- src/common/input.h | 7 +++++++ src/core/hid/emulated_controller.cpp | 34 +++++++++++++++++++++------------ src/input_common/drivers/sdl_driver.cpp | 20 ++++++++++++++++++- 3 files changed, 48 insertions(+), 13 deletions(-) (limited to 'src/input_common/drivers') diff --git a/src/common/input.h b/src/common/input.h index 8871a9d07..cdacd4689 100644 --- a/src/common/input.h +++ b/src/common/input.h @@ -60,6 +60,12 @@ enum class PollingError { Unknown, }; +// Hint for amplification curve to be used +enum class VibrationAmplificationType { + Linear, + Exponential, +}; + struct AnalogProperties { float deadzone{}; float range{1.0f}; @@ -126,6 +132,7 @@ struct VibrationStatus { f32 low_frequency{}; f32 high_amplitude{}; f32 high_frequency{}; + VibrationAmplificationType type; }; struct LedStatus { diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index e102c9437..7b0c4a49b 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -54,7 +54,6 @@ Settings::ControllerType EmulatedController::MapNPadToSettingsType(NpadType type } void EmulatedController::ReloadFromSettings() { - //LOG_ERROR(Service_HID, "reload config from settings {}", NpadIdTypeToIndex(npad_id_type)); const auto player_index = NpadIdTypeToIndex(npad_id_type); const auto& player = Settings::values.players.GetValue()[player_index]; @@ -92,7 +91,7 @@ void EmulatedController::ReloadFromSettings() { } void EmulatedController::ReloadInput() { - //LOG_ERROR(Service_HID, "reload config {}", NpadIdTypeToIndex(npad_id_type)); + // LOG_ERROR(Service_HID, "reload config {}", NpadIdTypeToIndex(npad_id_type)); // If you load any device here add the equivalent to the UnloadInput() function const auto left_side = button_params[Settings::NativeButton::ZL]; const auto right_side = button_params[Settings::NativeButton::ZR]; @@ -640,12 +639,22 @@ bool EmulatedController::SetVibration(std::size_t device_index, VibrationValue v if (!output_devices[device_index]) { return false; } + const auto player_index = NpadIdTypeToIndex(npad_id_type); + const auto& player = Settings::values.players.GetValue()[player_index]; + const f32 strength = static_cast(player.vibration_strength) / 100.0f; + + // Exponential amplification is too strong at low amplitudes. Switch to a linear + // amplification if strength is set below 0.7f + const Input::VibrationAmplificationType type = + strength > 0.7f ? Input::VibrationAmplificationType::Exponential + : Input::VibrationAmplificationType::Linear; const Input::VibrationStatus status = { - .low_amplitude = vibration.high_amplitude, - .low_frequency = vibration.high_amplitude, - .high_amplitude = vibration.high_amplitude, - .high_frequency = vibration.high_amplitude, + .low_amplitude = std::min(vibration.low_amplitude * strength, 1.0f), + .low_frequency = vibration.low_frequency, + .high_amplitude = std::min(vibration.high_amplitude * strength, 1.0f), + .high_frequency = vibration.high_frequency, + .type = type, }; return output_devices[device_index]->SetVibration(status) == Input::VibrationError::None; } @@ -661,6 +670,7 @@ bool EmulatedController::TestVibration(std::size_t device_index) { .low_frequency = 160.0f, .high_amplitude = 0.001f, .high_frequency = 320.0f, + .type = Input::VibrationAmplificationType::Linear, }; return output_devices[device_index]->SetVibration(status) == Input::VibrationError::None; } @@ -687,7 +697,7 @@ void EmulatedController::Connect() { std::lock_guard lock{mutex}; if (is_configuring) { temporary_is_connected = true; - TriggerOnChange(ControllerTriggerType::Connected,false); + TriggerOnChange(ControllerTriggerType::Connected, false); return; } @@ -697,7 +707,7 @@ void EmulatedController::Connect() { is_connected = true; } LOG_ERROR(Service_HID, "Connected controller {}", NpadIdTypeToIndex(npad_id_type)); - TriggerOnChange(ControllerTriggerType::Connected,true); + TriggerOnChange(ControllerTriggerType::Connected, true); } void EmulatedController::Disconnect() { @@ -707,7 +717,7 @@ void EmulatedController::Disconnect() { temporary_is_connected = false; LOG_ERROR(Service_HID, "Disconnected temporal controller {}", NpadIdTypeToIndex(npad_id_type)); - TriggerOnChange(ControllerTriggerType::Disconnected,false); + TriggerOnChange(ControllerTriggerType::Disconnected, false); return; } @@ -717,7 +727,7 @@ void EmulatedController::Disconnect() { is_connected = false; } LOG_ERROR(Service_HID, "Disconnected controller {}", NpadIdTypeToIndex(npad_id_type)); - TriggerOnChange(ControllerTriggerType::Disconnected,true); + TriggerOnChange(ControllerTriggerType::Disconnected, true); } bool EmulatedController::IsConnected(bool temporary) const { @@ -751,7 +761,7 @@ void EmulatedController::SetNpadType(NpadType npad_type_) { return; } temporary_npad_type = npad_type_; - TriggerOnChange(ControllerTriggerType::Type,false); + TriggerOnChange(ControllerTriggerType::Type, false); return; } @@ -764,7 +774,7 @@ void EmulatedController::SetNpadType(NpadType npad_type_) { } npad_type = npad_type_; } - TriggerOnChange(ControllerTriggerType::Type,true); + TriggerOnChange(ControllerTriggerType::Type, true); } LedPattern EmulatedController::GetLedPattern() const { diff --git a/src/input_common/drivers/sdl_driver.cpp b/src/input_common/drivers/sdl_driver.cpp index cee2d965f..d56351815 100644 --- a/src/input_common/drivers/sdl_driver.cpp +++ b/src/input_common/drivers/sdl_driver.cpp @@ -107,6 +107,14 @@ public: return false; } + + bool HasHDRumble() const { + if (sdl_controller) { + return (SDL_GameControllerGetType(sdl_controller.get()) == + SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO); + } + return false; + } /** * The Pad identifier of the joystick */ @@ -515,16 +523,26 @@ Input::VibrationError SDLDriver::SetRumble(const PadIdentifier& identifier, const auto process_amplitude = [](f32 amplitude) { return (amplitude + std::pow(amplitude, 0.3f)) * 0.5f * 0xFFFF; }; - const Input::VibrationStatus new_vibration{ + const Input::VibrationStatus exponential_vibration{ .low_amplitude = process_amplitude(vibration.low_amplitude), .low_frequency = vibration.low_frequency, .high_amplitude = process_amplitude(vibration.high_amplitude), .high_frequency = vibration.high_frequency, + .type = Input::VibrationAmplificationType::Exponential, }; + Input::VibrationStatus new_vibration{}; + + if (vibration.type == Input::VibrationAmplificationType::Linear || joystick->HasHDRumble()) { + new_vibration = vibration; + } else { + new_vibration = exponential_vibration; + } + if (!joystick->RumblePlay(new_vibration)) { return Input::VibrationError::Unknown; } + return Input::VibrationError::None; } Common::ParamPackage SDLDriver::BuildAnalogParamPackageForButton(int port, std::string guid, -- cgit v1.2.3 From 85052b8662d9512077780f717fb2e168390ed705 Mon Sep 17 00:00:00 2001 From: german77 Date: Wed, 20 Oct 2021 23:18:04 -0500 Subject: service/hid: Fix gesture input --- src/core/hid/emulated_console.cpp | 57 ++++++----- src/core/hid/emulated_console.h | 3 + src/core/hid/emulated_controller.cpp | 4 - src/core/hle/service/hid/controllers/gesture.cpp | 124 +++++++++++++---------- src/core/hle/service/hid/controllers/gesture.h | 29 ++++-- src/input_common/drivers/gc_adapter.cpp | 4 +- src/input_common/drivers/udp_client.cpp | 27 +++++ src/yuzu/main.cpp | 2 +- 8 files changed, 159 insertions(+), 91 deletions(-) (limited to 'src/input_common/drivers') diff --git a/src/core/hid/emulated_console.cpp b/src/core/hid/emulated_console.cpp index 7f7c8fd59..e82cf5990 100644 --- a/src/core/hid/emulated_console.cpp +++ b/src/core/hid/emulated_console.cpp @@ -20,27 +20,21 @@ void EmulatedConsole::ReloadFromSettings() { ReloadInput(); } -void EmulatedConsole::ReloadInput() { - motion_devices = Input::CreateDevice(motion_params); - if (motion_devices) { - Input::InputCallback motion_callback{ - [this](Input::CallbackStatus callback) { SetMotion(callback); }}; - motion_devices->SetCallback(motion_callback); - } - - // TODO: Fix this mess +void EmulatedConsole::SetTouchParams() { + // TODO(german77): Support any number of fingers std::size_t index = 0; - const std::string mouse_device_string = - fmt::format("engine:mouse,axis_x:10,axis_y:11,button:{}", index); - touch_devices[index] = Input::CreateDeviceFromString(mouse_device_string); - Input::InputCallback trigger_callbackk{ - [this, index](Input::CallbackStatus callback) { SetTouch(callback, index); }}; - touch_devices[index]->SetCallback(trigger_callbackk); - - index++; + + // Hardcode mouse, touchscreen and cemuhook parameters + touch_params[index++] = Common::ParamPackage{"engine:mouse,axis_x:10,axis_y:11,button:0"}; + touch_params[index++] = Common::ParamPackage{"engine:touch,axis_x:0,axis_y:1,button:0"}; + touch_params[index++] = Common::ParamPackage{"engine:touch,axis_x:2,axis_y:3,button:1"}; + touch_params[index++] = Common::ParamPackage{"engine:cemuhookudp,axis_x:0,axis_y:1,button:0"}; + touch_params[index++] = Common::ParamPackage{"engine:cemuhookudp,axis_x:2,axis_y:3,button:1"}; + const auto button_index = static_cast(Settings::values.touch_from_button_map_index.GetValue()); const auto& touch_buttons = Settings::values.touch_from_button_maps[button_index].buttons; + for (const auto& config_entry : touch_buttons) { Common::ParamPackage params{config_entry}; Common::ParamPackage touch_button_params; @@ -53,15 +47,32 @@ void EmulatedConsole::ReloadInput() { touch_button_params.Set("x", x); touch_button_params.Set("y", y); touch_button_params.Set("touch_id", static_cast(index)); - touch_devices[index] = - Input::CreateDeviceFromString(touch_button_params.Serialize()); - if (!touch_devices[index]) { - continue; + touch_params[index] = touch_button_params; + index++; + if (index >= touch_params.size()) { + return; } + } +} - Input::InputCallback trigger_callback{ +void EmulatedConsole::ReloadInput() { + SetTouchParams(); + motion_devices = Input::CreateDevice(motion_params); + if (motion_devices) { + Input::InputCallback motion_callback{ + [this](Input::CallbackStatus callback) { SetMotion(callback); }}; + motion_devices->SetCallback(motion_callback); + } + + std::size_t index = 0; + for (auto& touch_device : touch_devices) { + touch_device = Input::CreateDevice(touch_params[index]); + if (!touch_device) { + continue; + } + Input::InputCallback touch_callback{ [this, index](Input::CallbackStatus callback) { SetTouch(callback, index); }}; - touch_devices[index]->SetCallback(trigger_callback); + touch_device->SetCallback(touch_callback); index++; } } diff --git a/src/core/hid/emulated_console.h b/src/core/hid/emulated_console.h index 7d6cf9506..c48d25794 100644 --- a/src/core/hid/emulated_console.h +++ b/src/core/hid/emulated_console.h @@ -144,6 +144,9 @@ public: void DeleteCallback(int key); private: + /// Creates and stores the touch params + void SetTouchParams(); + /** * Updates the motion status of the console * @param A CallbackStatus containing gyro and accelerometer data diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index 662260327..1ff3022c5 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -705,7 +705,6 @@ void EmulatedController::Connect() { } is_connected = true; } - LOG_ERROR(Service_HID, "Connected controller {}", NpadIdTypeToIndex(npad_id_type)); TriggerOnChange(ControllerTriggerType::Connected, true); } @@ -714,8 +713,6 @@ void EmulatedController::Disconnect() { std::lock_guard lock{mutex}; if (is_configuring) { temporary_is_connected = false; - LOG_ERROR(Service_HID, "Disconnected temporal controller {}", - NpadIdTypeToIndex(npad_id_type)); TriggerOnChange(ControllerTriggerType::Disconnected, false); return; } @@ -725,7 +722,6 @@ void EmulatedController::Disconnect() { } is_connected = false; } - LOG_ERROR(Service_HID, "Disconnected controller {}", NpadIdTypeToIndex(npad_id_type)); TriggerOnChange(ControllerTriggerType::Disconnected, true); } diff --git a/src/core/hle/service/hid/controllers/gesture.cpp b/src/core/hle/service/hid/controllers/gesture.cpp index 2f98cc54b..a26ce5383 100644 --- a/src/core/hle/service/hid/controllers/gesture.cpp +++ b/src/core/hle/service/hid/controllers/gesture.cpp @@ -28,12 +28,10 @@ constexpr f32 Square(s32 num) { Controller_Gesture::Controller_Gesture(Core::System& system_) : ControllerBase(system_) { console = system.HIDCore().GetEmulatedConsole(); } - Controller_Gesture::~Controller_Gesture() = default; void Controller_Gesture::OnInit() { - gesture_lifo.entry_count = 0; - gesture_lifo.last_entry_index = 0; + shared_memory.header.entry_count = 0; force_update = true; } @@ -41,27 +39,27 @@ void Controller_Gesture::OnRelease() {} void Controller_Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) { - // TODO FIND WTF IS WRONG HERE!!!!!!!! - return; + shared_memory.header.timestamp = core_timing.GetCPUTicks(); + shared_memory.header.total_entry_count = 17; + if (!IsControllerActivated()) { - gesture_lifo.entry_count = 0; - gesture_lifo.last_entry_index = 0; - std::memcpy(data, &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); } @@ -77,7 +75,7 @@ void Controller_Gesture::ReadTouchInput() { bool Controller_Gesture::ShouldUpdateGesture(const GestureProperties& gesture, f32 time_difference) { - const auto& last_entry = gesture_lifo.ReadCurrentEntry().state; + const auto& last_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; if (force_update) { force_update = false; return true; @@ -105,16 +103,24 @@ void Controller_Gesture::UpdateGestureSharedMemory(u8* data, std::size_t size, GestureType type = GestureType::Idle; GestureAttribute 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]; + + 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 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; + // Reset values to default + cur_entry.delta = {}; + cur_entry.vel_x = 0; + cur_entry.vel_y = 0; + cur_entry.direction = GestureDirection::None; + cur_entry.rotation_angle = 0; + cur_entry.scale = 0; if (gesture.active_points > 0) { if (last_gesture.active_points == 0) { @@ -127,21 +133,20 @@ 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) { - const auto& last_entry = gesture_lifo.ReadCurrentEntry().state; + const auto& last_entry = GetLastGestureEntry(); gesture.detection_count++; type = GestureType::Touch; @@ -155,7 +160,7 @@ void Controller_Gesture::NewGesture(GestureProperties& gesture, GestureType& typ void Controller_Gesture::UpdateExistingGesture(GestureProperties& gesture, GestureType& type, f32 time_difference) { - const auto& last_entry = gesture_lifo.ReadCurrentEntry().state; + const auto& last_entry = GetLastGestureEntry(); // Promote to pan type if touch moved for (size_t id = 0; id < MAX_POINTS; id++) { @@ -190,7 +195,7 @@ void Controller_Gesture::UpdateExistingGesture(GestureProperties& gesture, Gestu void Controller_Gesture::EndGesture(GestureProperties& gesture, GestureProperties& last_gesture_props, GestureType& type, GestureAttribute& attributes, f32 time_difference) { - const auto& last_entry = gesture_lifo.ReadCurrentEntry().state; + const auto& last_entry = GetLastGestureEntry(); if (last_gesture_props.active_points != 0) { switch (last_entry.type) { @@ -240,18 +245,19 @@ void Controller_Gesture::SetTapEvent(GestureProperties& gesture, void Controller_Gesture::UpdatePanEvent(GestureProperties& gesture, GestureProperties& last_gesture_props, GestureType& type, f32 time_difference) { - const auto& last_entry = gesture_lifo.ReadCurrentEntry().state; + 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; + 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) / @@ -259,21 +265,22 @@ void Controller_Gesture::UpdatePanEvent(GestureProperties& gesture, // 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; + 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, f32 time_difference) { - const auto& last_entry = gesture_lifo.ReadCurrentEntry().state; - next_state.vel_x = + auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; + const auto& last_entry = GetLastGestureEntry(); + 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) { @@ -283,33 +290,42 @@ void Controller_Gesture::EndPanEvent(GestureProperties& gesture, // End panning without swipe type = GestureType::Complete; - next_state.vel_x = 0; - next_state.vel_y = 0; + 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) { - const auto& last_entry = gesture_lifo.ReadCurrentEntry().state; + auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; + const auto& last_entry = GetLastGestureEntry(); type = GestureType::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 = GestureDirection::Right; return; } - next_state.direction = GestureDirection::Left; + cur_entry.direction = GestureDirection::Left; return; } - if (next_state.delta.y > 0) { - next_state.direction = GestureDirection::Down; + if (cur_entry.delta.y > 0) { + cur_entry.direction = GestureDirection::Down; return; } - next_state.direction = GestureDirection::Up; + cur_entry.direction = GestureDirection::Up; +} + +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 shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17]; } Controller_Gesture::GestureProperties Controller_Gesture::GetGestureProperties() { diff --git a/src/core/hle/service/hid/controllers/gesture.h b/src/core/hle/service/hid/controllers/gesture.h index 8e6f315a4..6128fb0ad 100644 --- a/src/core/hle/service/hid/controllers/gesture.h +++ b/src/core/hle/service/hid/controllers/gesture.h @@ -71,6 +71,7 @@ private: // This is nn::hid::GestureState struct GestureState { s64_le sampling_number; + s64_le sampling_number2; s64_le detection_count; GestureType type; GestureDirection direction; @@ -84,7 +85,21 @@ private: s32_le point_count; std::array, 4> points; }; - static_assert(sizeof(GestureState) == 0x60, "GestureState is an invalid size"); + static_assert(sizeof(GestureState) == 0x68, "GestureState is an invalid size"); + + 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"); + + struct SharedMemory { + CommonHeader header; + std::array gesture_states; + }; + static_assert(sizeof(SharedMemory) == 0x708, "SharedMemory is an invalid size"); struct Finger { Common::Point pos{}; @@ -137,17 +152,17 @@ private: void SetSwipeEvent(GestureProperties& gesture, GestureProperties& last_gesture_props, GestureType& type); + // Retrieves the last gesture entry, as indicated by shared memory indices. + [[nodiscard]] GestureState& GetLastGestureEntry(); + [[nodiscard]] const GestureState& GetLastGestureEntry() const; + // 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{}; - - std::array fingers{}; + SharedMemory shared_memory{}; Core::HID::EmulatedConsole* console; + std::array fingers{}; GestureProperties last_gesture{}; s64_le last_update_timestamp{}; s64_le last_tap_timestamp{}; diff --git a/src/input_common/drivers/gc_adapter.cpp b/src/input_common/drivers/gc_adapter.cpp index 4fb6ab5af..25b66f528 100644 --- a/src/input_common/drivers/gc_adapter.cpp +++ b/src/input_common/drivers/gc_adapter.cpp @@ -209,7 +209,7 @@ void GCAdapter::UpdateStateAxes(std::size_t port, const AdapterPayload& adapter_ pads[port].axis_origin[index] = axis_value; pads[port].reset_origin_counter++; } - const f32 axis_status = (axis_value - pads[port].axis_origin[index]) / 110.0f; + const f32 axis_status = (axis_value - pads[port].axis_origin[index]) / 100.0f; SetAxis(pads[port].identifier, static_cast(index), axis_status); } } @@ -530,7 +530,7 @@ std::string GCAdapter::GetUIName(const Common::ParamPackage& params) const { return fmt::format("Button {}", GetUIButtonName(params)); } if (params.Has("axis")) { - return fmt::format("Axis {}", params.Get("axis",0)); + return fmt::format("Axis {}", params.Get("axis", 0)); } return "Bad GC Adapter"; diff --git a/src/input_common/drivers/udp_client.cpp b/src/input_common/drivers/udp_client.cpp index 6fcc3a01b..f0c0a6b8b 100644 --- a/src/input_common/drivers/udp_client.cpp +++ b/src/input_common/drivers/udp_client.cpp @@ -243,6 +243,33 @@ void UDPClient::OnPadData(Response::PadData data, std::size_t client) { }; const PadIdentifier identifier = GetPadIdentifier(pad_index); SetMotion(identifier, 0, motion); + + for (std::size_t id = 0; id < data.touch.size(); ++id) { + const auto touch_pad = data.touch[id]; + const int touch_id = static_cast(client * 2 + id); + + // TODO: Use custom calibration per device + const Common::ParamPackage touch_param(Settings::values.touch_device.GetValue()); + const u16 min_x = static_cast(touch_param.Get("min_x", 100)); + const u16 min_y = static_cast(touch_param.Get("min_y", 50)); + const u16 max_x = static_cast(touch_param.Get("max_x", 1800)); + const u16 max_y = static_cast(touch_param.Get("max_y", 850)); + + const f32 x = + static_cast(std::clamp(static_cast(touch_pad.x), min_x, max_x) - min_x) / + static_cast(max_x - min_x); + const f32 y = + static_cast(std::clamp(static_cast(touch_pad.y), min_y, max_y) - min_y) / + static_cast(max_y - min_y); + + if (touch_pad.is_active) { + SetAxis(identifier, touch_id * 2, x); + SetAxis(identifier, touch_id * 2 + 1, y); + SetButton(identifier, touch_id, true); + continue; + } + SetButton(identifier, touch_id, false); + } } void UDPClient::StartCommunication(std::size_t client, const std::string& host, u16 port) { diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 46a5f62ad..022d11cc4 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -2973,7 +2973,7 @@ 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 InputCommon::TasInput::TasState::Running: return tr("TAS state: Running %1/%2").arg(current_tas_frame).arg(total_tas_frames); case InputCommon::TasInput::TasState::Recording: return tr("TAS state: Recording %1").arg(total_tas_frames); -- cgit v1.2.3 From b5e72de753ae4de5c5fae7087abb00dc4242451d Mon Sep 17 00:00:00 2001 From: german77 Date: Thu, 21 Oct 2021 13:56:52 -0500 Subject: kraken: Address comments from review review fixes --- src/core/frontend/applets/controller.cpp | 51 +++++++++++---------------- src/core/frontend/applets/controller.h | 8 ++--- src/core/hid/emulated_console.cpp | 2 -- src/core/hid/emulated_controller.cpp | 12 +++++-- src/core/hid/emulated_controller.h | 1 - src/core/hid/hid_core.cpp | 4 +-- src/core/hid/hid_core.h | 3 ++ src/core/hle/service/am/applets/applets.cpp | 2 +- src/core/hle/service/hid/controllers/npad.cpp | 10 +++--- src/core/hle/service/hid/controllers/npad.h | 2 +- src/core/hle/service/hid/hid.cpp | 3 +- src/input_common/drivers/udp_client.cpp | 2 ++ src/input_common/drivers/udp_client.h | 4 +-- src/input_common/helpers/stick_from_buttons.h | 1 - src/input_common/main.cpp | 7 ++-- 15 files changed, 56 insertions(+), 56 deletions(-) (limited to 'src/input_common/drivers') diff --git a/src/core/frontend/applets/controller.cpp b/src/core/frontend/applets/controller.cpp index ca1edce15..30500ef1e 100644 --- a/src/core/frontend/applets/controller.cpp +++ b/src/core/frontend/applets/controller.cpp @@ -5,16 +5,16 @@ #include "common/assert.h" #include "common/logging/log.h" #include "core/frontend/applets/controller.h" -#include "core/hle/service/hid/controllers/npad.h" -#include "core/hle/service/hid/hid.h" -#include "core/hle/service/sm/sm.h" +#include "core/hid/emulated_controller.h" +#include "core/hid/hid_core.h" +#include "core/hid/hid_types.h" namespace Core::Frontend { ControllerApplet::~ControllerApplet() = default; -DefaultControllerApplet::DefaultControllerApplet(Service::SM::ServiceManager& service_manager_) - : service_manager{service_manager_} {} +DefaultControllerApplet::DefaultControllerApplet(HID::HIDCore& hid_core_) + : hid_core{hid_core_} {} DefaultControllerApplet::~DefaultControllerApplet() = default; @@ -22,24 +22,20 @@ 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. - npad.DisconnectNpadAtIndex(8); + auto* handheld =hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld); + handheld->Disconnect(); // Deduce the best configuration based on the input parameters. - for (std::size_t index = 0; index < players.size() - 2; ++index) { + for (std::size_t index = 0; index < hid_core.available_controllers - 2; ++index) { + auto* controller = hid_core.GetEmulatedControllerByIndex(index); + // First, disconnect all controllers regardless of the value of keep_controllers_connected. // This makes it easy to connect the desired controllers. - npad.DisconnectNpadAtIndex(index); + controller->Disconnect(); // Only connect the minimum number of required players. if (index >= min_supported_players) { @@ -49,32 +45,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) { - npad.AddNewControllerAt(Core::HID::EmulatedController::MapSettingsTypeToNPad( - Settings::ControllerType::ProController), - index); + controller->SetNpadType(Core::HID::NpadType::ProController); + controller->Connect(); } else if (parameters.allow_dual_joycons) { - npad.AddNewControllerAt(Core::HID::EmulatedController::MapSettingsTypeToNPad( - Settings::ControllerType::DualJoyconDetached), - index); + controller->SetNpadType(Core::HID::NpadType::JoyconDual); + controller->Connect(); } 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) { - npad.AddNewControllerAt(Core::HID::EmulatedController::MapSettingsTypeToNPad( - Settings::ControllerType::LeftJoycon), - index); + controller->SetNpadType(Core::HID::NpadType::JoyconLeft); + controller->Connect(); } else { - npad.AddNewControllerAt(Core::HID::EmulatedController::MapSettingsTypeToNPad( - Settings::ControllerType::RightJoycon), - index); + controller->SetNpadType(Core::HID::NpadType::JoyconRight); + controller->Connect(); } } 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. - npad.AddNewControllerAt(Core::HID::EmulatedController::MapSettingsTypeToNPad( - Settings::ControllerType::Handheld), - index); + controller->SetNpadType(Core::HID::NpadType::Handheld); + controller->Connect(); } 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 b0626a0f9..014bc8901 100644 --- a/src/core/frontend/applets/controller.h +++ b/src/core/frontend/applets/controller.h @@ -8,8 +8,8 @@ #include "common/common_types.h" -namespace Service::SM { -class ServiceManager; +namespace Core::HID { +class HIDCore; } namespace Core::Frontend { @@ -44,14 +44,14 @@ public: class DefaultControllerApplet final : public ControllerApplet { public: - explicit DefaultControllerApplet(Service::SM::ServiceManager& service_manager_); + explicit DefaultControllerApplet(HID::HIDCore& hid_core_); ~DefaultControllerApplet() override; void ReconfigureControllers(std::function callback, const ControllerParameters& parameters) const override; private: - Service::SM::ServiceManager& service_manager; + HID::HIDCore& hid_core; }; } // namespace Core::Frontend diff --git a/src/core/hid/emulated_console.cpp b/src/core/hid/emulated_console.cpp index e82cf5990..540fd107b 100644 --- a/src/core/hid/emulated_console.cpp +++ b/src/core/hid/emulated_console.cpp @@ -2,8 +2,6 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included -#include - #include "core/hid/emulated_console.h" #include "core/hid/input_converter.h" diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index 1ff3022c5..d59758e99 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -2,8 +2,6 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included -#include - #include "core/hid/emulated_controller.h" #include "core/hid/input_converter.h" @@ -635,6 +633,9 @@ void EmulatedController::SetBattery(Input::CallbackStatus callback, std::size_t } bool EmulatedController::SetVibration(std::size_t device_index, VibrationValue vibration) { + if (device_index >= output_devices.size()) { + return false; + } if (!output_devices[device_index]) { return false; } @@ -659,6 +660,9 @@ bool EmulatedController::SetVibration(std::size_t device_index, VibrationValue v } bool EmulatedController::TestVibration(std::size_t device_index) { + if (device_index >= output_devices.size()) { + return false; + } if (!output_devices[device_index]) { return false; } @@ -733,7 +737,9 @@ bool EmulatedController::IsConnected(bool temporary) const { } bool EmulatedController::IsVibrationEnabled() const { - return is_vibration_enabled; + const auto player_index = NpadIdTypeToIndex(npad_id_type); + const auto& player = Settings::values.players.GetValue()[player_index]; + return player.vibration_enabled; } NpadIdType EmulatedController::GetNpadIdType() const { diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h index f3ee70726..50f21ccd9 100644 --- a/src/core/hid/emulated_controller.h +++ b/src/core/hid/emulated_controller.h @@ -337,7 +337,6 @@ private: bool is_connected{false}; bool temporary_is_connected{false}; bool is_configuring{false}; - bool is_vibration_enabled{true}; f32 motion_sensitivity{0.01f}; ButtonParams button_params; diff --git a/src/core/hid/hid_core.cpp b/src/core/hid/hid_core.cpp index bd17081bd..cc1b3c295 100644 --- a/src/core/hid/hid_core.cpp +++ b/src/core/hid/hid_core.cpp @@ -113,7 +113,7 @@ NpadStyleTag HIDCore::GetSupportedStyleTag() const { s8 HIDCore::GetPlayerCount() const { s8 active_players = 0; - for (std::size_t player_index = 0; player_index < 8; player_index++) { + for (std::size_t player_index = 0; player_index < available_controllers -2; player_index++) { const auto* controller = GetEmulatedControllerByIndex(player_index); if (controller->IsConnected()) { active_players++; @@ -123,7 +123,7 @@ s8 HIDCore::GetPlayerCount() const { } NpadIdType HIDCore::GetFirstNpadId() const { - for (std::size_t player_index = 0; player_index < 10; player_index++) { + for (std::size_t player_index = 0; player_index < available_controllers; player_index++) { const auto* controller = GetEmulatedControllerByIndex(player_index); if (controller->IsConnected()) { return controller->GetNpadIdType(); diff --git a/src/core/hid/hid_core.h b/src/core/hid/hid_core.h index 196466a72..a4a66a3a4 100644 --- a/src/core/hid/hid_core.h +++ b/src/core/hid/hid_core.h @@ -47,6 +47,9 @@ public: /// Removes all callbacks from input common void UnloadInputDevices(); + /// Number of emulated controllers + const std::size_t available_controllers{10}; + private: std::unique_ptr player_1; std::unique_ptr player_2; diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp index 7320b1c0f..134ac1ee2 100644 --- 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.ServiceManager()); + std::make_unique(system.HIDCore()); } if (frontend.error == nullptr) { diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index 6b9d6d11c..62b324080 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -608,15 +608,15 @@ void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing sixaxis_fullkey_state.sampling_number = npad.sixaxis_fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1; sixaxis_handheld_state.sampling_number = - npad.sixaxis_fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1; + npad.sixaxis_handheld_lifo.ReadCurrentEntry().state.sampling_number + 1; sixaxis_dual_left_state.sampling_number = - npad.sixaxis_fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1; + npad.sixaxis_dual_left_lifo.ReadCurrentEntry().state.sampling_number + 1; sixaxis_dual_right_state.sampling_number = - npad.sixaxis_fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1; + npad.sixaxis_dual_right_lifo.ReadCurrentEntry().state.sampling_number + 1; sixaxis_left_lifo_state.sampling_number = - npad.sixaxis_fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1; + npad.sixaxis_left_lifo.ReadCurrentEntry().state.sampling_number + 1; sixaxis_right_lifo_state.sampling_number = - npad.sixaxis_fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1; + npad.sixaxis_right_lifo.ReadCurrentEntry().state.sampling_number + 1; npad.sixaxis_fullkey_lifo.WriteNextEntry(sixaxis_fullkey_state); npad.sixaxis_handheld_lifo.WriteNextEntry(sixaxis_handheld_state); diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h index d805ccb97..1c6ea6f88 100644 --- a/src/core/hle/service/hid/controllers/npad.h +++ b/src/core/hle/service/hid/controllers/npad.h @@ -342,7 +342,7 @@ private: INSERT_PADDING_BYTES(0x4); }; - // This is nn::hid::server::NpadGcTriggerState + // This is nn::hid::system::AppletFooterUiType enum class AppletFooterUiType : u8 { None = 0, HandheldNone = 1, diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 5391334f4..ac48f96d3 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -8,7 +8,6 @@ #include "common/settings.h" #include "core/core.h" #include "core/core_timing.h" -#include "core/hardware_properties.h" #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/k_readable_event.h" #include "core/hle/kernel/k_shared_memory.h" @@ -34,7 +33,7 @@ namespace Service::HID { // Updating period for each HID device. -// Period time is obtained by measuring the number of samples in a second +// 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 motion_update_ns = std::chrono::nanoseconds{5 * 1000 * 1000}; // (5ms, 200Hz) constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000; diff --git a/src/input_common/drivers/udp_client.cpp b/src/input_common/drivers/udp_client.cpp index f0c0a6b8b..192ab336b 100644 --- a/src/input_common/drivers/udp_client.cpp +++ b/src/input_common/drivers/udp_client.cpp @@ -268,6 +268,8 @@ void UDPClient::OnPadData(Response::PadData data, std::size_t client) { SetButton(identifier, touch_id, true); continue; } + SetAxis(identifier, touch_id * 2, 0); + SetAxis(identifier, touch_id * 2 + 1, 0); SetButton(identifier, touch_id, false); } } diff --git a/src/input_common/drivers/udp_client.h b/src/input_common/drivers/udp_client.h index 58b2e921d..639325b17 100644 --- a/src/input_common/drivers/udp_client.h +++ b/src/input_common/drivers/udp_client.h @@ -1,6 +1,6 @@ -// Copyright 2021 yuzu Emulator Project +// Copyright 2018 Citra Emulator Project // Licensed under GPLv2 or any later version -// Refer to the license.txt file included +// Refer to the license.txt file included. #pragma once diff --git a/src/input_common/helpers/stick_from_buttons.h b/src/input_common/helpers/stick_from_buttons.h index 1d6e24c98..82dff5ca8 100644 --- a/src/input_common/helpers/stick_from_buttons.h +++ b/src/input_common/helpers/stick_from_buttons.h @@ -1,4 +1,3 @@ - // Copyright 2017 Citra Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp index b048783c9..8f7ce59b7 100644 --- a/src/input_common/main.cpp +++ b/src/input_common/main.cpp @@ -87,25 +87,30 @@ struct InputSubsystem::Impl { void Shutdown() { Input::UnregisterFactory(keyboard->GetEngineName()); + Input::UnregisterFactory(keyboard->GetEngineName()); keyboard.reset(); Input::UnregisterFactory(mouse->GetEngineName()); + Input::UnregisterFactory(mouse->GetEngineName()); mouse.reset(); Input::UnregisterFactory(touch_screen->GetEngineName()); touch_screen.reset(); Input::UnregisterFactory(gcadapter->GetEngineName()); + Input::UnregisterFactory(gcadapter->GetEngineName()); gcadapter.reset(); Input::UnregisterFactory(udp_client->GetEngineName()); udp_client.reset(); Input::UnregisterFactory(tas_input->GetEngineName()); + Input::UnregisterFactory(tas_input->GetEngineName()); tas_input.reset(); #ifdef HAVE_SDL2 Input::UnregisterFactory(sdl->GetEngineName()); + Input::UnregisterFactory(sdl->GetEngineName()); sdl.reset(); #endif @@ -124,8 +129,6 @@ struct InputSubsystem::Impl { devices.insert(devices.end(), mouse_devices.begin(), mouse_devices.end()); auto gcadapter_devices = gcadapter->GetInputDevices(); devices.insert(devices.end(), gcadapter_devices.begin(), gcadapter_devices.end()); - auto tas_input_devices = tas_input->GetInputDevices(); - devices.insert(devices.end(), tas_input_devices.begin(), tas_input_devices.end()); #ifdef HAVE_SDL2 auto sdl_devices = sdl->GetInputDevices(); devices.insert(devices.end(), sdl_devices.begin(), sdl_devices.end()); -- cgit v1.2.3 From 464c4d26ac8e7af6302390684445b357e5cda4e4 Mon Sep 17 00:00:00 2001 From: german77 Date: Sun, 24 Oct 2021 11:22:20 -0500 Subject: settings: Fix mouse and keyboard mappings --- src/core/hid/emulated_controller.cpp | 8 +- src/core/hid/emulated_devices.cpp | 19 +-- src/core/hid/emulated_devices.h | 3 + src/input_common/drivers/mouse.cpp | 17 ++- src/input_common/drivers/mouse.h | 1 + src/input_common/input_engine.cpp | 2 + src/input_common/main.cpp | 3 + src/yuzu/configuration/configure_input_player.cpp | 147 +++++++++------------- src/yuzu/configuration/configure_vibration.cpp | 4 +- src/yuzu/debugger/controller.cpp | 3 +- 10 files changed, 102 insertions(+), 105 deletions(-) (limited to 'src/input_common/drivers') diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index 228f80183..bd0b89c05 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -246,7 +246,7 @@ std::vector EmulatedController::GetMappedDevices() const { devices.begin(), devices.end(), [param](const Common::ParamPackage param_) { return param.Get("engine", "") == param_.Get("engine", "") && param.Get("guid", "") == param_.Get("guid", "") && - param.Get("port", "") == param_.Get("port", ""); + param.Get("port", 0) == param_.Get("port", 0); }); if (devices_it != devices.end()) { continue; @@ -254,7 +254,7 @@ std::vector EmulatedController::GetMappedDevices() const { Common::ParamPackage device{}; device.Set("engine", param.Get("engine", "")); device.Set("guid", param.Get("guid", "")); - device.Set("port", param.Get("port", "")); + device.Set("port", param.Get("port", 0)); devices.push_back(device); } @@ -269,7 +269,7 @@ std::vector EmulatedController::GetMappedDevices() const { devices.begin(), devices.end(), [param](const Common::ParamPackage param_) { return param.Get("engine", "") == param_.Get("engine", "") && param.Get("guid", "") == param_.Get("guid", "") && - param.Get("port", "") == param_.Get("port", ""); + param.Get("port", 0) == param_.Get("port", 0); }); if (devices_it != devices.end()) { continue; @@ -277,7 +277,7 @@ std::vector EmulatedController::GetMappedDevices() const { Common::ParamPackage device{}; device.Set("engine", param.Get("engine", "")); device.Set("guid", param.Get("guid", "")); - device.Set("port", param.Get("port", "")); + device.Set("port", param.Get("port", 0)); devices.push_back(device); } return devices; diff --git a/src/core/hid/emulated_devices.cpp b/src/core/hid/emulated_devices.cpp index 1c4065cd8..5afd83f62 100644 --- a/src/core/hid/emulated_devices.cpp +++ b/src/core/hid/emulated_devices.cpp @@ -162,17 +162,22 @@ void EmulatedDevices::SetKeyboardButton(Input::CallbackStatus callback, std::siz return; } - // TODO(german77): Do this properly - // switch (index) { - // case Settings::NativeKeyboard::A: - // interface_status.keyboard_state.a.Assign(current_status.value); - // break; - // .... - // } + UpdateKey(index, current_status.value); TriggerOnChange(DeviceTriggerType::Keyboard); } +void EmulatedDevices::UpdateKey(std::size_t key_index, bool status) { + constexpr u8 KEYS_PER_BYTE = 8; + auto& entry = device_status.keyboard_state.key[key_index / KEYS_PER_BYTE]; + const u8 mask = 1 << (key_index % KEYS_PER_BYTE); + if (status) { + entry = entry | mask; + } else { + entry = entry & ~mask; + } +} + void EmulatedDevices::SetKeyboardModifier(Input::CallbackStatus callback, std::size_t index) { if (index >= device_status.keyboard_moddifier_values.size()) { return; diff --git a/src/core/hid/emulated_devices.h b/src/core/hid/emulated_devices.h index c6c19fae4..7ed95eac6 100644 --- a/src/core/hid/emulated_devices.h +++ b/src/core/hid/emulated_devices.h @@ -143,6 +143,9 @@ public: void DeleteCallback(int key); private: + /// Helps assigning a value to keyboard_state + void UpdateKey(std::size_t key_index, bool status); + /** * Updates the touch status of the console * @param callback: A CallbackStatus containing the key status diff --git a/src/input_common/drivers/mouse.cpp b/src/input_common/drivers/mouse.cpp index 2c2432fb7..1c32b54be 100644 --- a/src/input_common/drivers/mouse.cpp +++ b/src/input_common/drivers/mouse.cpp @@ -121,12 +121,27 @@ void Mouse::StopPanning() { std::vector Mouse::GetInputDevices() const { std::vector devices; devices.emplace_back(Common::ParamPackage{ - {"engine", "keyboard"}, + {"engine", GetEngineName()}, {"display", "Keyboard/Mouse"}, }); return devices; } +AnalogMapping Mouse::GetAnalogMappingForDevice( + [[maybe_unused]] const Common::ParamPackage& params) { + // Only overwrite different buttons from default + AnalogMapping mapping = {}; + Common::ParamPackage right_analog_params; + right_analog_params.Set("engine", GetEngineName()); + right_analog_params.Set("axis_x", 0); + right_analog_params.Set("axis_y", 1); + right_analog_params.Set("threshold", 0.5f); + right_analog_params.Set("range", 1.0f); + right_analog_params.Set("deadzone", 0.0f); + mapping.insert_or_assign(Settings::NativeAnalog::RStick, std::move(right_analog_params)); + return mapping; +} + std::string Mouse::GetUIName(const Common::ParamPackage& params) const { if (params.Has("button")) { return fmt::format("Mouse {}", params.Get("button", 0)); diff --git a/src/input_common/drivers/mouse.h b/src/input_common/drivers/mouse.h index e8355751a..d3178b1a9 100644 --- a/src/input_common/drivers/mouse.h +++ b/src/input_common/drivers/mouse.h @@ -55,6 +55,7 @@ public: void ReleaseAllButtons(); std::vector GetInputDevices() const override; + AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage& params) override; std::string GetUIName(const Common::ParamPackage& params) const override; private: diff --git a/src/input_common/input_engine.cpp b/src/input_common/input_engine.cpp index 1534f24b0..9cfe0f232 100644 --- a/src/input_common/input_engine.cpp +++ b/src/input_common/input_engine.cpp @@ -202,6 +202,8 @@ void InputEngine::TriggerOnButtonChange(const PadIdentifier& identifier, int but if (!configuring || !mapping_callback.on_data) { return; } + + PreSetButton(identifier, button); if (value == GetButton(identifier, button)) { return; } diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp index 8f7ce59b7..07d514ad7 100644 --- a/src/input_common/main.cpp +++ b/src/input_common/main.cpp @@ -143,6 +143,9 @@ struct InputSubsystem::Impl { return {}; } const std::string engine = params.Get("engine", ""); + if (engine == mouse->GetEngineName()) { + return mouse->GetAnalogMappingForDevice(params); + } if (engine == gcadapter->GetEngineName()) { return gcadapter->GetAnalogMappingForDevice(params); } diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index cd33b5711..416096333 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp @@ -478,37 +478,39 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i UpdateControllerEnabledButtons(); UpdateControllerButtonNames(); UpdateMotionButtons(); - connect(ui->comboControllerType, qOverload(&QComboBox::currentIndexChanged), [this, player_index](int) { - UpdateControllerAvailableButtons(); - UpdateControllerEnabledButtons(); - UpdateControllerButtonNames(); - UpdateMotionButtons(); - const Core::HID::NpadType type = GetControllerTypeFromIndex(ui->comboControllerType->currentIndex()); - - if (player_index == 0) { - auto* emulated_controller_p1 = - system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); - auto* emulated_controller_hanheld = - system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld); - bool is_connected = emulated_controller->IsConnected(true); - - emulated_controller_p1->SetNpadType(type); - emulated_controller_hanheld->SetNpadType(type); - if (is_connected) { - if (type == Core::HID::NpadType::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; + connect(ui->comboControllerType, qOverload(&QComboBox::currentIndexChanged), + [this, player_index](int) { + UpdateControllerAvailableButtons(); + UpdateControllerEnabledButtons(); + UpdateControllerButtonNames(); + UpdateMotionButtons(); + const Core::HID::NpadType type = + GetControllerTypeFromIndex(ui->comboControllerType->currentIndex()); + + if (player_index == 0) { + auto* emulated_controller_p1 = + system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); + auto* emulated_controller_hanheld = + system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld); + bool is_connected = emulated_controller->IsConnected(true); + + emulated_controller_p1->SetNpadType(type); + emulated_controller_hanheld->SetNpadType(type); + if (is_connected) { + if (type == Core::HID::NpadType::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); } - } - ui->controllerFrame->SetController(emulated_controller); - } - emulated_controller->SetNpadType(type); - }); + emulated_controller->SetNpadType(type); + }); connect(ui->comboDevices, qOverload(&QComboBox::activated), this, &ConfigureInputPlayer::UpdateMappingWithDefaults); @@ -555,7 +557,7 @@ ConfigureInputPlayer::~ConfigureInputPlayer() { } else { emulated_controller->DisableConfiguration(); } -}; +} void ConfigureInputPlayer::ApplyConfiguration() { if (player_index == 0) { @@ -642,7 +644,7 @@ void ConfigureInputPlayer::UpdateInputDeviceCombobox() { const auto first_engine = devices[0].Get("engine", ""); const auto first_guid = devices[0].Get("guid", ""); - const auto first_port = devices[0].Get("port", ""); + const auto first_port = devices[0].Get("port", 0); if (devices.size() == 1) { const auto devices_it = @@ -650,7 +652,7 @@ void ConfigureInputPlayer::UpdateInputDeviceCombobox() { [first_engine, first_guid, first_port](const Common::ParamPackage param) { return param.Get("engine", "") == first_engine && param.Get("guid", "") == first_guid && - param.Get("port", "") == first_port; + param.Get("port", 0) == first_port; }); const int device_index = devices_it != input_devices.end() @@ -662,7 +664,7 @@ void ConfigureInputPlayer::UpdateInputDeviceCombobox() { const auto second_engine = devices[1].Get("engine", ""); const auto second_guid = devices[1].Get("guid", ""); - const auto second_port = devices[1].Get("port", ""); + 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"); @@ -684,7 +686,7 @@ void ConfigureInputPlayer::UpdateInputDeviceCombobox() { 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", "") == first_port; + param.Get("port", 0) == first_port; }); const int device_index = devices_it != input_devices.end() @@ -1096,8 +1098,8 @@ void ConfigureInputPlayer::UpdateMappingWithDefaults() { emulated_controller->SetMotionParam(motion_id, {}); } - // Reset keyboard bindings - if (ui->comboDevices->currentIndex() == 1) { + // Reset keyboard or mouse bindings + if (ui->comboDevices->currentIndex() == 1 || ui->comboDevices->currentIndex() == 2) { for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; ++button_id) { emulated_controller->SetButtonParam( button_id, Common::ParamPackage{InputCommon::GenerateKeyboardParam( @@ -1122,63 +1124,30 @@ void ConfigureInputPlayer::UpdateMappingWithDefaults() { Config::default_motions[motion_id])}); } - UpdateUI(); - return; - } - - // Reset keyboard with mouse bindings - if (ui->comboDevices->currentIndex() == 2) { - 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])}); - } - - Common::ParamPackage left_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[Settings::NativeAnalog::LStick][sub_button_id])}; - SetAnalogParam(params, left_analog_param, analog_sub_buttons[sub_button_id]); - } - left_analog_param.Set("modifier", - InputCommon::GenerateKeyboardParam( - Config::default_stick_mod[Settings::NativeAnalog::LStick])); - emulated_controller->SetStickParam(Settings::NativeAnalog::LStick, left_analog_param); - - Common::ParamPackage right_analog_param{}; - right_analog_param.Set("engine", "mouse"); - right_analog_param.Set("port", 0); - right_analog_param.Set("axis_x", 0); - right_analog_param.Set("axis_y", 1); - emulated_controller->SetStickParam(Settings::NativeAnalog::RStick, - std::move(right_analog_param)); - - 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])}); + // 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_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 < button_mapping.size(); ++i) { - emulated_controller->SetButtonParam( - i, button_mapping[static_cast(i)]); + 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); } - for (std::size_t i = 0; i < analog_mapping.size(); ++i) { - emulated_controller->SetStickParam( - i, analog_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 < motion_mapping.size(); ++i) { - emulated_controller->SetMotionParam( - i, motion_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); } UpdateUI(); @@ -1237,7 +1206,7 @@ bool ConfigureInputPlayer::IsInputAcceptable(const Common::ParamPackage& params) } // Keyboard/Mouse - if (ui->comboDevices->currentIndex() == 2) { + if (ui->comboDevices->currentIndex() == 1 || ui->comboDevices->currentIndex() == 2) { return params.Get("engine", "") == "keyboard" || params.Get("engine", "") == "mouse"; } @@ -1245,7 +1214,7 @@ bool ConfigureInputPlayer::IsInputAcceptable(const Common::ParamPackage& params) 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", "") == current_input_device.Get("port", ""); + params.Get("port", 0) == current_input_device.Get("port", 0); } void ConfigureInputPlayer::mousePressEvent(QMouseEvent* event) { diff --git a/src/yuzu/configuration/configure_vibration.cpp b/src/yuzu/configuration/configure_vibration.cpp index 46a0f3025..f1ce7205d 100644 --- 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", ""); + const auto port = param.Get("port", 0); 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.empty()) { + if (port != 0) { 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 3619aed26..f93a46421 100644 --- a/src/yuzu/debugger/controller.cpp +++ b/src/yuzu/debugger/controller.cpp @@ -21,8 +21,7 @@ ControllerDialog::ControllerDialog(Core::System& system, QWidget* parent) Qt::WindowMaximizeButtonHint); widget = new PlayerControlPreview(this); - widget->SetController(system.HIDCore().GetEmulatedController( - Core::HID::NpadIdType::Player1)); + widget->SetController(system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1)); QLayout* layout = new QVBoxLayout(this); layout->setContentsMargins(0, 0, 0, 0); layout->addWidget(widget); -- cgit v1.2.3 From 7348e205d94e2fff777781498a2ef7931163703a Mon Sep 17 00:00:00 2001 From: german77 Date: Tue, 26 Oct 2021 23:37:46 -0500 Subject: input_common: Add multiple vibration curves --- src/core/hid/emulated_controller.cpp | 10 +++++++++- src/input_common/drivers/sdl_driver.cpp | 33 +++++++++++++++++++-------------- 2 files changed, 28 insertions(+), 15 deletions(-) (limited to 'src/input_common/drivers') diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index 83ced5635..916368c68 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -251,7 +251,8 @@ void EmulatedController::RestoreConfig() { ReloadFromSettings(); } -std::vector EmulatedController::GetMappedDevices(DeviceIndex device_index) const { +std::vector EmulatedController::GetMappedDevices( + DeviceIndex device_index) const { std::vector devices; for (const auto& param : button_params) { if (!param.Has("engine")) { @@ -658,6 +659,10 @@ bool EmulatedController::SetVibration(std::size_t device_index, VibrationValue v const auto& player = Settings::values.players.GetValue()[player_index]; const f32 strength = static_cast(player.vibration_strength) / 100.0f; + if (!player.vibration_enabled) { + return false; + } + // Exponential amplification is too strong at low amplitudes. Switch to a linear // amplification if strength is set below 0.7f const Input::VibrationAmplificationType type = @@ -860,6 +865,9 @@ AnalogSticks EmulatedController::GetSticks() const { } // Some drivers like stick from buttons need constant refreshing for (auto& device : stick_devices) { + if (!device) { + continue; + } device->SoftUpdate(); } return controller.analog_stick_state; diff --git a/src/input_common/drivers/sdl_driver.cpp b/src/input_common/drivers/sdl_driver.cpp index d56351815..53e282ef3 100644 --- a/src/input_common/drivers/sdl_driver.cpp +++ b/src/input_common/drivers/sdl_driver.cpp @@ -94,7 +94,6 @@ public: bool RumblePlay(const Input::VibrationStatus vibration) { constexpr u32 rumble_max_duration_ms = 1000; - if (sdl_controller) { return SDL_GameControllerRumble( sdl_controller.get(), static_cast(vibration.low_amplitude), @@ -520,25 +519,31 @@ Input::VibrationError SDLDriver::SetRumble(const PadIdentifier& identifier, const Input::VibrationStatus vibration) { const auto joystick = GetSDLJoystickByGUID(identifier.guid.Format(), static_cast(identifier.port)); - const auto process_amplitude = [](f32 amplitude) { - return (amplitude + std::pow(amplitude, 0.3f)) * 0.5f * 0xFFFF; + const auto process_amplitude_exp = [](f32 amplitude, f32 factor) { + return (amplitude + std::pow(amplitude, factor)) * 0.5f * 0xFFFF; }; - const Input::VibrationStatus exponential_vibration{ - .low_amplitude = process_amplitude(vibration.low_amplitude), + + // Default exponential curve for rumble + f32 factor = 0.35f; + + // If vibration is set as a linear output use a flatter value + if (vibration.type == Input::VibrationAmplificationType::Linear) { + factor = 0.5f; + } + + // Amplitude for HD rumble needs no modification + if (joystick->HasHDRumble()) { + factor = 1.0f; + } + + const Input::VibrationStatus new_vibration{ + .low_amplitude = process_amplitude_exp(vibration.low_amplitude, factor), .low_frequency = vibration.low_frequency, - .high_amplitude = process_amplitude(vibration.high_amplitude), + .high_amplitude = process_amplitude_exp(vibration.high_amplitude, factor), .high_frequency = vibration.high_frequency, .type = Input::VibrationAmplificationType::Exponential, }; - Input::VibrationStatus new_vibration{}; - - if (vibration.type == Input::VibrationAmplificationType::Linear || joystick->HasHDRumble()) { - new_vibration = vibration; - } else { - new_vibration = exponential_vibration; - } - if (!joystick->RumblePlay(new_vibration)) { return Input::VibrationError::Unknown; } -- cgit v1.2.3 From 1d71d4b87415b2581e6757f07d29275e02671b7a Mon Sep 17 00:00:00 2001 From: german77 Date: Mon, 25 Oct 2021 12:53:14 -0500 Subject: input_common: Fix UDP uuid --- src/input_common/drivers/udp_client.cpp | 10 +++++++++- src/input_common/drivers/udp_client.h | 2 ++ src/yuzu/configuration/configure_input_player.cpp | 6 +++++- 3 files changed, 16 insertions(+), 2 deletions(-) (limited to 'src/input_common/drivers') diff --git a/src/input_common/drivers/udp_client.cpp b/src/input_common/drivers/udp_client.cpp index 192ab336b..7cab707da 100644 --- a/src/input_common/drivers/udp_client.cpp +++ b/src/input_common/drivers/udp_client.cpp @@ -4,6 +4,7 @@ #include #include +#include #include "common/logging/log.h" #include "common/param_package.h" @@ -279,6 +280,7 @@ void UDPClient::StartCommunication(std::size_t client, const std::string& host, [this](Response::PortInfo info) { OnPortInfo(info); }, [this, client](Response::PadData data) { OnPadData(data, client); }}; LOG_INFO(Input, "Starting communication with UDP input server on {}:{}", host, port); + clients[client].uuid = GetHostUUID(host); clients[client].host = host; clients[client].port = port; clients[client].active = 0; @@ -293,12 +295,18 @@ void UDPClient::StartCommunication(std::size_t client, const std::string& host, const PadIdentifier UDPClient::GetPadIdentifier(std::size_t pad_index) const { const std::size_t client = pad_index / PADS_PER_CLIENT; return { - .guid = Common::UUID{clients[client].host}, + .guid = clients[client].uuid, .port = static_cast(clients[client].port), .pad = pad_index, }; } +const Common::UUID UDPClient::GetHostUUID(const std::string host) const { + const auto ip = boost::asio::ip::address_v4::from_string(host); + const auto hex_host = fmt::format("{:06x}", ip.to_ulong()); + return Common::UUID{hex_host}; +} + void UDPClient::Reset() { for (auto& client : clients) { if (client.thread.joinable()) { diff --git a/src/input_common/drivers/udp_client.h b/src/input_common/drivers/udp_client.h index 639325b17..1f02adba5 100644 --- a/src/input_common/drivers/udp_client.h +++ b/src/input_common/drivers/udp_client.h @@ -69,6 +69,7 @@ private: struct ClientConnection { ClientConnection(); ~ClientConnection(); + Common::UUID uuid{"7F000001"}; std::string host{"127.0.0.1"}; u16 port{26760}; s8 active{-1}; @@ -87,6 +88,7 @@ private: void OnPadData(Response::PadData, std::size_t client); void StartCommunication(std::size_t client, const std::string& host, u16 port); const PadIdentifier GetPadIdentifier(std::size_t pad_index) const; + const Common::UUID GetHostUUID(const std::string host) const; // Allocate clients for 8 udp servers static constexpr std::size_t MAX_UDP_CLIENTS = 8; diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index acb29a6b4..9a1b3575e 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp @@ -1178,7 +1178,7 @@ void ConfigureInputPlayer::HandleClick( } timeout_timer->start(2500); // Cancel after 2.5 seconds - poll_timer->start(50); // Check for new inputs every 50ms + poll_timer->start(25); // Check for new inputs every 25ms } void ConfigureInputPlayer::SetPollingResult(const Common::ParamPackage& params, bool abort) { @@ -1205,6 +1205,10 @@ 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) { return params.Get("engine", "") == "keyboard" || params.Get("engine", "") == "mouse"; -- cgit v1.2.3 From d8e3f2b10bad7e4a0ae09c90c76e8a1927c3d1ab Mon Sep 17 00:00:00 2001 From: german77 Date: Sat, 30 Oct 2021 11:20:47 -0500 Subject: input_common: Fix GC adapter initialization Fix GC controller --- src/input_common/drivers/gc_adapter.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'src/input_common/drivers') diff --git a/src/input_common/drivers/gc_adapter.cpp b/src/input_common/drivers/gc_adapter.cpp index 25b66f528..62dc28711 100644 --- a/src/input_common/drivers/gc_adapter.cpp +++ b/src/input_common/drivers/gc_adapter.cpp @@ -73,7 +73,7 @@ GCAdapter::GCAdapter(const std::string input_engine_) : InputEngine(input_engine if (usb_adapter_handle) { return; } - LOG_INFO(Input, "GC Adapter Initialization started"); + LOG_DEBUG(Input, "Initialization started"); libusb_ctx = std::make_unique(); const int init_res = libusb_ctx->InitResult(); @@ -90,7 +90,7 @@ GCAdapter::~GCAdapter() { } void GCAdapter::AdapterInputThread(std::stop_token stop_token) { - LOG_DEBUG(Input, "GC Adapter input thread started"); + LOG_DEBUG(Input, "Input thread started"); Common::SetCurrentThreadName("yuzu:input:GCAdapter"); s32 payload_size{}; AdapterPayload adapter_payload{}; @@ -120,7 +120,7 @@ bool GCAdapter::IsPayloadCorrect(const AdapterPayload& adapter_payload, s32 payl LOG_DEBUG(Input, "Error reading payload (size: {}, type: {:02x})", payload_size, adapter_payload[0]); if (input_error_counter++ > 20) { - LOG_ERROR(Input, "GC adapter timeout, Is the adapter connected?"); + LOG_ERROR(Input, "Timeout, Is the adapter connected?"); adapter_input_thread.request_stop(); restart_scan_thread = true; } @@ -263,13 +263,6 @@ bool GCAdapter::Setup() { } bool GCAdapter::CheckDeviceAccess() { - // This fixes payload problems from offbrand GCAdapters - const s32 control_transfer_error = - libusb_control_transfer(usb_adapter_handle->get(), 0x21, 11, 0x0001, 0, nullptr, 0, 1000); - if (control_transfer_error < 0) { - LOG_ERROR(Input, "libusb_control_transfer failed with error= {}", control_transfer_error); - } - s32 kernel_driver_error = libusb_kernel_driver_active(usb_adapter_handle->get(), 0); if (kernel_driver_error == 1) { kernel_driver_error = libusb_detach_kernel_driver(usb_adapter_handle->get(), 0); @@ -291,6 +284,13 @@ bool GCAdapter::CheckDeviceAccess() { return false; } + // This fixes payload problems from offbrand GCAdapters + const s32 control_transfer_error = + libusb_control_transfer(usb_adapter_handle->get(), 0x21, 11, 0x0001, 0, nullptr, 0, 1000); + if (control_transfer_error < 0) { + LOG_ERROR(Input, "libusb_control_transfer failed with error= {}", control_transfer_error); + } + return true; } @@ -370,9 +370,9 @@ void GCAdapter::SendVibrations() { libusb_interrupt_transfer(usb_adapter_handle->get(), output_endpoint, payload.data(), static_cast(payload.size()), &size, 16); if (err) { - LOG_DEBUG(Input, "Adapter libusb write failed: {}", libusb_error_name(err)); + LOG_DEBUG(Input, "Libusb write failed: {}", libusb_error_name(err)); if (output_error_counter++ > 5) { - LOG_ERROR(Input, "GC adapter output timeout, Rumble disabled"); + LOG_ERROR(Input, "Output timeout, Rumble disabled"); rumble_enabled = false; } return; -- cgit v1.2.3 From 61d9eb9f690d6afe141f24ba75c99b54e122dfa3 Mon Sep 17 00:00:00 2001 From: german77 Date: Sat, 30 Oct 2021 20:16:10 -0500 Subject: input_common: Revert deleted TAS functions --- src/core/hid/emulated_controller.cpp | 44 ++++++++++++------------- src/input_common/drivers/tas_input.cpp | 23 ++++++------- src/input_common/drivers/tas_input.h | 14 ++++---- src/yuzu/bootmanager.cpp | 1 + src/yuzu/debugger/controller.cpp | 60 ++++++++++++++++++++++++++++++++-- src/yuzu/debugger/controller.h | 26 ++++++++++++--- src/yuzu/main.cpp | 2 +- 7 files changed, 122 insertions(+), 48 deletions(-) (limited to 'src/input_common/drivers') diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index 3c3fa16d6..69568f4e9 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -127,7 +127,7 @@ void EmulatedController::LoadDevices() { // Initialize TAS devices std::transform(tas_button_params.begin(), tas_button_params.end(), tas_button_devices.begin(), Input::CreateDevice); - std::transform(tas_stick_params.begin(), tas_stick_params.begin(), tas_stick_devices.begin(), + std::transform(tas_stick_params.begin(), tas_stick_params.end(), tas_stick_devices.begin(), Input::CreateDevice); } @@ -135,7 +135,7 @@ void EmulatedController::LoadTASParams() { const auto player_index = NpadIdTypeToIndex(npad_id_type); Common::ParamPackage common_params{}; common_params.Set("engine", "tas"); - common_params.Set("pad", static_cast(player_index)); + common_params.Set("port", static_cast(player_index)); for (auto& param : tas_button_params) { param = common_params; } @@ -144,26 +144,26 @@ void EmulatedController::LoadTASParams() { } // TODO(german77): Replace this with an input profile or something better - tas_button_params[Settings::NativeButton::A].Set("button", 1 << 0); - tas_button_params[Settings::NativeButton::B].Set("button", 1 << 1); - tas_button_params[Settings::NativeButton::X].Set("button", 1 << 2); - tas_button_params[Settings::NativeButton::Y].Set("button", 1 << 3); - tas_button_params[Settings::NativeButton::LStick].Set("button", 1 << 4); - tas_button_params[Settings::NativeButton::RStick].Set("button", 1 << 5); - tas_button_params[Settings::NativeButton::L].Set("button", 1 << 6); - tas_button_params[Settings::NativeButton::R].Set("button", 1 << 7); - tas_button_params[Settings::NativeButton::ZL].Set("button", 1 << 8); - tas_button_params[Settings::NativeButton::ZR].Set("button", 1 << 9); - tas_button_params[Settings::NativeButton::Plus].Set("button", 1 << 10); - tas_button_params[Settings::NativeButton::Minus].Set("button", 1 << 11); - tas_button_params[Settings::NativeButton::DLeft].Set("button", 1 << 12); - tas_button_params[Settings::NativeButton::DUp].Set("button", 1 << 13); - tas_button_params[Settings::NativeButton::DRight].Set("button", 1 << 14); - tas_button_params[Settings::NativeButton::DDown].Set("button", 1 << 15); - tas_button_params[Settings::NativeButton::SL].Set("button", 1 << 16); - tas_button_params[Settings::NativeButton::SR].Set("button", 1 << 17); - tas_button_params[Settings::NativeButton::Home].Set("button", 1 << 18); - tas_button_params[Settings::NativeButton::Screenshot].Set("button", 1 << 19); + tas_button_params[Settings::NativeButton::A].Set("button", 0); + tas_button_params[Settings::NativeButton::B].Set("button", 1); + tas_button_params[Settings::NativeButton::X].Set("button", 2); + tas_button_params[Settings::NativeButton::Y].Set("button", 3); + tas_button_params[Settings::NativeButton::LStick].Set("button", 4); + tas_button_params[Settings::NativeButton::RStick].Set("button", 5); + tas_button_params[Settings::NativeButton::L].Set("button", 6); + tas_button_params[Settings::NativeButton::R].Set("button", 7); + tas_button_params[Settings::NativeButton::ZL].Set("button", 8); + tas_button_params[Settings::NativeButton::ZR].Set("button", 9); + tas_button_params[Settings::NativeButton::Plus].Set("button", 10); + tas_button_params[Settings::NativeButton::Minus].Set("button", 11); + tas_button_params[Settings::NativeButton::DLeft].Set("button", 12); + tas_button_params[Settings::NativeButton::DUp].Set("button", 13); + tas_button_params[Settings::NativeButton::DRight].Set("button", 14); + tas_button_params[Settings::NativeButton::DDown].Set("button", 15); + tas_button_params[Settings::NativeButton::SL].Set("button", 16); + tas_button_params[Settings::NativeButton::SR].Set("button", 17); + tas_button_params[Settings::NativeButton::Home].Set("button", 18); + tas_button_params[Settings::NativeButton::Screenshot].Set("button", 19); tas_stick_params[Settings::NativeAnalog::LStick].Set("axis_x", 0); tas_stick_params[Settings::NativeAnalog::LStick].Set("axis_y", 1); diff --git a/src/input_common/drivers/tas_input.cpp b/src/input_common/drivers/tas_input.cpp index 7e7a1d58f..d2748b240 100644 --- a/src/input_common/drivers/tas_input.cpp +++ b/src/input_common/drivers/tas_input.cpp @@ -141,7 +141,7 @@ void Tas::WriteTasFile(std::u8string file_name) { } } -void Tas::RecordInput(u32 buttons, TasAnalog left_axis, TasAnalog right_axis) { +void Tas::RecordInput(u64 buttons, TasAnalog left_axis, TasAnalog right_axis) { last_input = { .buttons = buttons, .l_axis = FlipAxisY(left_axis), @@ -195,7 +195,7 @@ void Tas::UpdateThread() { } if (current_command < script_length) { LOG_DEBUG(Input, "Playing TAS {}/{}", current_command, script_length); - size_t frame = current_command++; + const size_t frame = current_command++; for (size_t player_index = 0; player_index < commands.size(); player_index++) { TASCommand command{}; if (frame < commands[player_index].size()) { @@ -207,8 +207,8 @@ void Tas::UpdateThread() { .port = player_index, .pad = 0, }; - for (std::size_t i = 0; i < sizeof(command.buttons); ++i) { - const bool button_status = (command.buttons & (1U << i)) != 0; + for (std::size_t i = 0; i < sizeof(command.buttons) * 8; ++i) { + const bool button_status = (command.buttons & (1LLU << i)) != 0; const int button = static_cast(i); SetButton(identifier, button, button_status); } @@ -244,14 +244,14 @@ TasAnalog Tas::ReadCommandAxis(const std::string& line) const { return {x, y}; } -u32 Tas::ReadCommandButtons(const std::string& data) const { +u64 Tas::ReadCommandButtons(const std::string& data) const { std::stringstream button_text(data); std::string line; - u32 buttons = 0; + u64 buttons = 0; while (std::getline(button_text, line, ';')) { for (auto [text, tas_button] : text_to_tas_button) { if (text == line) { - buttons |= static_cast(tas_button); + buttons |= static_cast(tas_button); break; } } @@ -259,13 +259,14 @@ u32 Tas::ReadCommandButtons(const std::string& data) const { return buttons; } -std::string Tas::WriteCommandButtons(u32 buttons) const { +std::string Tas::WriteCommandButtons(u64 buttons) const { std::string returns = ""; for (auto [text_button, tas_button] : text_to_tas_button) { - if ((buttons & static_cast(tas_button)) != 0) - returns += fmt::format("{};", text_button.substr(4)); + if ((buttons & static_cast(tas_button)) != 0) { + returns += fmt::format("{};", text_button); + } } - return returns.empty() ? "NONE" : returns.substr(2); + return returns.empty() ? "NONE" : returns; } std::string Tas::WriteCommandAxis(TasAnalog analog) const { diff --git a/src/input_common/drivers/tas_input.h b/src/input_common/drivers/tas_input.h index 9fadc118b..5f5c3267c 100644 --- a/src/input_common/drivers/tas_input.h +++ b/src/input_common/drivers/tas_input.h @@ -47,7 +47,7 @@ namespace InputCommon::TasInput { constexpr size_t PLAYER_NUMBER = 10; -enum class TasButton : u32 { +enum class TasButton : u64 { BUTTON_A = 1U << 0, BUTTON_B = 1U << 1, BUTTON_X = 1U << 2, @@ -92,7 +92,7 @@ public: * @param left_axis: value of the left axis * @param right_axis: value of the right axis */ - void RecordInput(u32 buttons, TasAnalog left_axis, TasAnalog right_axis); + void RecordInput(u64 buttons, TasAnalog left_axis, TasAnalog right_axis); // Main loop that records or executes input void UpdateThread(); @@ -129,7 +129,7 @@ public: private: struct TASCommand { - u32 buttons{}; + u64 buttons{}; TasAnalog l_axis{}; TasAnalog r_axis{}; }; @@ -164,9 +164,9 @@ private: * Parses a string containing the button values. Each button is represented by it's text format * specified in text_to_tas_button array * @param line: string containing button name with the following format "a;b;c;d..." - * @return Returns a u32 with each bit representing the status of a button + * @return Returns a u64 with each bit representing the status of a button */ - u32 ReadCommandButtons(const std::string& line) const; + u64 ReadCommandButtons(const std::string& line) const; /** * Reset state of all players @@ -174,11 +174,11 @@ private: void ClearInput(); /** - * Converts an u32 containing the button status into the text equivalent + * Converts an u64 containing the button status into the text equivalent * @param buttons: bitfield with the status of the buttons * @return Returns a string with the name of the buttons to be written to the file */ - std::string WriteCommandButtons(u32 buttons) const; + std::string WriteCommandButtons(u64 buttons) const; /** * Converts an TAS analog object containing the axis status into the text equivalent diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 726f789b7..4b3cd9f3e 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -35,6 +35,7 @@ #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/main.h" #include "video_core/renderer_base.h" diff --git a/src/yuzu/debugger/controller.cpp b/src/yuzu/debugger/controller.cpp index f93a46421..aaca494b8 100644 --- a/src/yuzu/debugger/controller.cpp +++ b/src/yuzu/debugger/controller.cpp @@ -7,11 +7,16 @@ #include #include "common/settings.h" #include "core/core.h" +#include "core/hid/emulated_controller.h" +#include "input_common/drivers/tas_input.h" +#include "input_common/main.h" #include "yuzu/configuration/configure_input_player_widget.h" #include "yuzu/debugger/controller.h" -ControllerDialog::ControllerDialog(Core::System& system, QWidget* parent) - : QWidget(parent, Qt::Dialog) { +ControllerDialog::ControllerDialog(Core::System& system_, + std::shared_ptr input_subsystem_, + QWidget* parent) + : QWidget(parent, Qt::Dialog), system{system_}, input_subsystem{input_subsystem_} { setObjectName(QStringLiteral("Controller")); setWindowTitle(tr("Controller P1")); resize(500, 350); @@ -21,7 +26,7 @@ ControllerDialog::ControllerDialog(Core::System& system, QWidget* parent) Qt::WindowMaximizeButtonHint); widget = new PlayerControlPreview(this); - widget->SetController(system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1)); + refreshConfiguration(); QLayout* layout = new QVBoxLayout(this); layout->setContentsMargins(0, 0, 0, 0); layout->addWidget(widget); @@ -34,6 +39,22 @@ ControllerDialog::ControllerDialog(Core::System& system, QWidget* parent) widget->setFocus(); } +void ControllerDialog::refreshConfiguration() { + UnloadController(); + auto* player_1 = system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1); + auto* handheld = system.HIDCore().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; +} + QAction* ControllerDialog::toggleViewAction() { if (toggle_view_action == nullptr) { toggle_view_action = new QAction(tr("&Controller P1"), this); @@ -47,6 +68,10 @@ QAction* ControllerDialog::toggleViewAction() { void ControllerDialog::UnloadController() { widget->UnloadController(); + if (is_controller_set) { + controller->DeleteCallback(callback_key); + is_controller_set = false; + } } void ControllerDialog::showEvent(QShowEvent* ev) { @@ -62,3 +87,32 @@ void ControllerDialog::hideEvent(QHideEvent* ev) { } 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; + } +} diff --git a/src/yuzu/debugger/controller.h b/src/yuzu/debugger/controller.h index 33f617b9b..ba4185a4b 100644 --- a/src/yuzu/debugger/controller.h +++ b/src/yuzu/debugger/controller.h @@ -11,24 +11,33 @@ class QHideEvent; class QShowEvent; class PlayerControlPreview; +namespace InputCommon { +class InputSubsystem; +} + namespace Core { class System; } -namespace InputCommon { -class InputSubsystem; +namespace Core::HID { +class EmulatedController; } class ControllerDialog : public QWidget { Q_OBJECT public: - explicit ControllerDialog(Core::System& system, QWidget* parent = nullptr); + explicit ControllerDialog(Core::System& system_, + std::shared_ptr input_subsystem_, + QWidget* parent = nullptr); /// Returns a QAction that can be used to toggle visibility of this dialog. QAction* toggleViewAction(); - // Disables events from the emulated controller + /// Reloads the widget to apply any changes in the configuration + void refreshConfiguration(); + + /// Disables events from the emulated controller void UnloadController(); protected: @@ -36,6 +45,15 @@ protected: 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; + QAction* toggle_view_action = nullptr; PlayerControlPreview* widget; + Core::System& system; + std::shared_ptr input_subsystem; }; diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 022d11cc4..56db337a4 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -925,7 +925,7 @@ void GMainWindow::InitializeDebugWidgets() { waitTreeWidget->hide(); debug_menu->addAction(waitTreeWidget->toggleViewAction()); - controller_dialog = new ControllerDialog(*system, this); + controller_dialog = new ControllerDialog(*system, input_subsystem, this); controller_dialog->hide(); debug_menu->addAction(controller_dialog->toggleViewAction()); -- cgit v1.2.3 From 2b1b0c2a30e242b08ec120e09803ec54d5445703 Mon Sep 17 00:00:00 2001 From: german77 Date: Sat, 30 Oct 2021 22:23:10 -0500 Subject: kraken: Address comments from review start lion review --- src/common/input.h | 4 +- src/common/settings.h | 1 - src/core/hid/emulated_console.cpp | 17 +- src/core/hid/emulated_console.h | 15 +- src/core/hid/emulated_controller.cpp | 88 ++++----- src/core/hid/emulated_controller.h | 42 +++-- src/core/hid/emulated_devices.cpp | 37 ++-- src/core/hid/emulated_devices.h | 28 +-- src/core/hid/input_converter.cpp | 75 ++++---- src/core/hid/input_converter.h | 17 +- src/core/hle/service/hid/controllers/debug_pad.cpp | 3 - src/core/hle/service/hid/controllers/keyboard.cpp | 1 - src/core/hle/service/hid/controllers/npad.h | 3 +- src/core/hle/service/hid/ring_lifo.h | 6 +- src/input_common/drivers/gc_adapter.cpp | 10 +- src/input_common/drivers/gc_adapter.h | 7 +- src/input_common/drivers/keyboard.h | 2 +- src/input_common/drivers/mouse.h | 2 +- src/input_common/drivers/sdl_driver.cpp | 16 +- src/input_common/drivers/sdl_driver.h | 7 +- src/input_common/drivers/touch_screen.h | 2 +- src/input_common/helpers/stick_from_buttons.cpp | 70 +++---- src/input_common/helpers/stick_from_buttons.h | 4 +- src/input_common/helpers/touch_from_buttons.cpp | 29 +-- src/input_common/helpers/touch_from_buttons.h | 4 +- src/input_common/input_engine.h | 14 +- src/input_common/input_poller.cpp | 202 +++++++++++---------- src/input_common/input_poller.h | 32 ++-- src/input_common/main.cpp | 76 ++++---- .../configure_input_player_widget.cpp | 105 ++++++----- .../configuration/configure_input_player_widget.h | 81 +++++---- 31 files changed, 534 insertions(+), 466 deletions(-) (limited to 'src/input_common/drivers') diff --git a/src/common/input.h b/src/common/input.h index cb84f1005..6d3227f5e 100644 --- a/src/common/input.h +++ b/src/common/input.h @@ -12,7 +12,7 @@ #include "common/logging/log.h" #include "common/param_package.h" -namespace Input { +namespace Common::Input { enum class InputType { None, @@ -296,4 +296,4 @@ std::unique_ptr CreateDevice(const Common::ParamPackage package return pair->second->Create(package); } -} // namespace Input +} // namespace Common::Input diff --git a/src/common/settings.h b/src/common/settings.h index dac44d000..95225fba7 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -6,7 +6,6 @@ #include #include -#include #include #include #include diff --git a/src/core/hid/emulated_console.cpp b/src/core/hid/emulated_console.cpp index d1d4a5355..c259de0f1 100644 --- a/src/core/hid/emulated_console.cpp +++ b/src/core/hid/emulated_console.cpp @@ -55,21 +55,21 @@ void EmulatedConsole::SetTouchParams() { void EmulatedConsole::ReloadInput() { SetTouchParams(); - motion_devices = Input::CreateDevice(motion_params); + motion_devices = Common::Input::CreateDevice(motion_params); if (motion_devices) { - Input::InputCallback motion_callback{ - [this](Input::CallbackStatus callback) { SetMotion(callback); }}; + Common::Input::InputCallback motion_callback{ + [this](Common::Input::CallbackStatus callback) { SetMotion(callback); }}; motion_devices->SetCallback(motion_callback); } std::size_t index = 0; for (auto& touch_device : touch_devices) { - touch_device = Input::CreateDevice(touch_params[index]); + touch_device = Common::Input::CreateDevice(touch_params[index]); if (!touch_device) { continue; } - Input::InputCallback touch_callback{ - [this, index](Input::CallbackStatus callback) { SetTouch(callback, index); }}; + Common::Input::InputCallback touch_callback{ + [this, index](Common::Input::CallbackStatus callback) { SetTouch(callback, index); }}; touch_device->SetCallback(touch_callback); index++; } @@ -117,7 +117,7 @@ void EmulatedConsole::SetMotionParam(Common::ParamPackage param) { ReloadInput(); } -void EmulatedConsole::SetMotion(Input::CallbackStatus callback) { +void EmulatedConsole::SetMotion(Common::Input::CallbackStatus callback) { std::lock_guard lock{mutex}; auto& raw_status = console.motion_values.raw_status; auto& emulated = console.motion_values.emulated; @@ -152,7 +152,8 @@ void EmulatedConsole::SetMotion(Input::CallbackStatus callback) { TriggerOnChange(ConsoleTriggerType::Motion); } -void EmulatedConsole::SetTouch(Input::CallbackStatus callback, [[maybe_unused]] std::size_t index) { +void EmulatedConsole::SetTouch(Common::Input::CallbackStatus callback, + [[maybe_unused]] std::size_t index) { if (index >= console.touch_values.size()) { return; } diff --git a/src/core/hid/emulated_console.h b/src/core/hid/emulated_console.h index f26f24f2e..9aec482a6 100644 --- a/src/core/hid/emulated_console.h +++ b/src/core/hid/emulated_console.h @@ -4,10 +4,13 @@ #pragma once +#include #include +#include #include #include +#include "common/common_types.h" #include "common/input.h" #include "common/param_package.h" #include "common/point.h" @@ -20,18 +23,18 @@ namespace Core::HID { struct ConsoleMotionInfo { - Input::MotionStatus raw_status{}; + Common::Input::MotionStatus raw_status{}; MotionInput emulated{}; }; -using ConsoleMotionDevices = std::unique_ptr; -using TouchDevices = std::array, 16>; +using ConsoleMotionDevices = std::unique_ptr; +using TouchDevices = std::array, 16>; using ConsoleMotionParams = Common::ParamPackage; using TouchParams = std::array; using ConsoleMotionValues = ConsoleMotionInfo; -using TouchValues = std::array; +using TouchValues = std::array; struct TouchFinger { u64 last_touch{}; @@ -151,14 +154,14 @@ private: * Updates the motion status of the console * @param A CallbackStatus containing gyro and accelerometer data */ - void SetMotion(Input::CallbackStatus callback); + void SetMotion(Common::Input::CallbackStatus callback); /** * Updates the touch status of the console * @param callback: A CallbackStatus containing the touch position * @param index: Finger ID to be updated */ - void SetTouch(Input::CallbackStatus callback, std::size_t index); + void SetTouch(Common::Input::CallbackStatus callback, std::size_t index); /** * Triggers a callback that something has changed on the console status diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index 69568f4e9..49893cdbd 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -110,25 +110,25 @@ void EmulatedController::LoadDevices() { std::transform(button_params.begin() + Settings::NativeButton::BUTTON_HID_BEGIN, button_params.begin() + Settings::NativeButton::BUTTON_NS_END, - button_devices.begin(), Input::CreateDevice); + button_devices.begin(), Common::Input::CreateDevice); std::transform(stick_params.begin() + Settings::NativeAnalog::STICK_HID_BEGIN, stick_params.begin() + Settings::NativeAnalog::STICK_HID_END, - stick_devices.begin(), Input::CreateDevice); + stick_devices.begin(), Common::Input::CreateDevice); std::transform(motion_params.begin() + Settings::NativeMotion::MOTION_HID_BEGIN, motion_params.begin() + Settings::NativeMotion::MOTION_HID_END, - motion_devices.begin(), Input::CreateDevice); + motion_devices.begin(), Common::Input::CreateDevice); std::transform(trigger_params.begin(), trigger_params.end(), trigger_devices.begin(), - Input::CreateDevice); + Common::Input::CreateDevice); std::transform(battery_params.begin(), battery_params.begin(), battery_devices.end(), - Input::CreateDevice); + Common::Input::CreateDevice); std::transform(output_params.begin(), output_params.end(), output_devices.begin(), - Input::CreateDevice); + Common::Input::CreateDevice); // Initialize TAS devices std::transform(tas_button_params.begin(), tas_button_params.end(), tas_button_devices.begin(), - Input::CreateDevice); + Common::Input::CreateDevice); std::transform(tas_stick_params.begin(), tas_stick_params.end(), tas_stick_devices.begin(), - Input::CreateDevice); + Common::Input::CreateDevice); } void EmulatedController::LoadTASParams() { @@ -178,8 +178,8 @@ void EmulatedController::ReloadInput() { if (!button_devices[index]) { continue; } - Input::InputCallback button_callback{ - [this, index](Input::CallbackStatus callback) { SetButton(callback, index); }}; + Common::Input::InputCallback button_callback{ + [this, index](Common::Input::CallbackStatus callback) { SetButton(callback, index); }}; button_devices[index]->SetCallback(button_callback); button_devices[index]->ForceUpdate(); } @@ -188,8 +188,8 @@ void EmulatedController::ReloadInput() { if (!stick_devices[index]) { continue; } - Input::InputCallback stick_callback{ - [this, index](Input::CallbackStatus callback) { SetStick(callback, index); }}; + Common::Input::InputCallback stick_callback{ + [this, index](Common::Input::CallbackStatus callback) { SetStick(callback, index); }}; stick_devices[index]->SetCallback(stick_callback); stick_devices[index]->ForceUpdate(); } @@ -198,8 +198,8 @@ void EmulatedController::ReloadInput() { if (!trigger_devices[index]) { continue; } - Input::InputCallback trigger_callback{ - [this, index](Input::CallbackStatus callback) { SetTrigger(callback, index); }}; + Common::Input::InputCallback trigger_callback{ + [this, index](Common::Input::CallbackStatus callback) { SetTrigger(callback, index); }}; trigger_devices[index]->SetCallback(trigger_callback); trigger_devices[index]->ForceUpdate(); } @@ -208,8 +208,8 @@ void EmulatedController::ReloadInput() { if (!battery_devices[index]) { continue; } - Input::InputCallback battery_callback{ - [this, index](Input::CallbackStatus callback) { SetBattery(callback, index); }}; + Common::Input::InputCallback battery_callback{ + [this, index](Common::Input::CallbackStatus callback) { SetBattery(callback, index); }}; battery_devices[index]->SetCallback(battery_callback); battery_devices[index]->ForceUpdate(); } @@ -218,8 +218,8 @@ void EmulatedController::ReloadInput() { if (!motion_devices[index]) { continue; } - Input::InputCallback motion_callback{ - [this, index](Input::CallbackStatus callback) { SetMotion(callback, index); }}; + Common::Input::InputCallback motion_callback{ + [this, index](Common::Input::CallbackStatus callback) { SetMotion(callback, index); }}; motion_devices[index]->SetCallback(motion_callback); motion_devices[index]->ForceUpdate(); } @@ -229,8 +229,8 @@ void EmulatedController::ReloadInput() { if (!tas_button_devices[index]) { continue; } - Input::InputCallback button_callback{ - [this, index](Input::CallbackStatus callback) { SetButton(callback, index); }}; + Common::Input::InputCallback button_callback{ + [this, index](Common::Input::CallbackStatus callback) { SetButton(callback, index); }}; tas_button_devices[index]->SetCallback(button_callback); } @@ -238,8 +238,8 @@ void EmulatedController::ReloadInput() { if (!tas_stick_devices[index]) { continue; } - Input::InputCallback stick_callback{ - [this, index](Input::CallbackStatus callback) { SetStick(callback, index); }}; + Common::Input::InputCallback stick_callback{ + [this, index](Common::Input::CallbackStatus callback) { SetStick(callback, index); }}; tas_stick_devices[index]->SetCallback(stick_callback); } } @@ -418,7 +418,7 @@ void EmulatedController::SetMotionParam(std::size_t index, Common::ParamPackage ReloadInput(); } -void EmulatedController::SetButton(Input::CallbackStatus callback, std::size_t index) { +void EmulatedController::SetButton(Common::Input::CallbackStatus callback, std::size_t index) { if (index >= controller.button_values.size()) { return; } @@ -548,7 +548,7 @@ void EmulatedController::SetButton(Input::CallbackStatus callback, std::size_t i TriggerOnChange(ControllerTriggerType::Button, true); } -void EmulatedController::SetStick(Input::CallbackStatus callback, std::size_t index) { +void EmulatedController::SetStick(Common::Input::CallbackStatus callback, std::size_t index) { if (index >= controller.stick_values.size()) { return; } @@ -587,7 +587,7 @@ void EmulatedController::SetStick(Input::CallbackStatus callback, std::size_t in TriggerOnChange(ControllerTriggerType::Stick, true); } -void EmulatedController::SetTrigger(Input::CallbackStatus callback, std::size_t index) { +void EmulatedController::SetTrigger(Common::Input::CallbackStatus callback, std::size_t index) { if (index >= controller.trigger_values.size()) { return; } @@ -618,7 +618,7 @@ void EmulatedController::SetTrigger(Input::CallbackStatus callback, std::size_t TriggerOnChange(ControllerTriggerType::Trigger, true); } -void EmulatedController::SetMotion(Input::CallbackStatus callback, std::size_t index) { +void EmulatedController::SetMotion(Common::Input::CallbackStatus callback, std::size_t index) { if (index >= controller.motion_values.size()) { return; } @@ -655,7 +655,7 @@ void EmulatedController::SetMotion(Input::CallbackStatus callback, std::size_t i TriggerOnChange(ControllerTriggerType::Motion, true); } -void EmulatedController::SetBattery(Input::CallbackStatus callback, std::size_t index) { +void EmulatedController::SetBattery(Common::Input::CallbackStatus callback, std::size_t index) { if (index >= controller.battery_values.size()) { return; } @@ -671,25 +671,25 @@ void EmulatedController::SetBattery(Input::CallbackStatus callback, std::size_t bool is_powered = false; BatteryLevel battery_level = 0; switch (controller.battery_values[index]) { - case Input::BatteryLevel::Charging: + case Common::Input::BatteryLevel::Charging: is_charging = true; is_powered = true; battery_level = 6; break; - case Input::BatteryLevel::Medium: + case Common::Input::BatteryLevel::Medium: battery_level = 6; break; - case Input::BatteryLevel::Low: + case Common::Input::BatteryLevel::Low: battery_level = 4; break; - case Input::BatteryLevel::Critical: + case Common::Input::BatteryLevel::Critical: battery_level = 2; break; - case Input::BatteryLevel::Empty: + case Common::Input::BatteryLevel::Empty: battery_level = 0; break; - case Input::BatteryLevel::None: - case Input::BatteryLevel::Full: + case Common::Input::BatteryLevel::None: + case Common::Input::BatteryLevel::Full: default: is_powered = true; battery_level = 8; @@ -739,18 +739,19 @@ bool EmulatedController::SetVibration(std::size_t device_index, VibrationValue v // Exponential amplification is too strong at low amplitudes. Switch to a linear // amplification if strength is set below 0.7f - const Input::VibrationAmplificationType type = - strength > 0.7f ? Input::VibrationAmplificationType::Exponential - : Input::VibrationAmplificationType::Linear; + const Common::Input::VibrationAmplificationType type = + strength > 0.7f ? Common::Input::VibrationAmplificationType::Exponential + : Common::Input::VibrationAmplificationType::Linear; - const Input::VibrationStatus status = { + const Common::Input::VibrationStatus status = { .low_amplitude = std::min(vibration.low_amplitude * strength, 1.0f), .low_frequency = vibration.low_frequency, .high_amplitude = std::min(vibration.high_amplitude * strength, 1.0f), .high_frequency = vibration.high_frequency, .type = type, }; - return output_devices[device_index]->SetVibration(status) == Input::VibrationError::None; + return output_devices[device_index]->SetVibration(status) == + Common::Input::VibrationError::None; } bool EmulatedController::TestVibration(std::size_t device_index) { @@ -762,14 +763,15 @@ bool EmulatedController::TestVibration(std::size_t device_index) { } // Send a slight vibration to test for rumble support - constexpr Input::VibrationStatus status = { + constexpr Common::Input::VibrationStatus status = { .low_amplitude = 0.001f, .low_frequency = 160.0f, .high_amplitude = 0.001f, .high_frequency = 320.0f, - .type = Input::VibrationAmplificationType::Linear, + .type = Common::Input::VibrationAmplificationType::Linear, }; - return output_devices[device_index]->SetVibration(status) == Input::VibrationError::None; + return output_devices[device_index]->SetVibration(status) == + Common::Input::VibrationError::None; } void EmulatedController::SetLedPattern() { @@ -779,7 +781,7 @@ void EmulatedController::SetLedPattern() { } const LedPattern pattern = GetLedPattern(); - const Input::LedStatus status = { + const Common::Input::LedStatus status = { .led_1 = pattern.position1 != 0, .led_2 = pattern.position2 != 0, .led_3 = pattern.position3 != 0, diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h index fea401365..dd9a93364 100644 --- a/src/core/hid/emulated_controller.h +++ b/src/core/hid/emulated_controller.h @@ -4,10 +4,13 @@ #pragma once +#include #include +#include #include #include +#include "common/common_types.h" #include "common/input.h" #include "common/param_package.h" #include "common/point.h" @@ -20,20 +23,22 @@ namespace Core::HID { const std::size_t max_emulated_controllers = 2; struct ControllerMotionInfo { - Input::MotionStatus raw_status{}; + Common::Input::MotionStatus raw_status{}; MotionInput emulated{}; }; using ButtonDevices = - std::array, Settings::NativeButton::NumButtons>; + std::array, Settings::NativeButton::NumButtons>; using StickDevices = - std::array, Settings::NativeAnalog::NumAnalogs>; + std::array, Settings::NativeAnalog::NumAnalogs>; using ControllerMotionDevices = - std::array, Settings::NativeMotion::NumMotions>; + std::array, Settings::NativeMotion::NumMotions>; using TriggerDevices = - std::array, Settings::NativeTrigger::NumTriggers>; -using BatteryDevices = std::array, max_emulated_controllers>; -using OutputDevices = std::array, max_emulated_controllers>; + std::array, Settings::NativeTrigger::NumTriggers>; +using BatteryDevices = + std::array, max_emulated_controllers>; +using OutputDevices = + std::array, max_emulated_controllers>; using ButtonParams = std::array; using StickParams = std::array; @@ -42,13 +47,14 @@ using TriggerParams = std::array; using OutputParams = std::array; -using ButtonValues = std::array; -using SticksValues = std::array; -using TriggerValues = std::array; +using ButtonValues = std::array; +using SticksValues = std::array; +using TriggerValues = + std::array; using ControllerMotionValues = std::array; -using ColorValues = std::array; -using BatteryValues = std::array; -using VibrationValues = std::array; +using ColorValues = std::array; +using BatteryValues = std::array; +using VibrationValues = std::array; struct AnalogSticks { AnalogStickState left{}; @@ -307,35 +313,35 @@ private: * @param callback: A CallbackStatus containing the button status * @param index: Button ID of the to be updated */ - void SetButton(Input::CallbackStatus callback, std::size_t index); + void SetButton(Common::Input::CallbackStatus callback, std::size_t index); /** * Updates the analog stick status of the controller * @param callback: A CallbackStatus containing the analog stick status * @param index: stick ID of the to be updated */ - void SetStick(Input::CallbackStatus callback, std::size_t index); + void SetStick(Common::Input::CallbackStatus callback, std::size_t index); /** * Updates the trigger status of the controller * @param callback: A CallbackStatus containing the trigger status * @param index: trigger ID of the to be updated */ - void SetTrigger(Input::CallbackStatus callback, std::size_t index); + void SetTrigger(Common::Input::CallbackStatus callback, std::size_t index); /** * Updates the motion status of the controller * @param callback: A CallbackStatus containing gyro and accelerometer data * @param index: motion ID of the to be updated */ - void SetMotion(Input::CallbackStatus callback, std::size_t index); + void SetMotion(Common::Input::CallbackStatus callback, std::size_t index); /** * Updates the battery status of the controller * @param callback: A CallbackStatus containing the battery status * @param index: Button ID of the to be updated */ - void SetBattery(Input::CallbackStatus callback, std::size_t index); + void SetBattery(Common::Input::CallbackStatus callback, std::size_t index); /** * Triggers a callback that something has changed on the controller status diff --git a/src/core/hid/emulated_devices.cpp b/src/core/hid/emulated_devices.cpp index eb59c310c..c76a86b6c 100644 --- a/src/core/hid/emulated_devices.cpp +++ b/src/core/hid/emulated_devices.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included +#include #include #include "core/hid/emulated_devices.h" @@ -25,21 +26,25 @@ void EmulatedDevices::ReloadFromSettings() { void EmulatedDevices::ReloadInput() { std::transform(mouse_button_params.begin() + Settings::NativeMouseButton::MOUSE_HID_BEGIN, mouse_button_params.begin() + Settings::NativeMouseButton::MOUSE_HID_END, - mouse_button_devices.begin(), Input::CreateDevice); + mouse_button_devices.begin(), + Common::Input::CreateDevice); std::transform(Settings::values.keyboard_keys.begin(), Settings::values.keyboard_keys.end(), - keyboard_devices.begin(), Input::CreateDeviceFromString); + keyboard_devices.begin(), + Common::Input::CreateDeviceFromString); std::transform(Settings::values.keyboard_mods.begin(), Settings::values.keyboard_mods.end(), keyboard_modifier_devices.begin(), - Input::CreateDeviceFromString); + Common::Input::CreateDeviceFromString); for (std::size_t index = 0; index < mouse_button_devices.size(); ++index) { if (!mouse_button_devices[index]) { continue; } - Input::InputCallback button_callback{ - [this, index](Input::CallbackStatus callback) { SetMouseButton(callback, index); }}; + Common::Input::InputCallback button_callback{ + [this, index](Common::Input::CallbackStatus callback) { + SetMouseButton(callback, index); + }}; mouse_button_devices[index]->SetCallback(button_callback); } @@ -47,8 +52,10 @@ void EmulatedDevices::ReloadInput() { if (!keyboard_devices[index]) { continue; } - Input::InputCallback button_callback{ - [this, index](Input::CallbackStatus callback) { SetKeyboardButton(callback, index); }}; + Common::Input::InputCallback button_callback{ + [this, index](Common::Input::CallbackStatus callback) { + SetKeyboardButton(callback, index); + }}; keyboard_devices[index]->SetCallback(button_callback); } @@ -56,9 +63,10 @@ void EmulatedDevices::ReloadInput() { if (!keyboard_modifier_devices[index]) { continue; } - Input::InputCallback button_callback{[this, index](Input::CallbackStatus callback) { - SetKeyboardModifier(callback, index); - }}; + Common::Input::InputCallback button_callback{ + [this, index](Common::Input::CallbackStatus callback) { + SetKeyboardModifier(callback, index); + }}; keyboard_modifier_devices[index]->SetCallback(button_callback); } } @@ -122,7 +130,7 @@ void EmulatedDevices::SetMouseButtonParam(std::size_t index, Common::ParamPackag ReloadInput(); } -void EmulatedDevices::SetKeyboardButton(Input::CallbackStatus callback, std::size_t index) { +void EmulatedDevices::SetKeyboardButton(Common::Input::CallbackStatus callback, std::size_t index) { if (index >= device_status.keyboard_values.size()) { return; } @@ -170,7 +178,7 @@ void EmulatedDevices::SetKeyboardButton(Input::CallbackStatus callback, std::siz void EmulatedDevices::UpdateKey(std::size_t key_index, bool status) { constexpr u8 KEYS_PER_BYTE = 8; auto& entry = device_status.keyboard_state.key[key_index / KEYS_PER_BYTE]; - const u8 mask = 1 << (key_index % KEYS_PER_BYTE); + const u8 mask = static_cast(1 << (key_index % KEYS_PER_BYTE)); if (status) { entry = entry | mask; } else { @@ -178,7 +186,8 @@ void EmulatedDevices::UpdateKey(std::size_t key_index, bool status) { } } -void EmulatedDevices::SetKeyboardModifier(Input::CallbackStatus callback, std::size_t index) { +void EmulatedDevices::SetKeyboardModifier(Common::Input::CallbackStatus callback, + std::size_t index) { if (index >= device_status.keyboard_moddifier_values.size()) { return; } @@ -247,7 +256,7 @@ void EmulatedDevices::SetKeyboardModifier(Input::CallbackStatus callback, std::s TriggerOnChange(DeviceTriggerType::KeyboardModdifier); } -void EmulatedDevices::SetMouseButton(Input::CallbackStatus callback, std::size_t index) { +void EmulatedDevices::SetMouseButton(Common::Input::CallbackStatus callback, std::size_t index) { if (index >= device_status.mouse_button_values.size()) { return; } diff --git a/src/core/hid/emulated_devices.h b/src/core/hid/emulated_devices.h index 7ed95eac6..418b2f9b5 100644 --- a/src/core/hid/emulated_devices.h +++ b/src/core/hid/emulated_devices.h @@ -4,10 +4,13 @@ #pragma once +#include #include +#include #include #include +#include "common/common_types.h" #include "common/input.h" #include "common/param_package.h" #include "common/settings.h" @@ -16,21 +19,22 @@ namespace Core::HID { -using KeyboardDevices = - std::array, Settings::NativeKeyboard::NumKeyboardKeys>; -using KeyboardModifierDevices = - std::array, Settings::NativeKeyboard::NumKeyboardMods>; -using MouseButtonDevices = - std::array, Settings::NativeMouseButton::NumMouseButtons>; +using KeyboardDevices = std::array, + Settings::NativeKeyboard::NumKeyboardKeys>; +using KeyboardModifierDevices = std::array, + Settings::NativeKeyboard::NumKeyboardMods>; +using MouseButtonDevices = std::array, + Settings::NativeMouseButton::NumMouseButtons>; using MouseButtonParams = std::array; -using KeyboardValues = std::array; +using KeyboardValues = + std::array; using KeyboardModifierValues = - std::array; + std::array; using MouseButtonValues = - std::array; + std::array; struct MousePosition { s32 x; @@ -151,21 +155,21 @@ private: * @param callback: A CallbackStatus containing the key status * @param index: key ID to be updated */ - void SetKeyboardButton(Input::CallbackStatus callback, std::size_t index); + void SetKeyboardButton(Common::Input::CallbackStatus callback, std::size_t index); /** * Updates the touch status of the console * @param callback: A CallbackStatus containing the modifier key status * @param index: modifier key ID to be updated */ - void SetKeyboardModifier(Input::CallbackStatus callback, std::size_t index); + void SetKeyboardModifier(Common::Input::CallbackStatus callback, std::size_t index); /** * Updates the touch status of the console * @param callback: A CallbackStatus containing the button status * @param index: Button ID of the to be updated */ - void SetMouseButton(Input::CallbackStatus callback, std::size_t index); + void SetMouseButton(Common::Input::CallbackStatus callback, std::size_t index); /** * Triggers a callback that something has changed on the device status diff --git a/src/core/hid/input_converter.cpp b/src/core/hid/input_converter.cpp index e2598f367..14204917e 100644 --- a/src/core/hid/input_converter.cpp +++ b/src/core/hid/input_converter.cpp @@ -9,35 +9,35 @@ namespace Core::HID { -Input::BatteryStatus TransformToBattery(const Input::CallbackStatus& callback) { - Input::BatteryStatus battery{Input::BatteryStatus::None}; +Common::Input::BatteryStatus TransformToBattery(const Common::Input::CallbackStatus& callback) { + Common::Input::BatteryStatus battery{Common::Input::BatteryStatus::None}; switch (callback.type) { - case Input::InputType::Analog: - case Input::InputType::Trigger: { + case Common::Input::InputType::Analog: + case Common::Input::InputType::Trigger: { const auto value = TransformToTrigger(callback).analog.value; - battery = Input::BatteryLevel::Empty; + battery = Common::Input::BatteryLevel::Empty; if (value > 0.2f) { - battery = Input::BatteryLevel::Critical; + battery = Common::Input::BatteryLevel::Critical; } if (value > 0.4f) { - battery = Input::BatteryLevel::Low; + battery = Common::Input::BatteryLevel::Low; } if (value > 0.6f) { - battery = Input::BatteryLevel::Medium; + battery = Common::Input::BatteryLevel::Medium; } if (value > 0.8f) { - battery = Input::BatteryLevel::Full; + battery = Common::Input::BatteryLevel::Full; } if (value >= 1.0f) { - battery = Input::BatteryLevel::Charging; + battery = Common::Input::BatteryLevel::Charging; } break; } - case Input::InputType::Button: - battery = callback.button_status.value ? Input::BatteryLevel::Charging - : Input::BatteryLevel::Critical; + case Common::Input::InputType::Button: + battery = callback.button_status.value ? Common::Input::BatteryLevel::Charging + : Common::Input::BatteryLevel::Critical; break; - case Input::InputType::Battery: + case Common::Input::InputType::Battery: battery = callback.battery_status; break; default: @@ -48,14 +48,14 @@ Input::BatteryStatus TransformToBattery(const Input::CallbackStatus& callback) { return battery; } -Input::ButtonStatus TransformToButton(const Input::CallbackStatus& callback) { - Input::ButtonStatus status{}; +Common::Input::ButtonStatus TransformToButton(const Common::Input::CallbackStatus& callback) { + Common::Input::ButtonStatus status{}; switch (callback.type) { - case Input::InputType::Analog: - case Input::InputType::Trigger: + case Common::Input::InputType::Analog: + case Common::Input::InputType::Trigger: status.value = TransformToTrigger(callback).pressed; break; - case Input::InputType::Button: + case Common::Input::InputType::Button: status = callback.button_status; break; default: @@ -70,15 +70,15 @@ Input::ButtonStatus TransformToButton(const Input::CallbackStatus& callback) { return status; } -Input::MotionStatus TransformToMotion(const Input::CallbackStatus& callback) { - Input::MotionStatus status{}; +Common::Input::MotionStatus TransformToMotion(const Common::Input::CallbackStatus& callback) { + Common::Input::MotionStatus status{}; switch (callback.type) { - case Input::InputType::Button: { + case Common::Input::InputType::Button: { if (TransformToButton(callback).value) { std::random_device device; std::mt19937 gen(device()); std::uniform_int_distribution distribution(-1000, 1000); - Input::AnalogProperties properties{ + Common::Input::AnalogProperties properties{ .deadzone = 0.0, .range = 1.0f, .offset = 0.0, @@ -116,7 +116,7 @@ Input::MotionStatus TransformToMotion(const Input::CallbackStatus& callback) { } break; } - case Input::InputType::Motion: + case Common::Input::InputType::Motion: status = callback.motion_status; break; default: @@ -133,11 +133,11 @@ Input::MotionStatus TransformToMotion(const Input::CallbackStatus& callback) { return status; } -Input::StickStatus TransformToStick(const Input::CallbackStatus& callback) { - Input::StickStatus status{}; +Common::Input::StickStatus TransformToStick(const Common::Input::CallbackStatus& callback) { + Common::Input::StickStatus status{}; switch (callback.type) { - case Input::InputType::Stick: + case Common::Input::InputType::Stick: status = callback.stick_status; break; default: @@ -160,11 +160,11 @@ Input::StickStatus TransformToStick(const Input::CallbackStatus& callback) { return status; } -Input::TouchStatus TransformToTouch(const Input::CallbackStatus& callback) { - Input::TouchStatus status{}; +Common::Input::TouchStatus TransformToTouch(const Common::Input::CallbackStatus& callback) { + Common::Input::TouchStatus status{}; switch (callback.type) { - case Input::InputType::Touch: + case Common::Input::InputType::Touch: status = callback.touch_status; break; default: @@ -192,22 +192,22 @@ Input::TouchStatus TransformToTouch(const Input::CallbackStatus& callback) { return status; } -Input::TriggerStatus TransformToTrigger(const Input::CallbackStatus& callback) { - Input::TriggerStatus status{}; +Common::Input::TriggerStatus TransformToTrigger(const Common::Input::CallbackStatus& callback) { + Common::Input::TriggerStatus status{}; float& raw_value = status.analog.raw_value; bool calculate_button_value = true; switch (callback.type) { - case Input::InputType::Analog: + case Common::Input::InputType::Analog: status.analog.properties = callback.analog_status.properties; raw_value = callback.analog_status.raw_value; break; - case Input::InputType::Button: + case Common::Input::InputType::Button: status.analog.properties.range = 1.0f; status.analog.properties.inverted = callback.button_status.inverted; raw_value = callback.button_status.value ? 1.0f : 0.0f; break; - case Input::InputType::Trigger: + case Common::Input::InputType::Trigger: status = callback.trigger_status; calculate_button_value = false; break; @@ -234,7 +234,7 @@ Input::TriggerStatus TransformToTrigger(const Input::CallbackStatus& callback) { return status; } -void SanitizeAnalog(Input::AnalogStatus& analog, bool clamp_value) { +void SanitizeAnalog(Common::Input::AnalogStatus& analog, bool clamp_value) { const auto& properties = analog.properties; float& raw_value = analog.raw_value; float& value = analog.value; @@ -274,7 +274,8 @@ void SanitizeAnalog(Input::AnalogStatus& analog, bool clamp_value) { } } -void SanitizeStick(Input::AnalogStatus& analog_x, Input::AnalogStatus& analog_y, bool clamp_value) { +void SanitizeStick(Common::Input::AnalogStatus& analog_x, Common::Input::AnalogStatus& analog_y, + bool clamp_value) { const auto& properties_x = analog_x.properties; const auto& properties_y = analog_y.properties; float& raw_x = analog_x.raw_value; diff --git a/src/core/hid/input_converter.h b/src/core/hid/input_converter.h index 3cc32e26a..b38e657b0 100644 --- a/src/core/hid/input_converter.h +++ b/src/core/hid/input_converter.h @@ -16,7 +16,7 @@ namespace Core::HID { * @param Supported callbacks: Analog, Battery, Trigger. * @return A valid BatteryStatus object. */ -Input::BatteryStatus TransformToBattery(const Input::CallbackStatus& callback); +Common::Input::BatteryStatus TransformToBattery(const Common::Input::CallbackStatus& callback); /** * Converts raw input data into a valid button status. Applies invert properties to the output. @@ -24,7 +24,7 @@ Input::BatteryStatus TransformToBattery(const Input::CallbackStatus& callback); * @param Supported callbacks: Analog, Button, Trigger. * @return A valid TouchStatus object. */ -Input::ButtonStatus TransformToButton(const Input::CallbackStatus& callback); +Common::Input::ButtonStatus TransformToButton(const Common::Input::CallbackStatus& callback); /** * Converts raw input data into a valid motion status. @@ -32,7 +32,7 @@ Input::ButtonStatus TransformToButton(const Input::CallbackStatus& callback); * @param Supported callbacks: Motion. * @return A valid TouchStatus object. */ -Input::MotionStatus TransformToMotion(const Input::CallbackStatus& callback); +Common::Input::MotionStatus TransformToMotion(const Common::Input::CallbackStatus& callback); /** * Converts raw input data into a valid stick status. Applies offset, deadzone, range and invert @@ -41,7 +41,7 @@ Input::MotionStatus TransformToMotion(const Input::CallbackStatus& callback); * @param Supported callbacks: Stick. * @return A valid StickStatus object. */ -Input::StickStatus TransformToStick(const Input::CallbackStatus& callback); +Common::Input::StickStatus TransformToStick(const Common::Input::CallbackStatus& callback); /** * Converts raw input data into a valid touch status. @@ -49,7 +49,7 @@ Input::StickStatus TransformToStick(const Input::CallbackStatus& callback); * @param Supported callbacks: Touch. * @return A valid TouchStatus object. */ -Input::TouchStatus TransformToTouch(const Input::CallbackStatus& callback); +Common::Input::TouchStatus TransformToTouch(const Common::Input::CallbackStatus& callback); /** * Converts raw input data into a valid trigger status. Applies offset, deadzone, range and @@ -58,20 +58,21 @@ Input::TouchStatus TransformToTouch(const Input::CallbackStatus& callback); * @param Supported callbacks: Analog, Button, Trigger. * @return A valid TriggerStatus object. */ -Input::TriggerStatus TransformToTrigger(const Input::CallbackStatus& callback); +Common::Input::TriggerStatus TransformToTrigger(const Common::Input::CallbackStatus& callback); /** * Converts raw analog data into a valid analog value * @param An analog object containing raw data and properties, bool that determines if the value * needs to be clamped between -1.0f and 1.0f. */ -void SanitizeAnalog(Input::AnalogStatus& analog, bool clamp_value); +void SanitizeAnalog(Common::Input::AnalogStatus& analog, bool clamp_value); /** * Converts raw stick data into a valid stick value * @param Two analog objects containing raw data and properties, bool that determines if the value * needs to be clamped into the unit circle. */ -void SanitizeStick(Input::AnalogStatus& analog_x, Input::AnalogStatus& analog_y, bool clamp_value); +void SanitizeStick(Common::Input::AnalogStatus& analog_x, Common::Input::AnalogStatus& analog_y, + bool clamp_value); } // namespace Core::HID diff --git a/src/core/hle/service/hid/controllers/debug_pad.cpp b/src/core/hle/service/hid/controllers/debug_pad.cpp index 345134357..b009ed086 100644 --- a/src/core/hle/service/hid/controllers/debug_pad.cpp +++ b/src/core/hle/service/hid/controllers/debug_pad.cpp @@ -13,9 +13,6 @@ namespace Service::HID { constexpr std::size_t SHARED_MEMORY_OFFSET = 0x00000; -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 = system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Other); diff --git a/src/core/hle/service/hid/controllers/keyboard.cpp b/src/core/hle/service/hid/controllers/keyboard.cpp index f4d49965f..60dc62f2c 100644 --- a/src/core/hle/service/hid/controllers/keyboard.cpp +++ b/src/core/hle/service/hid/controllers/keyboard.cpp @@ -12,7 +12,6 @@ namespace Service::HID { constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3800; -constexpr u8 KEYS_PER_BYTE = 8; Controller_Keyboard::Controller_Keyboard(Core::System& system_) : ControllerBase{system_} { emulated_devices = system.HIDCore().GetEmulatedDevices(); diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h index af4934c55..4a9c9cc1a 100644 --- a/src/core/hle/service/hid/controllers/npad.h +++ b/src/core/hle/service/hid/controllers/npad.h @@ -403,8 +403,7 @@ private: AppletFooterUiType type; INSERT_PADDING_BYTES(0x5B); // Reserved }; - static_assert(sizeof(AppletFooterUi) == 0x60, - "AppletFooterUi is an invalid size"); + static_assert(sizeof(AppletFooterUi) == 0x60, "AppletFooterUi is an invalid size"); // This is nn::hid::NpadLarkType enum class NpadLarkType : u32 { diff --git a/src/core/hle/service/hid/ring_lifo.h b/src/core/hle/service/hid/ring_lifo.h index 382350a2d..6209ed0d1 100644 --- a/src/core/hle/service/hid/ring_lifo.h +++ b/src/core/hle/service/hid/ring_lifo.h @@ -4,6 +4,8 @@ #pragma once +#include + #include "common/common_types.h" #include "common/swap.h" @@ -29,10 +31,10 @@ struct Lifo { } const AtomicStorage& ReadPreviousEntry() const { - return entries[GetPreviuousEntryIndex()]; + return entries[GetPreviousEntryIndex()]; } - std::size_t GetPreviuousEntryIndex() const { + std::size_t GetPreviousEntryIndex() const { return (buffer_tail + total_buffer_count - 1) % total_buffer_count; } diff --git a/src/input_common/drivers/gc_adapter.cpp b/src/input_common/drivers/gc_adapter.cpp index 62dc28711..2550f8cba 100644 --- a/src/input_common/drivers/gc_adapter.cpp +++ b/src/input_common/drivers/gc_adapter.cpp @@ -248,7 +248,7 @@ bool GCAdapter::Setup() { std::size_t port = 0; for (GCController& pad : pads) { pad.identifier = { - .guid = Common::UUID{""}, + .guid = Common::UUID{Common::INVALID_UUID}, .port = port++, .pad = 0, }; @@ -325,8 +325,8 @@ bool GCAdapter::GetGCEndpoint(libusb_device* device) { return true; } -Input::VibrationError GCAdapter::SetRumble(const PadIdentifier& identifier, - const Input::VibrationStatus vibration) { +Common::Input::VibrationError GCAdapter::SetRumble(const PadIdentifier& identifier, + const Common::Input::VibrationStatus vibration) { const auto mean_amplitude = (vibration.low_amplitude + vibration.high_amplitude) * 0.5f; const auto processed_amplitude = static_cast((mean_amplitude + std::pow(mean_amplitude, 0.3f)) * 0.5f * 0x8); @@ -334,9 +334,9 @@ Input::VibrationError GCAdapter::SetRumble(const PadIdentifier& identifier, pads[identifier.port].rumble_amplitude = processed_amplitude; if (!rumble_enabled) { - return Input::VibrationError::Disabled; + return Common::Input::VibrationError::Disabled; } - return Input::VibrationError::None; + return Common::Input::VibrationError::None; } void GCAdapter::UpdateVibrations() { diff --git a/src/input_common/drivers/gc_adapter.h b/src/input_common/drivers/gc_adapter.h index b82e4803d..fba90352e 100644 --- a/src/input_common/drivers/gc_adapter.h +++ b/src/input_common/drivers/gc_adapter.h @@ -4,8 +4,11 @@ #pragma once +#include +#include #include #include +#include #include #include "input_common/input_engine.h" @@ -24,8 +27,8 @@ public: explicit GCAdapter(const std::string input_engine_); ~GCAdapter(); - Input::VibrationError SetRumble(const PadIdentifier& identifier, - const Input::VibrationStatus vibration) override; + Common::Input::VibrationError SetRumble( + const PadIdentifier& identifier, const Common::Input::VibrationStatus vibration) override; /// Used for automapping features std::vector GetInputDevices() const override; diff --git a/src/input_common/drivers/keyboard.h b/src/input_common/drivers/keyboard.h index a3e0d8a61..58df15050 100644 --- a/src/input_common/drivers/keyboard.h +++ b/src/input_common/drivers/keyboard.h @@ -35,7 +35,7 @@ public: private: const PadIdentifier identifier = { - .guid = Common::UUID{""}, + .guid = Common::UUID{Common::INVALID_UUID}, .port = 0, .pad = 0, }; diff --git a/src/input_common/drivers/mouse.h b/src/input_common/drivers/mouse.h index d3178b1a9..cf0918409 100644 --- a/src/input_common/drivers/mouse.h +++ b/src/input_common/drivers/mouse.h @@ -63,7 +63,7 @@ private: void StopPanning(); const PadIdentifier identifier = { - .guid = Common::UUID{""}, + .guid = Common::UUID{Common::INVALID_UUID}, .port = 0, .pad = 0, }; diff --git a/src/input_common/drivers/sdl_driver.cpp b/src/input_common/drivers/sdl_driver.cpp index 53e282ef3..1e3741e0f 100644 --- a/src/input_common/drivers/sdl_driver.cpp +++ b/src/input_common/drivers/sdl_driver.cpp @@ -92,7 +92,7 @@ public: return motion; } - bool RumblePlay(const Input::VibrationStatus vibration) { + bool RumblePlay(const Common::Input::VibrationStatus vibration) { constexpr u32 rumble_max_duration_ms = 1000; if (sdl_controller) { return SDL_GameControllerRumble( @@ -515,8 +515,8 @@ std::vector SDLDriver::GetInputDevices() const { } return devices; } -Input::VibrationError SDLDriver::SetRumble(const PadIdentifier& identifier, - const Input::VibrationStatus vibration) { +Common::Input::VibrationError SDLDriver::SetRumble(const PadIdentifier& identifier, + const Common::Input::VibrationStatus vibration) { const auto joystick = GetSDLJoystickByGUID(identifier.guid.Format(), static_cast(identifier.port)); const auto process_amplitude_exp = [](f32 amplitude, f32 factor) { @@ -527,7 +527,7 @@ Input::VibrationError SDLDriver::SetRumble(const PadIdentifier& identifier, f32 factor = 0.35f; // If vibration is set as a linear output use a flatter value - if (vibration.type == Input::VibrationAmplificationType::Linear) { + if (vibration.type == Common::Input::VibrationAmplificationType::Linear) { factor = 0.5f; } @@ -536,19 +536,19 @@ Input::VibrationError SDLDriver::SetRumble(const PadIdentifier& identifier, factor = 1.0f; } - const Input::VibrationStatus new_vibration{ + const Common::Input::VibrationStatus new_vibration{ .low_amplitude = process_amplitude_exp(vibration.low_amplitude, factor), .low_frequency = vibration.low_frequency, .high_amplitude = process_amplitude_exp(vibration.high_amplitude, factor), .high_frequency = vibration.high_frequency, - .type = Input::VibrationAmplificationType::Exponential, + .type = Common::Input::VibrationAmplificationType::Exponential, }; if (!joystick->RumblePlay(new_vibration)) { - return Input::VibrationError::Unknown; + return Common::Input::VibrationError::Unknown; } - return Input::VibrationError::None; + return Common::Input::VibrationError::None; } Common::ParamPackage SDLDriver::BuildAnalogParamPackageForButton(int port, std::string guid, s32 axis, float value) const { diff --git a/src/input_common/drivers/sdl_driver.h b/src/input_common/drivers/sdl_driver.h index 1ff85f48d..b879df8ab 100644 --- a/src/input_common/drivers/sdl_driver.h +++ b/src/input_common/drivers/sdl_driver.h @@ -58,8 +58,8 @@ public: std::string GetHatButtonName(u8 direction_value) const override; u8 GetHatButtonId(const std::string direction_name) const override; - Input::VibrationError SetRumble(const PadIdentifier& identifier, - const Input::VibrationStatus vibration) override; + Common::Input::VibrationError SetRumble( + const PadIdentifier& identifier, const Common::Input::VibrationStatus vibration) override; private: void InitJoystick(int joystick_index); @@ -105,9 +105,6 @@ private: /// Returns true if the button is on the left joycon bool IsButtonOnLeftSide(Settings::NativeButton::Values button) const; - // Set to true if SDL supports game controller subsystem - bool has_gamecontroller = false; - /// Map of GUID of a list of corresponding virtual Joysticks std::unordered_map>> joystick_map; std::mutex joystick_map_mutex; diff --git a/src/input_common/drivers/touch_screen.h b/src/input_common/drivers/touch_screen.h index 5fbb2f47f..d297d253c 100644 --- a/src/input_common/drivers/touch_screen.h +++ b/src/input_common/drivers/touch_screen.h @@ -41,7 +41,7 @@ public: private: const PadIdentifier identifier = { - .guid = Common::UUID{""}, + .guid = Common::UUID{Common::INVALID_UUID}, .port = 0, .pad = 0, }; diff --git a/src/input_common/helpers/stick_from_buttons.cpp b/src/input_common/helpers/stick_from_buttons.cpp index 806a0e8bb..1d5948f79 100644 --- a/src/input_common/helpers/stick_from_buttons.cpp +++ b/src/input_common/helpers/stick_from_buttons.cpp @@ -10,25 +10,27 @@ namespace InputCommon { -class Stick final : public Input::InputDevice { +class Stick final : public Common::Input::InputDevice { public: - using Button = std::unique_ptr; + using Button = std::unique_ptr; Stick(Button up_, Button down_, Button left_, Button right_, Button modifier_, float modifier_scale_, float modifier_angle_) : up(std::move(up_)), down(std::move(down_)), left(std::move(left_)), right(std::move(right_)), modifier(std::move(modifier_)), modifier_scale(modifier_scale_), modifier_angle(modifier_angle_) { - Input::InputCallback button_up_callback{ - [this](Input::CallbackStatus callback_) { UpdateUpButtonStatus(callback_); }}; - Input::InputCallback button_down_callback{ - [this](Input::CallbackStatus callback_) { UpdateDownButtonStatus(callback_); }}; - Input::InputCallback button_left_callback{ - [this](Input::CallbackStatus callback_) { UpdateLeftButtonStatus(callback_); }}; - Input::InputCallback button_right_callback{ - [this](Input::CallbackStatus callback_) { UpdateRightButtonStatus(callback_); }}; - Input::InputCallback button_modifier_callback{ - [this](Input::CallbackStatus callback_) { UpdateModButtonStatus(callback_); }}; + Common::Input::InputCallback button_up_callback{ + [this](Common::Input::CallbackStatus callback_) { UpdateUpButtonStatus(callback_); }}; + Common::Input::InputCallback button_down_callback{ + [this](Common::Input::CallbackStatus callback_) { UpdateDownButtonStatus(callback_); }}; + Common::Input::InputCallback button_left_callback{ + [this](Common::Input::CallbackStatus callback_) { UpdateLeftButtonStatus(callback_); }}; + Common::Input::InputCallback button_right_callback{ + [this](Common::Input::CallbackStatus callback_) { + UpdateRightButtonStatus(callback_); + }}; + Common::Input::InputCallback button_modifier_callback{ + [this](Common::Input::CallbackStatus callback_) { UpdateModButtonStatus(callback_); }}; up->SetCallback(button_up_callback); down->SetCallback(button_down_callback); left->SetCallback(button_left_callback); @@ -129,27 +131,27 @@ public: } } - void UpdateUpButtonStatus(Input::CallbackStatus button_callback) { + void UpdateUpButtonStatus(Common::Input::CallbackStatus button_callback) { up_status = button_callback.button_status.value; UpdateStatus(); } - void UpdateDownButtonStatus(Input::CallbackStatus button_callback) { + void UpdateDownButtonStatus(Common::Input::CallbackStatus button_callback) { down_status = button_callback.button_status.value; UpdateStatus(); } - void UpdateLeftButtonStatus(Input::CallbackStatus button_callback) { + void UpdateLeftButtonStatus(Common::Input::CallbackStatus button_callback) { left_status = button_callback.button_status.value; UpdateStatus(); } - void UpdateRightButtonStatus(Input::CallbackStatus button_callback) { + void UpdateRightButtonStatus(Common::Input::CallbackStatus button_callback) { right_status = button_callback.button_status.value; UpdateStatus(); } - void UpdateModButtonStatus(Input::CallbackStatus button_callback) { + void UpdateModButtonStatus(Common::Input::CallbackStatus button_callback) { modifier_status = button_callback.button_status.value; UpdateStatus(); } @@ -193,8 +195,8 @@ public: } last_update = now; - Input::CallbackStatus status{ - .type = Input::InputType::Stick, + Common::Input::CallbackStatus status{ + .type = Common::Input::InputType::Stick, .stick_status = GetStatus(), }; TriggerOnChange(status); @@ -209,15 +211,15 @@ public: } void SoftUpdate() override { - Input::CallbackStatus status{ - .type = Input::InputType::Stick, + Common::Input::CallbackStatus status{ + .type = Common::Input::InputType::Stick, .stick_status = GetStatus(), }; TriggerOnChange(status); } - Input::StickStatus GetStatus() const { - Input::StickStatus status{}; + Common::Input::StickStatus GetStatus() const { + Common::Input::StickStatus status{}; status.x.properties = properties; status.y.properties = properties; if (Settings::values.emulate_analog_keyboard) { @@ -263,19 +265,23 @@ private: bool left_status; bool right_status; bool modifier_status; - const Input::AnalogProperties properties{0.0f, 1.0f, 0.5f, 0.0f, false}; + const Common::Input::AnalogProperties properties{0.0f, 1.0f, 0.5f, 0.0f, false}; std::chrono::time_point last_update; }; -std::unique_ptr StickFromButton::Create(const Common::ParamPackage& params) { +std::unique_ptr StickFromButton::Create( + const Common::ParamPackage& params) { const std::string null_engine = Common::ParamPackage{{"engine", "null"}}.Serialize(); - auto up = Input::CreateDeviceFromString(params.Get("up", null_engine)); - auto down = Input::CreateDeviceFromString(params.Get("down", null_engine)); - auto left = Input::CreateDeviceFromString(params.Get("left", null_engine)); - auto right = - Input::CreateDeviceFromString(params.Get("right", null_engine)); - auto modifier = - Input::CreateDeviceFromString(params.Get("modifier", null_engine)); + auto up = Common::Input::CreateDeviceFromString( + params.Get("up", null_engine)); + auto down = Common::Input::CreateDeviceFromString( + params.Get("down", null_engine)); + auto left = Common::Input::CreateDeviceFromString( + params.Get("left", null_engine)); + auto right = Common::Input::CreateDeviceFromString( + params.Get("right", null_engine)); + auto modifier = Common::Input::CreateDeviceFromString( + params.Get("modifier", null_engine)); auto modifier_scale = params.Get("modifier_scale", 0.5f); auto modifier_angle = params.Get("modifier_angle", 5.5f); return std::make_unique(std::move(up), std::move(down), std::move(left), diff --git a/src/input_common/helpers/stick_from_buttons.h b/src/input_common/helpers/stick_from_buttons.h index 82dff5ca8..437ace4f7 100644 --- a/src/input_common/helpers/stick_from_buttons.h +++ b/src/input_common/helpers/stick_from_buttons.h @@ -12,7 +12,7 @@ namespace InputCommon { * An analog device factory that takes direction button devices and combines them into a analog * device. */ -class StickFromButton final : public Input::Factory { +class StickFromButton final : public Common::Input::Factory { public: /** * Creates an analog device from direction button devices @@ -24,7 +24,7 @@ public: * - "modifier": a serialized ParamPackage for creating a button device as the modifier * - "modifier_scale": a float for the multiplier the modifier gives to the position */ - std::unique_ptr Create(const Common::ParamPackage& params) override; + std::unique_ptr Create(const Common::ParamPackage& params) override; }; } // namespace InputCommon diff --git a/src/input_common/helpers/touch_from_buttons.cpp b/src/input_common/helpers/touch_from_buttons.cpp index bb2bad5b1..fee41cae3 100644 --- a/src/input_common/helpers/touch_from_buttons.cpp +++ b/src/input_common/helpers/touch_from_buttons.cpp @@ -9,22 +9,22 @@ namespace InputCommon { -class TouchFromButtonDevice final : public Input::InputDevice { +class TouchFromButtonDevice final : public Common::Input::InputDevice { public: - using Button = std::unique_ptr; + using Button = std::unique_ptr; TouchFromButtonDevice(Button button_, u32 touch_id_, float x_, float y_) : button(std::move(button_)), touch_id(touch_id_), x(x_), y(y_) { - Input::InputCallback button_up_callback{ - [this](Input::CallbackStatus callback_) { UpdateButtonStatus(callback_); }}; + Common::Input::InputCallback button_up_callback{ + [this](Common::Input::CallbackStatus callback_) { UpdateButtonStatus(callback_); }}; button->SetCallback(button_up_callback); button->ForceUpdate(); } - Input::TouchStatus GetStatus(bool pressed) const { - const Input::ButtonStatus button_status{ + Common::Input::TouchStatus GetStatus(bool pressed) const { + const Common::Input::ButtonStatus button_status{ .value = pressed, }; - Input::TouchStatus status{ + Common::Input::TouchStatus status{ .pressed = button_status, .x = {}, .y = {}, @@ -42,9 +42,9 @@ public: return status; } - void UpdateButtonStatus(Input::CallbackStatus button_callback) { - const Input::CallbackStatus status{ - .type = Input::InputType::Touch, + void UpdateButtonStatus(Common::Input::CallbackStatus button_callback) { + const Common::Input::CallbackStatus status{ + .type = Common::Input::InputType::Touch, .touch_status = GetStatus(button_callback.button_status.value), }; TriggerOnChange(status); @@ -55,13 +55,14 @@ private: const u32 touch_id; const float x; const float y; - const Input::AnalogProperties properties{0.0f, 1.0f, 0.5f, 0.0f, false}; + const Common::Input::AnalogProperties properties{0.0f, 1.0f, 0.5f, 0.0f, false}; }; -std::unique_ptr TouchFromButton::Create(const Common::ParamPackage& params) { +std::unique_ptr TouchFromButton::Create( + const Common::ParamPackage& params) { const std::string null_engine = Common::ParamPackage{{"engine", "null"}}.Serialize(); - auto button = - Input::CreateDeviceFromString(params.Get("button", null_engine)); + auto button = Common::Input::CreateDeviceFromString( + params.Get("button", null_engine)); const auto touch_id = params.Get("touch_id", 0); const float x = params.Get("x", 0.0f) / 1280.0f; const float y = params.Get("y", 0.0f) / 720.0f; diff --git a/src/input_common/helpers/touch_from_buttons.h b/src/input_common/helpers/touch_from_buttons.h index 21b353728..628f18215 100644 --- a/src/input_common/helpers/touch_from_buttons.h +++ b/src/input_common/helpers/touch_from_buttons.h @@ -11,12 +11,12 @@ namespace InputCommon { /** * A touch device factory that takes a list of button devices and combines them into a touch device. */ -class TouchFromButton final : public Input::Factory { +class TouchFromButton final : public Common::Input::Factory { public: /** * Creates a touch device from a list of button devices */ - std::unique_ptr Create(const Common::ParamPackage& params) override; + std::unique_ptr Create(const Common::ParamPackage& params) override; }; } // namespace InputCommon diff --git a/src/input_common/input_engine.h b/src/input_common/input_engine.h index 31ce900d7..ed79d3d93 100644 --- a/src/input_common/input_engine.h +++ b/src/input_common/input_engine.h @@ -116,22 +116,22 @@ public: // Sets a led pattern for a controller virtual void SetLeds([[maybe_unused]] const PadIdentifier& identifier, - [[maybe_unused]] const Input::LedStatus led_status) { + [[maybe_unused]] const Common::Input::LedStatus led_status) { return; } // Sets rumble to a controller - virtual Input::VibrationError SetRumble( + virtual Common::Input::VibrationError SetRumble( [[maybe_unused]] const PadIdentifier& identifier, - [[maybe_unused]] const Input::VibrationStatus vibration) { - return Input::VibrationError::NotSupported; + [[maybe_unused]] const Common::Input::VibrationStatus vibration) { + return Common::Input::VibrationError::NotSupported; } // Sets polling mode to a controller - virtual Input::PollingError SetPollingMode( + virtual Common::Input::PollingError SetPollingMode( [[maybe_unused]] const PadIdentifier& identifier, - [[maybe_unused]] const Input::PollingMode vibration) { - return Input::PollingError::NotSupported; + [[maybe_unused]] const Common::Input::PollingMode vibration) { + return Common::Input::PollingError::NotSupported; } // Returns the engine name diff --git a/src/input_common/input_poller.cpp b/src/input_common/input_poller.cpp index 6edb8d900..2b3b77938 100644 --- a/src/input_common/input_poller.cpp +++ b/src/input_common/input_poller.cpp @@ -10,13 +10,13 @@ namespace InputCommon { -class DummyInput final : public Input::InputDevice { +class DummyInput final : public Common::Input::InputDevice { public: explicit DummyInput() {} ~DummyInput() {} }; -class InputFromButton final : public Input::InputDevice { +class InputFromButton final : public Common::Input::InputDevice { public: explicit InputFromButton(PadIdentifier identifier_, u32 button_, bool toggle_, bool inverted_, InputEngine* input_engine_) @@ -37,7 +37,7 @@ public: input_engine->DeleteCallback(callback_key); } - Input::ButtonStatus GetStatus() const { + Common::Input::ButtonStatus GetStatus() const { return { .value = input_engine->GetButton(identifier, button), .inverted = inverted, @@ -46,8 +46,8 @@ public: } void ForceUpdate() { - const Input::CallbackStatus status{ - .type = Input::InputType::Button, + const Common::Input::CallbackStatus status{ + .type = Common::Input::InputType::Button, .button_status = GetStatus(), }; @@ -56,8 +56,8 @@ public: } void OnChange() { - const Input::CallbackStatus status{ - .type = Input::InputType::Button, + const Common::Input::CallbackStatus status{ + .type = Common::Input::InputType::Button, .button_status = GetStatus(), }; @@ -77,7 +77,7 @@ private: InputEngine* input_engine; }; -class InputFromHatButton final : public Input::InputDevice { +class InputFromHatButton final : public Common::Input::InputDevice { public: explicit InputFromHatButton(PadIdentifier identifier_, u32 button_, u8 direction_, bool toggle_, bool inverted_, InputEngine* input_engine_) @@ -98,7 +98,7 @@ public: input_engine->DeleteCallback(callback_key); } - Input::ButtonStatus GetStatus() const { + Common::Input::ButtonStatus GetStatus() const { return { .value = input_engine->GetHatButton(identifier, button, direction), .inverted = inverted, @@ -107,8 +107,8 @@ public: } void ForceUpdate() { - const Input::CallbackStatus status{ - .type = Input::InputType::Button, + const Common::Input::CallbackStatus status{ + .type = Common::Input::InputType::Button, .button_status = GetStatus(), }; @@ -117,8 +117,8 @@ public: } void OnChange() { - const Input::CallbackStatus status{ - .type = Input::InputType::Button, + const Common::Input::CallbackStatus status{ + .type = Common::Input::InputType::Button, .button_status = GetStatus(), }; @@ -139,11 +139,12 @@ private: InputEngine* input_engine; }; -class InputFromStick final : public Input::InputDevice { +class InputFromStick final : public Common::Input::InputDevice { public: explicit InputFromStick(PadIdentifier identifier_, u32 axis_x_, u32 axis_y_, - Input::AnalogProperties properties_x_, - Input::AnalogProperties properties_y_, InputEngine* input_engine_) + Common::Input::AnalogProperties properties_x_, + Common::Input::AnalogProperties properties_y_, + InputEngine* input_engine_) : identifier(identifier_), axis_x(axis_x_), axis_y(axis_y_), properties_x(properties_x_), properties_y(properties_y_), input_engine(input_engine_) { UpdateCallback engine_callback{[this]() { OnChange(); }}; @@ -170,8 +171,8 @@ public: input_engine->DeleteCallback(callback_key_y); } - Input::StickStatus GetStatus() const { - Input::StickStatus status; + Common::Input::StickStatus GetStatus() const { + Common::Input::StickStatus status; status.x = { .raw_value = input_engine->GetAxis(identifier, axis_x), .properties = properties_x, @@ -184,8 +185,8 @@ public: } void ForceUpdate() { - const Input::CallbackStatus status{ - .type = Input::InputType::Stick, + const Common::Input::CallbackStatus status{ + .type = Common::Input::InputType::Stick, .stick_status = GetStatus(), }; @@ -195,8 +196,8 @@ public: } void OnChange() { - const Input::CallbackStatus status{ - .type = Input::InputType::Stick, + const Common::Input::CallbackStatus status{ + .type = Common::Input::InputType::Stick, .stick_status = GetStatus(), }; @@ -212,8 +213,8 @@ private: const PadIdentifier identifier; const u32 axis_x; const u32 axis_y; - const Input::AnalogProperties properties_x; - const Input::AnalogProperties properties_y; + const Common::Input::AnalogProperties properties_x; + const Common::Input::AnalogProperties properties_y; int callback_key_x; int callback_key_y; float last_axis_x_value; @@ -221,12 +222,13 @@ private: InputEngine* input_engine; }; -class InputFromTouch final : public Input::InputDevice { +class InputFromTouch final : public Common::Input::InputDevice { public: explicit InputFromTouch(PadIdentifier identifier_, u32 touch_id_, u32 button_, bool toggle_, bool inverted_, u32 axis_x_, u32 axis_y_, - Input::AnalogProperties properties_x_, - Input::AnalogProperties properties_y_, InputEngine* input_engine_) + Common::Input::AnalogProperties properties_x_, + Common::Input::AnalogProperties properties_y_, + InputEngine* input_engine_) : identifier(identifier_), touch_id(touch_id_), button(button_), toggle(toggle_), inverted(inverted_), axis_x(axis_x_), axis_y(axis_y_), properties_x(properties_x_), properties_y(properties_y_), input_engine(input_engine_) { @@ -263,8 +265,8 @@ public: input_engine->DeleteCallback(callback_key_y); } - Input::TouchStatus GetStatus() const { - Input::TouchStatus status; + Common::Input::TouchStatus GetStatus() const { + Common::Input::TouchStatus status; status.id = touch_id; status.pressed = { .value = input_engine->GetButton(identifier, button), @@ -283,8 +285,8 @@ public: } void OnChange() { - const Input::CallbackStatus status{ - .type = Input::InputType::Touch, + const Common::Input::CallbackStatus status{ + .type = Common::Input::InputType::Touch, .touch_status = GetStatus(), }; @@ -306,8 +308,8 @@ private: const bool inverted; const u32 axis_x; const u32 axis_y; - const Input::AnalogProperties properties_x; - const Input::AnalogProperties properties_y; + const Common::Input::AnalogProperties properties_x; + const Common::Input::AnalogProperties properties_y; int callback_key_button; int callback_key_x; int callback_key_y; @@ -317,10 +319,10 @@ private: InputEngine* input_engine; }; -class InputFromTrigger final : public Input::InputDevice { +class InputFromTrigger final : public Common::Input::InputDevice { public: explicit InputFromTrigger(PadIdentifier identifier_, u32 button_, bool toggle_, bool inverted_, - u32 axis_, Input::AnalogProperties properties_, + u32 axis_, Common::Input::AnalogProperties properties_, InputEngine* input_engine_) : identifier(identifier_), button(button_), toggle(toggle_), inverted(inverted_), axis(axis_), properties(properties_), input_engine(input_engine_) { @@ -348,8 +350,8 @@ public: input_engine->DeleteCallback(axis_callback_key); } - Input::TriggerStatus GetStatus() const { - const Input::AnalogStatus analog_status{ + Common::Input::TriggerStatus GetStatus() const { + const Common::Input::AnalogStatus analog_status{ .raw_value = input_engine->GetAxis(identifier, axis), .properties = properties, }; @@ -360,8 +362,8 @@ public: } void OnChange() { - const Input::CallbackStatus status{ - .type = Input::InputType::Trigger, + const Common::Input::CallbackStatus status{ + .type = Common::Input::InputType::Trigger, .trigger_status = GetStatus(), }; @@ -379,7 +381,7 @@ private: const bool toggle; const bool inverted; const u32 axis; - const Input::AnalogProperties properties; + const Common::Input::AnalogProperties properties; int callback_key_button; int axis_callback_key; bool last_button_value; @@ -387,10 +389,11 @@ private: InputEngine* input_engine; }; -class InputFromAnalog final : public Input::InputDevice { +class InputFromAnalog final : public Common::Input::InputDevice { public: explicit InputFromAnalog(PadIdentifier identifier_, u32 axis_, - Input::AnalogProperties properties_, InputEngine* input_engine_) + Common::Input::AnalogProperties properties_, + InputEngine* input_engine_) : identifier(identifier_), axis(axis_), properties(properties_), input_engine(input_engine_) { UpdateCallback engine_callback{[this]() { OnChange(); }}; @@ -408,7 +411,7 @@ public: input_engine->DeleteCallback(callback_key); } - Input::AnalogStatus GetStatus() const { + Common::Input::AnalogStatus GetStatus() const { return { .raw_value = input_engine->GetAxis(identifier, axis), .properties = properties, @@ -416,8 +419,8 @@ public: } void OnChange() { - const Input::CallbackStatus status{ - .type = Input::InputType::Analog, + const Common::Input::CallbackStatus status{ + .type = Common::Input::InputType::Analog, .analog_status = GetStatus(), }; @@ -430,13 +433,13 @@ public: private: const PadIdentifier identifier; const u32 axis; - const Input::AnalogProperties properties; + const Common::Input::AnalogProperties properties; int callback_key; float last_axis_value; InputEngine* input_engine; }; -class InputFromBattery final : public Input::InputDevice { +class InputFromBattery final : public Common::Input::InputDevice { public: explicit InputFromBattery(PadIdentifier identifier_, InputEngine* input_engine_) : identifier(identifier_), input_engine(input_engine_) { @@ -447,7 +450,7 @@ public: .index = 0, .callback = engine_callback, }; - last_battery_value = Input::BatteryStatus::Charging; + last_battery_value = Common::Input::BatteryStatus::Charging; callback_key = input_engine->SetCallback(input_identifier); } @@ -455,13 +458,13 @@ public: input_engine->DeleteCallback(callback_key); } - Input::BatteryStatus GetStatus() const { - return static_cast(input_engine->GetBattery(identifier)); + Common::Input::BatteryStatus GetStatus() const { + return static_cast(input_engine->GetBattery(identifier)); } void ForceUpdate() { - const Input::CallbackStatus status{ - .type = Input::InputType::Battery, + const Common::Input::CallbackStatus status{ + .type = Common::Input::InputType::Battery, .battery_status = GetStatus(), }; @@ -470,8 +473,8 @@ public: } void OnChange() { - const Input::CallbackStatus status{ - .type = Input::InputType::Battery, + const Common::Input::CallbackStatus status{ + .type = Common::Input::InputType::Battery, .battery_status = GetStatus(), }; @@ -484,11 +487,11 @@ public: private: const PadIdentifier identifier; int callback_key; - Input::BatteryStatus last_battery_value; + Common::Input::BatteryStatus last_battery_value; InputEngine* input_engine; }; -class InputFromMotion final : public Input::InputDevice { +class InputFromMotion final : public Common::Input::InputDevice { public: explicit InputFromMotion(PadIdentifier identifier_, u32 motion_sensor_, InputEngine* input_engine_) @@ -507,10 +510,10 @@ public: input_engine->DeleteCallback(callback_key); } - Input::MotionStatus GetStatus() const { + Common::Input::MotionStatus GetStatus() const { const auto basic_motion = input_engine->GetMotion(identifier, motion_sensor); - Input::MotionStatus status{}; - const Input::AnalogProperties properties = { + Common::Input::MotionStatus status{}; + const Common::Input::AnalogProperties properties = { .deadzone = 0.001f, .range = 1.0f, .offset = 0.0f, @@ -526,8 +529,8 @@ public: } void OnChange() { - const Input::CallbackStatus status{ - .type = Input::InputType::Motion, + const Common::Input::CallbackStatus status{ + .type = Common::Input::InputType::Motion, .motion_status = GetStatus(), }; @@ -541,12 +544,13 @@ private: InputEngine* input_engine; }; -class InputFromAxisMotion final : public Input::InputDevice { +class InputFromAxisMotion final : public Common::Input::InputDevice { public: explicit InputFromAxisMotion(PadIdentifier identifier_, u32 axis_x_, u32 axis_y_, u32 axis_z_, - Input::AnalogProperties properties_x_, - Input::AnalogProperties properties_y_, - Input::AnalogProperties properties_z_, InputEngine* input_engine_) + Common::Input::AnalogProperties properties_x_, + Common::Input::AnalogProperties properties_y_, + Common::Input::AnalogProperties properties_z_, + InputEngine* input_engine_) : identifier(identifier_), axis_x(axis_x_), axis_y(axis_y_), axis_z(axis_z_), properties_x(properties_x_), properties_y(properties_y_), properties_z(properties_z_), input_engine(input_engine_) { @@ -583,8 +587,8 @@ public: input_engine->DeleteCallback(callback_key_z); } - Input::MotionStatus GetStatus() const { - Input::MotionStatus status{}; + Common::Input::MotionStatus GetStatus() const { + Common::Input::MotionStatus status{}; status.gyro.x = { .raw_value = input_engine->GetAxis(identifier, axis_x), .properties = properties_x, @@ -601,8 +605,8 @@ public: } void ForceUpdate() { - const Input::CallbackStatus status{ - .type = Input::InputType::Motion, + const Common::Input::CallbackStatus status{ + .type = Common::Input::InputType::Motion, .motion_status = GetStatus(), }; @@ -613,8 +617,8 @@ public: } void OnChange() { - const Input::CallbackStatus status{ - .type = Input::InputType::Motion, + const Common::Input::CallbackStatus status{ + .type = Common::Input::InputType::Motion, .motion_status = GetStatus(), }; @@ -633,9 +637,9 @@ private: const u32 axis_x; const u32 axis_y; const u32 axis_z; - const Input::AnalogProperties properties_x; - const Input::AnalogProperties properties_y; - const Input::AnalogProperties properties_z; + const Common::Input::AnalogProperties properties_x; + const Common::Input::AnalogProperties properties_y; + const Common::Input::AnalogProperties properties_z; int callback_key_x; int callback_key_y; int callback_key_z; @@ -645,20 +649,21 @@ private: InputEngine* input_engine; }; -class OutputFromIdentifier final : public Input::OutputDevice { +class OutputFromIdentifier final : public Common::Input::OutputDevice { public: explicit OutputFromIdentifier(PadIdentifier identifier_, InputEngine* input_engine_) : identifier(identifier_), input_engine(input_engine_) {} - virtual void SetLED(Input::LedStatus led_status) { + virtual void SetLED(Common::Input::LedStatus led_status) { input_engine->SetLeds(identifier, led_status); } - virtual Input::VibrationError SetVibration(Input::VibrationStatus vibration_status) { + virtual Common::Input::VibrationError SetVibration( + Common::Input::VibrationStatus vibration_status) { return input_engine->SetRumble(identifier, vibration_status); } - virtual Input::PollingError SetPollingMode(Input::PollingMode polling_mode) { + virtual Common::Input::PollingError SetPollingMode(Common::Input::PollingMode polling_mode) { return input_engine->SetPollingMode(identifier, polling_mode); } @@ -667,7 +672,7 @@ private: InputEngine* input_engine; }; -std::unique_ptr InputFactory::CreateButtonDevice( +std::unique_ptr InputFactory::CreateButtonDevice( const Common::ParamPackage& params) { const PadIdentifier identifier = { .guid = Common::UUID{params.Get("guid", "")}, @@ -690,7 +695,7 @@ std::unique_ptr InputFactory::CreateButtonDevice( input_engine.get()); } -std::unique_ptr InputFactory::CreateHatButtonDevice( +std::unique_ptr InputFactory::CreateHatButtonDevice( const Common::ParamPackage& params) { const PadIdentifier identifier = { .guid = Common::UUID{params.Get("guid", "")}, @@ -709,7 +714,7 @@ std::unique_ptr InputFactory::CreateHatButtonDevice( input_engine.get()); } -std::unique_ptr InputFactory::CreateStickDevice( +std::unique_ptr InputFactory::CreateStickDevice( const Common::ParamPackage& params) { const auto deadzone = std::clamp(params.Get("deadzone", 0.15f), 0.0f, 1.0f); const auto range = std::clamp(params.Get("range", 1.0f), 0.25f, 1.50f); @@ -721,7 +726,7 @@ std::unique_ptr InputFactory::CreateStickDevice( }; const auto axis_x = static_cast(params.Get("axis_x", 0)); - const Input::AnalogProperties properties_x = { + const Common::Input::AnalogProperties properties_x = { .deadzone = deadzone, .range = range, .threshold = threshold, @@ -730,7 +735,7 @@ std::unique_ptr InputFactory::CreateStickDevice( }; const auto axis_y = static_cast(params.Get("axis_y", 1)); - const Input::AnalogProperties properties_y = { + const Common::Input::AnalogProperties properties_y = { .deadzone = deadzone, .range = range, .threshold = threshold, @@ -744,7 +749,7 @@ std::unique_ptr InputFactory::CreateStickDevice( input_engine.get()); } -std::unique_ptr InputFactory::CreateAnalogDevice( +std::unique_ptr InputFactory::CreateAnalogDevice( const Common::ParamPackage& params) { const PadIdentifier identifier = { .guid = Common::UUID{params.Get("guid", "")}, @@ -753,7 +758,7 @@ std::unique_ptr InputFactory::CreateAnalogDevice( }; const auto axis = static_cast(params.Get("axis", 0)); - const Input::AnalogProperties properties = { + const Common::Input::AnalogProperties properties = { .deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, 1.0f), .range = std::clamp(params.Get("range", 1.0f), 0.25f, 1.50f), .threshold = std::clamp(params.Get("threshold", 0.5f), 0.0f, 1.0f), @@ -765,7 +770,7 @@ std::unique_ptr InputFactory::CreateAnalogDevice( return std::make_unique(identifier, axis, properties, input_engine.get()); } -std::unique_ptr InputFactory::CreateTriggerDevice( +std::unique_ptr InputFactory::CreateTriggerDevice( const Common::ParamPackage& params) { const PadIdentifier identifier = { .guid = Common::UUID{params.Get("guid", "")}, @@ -778,7 +783,7 @@ std::unique_ptr InputFactory::CreateTriggerDevice( const auto inverted = params.Get("inverted", false); const auto axis = static_cast(params.Get("axis", 0)); - const Input::AnalogProperties properties = { + const Common::Input::AnalogProperties properties = { .deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, 1.0f), .range = std::clamp(params.Get("range", 1.0f), 0.25f, 2.50f), .threshold = std::clamp(params.Get("threshold", 0.5f), 0.0f, 1.0f), @@ -792,7 +797,7 @@ std::unique_ptr InputFactory::CreateTriggerDevice( properties, input_engine.get()); } -std::unique_ptr InputFactory::CreateTouchDevice( +std::unique_ptr InputFactory::CreateTouchDevice( const Common::ParamPackage& params) { const auto touch_id = params.Get("touch_id", 0); const auto deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, 1.0f); @@ -809,7 +814,7 @@ std::unique_ptr InputFactory::CreateTouchDevice( const auto inverted = params.Get("inverted", false); const auto axis_x = static_cast(params.Get("axis_x", 0)); - const Input::AnalogProperties properties_x = { + const Common::Input::AnalogProperties properties_x = { .deadzone = deadzone, .range = range, .threshold = threshold, @@ -818,7 +823,7 @@ std::unique_ptr InputFactory::CreateTouchDevice( }; const auto axis_y = static_cast(params.Get("axis_y", 1)); - const Input::AnalogProperties properties_y = { + const Common::Input::AnalogProperties properties_y = { .deadzone = deadzone, .range = range, .threshold = threshold, @@ -833,7 +838,7 @@ std::unique_ptr InputFactory::CreateTouchDevice( axis_y, properties_x, properties_y, input_engine.get()); } -std::unique_ptr InputFactory::CreateBatteryDevice( +std::unique_ptr InputFactory::CreateBatteryDevice( const Common::ParamPackage& params) { const PadIdentifier identifier = { .guid = Common::UUID{params.Get("guid", "")}, @@ -845,7 +850,8 @@ std::unique_ptr InputFactory::CreateBatteryDevice( return std::make_unique(identifier, input_engine.get()); } -std::unique_ptr InputFactory::CreateMotionDevice(Common::ParamPackage params) { +std::unique_ptr InputFactory::CreateMotionDevice( + Common::ParamPackage params) { const PadIdentifier identifier = { .guid = Common::UUID{params.Get("guid", "")}, .port = static_cast(params.Get("port", 0)), @@ -864,7 +870,7 @@ std::unique_ptr InputFactory::CreateMotionDevice(Common::Par const auto threshold = std::clamp(params.Get("threshold", 0.5f), 0.0f, 1.0f); const auto axis_x = static_cast(params.Get("axis_x", 0)); - const Input::AnalogProperties properties_x = { + const Common::Input::AnalogProperties properties_x = { .deadzone = deadzone, .range = range, .threshold = threshold, @@ -873,7 +879,7 @@ std::unique_ptr InputFactory::CreateMotionDevice(Common::Par }; const auto axis_y = static_cast(params.Get("axis_y", 1)); - const Input::AnalogProperties properties_y = { + const Common::Input::AnalogProperties properties_y = { .deadzone = deadzone, .range = range, .threshold = threshold, @@ -882,7 +888,7 @@ std::unique_ptr InputFactory::CreateMotionDevice(Common::Par }; const auto axis_z = static_cast(params.Get("axis_z", 1)); - const Input::AnalogProperties properties_z = { + const Common::Input::AnalogProperties properties_z = { .deadzone = deadzone, .range = range, .threshold = threshold, @@ -900,7 +906,8 @@ std::unique_ptr InputFactory::CreateMotionDevice(Common::Par InputFactory::InputFactory(std::shared_ptr input_engine_) : input_engine(std::move(input_engine_)) {} -std::unique_ptr InputFactory::Create(const Common::ParamPackage& params) { +std::unique_ptr InputFactory::Create( + const Common::ParamPackage& params) { if (params.Has("battery")) { return CreateBatteryDevice(params); } @@ -935,7 +942,8 @@ std::unique_ptr InputFactory::Create(const Common::ParamPack OutputFactory::OutputFactory(std::shared_ptr input_engine_) : input_engine(std::move(input_engine_)) {} -std::unique_ptr OutputFactory::Create(const Common::ParamPackage& params) { +std::unique_ptr OutputFactory::Create( + const Common::ParamPackage& params) { const PadIdentifier identifier = { .guid = Common::UUID{params.Get("guid", "")}, .port = static_cast(params.Get("port", 0)), diff --git a/src/input_common/input_poller.h b/src/input_common/input_poller.h index 1357e104b..573f09fde 100644 --- a/src/input_common/input_poller.h +++ b/src/input_common/input_poller.h @@ -17,7 +17,7 @@ class InputEngine; * An Input factory. It receives input events and forward them to all input devices it created. */ -class OutputFactory final : public Input::Factory { +class OutputFactory final : public Common::Input::Factory { public: explicit OutputFactory(std::shared_ptr input_engine_); @@ -29,13 +29,14 @@ public: * @param - "pad": slot of the connected controller * @return an unique ouput device with the parameters specified */ - std::unique_ptr Create(const Common::ParamPackage& params) override; + std::unique_ptr Create( + const Common::ParamPackage& params) override; private: std::shared_ptr input_engine; }; -class InputFactory final : public Input::Factory { +class InputFactory final : public Common::Input::Factory { public: explicit InputFactory(std::shared_ptr input_engine_); @@ -64,7 +65,7 @@ public: * @param - "battery": Only used as a placeholder to set the input type * @return an unique input device with the parameters specified */ - std::unique_ptr Create(const Common::ParamPackage& params) override; + std::unique_ptr Create(const Common::ParamPackage& params) override; private: /** @@ -79,7 +80,8 @@ private: * @param - "pad": slot of the connected controller * @return an unique input device with the parameters specified */ - std::unique_ptr CreateButtonDevice(const Common::ParamPackage& params); + std::unique_ptr CreateButtonDevice( + const Common::ParamPackage& params); /** * Creates a hat button device from the parameters given. @@ -93,7 +95,8 @@ private: * @param - "pad": slot of the connected controller * @return an unique input device with the parameters specified */ - std::unique_ptr CreateHatButtonDevice(const Common::ParamPackage& params); + std::unique_ptr CreateHatButtonDevice( + const Common::ParamPackage& params); /** * Creates a stick device from the parameters given. @@ -112,7 +115,8 @@ private: * @param - "pad": slot of the connected controller * @return an unique input device with the parameters specified */ - std::unique_ptr CreateStickDevice(const Common::ParamPackage& params); + std::unique_ptr CreateStickDevice( + const Common::ParamPackage& params); /** * Creates an analog device from the parameters given. @@ -128,7 +132,8 @@ private: * @param - "pad": slot of the connected controller * @return an unique input device with the parameters specified */ - std::unique_ptr CreateAnalogDevice(const Common::ParamPackage& params); + std::unique_ptr CreateAnalogDevice( + const Common::ParamPackage& params); /** * Creates a trigger device from the parameters given. @@ -148,7 +153,8 @@ private: * @param - "pad": slot of the connected controller * @return an unique input device with the parameters specified */ - std::unique_ptr CreateTriggerDevice(const Common::ParamPackage& params); + std::unique_ptr CreateTriggerDevice( + const Common::ParamPackage& params); /** * Creates a touch device from the parameters given. @@ -171,7 +177,8 @@ private: * @param - "pad": slot of the connected controller * @return an unique input device with the parameters specified */ - std::unique_ptr CreateTouchDevice(const Common::ParamPackage& params); + std::unique_ptr CreateTouchDevice( + const Common::ParamPackage& params); /** * Creates a battery device from the parameters given. @@ -181,7 +188,8 @@ private: * @param - "pad": slot of the connected controller * @return an unique input device with the parameters specified */ - std::unique_ptr CreateBatteryDevice(const Common::ParamPackage& params); + std::unique_ptr CreateBatteryDevice( + const Common::ParamPackage& params); /** * Creates a motion device from the parameters given. @@ -202,7 +210,7 @@ private: * @param - "pad": slot of the connected controller * @return an unique input device with the parameters specified */ - std::unique_ptr CreateMotionDevice(Common::ParamPackage params); + std::unique_ptr CreateMotionDevice(Common::ParamPackage params); std::shared_ptr input_engine; }; diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp index 07d514ad7..df36a337c 100644 --- a/src/input_common/main.cpp +++ b/src/input_common/main.cpp @@ -33,89 +33,97 @@ struct InputSubsystem::Impl { keyboard->SetMappingCallback(mapping_callback); keyboard_factory = std::make_shared(keyboard); keyboard_output_factory = std::make_shared(keyboard); - Input::RegisterFactory(keyboard->GetEngineName(), keyboard_factory); - Input::RegisterFactory(keyboard->GetEngineName(), - keyboard_output_factory); + 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); - Input::RegisterFactory(mouse->GetEngineName(), mouse_factory); - Input::RegisterFactory(mouse->GetEngineName(), mouse_output_factory); + 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); - Input::RegisterFactory(touch_screen->GetEngineName(), - touch_screen_factory); + 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); - Input::RegisterFactory(gcadapter->GetEngineName(), - gcadapter_input_factory); - Input::RegisterFactory(gcadapter->GetEngineName(), - gcadapter_output_factory); + 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); - Input::RegisterFactory(udp_client->GetEngineName(), udp_client_factory); + 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); - Input::RegisterFactory(tas_input->GetEngineName(), tas_input_factory); - Input::RegisterFactory(tas_input->GetEngineName(), tas_output_factory); + Common::Input::RegisterFactory(tas_input->GetEngineName(), + tas_input_factory); + Common::Input::RegisterFactory(tas_input->GetEngineName(), + tas_output_factory); #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); - Input::RegisterFactory(sdl->GetEngineName(), sdl_input_factory); - Input::RegisterFactory(sdl->GetEngineName(), sdl_output_factory); + Common::Input::RegisterFactory(sdl->GetEngineName(), + sdl_input_factory); + Common::Input::RegisterFactory(sdl->GetEngineName(), + sdl_output_factory); #endif - Input::RegisterFactory("touch_from_button", - std::make_shared()); - Input::RegisterFactory("analog_from_button", - std::make_shared()); + Common::Input::RegisterFactory( + "touch_from_button", std::make_shared()); + Common::Input::RegisterFactory( + "analog_from_button", std::make_shared()); } void Shutdown() { - Input::UnregisterFactory(keyboard->GetEngineName()); - Input::UnregisterFactory(keyboard->GetEngineName()); + Common::Input::UnregisterFactory(keyboard->GetEngineName()); + Common::Input::UnregisterFactory(keyboard->GetEngineName()); keyboard.reset(); - Input::UnregisterFactory(mouse->GetEngineName()); - Input::UnregisterFactory(mouse->GetEngineName()); + Common::Input::UnregisterFactory(mouse->GetEngineName()); + Common::Input::UnregisterFactory(mouse->GetEngineName()); mouse.reset(); - Input::UnregisterFactory(touch_screen->GetEngineName()); + Common::Input::UnregisterFactory(touch_screen->GetEngineName()); touch_screen.reset(); - Input::UnregisterFactory(gcadapter->GetEngineName()); - Input::UnregisterFactory(gcadapter->GetEngineName()); + Common::Input::UnregisterFactory(gcadapter->GetEngineName()); + Common::Input::UnregisterFactory(gcadapter->GetEngineName()); gcadapter.reset(); - Input::UnregisterFactory(udp_client->GetEngineName()); + Common::Input::UnregisterFactory(udp_client->GetEngineName()); udp_client.reset(); - Input::UnregisterFactory(tas_input->GetEngineName()); - Input::UnregisterFactory(tas_input->GetEngineName()); + Common::Input::UnregisterFactory(tas_input->GetEngineName()); + Common::Input::UnregisterFactory(tas_input->GetEngineName()); tas_input.reset(); #ifdef HAVE_SDL2 - Input::UnregisterFactory(sdl->GetEngineName()); - Input::UnregisterFactory(sdl->GetEngineName()); + Common::Input::UnregisterFactory(sdl->GetEngineName()); + Common::Input::UnregisterFactory(sdl->GetEngineName()); sdl.reset(); #endif - Input::UnregisterFactory("touch_from_button"); - Input::UnregisterFactory("analog_from_button"); + Common::Input::UnregisterFactory("touch_from_button"); + Common::Input::UnregisterFactory("analog_from_button"); } [[nodiscard]] std::vector GetInputDevices() const { diff --git a/src/yuzu/configuration/configure_input_player_widget.cpp b/src/yuzu/configuration/configure_input_player_widget.cpp index 67e56ed3a..bb20e9339 100644 --- a/src/yuzu/configuration/configure_input_player_widget.cpp +++ b/src/yuzu/configuration/configure_input_player_widget.cpp @@ -1945,8 +1945,8 @@ void PlayerControlPreview::DrawRightBody(QPainter& p, const QPointF center) { } void PlayerControlPreview::DrawProTriggers(QPainter& p, const QPointF center, - const Input::ButtonStatus& left_pressed, - const Input::ButtonStatus& right_pressed) { + const Common::Input::ButtonStatus& left_pressed, + const Common::Input::ButtonStatus& right_pressed) { std::array qleft_trigger; std::array qright_trigger; std::array qbody_top; @@ -1984,8 +1984,8 @@ void PlayerControlPreview::DrawProTriggers(QPainter& p, const QPointF center, } void PlayerControlPreview::DrawGCTriggers(QPainter& p, const QPointF center, - Input::TriggerStatus left_trigger, - Input::TriggerStatus right_trigger) { + Common::Input::TriggerStatus left_trigger, + Common::Input::TriggerStatus right_trigger) { std::array qleft_trigger; std::array qright_trigger; @@ -2022,8 +2022,8 @@ void PlayerControlPreview::DrawGCTriggers(QPainter& p, const QPointF center, } void PlayerControlPreview::DrawHandheldTriggers(QPainter& p, const QPointF center, - const Input::ButtonStatus& left_pressed, - const Input::ButtonStatus& right_pressed) { + const Common::Input::ButtonStatus& left_pressed, + const Common::Input::ButtonStatus& right_pressed) { std::array qleft_trigger; std::array qright_trigger; @@ -2048,8 +2048,8 @@ void PlayerControlPreview::DrawHandheldTriggers(QPainter& p, const QPointF cente } void PlayerControlPreview::DrawDualTriggers(QPainter& p, const QPointF center, - const Input::ButtonStatus& left_pressed, - const Input::ButtonStatus& right_pressed) { + const Common::Input::ButtonStatus& left_pressed, + const Common::Input::ButtonStatus& right_pressed) { std::array qleft_trigger; std::array qright_trigger; constexpr float size = 1.62f; @@ -2076,9 +2076,9 @@ void PlayerControlPreview::DrawDualTriggers(QPainter& p, const QPointF center, DrawPolygon(p, qright_trigger); } -void PlayerControlPreview::DrawDualTriggersTopView(QPainter& p, const QPointF center, - const Input::ButtonStatus& left_pressed, - const Input::ButtonStatus& right_pressed) { +void PlayerControlPreview::DrawDualTriggersTopView( + QPainter& p, const QPointF center, const Common::Input::ButtonStatus& left_pressed, + const Common::Input::ButtonStatus& right_pressed) { std::array qleft_trigger; std::array qright_trigger; constexpr float size = 0.9f; @@ -2113,9 +2113,9 @@ void PlayerControlPreview::DrawDualTriggersTopView(QPainter& p, const QPointF ce DrawSymbol(p, center + QPointF(177, -84), Symbol::R, 1.0f); } -void PlayerControlPreview::DrawDualZTriggersTopView(QPainter& p, const QPointF center, - const Input::ButtonStatus& left_pressed, - const Input::ButtonStatus& right_pressed) { +void PlayerControlPreview::DrawDualZTriggersTopView( + QPainter& p, const QPointF center, const Common::Input::ButtonStatus& left_pressed, + const Common::Input::ButtonStatus& right_pressed) { std::array qleft_trigger; std::array qright_trigger; constexpr float size = 0.9f; @@ -2149,7 +2149,7 @@ void PlayerControlPreview::DrawDualZTriggersTopView(QPainter& p, const QPointF c } void PlayerControlPreview::DrawLeftTriggers(QPainter& p, const QPointF center, - const Input::ButtonStatus& left_pressed) { + const Common::Input::ButtonStatus& left_pressed) { std::array qleft_trigger; constexpr float size = 1.78f; constexpr float offset = 311.5f; @@ -2166,7 +2166,7 @@ void PlayerControlPreview::DrawLeftTriggers(QPainter& p, const QPointF center, } void PlayerControlPreview::DrawLeftZTriggers(QPainter& p, const QPointF center, - const Input::ButtonStatus& left_pressed) { + const Common::Input::ButtonStatus& left_pressed) { std::array qleft_trigger; constexpr float size = 1.1115f; constexpr float offset2 = 335; @@ -2184,8 +2184,8 @@ void PlayerControlPreview::DrawLeftZTriggers(QPainter& p, const QPointF center, 225 * 16, 44 * 16); } -void PlayerControlPreview::DrawLeftTriggersTopView(QPainter& p, const QPointF center, - const Input::ButtonStatus& left_pressed) { +void PlayerControlPreview::DrawLeftTriggersTopView( + QPainter& p, const QPointF center, const Common::Input::ButtonStatus& left_pressed) { std::array qleft_trigger; for (std::size_t point = 0; point < left_joystick_L_topview.size() / 2; ++point) { @@ -2203,8 +2203,8 @@ void PlayerControlPreview::DrawLeftTriggersTopView(QPainter& p, const QPointF ce DrawSymbol(p, center + QPointF(-143, -36), Symbol::L, 1.0f); } -void PlayerControlPreview::DrawLeftZTriggersTopView(QPainter& p, const QPointF center, - const Input::ButtonStatus& left_pressed) { +void PlayerControlPreview::DrawLeftZTriggersTopView( + QPainter& p, const QPointF center, const Common::Input::ButtonStatus& left_pressed) { std::array qleft_trigger; for (std::size_t point = 0; point < left_joystick_ZL_topview.size() / 2; ++point) { @@ -2223,7 +2223,7 @@ void PlayerControlPreview::DrawLeftZTriggersTopView(QPainter& p, const QPointF c } void PlayerControlPreview::DrawRightTriggers(QPainter& p, const QPointF center, - const Input::ButtonStatus& right_pressed) { + const Common::Input::ButtonStatus& right_pressed) { std::array qright_trigger; constexpr float size = 1.78f; constexpr float offset = 311.5f; @@ -2240,7 +2240,7 @@ void PlayerControlPreview::DrawRightTriggers(QPainter& p, const QPointF center, } void PlayerControlPreview::DrawRightZTriggers(QPainter& p, const QPointF center, - const Input::ButtonStatus& right_pressed) { + const Common::Input::ButtonStatus& right_pressed) { std::array qright_trigger; constexpr float size = 1.1115f; constexpr float offset2 = 335; @@ -2259,8 +2259,8 @@ void PlayerControlPreview::DrawRightZTriggers(QPainter& p, const QPointF center, 271 * 16, 44 * 16); } -void PlayerControlPreview::DrawRightTriggersTopView(QPainter& p, const QPointF center, - const Input::ButtonStatus& right_pressed) { +void PlayerControlPreview::DrawRightTriggersTopView( + QPainter& p, const QPointF center, const Common::Input::ButtonStatus& right_pressed) { std::array qright_trigger; for (std::size_t point = 0; point < left_joystick_L_topview.size() / 2; ++point) { @@ -2278,8 +2278,8 @@ void PlayerControlPreview::DrawRightTriggersTopView(QPainter& p, const QPointF c DrawSymbol(p, center + QPointF(137, -36), Symbol::R, 1.0f); } -void PlayerControlPreview::DrawRightZTriggersTopView(QPainter& p, const QPointF center, - const Input::ButtonStatus& right_pressed) { +void PlayerControlPreview::DrawRightZTriggersTopView( + QPainter& p, const QPointF center, const Common::Input::ButtonStatus& right_pressed) { std::array qright_trigger; for (std::size_t point = 0; point < left_joystick_ZL_topview.size() / 2; ++point) { @@ -2298,7 +2298,7 @@ void PlayerControlPreview::DrawRightZTriggersTopView(QPainter& p, const QPointF } void PlayerControlPreview::DrawJoystick(QPainter& p, const QPointF center, float size, - const Input::ButtonStatus& pressed) { + const Common::Input::ButtonStatus& pressed) { const float radius1 = 13.0f * size; const float radius2 = 9.0f * size; @@ -2317,7 +2317,8 @@ void PlayerControlPreview::DrawJoystick(QPainter& p, const QPointF center, float } void PlayerControlPreview::DrawJoystickSideview(QPainter& p, const QPointF center, float angle, - float size, const Input::ButtonStatus& pressed) { + float size, + const Common::Input::ButtonStatus& pressed) { QVector joystick; joystick.reserve(static_cast(left_joystick_sideview.size() / 2)); @@ -2342,7 +2343,7 @@ void PlayerControlPreview::DrawJoystickSideview(QPainter& p, const QPointF cente void PlayerControlPreview::DrawProJoystick(QPainter& p, const QPointF center, const QPointF offset, float offset_scalar, - const Input::ButtonStatus& pressed) { + const Common::Input::ButtonStatus& pressed) { const float radius1 = 24.0f; const float radius2 = 17.0f; @@ -2377,7 +2378,7 @@ void PlayerControlPreview::DrawProJoystick(QPainter& p, const QPointF center, co } void PlayerControlPreview::DrawGCJoystick(QPainter& p, const QPointF center, - const Input::ButtonStatus& pressed) { + const Common::Input::ButtonStatus& pressed) { // Outer circle p.setPen(colors.outline); p.setBrush(pressed.value ? colors.highlight : colors.button); @@ -2414,8 +2415,8 @@ void PlayerControlPreview::DrawRawJoystick(QPainter& p, QPointF center_left, QPo } } -void PlayerControlPreview::DrawJoystickProperties(QPainter& p, const QPointF center, - const Input::AnalogProperties& properties) { +void PlayerControlPreview::DrawJoystickProperties( + QPainter& p, const QPointF center, const Common::Input::AnalogProperties& properties) { constexpr float size = 45.0f; const float range = size * properties.range; const float deadzone = size * properties.deadzone; @@ -2435,7 +2436,7 @@ void PlayerControlPreview::DrawJoystickProperties(QPainter& p, const QPointF cen } void PlayerControlPreview::DrawJoystickDot(QPainter& p, const QPointF center, - const Input::StickStatus& stick, bool raw) { + const Common::Input::StickStatus& stick, bool raw) { constexpr float size = 45.0f; const float range = size * stick.x.properties.range; @@ -2450,7 +2451,7 @@ void PlayerControlPreview::DrawJoystickDot(QPainter& p, const QPointF center, } void PlayerControlPreview::DrawRoundButton(QPainter& p, QPointF center, - const Input::ButtonStatus& pressed, float width, + const Common::Input::ButtonStatus& pressed, float width, float height, Direction direction, float radius) { p.setBrush(button_color); if (pressed.value) { @@ -2476,13 +2477,15 @@ void PlayerControlPreview::DrawRoundButton(QPainter& p, QPointF center, p.drawRoundedRect(rect, radius, radius); } void PlayerControlPreview::DrawMinusButton(QPainter& p, const QPointF center, - const Input::ButtonStatus& pressed, int button_size) { + const Common::Input::ButtonStatus& pressed, + int button_size) { p.setPen(colors.outline); p.setBrush(pressed.value ? colors.highlight : colors.button); DrawRectangle(p, center, button_size, button_size / 3.0f); } void PlayerControlPreview::DrawPlusButton(QPainter& p, const QPointF center, - const Input::ButtonStatus& pressed, int button_size) { + const Common::Input::ButtonStatus& pressed, + int button_size) { // Draw outer line p.setPen(colors.outline); p.setBrush(pressed.value ? colors.highlight : colors.button); @@ -2499,7 +2502,7 @@ void PlayerControlPreview::DrawPlusButton(QPainter& p, const QPointF center, } void PlayerControlPreview::DrawGCButtonX(QPainter& p, const QPointF center, - const Input::ButtonStatus& pressed) { + const Common::Input::ButtonStatus& pressed) { std::array button_x; for (std::size_t point = 0; point < gc_button_x.size() / 2; ++point) { @@ -2512,7 +2515,7 @@ void PlayerControlPreview::DrawGCButtonX(QPainter& p, const QPointF center, } void PlayerControlPreview::DrawGCButtonY(QPainter& p, const QPointF center, - const Input::ButtonStatus& pressed) { + const Common::Input::ButtonStatus& pressed) { std::array button_x; for (std::size_t point = 0; point < gc_button_y.size() / 2; ++point) { @@ -2525,7 +2528,7 @@ void PlayerControlPreview::DrawGCButtonY(QPainter& p, const QPointF center, } void PlayerControlPreview::DrawGCButtonZ(QPainter& p, const QPointF center, - const Input::ButtonStatus& pressed) { + const Common::Input::ButtonStatus& pressed) { std::array button_x; for (std::size_t point = 0; point < gc_button_z.size() / 2; ++point) { @@ -2539,7 +2542,8 @@ void PlayerControlPreview::DrawGCButtonZ(QPainter& p, const QPointF center, } void PlayerControlPreview::DrawCircleButton(QPainter& p, const QPointF center, - const Input::ButtonStatus& pressed, float button_size) { + const Common::Input::ButtonStatus& pressed, + float button_size) { p.setBrush(button_color); if (pressed.value) { p.setBrush(colors.highlight); @@ -2571,7 +2575,7 @@ void PlayerControlPreview::DrawArrowButtonOutline(QPainter& p, const QPointF cen void PlayerControlPreview::DrawArrowButton(QPainter& p, const QPointF center, const Direction direction, - const Input::ButtonStatus& pressed, float size) { + const Common::Input::ButtonStatus& pressed, float size) { std::array arrow_button; QPoint offset; @@ -2628,7 +2632,7 @@ void PlayerControlPreview::DrawArrowButton(QPainter& p, const QPointF center, void PlayerControlPreview::DrawTriggerButton(QPainter& p, const QPointF center, const Direction direction, - const Input::ButtonStatus& pressed) { + const Common::Input::ButtonStatus& pressed) { std::array qtrigger_button; for (std::size_t point = 0; point < trigger_button.size() / 2; ++point) { @@ -2655,8 +2659,9 @@ void PlayerControlPreview::DrawTriggerButton(QPainter& p, const QPointF center, DrawPolygon(p, qtrigger_button); } -void PlayerControlPreview::DrawBattery(QPainter& p, QPointF center, Input::BatteryLevel battery) { - if (battery == Input::BatteryLevel::None) { +void PlayerControlPreview::DrawBattery(QPainter& p, QPointF center, + Common::Input::BatteryLevel battery) { + if (battery == Common::Input::BatteryLevel::None) { return; } p.setPen(colors.outline); @@ -2665,29 +2670,29 @@ void PlayerControlPreview::DrawBattery(QPainter& p, QPointF center, Input::Batte p.drawRect(center.x() + 56, center.y() + 6, 3, 8); p.setBrush(colors.deadzone); switch (battery) { - case Input::BatteryLevel::Charging: + case Common::Input::BatteryLevel::Charging: p.setBrush(colors.indicator2); p.drawText(center + QPoint(2, 14), tr("Charging")); break; - case Input::BatteryLevel::Full: + 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 Input::BatteryLevel::Medium: + 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 Input::BatteryLevel::Low: + case Common::Input::BatteryLevel::Low: p.drawRect(center.x() + 14, center.y(), 14, 20); p.drawRect(center.x(), center.y(), 14, 20); break; - case Input::BatteryLevel::Critical: + case Common::Input::BatteryLevel::Critical: p.drawRect(center.x(), center.y(), 14, 20); break; - case Input::BatteryLevel::Empty: + case Common::Input::BatteryLevel::Empty: p.drawRect(center.x(), center.y(), 5, 20); break; default: diff --git a/src/yuzu/configuration/configure_input_player_widget.h b/src/yuzu/configuration/configure_input_player_widget.h index 333c3fc56..430e4f4f4 100644 --- a/src/yuzu/configuration/configure_input_player_widget.h +++ b/src/yuzu/configuration/configure_input_player_widget.h @@ -115,66 +115,75 @@ private: void DrawGCBody(QPainter& p, QPointF center); // Draw triggers functions - void DrawProTriggers(QPainter& p, QPointF center, const Input::ButtonStatus& left_pressed, - const Input::ButtonStatus& right_pressed); - void DrawGCTriggers(QPainter& p, QPointF center, Input::TriggerStatus left_trigger, - Input::TriggerStatus right_trigger); - void DrawHandheldTriggers(QPainter& p, QPointF center, const Input::ButtonStatus& left_pressed, - const Input::ButtonStatus& right_pressed); - void DrawDualTriggers(QPainter& p, QPointF center, const Input::ButtonStatus& left_pressed, - const Input::ButtonStatus& right_pressed); + 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 Input::ButtonStatus& left_pressed, - const Input::ButtonStatus& right_pressed); + const Common::Input::ButtonStatus& left_pressed, + const Common::Input::ButtonStatus& right_pressed); void DrawDualZTriggersTopView(QPainter& p, QPointF center, - const Input::ButtonStatus& left_pressed, - const Input::ButtonStatus& right_pressed); - void DrawLeftTriggers(QPainter& p, QPointF center, const Input::ButtonStatus& left_pressed); - void DrawLeftZTriggers(QPainter& p, QPointF center, const Input::ButtonStatus& left_pressed); + 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 Input::ButtonStatus& left_pressed); + const Common::Input::ButtonStatus& left_pressed); void DrawLeftZTriggersTopView(QPainter& p, QPointF center, - const Input::ButtonStatus& left_pressed); - void DrawRightTriggers(QPainter& p, QPointF center, const Input::ButtonStatus& right_pressed); - void DrawRightZTriggers(QPainter& p, QPointF center, const Input::ButtonStatus& right_pressed); + 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 Input::ButtonStatus& right_pressed); + const Common::Input::ButtonStatus& right_pressed); void DrawRightZTriggersTopView(QPainter& p, QPointF center, - const Input::ButtonStatus& right_pressed); + const Common::Input::ButtonStatus& right_pressed); // Draw joystick functions - void DrawJoystick(QPainter& p, QPointF center, float size, const Input::ButtonStatus& pressed); + void DrawJoystick(QPainter& p, QPointF center, float size, + const Common::Input::ButtonStatus& pressed); void DrawJoystickSideview(QPainter& p, QPointF center, float angle, float size, - const Input::ButtonStatus& pressed); + const Common::Input::ButtonStatus& pressed); void DrawRawJoystick(QPainter& p, QPointF center_left, QPointF center_right); void DrawJoystickProperties(QPainter& p, QPointF center, - const Input::AnalogProperties& properties); - void DrawJoystickDot(QPainter& p, QPointF center, const Input::StickStatus& stick, bool raw); + 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 Input::ButtonStatus& pressed); - void DrawGCJoystick(QPainter& p, QPointF center, const Input::ButtonStatus& pressed); + const Common::Input::ButtonStatus& pressed); + void DrawGCJoystick(QPainter& p, QPointF center, const Common::Input::ButtonStatus& pressed); // Draw button functions - void DrawCircleButton(QPainter& p, QPointF center, const Input::ButtonStatus& pressed, + void DrawCircleButton(QPainter& p, QPointF center, const Common::Input::ButtonStatus& pressed, float button_size); - void DrawRoundButton(QPainter& p, QPointF center, const Input::ButtonStatus& pressed, + 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 Input::ButtonStatus& pressed, + void DrawMinusButton(QPainter& p, QPointF center, const Common::Input::ButtonStatus& pressed, int button_size); - void DrawPlusButton(QPainter& p, QPointF center, const Input::ButtonStatus& pressed, + void DrawPlusButton(QPainter& p, QPointF center, const Common::Input::ButtonStatus& pressed, int button_size); - void DrawGCButtonX(QPainter& p, QPointF center, const Input::ButtonStatus& pressed); - void DrawGCButtonY(QPainter& p, QPointF center, const Input::ButtonStatus& pressed); - void DrawGCButtonZ(QPainter& p, QPointF center, const Input::ButtonStatus& pressed); + 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 DrawArrowButtonOutline(QPainter& p, const QPointF center, float size = 1.0f); void DrawArrowButton(QPainter& p, QPointF center, Direction direction, - const Input::ButtonStatus& pressed, float size = 1.0f); + const Common::Input::ButtonStatus& pressed, float size = 1.0f); void DrawTriggerButton(QPainter& p, QPointF center, Direction direction, - const Input::ButtonStatus& pressed); + const Common::Input::ButtonStatus& pressed); // Draw battery functions - void DrawBattery(QPainter& p, QPointF center, Input::BatteryLevel battery); + void DrawBattery(QPainter& p, QPointF center, Common::Input::BatteryLevel battery); // Draw icon functions void DrawSymbol(QPainter& p, QPointF center, Symbol symbol, float icon_size); -- cgit v1.2.3 From 730f07830247cfcdc551c253d30c6717fc16316c Mon Sep 17 00:00:00 2001 From: german77 Date: Sun, 31 Oct 2021 10:41:44 -0500 Subject: settings: Fix Debug controller type options --- src/common/input.h | 4 +- src/core/hid/emulated_console.cpp | 3 +- src/core/hid/emulated_controller.cpp | 11 ++- src/core/hid/input_converter.cpp | 4 +- src/input_common/drivers/tas_input.h | 1 - src/input_common/helpers/touch_from_buttons.cpp | 4 +- src/input_common/input_engine.cpp | 2 +- src/input_common/input_engine.h | 5 +- src/input_common/input_poller.cpp | 89 ++++++++++++---------- src/yuzu/applets/qt_controller.cpp | 2 - src/yuzu/configuration/configure_input_player.cpp | 2 - src/yuzu/configuration/configure_input_player.ui | 25 ------ .../configure_input_player_widget.cpp | 20 ++--- 13 files changed, 77 insertions(+), 95 deletions(-) (limited to 'src/input_common/drivers') diff --git a/src/common/input.h b/src/common/input.h index 6d3227f5e..16b1e6f1b 100644 --- a/src/common/input.h +++ b/src/common/input.h @@ -100,7 +100,7 @@ struct StickStatus { struct TriggerStatus { AnalogStatus analog{}; - bool pressed{}; + ButtonStatus pressed{}; }; struct MotionSensor { @@ -119,7 +119,7 @@ struct TouchStatus { ButtonStatus pressed{}; AnalogStatus x{}; AnalogStatus y{}; - u32 id{}; + int id{}; }; struct BodyColorStatus { diff --git a/src/core/hid/emulated_console.cpp b/src/core/hid/emulated_console.cpp index c259de0f1..012909954 100644 --- a/src/core/hid/emulated_console.cpp +++ b/src/core/hid/emulated_console.cpp @@ -166,9 +166,10 @@ void EmulatedConsole::SetTouch(Common::Input::CallbackStatus callback, return; } + // TODO(german77): Remap touch id in sequential order console.touch_state[index] = { .position = {console.touch_values[index].x.value, console.touch_values[index].y.value}, - .id = console.touch_values[index].id, + .id = static_cast(console.touch_values[index].id), .pressed = console.touch_values[index].pressed.value, }; diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index 49893cdbd..9a1864279 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -77,7 +77,12 @@ void EmulatedController::ReloadFromSettings() { controller.colors_state.fullkey = controller.colors_state.left; - SetNpadType(MapSettingsTypeToNPad(player.controller_type)); + // Other or debug controller should always be a pro controller + if (npad_id_type != NpadIdType::Other) { + SetNpadType(MapSettingsTypeToNPad(player.controller_type)); + } else { + SetNpadType(NpadType::ProController); + } if (player.connected) { Connect(); @@ -606,12 +611,12 @@ void EmulatedController::SetTrigger(Common::Input::CallbackStatus callback, std: switch (index) { case Settings::NativeTrigger::LTrigger: controller.gc_trigger_state.left = static_cast(trigger.analog.value * HID_TRIGGER_MAX); - controller.npad_button_state.zl.Assign(trigger.pressed); + controller.npad_button_state.zl.Assign(trigger.pressed.value); break; case Settings::NativeTrigger::RTrigger: controller.gc_trigger_state.right = static_cast(trigger.analog.value * HID_TRIGGER_MAX); - controller.npad_button_state.zr.Assign(trigger.pressed); + controller.npad_button_state.zr.Assign(trigger.pressed.value); break; } diff --git a/src/core/hid/input_converter.cpp b/src/core/hid/input_converter.cpp index 14204917e..5b123bd3a 100644 --- a/src/core/hid/input_converter.cpp +++ b/src/core/hid/input_converter.cpp @@ -53,7 +53,7 @@ Common::Input::ButtonStatus TransformToButton(const Common::Input::CallbackStatu switch (callback.type) { case Common::Input::InputType::Analog: case Common::Input::InputType::Trigger: - status.value = TransformToTrigger(callback).pressed; + status.value = TransformToTrigger(callback).pressed.value; break; case Common::Input::InputType::Button: status = callback.button_status; @@ -222,7 +222,7 @@ Common::Input::TriggerStatus TransformToTrigger(const Common::Input::CallbackSta // Set button status if (calculate_button_value) { - status.pressed = value > properties.threshold; + status.pressed.value = value > properties.threshold; } // Adjust if value is inverted diff --git a/src/input_common/drivers/tas_input.h b/src/input_common/drivers/tas_input.h index 5f5c3267c..82dc9d616 100644 --- a/src/input_common/drivers/tas_input.h +++ b/src/input_common/drivers/tas_input.h @@ -188,7 +188,6 @@ private: std::string WriteCommandAxis(TasAnalog data) const; size_t script_length{0}; - bool is_old_input_saved{false}; bool is_recording{false}; bool is_running{false}; bool needs_reset{false}; diff --git a/src/input_common/helpers/touch_from_buttons.cpp b/src/input_common/helpers/touch_from_buttons.cpp index fee41cae3..024343715 100644 --- a/src/input_common/helpers/touch_from_buttons.cpp +++ b/src/input_common/helpers/touch_from_buttons.cpp @@ -12,7 +12,7 @@ namespace InputCommon { class TouchFromButtonDevice final : public Common::Input::InputDevice { public: using Button = std::unique_ptr; - TouchFromButtonDevice(Button button_, u32 touch_id_, float x_, float y_) + TouchFromButtonDevice(Button button_, int touch_id_, float x_, float y_) : button(std::move(button_)), touch_id(touch_id_), x(x_), y(y_) { Common::Input::InputCallback button_up_callback{ [this](Common::Input::CallbackStatus callback_) { UpdateButtonStatus(callback_); }}; @@ -52,7 +52,7 @@ public: private: Button button; - const u32 touch_id; + const int touch_id; const float x; const float y; const Common::Input::AnalogProperties properties{0.0f, 1.0f, 0.5f, 0.0f, false}; diff --git a/src/input_common/input_engine.cpp b/src/input_common/input_engine.cpp index 9cfe0f232..965a2bdf1 100644 --- a/src/input_common/input_engine.cpp +++ b/src/input_common/input_engine.cpp @@ -315,7 +315,7 @@ void InputEngine::TriggerOnMotionChange(const PadIdentifier& identifier, int mot bool InputEngine::IsInputIdentifierEqual(const InputIdentifier& input_identifier, const PadIdentifier& identifier, EngineInputType type, - std::size_t index) const { + int index) const { if (input_identifier.type != type) { return false; } diff --git a/src/input_common/input_engine.h b/src/input_common/input_engine.h index ed79d3d93..5430c0cf8 100644 --- a/src/input_common/input_engine.h +++ b/src/input_common/input_engine.h @@ -96,7 +96,7 @@ struct MappingCallback { struct InputIdentifier { PadIdentifier identifier; EngineInputType type; - std::size_t index; + int index; UpdateCallback callback; }; @@ -216,12 +216,11 @@ private: bool IsInputIdentifierEqual(const InputIdentifier& input_identifier, const PadIdentifier& identifier, EngineInputType type, - std::size_t index) const; + int index) const; mutable std::mutex mutex; mutable std::mutex mutex_callback; bool configuring{false}; - bool is_callback_enabled{true}; const std::string input_engine; int last_callback_key = 0; std::unordered_map controller_list; diff --git a/src/input_common/input_poller.cpp b/src/input_common/input_poller.cpp index 2b3b77938..01c435802 100644 --- a/src/input_common/input_poller.cpp +++ b/src/input_common/input_poller.cpp @@ -18,7 +18,7 @@ public: class InputFromButton final : public Common::Input::InputDevice { public: - explicit InputFromButton(PadIdentifier identifier_, u32 button_, bool toggle_, bool inverted_, + explicit InputFromButton(PadIdentifier identifier_, int button_, bool toggle_, bool inverted_, InputEngine* input_engine_) : identifier(identifier_), button(button_), toggle(toggle_), inverted(inverted_), input_engine(input_engine_) { @@ -69,7 +69,7 @@ public: private: const PadIdentifier identifier; - const u32 button; + const int button; const bool toggle; const bool inverted; int callback_key; @@ -79,7 +79,7 @@ private: class InputFromHatButton final : public Common::Input::InputDevice { public: - explicit InputFromHatButton(PadIdentifier identifier_, u32 button_, u8 direction_, bool toggle_, + explicit InputFromHatButton(PadIdentifier identifier_, int button_, u8 direction_, bool toggle_, bool inverted_, InputEngine* input_engine_) : identifier(identifier_), button(button_), direction(direction_), toggle(toggle_), inverted(inverted_), input_engine(input_engine_) { @@ -130,7 +130,7 @@ public: private: const PadIdentifier identifier; - const u32 button; + const int button; const u8 direction; const bool toggle; const bool inverted; @@ -141,7 +141,7 @@ private: class InputFromStick final : public Common::Input::InputDevice { public: - explicit InputFromStick(PadIdentifier identifier_, u32 axis_x_, u32 axis_y_, + explicit InputFromStick(PadIdentifier identifier_, int axis_x_, int axis_y_, Common::Input::AnalogProperties properties_x_, Common::Input::AnalogProperties properties_y_, InputEngine* input_engine_) @@ -211,8 +211,8 @@ public: private: const PadIdentifier identifier; - const u32 axis_x; - const u32 axis_y; + const int axis_x; + const int axis_y; const Common::Input::AnalogProperties properties_x; const Common::Input::AnalogProperties properties_y; int callback_key_x; @@ -224,8 +224,8 @@ private: class InputFromTouch final : public Common::Input::InputDevice { public: - explicit InputFromTouch(PadIdentifier identifier_, u32 touch_id_, u32 button_, bool toggle_, - bool inverted_, u32 axis_x_, u32 axis_y_, + explicit InputFromTouch(PadIdentifier identifier_, int touch_id_, int button_, bool toggle_, + bool inverted_, int axis_x_, int axis_y_, Common::Input::AnalogProperties properties_x_, Common::Input::AnalogProperties properties_y_, InputEngine* input_engine_) @@ -302,12 +302,12 @@ public: private: const PadIdentifier identifier; - const u32 touch_id; - const u32 button; + const int touch_id; + const int button; const bool toggle; const bool inverted; - const u32 axis_x; - const u32 axis_y; + const int axis_x; + const int axis_y; const Common::Input::AnalogProperties properties_x; const Common::Input::AnalogProperties properties_y; int callback_key_button; @@ -321,8 +321,8 @@ private: class InputFromTrigger final : public Common::Input::InputDevice { public: - explicit InputFromTrigger(PadIdentifier identifier_, u32 button_, bool toggle_, bool inverted_, - u32 axis_, Common::Input::AnalogProperties properties_, + explicit InputFromTrigger(PadIdentifier identifier_, int button_, bool toggle_, bool inverted_, + int axis_, Common::Input::AnalogProperties properties_, InputEngine* input_engine_) : identifier(identifier_), button(button_), toggle(toggle_), inverted(inverted_), axis(axis_), properties(properties_), input_engine(input_engine_) { @@ -355,9 +355,14 @@ public: .raw_value = input_engine->GetAxis(identifier, axis), .properties = properties, }; + const Common::Input::ButtonStatus button_status{ + .value = input_engine->GetButton(identifier, button), + .inverted = inverted, + .toggle = toggle, + }; return { .analog = analog_status, - .pressed = input_engine->GetButton(identifier, button), + .pressed = button_status, }; } @@ -368,19 +373,19 @@ public: }; if (status.trigger_status.analog.raw_value != last_axis_value || - status.trigger_status.pressed != last_button_value) { + status.trigger_status.pressed.value != last_button_value) { last_axis_value = status.trigger_status.analog.raw_value; - last_button_value = status.trigger_status.pressed; + last_button_value = status.trigger_status.pressed.value; TriggerOnChange(status); } } private: const PadIdentifier identifier; - const u32 button; + const int button; const bool toggle; const bool inverted; - const u32 axis; + const int axis; const Common::Input::AnalogProperties properties; int callback_key_button; int axis_callback_key; @@ -391,7 +396,7 @@ private: class InputFromAnalog final : public Common::Input::InputDevice { public: - explicit InputFromAnalog(PadIdentifier identifier_, u32 axis_, + explicit InputFromAnalog(PadIdentifier identifier_, int axis_, Common::Input::AnalogProperties properties_, InputEngine* input_engine_) : identifier(identifier_), axis(axis_), properties(properties_), @@ -432,7 +437,7 @@ public: private: const PadIdentifier identifier; - const u32 axis; + const int axis; const Common::Input::AnalogProperties properties; int callback_key; float last_axis_value; @@ -493,7 +498,7 @@ private: class InputFromMotion final : public Common::Input::InputDevice { public: - explicit InputFromMotion(PadIdentifier identifier_, u32 motion_sensor_, + explicit InputFromMotion(PadIdentifier identifier_, int motion_sensor_, InputEngine* input_engine_) : identifier(identifier_), motion_sensor(motion_sensor_), input_engine(input_engine_) { UpdateCallback engine_callback{[this]() { OnChange(); }}; @@ -539,14 +544,14 @@ public: private: const PadIdentifier identifier; - const u32 motion_sensor; + const int motion_sensor; int callback_key; InputEngine* input_engine; }; class InputFromAxisMotion final : public Common::Input::InputDevice { public: - explicit InputFromAxisMotion(PadIdentifier identifier_, u32 axis_x_, u32 axis_y_, u32 axis_z_, + explicit InputFromAxisMotion(PadIdentifier identifier_, int axis_x_, int axis_y_, int axis_z_, Common::Input::AnalogProperties properties_x_, Common::Input::AnalogProperties properties_y_, Common::Input::AnalogProperties properties_z_, @@ -634,9 +639,9 @@ public: private: const PadIdentifier identifier; - const u32 axis_x; - const u32 axis_y; - const u32 axis_z; + const int axis_x; + const int axis_y; + const int axis_z; const Common::Input::AnalogProperties properties_x; const Common::Input::AnalogProperties properties_y; const Common::Input::AnalogProperties properties_z; @@ -680,8 +685,8 @@ std::unique_ptr InputFactory::CreateButtonDevice( .pad = static_cast(params.Get("pad", 0)), }; - const auto button_id = static_cast(params.Get("button", 0)); - const auto keyboard_key = static_cast(params.Get("code", 0)); + const auto button_id = params.Get("button", 0); + const auto keyboard_key = params.Get("code", 0); const auto toggle = params.Get("toggle", false); const auto inverted = params.Get("inverted", false); input_engine->PreSetController(identifier); @@ -703,7 +708,7 @@ std::unique_ptr InputFactory::CreateHatButtonDevice( .pad = static_cast(params.Get("pad", 0)), }; - const auto button_id = static_cast(params.Get("hat", 0)); + const auto button_id = params.Get("hat", 0); const auto direction = input_engine->GetHatButtonId(params.Get("direction", "")); const auto toggle = params.Get("toggle", false); const auto inverted = params.Get("inverted", false); @@ -725,7 +730,7 @@ std::unique_ptr InputFactory::CreateStickDevice( .pad = static_cast(params.Get("pad", 0)), }; - const auto axis_x = static_cast(params.Get("axis_x", 0)); + const auto axis_x = params.Get("axis_x", 0); const Common::Input::AnalogProperties properties_x = { .deadzone = deadzone, .range = range, @@ -734,7 +739,7 @@ std::unique_ptr InputFactory::CreateStickDevice( .inverted = params.Get("invert_x", "+") == "-", }; - const auto axis_y = static_cast(params.Get("axis_y", 1)); + const auto axis_y = params.Get("axis_y", 1); const Common::Input::AnalogProperties properties_y = { .deadzone = deadzone, .range = range, @@ -757,7 +762,7 @@ std::unique_ptr InputFactory::CreateAnalogDevice( .pad = static_cast(params.Get("pad", 0)), }; - const auto axis = static_cast(params.Get("axis", 0)); + const auto axis = params.Get("axis", 0); const Common::Input::AnalogProperties properties = { .deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, 1.0f), .range = std::clamp(params.Get("range", 1.0f), 0.25f, 1.50f), @@ -778,11 +783,11 @@ std::unique_ptr InputFactory::CreateTriggerDevice( .pad = static_cast(params.Get("pad", 0)), }; - const auto button = static_cast(params.Get("button", 0)); + const auto button = params.Get("button", 0); const auto toggle = params.Get("toggle", false); const auto inverted = params.Get("inverted", false); - const auto axis = static_cast(params.Get("axis", 0)); + const auto axis = params.Get("axis", 0); const Common::Input::AnalogProperties properties = { .deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, 1.0f), .range = std::clamp(params.Get("range", 1.0f), 0.25f, 2.50f), @@ -809,11 +814,11 @@ std::unique_ptr InputFactory::CreateTouchDevice( .pad = static_cast(params.Get("pad", 0)), }; - const auto button = static_cast(params.Get("button", 0)); + const auto button = params.Get("button", 0); const auto toggle = params.Get("toggle", false); const auto inverted = params.Get("inverted", false); - const auto axis_x = static_cast(params.Get("axis_x", 0)); + const auto axis_x = params.Get("axis_x", 0); const Common::Input::AnalogProperties properties_x = { .deadzone = deadzone, .range = range, @@ -822,7 +827,7 @@ std::unique_ptr InputFactory::CreateTouchDevice( .inverted = params.Get("invert_x", "+") == "-", }; - const auto axis_y = static_cast(params.Get("axis_y", 1)); + const auto axis_y = params.Get("axis_y", 1); const Common::Input::AnalogProperties properties_y = { .deadzone = deadzone, .range = range, @@ -869,7 +874,7 @@ std::unique_ptr InputFactory::CreateMotionDevice( const auto range = std::clamp(params.Get("range", 1.0f), 0.25f, 1.50f); const auto threshold = std::clamp(params.Get("threshold", 0.5f), 0.0f, 1.0f); - const auto axis_x = static_cast(params.Get("axis_x", 0)); + const auto axis_x = params.Get("axis_x", 0); const Common::Input::AnalogProperties properties_x = { .deadzone = deadzone, .range = range, @@ -878,7 +883,7 @@ std::unique_ptr InputFactory::CreateMotionDevice( .inverted = params.Get("invert_x", "+") == "-", }; - const auto axis_y = static_cast(params.Get("axis_y", 1)); + const auto axis_y = params.Get("axis_y", 1); const Common::Input::AnalogProperties properties_y = { .deadzone = deadzone, .range = range, @@ -887,7 +892,7 @@ std::unique_ptr InputFactory::CreateMotionDevice( .inverted = params.Get("invert_y", "+") != "+", }; - const auto axis_z = static_cast(params.Get("axis_z", 1)); + const auto axis_z = params.Get("axis_z", 1); const Common::Input::AnalogProperties properties_z = { .deadzone = deadzone, .range = range, diff --git a/src/yuzu/applets/qt_controller.cpp b/src/yuzu/applets/qt_controller.cpp index 59289c6a5..e9cb578b4 100644 --- a/src/yuzu/applets/qt_controller.cpp +++ b/src/yuzu/applets/qt_controller.cpp @@ -26,8 +26,6 @@ namespace { -constexpr std::size_t HANDHELD_INDEX = 8; - void UpdateController(Core::HID::EmulatedController* controller, Core::HID::NpadType controller_type, bool connected) { if (controller->IsConnected()) { diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index 9a1b3575e..8d6289d8e 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp @@ -38,8 +38,6 @@ const std::array namespace { -constexpr std::size_t HANDHELD_INDEX = 8; - QString GetKeyName(int key_code) { switch (key_code) { case Qt::Key_Shift: diff --git a/src/yuzu/configuration/configure_input_player.ui b/src/yuzu/configuration/configure_input_player.ui index 14ca02fd8..958a89229 100644 --- a/src/yuzu/configuration/configure_input_player.ui +++ b/src/yuzu/configuration/configure_input_player.ui @@ -89,31 +89,6 @@ 21 - - - Pro Controller - - - - - Dual Joycons - - - - - Left Joycon - - - - - Right Joycon - - - - - Handheld - - diff --git a/src/yuzu/configuration/configure_input_player_widget.cpp b/src/yuzu/configuration/configure_input_player_widget.cpp index bb20e9339..99c4f13c3 100644 --- a/src/yuzu/configuration/configure_input_player_widget.cpp +++ b/src/yuzu/configuration/configure_input_player_widget.cpp @@ -118,7 +118,7 @@ void PlayerControlPreview::ResetInputs() { }); trigger_values.fill({ .analog = {.value = 0, .properties = {0, 1, 0}}, - .pressed = false, + .pressed = {.value = false}, }); update(); } @@ -2001,11 +2001,11 @@ void PlayerControlPreview::DrawGCTriggers(QPainter& p, const QPointF center, // Left trigger p.setPen(colors.outline); - p.setBrush(left_trigger.pressed ? colors.highlight : colors.button); + p.setBrush(left_trigger.pressed.value ? colors.highlight : colors.button); DrawPolygon(p, qleft_trigger); // Right trigger - p.setBrush(right_trigger.pressed ? colors.highlight : colors.button); + p.setBrush(right_trigger.pressed.value ? colors.highlight : colors.button); DrawPolygon(p, qright_trigger); // Draw L text @@ -2587,15 +2587,17 @@ 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 + arrow_button[point] = center + QPointF(up_arrow_button[point * 2 + 1] * size, + up_arrow_button[point * 2 + 0] * size); + break; case Direction::None: break; } @@ -2610,15 +2612,15 @@ void PlayerControlPreview::DrawArrowButton(QPainter& p, const QPointF center, 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; -- cgit v1.2.3 From 77fa4d4bf60526826ef8b53ee3870f7d2a761976 Mon Sep 17 00:00:00 2001 From: german77 Date: Mon, 1 Nov 2021 14:17:53 -0600 Subject: second commit lion review --- src/common/input.h | 2 +- src/core/hid/emulated_console.cpp | 5 +++-- src/core/hid/emulated_controller.cpp | 5 +++-- src/core/hid/emulated_devices.cpp | 5 +++-- src/core/hid/hid_core.cpp | 3 +++ src/core/hid/hid_core.h | 10 +++++++--- src/core/hid/input_converter.h | 12 ++++++++++-- src/core/hle/service/am/applets/applet_controller.cpp | 2 ++ src/core/hle/service/hid/controllers/console_sixaxis.cpp | 1 + src/core/hle/service/hid/controllers/debug_pad.cpp | 1 + src/core/hle/service/hid/controllers/gesture.h | 5 +---- src/core/hle/service/hid/controllers/keyboard.cpp | 1 + src/core/hle/service/hid/controllers/mouse.cpp | 1 + src/core/hle/service/hid/controllers/npad.cpp | 2 ++ src/core/hle/service/hid/controllers/npad.h | 6 +++++- src/core/hle/service/hid/controllers/touchscreen.h | 1 + src/input_common/drivers/keyboard.cpp | 6 ++++++ src/input_common/drivers/keyboard.h | 7 ------- src/input_common/drivers/mouse.cpp | 5 +++++ src/input_common/drivers/mouse.h | 5 ----- src/input_common/drivers/touch_screen.cpp | 6 ++++++ src/input_common/drivers/touch_screen.h | 8 +------- src/input_common/input_engine.cpp | 5 +++-- src/yuzu/applets/qt_controller.cpp | 1 + src/yuzu/configuration/configure_input_player_widget.cpp | 5 ++--- src/yuzu/configuration/configure_input_player_widget.h | 1 + src/yuzu/debugger/controller.h | 3 ++- src/yuzu/main.cpp | 1 + 28 files changed, 73 insertions(+), 42 deletions(-) (limited to 'src/input_common/drivers') diff --git a/src/common/input.h b/src/common/input.h index 16b1e6f1b..12acd8785 100644 --- a/src/common/input.h +++ b/src/common/input.h @@ -29,7 +29,7 @@ enum class InputType { Ir, }; -enum class BatteryLevel { +enum class BatteryLevel : u32 { None, Empty, Critical, diff --git a/src/core/hid/emulated_console.cpp b/src/core/hid/emulated_console.cpp index 012909954..dfbaa3f8c 100644 --- a/src/core/hid/emulated_console.cpp +++ b/src/core/hid/emulated_console.cpp @@ -209,10 +209,11 @@ int EmulatedConsole::SetCallback(ConsoleUpdateCallback update_callback) { void EmulatedConsole::DeleteCallback(int key) { std::lock_guard lock{mutex}; - if (!callback_list.contains(key)) { + const auto& iterator = callback_list.find(key); + if (iterator == callback_list.end()) { LOG_ERROR(Input, "Tried to delete non-existent callback {}", key); return; } - callback_list.erase(key); + callback_list.erase(iterator); } } // namespace Core::HID diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index 9a1864279..7bab00bb1 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -993,10 +993,11 @@ int EmulatedController::SetCallback(ControllerUpdateCallback update_callback) { void EmulatedController::DeleteCallback(int key) { std::lock_guard lock{mutex}; - if (!callback_list.contains(key)) { + const auto& iterator = callback_list.find(key); + if (iterator == callback_list.end()) { LOG_ERROR(Input, "Tried to delete non-existent callback {}", key); return; } - callback_list.erase(key); + callback_list.erase(iterator); } } // namespace Core::HID diff --git a/src/core/hid/emulated_devices.cpp b/src/core/hid/emulated_devices.cpp index c76a86b6c..e97470240 100644 --- a/src/core/hid/emulated_devices.cpp +++ b/src/core/hid/emulated_devices.cpp @@ -362,10 +362,11 @@ int EmulatedDevices::SetCallback(InterfaceUpdateCallback update_callback) { void EmulatedDevices::DeleteCallback(int key) { std::lock_guard lock{mutex}; - if (!callback_list.contains(key)) { + const auto& iterator = callback_list.find(key); + if (iterator == callback_list.end()) { LOG_ERROR(Input, "Tried to delete non-existent callback {}", key); return; } - callback_list.erase(key); + callback_list.erase(iterator); } } // namespace Core::HID diff --git a/src/core/hid/hid_core.cpp b/src/core/hid/hid_core.cpp index 3cb26e1e7..741a69c3c 100644 --- a/src/core/hid/hid_core.cpp +++ b/src/core/hid/hid_core.cpp @@ -3,6 +3,9 @@ // Refer to the license.txt file included. #include "common/assert.h" +#include "core/hid/emulated_console.h" +#include "core/hid/emulated_controller.h" +#include "core/hid/emulated_devices.h" #include "core/hid/hid_core.h" namespace Core::HID { diff --git a/src/core/hid/hid_core.h b/src/core/hid/hid_core.h index a4a66a3a4..1fe2fd89b 100644 --- a/src/core/hid/hid_core.h +++ b/src/core/hid/hid_core.h @@ -6,9 +6,13 @@ #include -#include "core/hid/emulated_console.h" -#include "core/hid/emulated_controller.h" -#include "core/hid/emulated_devices.h" +#include "core/hid/hid_types.h" + +namespace Core::HID { +class EmulatedConsole; +class EmulatedController; +class EmulatedDevices; +} // namespace Core::HID namespace Core::HID { diff --git a/src/core/hid/input_converter.h b/src/core/hid/input_converter.h index b38e657b0..2a722b39f 100644 --- a/src/core/hid/input_converter.h +++ b/src/core/hid/input_converter.h @@ -4,9 +4,17 @@ #pragma once -namespace Input { +namespace Common::Input { struct CallbackStatus; -}; +enum class BatteryLevel : u32; +using BatteryStatus = BatteryLevel; +struct AnalogStatus; +struct ButtonStatus; +struct MotionStatus; +struct StickStatus; +struct TouchStatus; +struct TriggerStatus; +}; // namespace Common::Input namespace Core::HID { diff --git a/src/core/hle/service/am/applets/applet_controller.cpp b/src/core/hle/service/am/applets/applet_controller.cpp index 658265a00..374e0c7f4 100644 --- a/src/core/hle/service/am/applets/applet_controller.cpp +++ b/src/core/hle/service/am/applets/applet_controller.cpp @@ -10,6 +10,8 @@ #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/hle/result.h" #include "core/hle/service/am/am.h" #include "core/hle/service/am/applets/applet_controller.h" diff --git a/src/core/hle/service/hid/controllers/console_sixaxis.cpp b/src/core/hle/service/hid/controllers/console_sixaxis.cpp index 1d351fde0..2bebcf0d0 100644 --- a/src/core/hle/service/hid/controllers/console_sixaxis.cpp +++ b/src/core/hle/service/hid/controllers/console_sixaxis.cpp @@ -5,6 +5,7 @@ #include "common/settings.h" #include "core/core.h" #include "core/core_timing.h" +#include "core/hid/emulated_console.h" #include "core/hle/service/hid/controllers/console_sixaxis.h" 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 b009ed086..86b95f2c8 100644 --- a/src/core/hle/service/hid/controllers/debug_pad.cpp +++ b/src/core/hle/service/hid/controllers/debug_pad.cpp @@ -7,6 +7,7 @@ #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/hid/hid_types.h" #include "core/hle/service/hid/controllers/debug_pad.h" diff --git a/src/core/hle/service/hid/controllers/gesture.h b/src/core/hle/service/hid/controllers/gesture.h index 58139a5cf..9bffde438 100644 --- a/src/core/hle/service/hid/controllers/gesture.h +++ b/src/core/hle/service/hid/controllers/gesture.h @@ -8,13 +8,10 @@ #include "common/bit_field.h" #include "common/common_types.h" #include "common/point.h" +#include "core/hid/emulated_console.h" #include "core/hle/service/hid/controllers/controller_base.h" #include "core/hle/service/hid/ring_lifo.h" -namespace Core::HID { -class EmulatedController; -} // namespace Core::HID - namespace Service::HID { class Controller_Gesture final : public ControllerBase { public: diff --git a/src/core/hle/service/hid/controllers/keyboard.cpp b/src/core/hle/service/hid/controllers/keyboard.cpp index 60dc62f2c..acea68e24 100644 --- a/src/core/hle/service/hid/controllers/keyboard.cpp +++ b/src/core/hle/service/hid/controllers/keyboard.cpp @@ -7,6 +7,7 @@ #include "common/settings.h" #include "core/core.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" diff --git a/src/core/hle/service/hid/controllers/mouse.cpp b/src/core/hle/service/hid/controllers/mouse.cpp index 7ec75e8c8..21f7e48bb 100644 --- a/src/core/hle/service/hid/controllers/mouse.cpp +++ b/src/core/hle/service/hid/controllers/mouse.cpp @@ -7,6 +7,7 @@ #include "core/core.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" diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index 9f82f872a..0b5a23696 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -12,6 +12,8 @@ #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/hle/kernel/k_event.h" #include "core/hle/kernel/k_readable_event.h" #include "core/hle/kernel/k_writable_event.h" diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h index 4a9c9cc1a..871d245fd 100644 --- a/src/core/hle/service/hid/controllers/npad.h +++ b/src/core/hle/service/hid/controllers/npad.h @@ -12,11 +12,15 @@ #include "common/common_types.h" #include "common/quaternion.h" #include "common/settings.h" -#include "core/hid/hid_core.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 Core::HID { +class EmulatedController; +enum class ControllerTriggerType; +} // namespace Core::HID + namespace Kernel { class KEvent; class KReadableEvent; diff --git a/src/core/hle/service/hid/controllers/touchscreen.h b/src/core/hle/service/hid/controllers/touchscreen.h index fa4dfa1a2..50dadd25f 100644 --- a/src/core/hle/service/hid/controllers/touchscreen.h +++ b/src/core/hle/service/hid/controllers/touchscreen.h @@ -9,6 +9,7 @@ #include "common/common_types.h" #include "common/point.h" #include "common/swap.h" +#include "core/hid/emulated_console.h" #include "core/hid/hid_core.h" #include "core/hid/hid_types.h" #include "core/hle/service/hid/controllers/controller_base.h" diff --git a/src/input_common/drivers/keyboard.cpp b/src/input_common/drivers/keyboard.cpp index 85a781a30..549704e89 100644 --- a/src/input_common/drivers/keyboard.cpp +++ b/src/input_common/drivers/keyboard.cpp @@ -7,6 +7,12 @@ namespace InputCommon { +constexpr PadIdentifier identifier = { + .guid = Common::UUID{Common::INVALID_UUID}, + .port = 0, + .pad = 0, +}; + Keyboard::Keyboard(const std::string& input_engine_) : InputEngine(input_engine_) { PreSetController(identifier); } diff --git a/src/input_common/drivers/keyboard.h b/src/input_common/drivers/keyboard.h index 58df15050..46fe78576 100644 --- a/src/input_common/drivers/keyboard.h +++ b/src/input_common/drivers/keyboard.h @@ -32,13 +32,6 @@ public: /// Used for automapping features std::vector GetInputDevices() const override; - -private: - const PadIdentifier identifier = { - .guid = Common::UUID{Common::INVALID_UUID}, - .port = 0, - .pad = 0, - }; }; } // namespace InputCommon diff --git a/src/input_common/drivers/mouse.cpp b/src/input_common/drivers/mouse.cpp index 1c32b54be..afa92b458 100644 --- a/src/input_common/drivers/mouse.cpp +++ b/src/input_common/drivers/mouse.cpp @@ -14,6 +14,11 @@ namespace InputCommon { constexpr int touch_axis_x = 10; constexpr int touch_axis_y = 11; +constexpr PadIdentifier identifier = { + .guid = Common::UUID{Common::INVALID_UUID}, + .port = 0, + .pad = 0, +}; Mouse::Mouse(const std::string input_engine_) : InputEngine(input_engine_) { PreSetController(identifier); diff --git a/src/input_common/drivers/mouse.h b/src/input_common/drivers/mouse.h index cf0918409..1be362b94 100644 --- a/src/input_common/drivers/mouse.h +++ b/src/input_common/drivers/mouse.h @@ -62,11 +62,6 @@ private: void UpdateThread(std::stop_token stop_token); void StopPanning(); - const PadIdentifier identifier = { - .guid = Common::UUID{Common::INVALID_UUID}, - .port = 0, - .pad = 0, - }; Common::Vec2 mouse_origin; Common::Vec2 last_mouse_position; Common::Vec2 last_mouse_change; diff --git a/src/input_common/drivers/touch_screen.cpp b/src/input_common/drivers/touch_screen.cpp index e13835e9f..377c9ee2b 100644 --- a/src/input_common/drivers/touch_screen.cpp +++ b/src/input_common/drivers/touch_screen.cpp @@ -7,6 +7,12 @@ namespace InputCommon { +constexpr PadIdentifier identifier = { + .guid = Common::UUID{Common::INVALID_UUID}, + .port = 0, + .pad = 0, +}; + TouchScreen::TouchScreen(const std::string input_engine_) : InputEngine(input_engine_) { PreSetController(identifier); } diff --git a/src/input_common/drivers/touch_screen.h b/src/input_common/drivers/touch_screen.h index d297d253c..0f4cd0e7a 100644 --- a/src/input_common/drivers/touch_screen.h +++ b/src/input_common/drivers/touch_screen.h @@ -37,14 +37,8 @@ public: */ void TouchReleased(std::size_t finger); + /// Resets all inputs to their initial value void ReleaseAllTouch(); - -private: - const PadIdentifier identifier = { - .guid = Common::UUID{Common::INVALID_UUID}, - .port = 0, - .pad = 0, - }; }; } // namespace InputCommon diff --git a/src/input_common/input_engine.cpp b/src/input_common/input_engine.cpp index 965a2bdf1..139d8d2e6 100644 --- a/src/input_common/input_engine.cpp +++ b/src/input_common/input_engine.cpp @@ -353,11 +353,12 @@ void InputEngine::SetMappingCallback(MappingCallback callback) { void InputEngine::DeleteCallback(int key) { std::lock_guard lock{mutex_callback}; - if (!callback_list.contains(key)) { + const auto& iterator = callback_list.find(key); + if (iterator == callback_list.end()) { LOG_ERROR(Input, "Tried to delete non-existent callback {}", key); return; } - callback_list.erase(key); + callback_list.erase(iterator); } } // namespace InputCommon diff --git a/src/yuzu/applets/qt_controller.cpp b/src/yuzu/applets/qt_controller.cpp index e9cb578b4..9c6377cf0 100644 --- a/src/yuzu/applets/qt_controller.cpp +++ b/src/yuzu/applets/qt_controller.cpp @@ -10,6 +10,7 @@ #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" diff --git a/src/yuzu/configuration/configure_input_player_widget.cpp b/src/yuzu/configuration/configure_input_player_widget.cpp index 99c4f13c3..7e71a0f58 100644 --- a/src/yuzu/configuration/configure_input_player_widget.cpp +++ b/src/yuzu/configuration/configure_input_player_widget.cpp @@ -2594,9 +2594,8 @@ void PlayerControlPreview::DrawArrowButton(QPainter& p, const QPointF center, arrow_button[point] = center + QPointF(up_arrow_x * size, -up_arrow_y * size); break; case Direction::Left: - // Compiler doesn't optimize this correctly - arrow_button[point] = center + QPointF(up_arrow_button[point * 2 + 1] * size, - up_arrow_button[point * 2 + 0] * size); + // 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; diff --git a/src/yuzu/configuration/configure_input_player_widget.h b/src/yuzu/configuration/configure_input_player_widget.h index 430e4f4f4..acc53a9e3 100644 --- a/src/yuzu/configuration/configure_input_player_widget.h +++ b/src/yuzu/configuration/configure_input_player_widget.h @@ -9,6 +9,7 @@ #include #include "common/input.h" #include "common/settings.h" +#include "core/hid/emulated_controller.h" #include "core/hid/hid_core.h" #include "core/hid/hid_types.h" diff --git a/src/yuzu/debugger/controller.h b/src/yuzu/debugger/controller.h index ba4185a4b..d08643baa 100644 --- a/src/yuzu/debugger/controller.h +++ b/src/yuzu/debugger/controller.h @@ -21,7 +21,8 @@ class System; namespace Core::HID { class EmulatedController; -} +enum class ControllerTriggerType; +} // namespace Core::HID class ControllerDialog : public QWidget { Q_OBJECT diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 56db337a4..7c95851b3 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -26,6 +26,7 @@ #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" -- cgit v1.2.3 From 157e0b85fdd805e02d234dccf1ce578e3159adee Mon Sep 17 00:00:00 2001 From: german77 Date: Tue, 2 Nov 2021 22:50:30 -0600 Subject: core/hid: Prevent Emulated controller from flapping with multiple inputs devices --- src/common/input.h | 4 ++ src/core/hid/emulated_controller.cpp | 68 +++++++++++++++++++++++++++++----- src/core/hid/emulated_controller.h | 6 +-- src/input_common/drivers/tas_input.cpp | 24 +++++------- src/input_common/drivers/tas_input.h | 11 ++---- 5 files changed, 77 insertions(+), 36 deletions(-) (limited to 'src/input_common/drivers') diff --git a/src/common/input.h b/src/common/input.h index 8f29026a1..f21872b0a 100644 --- a/src/common/input.h +++ b/src/common/input.h @@ -11,6 +11,7 @@ #include #include "common/logging/log.h" #include "common/param_package.h" +#include "common/uuid.h" namespace Common::Input { @@ -81,6 +82,7 @@ struct AnalogStatus { }; struct ButtonStatus { + Common::UUID uuid{}; bool value{}; bool inverted{}; bool toggle{}; @@ -90,6 +92,7 @@ struct ButtonStatus { using BatteryStatus = BatteryLevel; struct StickStatus { + Common::UUID uuid{}; AnalogStatus x{}; AnalogStatus y{}; bool left{}; @@ -99,6 +102,7 @@ struct StickStatus { }; struct TriggerStatus { + Common::UUID uuid{}; AnalogStatus analog{}; ButtonStatus pressed{}; }; diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index 2db2b4da0..6fe3744fd 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -183,8 +183,11 @@ void EmulatedController::ReloadInput() { if (!button_devices[index]) { continue; } + const auto uuid = Common::UUID{button_params[index].Get("guid", "")}; Common::Input::InputCallback button_callback{ - [this, index](Common::Input::CallbackStatus callback) { SetButton(callback, index); }}; + [this, index, uuid](Common::Input::CallbackStatus callback) { + SetButton(callback, index, uuid); + }}; button_devices[index]->SetCallback(button_callback); button_devices[index]->ForceUpdate(); } @@ -193,8 +196,11 @@ void EmulatedController::ReloadInput() { if (!stick_devices[index]) { continue; } + const auto uuid = Common::UUID{stick_params[index].Get("guid", "")}; Common::Input::InputCallback stick_callback{ - [this, index](Common::Input::CallbackStatus callback) { SetStick(callback, index); }}; + [this, index, uuid](Common::Input::CallbackStatus callback) { + SetStick(callback, index, uuid); + }}; stick_devices[index]->SetCallback(stick_callback); stick_devices[index]->ForceUpdate(); } @@ -203,8 +209,11 @@ void EmulatedController::ReloadInput() { if (!trigger_devices[index]) { continue; } + const auto uuid = Common::UUID{trigger_params[index].Get("guid", "")}; Common::Input::InputCallback trigger_callback{ - [this, index](Common::Input::CallbackStatus callback) { SetTrigger(callback, index); }}; + [this, index, uuid](Common::Input::CallbackStatus callback) { + SetTrigger(callback, index, uuid); + }}; trigger_devices[index]->SetCallback(trigger_callback); trigger_devices[index]->ForceUpdate(); } @@ -229,13 +238,18 @@ void EmulatedController::ReloadInput() { motion_devices[index]->ForceUpdate(); } + // Use a common UUID for TAS + const auto tas_uuid = Common::UUID{0x0, 0x7A5}; + // Register TAS devices. No need to force update for (std::size_t index = 0; index < tas_button_devices.size(); ++index) { if (!tas_button_devices[index]) { continue; } Common::Input::InputCallback button_callback{ - [this, index](Common::Input::CallbackStatus callback) { SetButton(callback, index); }}; + [this, index, tas_uuid](Common::Input::CallbackStatus callback) { + SetButton(callback, index, tas_uuid); + }}; tas_button_devices[index]->SetCallback(button_callback); } @@ -244,7 +258,9 @@ void EmulatedController::ReloadInput() { continue; } Common::Input::InputCallback stick_callback{ - [this, index](Common::Input::CallbackStatus callback) { SetStick(callback, index); }}; + [this, index, tas_uuid](Common::Input::CallbackStatus callback) { + SetStick(callback, index, tas_uuid); + }}; tas_stick_devices[index]->SetCallback(stick_callback); } } @@ -423,7 +439,8 @@ void EmulatedController::SetMotionParam(std::size_t index, Common::ParamPackage ReloadInput(); } -void EmulatedController::SetButton(Common::Input::CallbackStatus callback, std::size_t index) { +void EmulatedController::SetButton(Common::Input::CallbackStatus callback, std::size_t index, + Common::UUID uuid) { if (index >= controller.button_values.size()) { return; } @@ -432,7 +449,16 @@ void EmulatedController::SetButton(Common::Input::CallbackStatus callback, std:: bool value_changed = false; const auto new_status = TransformToButton(callback); auto& current_status = controller.button_values[index]; + + // Only read button values that have the same uuid or are pressed once + if (current_status.uuid != uuid) { + if (!new_status.value) { + return; + } + } + current_status.toggle = new_status.toggle; + current_status.uuid = uuid; // Update button status with current if (!current_status.toggle) { @@ -553,12 +579,23 @@ void EmulatedController::SetButton(Common::Input::CallbackStatus callback, std:: TriggerOnChange(ControllerTriggerType::Button, true); } -void EmulatedController::SetStick(Common::Input::CallbackStatus callback, std::size_t index) { +void EmulatedController::SetStick(Common::Input::CallbackStatus callback, std::size_t index, + Common::UUID uuid) { if (index >= controller.stick_values.size()) { return; } std::lock_guard lock{mutex}; - controller.stick_values[index] = TransformToStick(callback); + const auto stick_value = TransformToStick(callback); + + // Only read stick values that have the same uuid or are over the threshold to avoid flapping + if (controller.stick_values[index].uuid != uuid) { + if (!stick_value.down && !stick_value.up && !stick_value.left && !stick_value.right) { + return; + } + } + + controller.stick_values[index] = stick_value; + controller.stick_values[index].uuid = uuid; if (is_configuring) { controller.analog_stick_state.left = {}; @@ -592,12 +629,23 @@ void EmulatedController::SetStick(Common::Input::CallbackStatus callback, std::s TriggerOnChange(ControllerTriggerType::Stick, true); } -void EmulatedController::SetTrigger(Common::Input::CallbackStatus callback, std::size_t index) { +void EmulatedController::SetTrigger(Common::Input::CallbackStatus callback, std::size_t index, + Common::UUID uuid) { if (index >= controller.trigger_values.size()) { return; } std::lock_guard lock{mutex}; - controller.trigger_values[index] = TransformToTrigger(callback); + const auto trigger_value = TransformToTrigger(callback); + + // Only read trigger values that have the same uuid or are pressed once + if (controller.stick_values[index].uuid != uuid) { + if (!trigger_value.pressed.value) { + return; + } + } + + controller.trigger_values[index] = trigger_value; + controller.trigger_values[index].uuid = uuid; if (is_configuring) { controller.gc_trigger_state.left = 0; diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h index 2f7afff56..9a8bdf14d 100644 --- a/src/core/hid/emulated_controller.h +++ b/src/core/hid/emulated_controller.h @@ -313,21 +313,21 @@ private: * @param callback: A CallbackStatus containing the button status * @param index: Button ID of the to be updated */ - void SetButton(Common::Input::CallbackStatus callback, std::size_t index); + void SetButton(Common::Input::CallbackStatus callback, std::size_t index, Common::UUID uuid); /** * Updates the analog stick status of the controller * @param callback: A CallbackStatus containing the analog stick status * @param index: stick ID of the to be updated */ - void SetStick(Common::Input::CallbackStatus callback, std::size_t index); + void SetStick(Common::Input::CallbackStatus callback, std::size_t index, Common::UUID uuid); /** * Updates the trigger status of the controller * @param callback: A CallbackStatus containing the trigger status * @param index: trigger ID of the to be updated */ - void SetTrigger(Common::Input::CallbackStatus callback, std::size_t index); + void SetTrigger(Common::Input::CallbackStatus callback, std::size_t index, Common::UUID uuid); /** * Updates the motion status of the controller diff --git a/src/input_common/drivers/tas_input.cpp b/src/input_common/drivers/tas_input.cpp index d2748b240..bb9c236ea 100644 --- a/src/input_common/drivers/tas_input.cpp +++ b/src/input_common/drivers/tas_input.cpp @@ -71,21 +71,21 @@ Tas::~Tas() { void Tas::LoadTasFiles() { script_length = 0; for (size_t i = 0; i < commands.size(); i++) { - LoadTasFile(i); + LoadTasFile(i, 0); if (commands[i].size() > script_length) { script_length = commands[i].size(); } } } -void Tas::LoadTasFile(size_t player_index) { +void Tas::LoadTasFile(size_t player_index, size_t file_index) { if (!commands[player_index].empty()) { commands[player_index].clear(); } - std::string file = - Common::FS::ReadStringFromFile(Common::FS::GetYuzuPath(Common::FS::YuzuPath::TASDir) / - fmt::format("script0-{}.txt", player_index + 1), - Common::FS::FileType::BinaryFile); + std::string file = Common::FS::ReadStringFromFile( + Common::FS::GetYuzuPath(Common::FS::YuzuPath::TASDir) / + fmt::format("script{}-{}.txt", file_index, player_index + 1), + Common::FS::FileType::BinaryFile); std::stringstream command_line(file); std::string line; int frame_no = 0; @@ -144,15 +144,8 @@ void Tas::WriteTasFile(std::u8string file_name) { void Tas::RecordInput(u64 buttons, TasAnalog left_axis, TasAnalog right_axis) { last_input = { .buttons = buttons, - .l_axis = FlipAxisY(left_axis), - .r_axis = FlipAxisY(right_axis), - }; -} - -TasAnalog Tas::FlipAxisY(TasAnalog old) { - return { - .x = old.x, - .y = -old.y, + .l_axis = left_axis, + .r_axis = right_axis, }; } @@ -219,6 +212,7 @@ void Tas::UpdateThread() { } } else { is_running = Settings::values.tas_loop.GetValue(); + LoadTasFiles(); current_command = 0; ClearInput(); } diff --git a/src/input_common/drivers/tas_input.h b/src/input_common/drivers/tas_input.h index 82dc9d616..bfb37a638 100644 --- a/src/input_common/drivers/tas_input.h +++ b/src/input_common/drivers/tas_input.h @@ -138,21 +138,16 @@ private: void LoadTasFiles(); /** Loads TAS file from the specified player - * @param player_index: player number where data is going to be stored + * @param player_index: player number to save the script + * @param file_index: script number of the file */ - void LoadTasFile(size_t player_index); + void LoadTasFile(size_t player_index, size_t file_index); /** Writes a TAS file from the recorded commands * @param file_name: name of the file to be written */ void WriteTasFile(std::u8string file_name); - /** Inverts the Y axis polarity - * @param old: value of the axis - * @return new value of the axis - */ - TasAnalog FlipAxisY(TasAnalog old); - /** * Parses a string containing the axis values. X and Y have a range from -32767 to 32767 * @param line: string containing axis values with the following format "x;y" -- cgit v1.2.3 From b673857d7dfc72f38d9242b315cd590b859795ff Mon Sep 17 00:00:00 2001 From: german77 Date: Sat, 13 Nov 2021 23:25:45 -0600 Subject: core/hid: Improve accuracy of the keyboard implementation --- src/common/settings_input.h | 35 +- src/core/hid/emulated_devices.cpp | 3 +- src/core/hid/hid_types.h | 398 +++++++++++++++------- src/core/hle/service/hid/controllers/keyboard.cpp | 1 + src/core/hle/service/hid/hid.cpp | 35 +- src/core/hle/service/hid/hid.h | 2 + src/input_common/drivers/keyboard.cpp | 53 ++- src/input_common/drivers/keyboard.h | 7 + src/input_common/main.cpp | 9 + src/input_common/main.h | 3 + src/yuzu/bootmanager.cpp | 276 ++++++++++++++- src/yuzu/bootmanager.h | 6 + src/yuzu/configuration/config.cpp | 167 +-------- 13 files changed, 682 insertions(+), 313 deletions(-) (limited to 'src/input_common/drivers') diff --git a/src/common/settings_input.h b/src/common/settings_input.h index 2c0eb31d3..a2982fca4 100644 --- a/src/common/settings_input.h +++ b/src/common/settings_input.h @@ -129,7 +129,6 @@ extern const std::array mapping; namespace NativeKeyboard { enum Keys { None, - Error, A = 4, B, @@ -167,22 +166,22 @@ enum Keys { N8, N9, N0, - Enter, + Return, Escape, Backspace, Tab, Space, Minus, - Equal, - LeftBrace, - RightBrace, - Backslash, + Plus, + OpenBracket, + CloseBracket, + Pipe, Tilde, Semicolon, - Apostrophe, - Grave, + Quote, + Backquote, Comma, - Dot, + Period, Slash, CapsLockKey, @@ -199,7 +198,7 @@ enum Keys { F11, F12, - SystemRequest, + PrintScreen, ScrollLockKey, Pause, Insert, @@ -268,8 +267,18 @@ enum Keys { ScrollLockActive, KPComma, - KPLeftParenthesis, - KPRightParenthesis, + Ro = 0x87, + KatakanaHiragana, + Yen, + Henkan, + Muhenkan, + NumPadCommaPc98, + + HangulEnglish = 0x90, + Hanja, + KatakanaKey, + HiraganaKey, + ZenkakuHankaku, LeftControlKey = 0xE0, LeftShiftKey, @@ -318,6 +327,8 @@ enum Modifiers { CapsLock, ScrollLock, NumLock, + Katakana, + Hiragana, NumKeyboardMods, }; diff --git a/src/core/hid/emulated_devices.cpp b/src/core/hid/emulated_devices.cpp index e97470240..0d840a003 100644 --- a/src/core/hid/emulated_devices.cpp +++ b/src/core/hid/emulated_devices.cpp @@ -170,13 +170,14 @@ void EmulatedDevices::SetKeyboardButton(Common::Input::CallbackStatus callback, return; } + // Index should be converted from NativeKeyboard to KeyboardKeyIndex UpdateKey(index, current_status.value); TriggerOnChange(DeviceTriggerType::Keyboard); } void EmulatedDevices::UpdateKey(std::size_t key_index, bool status) { - constexpr u8 KEYS_PER_BYTE = 8; + constexpr std::size_t KEYS_PER_BYTE = 8; auto& entry = device_status.keyboard_state.key[key_index / KEYS_PER_BYTE]; const u8 mask = static_cast(1 << (key_index % KEYS_PER_BYTE)); if (status) { diff --git a/src/core/hid/hid_types.h b/src/core/hid/hid_types.h index 41bc65ce2..af95f3aff 100644 --- a/src/core/hid/hid_types.h +++ b/src/core/hid/hid_types.h @@ -12,6 +12,195 @@ namespace Core::HID { +enum class DeviceIndex : u8 { + Left = 0, + Right = 1, + None = 2, + MaxDeviceIndex = 3, +}; + +// This is nn::hid::NpadButton +enum class NpadButton : u64 { + None = 0, + A = 1U << 0, + B = 1U << 1, + X = 1U << 2, + Y = 1U << 3, + StickL = 1U << 4, + StickR = 1U << 5, + L = 1U << 6, + R = 1U << 7, + ZL = 1U << 8, + ZR = 1U << 9, + Plus = 1U << 10, + Minus = 1U << 11, + + Left = 1U << 12, + Up = 1U << 13, + Right = 1U << 14, + Down = 1U << 15, + + StickLLeft = 1U << 16, + StickLUp = 1U << 17, + StickLRight = 1U << 18, + StickLDown = 1U << 19, + + StickRLeft = 1U << 20, + StickRUp = 1U << 21, + StickRRight = 1U << 22, + StickRDown = 1U << 23, + + LeftSL = 1U << 24, + LeftSR = 1U << 25, + + RightSL = 1U << 26, + RightSR = 1U << 27, + + Palma = 1U << 28, + Verification = 1U << 29, + HandheldLeftB = 1U << 30, + LagonCLeft = 1U << 31, + LagonCUp = 1ULL << 32, + LagonCRight = 1ULL << 33, + LagonCDown = 1ULL << 34, +}; +DECLARE_ENUM_FLAG_OPERATORS(NpadButton); + +enum class KeyboardKeyIndex : u32 { + A = 4, + B = 5, + C = 6, + D = 7, + E = 8, + F = 9, + G = 10, + H = 11, + I = 12, + J = 13, + K = 14, + L = 15, + M = 16, + N = 17, + O = 18, + P = 19, + Q = 20, + R = 21, + S = 22, + T = 23, + U = 24, + V = 25, + W = 26, + X = 27, + Y = 28, + Z = 29, + D1 = 30, + D2 = 31, + D3 = 32, + D4 = 33, + D5 = 34, + D6 = 35, + D7 = 36, + D8 = 37, + D9 = 38, + D0 = 39, + Return = 40, + Escape = 41, + Backspace = 42, + Tab = 43, + Space = 44, + Minus = 45, + Plus = 46, + OpenBracket = 47, + CloseBracket = 48, + Pipe = 49, + Tilde = 50, + Semicolon = 51, + Quote = 52, + Backquote = 53, + Comma = 54, + Period = 55, + Slash = 56, + CapsLock = 57, + F1 = 58, + F2 = 59, + F3 = 60, + F4 = 61, + F5 = 62, + F6 = 63, + F7 = 64, + F8 = 65, + F9 = 66, + F10 = 67, + F11 = 68, + F12 = 69, + PrintScreen = 70, + ScrollLock = 71, + Pause = 72, + Insert = 73, + Home = 74, + PageUp = 75, + Delete = 76, + End = 77, + PageDown = 78, + RightArrow = 79, + LeftArrow = 80, + DownArrow = 81, + UpArrow = 82, + NumLock = 83, + NumPadDivide = 84, + NumPadMultiply = 85, + NumPadSubtract = 86, + NumPadAdd = 87, + NumPadEnter = 88, + NumPad1 = 89, + NumPad2 = 90, + NumPad3 = 91, + NumPad4 = 92, + NumPad5 = 93, + NumPad6 = 94, + NumPad7 = 95, + NumPad8 = 96, + NumPad9 = 97, + NumPad0 = 98, + NumPadDot = 99, + Backslash = 100, + Application = 101, + Power = 102, + NumPadEquals = 103, + F13 = 104, + F14 = 105, + F15 = 106, + F16 = 107, + F17 = 108, + F18 = 109, + F19 = 110, + F20 = 111, + F21 = 112, + F22 = 113, + F23 = 114, + F24 = 115, + NumPadComma = 133, + Ro = 135, + KatakanaHiragana = 136, + Yen = 137, + Henkan = 138, + Muhenkan = 139, + NumPadCommaPc98 = 140, + HangulEnglish = 144, + Hanja = 145, + Katakana = 146, + Hiragana = 147, + ZenkakuHankaku = 148, + LeftControl = 224, + LeftShift = 225, + LeftAlt = 226, + LeftGui = 227, + RightControl = 228, + RightShift = 229, + RightAlt = 230, + RightGui = 231, +}; + // This is nn::hid::NpadIdType enum class NpadIdType : u32 { Player1 = 0x0, @@ -28,62 +217,6 @@ enum class NpadIdType : u32 { Invalid = 0xFFFFFFFF, }; -/// Converts a NpadIdType to an array index. -constexpr size_t NpadIdTypeToIndex(NpadIdType npad_id_type) { - switch (npad_id_type) { - case NpadIdType::Player1: - return 0; - case NpadIdType::Player2: - return 1; - case NpadIdType::Player3: - return 2; - case NpadIdType::Player4: - return 3; - case NpadIdType::Player5: - return 4; - case NpadIdType::Player6: - return 5; - case NpadIdType::Player7: - return 6; - case NpadIdType::Player8: - return 7; - case NpadIdType::Handheld: - return 8; - case NpadIdType::Other: - return 9; - default: - return 0; - } -} - -/// Converts an array index to a NpadIdType -constexpr NpadIdType IndexToNpadIdType(size_t index) { - switch (index) { - case 0: - return NpadIdType::Player1; - case 1: - return NpadIdType::Player2; - case 2: - return NpadIdType::Player3; - case 3: - return NpadIdType::Player4; - case 4: - return NpadIdType::Player5; - case 5: - return NpadIdType::Player6; - case 6: - return NpadIdType::Player7; - case 7: - return NpadIdType::Player8; - case 8: - return NpadIdType::Handheld; - case 9: - return NpadIdType::Other; - default: - return NpadIdType::Invalid; - } -} - // This is nn::hid::NpadStyleIndex enum class NpadStyleIndex : u8 { None = 0, @@ -124,6 +257,27 @@ enum class NpadStyleSet : u32 { }; static_assert(sizeof(NpadStyleSet) == 4, "NpadStyleSet is an invalid size"); +// This is nn::hid::VibrationDevicePosition +enum class VibrationDevicePosition : u32 { + None = 0, + Left = 1, + Right = 2, +}; + +// This is nn::hid::VibrationDeviceType +enum class VibrationDeviceType : u32 { + Unknown = 0, + LinearResonantActuator = 1, + GcErm = 2, +}; + +// This is nn::hid::VibrationGcErmCommand +enum class VibrationGcErmCommand : u64 { + Stop = 0, + Start = 1, + StopHard = 2, +}; + // This is nn::hid::NpadStyleTag struct NpadStyleTag { union { @@ -220,53 +374,6 @@ struct LedPattern { }; }; -// This is nn::hid::NpadButton -enum class NpadButton : u64 { - None = 0, - A = 1U << 0, - B = 1U << 1, - X = 1U << 2, - Y = 1U << 3, - StickL = 1U << 4, - StickR = 1U << 5, - L = 1U << 6, - R = 1U << 7, - ZL = 1U << 8, - ZR = 1U << 9, - Plus = 1U << 10, - Minus = 1U << 11, - - Left = 1U << 12, - Up = 1U << 13, - Right = 1U << 14, - Down = 1U << 15, - - StickLLeft = 1U << 16, - StickLUp = 1U << 17, - StickLRight = 1U << 18, - StickLDown = 1U << 19, - - StickRLeft = 1U << 20, - StickRUp = 1U << 21, - StickRRight = 1U << 22, - StickRDown = 1U << 23, - - LeftSL = 1U << 24, - LeftSR = 1U << 25, - - RightSL = 1U << 26, - RightSR = 1U << 27, - - Palma = 1U << 28, - Verification = 1U << 29, - HandheldLeftB = 1U << 30, - LagonCLeft = 1U << 31, - LagonCUp = 1ULL << 32, - LagonCRight = 1ULL << 33, - LagonCDown = 1ULL << 34, -}; -DECLARE_ENUM_FLAG_OPERATORS(NpadButton); - struct NpadButtonState { union { NpadButton raw{}; @@ -342,13 +449,6 @@ struct DebugPadButton { }; static_assert(sizeof(DebugPadButton) == 0x4, "DebugPadButton is an invalid size"); -enum class DeviceIndex : u8 { - Left = 0, - Right = 1, - None = 2, - MaxDeviceIndex = 3, -}; - // This is nn::hid::ConsoleSixAxisSensorHandle struct ConsoleSixAxisSensorHandle { u8 unknown_1; @@ -383,20 +483,6 @@ struct VibrationDeviceHandle { }; static_assert(sizeof(VibrationDeviceHandle) == 4, "SixAxisSensorHandle is an invalid size"); -// This is nn::hid::VibrationDeviceType -enum class VibrationDeviceType : u32 { - Unknown = 0, - LinearResonantActuator = 1, - GcErm = 2, -}; - -// This is nn::hid::VibrationDevicePosition -enum class VibrationDevicePosition : u32 { - None = 0, - Left = 1, - Right = 2, -}; - // This is nn::hid::VibrationValue struct VibrationValue { f32 low_amplitude; @@ -406,13 +492,6 @@ struct VibrationValue { }; static_assert(sizeof(VibrationValue) == 0x10, "VibrationValue has incorrect size."); -// This is nn::hid::VibrationGcErmCommand -enum class VibrationGcErmCommand : u64 { - Stop = 0, - Start = 1, - StopHard = 2, -}; - // This is nn::hid::VibrationDeviceInfo struct VibrationDeviceInfo { VibrationDeviceType type{}; @@ -482,4 +561,61 @@ struct MouseState { MouseAttribute attribute; }; static_assert(sizeof(MouseState) == 0x28, "MouseState is an invalid size"); + +/// Converts a NpadIdType to an array index. +constexpr size_t NpadIdTypeToIndex(NpadIdType npad_id_type) { + switch (npad_id_type) { + case NpadIdType::Player1: + return 0; + case NpadIdType::Player2: + return 1; + case NpadIdType::Player3: + return 2; + case NpadIdType::Player4: + return 3; + case NpadIdType::Player5: + return 4; + case NpadIdType::Player6: + return 5; + case NpadIdType::Player7: + return 6; + case NpadIdType::Player8: + return 7; + case NpadIdType::Handheld: + return 8; + case NpadIdType::Other: + return 9; + default: + return 0; + } +} + +/// Converts an array index to a NpadIdType +constexpr NpadIdType IndexToNpadIdType(size_t index) { + switch (index) { + case 0: + return NpadIdType::Player1; + case 1: + return NpadIdType::Player2; + case 2: + return NpadIdType::Player3; + case 3: + return NpadIdType::Player4; + case 4: + return NpadIdType::Player5; + case 5: + return NpadIdType::Player6; + case 6: + return NpadIdType::Player7; + case 7: + return NpadIdType::Player8; + case 8: + return NpadIdType::Handheld; + case 9: + return NpadIdType::Other; + default: + return NpadIdType::Invalid; + } +} + } // namespace Core::HID diff --git a/src/core/hle/service/hid/controllers/keyboard.cpp b/src/core/hle/service/hid/controllers/keyboard.cpp index d6505dbc5..0ef8af0e6 100644 --- a/src/core/hle/service/hid/controllers/keyboard.cpp +++ b/src/core/hle/service/hid/controllers/keyboard.cpp @@ -42,6 +42,7 @@ void Controller_Keyboard::OnUpdate(const Core::Timing::CoreTiming& core_timing, 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); } diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 496b55d0e..e740b4331 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -35,8 +35,9 @@ 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 motion_update_ns = std::chrono::nanoseconds{5 * 1000 * 1000}; // (5ms, 200Hz) +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) constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000; IAppletResource::IAppletResource(Core::System& system_, @@ -78,14 +79,21 @@ 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::MotionPadCallback", + "HID::UpdateMotionCallback", [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(); @@ -101,6 +109,7 @@ 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); } @@ -117,18 +126,36 @@ void IAppletResource::UpdateControllers(std::uintptr_t user_data, auto& core_timing = system.CoreTiming(); for (const auto& controller : controllers) { + // Keyboard has it's own update event + if (controller == controllers[static_cast(HidController::Keyboard)]) { + continue; + } 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 > motion_update_ns) { + if (ns_late > pad_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(); diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index 973e6a8ac..bbad165f8 100644 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h @@ -70,11 +70,13 @@ private: 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)> diff --git a/src/input_common/drivers/keyboard.cpp b/src/input_common/drivers/keyboard.cpp index 549704e89..328fe1ac1 100644 --- a/src/input_common/drivers/keyboard.cpp +++ b/src/input_common/drivers/keyboard.cpp @@ -3,26 +3,71 @@ // Refer to the license.txt file included #include "common/param_package.h" +#include "common/settings_input.h" #include "input_common/drivers/keyboard.h" namespace InputCommon { -constexpr PadIdentifier identifier = { +constexpr PadIdentifier key_identifier = { .guid = Common::UUID{Common::INVALID_UUID}, .port = 0, .pad = 0, }; +constexpr PadIdentifier modifier_identifier = { + .guid = Common::UUID{Common::INVALID_UUID}, + .port = 0, + .pad = 1, +}; Keyboard::Keyboard(const std::string& input_engine_) : InputEngine(input_engine_) { - PreSetController(identifier); + PreSetController(key_identifier); + PreSetController(modifier_identifier); } void Keyboard::PressKey(int key_code) { - SetButton(identifier, key_code, true); + SetButton(key_identifier, key_code, true); } void Keyboard::ReleaseKey(int key_code) { - SetButton(identifier, key_code, false); + SetButton(key_identifier, key_code, false); +} + +void Keyboard::SetModifiers(int key_modifiers) { + for (int i = 0; i < 32; ++i) { + bool key_value = ((key_modifiers >> i) & 0x1) != 0; + SetButton(modifier_identifier, i, key_value); + // Use the modifier to press the key button equivalent + switch (i) { + case Settings::NativeKeyboard::LeftControl: + SetButton(key_identifier, Settings::NativeKeyboard::LeftControlKey, key_value); + break; + case Settings::NativeKeyboard::LeftShift: + SetButton(key_identifier, Settings::NativeKeyboard::LeftShiftKey, key_value); + break; + case Settings::NativeKeyboard::LeftAlt: + SetButton(key_identifier, Settings::NativeKeyboard::LeftAltKey, key_value); + break; + case Settings::NativeKeyboard::LeftMeta: + SetButton(key_identifier, Settings::NativeKeyboard::LeftMetaKey, key_value); + break; + case Settings::NativeKeyboard::RightControl: + SetButton(key_identifier, Settings::NativeKeyboard::RightControlKey, key_value); + break; + case Settings::NativeKeyboard::RightShift: + SetButton(key_identifier, Settings::NativeKeyboard::RightShiftKey, key_value); + break; + case Settings::NativeKeyboard::RightAlt: + SetButton(key_identifier, Settings::NativeKeyboard::RightAltKey, key_value); + break; + case Settings::NativeKeyboard::RightMeta: + SetButton(key_identifier, Settings::NativeKeyboard::RightMetaKey, key_value); + break; + default: + // Other modifier keys should be pressed with PressKey since they stay enabled until + // next press + break; + } + } } void Keyboard::ReleaseAllKeys() { diff --git a/src/input_common/drivers/keyboard.h b/src/input_common/drivers/keyboard.h index 46fe78576..2ab92fd6c 100644 --- a/src/input_common/drivers/keyboard.h +++ b/src/input_common/drivers/keyboard.h @@ -28,6 +28,13 @@ public: */ void ReleaseKey(int key_code); + /** + * Sets the status of all keyboard modifier keys + * @param key_modifiers the code of the key to release + */ + void SetModifiers(int key_modifiers); + + /// Sets all keys to the non pressed state void ReleaseAllKeys(); /// Used for automapping features diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp index df36a337c..ae2518f53 100644 --- a/src/input_common/main.cpp +++ b/src/input_common/main.cpp @@ -402,6 +402,15 @@ 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 a4a24d076..9ea395465 100644 --- a/src/input_common/main.h +++ b/src/input_common/main.h @@ -134,6 +134,9 @@ private: /// 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. std::string GenerateAnalogParamFromKeys(int key_up, int key_down, int key_left, int key_right, int key_modifier, float modifier_scale); diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 3c5590a01..61513a5b4 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -392,15 +392,287 @@ 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()) { - input_subsystem->GetKeyboard()->PressKey(event->key()); + 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); } } void GRenderWindow::keyReleaseEvent(QKeyEvent* event) { if (!event->isAutoRepeat()) { - input_subsystem->GetKeyboard()->ReleaseKey(event->key()); + const auto moddifier = QtModifierToSwitchModdifier(event->nativeModifiers()); + const auto key = QtKeyToSwitchKey(Qt::Key(event->key())); + input_subsystem->GetKeyboard()->SetModifiers(moddifier); + input_subsystem->GetKeyboard()->ReleaseKey(key); } } diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h index 95594f81c..c42d139be 100644 --- a/src/yuzu/bootmanager.h +++ b/src/yuzu/bootmanager.h @@ -158,6 +158,12 @@ 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; diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index 7669fe474..ccf274895 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -65,157 +65,6 @@ 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 @@ -496,14 +345,14 @@ void Config::ReadDebugValues() { void Config::ReadKeyboardValues() { ReadBasicSetting(Settings::values.keyboard_enabled); - 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); + 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)); + } } void Config::ReadMouseValues() { -- cgit v1.2.3 From bca299e8e0489867f7d4bbfd264e221e7e61ae1e Mon Sep 17 00:00:00 2001 From: german77 Date: Sun, 14 Nov 2021 10:45:07 -0600 Subject: input_common: Allow keyboard to be backwards compatible --- src/common/settings.h | 2 -- src/core/hid/emulated_devices.cpp | 28 +++++++++++++++---- src/input_common/drivers/keyboard.cpp | 52 ++++++++++++++++++++++++++--------- src/input_common/drivers/keyboard.h | 14 +++++++++- src/input_common/input_mapping.cpp | 25 +++++++++++++++++ src/input_common/input_mapping.h | 7 +++++ src/input_common/main.cpp | 9 ------ src/input_common/main.h | 3 -- src/yuzu/bootmanager.cpp | 14 ++++++---- src/yuzu/configuration/config.cpp | 9 ------ 10 files changed, 115 insertions(+), 48 deletions(-) (limited to 'src/input_common/drivers') diff --git a/src/common/settings.h b/src/common/settings.h index b52d0d1d0..ee9e0b5a1 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -572,8 +572,6 @@ struct Values { BasicSetting emulate_analog_keyboard{false, "emulate_analog_keyboard"}; BasicSetting keyboard_enabled{false, "keyboard_enabled"}; - KeyboardKeysRaw keyboard_keys; - KeyboardModsRaw keyboard_mods; BasicSetting debug_pad_enabled{false, "debug_pad_enabled"}; ButtonsRaw debug_pad_buttons; diff --git a/src/core/hid/emulated_devices.cpp b/src/core/hid/emulated_devices.cpp index 0d840a003..45e0bd80d 100644 --- a/src/core/hid/emulated_devices.cpp +++ b/src/core/hid/emulated_devices.cpp @@ -29,13 +29,29 @@ void EmulatedDevices::ReloadInput() { mouse_button_devices.begin(), Common::Input::CreateDevice); - std::transform(Settings::values.keyboard_keys.begin(), Settings::values.keyboard_keys.end(), - keyboard_devices.begin(), - Common::Input::CreateDeviceFromString); + std::size_t key_index = 0; + for (auto& keyboard_device : keyboard_devices) { + // Keyboard keys are only mapped on port 1, pad 0 + Common::ParamPackage keyboard_params; + keyboard_params.Set("engine", "keyboard"); + keyboard_params.Set("button", static_cast(key_index)); + keyboard_params.Set("port", 1); + keyboard_params.Set("pad", 0); + keyboard_device = Common::Input::CreateDevice(keyboard_params); + key_index++; + } - std::transform(Settings::values.keyboard_mods.begin(), Settings::values.keyboard_mods.end(), - keyboard_modifier_devices.begin(), - Common::Input::CreateDeviceFromString); + key_index = 0; + for (auto& keyboard_device : keyboard_modifier_devices) { + // Keyboard moddifiers are only mapped on port 1, pad 1 + Common::ParamPackage keyboard_params; + keyboard_params.Set("engine", "keyboard"); + keyboard_params.Set("button", static_cast(key_index)); + keyboard_params.Set("port", 1); + keyboard_params.Set("pad", 1); + keyboard_device = Common::Input::CreateDevice(keyboard_params); + key_index++; + } for (std::size_t index = 0; index < mouse_button_devices.size(); ++index) { if (!mouse_button_devices[index]) { diff --git a/src/input_common/drivers/keyboard.cpp b/src/input_common/drivers/keyboard.cpp index 328fe1ac1..23b0c0ccf 100644 --- a/src/input_common/drivers/keyboard.cpp +++ b/src/input_common/drivers/keyboard.cpp @@ -13,15 +13,26 @@ constexpr PadIdentifier key_identifier = { .port = 0, .pad = 0, }; -constexpr PadIdentifier modifier_identifier = { +constexpr PadIdentifier keyboard_key_identifier = { .guid = Common::UUID{Common::INVALID_UUID}, - .port = 0, + .port = 1, + .pad = 0, +}; +constexpr PadIdentifier keyboard_modifier_identifier = { + .guid = Common::UUID{Common::INVALID_UUID}, + .port = 1, .pad = 1, }; Keyboard::Keyboard(const std::string& input_engine_) : InputEngine(input_engine_) { + // Keyboard is broken into 3 diferent sets: + // key: Unfiltered intended for controllers. + // keyboard_key: Allows only Settings::NativeKeyboard::Keys intended for keyboard emulation. + // keyboard_modifier: Allows only Settings::NativeKeyboard::Modifiers intended for keyboard + // emulation. PreSetController(key_identifier); - PreSetController(modifier_identifier); + PreSetController(keyboard_key_identifier); + PreSetController(keyboard_modifier_identifier); } void Keyboard::PressKey(int key_code) { @@ -32,35 +43,50 @@ void Keyboard::ReleaseKey(int key_code) { SetButton(key_identifier, key_code, false); } -void Keyboard::SetModifiers(int key_modifiers) { +void Keyboard::PressKeyboardKey(int key_index) { + if (key_index == Settings::NativeKeyboard::None) { + return; + } + SetButton(keyboard_key_identifier, key_index, true); +} + +void Keyboard::ReleaseKeyboardKey(int key_index) { + if (key_index == Settings::NativeKeyboard::None) { + return; + } + SetButton(keyboard_key_identifier, key_index, false); +} + +void Keyboard::SetKeyboardModifiers(int key_modifiers) { for (int i = 0; i < 32; ++i) { bool key_value = ((key_modifiers >> i) & 0x1) != 0; - SetButton(modifier_identifier, i, key_value); + SetButton(keyboard_modifier_identifier, i, key_value); // Use the modifier to press the key button equivalent switch (i) { case Settings::NativeKeyboard::LeftControl: - SetButton(key_identifier, Settings::NativeKeyboard::LeftControlKey, key_value); + SetButton(keyboard_key_identifier, Settings::NativeKeyboard::LeftControlKey, key_value); break; case Settings::NativeKeyboard::LeftShift: - SetButton(key_identifier, Settings::NativeKeyboard::LeftShiftKey, key_value); + SetButton(keyboard_key_identifier, Settings::NativeKeyboard::LeftShiftKey, key_value); break; case Settings::NativeKeyboard::LeftAlt: - SetButton(key_identifier, Settings::NativeKeyboard::LeftAltKey, key_value); + SetButton(keyboard_key_identifier, Settings::NativeKeyboard::LeftAltKey, key_value); break; case Settings::NativeKeyboard::LeftMeta: - SetButton(key_identifier, Settings::NativeKeyboard::LeftMetaKey, key_value); + SetButton(keyboard_key_identifier, Settings::NativeKeyboard::LeftMetaKey, key_value); break; case Settings::NativeKeyboard::RightControl: - SetButton(key_identifier, Settings::NativeKeyboard::RightControlKey, key_value); + SetButton(keyboard_key_identifier, Settings::NativeKeyboard::RightControlKey, + key_value); break; case Settings::NativeKeyboard::RightShift: - SetButton(key_identifier, Settings::NativeKeyboard::RightShiftKey, key_value); + SetButton(keyboard_key_identifier, Settings::NativeKeyboard::RightShiftKey, key_value); break; case Settings::NativeKeyboard::RightAlt: - SetButton(key_identifier, Settings::NativeKeyboard::RightAltKey, key_value); + SetButton(keyboard_key_identifier, Settings::NativeKeyboard::RightAltKey, key_value); break; case Settings::NativeKeyboard::RightMeta: - SetButton(key_identifier, Settings::NativeKeyboard::RightMetaKey, key_value); + SetButton(keyboard_key_identifier, Settings::NativeKeyboard::RightMetaKey, key_value); break; default: // Other modifier keys should be pressed with PressKey since they stay enabled until diff --git a/src/input_common/drivers/keyboard.h b/src/input_common/drivers/keyboard.h index 2ab92fd6c..ad123b136 100644 --- a/src/input_common/drivers/keyboard.h +++ b/src/input_common/drivers/keyboard.h @@ -28,11 +28,23 @@ public: */ void ReleaseKey(int key_code); + /** + * Sets the status of the keyboard key to pressed + * @param key_index index of the key to press + */ + void PressKeyboardKey(int key_index); + + /** + * Sets the status of the keyboard key to released + * @param key_index index of the key to release + */ + void ReleaseKeyboardKey(int key_index); + /** * Sets the status of all keyboard modifier keys * @param key_modifiers the code of the key to release */ - void SetModifiers(int key_modifiers); + void SetKeyboardModifiers(int key_modifiers); /// Sets all keys to the non pressed state void ReleaseAllKeys(); diff --git a/src/input_common/input_mapping.cpp b/src/input_common/input_mapping.cpp index 0ffc71028..0eeeff372 100644 --- a/src/input_common/input_mapping.cpp +++ b/src/input_common/input_mapping.cpp @@ -28,6 +28,10 @@ void MappingFactory::RegisterInput(const MappingData& data) { if (!is_enabled) { return; } + if (!IsDriverValid(data)) { + return; + } + switch (input_type) { case Polling::InputType::Button: RegisterButton(data); @@ -168,4 +172,25 @@ void MappingFactory::RegisterMotion(const MappingData& data) { input_queue.Push(new_input); } +bool MappingFactory::IsDriverValid(const MappingData& data) const { + // Only port 0 can be mapped on the keyboard + if (data.engine == "keyboard" && data.pad.port != 0) { + return false; + } + // The following drivers don't need to be mapped + if (data.engine == "tas") { + return false; + } + if (data.engine == "touch") { + return false; + } + if (data.engine == "touch_from_button") { + return false; + } + if (data.engine == "analog_from_button") { + return false; + } + return true; +} + } // namespace InputCommon diff --git a/src/input_common/input_mapping.h b/src/input_common/input_mapping.h index 2622dba70..44eb8ad9a 100644 --- a/src/input_common/input_mapping.h +++ b/src/input_common/input_mapping.h @@ -66,6 +66,13 @@ private: */ void RegisterMotion(const MappingData& data); + /** + * Returns true if driver can be mapped + * @param "data": An struct containing all the information needed to create a proper + * ParamPackage + */ + bool IsDriverValid(const MappingData& data) const; + Common::SPSCQueue input_queue; Polling::InputType input_type{Polling::InputType::None}; bool is_enabled{}; diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp index ae2518f53..df36a337c 100644 --- a/src/input_common/main.cpp +++ b/src/input_common/main.cpp @@ -402,15 +402,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..a4a24d076 100644 --- a/src/input_common/main.h +++ b/src/input_common/main.h @@ -134,9 +134,6 @@ private: /// 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. std::string GenerateAnalogParamFromKeys(int key_up, int key_down, int key_left, int key_right, int key_modifier, float modifier_scale); diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 61513a5b4..9f4d1aac3 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -609,7 +609,7 @@ int GRenderWindow::QtKeyToSwitchKey(Qt::Key qt_key) { return Settings::NativeKeyboard::ZenkakuHankaku; // Modifier keys are handled by the modifier property default: - return 0; + return Settings::NativeKeyboard::None; } } @@ -662,8 +662,10 @@ void GRenderWindow::keyPressEvent(QKeyEvent* event) { // 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()->SetKeyboardModifiers(moddifier); + input_subsystem->GetKeyboard()->PressKeyboardKey(key); + // This is used for gamepads + input_subsystem->GetKeyboard()->PressKey(event->key()); } } @@ -671,8 +673,10 @@ 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()->SetKeyboardModifiers(moddifier); + input_subsystem->GetKeyboard()->ReleaseKeyboardKey(key); + // This is used for gamepads + input_subsystem->GetKeyboard()->ReleaseKey(event->key()); } } diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index ccf274895..5865359fe 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -344,15 +344,6 @@ 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)); - } } void Config::ReadMouseValues() { -- cgit v1.2.3 From 654d76e79e84a3384fa503fac9003a5d0a32f28b Mon Sep 17 00:00:00 2001 From: german77 Date: Sun, 14 Nov 2021 14:09:29 -0600 Subject: core/hid: Fully implement native mouse --- src/common/settings.h | 1 - src/common/settings_input.h | 15 +- src/core/hid/emulated_console.cpp | 11 +- src/core/hid/emulated_devices.cpp | 124 ++++++-- src/core/hid/emulated_devices.h | 56 ++-- src/core/hid/input_converter.cpp | 21 ++ src/core/hid/input_converter.h | 9 + src/core/hle/service/hid/controllers/mouse.cpp | 9 +- src/input_common/drivers/mouse.cpp | 31 +- src/input_common/drivers/mouse.h | 7 + src/yuzu/CMakeLists.txt | 3 - src/yuzu/bootmanager.cpp | 6 + src/yuzu/bootmanager.h | 1 + src/yuzu/configuration/config.cpp | 30 -- src/yuzu/configuration/configure_input.cpp | 4 - .../configuration/configure_input_advanced.cpp | 2 - src/yuzu/configuration/configure_input_advanced.ui | 204 ++++++------- .../configuration/configure_mouse_advanced.cpp | 247 --------------- src/yuzu/configuration/configure_mouse_advanced.h | 72 ----- src/yuzu/configuration/configure_mouse_advanced.ui | 335 --------------------- src/yuzu_cmd/config.cpp | 174 ----------- 21 files changed, 323 insertions(+), 1039 deletions(-) delete mode 100644 src/yuzu/configuration/configure_mouse_advanced.cpp delete mode 100644 src/yuzu/configuration/configure_mouse_advanced.h delete mode 100644 src/yuzu/configuration/configure_mouse_advanced.ui (limited to 'src/input_common/drivers') diff --git a/src/common/settings.h b/src/common/settings.h index ee9e0b5a1..d7410fa9b 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -568,7 +568,6 @@ struct Values { BasicSetting mouse_panning{false, "mouse_panning"}; BasicRangedSetting mouse_panning_sensitivity{10, 1, 100, "mouse_panning_sensitivity"}; BasicSetting mouse_enabled{false, "mouse_enabled"}; - MouseButtonsRaw mouse_buttons; BasicSetting emulate_analog_keyboard{false, "emulate_analog_keyboard"}; BasicSetting keyboard_enabled{false, "keyboard_enabled"}; diff --git a/src/common/settings_input.h b/src/common/settings_input.h index a2982fca4..9a8804488 100644 --- a/src/common/settings_input.h +++ b/src/common/settings_input.h @@ -126,6 +126,17 @@ constexpr int NUM_MOUSE_HID = NumMouseButtons; extern const std::array mapping; } // namespace NativeMouseButton +namespace NativeMouseWheel { +enum Values { + X, + Y, + + NumMouseWheels, +}; + +extern const std::array mapping; +} // namespace NativeMouseWheel + namespace NativeKeyboard { enum Keys { None, @@ -348,10 +359,6 @@ using ButtonsRaw = std::array; using MotionsRaw = std::array; using VibrationsRaw = std::array; -using MouseButtonsRaw = std::array; -using KeyboardKeysRaw = std::array; -using KeyboardModsRaw = std::array; - constexpr u32 JOYCON_BODY_NEON_RED = 0xFF3C28; constexpr u32 JOYCON_BUTTONS_NEON_RED = 0x1E0A0A; constexpr u32 JOYCON_BODY_NEON_BLUE = 0x0AB9E6; diff --git a/src/core/hid/emulated_console.cpp b/src/core/hid/emulated_console.cpp index 374dd5d41..b224932dc 100644 --- a/src/core/hid/emulated_console.cpp +++ b/src/core/hid/emulated_console.cpp @@ -24,7 +24,10 @@ void EmulatedConsole::SetTouchParams() { std::size_t index = 0; // Hardcode mouse, touchscreen and cemuhook parameters - touch_params[index++] = Common::ParamPackage{"engine:mouse,axis_x:10,axis_y:11,button:0"}; + if (!Settings::values.mouse_enabled) { + // We can't use mouse as touch if native mouse is enabled + touch_params[index++] = Common::ParamPackage{"engine:mouse,axis_x:10,axis_y:11,button:0"}; + } touch_params[index++] = Common::ParamPackage{"engine:touch,axis_x:0,axis_y:1,button:0"}; touch_params[index++] = Common::ParamPackage{"engine:touch,axis_x:2,axis_y:3,button:1"}; touch_params[index++] = Common::ParamPackage{"engine:cemuhookudp,axis_x:0,axis_y:1,button:0"}; @@ -36,6 +39,9 @@ void EmulatedConsole::SetTouchParams() { // Map the rest of the fingers from touch from button configuration for (const auto& config_entry : touch_buttons) { + if (index >= touch_params.size()) { + continue; + } Common::ParamPackage params{config_entry}; Common::ParamPackage touch_button_params; const int x = params.Get("x", 0); @@ -49,9 +55,6 @@ void EmulatedConsole::SetTouchParams() { touch_button_params.Set("touch_id", static_cast(index)); touch_params[index] = touch_button_params; index++; - if (index >= touch_params.size()) { - return; - } } } diff --git a/src/core/hid/emulated_devices.cpp b/src/core/hid/emulated_devices.cpp index 45e0bd80d..70a494097 100644 --- a/src/core/hid/emulated_devices.cpp +++ b/src/core/hid/emulated_devices.cpp @@ -15,21 +15,34 @@ EmulatedDevices::EmulatedDevices() = default; EmulatedDevices::~EmulatedDevices() = default; void EmulatedDevices::ReloadFromSettings() { - const auto& mouse = Settings::values.mouse_buttons; - - for (std::size_t index = 0; index < mouse.size(); ++index) { - mouse_button_params[index] = Common::ParamPackage(mouse[index]); - } ReloadInput(); } void EmulatedDevices::ReloadInput() { - std::transform(mouse_button_params.begin() + Settings::NativeMouseButton::MOUSE_HID_BEGIN, - mouse_button_params.begin() + Settings::NativeMouseButton::MOUSE_HID_END, - mouse_button_devices.begin(), - Common::Input::CreateDevice); - + // If you load any device here add the equivalent to the UnloadInput() function std::size_t key_index = 0; + for (auto& mouse_device : mouse_button_devices) { + Common::ParamPackage mouse_params; + mouse_params.Set("engine", "mouse"); + mouse_params.Set("button", static_cast(key_index)); + mouse_device = Common::Input::CreateDevice(mouse_params); + key_index++; + } + + mouse_stick_device = Common::Input::CreateDeviceFromString( + "engine:mouse,axis_x:0,axis_y:1"); + + // First two axis are reserved for mouse position + key_index = 2; + for (auto& mouse_device : mouse_analog_devices) { + Common::ParamPackage mouse_params; + mouse_params.Set("engine", "mouse"); + mouse_params.Set("axis", static_cast(key_index)); + mouse_device = Common::Input::CreateDevice(mouse_params); + key_index++; + } + + key_index = 0; for (auto& keyboard_device : keyboard_devices) { // Keyboard keys are only mapped on port 1, pad 0 Common::ParamPackage keyboard_params; @@ -64,6 +77,23 @@ void EmulatedDevices::ReloadInput() { mouse_button_devices[index]->SetCallback(button_callback); } + for (std::size_t index = 0; index < mouse_analog_devices.size(); ++index) { + if (!mouse_analog_devices[index]) { + continue; + } + Common::Input::InputCallback button_callback{ + [this, index](Common::Input::CallbackStatus callback) { + SetMouseAnalog(callback, index); + }}; + mouse_analog_devices[index]->SetCallback(button_callback); + } + + if (mouse_stick_device) { + Common::Input::InputCallback button_callback{ + [this](Common::Input::CallbackStatus callback) { SetMouseStick(callback); }}; + mouse_stick_device->SetCallback(button_callback); + } + for (std::size_t index = 0; index < keyboard_devices.size(); ++index) { if (!keyboard_devices[index]) { continue; @@ -91,6 +121,10 @@ void EmulatedDevices::UnloadInput() { for (auto& button : mouse_button_devices) { button.reset(); } + for (auto& analog : mouse_analog_devices) { + analog.reset(); + } + mouse_stick_device.reset(); for (auto& button : keyboard_devices) { button.reset(); } @@ -116,12 +150,6 @@ void EmulatedDevices::SaveCurrentConfig() { if (!is_configuring) { return; } - - auto& mouse = Settings::values.mouse_buttons; - - for (std::size_t index = 0; index < mouse.size(); ++index) { - mouse[index] = mouse_button_params[index].Serialize(); - } } void EmulatedDevices::RestoreConfig() { @@ -131,21 +159,6 @@ void EmulatedDevices::RestoreConfig() { ReloadFromSettings(); } -Common::ParamPackage EmulatedDevices::GetMouseButtonParam(std::size_t index) const { - if (index >= mouse_button_params.size()) { - return {}; - } - return mouse_button_params[index]; -} - -void EmulatedDevices::SetMouseButtonParam(std::size_t index, Common::ParamPackage param) { - if (index >= mouse_button_params.size()) { - return; - } - mouse_button_params[index] = param; - ReloadInput(); -} - void EmulatedDevices::SetKeyboardButton(Common::Input::CallbackStatus callback, std::size_t index) { if (index >= device_status.keyboard_values.size()) { return; @@ -334,6 +347,51 @@ void EmulatedDevices::SetMouseButton(Common::Input::CallbackStatus callback, std TriggerOnChange(DeviceTriggerType::Mouse); } +void EmulatedDevices::SetMouseAnalog(Common::Input::CallbackStatus callback, std::size_t index) { + if (index >= device_status.mouse_analog_values.size()) { + return; + } + std::lock_guard lock{mutex}; + const auto analog_value = TransformToAnalog(callback); + + device_status.mouse_analog_values[index] = analog_value; + + if (is_configuring) { + device_status.mouse_position_state = {}; + TriggerOnChange(DeviceTriggerType::Mouse); + return; + } + + switch (index) { + case Settings::NativeMouseWheel::X: + device_status.mouse_wheel_state.x = static_cast(analog_value.value); + break; + case Settings::NativeMouseWheel::Y: + device_status.mouse_wheel_state.y = static_cast(analog_value.value); + break; + } + + TriggerOnChange(DeviceTriggerType::Mouse); +} + +void EmulatedDevices::SetMouseStick(Common::Input::CallbackStatus callback) { + std::lock_guard lock{mutex}; + const auto stick_value = TransformToStick(callback); + + device_status.mouse_stick_value = stick_value; + + if (is_configuring) { + device_status.mouse_position_state = {}; + TriggerOnChange(DeviceTriggerType::Mouse); + return; + } + + device_status.mouse_position_state.x = stick_value.x.value; + device_status.mouse_position_state.y = stick_value.y.value; + + TriggerOnChange(DeviceTriggerType::Mouse); +} + KeyboardValues EmulatedDevices::GetKeyboardValues() const { return device_status.keyboard_values; } @@ -362,6 +420,10 @@ MousePosition EmulatedDevices::GetMousePosition() const { return device_status.mouse_position_state; } +AnalogStickState EmulatedDevices::GetMouseDeltaWheel() const { + return device_status.mouse_wheel_state; +} + void EmulatedDevices::TriggerOnChange(DeviceTriggerType type) { for (const auto& poller_pair : callback_list) { const InterfaceUpdateCallback& poller = poller_pair.second; diff --git a/src/core/hid/emulated_devices.h b/src/core/hid/emulated_devices.h index d49d6d78a..49edfd255 100644 --- a/src/core/hid/emulated_devices.h +++ b/src/core/hid/emulated_devices.h @@ -17,13 +17,15 @@ #include "core/hid/hid_types.h" namespace Core::HID { - using KeyboardDevices = std::array, Settings::NativeKeyboard::NumKeyboardKeys>; using KeyboardModifierDevices = std::array, Settings::NativeKeyboard::NumKeyboardMods>; using MouseButtonDevices = std::array, Settings::NativeMouseButton::NumMouseButtons>; +using MouseAnalogDevices = std::array, + Settings::NativeMouseWheel::NumMouseWheels>; +using MouseStickDevice = std::unique_ptr; using MouseButtonParams = std::array; @@ -34,12 +36,13 @@ using KeyboardModifierValues = std::array; using MouseButtonValues = std::array; +using MouseAnalogValues = + std::array; +using MouseStickValue = Common::Input::StickStatus; struct MousePosition { - s32 x; - s32 y; - s32 delta_wheel_x; - s32 delta_wheel_y; + f32 x; + f32 y; }; struct DeviceStatus { @@ -47,12 +50,15 @@ struct DeviceStatus { KeyboardValues keyboard_values{}; KeyboardModifierValues keyboard_moddifier_values{}; MouseButtonValues mouse_button_values{}; + MouseAnalogValues mouse_analog_values{}; + MouseStickValue mouse_stick_value{}; // Data for HID serices KeyboardKey keyboard_state{}; KeyboardModifier keyboard_moddifier_state{}; MouseButton mouse_button_state{}; MousePosition mouse_position_state{}; + AnalogStickState mouse_wheel_state{}; }; enum class DeviceTriggerType { @@ -102,15 +108,6 @@ public: /// Reverts any mapped changes made that weren't saved void RestoreConfig(); - /// Returns the current mapped mouse button device - Common::ParamPackage GetMouseButtonParam(std::size_t index) const; - - /** - * Updates the current mapped mouse button device - * @param ParamPackage with controller data to be mapped - */ - void SetMouseButtonParam(std::size_t index, Common::ParamPackage param); - /// Returns the latest status of button input from the keyboard with parameters KeyboardValues GetKeyboardValues() const; @@ -132,9 +129,12 @@ public: /// Returns the latest mouse coordinates MousePosition GetMousePosition() const; + /// Returns the latest mouse wheel change + AnalogStickState GetMouseDeltaWheel() const; + /** * Adds a callback to the list of events - * @param ConsoleUpdateCallback that will be triggered + * @param InterfaceUpdateCallback that will be triggered * @return an unique key corresponding to the callback index in the list */ int SetCallback(InterfaceUpdateCallback update_callback); @@ -150,26 +150,40 @@ private: void UpdateKey(std::size_t key_index, bool status); /** - * Updates the touch status of the console + * Updates the touch status of the keyboard device * @param callback: A CallbackStatus containing the key status * @param index: key ID to be updated */ void SetKeyboardButton(Common::Input::CallbackStatus callback, std::size_t index); /** - * Updates the touch status of the console + * Updates the keyboard status of the keyboard device * @param callback: A CallbackStatus containing the modifier key status * @param index: modifier key ID to be updated */ void SetKeyboardModifier(Common::Input::CallbackStatus callback, std::size_t index); /** - * Updates the touch status of the console + * Updates the mouse button status of the mouse device * @param callback: A CallbackStatus containing the button status - * @param index: Button ID of the to be updated + * @param index: Button ID to be updated */ void SetMouseButton(Common::Input::CallbackStatus callback, std::size_t index); + /** + * Updates the mouse wheel status of the mouse device + * @param callback: A CallbackStatus containing the wheel status + * @param index: wheel ID to be updated + */ + void SetMouseAnalog(Common::Input::CallbackStatus callback, std::size_t index); + + /** + * Updates the mouse position status of the mouse device + * @param callback: A CallbackStatus containing the position status + * @param index: stick ID to be updated + */ + void SetMouseStick(Common::Input::CallbackStatus callback); + /** * Triggers a callback that something has changed on the device status * @param Input type of the event to trigger @@ -178,11 +192,11 @@ private: bool is_configuring{false}; - MouseButtonParams mouse_button_params; - KeyboardDevices keyboard_devices; KeyboardModifierDevices keyboard_modifier_devices; MouseButtonDevices mouse_button_devices; + MouseAnalogDevices mouse_analog_devices; + MouseStickDevice mouse_stick_device; mutable std::mutex mutex; std::unordered_map callback_list; diff --git a/src/core/hid/input_converter.cpp b/src/core/hid/input_converter.cpp index 480b862fd..c4e653956 100644 --- a/src/core/hid/input_converter.cpp +++ b/src/core/hid/input_converter.cpp @@ -242,6 +242,27 @@ Common::Input::TriggerStatus TransformToTrigger(const Common::Input::CallbackSta return status; } +Common::Input::AnalogStatus TransformToAnalog(const Common::Input::CallbackStatus& callback) { + Common::Input::AnalogStatus status{}; + + switch (callback.type) { + case Common::Input::InputType::Analog: + status.properties = callback.analog_status.properties; + status.raw_value = callback.analog_status.raw_value; + break; + default: + LOG_ERROR(Input, "Conversion from type {} to analog not implemented", callback.type); + break; + } + + SanitizeAnalog(status, false); + + // Adjust if value is inverted + status.value = status.properties.inverted ? -status.value : status.value; + + return status; +} + void SanitizeAnalog(Common::Input::AnalogStatus& analog, bool clamp_value) { const auto& properties = analog.properties; float& raw_value = analog.raw_value; diff --git a/src/core/hid/input_converter.h b/src/core/hid/input_converter.h index 2a722b39f..1492489d7 100644 --- a/src/core/hid/input_converter.h +++ b/src/core/hid/input_converter.h @@ -68,6 +68,15 @@ Common::Input::TouchStatus TransformToTouch(const Common::Input::CallbackStatus& */ Common::Input::TriggerStatus TransformToTrigger(const Common::Input::CallbackStatus& callback); +/** + * Converts raw input data into a valid analog status. Applies offset, deadzone, range and + * invert properties to the output. + * + * @param Supported callbacks: Analog. + * @return A valid AnalogStatus object. + */ +Common::Input::AnalogStatus TransformToAnalog(const Common::Input::CallbackStatus& callback); + /** * Converts raw analog data into a valid analog value * @param An analog object containing raw data and properties, bool that determines if the value diff --git a/src/core/hle/service/hid/controllers/mouse.cpp b/src/core/hle/service/hid/controllers/mouse.cpp index 83e69ca94..9c408e7f4 100644 --- a/src/core/hle/service/hid/controllers/mouse.cpp +++ b/src/core/hle/service/hid/controllers/mouse.cpp @@ -38,13 +38,14 @@ void Controller_Mouse::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* if (Settings::values.mouse_enabled) { const auto& mouse_button_state = emulated_devices->GetMouseButtons(); const auto& mouse_position_state = emulated_devices->GetMousePosition(); + const auto& mouse_wheel_state = emulated_devices->GetMouseDeltaWheel(); next_state.attribute.is_connected.Assign(1); - next_state.x = mouse_position_state.x; - next_state.y = mouse_position_state.y; + next_state.x = static_cast(mouse_position_state.x * Layout::ScreenUndocked::Width); + next_state.y = static_cast(mouse_position_state.y * Layout::ScreenUndocked::Height); 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; + next_state.delta_wheel_x = mouse_wheel_state.x; + next_state.delta_wheel_y = mouse_wheel_state.y; next_state.button = mouse_button_state; } diff --git a/src/input_common/drivers/mouse.cpp b/src/input_common/drivers/mouse.cpp index afa92b458..478737db2 100644 --- a/src/input_common/drivers/mouse.cpp +++ b/src/input_common/drivers/mouse.cpp @@ -12,6 +12,10 @@ #include "input_common/drivers/mouse.h" namespace InputCommon { +constexpr int mouse_axis_x = 0; +constexpr int mouse_axis_y = 1; +constexpr int wheel_axis_x = 2; +constexpr int wheel_axis_y = 3; constexpr int touch_axis_x = 10; constexpr int touch_axis_y = 11; constexpr PadIdentifier identifier = { @@ -22,6 +26,12 @@ constexpr PadIdentifier identifier = { Mouse::Mouse(const std::string input_engine_) : InputEngine(input_engine_) { PreSetController(identifier); + PreSetAxis(identifier, mouse_axis_x); + PreSetAxis(identifier, mouse_axis_y); + PreSetAxis(identifier, wheel_axis_x); + PreSetAxis(identifier, wheel_axis_y); + PreSetAxis(identifier, touch_axis_x); + PreSetAxis(identifier, touch_axis_x); update_thread = std::jthread([this](std::stop_token stop_token) { UpdateThread(stop_token); }); } @@ -34,14 +44,18 @@ void Mouse::UpdateThread(std::stop_token stop_token) { last_mouse_change *= 0.96f; const float sensitivity = Settings::values.mouse_panning_sensitivity.GetValue() * 0.022f; - SetAxis(identifier, 0, last_mouse_change.x * sensitivity); - SetAxis(identifier, 1, -last_mouse_change.y * sensitivity); + SetAxis(identifier, mouse_axis_x, last_mouse_change.x * sensitivity); + SetAxis(identifier, mouse_axis_y, -last_mouse_change.y * sensitivity); } if (mouse_panning_timout++ > 20) { StopPanning(); } std::this_thread::sleep_for(std::chrono::milliseconds(update_time)); + + // Reset wheel position + SetAxis(identifier, wheel_axis_x, 0); + SetAxis(identifier, wheel_axis_y, 0); } } @@ -89,8 +103,8 @@ void Mouse::MouseMove(int x, int y, f32 touch_x, f32 touch_y, int center_x, int if (button_pressed) { const auto mouse_move = Common::MakeVec(x, y) - mouse_origin; const float sensitivity = Settings::values.mouse_panning_sensitivity.GetValue() * 0.0012f; - SetAxis(identifier, 0, static_cast(mouse_move.x) * sensitivity); - SetAxis(identifier, 1, static_cast(-mouse_move.y) * sensitivity); + SetAxis(identifier, mouse_axis_x, static_cast(mouse_move.x) * sensitivity); + SetAxis(identifier, mouse_axis_y, static_cast(-mouse_move.y) * sensitivity); } } @@ -108,12 +122,17 @@ void Mouse::ReleaseButton(MouseButton button) { SetButton(identifier, static_cast(button), false); if (!Settings::values.mouse_panning) { - SetAxis(identifier, 0, 0); - SetAxis(identifier, 1, 0); + SetAxis(identifier, mouse_axis_x, 0); + SetAxis(identifier, mouse_axis_y, 0); } button_pressed = false; } +void Mouse::MouseWheelChange(int x, int y) { + SetAxis(identifier, wheel_axis_x, static_cast(x)); + SetAxis(identifier, wheel_axis_y, static_cast(y)); +} + void Mouse::ReleaseAllButtons() { ResetButtonState(); button_pressed = false; diff --git a/src/input_common/drivers/mouse.h b/src/input_common/drivers/mouse.h index 1be362b94..429502af9 100644 --- a/src/input_common/drivers/mouse.h +++ b/src/input_common/drivers/mouse.h @@ -52,6 +52,13 @@ public: */ void ReleaseButton(MouseButton button); + /** + * Sets the status of the mouse wheel + * @param x delta movement in the x direction + * @param y delta movement in the y direction + */ + void MouseWheelChange(int x, int y); + void ReleaseAllButtons(); std::vector GetInputDevices() const override; diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index d62fd566f..a44815e71 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt @@ -90,9 +90,6 @@ add_executable(yuzu configuration/configure_motion_touch.cpp configuration/configure_motion_touch.h configuration/configure_motion_touch.ui - configuration/configure_mouse_advanced.cpp - configuration/configure_mouse_advanced.h - configuration/configure_mouse_advanced.ui configuration/configure_per_game.cpp configuration/configure_per_game.h configuration/configure_per_game.ui diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 9f4d1aac3..1015e51b5 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -746,6 +746,12 @@ void GRenderWindow::mouseReleaseEvent(QMouseEvent* event) { input_subsystem->GetMouse()->ReleaseButton(button); } +void GRenderWindow::wheelEvent(QWheelEvent* event) { + const int x = event->delta(); + const int y = 0; + input_subsystem->GetMouse()->MouseWheelChange(x, y); +} + void GRenderWindow::TouchBeginEvent(const QTouchEvent* event) { QList touch_points = event->touchPoints(); for (const auto& touch_point : touch_points) { diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h index c42d139be..d6b2ab5f3 100644 --- a/src/yuzu/bootmanager.h +++ b/src/yuzu/bootmanager.h @@ -173,6 +173,7 @@ public: void mousePressEvent(QMouseEvent* event) override; void mouseMoveEvent(QMouseEvent* event) override; void mouseReleaseEvent(QMouseEvent* event) override; + void wheelEvent(QWheelEvent* event) override; bool event(QEvent* event) override; diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index 5865359fe..ae1684dd4 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -60,11 +60,6 @@ const std::array Config::default_stick_mod = { 0, }; -const std::array Config::default_mouse_buttons = - { - Qt::Key_BracketLeft, Qt::Key_BracketRight, Qt::Key_Apostrophe, Qt::Key_Minus, Qt::Key_Equal, -}; - // 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 @@ -348,22 +343,6 @@ void Config::ReadKeyboardValues() { void Config::ReadMouseValues() { ReadBasicSetting(Settings::values.mouse_enabled); - - for (int i = 0; i < Settings::NativeMouseButton::NumMouseButtons; ++i) { - const std::string default_param = - InputCommon::GenerateKeyboardParam(default_mouse_buttons[i]); - auto& mouse_buttons = Settings::values.mouse_buttons[i]; - - mouse_buttons = qt_config - ->value(QStringLiteral("mouse_") + - QString::fromUtf8(Settings::NativeMouseButton::mapping[i]), - QString::fromStdString(default_param)) - .toString() - .toStdString(); - if (mouse_buttons.empty()) { - mouse_buttons = default_param; - } - } } void Config::ReadTouchscreenValues() { @@ -947,15 +926,6 @@ void Config::SaveDebugValues() { void Config::SaveMouseValues() { WriteBasicSetting(Settings::values.mouse_enabled); - - for (int i = 0; i < Settings::NativeMouseButton::NumMouseButtons; ++i) { - const std::string default_param = - InputCommon::GenerateKeyboardParam(default_mouse_buttons[i]); - WriteSetting(QStringLiteral("mouse_") + - QString::fromStdString(Settings::NativeMouseButton::mapping[i]), - QString::fromStdString(Settings::values.mouse_buttons[i]), - QString::fromStdString(default_param)); - } } void Config::SaveTouchscreenValues() { diff --git a/src/yuzu/configuration/configure_input.cpp b/src/yuzu/configuration/configure_input.cpp index 99450bc7d..d53179dbb 100644 --- a/src/yuzu/configuration/configure_input.cpp +++ b/src/yuzu/configuration/configure_input.cpp @@ -24,7 +24,6 @@ #include "yuzu/configuration/configure_input_advanced.h" #include "yuzu/configuration/configure_input_player.h" #include "yuzu/configuration/configure_motion_touch.h" -#include "yuzu/configuration/configure_mouse_advanced.h" #include "yuzu/configuration/configure_touchscreen_advanced.h" #include "yuzu/configuration/configure_vibration.h" #include "yuzu/configuration/input_profiles.h" @@ -157,9 +156,6 @@ void ConfigureInput::Initialize(InputCommon::InputSubsystem* input_subsystem, CallConfigureDialog( *this, input_subsystem, profiles.get(), hid_core, is_powered_on); }); - connect(advanced, &ConfigureInputAdvanced::CallMouseConfigDialog, [this, input_subsystem] { - CallConfigureDialog(*this, input_subsystem); - }); connect(advanced, &ConfigureInputAdvanced::CallTouchscreenConfigDialog, [this] { CallConfigureDialog(*this); }); connect(advanced, &ConfigureInputAdvanced::CallMotionTouchConfigDialog, diff --git a/src/yuzu/configuration/configure_input_advanced.cpp b/src/yuzu/configuration/configure_input_advanced.cpp index b30f09013..cf8aad4ab 100644 --- a/src/yuzu/configuration/configure_input_advanced.cpp +++ b/src/yuzu/configuration/configure_input_advanced.cpp @@ -82,7 +82,6 @@ ConfigureInputAdvanced::ConfigureInputAdvanced(QWidget* parent) connect(ui->debug_configure, &QPushButton::clicked, this, [this] { CallDebugControllerDialog(); }); - connect(ui->mouse_advanced, &QPushButton::clicked, this, [this] { CallMouseConfigDialog(); }); connect(ui->touchscreen_advanced, &QPushButton::clicked, this, [this] { CallTouchscreenConfigDialog(); }); connect(ui->buttonMotionTouch, &QPushButton::clicked, this, @@ -178,7 +177,6 @@ void ConfigureInputAdvanced::RetranslateUI() { } void ConfigureInputAdvanced::UpdateUIEnabled() { - ui->mouse_advanced->setEnabled(ui->mouse_enabled->isChecked()); ui->debug_configure->setEnabled(ui->debug_enabled->isChecked()); ui->touchscreen_advanced->setEnabled(ui->touchscreen_enabled->isChecked()); } diff --git a/src/yuzu/configuration/configure_input_advanced.ui b/src/yuzu/configuration/configure_input_advanced.ui index 9095206a0..75487a5d0 100644 --- a/src/yuzu/configuration/configure_input_advanced.ui +++ b/src/yuzu/configuration/configure_input_advanced.ui @@ -2528,11 +2528,11 @@ 0 - + - Other + Emulated Devices - + @@ -2547,7 +2547,7 @@ - + 0 @@ -2555,53 +2555,18 @@ - Emulate Analog with Keyboard Input + Mouse - - - - 0 - 23 - - + - Enable mouse panning + Touchscreen - - - - Mouse sensitivity - - - Qt::AlignCenter - - - % - - - 1 - - - 100 - - - 100 - - - - - - - Advanced - - - - + Qt::Horizontal @@ -2617,80 +2582,117 @@ - - - - Advanced - - - - - - - Touchscreen - - - + + + + Advanced + + + - - - - 0 - 23 - - - - Mouse - - - - - - - Motion / Touch - - - - - - - Configure - - - - Debug Controller - + Configure - - - - Requires restarting yuzu - - - - 0 - 23 - - - - Enable XInput 8 player support (disables web applet) - - - + + + + Other + + + + + + + 0 + 23 + + + + Emulate Analog with Keyboard Input + + + + + + + Requires restarting yuzu + + + + 0 + 23 + + + + Enable XInput 8 player support (disables web applet) + + + + + + + + 0 + 23 + + + + Enable mouse panning + + + + + + + Mouse sensitivity + + + Qt::AlignCenter + + + % + + + 1 + + + 100 + + + 100 + + + + + + + Motion / Touch + + + + + + + Configure + + + + + + diff --git a/src/yuzu/configuration/configure_mouse_advanced.cpp b/src/yuzu/configuration/configure_mouse_advanced.cpp deleted file mode 100644 index 1e7a3751d..000000000 --- a/src/yuzu/configuration/configure_mouse_advanced.cpp +++ /dev/null @@ -1,247 +0,0 @@ -// Copyright 2016 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include -#include - -#include -#include -#include - -#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" - -static 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: - return QObject::tr("Ctrl"); - case Qt::Key_Alt: - return QObject::tr("Alt"); - case Qt::Key_Meta: - return {}; - default: - return QKeySequence(key_code).toString(); - } -} - -static QString ButtonToText(const Common::ParamPackage& param) { - if (!param.Has("engine")) { - return QObject::tr("[not set]"); - } - - if (param.Get("engine", "") == "keyboard") { - 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", "")); - - return QObject::tr("Button %1").arg(button_str); - } - return {}; - } - - return QObject::tr("[unknown]"); -} - -ConfigureMouseAdvanced::ConfigureMouseAdvanced(QWidget* parent, - InputCommon::InputSubsystem* input_subsystem_) - : QDialog(parent), - ui(std::make_unique()), input_subsystem{input_subsystem_}, - timeout_timer(std::make_unique()), poll_timer(std::make_unique()) { - ui->setupUi(this); - setFocusPolicy(Qt::ClickFocus); - - button_map = { - ui->left_button, ui->right_button, ui->middle_button, ui->forward_button, ui->back_button, - }; - - for (int button_id = 0; button_id < Settings::NativeMouseButton::NumMouseButtons; button_id++) { - auto* const button = button_map[button_id]; - if (button == nullptr) { - continue; - } - - button->setContextMenuPolicy(Qt::CustomContextMenu); - connect(button, &QPushButton::clicked, [=, this] { - HandleClick( - button_map[button_id], - [=, this](const Common::ParamPackage& params) { - buttons_param[button_id] = params; - }, - InputCommon::Polling::InputType::Button); - }); - connect(button, &QPushButton::customContextMenuRequested, - [=, this](const QPoint& menu_location) { - QMenu context_menu; - context_menu.addAction(tr("Clear"), [&] { - buttons_param[button_id].Clear(); - button_map[button_id]->setText(tr("[not set]")); - }); - context_menu.addAction(tr("Restore Default"), [&] { - buttons_param[button_id] = - Common::ParamPackage{InputCommon::GenerateKeyboardParam( - Config::default_mouse_buttons[button_id])}; - button_map[button_id]->setText(ButtonToText(buttons_param[button_id])); - }); - context_menu.exec(button_map[button_id]->mapToGlobal(menu_location)); - }); - } - - connect(ui->buttonClearAll, &QPushButton::clicked, [this] { ClearAll(); }); - connect(ui->buttonRestoreDefaults, &QPushButton::clicked, [this] { RestoreDefaults(); }); - - timeout_timer->setSingleShot(true); - 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; - } - }); - - LoadConfiguration(); - resize(0, 0); -} - -ConfigureMouseAdvanced::~ConfigureMouseAdvanced() = default; - -void ConfigureMouseAdvanced::ApplyConfiguration() { - std::transform(buttons_param.begin(), buttons_param.end(), - Settings::values.mouse_buttons.begin(), - [](const Common::ParamPackage& param) { return param.Serialize(); }); -} - -void ConfigureMouseAdvanced::LoadConfiguration() { - std::transform(Settings::values.mouse_buttons.begin(), Settings::values.mouse_buttons.end(), - buttons_param.begin(), - [](const std::string& str) { return Common::ParamPackage(str); }); - UpdateButtonLabels(); -} - -void ConfigureMouseAdvanced::changeEvent(QEvent* event) { - if (event->type() == QEvent::LanguageChange) { - RetranslateUI(); - } - - QDialog::changeEvent(event); -} - -void ConfigureMouseAdvanced::RetranslateUI() { - ui->retranslateUi(this); -} - -void ConfigureMouseAdvanced::RestoreDefaults() { - for (int button_id = 0; button_id < Settings::NativeMouseButton::NumMouseButtons; button_id++) { - buttons_param[button_id] = Common::ParamPackage{ - InputCommon::GenerateKeyboardParam(Config::default_mouse_buttons[button_id])}; - } - - UpdateButtonLabels(); -} - -void ConfigureMouseAdvanced::ClearAll() { - for (int i = 0; i < Settings::NativeMouseButton::NumMouseButtons; ++i) { - const auto* const button = button_map[i]; - if (button != nullptr && button->isEnabled()) { - buttons_param[i].Clear(); - } - } - - UpdateButtonLabels(); -} - -void ConfigureMouseAdvanced::UpdateButtonLabels() { - for (int button = 0; button < Settings::NativeMouseButton::NumMouseButtons; button++) { - button_map[button]->setText(ButtonToText(buttons_param[button])); - } -} - -void ConfigureMouseAdvanced::HandleClick( - QPushButton* button, std::function new_input_setter, - InputCommon::Polling::InputType type) { - button->setText(tr("[press key]")); - button->setFocus(); - - input_setter = new_input_setter; - - input_subsystem->BeginMapping(type); - - QWidget::grabMouse(); - QWidget::grabKeyboard(); - - timeout_timer->start(2500); // Cancel after 2.5 seconds - poll_timer->start(50); // Check for new inputs every 50ms -} - -void ConfigureMouseAdvanced::SetPollingResult(const Common::ParamPackage& params, bool abort) { - timeout_timer->stop(); - poll_timer->stop(); - input_subsystem->StopMapping(); - - QWidget::releaseMouse(); - QWidget::releaseKeyboard(); - - if (!abort) { - (*input_setter)(params); - } - - UpdateButtonLabels(); - input_setter = std::nullopt; -} - -void ConfigureMouseAdvanced::mousePressEvent(QMouseEvent* event) { - if (!input_setter || !event) { - return; - } - - const auto button = GRenderWindow::QtButtonToMouseButton(event->button()); - input_subsystem->GetMouse()->PressButton(0, 0, 0, 0, button); -} - -void ConfigureMouseAdvanced::keyPressEvent(QKeyEvent* event) { - if (!input_setter || !event) { - return; - } - - if (event->key() != Qt::Key_Escape) { - input_subsystem->GetKeyboard()->PressKey(event->key()); - } -} diff --git a/src/yuzu/configuration/configure_mouse_advanced.h b/src/yuzu/configuration/configure_mouse_advanced.h deleted file mode 100644 index 5fa534eaf..000000000 --- a/src/yuzu/configuration/configure_mouse_advanced.h +++ /dev/null @@ -1,72 +0,0 @@ -// Copyright 2016 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include -#include -#include - -class QCheckBox; -class QPushButton; -class QTimer; - -namespace InputCommon { -class InputSubsystem; -} - -namespace Ui { -class ConfigureMouseAdvanced; -} - -class ConfigureMouseAdvanced : public QDialog { - Q_OBJECT - -public: - explicit ConfigureMouseAdvanced(QWidget* parent, InputCommon::InputSubsystem* input_subsystem_); - ~ConfigureMouseAdvanced() override; - - void ApplyConfiguration(); - -private: - void changeEvent(QEvent* event) override; - void RetranslateUI(); - - /// Load configuration settings. - void LoadConfiguration(); - /// Restore all buttons to their default values. - void RestoreDefaults(); - /// Clear all input configuration - void ClearAll(); - - /// Update UI to reflect current configuration. - void UpdateButtonLabels(); - - /// Called when the button was pressed. - void HandleClick(QPushButton* button, - std::function new_input_setter, - InputCommon::Polling::InputType type); - - /// Finish polling and configure input using the input_setter - void SetPollingResult(const Common::ParamPackage& params, bool abort); - - /// Handle mouse button press events. - void mousePressEvent(QMouseEvent* event) override; - - /// Handle key press events. - void keyPressEvent(QKeyEvent* event) override; - - std::unique_ptr ui; - - InputCommon::InputSubsystem* input_subsystem; - - /// This will be the the setting function when an input is awaiting configuration. - std::optional> input_setter; - - std::array button_map; - std::array buttons_param; - - std::unique_ptr timeout_timer; - std::unique_ptr poll_timer; -}; diff --git a/src/yuzu/configuration/configure_mouse_advanced.ui b/src/yuzu/configuration/configure_mouse_advanced.ui deleted file mode 100644 index 5b99e1c37..000000000 --- a/src/yuzu/configuration/configure_mouse_advanced.ui +++ /dev/null @@ -1,335 +0,0 @@ - - - ConfigureMouseAdvanced - - - - 0 - 0 - 310 - 193 - - - - Configure Mouse - - - QPushButton { - min-width: 60px; -} - - - - - - Mouse Buttons - - - - - - - - - - Forward: - - - - - - - - - - 68 - 0 - - - - - 68 - 16777215 - - - - - - - - - - - - - - - - - - 54 - 0 - - - - Back: - - - - - - - - - - 68 - 0 - - - - - - - - - - - - - - - - - Left: - - - - - - - - - - 68 - 0 - - - - - - - - - - - - - - - - - Middle: - - - - - - - - - - 68 - 0 - - - - - 68 - 16777215 - - - - - - - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 0 - 20 - - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 0 - 20 - - - - - - - - - - - - Right: - - - - - - - - - - 68 - 0 - - - - - 68 - 16777215 - - - - - - - - - - - - - Qt::Horizontal - - - - 0 - 20 - - - - - - - - Qt::Horizontal - - - - 0 - 20 - - - - - - - - - - - - - - 68 - 0 - - - - - 68 - 16777215 - - - - Clear - - - - - - - - 68 - 0 - - - - - 68 - 16777215 - - - - Defaults - - - - - - - Qt::Horizontal - - - - 0 - 20 - - - - - - - - - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - - - - - - buttonBox - accepted() - ConfigureMouseAdvanced - accept() - - - buttonBox - rejected() - ConfigureMouseAdvanced - reject() - - - diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp index 7ca09a635..8e9c7d211 100644 --- a/src/yuzu_cmd/config.cpp +++ b/src/yuzu_cmd/config.cpp @@ -83,163 +83,6 @@ static const std::array, Settings::NativeAnalog::NumAnalogs> }, }}; -static const std::array default_mouse_buttons = { - SDL_SCANCODE_LEFTBRACKET, SDL_SCANCODE_RIGHTBRACKET, SDL_SCANCODE_APOSTROPHE, - SDL_SCANCODE_MINUS, SDL_SCANCODE_EQUALS, -}; - -static const std::array keyboard_keys = { - 0, - 0, - 0, - 0, - SDL_SCANCODE_A, - SDL_SCANCODE_B, - SDL_SCANCODE_C, - SDL_SCANCODE_D, - SDL_SCANCODE_E, - SDL_SCANCODE_F, - SDL_SCANCODE_G, - SDL_SCANCODE_H, - SDL_SCANCODE_I, - SDL_SCANCODE_J, - SDL_SCANCODE_K, - SDL_SCANCODE_L, - SDL_SCANCODE_M, - SDL_SCANCODE_N, - SDL_SCANCODE_O, - SDL_SCANCODE_P, - SDL_SCANCODE_Q, - SDL_SCANCODE_R, - SDL_SCANCODE_S, - SDL_SCANCODE_T, - SDL_SCANCODE_U, - SDL_SCANCODE_V, - SDL_SCANCODE_W, - SDL_SCANCODE_X, - SDL_SCANCODE_Y, - SDL_SCANCODE_Z, - SDL_SCANCODE_1, - SDL_SCANCODE_2, - SDL_SCANCODE_3, - SDL_SCANCODE_4, - SDL_SCANCODE_5, - SDL_SCANCODE_6, - SDL_SCANCODE_7, - SDL_SCANCODE_8, - SDL_SCANCODE_9, - SDL_SCANCODE_0, - SDL_SCANCODE_RETURN, - SDL_SCANCODE_ESCAPE, - SDL_SCANCODE_BACKSPACE, - SDL_SCANCODE_TAB, - SDL_SCANCODE_SPACE, - SDL_SCANCODE_MINUS, - SDL_SCANCODE_EQUALS, - SDL_SCANCODE_LEFTBRACKET, - SDL_SCANCODE_RIGHTBRACKET, - SDL_SCANCODE_BACKSLASH, - 0, - SDL_SCANCODE_SEMICOLON, - SDL_SCANCODE_APOSTROPHE, - SDL_SCANCODE_GRAVE, - SDL_SCANCODE_COMMA, - SDL_SCANCODE_PERIOD, - SDL_SCANCODE_SLASH, - SDL_SCANCODE_CAPSLOCK, - - SDL_SCANCODE_F1, - SDL_SCANCODE_F2, - SDL_SCANCODE_F3, - SDL_SCANCODE_F4, - SDL_SCANCODE_F5, - SDL_SCANCODE_F6, - SDL_SCANCODE_F7, - SDL_SCANCODE_F8, - SDL_SCANCODE_F9, - SDL_SCANCODE_F10, - SDL_SCANCODE_F11, - SDL_SCANCODE_F12, - - 0, - SDL_SCANCODE_SCROLLLOCK, - SDL_SCANCODE_PAUSE, - SDL_SCANCODE_INSERT, - SDL_SCANCODE_HOME, - SDL_SCANCODE_PAGEUP, - SDL_SCANCODE_DELETE, - SDL_SCANCODE_END, - SDL_SCANCODE_PAGEDOWN, - SDL_SCANCODE_RIGHT, - SDL_SCANCODE_LEFT, - SDL_SCANCODE_DOWN, - SDL_SCANCODE_UP, - - SDL_SCANCODE_NUMLOCKCLEAR, - SDL_SCANCODE_KP_DIVIDE, - SDL_SCANCODE_KP_MULTIPLY, - SDL_SCANCODE_KP_MINUS, - SDL_SCANCODE_KP_PLUS, - SDL_SCANCODE_KP_ENTER, - SDL_SCANCODE_KP_1, - SDL_SCANCODE_KP_2, - SDL_SCANCODE_KP_3, - SDL_SCANCODE_KP_4, - SDL_SCANCODE_KP_5, - SDL_SCANCODE_KP_6, - SDL_SCANCODE_KP_7, - SDL_SCANCODE_KP_8, - SDL_SCANCODE_KP_9, - SDL_SCANCODE_KP_0, - SDL_SCANCODE_KP_PERIOD, - - 0, - 0, - SDL_SCANCODE_POWER, - SDL_SCANCODE_KP_EQUALS, - - SDL_SCANCODE_F13, - SDL_SCANCODE_F14, - SDL_SCANCODE_F15, - SDL_SCANCODE_F16, - SDL_SCANCODE_F17, - SDL_SCANCODE_F18, - SDL_SCANCODE_F19, - SDL_SCANCODE_F20, - SDL_SCANCODE_F21, - SDL_SCANCODE_F22, - SDL_SCANCODE_F23, - SDL_SCANCODE_F24, - - 0, - SDL_SCANCODE_HELP, - SDL_SCANCODE_MENU, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - SDL_SCANCODE_KP_COMMA, - SDL_SCANCODE_KP_LEFTPAREN, - SDL_SCANCODE_KP_RIGHTPAREN, - 0, - 0, - 0, - 0, -}; - -static const std::array keyboard_mods{ - SDL_SCANCODE_LCTRL, SDL_SCANCODE_LSHIFT, SDL_SCANCODE_LALT, SDL_SCANCODE_LGUI, - SDL_SCANCODE_RCTRL, SDL_SCANCODE_RSHIFT, SDL_SCANCODE_RALT, SDL_SCANCODE_RGUI, -}; - template <> void Config::ReadSetting(const std::string& group, Settings::BasicSetting& setting) { setting = sdl2_config->Get(group, setting.GetLabel(), setting.GetDefault()); @@ -283,14 +126,6 @@ void Config::ReadValues() { } ReadSetting("ControlsGeneral", Settings::values.mouse_enabled); - for (int i = 0; i < Settings::NativeMouseButton::NumMouseButtons; ++i) { - std::string default_param = InputCommon::GenerateKeyboardParam(default_mouse_buttons[i]); - Settings::values.mouse_buttons[i] = sdl2_config->Get( - "ControlsGeneral", std::string("mouse_") + Settings::NativeMouseButton::mapping[i], - default_param); - if (Settings::values.mouse_buttons[i].empty()) - Settings::values.mouse_buttons[i] = default_param; - } ReadSetting("ControlsGeneral", Settings::values.touch_device); @@ -365,15 +200,6 @@ void Config::ReadValues() { ReadSetting("ControlsGeneral", Settings::values.udp_input_servers); - std::transform(keyboard_keys.begin(), keyboard_keys.end(), - Settings::values.keyboard_keys.begin(), InputCommon::GenerateKeyboardParam); - std::transform(keyboard_mods.begin(), keyboard_mods.end(), - Settings::values.keyboard_keys.begin() + - Settings::NativeKeyboard::LeftControlKey, - InputCommon::GenerateKeyboardParam); - std::transform(keyboard_mods.begin(), keyboard_mods.end(), - Settings::values.keyboard_mods.begin(), InputCommon::GenerateKeyboardParam); - // Data Storage ReadSetting("Data Storage", Settings::values.use_virtual_sd); FS::SetYuzuPath(FS::YuzuPath::NANDDir, -- cgit v1.2.3 From f4e5f89e6fb9d68cd4ba7d98c281584c50f0e149 Mon Sep 17 00:00:00 2001 From: german77 Date: Sun, 14 Nov 2021 21:28:38 -0600 Subject: core/hid: Improve accuary of mouse implementation --- src/core/hid/emulated_devices.cpp | 10 +++---- src/core/hid/emulated_devices.h | 4 +-- src/core/hid/hid_types.h | 35 ++++++++++++++-------- src/core/hid/input_converter.cpp | 4 +++ src/core/hle/service/hid/controllers/keyboard.cpp | 3 +- src/core/hle/service/hid/controllers/keyboard.h | 1 + src/core/hle/service/hid/controllers/mouse.cpp | 7 +++-- src/core/hle/service/hid/controllers/mouse.h | 2 ++ src/core/hle/service/hid/hid.cpp | 29 +++++++++++------- src/core/hle/service/hid/hid.h | 4 +-- src/input_common/drivers/mouse.cpp | 21 ++++++++----- src/input_common/drivers/mouse.h | 1 + src/yuzu/bootmanager.cpp | 4 +-- .../configuration/configure_input_advanced.cpp | 2 ++ 14 files changed, 79 insertions(+), 48 deletions(-) (limited to 'src/input_common/drivers') diff --git a/src/core/hid/emulated_devices.cpp b/src/core/hid/emulated_devices.cpp index 70a494097..874780ec2 100644 --- a/src/core/hid/emulated_devices.cpp +++ b/src/core/hid/emulated_devices.cpp @@ -376,9 +376,9 @@ void EmulatedDevices::SetMouseAnalog(Common::Input::CallbackStatus callback, std void EmulatedDevices::SetMouseStick(Common::Input::CallbackStatus callback) { std::lock_guard lock{mutex}; - const auto stick_value = TransformToStick(callback); + const auto touch_value = TransformToTouch(callback); - device_status.mouse_stick_value = stick_value; + device_status.mouse_stick_value = touch_value; if (is_configuring) { device_status.mouse_position_state = {}; @@ -386,8 +386,8 @@ void EmulatedDevices::SetMouseStick(Common::Input::CallbackStatus callback) { return; } - device_status.mouse_position_state.x = stick_value.x.value; - device_status.mouse_position_state.y = stick_value.y.value; + device_status.mouse_position_state.x = touch_value.x.value; + device_status.mouse_position_state.y = touch_value.y.value; TriggerOnChange(DeviceTriggerType::Mouse); } @@ -420,7 +420,7 @@ MousePosition EmulatedDevices::GetMousePosition() const { return device_status.mouse_position_state; } -AnalogStickState EmulatedDevices::GetMouseDeltaWheel() const { +AnalogStickState EmulatedDevices::GetMouseWheel() const { return device_status.mouse_wheel_state; } diff --git a/src/core/hid/emulated_devices.h b/src/core/hid/emulated_devices.h index 49edfd255..05a945d08 100644 --- a/src/core/hid/emulated_devices.h +++ b/src/core/hid/emulated_devices.h @@ -38,7 +38,7 @@ using MouseButtonValues = std::array; using MouseAnalogValues = std::array; -using MouseStickValue = Common::Input::StickStatus; +using MouseStickValue = Common::Input::TouchStatus; struct MousePosition { f32 x; @@ -130,7 +130,7 @@ public: MousePosition GetMousePosition() const; /// Returns the latest mouse wheel change - AnalogStickState GetMouseDeltaWheel() const; + AnalogStickState GetMouseWheel() const; /** * Adds a callback to the list of events diff --git a/src/core/hid/hid_types.h b/src/core/hid/hid_types.h index af95f3aff..8b12f63ad 100644 --- a/src/core/hid/hid_types.h +++ b/src/core/hid/hid_types.h @@ -502,21 +502,30 @@ static_assert(sizeof(VibrationDeviceInfo) == 0x8, "VibrationDeviceInfo has incor // This is nn::hid::KeyboardModifier struct KeyboardModifier { union { - u64 raw{}; - BitField<0, 1, u64> control; - BitField<1, 1, u64> shift; - BitField<2, 1, u64> left_alt; - BitField<3, 1, u64> right_alt; - BitField<4, 1, u64> gui; - BitField<8, 1, u64> caps_lock; - BitField<9, 1, u64> scroll_lock; - BitField<10, 1, u64> num_lock; - BitField<11, 1, u64> katakana; - BitField<12, 1, u64> hiragana; - BitField<32, 1, u64> unknown; + u32 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(KeyboardModifier) == 0x4, "KeyboardModifier is an invalid size"); + +// This is nn::hid::KeyboardAttribute +struct KeyboardAttribute { + union { + u32 raw{}; + BitField<0, 1, u32> is_connected; }; }; -static_assert(sizeof(KeyboardModifier) == 0x8, "KeyboardModifier is an invalid size"); +static_assert(sizeof(KeyboardAttribute) == 0x4, "KeyboardAttribute is an invalid size"); // This is nn::hid::KeyboardKey struct KeyboardKey { diff --git a/src/core/hid/input_converter.cpp b/src/core/hid/input_converter.cpp index c4e653956..f5acff6e0 100644 --- a/src/core/hid/input_converter.cpp +++ b/src/core/hid/input_converter.cpp @@ -175,6 +175,10 @@ Common::Input::TouchStatus TransformToTouch(const Common::Input::CallbackStatus& case Common::Input::InputType::Touch: status = callback.touch_status; break; + case Common::Input::InputType::Stick: + status.x = callback.stick_status.x; + status.y = callback.stick_status.y; + break; default: LOG_ERROR(Input, "Conversion from type {} to touch not implemented", callback.type); break; diff --git a/src/core/hle/service/hid/controllers/keyboard.cpp b/src/core/hle/service/hid/controllers/keyboard.cpp index 0ef8af0e6..9588a6910 100644 --- a/src/core/hle/service/hid/controllers/keyboard.cpp +++ b/src/core/hle/service/hid/controllers/keyboard.cpp @@ -42,8 +42,7 @@ void Controller_Keyboard::OnUpdate(const Core::Timing::CoreTiming& core_timing, 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); + next_state.attribute.is_connected.Assign(1); } keyboard_lifo.WriteNextEntry(next_state); diff --git a/src/core/hle/service/hid/controllers/keyboard.h b/src/core/hle/service/hid/controllers/keyboard.h index ec5dd607c..0d61cb470 100644 --- a/src/core/hle/service/hid/controllers/keyboard.h +++ b/src/core/hle/service/hid/controllers/keyboard.h @@ -38,6 +38,7 @@ private: struct KeyboardState { s64 sampling_number; Core::HID::KeyboardModifier modifier; + Core::HID::KeyboardAttribute attribute; Core::HID::KeyboardKey key; }; static_assert(sizeof(KeyboardState) == 0x30, "KeyboardState is an invalid size"); diff --git a/src/core/hle/service/hid/controllers/mouse.cpp b/src/core/hle/service/hid/controllers/mouse.cpp index 9c408e7f4..ba79888ae 100644 --- a/src/core/hle/service/hid/controllers/mouse.cpp +++ b/src/core/hle/service/hid/controllers/mouse.cpp @@ -38,15 +38,16 @@ void Controller_Mouse::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* if (Settings::values.mouse_enabled) { const auto& mouse_button_state = emulated_devices->GetMouseButtons(); const auto& mouse_position_state = emulated_devices->GetMousePosition(); - const auto& mouse_wheel_state = emulated_devices->GetMouseDeltaWheel(); + const auto& mouse_wheel_state = emulated_devices->GetMouseWheel(); next_state.attribute.is_connected.Assign(1); next_state.x = static_cast(mouse_position_state.x * Layout::ScreenUndocked::Width); next_state.y = static_cast(mouse_position_state.y * Layout::ScreenUndocked::Height); 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_wheel_state.x; - next_state.delta_wheel_y = mouse_wheel_state.y; + next_state.delta_wheel_x = mouse_wheel_state.x - last_mouse_wheel_state.x; + next_state.delta_wheel_y = mouse_wheel_state.y - last_mouse_wheel_state.y; + last_mouse_wheel_state = mouse_wheel_state; next_state.button = mouse_button_state; } diff --git a/src/core/hle/service/hid/controllers/mouse.h b/src/core/hle/service/hid/controllers/mouse.h index 25017f117..1ac69aa6f 100644 --- a/src/core/hle/service/hid/controllers/mouse.h +++ b/src/core/hle/service/hid/controllers/mouse.h @@ -14,6 +14,7 @@ namespace Core::HID { class EmulatedDevices; struct MouseState; +struct AnalogStickState; } // namespace Core::HID namespace Service::HID { @@ -37,6 +38,7 @@ private: static_assert(sizeof(mouse_lifo) == 0x350, "mouse_lifo is an invalid size"); Core::HID::MouseState next_state{}; + Core::HID::AnalogStickState last_mouse_wheel_state; Core::HID::EmulatedDevices* emulated_devices; }; } // namespace Service::HID diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index e740b4331..95fc07325 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -35,9 +35,9 @@ 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) +constexpr auto pad_update_ns = std::chrono::nanoseconds{4 * 1000 * 1000}; // (4ms, 250Hz) +constexpr auto mouse_keyboard_update_ns = std::chrono::nanoseconds{8 * 1000 * 1000}; // (8ms, 125Hz) +constexpr auto motion_update_ns = std::chrono::nanoseconds{5 * 1000 * 1000}; // (5ms, 200Hz) constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000; IAppletResource::IAppletResource(Core::System& system_, @@ -79,11 +79,11 @@ IAppletResource::IAppletResource(Core::System& system_, const auto guard = LockService(); UpdateControllers(user_data, ns_late); }); - keyboard_update_event = Core::Timing::CreateEvent( - "HID::UpdatekeyboardCallback", + mouse_keyboard_update_event = Core::Timing::CreateEvent( + "HID::UpdateMouseKeyboardCallback", [this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { const auto guard = LockService(); - UpdateKeyboard(user_data, ns_late); + UpdateMouseKeyboard(user_data, ns_late); }); motion_update_event = Core::Timing::CreateEvent( "HID::UpdateMotionCallback", @@ -93,7 +93,7 @@ IAppletResource::IAppletResource(Core::System& system_, }); system.CoreTiming().ScheduleEvent(pad_update_ns, pad_update_event); - system.CoreTiming().ScheduleEvent(keyboard_update_ns, keyboard_update_event); + system.CoreTiming().ScheduleEvent(mouse_keyboard_update_ns, mouse_keyboard_update_event); system.CoreTiming().ScheduleEvent(motion_update_ns, motion_update_event); system.HIDCore().ReloadInputDevices(); @@ -109,7 +109,7 @@ void IAppletResource::DeactivateController(HidController controller) { IAppletResource::~IAppletResource() { system.CoreTiming().UnscheduleEvent(pad_update_event, 0); - system.CoreTiming().UnscheduleEvent(keyboard_update_event, 0); + system.CoreTiming().UnscheduleEvent(mouse_keyboard_update_event, 0); system.CoreTiming().UnscheduleEvent(motion_update_event, 0); } @@ -130,6 +130,10 @@ void IAppletResource::UpdateControllers(std::uintptr_t user_data, if (controller == controllers[static_cast(HidController::Keyboard)]) { continue; } + // Mouse has it's own update event + if (controller == controllers[static_cast(HidController::Mouse)]) { + continue; + } controller->OnUpdate(core_timing, system.Kernel().GetHidSharedMem().GetPointer(), SHARED_MEMORY_SIZE); } @@ -142,18 +146,21 @@ void IAppletResource::UpdateControllers(std::uintptr_t user_data, core_timing.ScheduleEvent(pad_update_ns - ns_late, pad_update_event); } -void IAppletResource::UpdateKeyboard(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { +void IAppletResource::UpdateMouseKeyboard(std::uintptr_t user_data, + std::chrono::nanoseconds ns_late) { auto& core_timing = system.CoreTiming(); + controllers[static_cast(HidController::Mouse)]->OnUpdate( + core_timing, system.Kernel().GetHidSharedMem().GetPointer(), SHARED_MEMORY_SIZE); 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) { + if (ns_late > mouse_keyboard_update_ns) { ns_late = {}; } - core_timing.ScheduleEvent(keyboard_update_ns - ns_late, keyboard_update_event); + core_timing.ScheduleEvent(mouse_keyboard_update_ns - ns_late, mouse_keyboard_update_event); } void IAppletResource::UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index bbad165f8..ab0084118 100644 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h @@ -70,13 +70,13 @@ private: 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 UpdateMouseKeyboard(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 mouse_keyboard_update_event; std::shared_ptr motion_update_event; std::array, static_cast(HidController::MaxControllers)> diff --git a/src/input_common/drivers/mouse.cpp b/src/input_common/drivers/mouse.cpp index 478737db2..05fd7f9c0 100644 --- a/src/input_common/drivers/mouse.cpp +++ b/src/input_common/drivers/mouse.cpp @@ -39,7 +39,7 @@ void Mouse::UpdateThread(std::stop_token stop_token) { Common::SetCurrentThreadName("yuzu:input:Mouse"); constexpr int update_time = 10; while (!stop_token.stop_requested()) { - if (Settings::values.mouse_panning) { + if (Settings::values.mouse_panning && !Settings::values.mouse_enabled) { // Slow movement by 4% last_mouse_change *= 0.96f; const float sensitivity = @@ -52,14 +52,17 @@ void Mouse::UpdateThread(std::stop_token stop_token) { StopPanning(); } std::this_thread::sleep_for(std::chrono::milliseconds(update_time)); - - // Reset wheel position - SetAxis(identifier, wheel_axis_x, 0); - SetAxis(identifier, wheel_axis_y, 0); } } void Mouse::MouseMove(int x, int y, f32 touch_x, f32 touch_y, int center_x, int center_y) { + // If native mouse is enabled just set the screen coordinates + if (Settings::values.mouse_enabled) { + SetAxis(identifier, mouse_axis_x, touch_x); + SetAxis(identifier, mouse_axis_y, touch_y); + return; + } + SetAxis(identifier, touch_axis_x, touch_x); SetAxis(identifier, touch_axis_y, touch_y); @@ -121,7 +124,7 @@ void Mouse::PressButton(int x, int y, f32 touch_x, f32 touch_y, MouseButton butt void Mouse::ReleaseButton(MouseButton button) { SetButton(identifier, static_cast(button), false); - if (!Settings::values.mouse_panning) { + if (!Settings::values.mouse_panning && !Settings::values.mouse_enabled) { SetAxis(identifier, mouse_axis_x, 0); SetAxis(identifier, mouse_axis_y, 0); } @@ -129,8 +132,10 @@ void Mouse::ReleaseButton(MouseButton button) { } void Mouse::MouseWheelChange(int x, int y) { - SetAxis(identifier, wheel_axis_x, static_cast(x)); - SetAxis(identifier, wheel_axis_y, static_cast(y)); + wheel_position.x += x; + wheel_position.y += y; + SetAxis(identifier, wheel_axis_x, static_cast(wheel_position.x)); + SetAxis(identifier, wheel_axis_y, static_cast(wheel_position.y)); } void Mouse::ReleaseAllButtons() { diff --git a/src/input_common/drivers/mouse.h b/src/input_common/drivers/mouse.h index 429502af9..f7e6db0b5 100644 --- a/src/input_common/drivers/mouse.h +++ b/src/input_common/drivers/mouse.h @@ -72,6 +72,7 @@ private: Common::Vec2 mouse_origin; Common::Vec2 last_mouse_position; Common::Vec2 last_mouse_change; + Common::Vec2 wheel_position; bool button_pressed; int mouse_panning_timout{}; std::jthread update_thread; diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 1015e51b5..2313a4189 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -729,7 +729,7 @@ void GRenderWindow::mouseMoveEvent(QMouseEvent* event) { const int center_y = height() / 2; input_subsystem->GetMouse()->MouseMove(x, y, touch_x, touch_y, center_x, center_y); - if (Settings::values.mouse_panning) { + if (Settings::values.mouse_panning && !Settings::values.mouse_enabled) { QCursor::setPos(mapToGlobal({center_x, center_y})); } @@ -1044,7 +1044,7 @@ void GRenderWindow::showEvent(QShowEvent* event) { bool GRenderWindow::eventFilter(QObject* object, QEvent* event) { if (event->type() == QEvent::HoverMove) { - if (Settings::values.mouse_panning) { + if (Settings::values.mouse_panning || Settings::values.mouse_enabled) { auto* hover_event = static_cast(event); mouseMoveEvent(hover_event); return false; diff --git a/src/yuzu/configuration/configure_input_advanced.cpp b/src/yuzu/configuration/configure_input_advanced.cpp index cf8aad4ab..e6127f9e6 100644 --- a/src/yuzu/configuration/configure_input_advanced.cpp +++ b/src/yuzu/configuration/configure_input_advanced.cpp @@ -179,4 +179,6 @@ void ConfigureInputAdvanced::RetranslateUI() { void ConfigureInputAdvanced::UpdateUIEnabled() { ui->debug_configure->setEnabled(ui->debug_enabled->isChecked()); ui->touchscreen_advanced->setEnabled(ui->touchscreen_enabled->isChecked()); + ui->mouse_panning->setEnabled(!ui->mouse_enabled->isChecked()); + ui->mouse_panning_sensitivity->setEnabled(!ui->mouse_enabled->isChecked()); } -- cgit v1.2.3 From 42949738f2c01a4125a9a385c9100240181153ec Mon Sep 17 00:00:00 2001 From: german77 Date: Sun, 14 Nov 2021 21:56:54 -0600 Subject: kraken: Address comments from review Fix compiler bug --- src/core/hid/hid_types.h | 3 +- src/core/hle/service/hid/controllers/npad.cpp | 2 +- src/core/hle/service/hid/ring_lifo.h | 7 ++- src/input_common/drivers/gc_adapter.cpp | 16 +------ src/input_common/drivers/gc_adapter.h | 2 +- src/input_common/drivers/mouse.cpp | 2 +- src/input_common/drivers/mouse.h | 2 +- src/input_common/drivers/sdl_driver.cpp | 2 +- src/input_common/drivers/sdl_driver.h | 2 +- src/input_common/drivers/tas_input.cpp | 2 +- src/input_common/drivers/tas_input.h | 2 +- src/input_common/drivers/touch_screen.cpp | 2 +- src/input_common/drivers/touch_screen.h | 2 +- src/input_common/input_engine.cpp | 4 +- src/input_common/input_engine.h | 2 +- src/yuzu/bootmanager.cpp | 66 +++++++++++++-------------- src/yuzu/bootmanager.h | 2 +- 17 files changed, 54 insertions(+), 66 deletions(-) (limited to 'src/input_common/drivers') diff --git a/src/core/hid/hid_types.h b/src/core/hid/hid_types.h index 8b12f63ad..3cbe16260 100644 --- a/src/core/hid/hid_types.h +++ b/src/core/hid/hid_types.h @@ -564,8 +564,9 @@ struct MouseState { s32 y; s32 delta_x; s32 delta_y; - s32 delta_wheel_x; + // Axis Order in HW is switched for the wheel s32 delta_wheel_y; + s32 delta_wheel_x; MouseButton button; MouseAttribute attribute; }; diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index eaec79139..4b23230e1 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -345,7 +345,7 @@ void Controller_NPad::RequestPadStateUpdate(Core::HID::NpadIdType npad_id) { 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.npad_buttons.raw = button_state.raw & right_button_mask; pad_entry.r_stick = stick_state.right; } diff --git a/src/core/hle/service/hid/ring_lifo.h b/src/core/hle/service/hid/ring_lifo.h index 6209ed0d1..f0e0bab7f 100644 --- a/src/core/hle/service/hid/ring_lifo.h +++ b/src/core/hle/service/hid/ring_lifo.h @@ -7,7 +7,6 @@ #include #include "common/common_types.h" -#include "common/swap.h" namespace Service::HID { constexpr std::size_t max_buffer_size = 17; @@ -21,7 +20,7 @@ struct AtomicStorage { template struct Lifo { s64 timestamp{}; - s64 total_buffer_count = max_buffer_size; + s64 total_buffer_count = static_cast(max_buffer_size); s64 buffer_tail{}; s64 buffer_count{}; std::array, max_buffer_size> entries{}; @@ -35,11 +34,11 @@ struct Lifo { } std::size_t GetPreviousEntryIndex() const { - return (buffer_tail + total_buffer_count - 1) % total_buffer_count; + return static_cast((buffer_tail + total_buffer_count - 1) % total_buffer_count); } std::size_t GetNextEntryIndex() const { - return (buffer_tail + 1) % total_buffer_count; + return static_cast((buffer_tail + 1) % total_buffer_count); } void WriteNextEntry(const State& new_state) { diff --git a/src/input_common/drivers/gc_adapter.cpp b/src/input_common/drivers/gc_adapter.cpp index 2550f8cba..a1b9b6d98 100644 --- a/src/input_common/drivers/gc_adapter.cpp +++ b/src/input_common/drivers/gc_adapter.cpp @@ -69,7 +69,7 @@ private: libusb_device_handle* handle{}; }; -GCAdapter::GCAdapter(const std::string input_engine_) : InputEngine(input_engine_) { +GCAdapter::GCAdapter(const std::string& input_engine_) : InputEngine(input_engine_) { if (usb_adapter_handle) { return; } @@ -486,42 +486,30 @@ std::string GCAdapter::GetUIButtonName(const Common::ParamPackage& params) const switch (button) { case PadButton::ButtonLeft: return "left"; - break; case PadButton::ButtonRight: return "right"; - break; case PadButton::ButtonDown: return "down"; - break; case PadButton::ButtonUp: return "up"; - break; case PadButton::TriggerZ: return "Z"; - break; case PadButton::TriggerR: return "R"; - break; case PadButton::TriggerL: return "L"; - break; case PadButton::ButtonA: return "A"; - break; case PadButton::ButtonB: return "B"; - break; case PadButton::ButtonX: return "X"; - break; case PadButton::ButtonY: return "Y"; - break; case PadButton::ButtonStart: return "start"; - break; default: - return "Unkown GC"; + return "Unknown GC"; } } diff --git a/src/input_common/drivers/gc_adapter.h b/src/input_common/drivers/gc_adapter.h index fba90352e..3e4747040 100644 --- a/src/input_common/drivers/gc_adapter.h +++ b/src/input_common/drivers/gc_adapter.h @@ -24,7 +24,7 @@ class LibUSBDeviceHandle; class GCAdapter : public InputCommon::InputEngine { public: - explicit GCAdapter(const std::string input_engine_); + explicit GCAdapter(const std::string& input_engine_); ~GCAdapter(); Common::Input::VibrationError SetRumble( diff --git a/src/input_common/drivers/mouse.cpp b/src/input_common/drivers/mouse.cpp index 05fd7f9c0..9a9a1987d 100644 --- a/src/input_common/drivers/mouse.cpp +++ b/src/input_common/drivers/mouse.cpp @@ -24,7 +24,7 @@ constexpr PadIdentifier identifier = { .pad = 0, }; -Mouse::Mouse(const std::string input_engine_) : InputEngine(input_engine_) { +Mouse::Mouse(const std::string& input_engine_) : InputEngine(input_engine_) { PreSetController(identifier); PreSetAxis(identifier, mouse_axis_x); PreSetAxis(identifier, mouse_axis_y); diff --git a/src/input_common/drivers/mouse.h b/src/input_common/drivers/mouse.h index f7e6db0b5..11dd76e14 100644 --- a/src/input_common/drivers/mouse.h +++ b/src/input_common/drivers/mouse.h @@ -29,7 +29,7 @@ enum class MouseButton { */ class Mouse final : public InputCommon::InputEngine { public: - explicit Mouse(const std::string input_engine_); + explicit Mouse(const std::string& input_engine_); /** * Signals that mouse has moved. diff --git a/src/input_common/drivers/sdl_driver.cpp b/src/input_common/drivers/sdl_driver.cpp index 1e3741e0f..0b24f1858 100644 --- a/src/input_common/drivers/sdl_driver.cpp +++ b/src/input_common/drivers/sdl_driver.cpp @@ -929,7 +929,7 @@ std::string SDLDriver::GetHatButtonName(u8 direction_value) const { } } -u8 SDLDriver::GetHatButtonId(const std::string direction_name) const { +u8 SDLDriver::GetHatButtonId(const std::string& direction_name) const { Uint8 direction; if (direction_name == "up") { direction = SDL_HAT_UP; diff --git a/src/input_common/drivers/sdl_driver.h b/src/input_common/drivers/sdl_driver.h index b879df8ab..3faaca984 100644 --- a/src/input_common/drivers/sdl_driver.h +++ b/src/input_common/drivers/sdl_driver.h @@ -56,7 +56,7 @@ public: std::string GetUIName(const Common::ParamPackage& params) const override; std::string GetHatButtonName(u8 direction_value) const override; - u8 GetHatButtonId(const std::string direction_name) const override; + u8 GetHatButtonId(const std::string& direction_name) const override; Common::Input::VibrationError SetRumble( const PadIdentifier& identifier, const Common::Input::VibrationStatus vibration) override; diff --git a/src/input_common/drivers/tas_input.cpp b/src/input_common/drivers/tas_input.cpp index bb9c236ea..0e01fb0d9 100644 --- a/src/input_common/drivers/tas_input.cpp +++ b/src/input_common/drivers/tas_input.cpp @@ -47,7 +47,7 @@ constexpr std::array, 20> text_to_tas_but {"KEY_ZR", TasButton::TRIGGER_ZR}, }; -Tas::Tas(const std::string input_engine_) : InputCommon::InputEngine(input_engine_) { +Tas::Tas(const std::string& input_engine_) : InputCommon::InputEngine(input_engine_) { for (size_t player_index = 0; player_index < PLAYER_NUMBER; player_index++) { PadIdentifier identifier{ .guid = Common::UUID{}, diff --git a/src/input_common/drivers/tas_input.h b/src/input_common/drivers/tas_input.h index bfb37a638..c95a130fc 100644 --- a/src/input_common/drivers/tas_input.h +++ b/src/input_common/drivers/tas_input.h @@ -83,7 +83,7 @@ enum class TasState { class Tas final : public InputCommon::InputEngine { public: - explicit Tas(const std::string input_engine_); + explicit Tas(const std::string& input_engine_); ~Tas(); /** diff --git a/src/input_common/drivers/touch_screen.cpp b/src/input_common/drivers/touch_screen.cpp index 377c9ee2b..45b3086f6 100644 --- a/src/input_common/drivers/touch_screen.cpp +++ b/src/input_common/drivers/touch_screen.cpp @@ -13,7 +13,7 @@ constexpr PadIdentifier identifier = { .pad = 0, }; -TouchScreen::TouchScreen(const std::string input_engine_) : InputEngine(input_engine_) { +TouchScreen::TouchScreen(const std::string& input_engine_) : InputEngine(input_engine_) { PreSetController(identifier); } diff --git a/src/input_common/drivers/touch_screen.h b/src/input_common/drivers/touch_screen.h index 0f4cd0e7a..25c11e8bf 100644 --- a/src/input_common/drivers/touch_screen.h +++ b/src/input_common/drivers/touch_screen.h @@ -14,7 +14,7 @@ namespace InputCommon { */ class TouchScreen final : public InputCommon::InputEngine { public: - explicit TouchScreen(const std::string input_engine_); + explicit TouchScreen(const std::string& input_engine_); /** * Signals that mouse has moved. diff --git a/src/input_common/input_engine.cpp b/src/input_common/input_engine.cpp index 139d8d2e6..2b2105376 100644 --- a/src/input_common/input_engine.cpp +++ b/src/input_common/input_engine.cpp @@ -300,8 +300,8 @@ void InputEngine::TriggerOnMotionChange(const PadIdentifier& identifier, int mot if (!configuring || !mapping_callback.on_data) { return; } - if (std::abs(value.gyro_x) < 1.0f && std::abs(value.gyro_y) < 1.0f && - std::abs(value.gyro_z) < 1.0f) { + if (std::abs(value.gyro_x) < 0.6f && std::abs(value.gyro_y) < 0.6f && + std::abs(value.gyro_z) < 0.6f) { return; } mapping_callback.on_data(MappingData{ diff --git a/src/input_common/input_engine.h b/src/input_common/input_engine.h index 5430c0cf8..c621686e5 100644 --- a/src/input_common/input_engine.h +++ b/src/input_common/input_engine.h @@ -166,7 +166,7 @@ public: }; /// Retrieves the index number of the given hat button direction - virtual u8 GetHatButtonId([[maybe_unused]] const std::string direction_name) const { + virtual u8 GetHatButtonId([[maybe_unused]] const std::string& direction_name) const { return 0; }; diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 2313a4189..7390fc5bd 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -613,56 +613,56 @@ int GRenderWindow::QtKeyToSwitchKey(Qt::Key qt_key) { } } -int GRenderWindow::QtModifierToSwitchModdifier(quint32 qt_moddifiers) { - int moddifier = 0; +int GRenderWindow::QtModifierToSwitchModifier(quint32 qt_modifiers) { + int modifier = 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_modifiers & 0x1) != 0) { + modifier |= 1 << Settings::NativeKeyboard::LeftShift; } - if ((qt_moddifiers & 0x2) != 0) { - moddifier |= 1 << Settings::NativeKeyboard::LeftControl; + if ((qt_modifiers & 0x2) != 0) { + modifier |= 1 << Settings::NativeKeyboard::LeftControl; } - if ((qt_moddifiers & 0x4) != 0) { - moddifier |= 1 << Settings::NativeKeyboard::LeftAlt; + if ((qt_modifiers & 0x4) != 0) { + modifier |= 1 << Settings::NativeKeyboard::LeftAlt; } - if ((qt_moddifiers & 0x08) != 0) { - moddifier |= 1 << Settings::NativeKeyboard::LeftMeta; + if ((qt_modifiers & 0x08) != 0) { + modifier |= 1 << Settings::NativeKeyboard::LeftMeta; } - if ((qt_moddifiers & 0x10) != 0) { - moddifier |= 1 << Settings::NativeKeyboard::RightShift; + if ((qt_modifiers & 0x10) != 0) { + modifier |= 1 << Settings::NativeKeyboard::RightShift; } - if ((qt_moddifiers & 0x20) != 0) { - moddifier |= 1 << Settings::NativeKeyboard::RightControl; + if ((qt_modifiers & 0x20) != 0) { + modifier |= 1 << Settings::NativeKeyboard::RightControl; } - if ((qt_moddifiers & 0x40) != 0) { - moddifier |= 1 << Settings::NativeKeyboard::RightAlt; + if ((qt_modifiers & 0x40) != 0) { + modifier |= 1 << Settings::NativeKeyboard::RightAlt; } - if ((qt_moddifiers & 0x80) != 0) { - moddifier |= 1 << Settings::NativeKeyboard::RightMeta; + if ((qt_modifiers & 0x80) != 0) { + modifier |= 1 << Settings::NativeKeyboard::RightMeta; } - if ((qt_moddifiers & 0x100) != 0) { - moddifier |= 1 << Settings::NativeKeyboard::CapsLock; + if ((qt_modifiers & 0x100) != 0) { + modifier |= 1 << Settings::NativeKeyboard::CapsLock; } - if ((qt_moddifiers & 0x200) != 0) { - moddifier |= 1 << Settings::NativeKeyboard::NumLock; + if ((qt_modifiers & 0x200) != 0) { + modifier |= 1 << Settings::NativeKeyboard::NumLock; } // Verify the last two keys - if ((qt_moddifiers & 0x400) != 0) { - moddifier |= 1 << Settings::NativeKeyboard::Katakana; + if ((qt_modifiers & 0x400) != 0) { + modifier |= 1 << Settings::NativeKeyboard::Katakana; } - if ((qt_moddifiers & 0x800) != 0) { - moddifier |= 1 << Settings::NativeKeyboard::Hiragana; + if ((qt_modifiers & 0x800) != 0) { + modifier |= 1 << Settings::NativeKeyboard::Hiragana; } - return moddifier; + return modifier; } void GRenderWindow::keyPressEvent(QKeyEvent* event) { if (!event->isAutoRepeat()) { - const auto moddifier = QtModifierToSwitchModdifier(event->nativeModifiers()); + const auto modifier = QtModifierToSwitchModifier(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()->SetKeyboardModifiers(moddifier); + input_subsystem->GetKeyboard()->SetKeyboardModifiers(modifier); input_subsystem->GetKeyboard()->PressKeyboardKey(key); // This is used for gamepads input_subsystem->GetKeyboard()->PressKey(event->key()); @@ -671,9 +671,9 @@ void GRenderWindow::keyPressEvent(QKeyEvent* event) { void GRenderWindow::keyReleaseEvent(QKeyEvent* event) { if (!event->isAutoRepeat()) { - const auto moddifier = QtModifierToSwitchModdifier(event->nativeModifiers()); + const auto modifier = QtModifierToSwitchModifier(event->nativeModifiers()); const auto key = QtKeyToSwitchKey(Qt::Key(event->key())); - input_subsystem->GetKeyboard()->SetKeyboardModifiers(moddifier); + input_subsystem->GetKeyboard()->SetKeyboardModifiers(modifier); input_subsystem->GetKeyboard()->ReleaseKeyboardKey(key); // This is used for gamepads input_subsystem->GetKeyboard()->ReleaseKey(event->key()); @@ -747,8 +747,8 @@ void GRenderWindow::mouseReleaseEvent(QMouseEvent* event) { } void GRenderWindow::wheelEvent(QWheelEvent* event) { - const int x = event->delta(); - const int y = 0; + const int x = event->angleDelta().x(); + const int y = event->angleDelta().y(); input_subsystem->GetMouse()->MouseWheelChange(x, y); } diff --git a/src/yuzu/bootmanager.h b/src/yuzu/bootmanager.h index d6b2ab5f3..81e3c4eb0 100644 --- a/src/yuzu/bootmanager.h +++ b/src/yuzu/bootmanager.h @@ -162,7 +162,7 @@ public: static int QtKeyToSwitchKey(Qt::Key qt_keys); /// Converts a Qt modifier keys into NativeKeyboard modifier keys - static int QtModifierToSwitchModdifier(quint32 qt_moddifiers); + static int QtModifierToSwitchModifier(quint32 qt_modifiers); void keyPressEvent(QKeyEvent* event) override; void keyReleaseEvent(QKeyEvent* event) override; -- cgit v1.2.3 From c4760489a0386cdeaed68ecbed7f87532193743e Mon Sep 17 00:00:00 2001 From: german77 Date: Sun, 21 Nov 2021 12:59:51 -0600 Subject: input_common: Fix SDL controller with inverted axis --- src/input_common/drivers/sdl_driver.cpp | 23 ----------------------- src/input_common/input_poller.cpp | 9 ++++++++- 2 files changed, 8 insertions(+), 24 deletions(-) (limited to 'src/input_common/drivers') diff --git a/src/input_common/drivers/sdl_driver.cpp b/src/input_common/drivers/sdl_driver.cpp index 0b24f1858..d5af6c09b 100644 --- a/src/input_common/drivers/sdl_driver.cpp +++ b/src/input_common/drivers/sdl_driver.cpp @@ -220,24 +220,6 @@ public: return "Unknown"; } - bool IsYAxis(u8 index) { - if (!sdl_controller) { - return false; - } - - const auto& binding_left_y = - SDL_GameControllerGetBindForAxis(sdl_controller.get(), SDL_CONTROLLER_AXIS_LEFTY); - const auto& binding_right_y = - SDL_GameControllerGetBindForAxis(sdl_controller.get(), SDL_CONTROLLER_AXIS_RIGHTY); - if (index == binding_left_y.value.axis) { - return true; - } - if (index == binding_right_y.value.axis) { - return true; - } - return false; - } - private: std::string guid; int port; @@ -376,11 +358,6 @@ void SDLDriver::HandleGameControllerEvent(const SDL_Event& event) { case SDL_JOYAXISMOTION: { if (const auto joystick = GetSDLJoystickBySDLID(event.jaxis.which)) { const PadIdentifier identifier = joystick->GetPadIdentifier(); - // Vertical axis is inverted on nintendo compared to SDL - if (joystick->IsYAxis(event.jaxis.axis)) { - SetAxis(identifier, event.jaxis.axis, -event.jaxis.value / 32767.0f); - break; - } SetAxis(identifier, event.jaxis.axis, event.jaxis.value / 32767.0f); } break; diff --git a/src/input_common/input_poller.cpp b/src/input_common/input_poller.cpp index 92cf690cd..7e4eafded 100644 --- a/src/input_common/input_poller.cpp +++ b/src/input_common/input_poller.cpp @@ -146,7 +146,8 @@ public: Common::Input::AnalogProperties properties_y_, InputEngine* input_engine_) : identifier(identifier_), axis_x(axis_x_), axis_y(axis_y_), properties_x(properties_x_), - properties_y(properties_y_), input_engine(input_engine_) { + properties_y(properties_y_), + input_engine(input_engine_), invert_axis_y{input_engine_->GetEngineName() == "sdl"} { UpdateCallback engine_callback{[this]() { OnChange(); }}; const InputIdentifier x_input_identifier{ .identifier = identifier, @@ -181,6 +182,11 @@ public: .raw_value = input_engine->GetAxis(identifier, axis_y), .properties = properties_y, }; + // This is a workaround too keep compatibility with old yuzu versions. Vertical axis is + // inverted on SDL compared to Nintendo + if (invert_axis_y) { + status.y.raw_value = -status.y.raw_value; + } return status; } @@ -220,6 +226,7 @@ private: float last_axis_x_value; float last_axis_y_value; InputEngine* input_engine; + const bool invert_axis_y; }; class InputFromTouch final : public Common::Input::InputDevice { -- cgit v1.2.3 From 746c85b56011b87afb57e37b75953435389fc810 Mon Sep 17 00:00:00 2001 From: german77 Date: Sun, 21 Nov 2021 14:12:01 -0600 Subject: input_common: Move button names to the frontend --- src/common/input.h | 22 ++++++ src/input_common/drivers/gc_adapter.cpp | 36 +++++----- src/input_common/drivers/gc_adapter.h | 4 +- src/input_common/drivers/mouse.cpp | 9 ++- src/input_common/drivers/mouse.h | 2 +- src/input_common/drivers/sdl_driver.cpp | 15 ++-- src/input_common/drivers/sdl_driver.h | 2 +- src/input_common/input_engine.h | 5 +- src/input_common/input_mapping.cpp | 5 ++ src/input_common/main.cpp | 17 ++--- src/input_common/main.h | 9 ++- src/yuzu/configuration/configure_input_player.cpp | 86 ++++++++++++++++++++++- 12 files changed, 160 insertions(+), 52 deletions(-) (limited to 'src/input_common/drivers') diff --git a/src/common/input.h b/src/common/input.h index d997853c6..cc0cbd9b8 100644 --- a/src/common/input.h +++ b/src/common/input.h @@ -175,6 +175,28 @@ struct LedStatus { bool led_4{}; }; +// List of buttons to be passed to Qt that can be translated +enum class ButtonNames { + Undefined, + Invalid, + // This will display the engine name instead of the button name + Engine, + // This will display the button by value instead of the button name + Value, + ButtonLeft, + ButtonRight, + ButtonDown, + ButtonUp, + TriggerZ, + TriggerR, + TriggerL, + ButtonA, + ButtonB, + ButtonX, + ButtonY, + ButtonStart, +}; + // Callback data consisting of an input type and the equivalent data status struct CallbackStatus { InputType type{InputType::None}; diff --git a/src/input_common/drivers/gc_adapter.cpp b/src/input_common/drivers/gc_adapter.cpp index a1b9b6d98..8b6574223 100644 --- a/src/input_common/drivers/gc_adapter.cpp +++ b/src/input_common/drivers/gc_adapter.cpp @@ -481,47 +481,47 @@ AnalogMapping GCAdapter::GetAnalogMappingForDevice(const Common::ParamPackage& p return mapping; } -std::string GCAdapter::GetUIButtonName(const Common::ParamPackage& params) const { +Common::Input::ButtonNames GCAdapter::GetUIButtonName(const Common::ParamPackage& params) const { PadButton button = static_cast(params.Get("button", 0)); switch (button) { case PadButton::ButtonLeft: - return "left"; + return Common::Input::ButtonNames::ButtonLeft; case PadButton::ButtonRight: - return "right"; + return Common::Input::ButtonNames::ButtonRight; case PadButton::ButtonDown: - return "down"; + return Common::Input::ButtonNames::ButtonDown; case PadButton::ButtonUp: - return "up"; + return Common::Input::ButtonNames::ButtonUp; case PadButton::TriggerZ: - return "Z"; + return Common::Input::ButtonNames::TriggerZ; case PadButton::TriggerR: - return "R"; + return Common::Input::ButtonNames::TriggerR; case PadButton::TriggerL: - return "L"; + return Common::Input::ButtonNames::TriggerL; case PadButton::ButtonA: - return "A"; + return Common::Input::ButtonNames::ButtonA; case PadButton::ButtonB: - return "B"; + return Common::Input::ButtonNames::ButtonB; case PadButton::ButtonX: - return "X"; + return Common::Input::ButtonNames::ButtonX; case PadButton::ButtonY: - return "Y"; + return Common::Input::ButtonNames::ButtonY; case PadButton::ButtonStart: - return "start"; + return Common::Input::ButtonNames::ButtonStart; default: - return "Unknown GC"; + return Common::Input::ButtonNames::Undefined; } } -std::string GCAdapter::GetUIName(const Common::ParamPackage& params) const { +Common::Input::ButtonNames GCAdapter::GetUIName(const Common::ParamPackage& params) const { if (params.Has("button")) { - return fmt::format("Button {}", GetUIButtonName(params)); + return GetUIButtonName(params); } if (params.Has("axis")) { - return fmt::format("Axis {}", params.Get("axis", 0)); + return Common::Input::ButtonNames::Value; } - return "Bad GC Adapter"; + return Common::Input::ButtonNames::Invalid; } } // namespace InputCommon diff --git a/src/input_common/drivers/gc_adapter.h b/src/input_common/drivers/gc_adapter.h index 3e4747040..8dc51d2e5 100644 --- a/src/input_common/drivers/gc_adapter.h +++ b/src/input_common/drivers/gc_adapter.h @@ -34,7 +34,7 @@ public: std::vector GetInputDevices() const override; ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage& params) override; AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage& params) override; - std::string GetUIName(const Common::ParamPackage& params) const override; + Common::Input::ButtonNames GetUIName(const Common::ParamPackage& params) const override; private: enum class PadButton { @@ -112,7 +112,7 @@ private: /// Updates vibration state of all controllers void SendVibrations(); - std::string GetUIButtonName(const Common::ParamPackage& params) const; + Common::Input::ButtonNames GetUIButtonName(const Common::ParamPackage& params) const; std::unique_ptr usb_adapter_handle; std::array pads; diff --git a/src/input_common/drivers/mouse.cpp b/src/input_common/drivers/mouse.cpp index 9a9a1987d..752118e97 100644 --- a/src/input_common/drivers/mouse.cpp +++ b/src/input_common/drivers/mouse.cpp @@ -171,12 +171,15 @@ AnalogMapping Mouse::GetAnalogMappingForDevice( return mapping; } -std::string Mouse::GetUIName(const Common::ParamPackage& params) const { +Common::Input::ButtonNames Mouse::GetUIName(const Common::ParamPackage& params) const { if (params.Has("button")) { - return fmt::format("Mouse {}", params.Get("button", 0)); + return Common::Input::ButtonNames::Value; + } + if (params.Has("axis")) { + return Common::Input::ButtonNames::Value; } - return "Bad Mouse"; + return Common::Input::ButtonNames::Invalid; } } // namespace InputCommon diff --git a/src/input_common/drivers/mouse.h b/src/input_common/drivers/mouse.h index 11dd76e14..4a1fd2fd9 100644 --- a/src/input_common/drivers/mouse.h +++ b/src/input_common/drivers/mouse.h @@ -63,7 +63,7 @@ public: std::vector GetInputDevices() const override; AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage& params) override; - std::string GetUIName(const Common::ParamPackage& params) const override; + Common::Input::ButtonNames GetUIName(const Common::ParamPackage& params) const override; private: void UpdateThread(std::stop_token stop_token); diff --git a/src/input_common/drivers/sdl_driver.cpp b/src/input_common/drivers/sdl_driver.cpp index d5af6c09b..90128b6cf 100644 --- a/src/input_common/drivers/sdl_driver.cpp +++ b/src/input_common/drivers/sdl_driver.cpp @@ -869,26 +869,25 @@ MotionMapping SDLDriver::GetMotionMappingForDevice(const Common::ParamPackage& p return mapping; } -std::string SDLDriver::GetUIName(const Common::ParamPackage& params) const { +Common::Input::ButtonNames SDLDriver::GetUIName(const Common::ParamPackage& params) const { if (params.Has("button")) { // TODO(German77): Find how to substitue the values for real button names - return fmt::format("Button {}", params.Get("button", 0)); + return Common::Input::ButtonNames::Value; } if (params.Has("hat")) { - return fmt::format("Hat {}", params.Get("direction", "")); + return Common::Input::ButtonNames::Value; } if (params.Has("axis")) { - return fmt::format("Axis {}", params.Get("axis", "")); + return Common::Input::ButtonNames::Value; } if (params.Has("axis_x") && params.Has("axis_y") && params.Has("axis_z")) { - return fmt::format("Axis {},{},{}", params.Get("axis_x", ""), params.Get("axis_y", ""), - params.Get("axis_z", "")); + return Common::Input::ButtonNames::Value; } if (params.Has("motion")) { - return "SDL motion"; + return Common::Input::ButtonNames::Engine; } - return "Bad SDL"; + return Common::Input::ButtonNames::Invalid; } std::string SDLDriver::GetHatButtonName(u8 direction_value) const { diff --git a/src/input_common/drivers/sdl_driver.h b/src/input_common/drivers/sdl_driver.h index 3faaca984..d03ff4b84 100644 --- a/src/input_common/drivers/sdl_driver.h +++ b/src/input_common/drivers/sdl_driver.h @@ -53,7 +53,7 @@ public: ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage& params) override; AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage& params) override; MotionMapping GetMotionMappingForDevice(const Common::ParamPackage& params) override; - std::string GetUIName(const Common::ParamPackage& params) const override; + Common::Input::ButtonNames GetUIName(const Common::ParamPackage& params) const override; std::string GetHatButtonName(u8 direction_value) const override; u8 GetHatButtonId(const std::string& direction_name) const override; diff --git a/src/input_common/input_engine.h b/src/input_common/input_engine.h index c621686e5..02272b3f8 100644 --- a/src/input_common/input_engine.h +++ b/src/input_common/input_engine.h @@ -161,8 +161,9 @@ public: }; /// Retrieves the name of the given input. - virtual std::string GetUIName([[maybe_unused]] const Common::ParamPackage& params) const { - return GetEngineName(); + virtual Common::Input::ButtonNames GetUIName( + [[maybe_unused]] const Common::ParamPackage& params) const { + return Common::Input::ButtonNames::Engine; }; /// Retrieves the index number of the given hat button direction diff --git a/src/input_common/input_mapping.cpp b/src/input_common/input_mapping.cpp index 0eeeff372..c5218f2cb 100644 --- a/src/input_common/input_mapping.cpp +++ b/src/input_common/input_mapping.cpp @@ -61,6 +61,7 @@ void MappingFactory::RegisterButton(const MappingData& data) { } new_input.Set("port", static_cast(data.pad.port)); new_input.Set("pad", static_cast(data.pad.pad)); + switch (data.type) { case EngineInputType::Button: // Workaround for old compatibility @@ -75,6 +76,10 @@ void MappingFactory::RegisterButton(const MappingData& data) { new_input.Set("direction", data.hat_name); break; case EngineInputType::Analog: + // Ignore mouse axis when mapping buttons + if (data.engine == "mouse") { + return; + } new_input.Set("axis", data.index); new_input.Set("threshold", 0.5f); break; diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp index df36a337c..39e4935dc 100644 --- a/src/input_common/main.cpp +++ b/src/input_common/main.cpp @@ -205,9 +205,9 @@ struct InputSubsystem::Impl { return {}; } - std::string GetButtonName(const Common::ParamPackage& params) const { + Common::Input::ButtonNames GetButtonName(const Common::ParamPackage& params) const { if (!params.Has("engine") || params.Get("engine", "") == "any") { - return "Unknown"; + return Common::Input::ButtonNames::Undefined; } const std::string engine = params.Get("engine", ""); if (engine == mouse->GetEngineName()) { @@ -227,7 +227,7 @@ struct InputSubsystem::Impl { return sdl->GetUIName(params); } #endif - return "Bad engine"; + return Common::Input::ButtonNames::Invalid; } bool IsController(const Common::ParamPackage& params) { @@ -361,15 +361,8 @@ 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); +Common::Input::ButtonNames InputSubsystem::GetButtonName(const Common::ParamPackage& params) const { + return impl->GetButtonName(params); } bool InputSubsystem::IsController(const Common::ParamPackage& params) const { diff --git a/src/input_common/main.h b/src/input_common/main.h index a4a24d076..c6f97f691 100644 --- a/src/input_common/main.h +++ b/src/input_common/main.h @@ -13,6 +13,10 @@ namespace Common { class ParamPackage; } +namespace Common::Input { +enum class ButtonNames; +} + namespace Settings::NativeAnalog { enum Values : int; } @@ -108,8 +112,9 @@ 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; + /// Returns an enum contaning the name to be displayed from the input engine. + [[nodiscard]] Common::Input::ButtonNames GetButtonName( + const Common::ParamPackage& params) const; /// Returns true if device is a controller. [[nodiscard]] bool IsController(const Common::ParamPackage& params) const; diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index 0254ea6fe..6219a09a8 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp @@ -52,6 +52,37 @@ QString GetKeyName(int key_code) { } } +QString GetButtonName(Common::Input::ButtonNames button_name) { + switch (button_name) { + case Common::Input::ButtonNames::ButtonLeft: + return QObject::tr("Left"); + case Common::Input::ButtonNames::ButtonRight: + return QObject::tr("Right"); + case Common::Input::ButtonNames::ButtonDown: + return QObject::tr("Down"); + case Common::Input::ButtonNames::ButtonUp: + return QObject::tr("Up"); + case Common::Input::ButtonNames::TriggerZ: + return QObject::tr("Z"); + case Common::Input::ButtonNames::TriggerR: + return QObject::tr("R"); + case Common::Input::ButtonNames::TriggerL: + return QObject::tr("L"); + case Common::Input::ButtonNames::ButtonA: + return QObject::tr("A"); + case Common::Input::ButtonNames::ButtonB: + return QObject::tr("B"); + case Common::Input::ButtonNames::ButtonX: + return QObject::tr("X"); + case Common::Input::ButtonNames::ButtonY: + return QObject::tr("Y"); + case Common::Input::ButtonNames::ButtonStart: + return QObject::tr("Start"); + default: + return QObject::tr("[undefined]"); + } +} + void SetAnalogParam(const Common::ParamPackage& input_param, Common::ParamPackage& analog_param, const std::string& button_name) { // The poller returned a complete axis, so set all the buttons @@ -75,15 +106,64 @@ QString ConfigureInputPlayer::ButtonToText(const Common::ParamPackage& param) { return QObject::tr("[not set]"); } + const QString toggle = QString::fromStdString(param.Get("toggle", false) ? "~" : ""); + const QString inverted = QString::fromStdString(param.Get("inverted", false) ? "!" : ""); + const auto common_button_name = input_subsystem->GetButtonName(param); + // 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 (common_button_name == Common::Input::ButtonNames::Invalid) { + return QObject::tr("[invalid]"); + } + + if (common_button_name == Common::Input::ButtonNames::Engine) { + return QString::fromStdString(param.Get("engine", "")); + } + + if (common_button_name == Common::Input::ButtonNames::Value) { + if (param.Has("hat")) { + const QString hat = QString::fromStdString(param.Get("direction", "")); + return QObject::tr("%1%2Hat %3").arg(toggle, inverted, hat); + } + if (param.Has("axis")) { + const QString axis = QString::fromStdString(param.Get("axis", "")); + return QObject::tr("%1%2Axis %3").arg(toggle, inverted, axis); + } + if (param.Has("axis_x") && param.Has("axis_y") && param.Has("axis_z")) { + const QString axis_x = QString::fromStdString(param.Get("axis_x", "")); + const QString axis_y = QString::fromStdString(param.Get("axis_y", "")); + const QString axis_z = QString::fromStdString(param.Get("axis_z", "")); + return QObject::tr("%1%2Axis %3,%4,%5").arg(toggle, inverted, axis_x, axis_y, axis_z); + } + if (param.Has("motion")) { + const QString motion = QString::fromStdString(param.Get("motion", "")); + return QObject::tr("%1%2Motion %3").arg(toggle, inverted, motion); + } + if (param.Has("button")) { + const QString button = QString::fromStdString(param.Get("button", "")); + return QObject::tr("%1%2Button %3").arg(toggle, inverted, button); + } + } + + QString button_name = GetButtonName(common_button_name); + if (param.Has("hat")) { + return QObject::tr("%1%2Hat %3").arg(toggle, inverted, button_name); + } + if (param.Has("axis")) { + return QObject::tr("%1%2Axis %3").arg(toggle, inverted, button_name); + } + if (param.Has("motion")) { + return QObject::tr("%1%2Axis %3").arg(toggle, inverted, button_name); + } + if (param.Has("button")) { + return QObject::tr("%1%2Button %3").arg(toggle, inverted, button_name); + } + + return QObject::tr("[unknown]"); } QString ConfigureInputPlayer::AnalogToText(const Common::ParamPackage& param, -- cgit v1.2.3 From 639402850ac65c694967ef6519becb65abe89b39 Mon Sep 17 00:00:00 2001 From: Narr the Reg Date: Fri, 26 Nov 2021 15:45:37 -0600 Subject: input_common: Fully implement UDP controllers --- src/common/input.h | 14 ++ src/common/settings.h | 1 + src/core/hid/emulated_console.cpp | 6 +- src/input_common/drivers/udp_client.cpp | 206 ++++++++++++++++++++- src/input_common/drivers/udp_client.h | 56 ++++++ src/input_common/helpers/udp_protocol.h | 75 +++++--- src/input_common/input_mapping.cpp | 6 + src/input_common/main.cpp | 26 ++- src/yuzu/configuration/config.cpp | 2 + .../configuration/configure_input_advanced.cpp | 2 + src/yuzu/configuration/configure_input_advanced.ui | 19 +- src/yuzu/configuration/configure_input_player.cpp | 24 +++ 12 files changed, 397 insertions(+), 40 deletions(-) (limited to 'src/input_common/drivers') diff --git a/src/common/input.h b/src/common/input.h index cc0cbd9b8..eaee0bdea 100644 --- a/src/common/input.h +++ b/src/common/input.h @@ -195,6 +195,20 @@ enum class ButtonNames { ButtonX, ButtonY, ButtonStart, + + // DS4 button names + L1, + L2, + L3, + R1, + R2, + R3, + Circle, + Cross, + Square, + Triangle, + Share, + Options, }; // Callback data consisting of an input type and the equivalent data status diff --git a/src/common/settings.h b/src/common/settings.h index d7410fa9b..e4e049f67 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -560,6 +560,7 @@ struct Values { Setting motion_enabled{true, "motion_enabled"}; BasicSetting udp_input_servers{"127.0.0.1:26760", "udp_input_servers"}; + BasicSetting enable_udp_controller{false, "enable_udp_controller"}; BasicSetting pause_tas_on_load{true, "pause_tas_on_load"}; BasicSetting tas_enable{false, "tas_enable"}; diff --git a/src/core/hid/emulated_console.cpp b/src/core/hid/emulated_console.cpp index b224932dc..80db8e9c6 100644 --- a/src/core/hid/emulated_console.cpp +++ b/src/core/hid/emulated_console.cpp @@ -30,8 +30,10 @@ void EmulatedConsole::SetTouchParams() { } touch_params[index++] = Common::ParamPackage{"engine:touch,axis_x:0,axis_y:1,button:0"}; touch_params[index++] = Common::ParamPackage{"engine:touch,axis_x:2,axis_y:3,button:1"}; - touch_params[index++] = Common::ParamPackage{"engine:cemuhookudp,axis_x:0,axis_y:1,button:0"}; - touch_params[index++] = Common::ParamPackage{"engine:cemuhookudp,axis_x:2,axis_y:3,button:1"}; + touch_params[index++] = + Common::ParamPackage{"engine:cemuhookudp,axis_x:17,axis_y:18,button:65536"}; + touch_params[index++] = + Common::ParamPackage{"engine:cemuhookudp,axis_x:19,axis_y:20,button:131072"}; const auto button_index = static_cast(Settings::values.touch_from_button_map_index.GetValue()); diff --git a/src/input_common/drivers/udp_client.cpp b/src/input_common/drivers/udp_client.cpp index 7cab707da..fdee0f2d5 100644 --- a/src/input_common/drivers/udp_client.cpp +++ b/src/input_common/drivers/udp_client.cpp @@ -103,7 +103,7 @@ private: // Send a request for getting pad data for the pad const Request::PadData pad_data{ - Request::PadData::Flags::AllPorts, + Request::RegisterFlags::AllPads, 0, EMPTY_MAC_ADDRESS, }; @@ -247,7 +247,12 @@ void UDPClient::OnPadData(Response::PadData data, std::size_t client) { for (std::size_t id = 0; id < data.touch.size(); ++id) { const auto touch_pad = data.touch[id]; - const int touch_id = static_cast(client * 2 + id); + const auto touch_axis_x_id = + static_cast(id == 0 ? PadAxes::Touch1X : PadAxes::Touch2X); + const auto touch_axis_y_id = + static_cast(id == 0 ? PadAxes::Touch1Y : PadAxes::Touch2Y); + const auto touch_button_id = + static_cast(id == 0 ? PadButton::Touch1 : PadButton::touch2); // TODO: Use custom calibration per device const Common::ParamPackage touch_param(Settings::values.touch_device.GetValue()); @@ -264,14 +269,35 @@ void UDPClient::OnPadData(Response::PadData data, std::size_t client) { static_cast(max_y - min_y); if (touch_pad.is_active) { - SetAxis(identifier, touch_id * 2, x); - SetAxis(identifier, touch_id * 2 + 1, y); - SetButton(identifier, touch_id, true); + SetAxis(identifier, touch_axis_x_id, x); + SetAxis(identifier, touch_axis_y_id, y); + SetButton(identifier, touch_button_id, true); continue; } - SetAxis(identifier, touch_id * 2, 0); - SetAxis(identifier, touch_id * 2 + 1, 0); - SetButton(identifier, touch_id, false); + SetAxis(identifier, touch_axis_x_id, 0); + SetAxis(identifier, touch_axis_y_id, 0); + SetButton(identifier, touch_button_id, false); + } + + SetAxis(identifier, static_cast(PadAxes::LeftStickX), + (data.left_stick_x - 127.0f) / 127.0f); + SetAxis(identifier, static_cast(PadAxes::LeftStickY), + (data.left_stick_y - 127.0f) / 127.0f); + SetAxis(identifier, static_cast(PadAxes::RightStickX), + (data.right_stick_x - 127.0f) / 127.0f); + SetAxis(identifier, static_cast(PadAxes::RightStickY), + (data.right_stick_y - 127.0f) / 127.0f); + + static constexpr std::array buttons{ + PadButton::Share, PadButton::L3, PadButton::R3, PadButton::Options, + PadButton::Up, PadButton::Right, PadButton::Down, PadButton::Left, + PadButton::L2, PadButton::R2, PadButton::L1, PadButton::R1, + PadButton::Triangle, PadButton::Circle, PadButton::Cross, PadButton::Square}; + + for (std::size_t i = 0; i < buttons.size(); ++i) { + const bool button_status = (data.digital_button & (1U << i)) != 0; + const int button = static_cast(buttons[i]); + SetButton(identifier, button, button_status); } } @@ -317,6 +343,170 @@ void UDPClient::Reset() { } } +std::vector UDPClient::GetInputDevices() const { + std::vector devices; + if (!Settings::values.enable_udp_controller) { + return devices; + } + for (std::size_t client = 0; client < clients.size(); client++) { + if (clients[client].active != 1) { + continue; + } + for (std::size_t index = 0; index < PADS_PER_CLIENT; ++index) { + const std::size_t pad_index = client * PADS_PER_CLIENT + index; + if (!pads[pad_index].connected) { + continue; + } + const auto pad_identifier = GetPadIdentifier(pad_index); + Common::ParamPackage identifier{}; + identifier.Set("engine", GetEngineName()); + identifier.Set("display", fmt::format("UDP Controller {}", pad_identifier.pad)); + identifier.Set("guid", pad_identifier.guid.Format()); + identifier.Set("port", static_cast(pad_identifier.port)); + identifier.Set("pad", static_cast(pad_identifier.pad)); + devices.emplace_back(identifier); + } + } + return devices; +} + +ButtonMapping UDPClient::GetButtonMappingForDevice(const Common::ParamPackage& params) { + // This list excludes any button that can't be really mapped + static constexpr std::array, 18> + switch_to_dsu_button = { + std::pair{Settings::NativeButton::A, PadButton::Circle}, + {Settings::NativeButton::B, PadButton::Cross}, + {Settings::NativeButton::X, PadButton::Triangle}, + {Settings::NativeButton::Y, PadButton::Square}, + {Settings::NativeButton::Plus, PadButton::Options}, + {Settings::NativeButton::Minus, PadButton::Share}, + {Settings::NativeButton::DLeft, PadButton::Left}, + {Settings::NativeButton::DUp, PadButton::Up}, + {Settings::NativeButton::DRight, PadButton::Right}, + {Settings::NativeButton::DDown, PadButton::Down}, + {Settings::NativeButton::L, PadButton::L1}, + {Settings::NativeButton::R, PadButton::R1}, + {Settings::NativeButton::ZL, PadButton::L2}, + {Settings::NativeButton::ZR, PadButton::R2}, + {Settings::NativeButton::SL, PadButton::L2}, + {Settings::NativeButton::SR, PadButton::R2}, + {Settings::NativeButton::LStick, PadButton::L3}, + {Settings::NativeButton::RStick, PadButton::R3}, + }; + if (!params.Has("guid") || !params.Has("port") || !params.Has("pad")) { + return {}; + } + + ButtonMapping mapping{}; + for (const auto& [switch_button, dsu_button] : switch_to_dsu_button) { + Common::ParamPackage button_params{}; + button_params.Set("engine", GetEngineName()); + button_params.Set("guid", params.Get("guid", "")); + button_params.Set("port", params.Get("port", 0)); + button_params.Set("pad", params.Get("pad", 0)); + button_params.Set("button", static_cast(dsu_button)); + mapping.insert_or_assign(switch_button, std::move(button_params)); + } + + return mapping; +} + +AnalogMapping UDPClient::GetAnalogMappingForDevice(const Common::ParamPackage& params) { + if (!params.Has("guid") || !params.Has("port") || !params.Has("pad")) { + return {}; + } + + AnalogMapping mapping = {}; + Common::ParamPackage left_analog_params; + left_analog_params.Set("engine", GetEngineName()); + left_analog_params.Set("guid", params.Get("guid", "")); + left_analog_params.Set("port", params.Get("port", 0)); + left_analog_params.Set("pad", params.Get("pad", 0)); + left_analog_params.Set("axis_x", static_cast(PadAxes::LeftStickX)); + left_analog_params.Set("axis_y", static_cast(PadAxes::LeftStickY)); + mapping.insert_or_assign(Settings::NativeAnalog::LStick, std::move(left_analog_params)); + Common::ParamPackage right_analog_params; + right_analog_params.Set("engine", GetEngineName()); + right_analog_params.Set("guid", params.Get("guid", "")); + right_analog_params.Set("port", params.Get("port", 0)); + right_analog_params.Set("pad", params.Get("pad", 0)); + right_analog_params.Set("axis_x", static_cast(PadAxes::RightStickX)); + right_analog_params.Set("axis_y", static_cast(PadAxes::RightStickY)); + mapping.insert_or_assign(Settings::NativeAnalog::RStick, std::move(right_analog_params)); + return mapping; +} + +MotionMapping UDPClient::GetMotionMappingForDevice(const Common::ParamPackage& params) { + if (!params.Has("guid") || !params.Has("port") || !params.Has("pad")) { + return {}; + } + + MotionMapping mapping = {}; + Common::ParamPackage motion_params; + motion_params.Set("engine", GetEngineName()); + motion_params.Set("guid", params.Get("guid", "")); + motion_params.Set("port", params.Get("port", 0)); + motion_params.Set("pad", params.Get("pad", 0)); + motion_params.Set("motion", 0); + mapping.insert_or_assign(Settings::NativeMotion::MotionLeft, std::move(motion_params)); + mapping.insert_or_assign(Settings::NativeMotion::MotionRight, std::move(motion_params)); + return mapping; +} + +Common::Input::ButtonNames UDPClient::GetUIButtonName(const Common::ParamPackage& params) const { + PadButton button = static_cast(params.Get("button", 0)); + switch (button) { + case PadButton::Left: + return Common::Input::ButtonNames::ButtonLeft; + case PadButton::Right: + return Common::Input::ButtonNames::ButtonRight; + case PadButton::Down: + return Common::Input::ButtonNames::ButtonDown; + case PadButton::Up: + return Common::Input::ButtonNames::ButtonUp; + case PadButton::L1: + return Common::Input::ButtonNames::L1; + case PadButton::L2: + return Common::Input::ButtonNames::L2; + case PadButton::L3: + return Common::Input::ButtonNames::L3; + case PadButton::R1: + return Common::Input::ButtonNames::R1; + case PadButton::R2: + return Common::Input::ButtonNames::R2; + case PadButton::R3: + return Common::Input::ButtonNames::R3; + case PadButton::Circle: + return Common::Input::ButtonNames::Circle; + case PadButton::Cross: + return Common::Input::ButtonNames::Cross; + case PadButton::Square: + return Common::Input::ButtonNames::Square; + case PadButton::Triangle: + return Common::Input::ButtonNames::Triangle; + case PadButton::Share: + return Common::Input::ButtonNames::Share; + case PadButton::Options: + return Common::Input::ButtonNames::Options; + default: + return Common::Input::ButtonNames::Undefined; + } +} + +Common::Input::ButtonNames UDPClient::GetUIName(const Common::ParamPackage& params) const { + if (params.Has("button")) { + return GetUIButtonName(params); + } + if (params.Has("axis")) { + return Common::Input::ButtonNames::Value; + } + if (params.Has("motion")) { + return Common::Input::ButtonNames::Engine; + } + + return Common::Input::ButtonNames::Invalid; +} + void TestCommunication(const std::string& host, u16 port, const std::function& success_callback, const std::function& failure_callback) { diff --git a/src/input_common/drivers/udp_client.h b/src/input_common/drivers/udp_client.h index 1f02adba5..5d483f26b 100644 --- a/src/input_common/drivers/udp_client.h +++ b/src/input_common/drivers/udp_client.h @@ -56,7 +56,61 @@ public: void ReloadSockets(); + /// Used for automapping features + std::vector GetInputDevices() const override; + ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage& params) override; + AnalogMapping GetAnalogMappingForDevice(const Common::ParamPackage& params) override; + MotionMapping GetMotionMappingForDevice(const Common::ParamPackage& params) override; + Common::Input::ButtonNames GetUIName(const Common::ParamPackage& params) const override; + private: + enum class PadButton { + Undefined = 0x0000, + Share = 0x0001, + L3 = 0x0002, + R3 = 0x0004, + Options = 0x0008, + Up = 0x0010, + Right = 0x0020, + Down = 0x0040, + Left = 0x0080, + L2 = 0x0100, + R2 = 0x0200, + L1 = 0x0400, + R1 = 0x0800, + Triangle = 0x1000, + Circle = 0x2000, + Cross = 0x4000, + Square = 0x8000, + Touch1 = 0x10000, + touch2 = 0x20000, + }; + + enum class PadAxes : u8 { + LeftStickX, + LeftStickY, + RightStickX, + RightStickY, + AnalogLeft, + AnalogDown, + AnalogRight, + AnalogUp, + AnalogSquare, + AnalogCross, + AnalogCircle, + AnalogTriangle, + AnalogR1, + AnalogL1, + AnalogR2, + AnalogL3, + AnalogR3, + Touch1X, + Touch1Y, + Touch2X, + Touch2Y, + Undefined, + }; + struct PadData { std::size_t pad_index{}; bool connected{}; @@ -90,6 +144,8 @@ private: const PadIdentifier GetPadIdentifier(std::size_t pad_index) const; const Common::UUID GetHostUUID(const std::string host) const; + Common::Input::ButtonNames GetUIButtonName(const Common::ParamPackage& params) const; + // Allocate clients for 8 udp servers static constexpr std::size_t MAX_UDP_CLIENTS = 8; static constexpr std::size_t PADS_PER_CLIENT = 4; diff --git a/src/input_common/helpers/udp_protocol.h b/src/input_common/helpers/udp_protocol.h index 1bdc9209e..bcba12c58 100644 --- a/src/input_common/helpers/udp_protocol.h +++ b/src/input_common/helpers/udp_protocol.h @@ -56,6 +56,12 @@ constexpr Type GetMessageType(); namespace Request { +enum RegisterFlags : u8 { + AllPads, + PadID, + PadMACAdddress, +}; + struct Version {}; /** * Requests the server to send information about what controllers are plugged into the ports @@ -77,13 +83,8 @@ static_assert(std::is_trivially_copyable_v, * timeout seems to be 5 seconds. */ struct PadData { - enum class Flags : u8 { - AllPorts, - Id, - Mac, - }; /// Determines which method will be used as a look up for the controller - Flags flags{}; + RegisterFlags flags{}; /// Index of the port of the controller to retrieve data about u8 port_id{}; /// Mac address of the controller to retrieve data about @@ -113,6 +114,36 @@ Message Create(const T data, const u32 client_id = 0) { namespace Response { +enum class ConnectionType : u8 { + None, + Usb, + Bluetooth, +}; + +enum class State : u8 { + Disconnected, + Reserved, + Connected, +}; + +enum class Model : u8 { + None, + PartialGyro, + FullGyro, + Generic, +}; + +enum class Battery : u8 { + None = 0x00, + Dying = 0x01, + Low = 0x02, + Medium = 0x03, + High = 0x04, + Full = 0x05, + Charging = 0xEE, + Charged = 0xEF, +}; + struct Version { u16_le version{}; }; @@ -122,11 +153,11 @@ static_assert(std::is_trivially_copyable_v, struct PortInfo { u8 id{}; - u8 state{}; - u8 model{}; - u8 connection_type{}; + State state{}; + Model model{}; + ConnectionType connection_type{}; MacAddress mac; - u8 battery{}; + Battery battery{}; u8 is_pad_active{}; }; static_assert(sizeof(PortInfo) == 12, "UDP Response PortInfo struct has wrong size"); @@ -177,18 +208,18 @@ struct PadData { u8 right_stick_y{}; struct AnalogButton { - u8 button_8{}; - u8 button_7{}; - u8 button_6{}; - u8 button_5{}; - u8 button_12{}; - u8 button_11{}; - u8 button_10{}; - u8 button_9{}; - u8 button_16{}; - u8 button_15{}; - u8 button_14{}; - u8 button_13{}; + u8 button_dpad_left_analog{}; + u8 button_dpad_down_analog{}; + u8 button_dpad_right_analog{}; + u8 button_dpad_up_analog{}; + u8 button_square_analog{}; + u8 button_cross_analog{}; + u8 button_circle_analog{}; + u8 button_triangle_analog{}; + u8 button_r1_analog{}; + u8 button_l1_analog{}; + u8 trigger_r2{}; + u8 trigger_l2{}; } analog_button; std::array touch; diff --git a/src/input_common/input_mapping.cpp b/src/input_common/input_mapping.cpp index c5218f2cb..6e0024b2d 100644 --- a/src/input_common/input_mapping.cpp +++ b/src/input_common/input_mapping.cpp @@ -3,6 +3,7 @@ // Refer to the license.txt file included #include "common/common_types.h" +#include "common/settings.h" #include "input_common/input_engine.h" #include "input_common/input_mapping.h" @@ -182,6 +183,11 @@ bool MappingFactory::IsDriverValid(const MappingData& data) const { if (data.engine == "keyboard" && data.pad.port != 0) { return false; } + // To prevent mapping with two devices we disable any UDP except motion + if (!Settings::values.enable_udp_controller && data.engine == "cemuhookudp" && + data.type != EngineInputType::Motion) { + return false; + } // The following drivers don't need to be mapped if (data.engine == "tas") { return false; diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp index 39e4935dc..940744c5f 100644 --- a/src/input_common/main.cpp +++ b/src/input_common/main.cpp @@ -63,9 +63,12 @@ struct InputSubsystem::Impl { udp_client = std::make_shared("cemuhookudp"); udp_client->SetMappingCallback(mapping_callback); - udp_client_factory = std::make_shared(udp_client); + udp_client_input_factory = std::make_shared(udp_client); + udp_client_output_factory = std::make_shared(udp_client); Common::Input::RegisterFactory(udp_client->GetEngineName(), - udp_client_factory); + udp_client_input_factory); + Common::Input::RegisterFactory(udp_client->GetEngineName(), + udp_client_output_factory); tas_input = std::make_shared("tas"); tas_input->SetMappingCallback(mapping_callback); @@ -110,6 +113,7 @@ struct InputSubsystem::Impl { gcadapter.reset(); Common::Input::UnregisterFactory(udp_client->GetEngineName()); + Common::Input::UnregisterFactory(udp_client->GetEngineName()); udp_client.reset(); Common::Input::UnregisterFactory(tas_input->GetEngineName()); @@ -137,6 +141,8 @@ struct InputSubsystem::Impl { devices.insert(devices.end(), mouse_devices.begin(), mouse_devices.end()); auto gcadapter_devices = gcadapter->GetInputDevices(); devices.insert(devices.end(), gcadapter_devices.begin(), gcadapter_devices.end()); + auto udp_devices = udp_client->GetInputDevices(); + devices.insert(devices.end(), udp_devices.begin(), udp_devices.end()); #ifdef HAVE_SDL2 auto sdl_devices = sdl->GetInputDevices(); devices.insert(devices.end(), sdl_devices.begin(), sdl_devices.end()); @@ -157,6 +163,9 @@ struct InputSubsystem::Impl { if (engine == gcadapter->GetEngineName()) { return gcadapter->GetAnalogMappingForDevice(params); } + if (engine == udp_client->GetEngineName()) { + return udp_client->GetAnalogMappingForDevice(params); + } if (engine == tas_input->GetEngineName()) { return tas_input->GetAnalogMappingForDevice(params); } @@ -177,6 +186,9 @@ struct InputSubsystem::Impl { if (engine == gcadapter->GetEngineName()) { return gcadapter->GetButtonMappingForDevice(params); } + if (engine == udp_client->GetEngineName()) { + return udp_client->GetButtonMappingForDevice(params); + } if (engine == tas_input->GetEngineName()) { return tas_input->GetButtonMappingForDevice(params); } @@ -194,8 +206,8 @@ struct InputSubsystem::Impl { return {}; } const std::string engine = params.Get("engine", ""); - if (engine == gcadapter->GetEngineName()) { - return gcadapter->GetMotionMappingForDevice(params); + if (engine == udp_client->GetEngineName()) { + return udp_client->GetMotionMappingForDevice(params); } #ifdef HAVE_SDL2 if (engine == sdl->GetEngineName()) { @@ -238,6 +250,9 @@ struct InputSubsystem::Impl { if (engine == gcadapter->GetEngineName()) { return true; } + if (engine == udp_client->GetEngineName()) { + return true; + } if (engine == tas_input->GetEngineName()) { return true; } @@ -286,12 +301,13 @@ struct InputSubsystem::Impl { 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 udp_client_input_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 udp_client_output_factory; std::shared_ptr tas_output_factory; #ifdef HAVE_SDL2 diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index ae1684dd4..38fd6e93b 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -447,6 +447,7 @@ void Config::ReadMotionTouchValues() { Settings::values.touch_from_button_map_index = std::clamp( Settings::values.touch_from_button_map_index.GetValue(), 0, num_touch_from_button_maps - 1); ReadBasicSetting(Settings::values.udp_input_servers); + ReadBasicSetting(Settings::values.enable_udp_controller); } void Config::ReadCoreValues() { @@ -942,6 +943,7 @@ void Config::SaveMotionTouchValues() { WriteBasicSetting(Settings::values.touch_device); WriteBasicSetting(Settings::values.touch_from_button_map_index); WriteBasicSetting(Settings::values.udp_input_servers); + WriteBasicSetting(Settings::values.enable_udp_controller); qt_config->beginWriteArray(QStringLiteral("touch_from_button_maps")); for (std::size_t p = 0; p < Settings::values.touch_from_button_maps.size(); ++p) { diff --git a/src/yuzu/configuration/configure_input_advanced.cpp b/src/yuzu/configuration/configure_input_advanced.cpp index e6127f9e6..65c8e59ac 100644 --- a/src/yuzu/configuration/configure_input_advanced.cpp +++ b/src/yuzu/configuration/configure_input_advanced.cpp @@ -130,6 +130,7 @@ void ConfigureInputAdvanced::ApplyConfiguration() { static_cast(ui->mouse_panning_sensitivity->value()); Settings::values.touchscreen.enabled = ui->touchscreen_enabled->isChecked(); Settings::values.enable_raw_input = ui->enable_raw_input->isChecked(); + Settings::values.enable_udp_controller = ui->enable_udp_controller->isChecked(); } void ConfigureInputAdvanced::LoadConfiguration() { @@ -160,6 +161,7 @@ void ConfigureInputAdvanced::LoadConfiguration() { ui->mouse_panning_sensitivity->setValue(Settings::values.mouse_panning_sensitivity.GetValue()); ui->touchscreen_enabled->setChecked(Settings::values.touchscreen.enabled); ui->enable_raw_input->setChecked(Settings::values.enable_raw_input.GetValue()); + ui->enable_udp_controller->setChecked(Settings::values.enable_udp_controller.GetValue()); UpdateUIEnabled(); } diff --git a/src/yuzu/configuration/configure_input_advanced.ui b/src/yuzu/configuration/configure_input_advanced.ui index 75487a5d0..df0e4d602 100644 --- a/src/yuzu/configuration/configure_input_advanced.ui +++ b/src/yuzu/configuration/configure_input_advanced.ui @@ -2642,6 +2642,19 @@ + + + + 0 + 23 + + + + Enable UDP controllers (not needed for motion) + + + + @@ -2654,7 +2667,7 @@ - + Mouse sensitivity @@ -2676,14 +2689,14 @@ - + Motion / Touch - + Configure diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index 6219a09a8..ec071d6ec 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp @@ -78,6 +78,30 @@ QString GetButtonName(Common::Input::ButtonNames button_name) { return QObject::tr("Y"); case Common::Input::ButtonNames::ButtonStart: return QObject::tr("Start"); + case Common::Input::ButtonNames::L1: + return QObject::tr("L1"); + case Common::Input::ButtonNames::L2: + return QObject::tr("L2"); + case Common::Input::ButtonNames::L3: + return QObject::tr("L3"); + case Common::Input::ButtonNames::R1: + return QObject::tr("R1"); + case Common::Input::ButtonNames::R2: + return QObject::tr("R2"); + case Common::Input::ButtonNames::R3: + return QObject::tr("R3"); + case Common::Input::ButtonNames::Circle: + return QObject::tr("Circle"); + case Common::Input::ButtonNames::Cross: + return QObject::tr("Cross"); + case Common::Input::ButtonNames::Square: + return QObject::tr("Square"); + case Common::Input::ButtonNames::Triangle: + return QObject::tr("Triangle"); + case Common::Input::ButtonNames::Share: + return QObject::tr("Share"); + case Common::Input::ButtonNames::Options: + return QObject::tr("Options"); default: return QObject::tr("[undefined]"); } -- cgit v1.2.3 From e4492a9a821659cd0c4e874234020cdb630a108b Mon Sep 17 00:00:00 2001 From: Narr the Reg Date: Mon, 29 Nov 2021 21:03:47 -0600 Subject: input_common: Fix error with thread name --- src/input_common/drivers/sdl_driver.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/input_common/drivers') diff --git a/src/input_common/drivers/sdl_driver.cpp b/src/input_common/drivers/sdl_driver.cpp index 90128b6cf..1052ed394 100644 --- a/src/input_common/drivers/sdl_driver.cpp +++ b/src/input_common/drivers/sdl_driver.cpp @@ -388,8 +388,6 @@ void SDLDriver::CloseJoysticks() { } SDLDriver::SDLDriver(const std::string& input_engine_) : InputEngine(input_engine_) { - Common::SetCurrentThreadName("yuzu:input:SDL"); - if (!Settings::values.enable_raw_input) { // Disable raw input. When enabled this setting causes SDL to die when a web applet opens SDL_SetHint(SDL_HINT_JOYSTICK_RAWINPUT, "0"); @@ -422,6 +420,7 @@ SDLDriver::SDLDriver(const std::string& input_engine_) : InputEngine(input_engin initialized = true; if (start_thread) { poll_thread = std::thread([this] { + Common::SetCurrentThreadName("yuzu:input:SDL"); using namespace std::chrono_literals; while (initialized) { SDL_PumpEvents(); -- cgit v1.2.3 From 2b92d22bda767c7c723935c357bea474f8e2d2f8 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 13 Dec 2021 09:05:23 -0500 Subject: input_engine: std::move engine name where applicable We can allow the name to be moved into, allowing allocations to be avoided. --- src/input_common/drivers/gc_adapter.cpp | 2 +- src/input_common/drivers/gc_adapter.h | 6 +++--- src/input_common/drivers/keyboard.cpp | 2 +- src/input_common/drivers/keyboard.h | 4 ++-- src/input_common/drivers/mouse.cpp | 2 +- src/input_common/drivers/mouse.h | 4 ++-- src/input_common/drivers/sdl_driver.cpp | 2 +- src/input_common/drivers/sdl_driver.h | 12 ++++++------ src/input_common/drivers/tas_input.cpp | 2 +- src/input_common/drivers/tas_input.h | 6 +++--- src/input_common/drivers/touch_screen.cpp | 2 +- src/input_common/drivers/touch_screen.h | 4 ++-- src/input_common/drivers/udp_client.cpp | 2 +- src/input_common/drivers/udp_client.h | 6 +++--- src/input_common/input_engine.h | 2 +- 15 files changed, 29 insertions(+), 29 deletions(-) (limited to 'src/input_common/drivers') diff --git a/src/input_common/drivers/gc_adapter.cpp b/src/input_common/drivers/gc_adapter.cpp index 8b6574223..451147755 100644 --- a/src/input_common/drivers/gc_adapter.cpp +++ b/src/input_common/drivers/gc_adapter.cpp @@ -69,7 +69,7 @@ private: libusb_device_handle* handle{}; }; -GCAdapter::GCAdapter(const std::string& input_engine_) : InputEngine(input_engine_) { +GCAdapter::GCAdapter(std::string input_engine_) : InputEngine(std::move(input_engine_)) { if (usb_adapter_handle) { return; } diff --git a/src/input_common/drivers/gc_adapter.h b/src/input_common/drivers/gc_adapter.h index 8dc51d2e5..3c4f0396c 100644 --- a/src/input_common/drivers/gc_adapter.h +++ b/src/input_common/drivers/gc_adapter.h @@ -22,10 +22,10 @@ namespace InputCommon { class LibUSBContext; class LibUSBDeviceHandle; -class GCAdapter : public InputCommon::InputEngine { +class GCAdapter : public InputEngine { public: - explicit GCAdapter(const std::string& input_engine_); - ~GCAdapter(); + explicit GCAdapter(std::string input_engine_); + ~GCAdapter() override; Common::Input::VibrationError SetRumble( const PadIdentifier& identifier, const Common::Input::VibrationStatus vibration) override; diff --git a/src/input_common/drivers/keyboard.cpp b/src/input_common/drivers/keyboard.cpp index 23b0c0ccf..4c1e5bbec 100644 --- a/src/input_common/drivers/keyboard.cpp +++ b/src/input_common/drivers/keyboard.cpp @@ -24,7 +24,7 @@ constexpr PadIdentifier keyboard_modifier_identifier = { .pad = 1, }; -Keyboard::Keyboard(const std::string& input_engine_) : InputEngine(input_engine_) { +Keyboard::Keyboard(std::string input_engine_) : InputEngine(std::move(input_engine_)) { // Keyboard is broken into 3 diferent sets: // key: Unfiltered intended for controllers. // keyboard_key: Allows only Settings::NativeKeyboard::Keys intended for keyboard emulation. diff --git a/src/input_common/drivers/keyboard.h b/src/input_common/drivers/keyboard.h index ad123b136..3856c882c 100644 --- a/src/input_common/drivers/keyboard.h +++ b/src/input_common/drivers/keyboard.h @@ -12,9 +12,9 @@ namespace InputCommon { * A button device factory representing a keyboard. It receives keyboard events and forward them * to all button devices it created. */ -class Keyboard final : public InputCommon::InputEngine { +class Keyboard final : public InputEngine { public: - explicit Keyboard(const std::string& input_engine_); + explicit Keyboard(std::string input_engine_); /** * Sets the status of all buttons bound with the key to pressed diff --git a/src/input_common/drivers/mouse.cpp b/src/input_common/drivers/mouse.cpp index 752118e97..aa69216c8 100644 --- a/src/input_common/drivers/mouse.cpp +++ b/src/input_common/drivers/mouse.cpp @@ -24,7 +24,7 @@ constexpr PadIdentifier identifier = { .pad = 0, }; -Mouse::Mouse(const std::string& input_engine_) : InputEngine(input_engine_) { +Mouse::Mouse(std::string input_engine_) : InputEngine(std::move(input_engine_)) { PreSetController(identifier); PreSetAxis(identifier, mouse_axis_x); PreSetAxis(identifier, mouse_axis_y); diff --git a/src/input_common/drivers/mouse.h b/src/input_common/drivers/mouse.h index 4a1fd2fd9..040446178 100644 --- a/src/input_common/drivers/mouse.h +++ b/src/input_common/drivers/mouse.h @@ -27,9 +27,9 @@ enum class MouseButton { * A button device factory representing a keyboard. It receives keyboard events and forward them * to all button devices it created. */ -class Mouse final : public InputCommon::InputEngine { +class Mouse final : public InputEngine { public: - explicit Mouse(const std::string& input_engine_); + explicit Mouse(std::string input_engine_); /** * Signals that mouse has moved. diff --git a/src/input_common/drivers/sdl_driver.cpp b/src/input_common/drivers/sdl_driver.cpp index 1052ed394..1bae6cdc8 100644 --- a/src/input_common/drivers/sdl_driver.cpp +++ b/src/input_common/drivers/sdl_driver.cpp @@ -387,7 +387,7 @@ void SDLDriver::CloseJoysticks() { joystick_map.clear(); } -SDLDriver::SDLDriver(const std::string& input_engine_) : InputEngine(input_engine_) { +SDLDriver::SDLDriver(std::string input_engine_) : InputEngine(std::move(input_engine_)) { if (!Settings::values.enable_raw_input) { // Disable raw input. When enabled this setting causes SDL to die when a web applet opens SDL_SetHint(SDL_HINT_JOYSTICK_RAWINPUT, "0"); diff --git a/src/input_common/drivers/sdl_driver.h b/src/input_common/drivers/sdl_driver.h index d03ff4b84..c6fffe374 100644 --- a/src/input_common/drivers/sdl_driver.h +++ b/src/input_common/drivers/sdl_driver.h @@ -19,19 +19,19 @@ using SDL_GameController = struct _SDL_GameController; using SDL_Joystick = struct _SDL_Joystick; using SDL_JoystickID = s32; +namespace InputCommon { + +class SDLJoystick; + using ButtonBindings = std::array, 17>; using ZButtonBindings = std::array, 2>; -namespace InputCommon { - -class SDLJoystick; - -class SDLDriver : public InputCommon::InputEngine { +class SDLDriver : public InputEngine { public: /// Initializes and registers SDL device factories - SDLDriver(const std::string& input_engine_); + explicit SDLDriver(std::string input_engine_); /// Unregisters SDL device factories and shut them down. ~SDLDriver() override; diff --git a/src/input_common/drivers/tas_input.cpp b/src/input_common/drivers/tas_input.cpp index 0e01fb0d9..a2bedc951 100644 --- a/src/input_common/drivers/tas_input.cpp +++ b/src/input_common/drivers/tas_input.cpp @@ -47,7 +47,7 @@ constexpr std::array, 20> text_to_tas_but {"KEY_ZR", TasButton::TRIGGER_ZR}, }; -Tas::Tas(const std::string& input_engine_) : InputCommon::InputEngine(input_engine_) { +Tas::Tas(std::string input_engine_) : InputEngine(std::move(input_engine_)) { for (size_t player_index = 0; player_index < PLAYER_NUMBER; player_index++) { PadIdentifier identifier{ .guid = Common::UUID{}, diff --git a/src/input_common/drivers/tas_input.h b/src/input_common/drivers/tas_input.h index c95a130fc..9a7f98727 100644 --- a/src/input_common/drivers/tas_input.h +++ b/src/input_common/drivers/tas_input.h @@ -81,10 +81,10 @@ enum class TasState { Stopped, }; -class Tas final : public InputCommon::InputEngine { +class Tas final : public InputEngine { public: - explicit Tas(const std::string& input_engine_); - ~Tas(); + explicit Tas(std::string input_engine_); + ~Tas() override; /** * Changes the input status that will be stored in each frame diff --git a/src/input_common/drivers/touch_screen.cpp b/src/input_common/drivers/touch_screen.cpp index 45b3086f6..880781825 100644 --- a/src/input_common/drivers/touch_screen.cpp +++ b/src/input_common/drivers/touch_screen.cpp @@ -13,7 +13,7 @@ constexpr PadIdentifier identifier = { .pad = 0, }; -TouchScreen::TouchScreen(const std::string& input_engine_) : InputEngine(input_engine_) { +TouchScreen::TouchScreen(std::string input_engine_) : InputEngine(std::move(input_engine_)) { PreSetController(identifier); } diff --git a/src/input_common/drivers/touch_screen.h b/src/input_common/drivers/touch_screen.h index 25c11e8bf..bf395c40b 100644 --- a/src/input_common/drivers/touch_screen.h +++ b/src/input_common/drivers/touch_screen.h @@ -12,9 +12,9 @@ namespace InputCommon { * A button device factory representing a keyboard. It receives keyboard events and forward them * to all button devices it created. */ -class TouchScreen final : public InputCommon::InputEngine { +class TouchScreen final : public InputEngine { public: - explicit TouchScreen(const std::string& input_engine_); + explicit TouchScreen(std::string input_engine_); /** * Signals that mouse has moved. diff --git a/src/input_common/drivers/udp_client.cpp b/src/input_common/drivers/udp_client.cpp index fdee0f2d5..4ab991a7d 100644 --- a/src/input_common/drivers/udp_client.cpp +++ b/src/input_common/drivers/udp_client.cpp @@ -136,7 +136,7 @@ static void SocketLoop(Socket* socket) { socket->Loop(); } -UDPClient::UDPClient(const std::string& input_engine_) : InputEngine(input_engine_) { +UDPClient::UDPClient(std::string input_engine_) : InputEngine(std::move(input_engine_)) { LOG_INFO(Input, "Udp Initialization started"); ReloadSockets(); } diff --git a/src/input_common/drivers/udp_client.h b/src/input_common/drivers/udp_client.h index 5d483f26b..1adc947c4 100644 --- a/src/input_common/drivers/udp_client.h +++ b/src/input_common/drivers/udp_client.h @@ -49,10 +49,10 @@ struct DeviceStatus { * A button device factory representing a keyboard. It receives keyboard events and forward them * to all button devices it created. */ -class UDPClient final : public InputCommon::InputEngine { +class UDPClient final : public InputEngine { public: - explicit UDPClient(const std::string& input_engine_); - ~UDPClient(); + explicit UDPClient(std::string input_engine_); + ~UDPClient() override; void ReloadSockets(); diff --git a/src/input_common/input_engine.h b/src/input_common/input_engine.h index 44accd0be..b21adfabf 100644 --- a/src/input_common/input_engine.h +++ b/src/input_common/input_engine.h @@ -102,7 +102,7 @@ struct InputIdentifier { class InputEngine { public: - explicit InputEngine(const std::string& input_engine_) : input_engine(input_engine_) {} + explicit InputEngine(std::string input_engine_) : input_engine{std::move(input_engine_)} {} virtual ~InputEngine() = default; -- cgit v1.2.3 From 38f3442ea56a3ac9447924c015c2a9ade0f5bb83 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 13 Dec 2021 09:09:03 -0500 Subject: input_engine: Pass VibrationStatus by const reference in SetRumble() Avoids creating copies of the struct where not necessary. --- src/common/input.h | 6 ++---- src/input_common/drivers/gc_adapter.cpp | 4 ++-- src/input_common/drivers/gc_adapter.h | 2 +- src/input_common/drivers/sdl_driver.cpp | 6 ++++-- src/input_common/drivers/sdl_driver.h | 2 +- src/input_common/input_engine.h | 2 +- src/input_common/input_poller.cpp | 2 +- 7 files changed, 12 insertions(+), 12 deletions(-) (limited to 'src/input_common/drivers') diff --git a/src/common/input.h b/src/common/input.h index eaee0bdea..12d5d976f 100644 --- a/src/common/input.h +++ b/src/common/input.h @@ -266,11 +266,9 @@ class OutputDevice { public: virtual ~OutputDevice() = default; - virtual void SetLED([[maybe_unused]] LedStatus led_status) { - return; - } + virtual void SetLED([[maybe_unused]] LedStatus led_status) {} - virtual VibrationError SetVibration([[maybe_unused]] VibrationStatus vibration_status) { + virtual VibrationError SetVibration([[maybe_unused]] const VibrationStatus& vibration_status) { return VibrationError::NotSupported; } diff --git a/src/input_common/drivers/gc_adapter.cpp b/src/input_common/drivers/gc_adapter.cpp index 451147755..7ab4540a8 100644 --- a/src/input_common/drivers/gc_adapter.cpp +++ b/src/input_common/drivers/gc_adapter.cpp @@ -325,8 +325,8 @@ bool GCAdapter::GetGCEndpoint(libusb_device* device) { return true; } -Common::Input::VibrationError GCAdapter::SetRumble(const PadIdentifier& identifier, - const Common::Input::VibrationStatus vibration) { +Common::Input::VibrationError GCAdapter::SetRumble( + const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) { const auto mean_amplitude = (vibration.low_amplitude + vibration.high_amplitude) * 0.5f; const auto processed_amplitude = static_cast((mean_amplitude + std::pow(mean_amplitude, 0.3f)) * 0.5f * 0x8); diff --git a/src/input_common/drivers/gc_adapter.h b/src/input_common/drivers/gc_adapter.h index 3c4f0396c..7ce1912a3 100644 --- a/src/input_common/drivers/gc_adapter.h +++ b/src/input_common/drivers/gc_adapter.h @@ -28,7 +28,7 @@ public: ~GCAdapter() override; Common::Input::VibrationError SetRumble( - const PadIdentifier& identifier, const Common::Input::VibrationStatus vibration) override; + const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) override; /// Used for automapping features std::vector GetInputDevices() const override; diff --git a/src/input_common/drivers/sdl_driver.cpp b/src/input_common/drivers/sdl_driver.cpp index 1bae6cdc8..a9219dbf2 100644 --- a/src/input_common/drivers/sdl_driver.cpp +++ b/src/input_common/drivers/sdl_driver.cpp @@ -491,8 +491,9 @@ std::vector SDLDriver::GetInputDevices() const { } return devices; } -Common::Input::VibrationError SDLDriver::SetRumble(const PadIdentifier& identifier, - const Common::Input::VibrationStatus vibration) { + +Common::Input::VibrationError SDLDriver::SetRumble( + const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) { const auto joystick = GetSDLJoystickByGUID(identifier.guid.Format(), static_cast(identifier.port)); const auto process_amplitude_exp = [](f32 amplitude, f32 factor) { @@ -526,6 +527,7 @@ Common::Input::VibrationError SDLDriver::SetRumble(const PadIdentifier& identifi return Common::Input::VibrationError::None; } + Common::ParamPackage SDLDriver::BuildAnalogParamPackageForButton(int port, std::string guid, s32 axis, float value) const { Common::ParamPackage params{}; diff --git a/src/input_common/drivers/sdl_driver.h b/src/input_common/drivers/sdl_driver.h index c6fffe374..e9a5d2e26 100644 --- a/src/input_common/drivers/sdl_driver.h +++ b/src/input_common/drivers/sdl_driver.h @@ -59,7 +59,7 @@ public: u8 GetHatButtonId(const std::string& direction_name) const override; Common::Input::VibrationError SetRumble( - const PadIdentifier& identifier, const Common::Input::VibrationStatus vibration) override; + const PadIdentifier& identifier, const Common::Input::VibrationStatus& vibration) override; private: void InitJoystick(int joystick_index); diff --git a/src/input_common/input_engine.h b/src/input_common/input_engine.h index b21adfabf..15cd5fa2e 100644 --- a/src/input_common/input_engine.h +++ b/src/input_common/input_engine.h @@ -119,7 +119,7 @@ public: // Sets rumble to a controller virtual Common::Input::VibrationError SetRumble( [[maybe_unused]] const PadIdentifier& identifier, - [[maybe_unused]] const Common::Input::VibrationStatus vibration) { + [[maybe_unused]] const Common::Input::VibrationStatus& vibration) { return Common::Input::VibrationError::NotSupported; } diff --git a/src/input_common/input_poller.cpp b/src/input_common/input_poller.cpp index 7e4eafded..de63f36b3 100644 --- a/src/input_common/input_poller.cpp +++ b/src/input_common/input_poller.cpp @@ -673,7 +673,7 @@ public: } virtual Common::Input::VibrationError SetVibration( - Common::Input::VibrationStatus vibration_status) { + const Common::Input::VibrationStatus& vibration_status) { return input_engine->SetRumble(identifier, vibration_status); } -- cgit v1.2.3 From 755822ceecf2a261a09f486706955bebc23d3917 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 13 Dec 2021 09:26:44 -0500 Subject: input_engine: Take BasicMotion by const reference with SetMotion() and TriggerOnMotionChange() Copies the BasicMotion instance once instead of twice. --- src/input_common/drivers/sdl_driver.cpp | 4 ++-- src/input_common/input_engine.cpp | 4 ++-- src/input_common/input_engine.h | 5 +++-- 3 files changed, 7 insertions(+), 6 deletions(-) (limited to 'src/input_common/drivers') diff --git a/src/input_common/drivers/sdl_driver.cpp b/src/input_common/drivers/sdl_driver.cpp index a9219dbf2..e33a5ff31 100644 --- a/src/input_common/drivers/sdl_driver.cpp +++ b/src/input_common/drivers/sdl_driver.cpp @@ -88,7 +88,7 @@ public: return true; } - BasicMotion GetMotion() { + const BasicMotion& GetMotion() const { return motion; } @@ -367,7 +367,7 @@ void SDLDriver::HandleGameControllerEvent(const SDL_Event& event) { if (joystick->UpdateMotion(event.csensor)) { const PadIdentifier identifier = joystick->GetPadIdentifier(); SetMotion(identifier, 0, joystick->GetMotion()); - }; + } } break; } diff --git a/src/input_common/input_engine.cpp b/src/input_common/input_engine.cpp index 6b057e2f1..5481607bf 100644 --- a/src/input_common/input_engine.cpp +++ b/src/input_common/input_engine.cpp @@ -91,7 +91,7 @@ void InputEngine::SetBattery(const PadIdentifier& identifier, BatteryLevel value TriggerOnBatteryChange(identifier, value); } -void InputEngine::SetMotion(const PadIdentifier& identifier, int motion, BasicMotion value) { +void InputEngine::SetMotion(const PadIdentifier& identifier, int motion, const BasicMotion& value) { { std::lock_guard lock{mutex}; ControllerData& controller = controller_list.at(identifier); @@ -286,7 +286,7 @@ void InputEngine::TriggerOnBatteryChange(const PadIdentifier& identifier, } void InputEngine::TriggerOnMotionChange(const PadIdentifier& identifier, int motion, - BasicMotion value) { + const BasicMotion& value) { std::lock_guard lock{mutex_callback}; for (const std::pair poller_pair : callback_list) { const InputIdentifier& poller = poller_pair.second; diff --git a/src/input_common/input_engine.h b/src/input_common/input_engine.h index 78e7046c7..f9fa5fec3 100644 --- a/src/input_common/input_engine.h +++ b/src/input_common/input_engine.h @@ -190,7 +190,7 @@ protected: void SetHatButton(const PadIdentifier& identifier, int button, u8 value); void SetAxis(const PadIdentifier& identifier, int axis, f32 value); void SetBattery(const PadIdentifier& identifier, BatteryLevel value); - void SetMotion(const PadIdentifier& identifier, int motion, BasicMotion value); + void SetMotion(const PadIdentifier& identifier, int motion, const BasicMotion& value); virtual std::string GetHatButtonName([[maybe_unused]] u8 direction_value) const { return "Unknown"; @@ -209,7 +209,8 @@ private: void TriggerOnHatButtonChange(const PadIdentifier& identifier, int button, u8 value); void TriggerOnAxisChange(const PadIdentifier& identifier, int button, f32 value); void TriggerOnBatteryChange(const PadIdentifier& identifier, BatteryLevel value); - void TriggerOnMotionChange(const PadIdentifier& identifier, int motion, BasicMotion value); + void TriggerOnMotionChange(const PadIdentifier& identifier, int motion, + const BasicMotion& value); bool IsInputIdentifierEqual(const InputIdentifier& input_identifier, const PadIdentifier& identifier, EngineInputType type, -- cgit v1.2.3 From c126b0718ca4ffff463c4462ca38f61019df4acf Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 13 Dec 2021 10:41:30 -0500 Subject: tas_input: Make TasAxes enum an enum class Prevents these values from potentially clashing with anything in other headers. --- src/input_common/drivers/tas_input.cpp | 14 +++++++++----- src/input_common/drivers/tas_input.h | 5 +++++ 2 files changed, 14 insertions(+), 5 deletions(-) (limited to 'src/input_common/drivers') diff --git a/src/input_common/drivers/tas_input.cpp b/src/input_common/drivers/tas_input.cpp index 0e01fb0d9..1a38616b4 100644 --- a/src/input_common/drivers/tas_input.cpp +++ b/src/input_common/drivers/tas_input.cpp @@ -15,7 +15,7 @@ namespace InputCommon::TasInput { -enum TasAxes : u8 { +enum class Tas::TasAxis : u8 { StickX, StickY, SubstickX, @@ -205,10 +205,10 @@ void Tas::UpdateThread() { const int button = static_cast(i); SetButton(identifier, button, button_status); } - SetAxis(identifier, TasAxes::StickX, command.l_axis.x); - SetAxis(identifier, TasAxes::StickY, command.l_axis.y); - SetAxis(identifier, TasAxes::SubstickX, command.r_axis.x); - SetAxis(identifier, TasAxes::SubstickY, command.r_axis.y); + SetTasAxis(identifier, TasAxis::StickX, command.l_axis.x); + SetTasAxis(identifier, TasAxis::StickY, command.l_axis.y); + SetTasAxis(identifier, TasAxis::SubstickX, command.r_axis.x); + SetTasAxis(identifier, TasAxis::SubstickY, command.r_axis.y); } } else { is_running = Settings::values.tas_loop.GetValue(); @@ -267,6 +267,10 @@ std::string Tas::WriteCommandAxis(TasAnalog analog) const { return fmt::format("{};{}", analog.x * 32767, analog.y * 32767); } +void Tas::SetTasAxis(const PadIdentifier& identifier, TasAxis axis, f32 value) { + SetAxis(identifier, static_cast(axis), value); +} + void Tas::StartStop() { if (!Settings::values.tas_enable) { return; diff --git a/src/input_common/drivers/tas_input.h b/src/input_common/drivers/tas_input.h index c95a130fc..c44c39da9 100644 --- a/src/input_common/drivers/tas_input.h +++ b/src/input_common/drivers/tas_input.h @@ -128,6 +128,8 @@ public: std::tuple GetStatus() const; private: + enum class TasAxis : u8; + struct TASCommand { u64 buttons{}; TasAnalog l_axis{}; @@ -182,6 +184,9 @@ private: */ std::string WriteCommandAxis(TasAnalog data) const; + /// Sets an axis for a particular pad to the given value. + void SetTasAxis(const PadIdentifier& identifier, TasAxis axis, f32 value); + size_t script_length{0}; bool is_recording{false}; bool is_running{false}; -- cgit v1.2.3 From d52ad96ce348656b2ea7de8b8a85badfa86d2860 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 13 Dec 2021 10:49:06 -0500 Subject: tas_input: Amend -Wdocumentation warnings Parameters shouldn't have the colon by their name. --- src/input_common/drivers/tas_input.cpp | 10 +++---- src/input_common/drivers/tas_input.h | 48 ++++++++++++++++++---------------- 2 files changed, 30 insertions(+), 28 deletions(-) (limited to 'src/input_common/drivers') diff --git a/src/input_common/drivers/tas_input.cpp b/src/input_common/drivers/tas_input.cpp index 1a38616b4..19d8ccae3 100644 --- a/src/input_common/drivers/tas_input.cpp +++ b/src/input_common/drivers/tas_input.cpp @@ -238,13 +238,13 @@ TasAnalog Tas::ReadCommandAxis(const std::string& line) const { return {x, y}; } -u64 Tas::ReadCommandButtons(const std::string& data) const { - std::stringstream button_text(data); - std::string line; +u64 Tas::ReadCommandButtons(const std::string& line) const { + std::stringstream button_text(line); + std::string button_line; u64 buttons = 0; - while (std::getline(button_text, line, ';')) { + while (std::getline(button_text, button_line, ';')) { for (auto [text, tas_button] : text_to_tas_button) { - if (text == line) { + if (text == button_line) { buttons |= static_cast(tas_button); break; } diff --git a/src/input_common/drivers/tas_input.h b/src/input_common/drivers/tas_input.h index c44c39da9..7c2c4a21b 100644 --- a/src/input_common/drivers/tas_input.h +++ b/src/input_common/drivers/tas_input.h @@ -88,39 +88,39 @@ public: /** * Changes the input status that will be stored in each frame - * @param buttons: bitfield with the status of the buttons - * @param left_axis: value of the left axis - * @param right_axis: value of the right axis + * @param buttons Bitfield with the status of the buttons + * @param left_axis Value of the left axis + * @param right_axis Value of the right axis */ void RecordInput(u64 buttons, TasAnalog left_axis, TasAnalog right_axis); // Main loop that records or executes input void UpdateThread(); - // Sets the flag to start or stop the TAS command excecution and swaps controllers profiles + // Sets the flag to start or stop the TAS command execution and swaps controllers profiles void StartStop(); - // Stop the TAS and reverts any controller profile + // Stop the TAS and reverts any controller profile void Stop(); - // Sets the flag to reload the file and start from the begining in the next update + // Sets the flag to reload the file and start from the beginning in the next update void Reset(); /** * Sets the flag to enable or disable recording of inputs - * @return Returns true if the current recording status is enabled + * @returns true if the current recording status is enabled */ bool Record(); /** * Saves contents of record_commands on a file - * @param overwrite_file: Indicates if player 1 should be overwritten + * @param overwrite_file Indicates if player 1 should be overwritten */ void SaveRecording(bool overwrite_file); /** * Returns the current status values of TAS playback/recording - * @return Tuple of + * @returns A Tuple of * TasState indicating the current state out of Running ; * Current playback progress ; * Total length of script file currently loaded or being recorded @@ -139,29 +139,31 @@ private: /// Loads TAS files from all players void LoadTasFiles(); - /** Loads TAS file from the specified player - * @param player_index: player number to save the script - * @param file_index: script number of the file + /** + * Loads TAS file from the specified player + * @param player_index Player number to save the script + * @param file_index Script number of the file */ void LoadTasFile(size_t player_index, size_t file_index); - /** Writes a TAS file from the recorded commands - * @param file_name: name of the file to be written + /** + * Writes a TAS file from the recorded commands + * @param file_name Name of the file to be written */ void WriteTasFile(std::u8string file_name); /** * Parses a string containing the axis values. X and Y have a range from -32767 to 32767 - * @param line: string containing axis values with the following format "x;y" - * @return Returns a TAS analog object with axis values with range from -1.0 to 1.0 + * @param line String containing axis values with the following format "x;y" + * @returns A TAS analog object with axis values with range from -1.0 to 1.0 */ TasAnalog ReadCommandAxis(const std::string& line) const; /** * Parses a string containing the button values. Each button is represented by it's text format * specified in text_to_tas_button array - * @param line: string containing button name with the following format "a;b;c;d..." - * @return Returns a u64 with each bit representing the status of a button + * @param line string containing button name with the following format "a;b;c;d..." + * @returns A u64 with each bit representing the status of a button */ u64 ReadCommandButtons(const std::string& line) const; @@ -172,17 +174,17 @@ private: /** * Converts an u64 containing the button status into the text equivalent - * @param buttons: bitfield with the status of the buttons - * @return Returns a string with the name of the buttons to be written to the file + * @param buttons Bitfield with the status of the buttons + * @returns A string with the name of the buttons to be written to the file */ std::string WriteCommandButtons(u64 buttons) const; /** * Converts an TAS analog object containing the axis status into the text equivalent - * @param data: value of the axis - * @return A string with the value of the axis to be written to the file + * @param analog Value of the axis + * @returns A string with the value of the axis to be written to the file */ - std::string WriteCommandAxis(TasAnalog data) const; + std::string WriteCommandAxis(TasAnalog analog) const; /// Sets an axis for a particular pad to the given value. void SetTasAxis(const PadIdentifier& identifier, TasAxis axis, f32 value); -- cgit v1.2.3 From 37a8e2a67eae239b13f10ac56bc42932e9a25b25 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 13 Dec 2021 10:50:22 -0500 Subject: tas_input: Remove unused std::smatch variable This also means we can get rid of the dependency on --- src/input_common/drivers/tas_input.cpp | 2 -- 1 file changed, 2 deletions(-) (limited to 'src/input_common/drivers') diff --git a/src/input_common/drivers/tas_input.cpp b/src/input_common/drivers/tas_input.cpp index 19d8ccae3..0a504c484 100644 --- a/src/input_common/drivers/tas_input.cpp +++ b/src/input_common/drivers/tas_input.cpp @@ -3,7 +3,6 @@ // Refer to the license.txt file included. #include -#include #include #include "common/fs/file.h" @@ -93,7 +92,6 @@ void Tas::LoadTasFile(size_t player_index, size_t file_index) { if (line.empty()) { continue; } - std::smatch m; std::stringstream linestream(line); std::string segment; -- cgit v1.2.3 From 6be730bdcdf875655973b1a39576e6933fd93eab Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 13 Dec 2021 10:54:05 -0500 Subject: tas_input: Use u8string_view instead of u8string Same behavior, but without the potential for extra allocations. --- src/input_common/drivers/tas_input.cpp | 11 ++++++----- src/input_common/drivers/tas_input.h | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) (limited to 'src/input_common/drivers') diff --git a/src/input_common/drivers/tas_input.cpp b/src/input_common/drivers/tas_input.cpp index 0a504c484..3fdd3649b 100644 --- a/src/input_common/drivers/tas_input.cpp +++ b/src/input_common/drivers/tas_input.cpp @@ -121,16 +121,17 @@ void Tas::LoadTasFile(size_t player_index, size_t file_index) { LOG_INFO(Input, "TAS file loaded! {} frames", frame_no); } -void Tas::WriteTasFile(std::u8string file_name) { +void Tas::WriteTasFile(std::u8string_view file_name) { std::string output_text; for (size_t frame = 0; frame < record_commands.size(); frame++) { const TASCommand& line = record_commands[frame]; output_text += fmt::format("{} {} {} {}\n", frame, WriteCommandButtons(line.buttons), WriteCommandAxis(line.l_axis), WriteCommandAxis(line.r_axis)); } - const auto bytes_written = Common::FS::WriteStringToFile( - Common::FS::GetYuzuPath(Common::FS::YuzuPath::TASDir) / file_name, - Common::FS::FileType::TextFile, output_text); + + const auto tas_file_name = Common::FS::GetYuzuPath(Common::FS::YuzuPath::TASDir) / file_name; + const auto bytes_written = + Common::FS::WriteStringToFile(tas_file_name, Common::FS::FileType::TextFile, output_text); if (bytes_written == output_text.size()) { LOG_INFO(Input, "TAS file written to file!"); } else { @@ -252,7 +253,7 @@ u64 Tas::ReadCommandButtons(const std::string& line) const { } std::string Tas::WriteCommandButtons(u64 buttons) const { - std::string returns = ""; + std::string returns; for (auto [text_button, tas_button] : text_to_tas_button) { if ((buttons & static_cast(tas_button)) != 0) { returns += fmt::format("{};", text_button); diff --git a/src/input_common/drivers/tas_input.h b/src/input_common/drivers/tas_input.h index 7c2c4a21b..68970dcec 100644 --- a/src/input_common/drivers/tas_input.h +++ b/src/input_common/drivers/tas_input.h @@ -150,7 +150,7 @@ private: * Writes a TAS file from the recorded commands * @param file_name Name of the file to be written */ - void WriteTasFile(std::u8string file_name); + void WriteTasFile(std::u8string_view file_name); /** * Parses a string containing the axis values. X and Y have a range from -32767 to 32767 -- cgit v1.2.3 From a515ede2af822a337b95ed0b3987a197664d5180 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 13 Dec 2021 10:57:51 -0500 Subject: tas_input: Use istringstream over stringstream This is only using the input facilities, so we don't need to use the fully-fleged stringstream. --- src/input_common/drivers/tas_input.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/input_common/drivers') diff --git a/src/input_common/drivers/tas_input.cpp b/src/input_common/drivers/tas_input.cpp index 3fdd3649b..a7d3d0b47 100644 --- a/src/input_common/drivers/tas_input.cpp +++ b/src/input_common/drivers/tas_input.cpp @@ -85,7 +85,7 @@ void Tas::LoadTasFile(size_t player_index, size_t file_index) { Common::FS::GetYuzuPath(Common::FS::YuzuPath::TASDir) / fmt::format("script{}-{}.txt", file_index, player_index + 1), Common::FS::FileType::BinaryFile); - std::stringstream command_line(file); + std::istringstream command_line(file); std::string line; int frame_no = 0; while (std::getline(command_line, line, '\n')) { @@ -93,7 +93,7 @@ void Tas::LoadTasFile(size_t player_index, size_t file_index) { continue; } - std::stringstream linestream(line); + std::istringstream linestream(line); std::string segment; std::vector seglist; -- cgit v1.2.3 From 26ef76213c81b6c2dc8eeeae11e9586f22a76011 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 13 Dec 2021 11:07:26 -0500 Subject: tas_input: std::move strings into vector While we're in the same area, we can also avoid performing std::stoi in a loop when it only needs to be performed once. --- src/input_common/drivers/tas_input.cpp | 45 ++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 21 deletions(-) (limited to 'src/input_common/drivers') diff --git a/src/input_common/drivers/tas_input.cpp b/src/input_common/drivers/tas_input.cpp index a7d3d0b47..d14a43b9e 100644 --- a/src/input_common/drivers/tas_input.cpp +++ b/src/input_common/drivers/tas_input.cpp @@ -93,27 +93,29 @@ void Tas::LoadTasFile(size_t player_index, size_t file_index) { continue; } - std::istringstream linestream(line); - std::string segment; - std::vector seglist; - - while (std::getline(linestream, segment, ' ')) { - seglist.push_back(segment); + std::vector seg_list; + { + std::istringstream line_stream(line); + std::string segment; + while (std::getline(line_stream, segment, ' ')) { + seg_list.push_back(std::move(segment)); + } } - if (seglist.size() < 4) { + if (seg_list.size() < 4) { continue; } - while (frame_no < std::stoi(seglist.at(0))) { - commands[player_index].push_back({}); + const auto num_frames = std::stoi(seg_list[0]); + while (frame_no < num_frames) { + commands[player_index].emplace_back(); frame_no++; } TASCommand command = { - .buttons = ReadCommandButtons(seglist.at(1)), - .l_axis = ReadCommandAxis(seglist.at(2)), - .r_axis = ReadCommandAxis(seglist.at(3)), + .buttons = ReadCommandButtons(seg_list[1]), + .l_axis = ReadCommandAxis(seg_list[2]), + .r_axis = ReadCommandAxis(seg_list[3]), }; commands[player_index].push_back(command); frame_no++; @@ -223,22 +225,23 @@ void Tas::ClearInput() { } TasAnalog Tas::ReadCommandAxis(const std::string& line) const { - std::stringstream linestream(line); - std::string segment; - std::vector seglist; - - while (std::getline(linestream, segment, ';')) { - seglist.push_back(segment); + std::vector seg_list; + { + std::istringstream line_stream(line); + std::string segment; + while (std::getline(line_stream, segment, ';')) { + seg_list.push_back(std::move(segment)); + } } - const float x = std::stof(seglist.at(0)) / 32767.0f; - const float y = std::stof(seglist.at(1)) / 32767.0f; + const float x = std::stof(seg_list.at(0)) / 32767.0f; + const float y = std::stof(seg_list.at(1)) / 32767.0f; return {x, y}; } u64 Tas::ReadCommandButtons(const std::string& line) const { - std::stringstream button_text(line); + std::istringstream button_text(line); std::string button_line; u64 buttons = 0; while (std::getline(button_text, button_line, ';')) { -- cgit v1.2.3 From db9320e7541430dc487e85f40912725bd5b66c8a Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 13 Dec 2021 11:10:56 -0500 Subject: tas_input: Remove unnecessary includes Gets rid of indirect includes and includes only what the interface needs. --- src/input_common/drivers/tas_input.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/input_common/drivers') diff --git a/src/input_common/drivers/tas_input.h b/src/input_common/drivers/tas_input.h index 68970dcec..3996fe3a8 100644 --- a/src/input_common/drivers/tas_input.h +++ b/src/input_common/drivers/tas_input.h @@ -5,11 +5,11 @@ #pragma once #include +#include +#include #include "common/common_types.h" -#include "common/settings_input.h" #include "input_common/input_engine.h" -#include "input_common/main.h" /* To play back TAS scripts on Yuzu, select the folder with scripts in the configuration menu below -- cgit v1.2.3 From ddda6ae776e0fab22a3cf70a9f4f5a87df86fda8 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 13 Dec 2021 11:19:24 -0500 Subject: tas_input: Execute clear() even if empty clear() when empty is simply a no-op, so we can get rid of the check here and let the stdlib do it for us. --- src/input_common/drivers/tas_input.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src/input_common/drivers') diff --git a/src/input_common/drivers/tas_input.cpp b/src/input_common/drivers/tas_input.cpp index d14a43b9e..bd4e411c9 100644 --- a/src/input_common/drivers/tas_input.cpp +++ b/src/input_common/drivers/tas_input.cpp @@ -78,9 +78,8 @@ void Tas::LoadTasFiles() { } void Tas::LoadTasFile(size_t player_index, size_t file_index) { - if (!commands[player_index].empty()) { - commands[player_index].clear(); - } + commands[player_index].clear(); + std::string file = Common::FS::ReadStringFromFile( Common::FS::GetYuzuPath(Common::FS::YuzuPath::TASDir) / fmt::format("script{}-{}.txt", file_index, player_index + 1), -- cgit v1.2.3 From 734fb180bb42d361f05d1fab02323de5095e2d8d Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 13 Dec 2021 11:20:23 -0500 Subject: tas_input: Remove unnecessary semicolon Resolves a -Wextra-semi warning --- src/input_common/drivers/tas_input.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/input_common/drivers') diff --git a/src/input_common/drivers/tas_input.cpp b/src/input_common/drivers/tas_input.cpp index bd4e411c9..1617ba1d4 100644 --- a/src/input_common/drivers/tas_input.cpp +++ b/src/input_common/drivers/tas_input.cpp @@ -65,7 +65,7 @@ Tas::Tas(const std::string& input_engine_) : InputCommon::InputEngine(input_engi Tas::~Tas() { Stop(); -}; +} void Tas::LoadTasFiles() { script_length = 0; -- cgit v1.2.3 From 54ca48e8b772453814d2e4d49a4ba29a1b46b32d Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 13 Dec 2021 11:36:48 -0500 Subject: tas_input: Avoid minor copies in Read/WriteCommandButtons() We don't need to copy the whole pair --- src/input_common/drivers/tas_input.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/input_common/drivers') diff --git a/src/input_common/drivers/tas_input.cpp b/src/input_common/drivers/tas_input.cpp index 1617ba1d4..2094c1feb 100644 --- a/src/input_common/drivers/tas_input.cpp +++ b/src/input_common/drivers/tas_input.cpp @@ -244,7 +244,7 @@ u64 Tas::ReadCommandButtons(const std::string& line) const { std::string button_line; u64 buttons = 0; while (std::getline(button_text, button_line, ';')) { - for (auto [text, tas_button] : text_to_tas_button) { + for (const auto& [text, tas_button] : text_to_tas_button) { if (text == button_line) { buttons |= static_cast(tas_button); break; @@ -256,7 +256,7 @@ u64 Tas::ReadCommandButtons(const std::string& line) const { std::string Tas::WriteCommandButtons(u64 buttons) const { std::string returns; - for (auto [text_button, tas_button] : text_to_tas_button) { + for (const auto& [text_button, tas_button] : text_to_tas_button) { if ((buttons & static_cast(tas_button)) != 0) { returns += fmt::format("{};", text_button); } -- cgit v1.2.3 From 7f965172c5cd4f891e1f2025050cbf9492dbf5c8 Mon Sep 17 00:00:00 2001 From: Valeri Date: Mon, 13 Dec 2021 23:23:34 +0300 Subject: input/SDL: Update SDL hints SDL_HINT_JOYSTICK_HIDAPI_SWITCH_HOME_LED is no longer needed thanks to new default in SDL 2.0.18. SDL_HINT_JOYSTICK_HIDAPI_XBOX is reported to cause conflicts with native driver Xbox driver on Linux, and Xbox controllers don't benefit from hidapi anyways. --- src/input_common/drivers/sdl_driver.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src/input_common/drivers') diff --git a/src/input_common/drivers/sdl_driver.cpp b/src/input_common/drivers/sdl_driver.cpp index 1052ed394..24fd3ab92 100644 --- a/src/input_common/drivers/sdl_driver.cpp +++ b/src/input_common/drivers/sdl_driver.cpp @@ -403,10 +403,11 @@ SDLDriver::SDLDriver(const std::string& input_engine_) : InputEngine(input_engin // Use hidapi driver for joycons. This will allow joycons to be detected as a GameController and // not a generic one - SDL_SetHint("SDL_JOYSTICK_HIDAPI_JOY_CONS", "1"); + SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_JOY_CONS, "1"); - // Turn off Pro controller home led - SDL_SetHint("SDL_JOYSTICK_HIDAPI_SWITCH_HOME_LED", "0"); + // Disable hidapi driver for xbox. Already default on Windows, this causes conflict with native + // driver on Linux. + SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_XBOX, "0"); // If the frontend is going to manage the event loop, then we don't start one here start_thread = SDL_WasInit(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER) == 0; -- cgit v1.2.3