diff options
Diffstat (limited to 'src/input_common')
-rw-r--r-- | src/input_common/CMakeLists.txt | 6 | ||||
-rw-r--r-- | src/input_common/main.cpp | 75 | ||||
-rw-r--r-- | src/input_common/main.h | 41 | ||||
-rw-r--r-- | src/input_common/motion_emu.cpp | 179 | ||||
-rw-r--r-- | src/input_common/motion_emu.h | 46 | ||||
-rw-r--r-- | src/input_common/mouse/mouse_input.cpp | 129 | ||||
-rw-r--r-- | src/input_common/mouse/mouse_input.h | 98 | ||||
-rw-r--r-- | src/input_common/mouse/mouse_poller.cpp | 259 | ||||
-rw-r--r-- | src/input_common/mouse/mouse_poller.h | 109 | ||||
-rw-r--r-- | src/input_common/udp/client.cpp | 143 | ||||
-rw-r--r-- | src/input_common/udp/client.h | 40 | ||||
-rw-r--r-- | src/input_common/udp/udp.cpp | 64 |
12 files changed, 847 insertions, 342 deletions
diff --git a/src/input_common/CMakeLists.txt b/src/input_common/CMakeLists.txt index 5682e5ca5..38ab31898 100644 --- a/src/input_common/CMakeLists.txt +++ b/src/input_common/CMakeLists.txt @@ -5,8 +5,6 @@ add_library(input_common STATIC keyboard.h main.cpp main.h - motion_emu.cpp - motion_emu.h motion_from_button.cpp motion_from_button.h motion_input.cpp @@ -19,6 +17,10 @@ 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 udp/client.cpp diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp index e59ad4ff5..7c4e7dd3b 100644 --- a/src/input_common/main.cpp +++ b/src/input_common/main.cpp @@ -10,8 +10,9 @@ #include "input_common/gcadapter/gc_poller.h" #include "input_common/keyboard.h" #include "input_common/main.h" -#include "input_common/motion_emu.h" #include "input_common/motion_from_button.h" +#include "input_common/mouse/mouse_input.h" +#include "input_common/mouse/mouse_poller.h" #include "input_common/touch_from_button.h" #include "input_common/udp/client.h" #include "input_common/udp/udp.h" @@ -37,8 +38,6 @@ struct InputSubsystem::Impl { std::make_shared<AnalogFromButton>()); Input::RegisterFactory<Input::MotionDevice>("keyboard", std::make_shared<MotionFromButton>()); - motion_emu = std::make_shared<MotionEmu>(); - Input::RegisterFactory<Input::MotionDevice>("motion_emu", motion_emu); Input::RegisterFactory<Input::TouchDevice>("touch_from_button", std::make_shared<TouchFromButtonFactory>()); @@ -51,6 +50,16 @@ struct InputSubsystem::Impl { Input::RegisterFactory<Input::MotionDevice>("cemuhookudp", udpmotion); udptouch = std::make_shared<UDPTouchFactory>(udp); Input::RegisterFactory<Input::TouchDevice>("cemuhookudp", udptouch); + + mouse = std::make_shared<MouseInput::Mouse>(); + mousebuttons = std::make_shared<MouseButtonFactory>(mouse); + Input::RegisterFactory<Input::ButtonDevice>("mouse", mousebuttons); + mouseanalog = std::make_shared<MouseAnalogFactory>(mouse); + Input::RegisterFactory<Input::AnalogDevice>("mouse", mouseanalog); + mousemotion = std::make_shared<MouseMotionFactory>(mouse); + Input::RegisterFactory<Input::MotionDevice>("mouse", mousemotion); + mousetouch = std::make_shared<MouseTouchFactory>(mouse); + Input::RegisterFactory<Input::TouchDevice>("mouse", mousetouch); } void Shutdown() { @@ -58,8 +67,6 @@ struct InputSubsystem::Impl { Input::UnregisterFactory<Input::MotionDevice>("keyboard"); keyboard.reset(); Input::UnregisterFactory<Input::AnalogDevice>("analog_from_button"); - Input::UnregisterFactory<Input::MotionDevice>("motion_emu"); - motion_emu.reset(); Input::UnregisterFactory<Input::TouchDevice>("touch_from_button"); #ifdef HAVE_SDL2 sdl.reset(); @@ -77,6 +84,16 @@ struct InputSubsystem::Impl { udpmotion.reset(); udptouch.reset(); + + Input::UnregisterFactory<Input::ButtonDevice>("mouse"); + Input::UnregisterFactory<Input::AnalogDevice>("mouse"); + Input::UnregisterFactory<Input::MotionDevice>("mouse"); + Input::UnregisterFactory<Input::TouchDevice>("mouse"); + + mousebuttons.reset(); + mouseanalog.reset(); + mousemotion.reset(); + mousetouch.reset(); } [[nodiscard]] std::vector<Common::ParamPackage> GetInputDevices() const { @@ -140,7 +157,6 @@ struct InputSubsystem::Impl { } std::shared_ptr<Keyboard> keyboard; - std::shared_ptr<MotionEmu> motion_emu; #ifdef HAVE_SDL2 std::unique_ptr<SDL::State> sdl; #endif @@ -149,8 +165,13 @@ struct InputSubsystem::Impl { std::shared_ptr<GCVibrationFactory> gcvibration; std::shared_ptr<UDPMotionFactory> udpmotion; std::shared_ptr<UDPTouchFactory> udptouch; + std::shared_ptr<MouseButtonFactory> mousebuttons; + std::shared_ptr<MouseAnalogFactory> mouseanalog; + std::shared_ptr<MouseMotionFactory> mousemotion; + std::shared_ptr<MouseTouchFactory> mousetouch; std::shared_ptr<CemuhookUDP::Client> udp; std::shared_ptr<GCAdapter::Adapter> gcadapter; + std::shared_ptr<MouseInput::Mouse> mouse; }; InputSubsystem::InputSubsystem() : impl{std::make_unique<Impl>()} {} @@ -173,12 +194,12 @@ const Keyboard* InputSubsystem::GetKeyboard() const { return impl->keyboard.get(); } -MotionEmu* InputSubsystem::GetMotionEmu() { - return impl->motion_emu.get(); +MouseInput::Mouse* InputSubsystem::GetMouse() { + return impl->mouse.get(); } -const MotionEmu* InputSubsystem::GetMotionEmu() const { - return impl->motion_emu.get(); +const MouseInput::Mouse* InputSubsystem::GetMouse() const { + return impl->mouse.get(); } std::vector<Common::ParamPackage> InputSubsystem::GetInputDevices() const { @@ -229,11 +250,43 @@ const UDPTouchFactory* InputSubsystem::GetUDPTouch() const { return impl->udptouch.get(); } +MouseButtonFactory* InputSubsystem::GetMouseButtons() { + return impl->mousebuttons.get(); +} + +const MouseButtonFactory* InputSubsystem::GetMouseButtons() const { + return impl->mousebuttons.get(); +} + +MouseAnalogFactory* InputSubsystem::GetMouseAnalogs() { + return impl->mouseanalog.get(); +} + +const MouseAnalogFactory* InputSubsystem::GetMouseAnalogs() const { + return impl->mouseanalog.get(); +} + +MouseMotionFactory* InputSubsystem::GetMouseMotions() { + return impl->mousemotion.get(); +} + +const MouseMotionFactory* InputSubsystem::GetMouseMotions() const { + return impl->mousemotion.get(); +} + +MouseTouchFactory* InputSubsystem::GetMouseTouch() { + return impl->mousetouch.get(); +} + +const MouseTouchFactory* InputSubsystem::GetMouseTouch() const { + return impl->mousetouch.get(); +} + void InputSubsystem::ReloadInputDevices() { if (!impl->udp) { return; } - impl->udp->ReloadUDPClient(); + impl->udp->ReloadSockets(); } std::vector<std::unique_ptr<Polling::DevicePoller>> InputSubsystem::GetPollers( diff --git a/src/input_common/main.h b/src/input_common/main.h index dded3f1ef..5d6f26385 100644 --- a/src/input_common/main.h +++ b/src/input_common/main.h @@ -25,6 +25,10 @@ namespace Settings::NativeMotion { enum Values : int; } +namespace MouseInput { +class Mouse; +} + namespace InputCommon { namespace Polling { @@ -56,8 +60,11 @@ class GCAnalogFactory; class GCButtonFactory; class UDPMotionFactory; class UDPTouchFactory; +class MouseButtonFactory; +class MouseAnalogFactory; +class MouseMotionFactory; +class MouseTouchFactory; class Keyboard; -class MotionEmu; /** * Given a ParamPackage for a Device returned from `GetInputDevices`, attempt to get the default @@ -90,11 +97,11 @@ public: /// Retrieves the underlying keyboard device. [[nodiscard]] const Keyboard* GetKeyboard() const; - /// Retrieves the underlying motion emulation factory. - [[nodiscard]] MotionEmu* GetMotionEmu(); + /// Retrieves the underlying mouse device. + [[nodiscard]] MouseInput::Mouse* GetMouse(); - /// Retrieves the underlying motion emulation factory. - [[nodiscard]] const MotionEmu* GetMotionEmu() const; + /// Retrieves the underlying mouse device. + [[nodiscard]] const MouseInput::Mouse* GetMouse() const; /** * Returns all available input devices that this Factory can create a new device with. @@ -137,6 +144,30 @@ public: /// Retrieves the underlying udp touch handler. [[nodiscard]] const UDPTouchFactory* GetUDPTouch() const; + /// Retrieves the underlying GameCube button handler. + [[nodiscard]] MouseButtonFactory* GetMouseButtons(); + + /// Retrieves the underlying GameCube button handler. + [[nodiscard]] const MouseButtonFactory* GetMouseButtons() const; + + /// Retrieves the underlying udp touch handler. + [[nodiscard]] MouseAnalogFactory* GetMouseAnalogs(); + + /// Retrieves the underlying udp touch handler. + [[nodiscard]] const MouseAnalogFactory* GetMouseAnalogs() const; + + /// Retrieves the underlying udp motion handler. + [[nodiscard]] MouseMotionFactory* GetMouseMotions(); + + /// Retrieves the underlying udp motion handler. + [[nodiscard]] const MouseMotionFactory* GetMouseMotions() const; + + /// Retrieves the underlying udp touch handler. + [[nodiscard]] MouseTouchFactory* GetMouseTouch(); + + /// Retrieves the underlying udp touch handler. + [[nodiscard]] const MouseTouchFactory* GetMouseTouch() const; + /// Reloads the input devices void ReloadInputDevices(); diff --git a/src/input_common/motion_emu.cpp b/src/input_common/motion_emu.cpp deleted file mode 100644 index d4da5596b..000000000 --- a/src/input_common/motion_emu.cpp +++ /dev/null @@ -1,179 +0,0 @@ -// Copyright 2017 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include <algorithm> -#include <chrono> -#include <mutex> -#include <thread> -#include <tuple> -#include "common/math_util.h" -#include "common/quaternion.h" -#include "common/thread.h" -#include "common/vector_math.h" -#include "input_common/motion_emu.h" - -namespace InputCommon { - -// Implementation class of the motion emulation device -class MotionEmuDevice { -public: - explicit MotionEmuDevice(int update_millisecond_, float sensitivity_) - : update_millisecond(update_millisecond_), - update_duration(std::chrono::duration_cast<std::chrono::steady_clock::duration>( - std::chrono::milliseconds(update_millisecond))), - sensitivity(sensitivity_), motion_emu_thread(&MotionEmuDevice::MotionEmuThread, this) {} - - ~MotionEmuDevice() { - if (motion_emu_thread.joinable()) { - shutdown_event.Set(); - motion_emu_thread.join(); - } - } - - void BeginTilt(int x, int y) { - mouse_origin = Common::MakeVec(x, y); - is_tilting = true; - } - - void Tilt(int x, int y) { - if (!is_tilting) { - return; - } - - std::lock_guard guard{tilt_mutex}; - const auto mouse_move = Common::MakeVec(x, y) - mouse_origin; - if (mouse_move.x == 0 && mouse_move.y == 0) { - tilt_angle = 0; - } else { - tilt_direction = mouse_move.Cast<float>(); - tilt_angle = - std::clamp(tilt_direction.Normalize() * sensitivity, 0.0f, Common::PI * 0.5f); - } - } - - void EndTilt() { - std::lock_guard guard{tilt_mutex}; - tilt_angle = 0; - is_tilting = false; - } - - Input::MotionStatus GetStatus() { - std::lock_guard guard{status_mutex}; - return status; - } - -private: - const int update_millisecond; - const std::chrono::steady_clock::duration update_duration; - const float sensitivity; - - Common::Vec2<int> mouse_origin; - - std::mutex tilt_mutex; - Common::Vec2<float> tilt_direction; - float tilt_angle = 0; - - bool is_tilting = false; - - Common::Event shutdown_event; - - Input::MotionStatus status; - std::mutex status_mutex; - - // Note: always keep the thread declaration at the end so that other objects are initialized - // before this! - std::thread motion_emu_thread; - - void MotionEmuThread() { - auto update_time = std::chrono::steady_clock::now(); - Common::Quaternion<float> q = Common::MakeQuaternion(Common::Vec3<float>(), 0); - - while (!shutdown_event.WaitUntil(update_time)) { - update_time += update_duration; - const Common::Quaternion<float> old_q = q; - - { - std::lock_guard guard{tilt_mutex}; - - // Find the quaternion describing current 3DS tilting - q = Common::MakeQuaternion( - Common::MakeVec(-tilt_direction.y, 0.0f, tilt_direction.x), tilt_angle); - } - - const auto inv_q = q.Inverse(); - - // Set the gravity vector in world space - auto gravity = Common::MakeVec(0.0f, -1.0f, 0.0f); - - // Find the angular rate vector in world space - auto angular_rate = ((q - old_q) * inv_q).xyz * 2; - angular_rate *= static_cast<float>(1000 / update_millisecond) / Common::PI * 180.0f; - - // Transform the two vectors from world space to 3DS space - gravity = QuaternionRotate(inv_q, gravity); - angular_rate = QuaternionRotate(inv_q, angular_rate); - - // TODO: Calculate the correct rotation vector and orientation matrix - const auto matrix4x4 = q.ToMatrix(); - const auto rotation = Common::MakeVec(0.0f, 0.0f, 0.0f); - const std::array orientation{ - Common::Vec3f(matrix4x4[0], matrix4x4[1], -matrix4x4[2]), - Common::Vec3f(matrix4x4[4], matrix4x4[5], -matrix4x4[6]), - Common::Vec3f(-matrix4x4[8], -matrix4x4[9], matrix4x4[10]), - }; - - // Update the sensor state - { - std::lock_guard guard{status_mutex}; - status = std::make_tuple(gravity, angular_rate, rotation, orientation); - } - } - } -}; - -// Interface wrapper held by input receiver as a unique_ptr. It holds the implementation class as -// a shared_ptr, which is also observed by the factory class as a weak_ptr. In this way the factory -// can forward all the inputs to the implementation only when it is valid. -class MotionEmuDeviceWrapper : public Input::MotionDevice { -public: - explicit MotionEmuDeviceWrapper(int update_millisecond, float sensitivity) { - device = std::make_shared<MotionEmuDevice>(update_millisecond, sensitivity); - } - - Input::MotionStatus GetStatus() const override { - return device->GetStatus(); - } - - std::shared_ptr<MotionEmuDevice> device; -}; - -std::unique_ptr<Input::MotionDevice> MotionEmu::Create(const Common::ParamPackage& params) { - const int update_period = params.Get("update_period", 100); - const float sensitivity = params.Get("sensitivity", 0.01f); - auto device_wrapper = std::make_unique<MotionEmuDeviceWrapper>(update_period, sensitivity); - // Previously created device is disconnected here. Having two motion devices for 3DS is not - // expected. - current_device = device_wrapper->device; - return device_wrapper; -} - -void MotionEmu::BeginTilt(int x, int y) { - if (auto ptr = current_device.lock()) { - ptr->BeginTilt(x, y); - } -} - -void MotionEmu::Tilt(int x, int y) { - if (auto ptr = current_device.lock()) { - ptr->Tilt(x, y); - } -} - -void MotionEmu::EndTilt() { - if (auto ptr = current_device.lock()) { - ptr->EndTilt(); - } -} - -} // namespace InputCommon diff --git a/src/input_common/motion_emu.h b/src/input_common/motion_emu.h deleted file mode 100644 index 7a7e22467..000000000 --- a/src/input_common/motion_emu.h +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2017 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include "core/frontend/input.h" - -namespace InputCommon { - -class MotionEmuDevice; - -class MotionEmu : public Input::Factory<Input::MotionDevice> { -public: - /** - * Creates a motion device emulated from mouse input - * @param params contains parameters for creating the device: - * - "update_period": update period in milliseconds - * - "sensitivity": the coefficient converting mouse movement to tilting angle - */ - std::unique_ptr<Input::MotionDevice> Create(const Common::ParamPackage& params) override; - - /** - * Signals that a motion sensor tilt has begun. - * @param x the x-coordinate of the cursor - * @param y the y-coordinate of the cursor - */ - void BeginTilt(int x, int y); - - /** - * Signals that a motion sensor tilt is occurring. - * @param x the x-coordinate of the cursor - * @param y the y-coordinate of the cursor - */ - void Tilt(int x, int y); - - /** - * Signals that a motion sensor tilt has ended. - */ - void EndTilt(); - -private: - std::weak_ptr<MotionEmuDevice> current_device; -}; - -} // namespace InputCommon diff --git a/src/input_common/mouse/mouse_input.cpp b/src/input_common/mouse/mouse_input.cpp new file mode 100644 index 000000000..10786a541 --- /dev/null +++ b/src/input_common/mouse/mouse_input.cpp @@ -0,0 +1,129 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include "input_common/mouse/mouse_input.h" + +namespace MouseInput { + +Mouse::Mouse() { + update_thread = std::thread(&Mouse::UpdateThread, this); +} + +Mouse::~Mouse() { + update_thread_running = false; + if (update_thread.joinable()) { + update_thread.join(); + } +} + +void Mouse::UpdateThread() { + constexpr int update_time = 10; + while (update_thread_running) { + 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 (configuring) { + UpdateYuzuSettings(); + } + 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, int button_) { + const auto button_index = static_cast<std::size_t>(button_); + if (button_index >= mouse_info.size()) { + return; + } + + const auto button = 1U << button_index; + buttons |= static_cast<u16>(button); + last_button = static_cast<MouseButton>(button_index); + + 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::MouseMove(int x, int y) { + for (MouseInfo& info : mouse_info) { + 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<float>(); + info.tilt_speed = info.tilt_direction.Normalize() * info.sensitivity; + } + } + } +} + +void Mouse::ReleaseButton(int button_) { + const auto button_index = static_cast<std::size_t>(button_); + if (button_index >= mouse_info.size()) { + return; + } + + const auto button = 1U << button_index; + buttons &= static_cast<u16>(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::BeginConfiguration() { + buttons = 0; + last_button = MouseButton::Undefined; + mouse_queue.Clear(); + configuring = true; +} + +void Mouse::EndConfiguration() { + buttons = 0; + last_button = MouseButton::Undefined; + mouse_queue.Clear(); + configuring = false; +} + +Common::SPSCQueue<MouseStatus>& Mouse::GetMouseQueue() { + return mouse_queue; +} + +const Common::SPSCQueue<MouseStatus>& 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 new file mode 100644 index 000000000..65e64bee7 --- /dev/null +++ b/src/input_common/mouse/mouse_input.h @@ -0,0 +1,98 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <array> +#include <mutex> +#include <thread> + +#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, + Wheel, + Right, + Foward, + Backward, + Undefined, +}; + +struct MouseStatus { + MouseButton button{MouseButton::Undefined}; +}; + +struct MouseData { + bool pressed{}; + std::array<int, 2> 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, int button_); + + /** + * Signals that mouse has moved. + * @param x the x-coordinate of the cursor + * @param y the y-coordinate of the cursor + */ + void MouseMove(int x, int y); + + /** + * Signals that a motion sensor tilt has ended. + */ + void ReleaseButton(int button_); + + [[nodiscard]] Common::SPSCQueue<MouseStatus>& GetMouseQueue(); + [[nodiscard]] const Common::SPSCQueue<MouseStatus>& GetMouseQueue() const; + + [[nodiscard]] MouseData& GetMouseState(std::size_t button); + [[nodiscard]] const MouseData& GetMouseState(std::size_t button) const; + +private: + void UpdateThread(); + void UpdateYuzuSettings(); + + struct MouseInfo { + InputCommon::MotionInput motion{0.0f, 0.0f, 0.0f}; + Common::Vec2<int> mouse_origin; + Common::Vec2<int> last_mouse_position; + bool is_tilting = false; + float sensitivity{0.120f}; + + float tilt_speed = 0; + Common::Vec2<float> tilt_direction; + MouseData data; + }; + + u16 buttons{}; + std::thread update_thread; + MouseButton last_button{MouseButton::Undefined}; + std::array<MouseInfo, 5> mouse_info; + Common::SPSCQueue<MouseStatus> mouse_queue; + bool configuring{false}; + bool update_thread_running{true}; +}; +} // namespace MouseInput diff --git a/src/input_common/mouse/mouse_poller.cpp b/src/input_common/mouse/mouse_poller.cpp new file mode 100644 index 000000000..7445ad3ad --- /dev/null +++ b/src/input_common/mouse/mouse_poller.cpp @@ -0,0 +1,259 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <mutex> +#include <utility> + +#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_, const MouseInput::Mouse* mouse_input_) + : button(button_), mouse_input(mouse_input_) {} + + bool GetStatus() const override { + return mouse_input->GetMouseState(button).pressed; + } + +private: + const u32 button; + const MouseInput::Mouse* mouse_input; +}; + +MouseButtonFactory::MouseButtonFactory(std::shared_ptr<MouseInput::Mouse> mouse_input_) + : mouse_input(std::move(mouse_input_)) {} + +std::unique_ptr<Input::ButtonDevice> MouseButtonFactory::Create( + const Common::ParamPackage& params) { + const auto button_id = params.Get("button", 0); + + return std::make_unique<MouseButton>(button_id, 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<u16>(pad.button)); + 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_, float deadzone_, float range_, + const MouseInput::Mouse* mouse_input_) + : button(port_), axis_x(axis_x_), axis_y(axis_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<float>(mouse_input->GetMouseState(button).axis.at(axis)); + return axis_value / (100.0f * range); + } + + std::pair<float, float> GetAnalog(u32 analog_axis_x, u32 analog_axis_y) const { + float x = GetAxis(analog_axis_x); + float y = GetAxis(analog_axis_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<float, float> 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}; + } + +private: + const u32 button; + const u32 axis_x; + const u32 axis_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<MouseInput::Mouse> 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<Input::AnalogDevice> MouseAnalogFactory::Create( + const Common::ParamPackage& params) { + const auto port = static_cast<u32>(params.Get("port", 0)); + const auto axis_x = static_cast<u32>(params.Get("axis_x", 0)); + const auto axis_y = static_cast<u32>(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); + + return std::make_unique<MouseAnalog>(port, axis_x, axis_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<u16>(pad.button)); + params.Set("axis_x", 0); + params.Set("axis_y", 1); + 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<MouseInput::Mouse> mouse_input_) + : mouse_input(std::move(mouse_input_)) {} + +std::unique_ptr<Input::MotionDevice> MouseMotionFactory::Create( + const Common::ParamPackage& params) { + const auto button_id = params.Get("button", 0); + + return std::make_unique<MouseMotion>(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<u16>(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<MouseInput::Mouse> mouse_input_) + : mouse_input(std::move(mouse_input_)) {} + +std::unique_ptr<Input::TouchDevice> MouseTouchFactory::Create(const Common::ParamPackage& params) { + const auto button_id = params.Get("button", 0); + + return std::make_unique<MouseTouch>(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<u16>(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 new file mode 100644 index 000000000..cf331293b --- /dev/null +++ b/src/input_common/mouse/mouse_poller.h @@ -0,0 +1,109 @@ +// Copyright 2020 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <memory> +#include "core/frontend/input.h" +#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<Input::ButtonDevice> { +public: + explicit MouseButtonFactory(std::shared_ptr<MouseInput::Mouse> 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<Input::ButtonDevice> 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<MouseInput::Mouse> mouse_input; + bool polling = false; +}; + +/// An analog device factory that creates analog devices from mouse +class MouseAnalogFactory final : public Input::Factory<Input::AnalogDevice> { +public: + explicit MouseAnalogFactory(std::shared_ptr<MouseInput::Mouse> mouse_input_); + + std::unique_ptr<Input::AnalogDevice> 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<MouseInput::Mouse> mouse_input; + bool polling = false; +}; + +/// A motion device factory that creates motion devices from mouse +class MouseMotionFactory final : public Input::Factory<Input::MotionDevice> { +public: + explicit MouseMotionFactory(std::shared_ptr<MouseInput::Mouse> mouse_input_); + + std::unique_ptr<Input::MotionDevice> 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<MouseInput::Mouse> mouse_input; + bool polling = false; +}; + +/// An touch device factory that creates touch devices from mouse +class MouseTouchFactory final : public Input::Factory<Input::TouchDevice> { +public: + explicit MouseTouchFactory(std::shared_ptr<MouseInput::Mouse> mouse_input_); + + std::unique_ptr<Input::TouchDevice> 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<MouseInput::Mouse> mouse_input; + bool polling = false; +}; + +} // namespace InputCommon diff --git a/src/input_common/udp/client.cpp b/src/input_common/udp/client.cpp index c0bb90048..17a9225d7 100644 --- a/src/input_common/udp/client.cpp +++ b/src/input_common/udp/client.cpp @@ -136,15 +136,7 @@ static void SocketLoop(Socket* socket) { Client::Client() { LOG_INFO(Input, "Udp Initialization started"); - for (std::size_t client = 0; client < clients.size(); client++) { - const auto pad = client % 4; - StartCommunication(client, Settings::values.udp_input_address, - Settings::values.udp_input_port, pad, 24872); - // Set motion parameters - // SetGyroThreshold value should be dependent on GyroscopeZeroDriftMode - // Real HW values are unknown, 0.0001 is an approximate to Standard - clients[client].motion.SetGyroThreshold(0.0001f); - } + ReloadSockets(); } Client::~Client() { @@ -167,26 +159,61 @@ std::vector<Common::ParamPackage> Client::GetInputDevices() const { return devices; } -bool Client::DeviceConnected(std::size_t pad) const { +bool Client::DeviceConnected(std::size_t client) const { // Use last timestamp to detect if the socket has stopped sending data - const auto now = std::chrono::system_clock::now(); - const auto time_difference = static_cast<u64>( - std::chrono::duration_cast<std::chrono::milliseconds>(now - clients[pad].last_motion_update) - .count()); - return time_difference < 1000 && clients[pad].active == 1; + const auto now = std::chrono::steady_clock::now(); + const auto time_difference = + static_cast<u64>(std::chrono::duration_cast<std::chrono::milliseconds>( + now - clients[client].last_motion_update) + .count()); + return time_difference < 1000 && clients[client].active == 1; } -void Client::ReloadUDPClient() { - for (std::size_t client = 0; client < clients.size(); client++) { - ReloadSocket(Settings::values.udp_input_address, Settings::values.udp_input_port, client); +void Client::ReloadSockets() { + Reset(); + + std::stringstream servers_ss(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<u16>(std::strtol(token.c_str(), &temp, 0)); + if (*temp != '\0') { + LOG_ERROR(Input, "Port number is not valid {}", token); + continue; + } + + for (std::size_t pad = 0; pad < 4; ++pad) { + const std::size_t client_number = + GetClientNumber(udp_input_address, udp_input_port, pad); + if (client_number != max_udp_clients) { + LOG_ERROR(Input, "Duplicated UDP servers found"); + continue; + } + StartCommunication(client++, udp_input_address, udp_input_port, pad, 24872); + } } } -void Client::ReloadSocket(const std::string& host, u16 port, std::size_t pad_index, u32 client_id) { - // client number must be determined from host / port and pad index - const std::size_t client = pad_index; - clients[client].socket->Stop(); - clients[client].thread.join(); - StartCommunication(client, host, port, pad_index, client_id); + +std::size_t Client::GetClientNumber(std::string_view host, u16 port, std::size_t pad) 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 && + clients[client].pad_index == pad) { + return client; + } + } + return max_udp_clients; } void Client::OnVersion([[maybe_unused]] Response::Version data) { @@ -197,9 +224,7 @@ void Client::OnPortInfo([[maybe_unused]] Response::PortInfo data) { LOG_TRACE(Input, "PortInfo packet received: {}", data.model); } -void Client::OnPadData(Response::PadData data) { - // Client number must be determined from host / port and pad index - const std::size_t client = data.info.id; +void Client::OnPadData(Response::PadData data, std::size_t client) { LOG_TRACE(Input, "PadData packet received"); if (data.packet_counter == clients[client].packet_sequence) { LOG_WARNING( @@ -208,9 +233,9 @@ void Client::OnPadData(Response::PadData data) { clients[client].packet_sequence, data.packet_counter); return; } - clients[client].active = data.info.is_pad_active; + clients[client].active = static_cast<s8>(data.info.is_pad_active); clients[client].packet_sequence = data.packet_counter; - const auto now = std::chrono::system_clock::now(); + const auto now = std::chrono::steady_clock::now(); const auto time_difference = static_cast<u64>(std::chrono::duration_cast<std::chrono::microseconds>( now - clients[client].last_motion_update) @@ -264,16 +289,28 @@ void Client::StartCommunication(std::size_t client, const std::string& host, u16 std::size_t pad_index, u32 client_id) { SocketCallback callback{[this](Response::Version version) { OnVersion(version); }, [this](Response::PortInfo info) { OnPortInfo(info); }, - [this](Response::PadData data) { OnPadData(data); }}; - LOG_INFO(Input, "Starting communication with UDP input server on {}:{}", host, port); + [this, client](Response::PadData data) { OnPadData(data, client); }}; + LOG_INFO(Input, "Starting communication with UDP input server on {}:{}:{}", host, port, + pad_index); + clients[client].host = host; + clients[client].port = port; + clients[client].pad_index = pad_index; + clients[client].active = 0; clients[client].socket = std::make_unique<Socket>(host, port, pad_index, client_id, 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 + clients[client].motion.SetGyroThreshold(0.0001f); } void Client::Reset() { for (auto& client : clients) { - client.socket->Stop(); - client.thread.join(); + if (client.thread.joinable()) { + client.active = -1; + client.socket->Stop(); + client.thread.join(); + } } } @@ -283,52 +320,60 @@ void Client::UpdateYuzuSettings(std::size_t client, const Common::Vec3<float>& a LOG_DEBUG(Input, "UDP Controller {}: gyro=({}, {}, {}), accel=({}, {}, {}), touch={}", client, gyro[0], gyro[1], gyro[2], acc[0], acc[1], acc[2], touch); } - UDPPadStatus pad; + UDPPadStatus pad{ + .host = clients[client].host, + .port = clients[client].port, + .pad_index = clients[client].pad_index, + }; if (touch) { pad.touch = PadTouch::Click; - pad_queue[client].Push(pad); + pad_queue.Push(pad); } for (size_t i = 0; i < 3; ++i) { if (gyro[i] > 5.0f || gyro[i] < -5.0f) { pad.motion = static_cast<PadMotion>(i); pad.motion_value = gyro[i]; - pad_queue[client].Push(pad); + pad_queue.Push(pad); } if (acc[i] > 1.75f || acc[i] < -1.75f) { pad.motion = static_cast<PadMotion>(i + 3); pad.motion_value = acc[i]; - pad_queue[client].Push(pad); + pad_queue.Push(pad); } } } void Client::BeginConfiguration() { - for (auto& pq : pad_queue) { - pq.Clear(); - } + pad_queue.Clear(); configuring = true; } void Client::EndConfiguration() { - for (auto& pq : pad_queue) { - pq.Clear(); - } + pad_queue.Clear(); configuring = false; } -DeviceStatus& Client::GetPadState(std::size_t pad) { - return clients[pad].status; +DeviceStatus& Client::GetPadState(const std::string& host, u16 port, std::size_t pad) { + const std::size_t client_number = GetClientNumber(host, port, pad); + if (client_number == max_udp_clients) { + return clients[0].status; + } + return clients[client_number].status; } -const DeviceStatus& Client::GetPadState(std::size_t pad) const { - return clients[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, pad); + if (client_number == max_udp_clients) { + return clients[0].status; + } + return clients[client_number].status; } -std::array<Common::SPSCQueue<UDPPadStatus>, 4>& Client::GetPadQueue() { +Common::SPSCQueue<UDPPadStatus>& Client::GetPadQueue() { return pad_queue; } -const std::array<Common::SPSCQueue<UDPPadStatus>, 4>& Client::GetPadQueue() const { +const Common::SPSCQueue<UDPPadStatus>& Client::GetPadQueue() const { return pad_queue; } diff --git a/src/input_common/udp/client.h b/src/input_common/udp/client.h index 747e0c0a2..00c8b09f5 100644 --- a/src/input_common/udp/client.h +++ b/src/input_common/udp/client.h @@ -21,8 +21,7 @@ namespace InputCommon::CemuhookUDP { -constexpr u16 DEFAULT_PORT = 26760; -constexpr char DEFAULT_ADDR[] = "127.0.0.1"; +constexpr char DEFAULT_SRV[] = "127.0.0.1:26760"; class Socket; @@ -48,6 +47,9 @@ enum class PadTouch { }; struct UDPPadStatus { + std::string host{"127.0.0.1"}; + u16 port{26760}; + std::size_t pad_index{}; PadTouch touch{PadTouch::Undefined}; PadMotion motion{PadMotion::Undefined}; f32 motion_value{0.0f}; @@ -82,37 +84,41 @@ public: std::vector<Common::ParamPackage> GetInputDevices() const; - bool DeviceConnected(std::size_t pad) const; - void ReloadUDPClient(); - void ReloadSocket(const std::string& host = "127.0.0.1", u16 port = 26760, - std::size_t pad_index = 0, u32 client_id = 24872); + bool DeviceConnected(std::size_t client) const; + void ReloadSockets(); - std::array<Common::SPSCQueue<UDPPadStatus>, 4>& GetPadQueue(); - const std::array<Common::SPSCQueue<UDPPadStatus>, 4>& GetPadQueue() const; + Common::SPSCQueue<UDPPadStatus>& GetPadQueue(); + const Common::SPSCQueue<UDPPadStatus>& GetPadQueue() const; - DeviceStatus& GetPadState(std::size_t pad); - const DeviceStatus& GetPadState(std::size_t pad) 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; private: struct ClientData { + std::string host{"127.0.0.1"}; + u16 port{26760}; + std::size_t pad_index{}; std::unique_ptr<Socket> socket; DeviceStatus status; std::thread thread; - u64 packet_sequence = 0; - u8 active = 0; + u64 packet_sequence{}; + s8 active{-1}; // 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<std::chrono::system_clock> last_motion_update; + std::chrono::time_point<std::chrono::steady_clock> last_motion_update; }; // 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, std::size_t pad) const; + void OnVersion(Response::Version); void OnPortInfo(Response::PortInfo); - void OnPadData(Response::PadData); + void OnPadData(Response::PadData, std::size_t client); void StartCommunication(std::size_t client, const std::string& host, u16 port, std::size_t pad_index, u32 client_id); void UpdateYuzuSettings(std::size_t client, const Common::Vec3<float>& acc, @@ -120,8 +126,10 @@ private: bool configuring = false; - std::array<ClientData, 4> clients; - std::array<Common::SPSCQueue<UDPPadStatus>, 4> pad_queue; + // Allocate clients for 8 udp servers + const std::size_t max_udp_clients = 32; + std::array<ClientData, 4 * 8> clients; + Common::SPSCQueue<UDPPadStatus> pad_queue; }; /// An async job allowing configuration of the touchpad calibration. diff --git a/src/input_common/udp/udp.cpp b/src/input_common/udp/udp.cpp index 71a76a7aa..8686a059c 100644 --- a/src/input_common/udp/udp.cpp +++ b/src/input_common/udp/udp.cpp @@ -13,17 +13,17 @@ namespace InputCommon { class UDPMotion final : public Input::MotionDevice { public: - explicit UDPMotion(std::string ip_, int port_, u32 pad_, CemuhookUDP::Client* client_) + 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(pad).motion_status; + return client->GetPadState(ip, port, pad).motion_status; } private: const std::string ip; - const int port; - const u32 pad; + const u16 port; + const u16 pad; CemuhookUDP::Client* client; mutable std::mutex mutex; }; @@ -39,8 +39,8 @@ UDPMotionFactory::UDPMotionFactory(std::shared_ptr<CemuhookUDP::Client> client_) */ std::unique_ptr<Input::MotionDevice> UDPMotionFactory::Create(const Common::ParamPackage& params) { auto ip = params.Get("ip", "127.0.0.1"); - const auto port = params.Get("port", 26760); - const auto pad = static_cast<u32>(params.Get("pad_index", 0)); + const auto port = static_cast<u16>(params.Get("port", 26760)); + const auto pad = static_cast<u16>(params.Get("pad_index", 0)); return std::make_unique<UDPMotion>(std::move(ip), port, pad, client.get()); } @@ -59,35 +59,33 @@ Common::ParamPackage UDPMotionFactory::GetNextInput() { Common::ParamPackage params; CemuhookUDP::UDPPadStatus pad; auto& queue = client->GetPadQueue(); - for (std::size_t pad_number = 0; pad_number < queue.size(); ++pad_number) { - while (queue[pad_number].Pop(pad)) { - if (pad.motion == CemuhookUDP::PadMotion::Undefined || std::abs(pad.motion_value) < 1) { - continue; - } - params.Set("engine", "cemuhookudp"); - params.Set("ip", "127.0.0.1"); - params.Set("port", 26760); - params.Set("pad_index", static_cast<int>(pad_number)); - params.Set("motion", static_cast<u16>(pad.motion)); - return params; + 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<u16>(pad.port)); + params.Set("pad_index", static_cast<u16>(pad.pad_index)); + params.Set("motion", static_cast<u16>(pad.motion)); + return params; } return params; } class UDPTouch final : public Input::TouchDevice { public: - explicit UDPTouch(std::string ip_, int port_, u32 pad_, CemuhookUDP::Client* client_) + explicit UDPTouch(std::string ip_, u16 port_, u16 pad_, CemuhookUDP::Client* client_) : ip(std::move(ip_)), port(port_), pad(pad_), client(client_) {} std::tuple<float, float, bool> GetStatus() const override { - return client->GetPadState(pad).touch_status; + return client->GetPadState(ip, port, pad).touch_status; } private: const std::string ip; - const int port; - const u32 pad; + const u16 port; + const u16 pad; CemuhookUDP::Client* client; mutable std::mutex mutex; }; @@ -103,8 +101,8 @@ UDPTouchFactory::UDPTouchFactory(std::shared_ptr<CemuhookUDP::Client> client_) */ std::unique_ptr<Input::TouchDevice> UDPTouchFactory::Create(const Common::ParamPackage& params) { auto ip = params.Get("ip", "127.0.0.1"); - const auto port = params.Get("port", 26760); - const auto pad = static_cast<u32>(params.Get("pad_index", 0)); + const auto port = static_cast<u16>(params.Get("port", 26760)); + const auto pad = static_cast<u16>(params.Get("pad_index", 0)); return std::make_unique<UDPTouch>(std::move(ip), port, pad, client.get()); } @@ -123,18 +121,16 @@ Common::ParamPackage UDPTouchFactory::GetNextInput() { Common::ParamPackage params; CemuhookUDP::UDPPadStatus pad; auto& queue = client->GetPadQueue(); - for (std::size_t pad_number = 0; pad_number < queue.size(); ++pad_number) { - while (queue[pad_number].Pop(pad)) { - if (pad.touch == CemuhookUDP::PadTouch::Undefined) { - continue; - } - params.Set("engine", "cemuhookudp"); - params.Set("ip", "127.0.0.1"); - params.Set("port", 26760); - params.Set("pad_index", static_cast<int>(pad_number)); - params.Set("touch", static_cast<u16>(pad.touch)); - return params; + while (queue.Pop(pad)) { + if (pad.touch == CemuhookUDP::PadTouch::Undefined) { + continue; } + params.Set("engine", "cemuhookudp"); + params.Set("ip", pad.host); + params.Set("port", static_cast<u16>(pad.port)); + params.Set("pad_index", static_cast<u16>(pad.pad_index)); + params.Set("touch", static_cast<u16>(pad.touch)); + return params; } return params; } |