diff options
Diffstat (limited to 'src/input_common')
| -rwxr-xr-x | src/input_common/analog_from_button.cpp | 18 | ||||
| -rw-r--r-- | src/input_common/gcadapter/gc_poller.cpp | 10 | ||||
| -rw-r--r-- | src/input_common/keyboard.cpp | 31 | ||||
| -rw-r--r-- | src/input_common/mouse/mouse_input.cpp | 95 | ||||
| -rw-r--r-- | src/input_common/mouse/mouse_input.h | 24 | ||||
| -rw-r--r-- | src/input_common/mouse/mouse_poller.cpp | 33 | ||||
| -rw-r--r-- | src/input_common/sdl/sdl_impl.cpp | 18 | ||||
| -rw-r--r-- | src/input_common/settings.h | 1 | ||||
| -rw-r--r-- | src/input_common/touch_from_button.cpp | 15 | ||||
| -rw-r--r-- | src/input_common/udp/client.cpp | 148 | ||||
| -rw-r--r-- | src/input_common/udp/client.h | 33 | ||||
| -rw-r--r-- | src/input_common/udp/protocol.h | 16 | ||||
| -rw-r--r-- | src/input_common/udp/udp.cpp | 36 |
13 files changed, 344 insertions, 134 deletions
diff --git a/src/input_common/analog_from_button.cpp b/src/input_common/analog_from_button.cpp index 40b516f85..770893687 100755 --- a/src/input_common/analog_from_button.cpp +++ b/src/input_common/analog_from_button.cpp | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <atomic> | ||
| 5 | #include <chrono> | 6 | #include <chrono> |
| 6 | #include <cmath> | 7 | #include <cmath> |
| 7 | #include <thread> | 8 | #include <thread> |
| @@ -20,13 +21,16 @@ public: | |||
| 20 | : up(std::move(up_)), down(std::move(down_)), left(std::move(left_)), | 21 | : up(std::move(up_)), down(std::move(down_)), left(std::move(left_)), |
| 21 | right(std::move(right_)), modifier(std::move(modifier_)), modifier_scale(modifier_scale_), | 22 | right(std::move(right_)), modifier(std::move(modifier_)), modifier_scale(modifier_scale_), |
| 22 | modifier_angle(modifier_angle_) { | 23 | modifier_angle(modifier_angle_) { |
| 24 | update_thread_running.store(true); | ||
| 23 | update_thread = std::thread(&Analog::UpdateStatus, this); | 25 | update_thread = std::thread(&Analog::UpdateStatus, this); |
| 24 | } | 26 | } |
| 25 | 27 | ||
| 26 | ~Analog() override { | 28 | ~Analog() override { |
| 27 | update_thread_running = false; | 29 | if (update_thread_running.load()) { |
| 28 | if (update_thread.joinable()) { | 30 | update_thread_running.store(false); |
| 29 | update_thread.join(); | 31 | if (update_thread.joinable()) { |
| 32 | update_thread.join(); | ||
| 33 | } | ||
| 30 | } | 34 | } |
| 31 | } | 35 | } |
| 32 | 36 | ||
| @@ -58,7 +62,7 @@ public: | |||
| 58 | } | 62 | } |
| 59 | 63 | ||
| 60 | void UpdateStatus() { | 64 | void UpdateStatus() { |
| 61 | while (update_thread_running) { | 65 | while (update_thread_running.load()) { |
| 62 | const float coef = modifier->GetStatus() ? modifier_scale : 1.0f; | 66 | const float coef = modifier->GetStatus() ? modifier_scale : 1.0f; |
| 63 | 67 | ||
| 64 | bool r = right->GetStatus(); | 68 | bool r = right->GetStatus(); |
| @@ -135,6 +139,10 @@ public: | |||
| 135 | static_cast<float>(y) * coef * (x == 0 ? 1.0f : SQRT_HALF)); | 139 | static_cast<float>(y) * coef * (x == 0 ? 1.0f : SQRT_HALF)); |
| 136 | } | 140 | } |
| 137 | 141 | ||
| 142 | Input::AnalogProperties GetAnalogProperties() const override { | ||
| 143 | return {modifier_scale, 1.0f, 0.5f}; | ||
| 144 | } | ||
| 145 | |||
| 138 | bool GetAnalogDirectionStatus(Input::AnalogDirection direction) const override { | 146 | bool GetAnalogDirectionStatus(Input::AnalogDirection direction) const override { |
| 139 | switch (direction) { | 147 | switch (direction) { |
| 140 | case Input::AnalogDirection::RIGHT: | 148 | case Input::AnalogDirection::RIGHT: |
| @@ -160,7 +168,7 @@ private: | |||
| 160 | float angle{}; | 168 | float angle{}; |
| 161 | float amplitude{}; | 169 | float amplitude{}; |
| 162 | std::thread update_thread; | 170 | std::thread update_thread; |
| 163 | bool update_thread_running{true}; | 171 | std::atomic<bool> update_thread_running{}; |
| 164 | }; | 172 | }; |
| 165 | 173 | ||
| 166 | std::unique_ptr<Input::AnalogDevice> AnalogFromButton::Create(const Common::ParamPackage& params) { | 174 | std::unique_ptr<Input::AnalogDevice> AnalogFromButton::Create(const Common::ParamPackage& params) { |
diff --git a/src/input_common/gcadapter/gc_poller.cpp b/src/input_common/gcadapter/gc_poller.cpp index 9670bdeb2..1b6ded8d6 100644 --- a/src/input_common/gcadapter/gc_poller.cpp +++ b/src/input_common/gcadapter/gc_poller.cpp | |||
| @@ -185,6 +185,16 @@ public: | |||
| 185 | return {0.0f, 0.0f}; | 185 | return {0.0f, 0.0f}; |
| 186 | } | 186 | } |
| 187 | 187 | ||
| 188 | std::tuple<float, float> GetRawStatus() const override { | ||
| 189 | const float x = GetAxis(axis_x); | ||
| 190 | const float y = GetAxis(axis_y); | ||
| 191 | return {x, y}; | ||
| 192 | } | ||
| 193 | |||
| 194 | Input::AnalogProperties GetAnalogProperties() const override { | ||
| 195 | return {deadzone, range, 0.5f}; | ||
| 196 | } | ||
| 197 | |||
| 188 | bool GetAnalogDirectionStatus(Input::AnalogDirection direction) const override { | 198 | bool GetAnalogDirectionStatus(Input::AnalogDirection direction) const override { |
| 189 | const auto [x, y] = GetStatus(); | 199 | const auto [x, y] = GetStatus(); |
| 190 | const float directional_deadzone = 0.5f; | 200 | const float directional_deadzone = 0.5f; |
diff --git a/src/input_common/keyboard.cpp b/src/input_common/keyboard.cpp index 24a6f7a33..c467ff4c5 100644 --- a/src/input_common/keyboard.cpp +++ b/src/input_common/keyboard.cpp | |||
| @@ -12,20 +12,39 @@ namespace InputCommon { | |||
| 12 | 12 | ||
| 13 | class KeyButton final : public Input::ButtonDevice { | 13 | class KeyButton final : public Input::ButtonDevice { |
| 14 | public: | 14 | public: |
| 15 | explicit KeyButton(std::shared_ptr<KeyButtonList> key_button_list_) | 15 | explicit KeyButton(std::shared_ptr<KeyButtonList> key_button_list_, bool toggle_) |
| 16 | : key_button_list(std::move(key_button_list_)) {} | 16 | : key_button_list(std::move(key_button_list_)), toggle(toggle_) {} |
| 17 | 17 | ||
| 18 | ~KeyButton() override; | 18 | ~KeyButton() override; |
| 19 | 19 | ||
| 20 | bool GetStatus() const override { | 20 | bool GetStatus() const override { |
| 21 | if (toggle) { | ||
| 22 | return toggled_status.load(std::memory_order_relaxed); | ||
| 23 | } | ||
| 21 | return status.load(); | 24 | return status.load(); |
| 22 | } | 25 | } |
| 23 | 26 | ||
| 27 | void ToggleButton() { | ||
| 28 | if (lock) { | ||
| 29 | return; | ||
| 30 | } | ||
| 31 | lock = true; | ||
| 32 | const bool old_toggle_status = toggled_status.load(); | ||
| 33 | toggled_status.store(!old_toggle_status); | ||
| 34 | } | ||
| 35 | |||
| 36 | void UnlockButton() { | ||
| 37 | lock = false; | ||
| 38 | } | ||
| 39 | |||
| 24 | friend class KeyButtonList; | 40 | friend class KeyButtonList; |
| 25 | 41 | ||
| 26 | private: | 42 | private: |
| 27 | std::shared_ptr<KeyButtonList> key_button_list; | 43 | std::shared_ptr<KeyButtonList> key_button_list; |
| 28 | std::atomic<bool> status{false}; | 44 | std::atomic<bool> status{false}; |
| 45 | std::atomic<bool> toggled_status{false}; | ||
| 46 | bool lock{false}; | ||
| 47 | const bool toggle; | ||
| 29 | }; | 48 | }; |
| 30 | 49 | ||
| 31 | struct KeyButtonPair { | 50 | struct KeyButtonPair { |
| @@ -51,6 +70,11 @@ public: | |||
| 51 | for (const KeyButtonPair& pair : list) { | 70 | for (const KeyButtonPair& pair : list) { |
| 52 | if (pair.key_code == key_code) { | 71 | if (pair.key_code == key_code) { |
| 53 | pair.key_button->status.store(pressed); | 72 | pair.key_button->status.store(pressed); |
| 73 | if (pressed) { | ||
| 74 | pair.key_button->ToggleButton(); | ||
| 75 | } else { | ||
| 76 | pair.key_button->UnlockButton(); | ||
| 77 | } | ||
| 54 | } | 78 | } |
| 55 | } | 79 | } |
| 56 | } | 80 | } |
| @@ -75,7 +99,8 @@ KeyButton::~KeyButton() { | |||
| 75 | 99 | ||
| 76 | std::unique_ptr<Input::ButtonDevice> Keyboard::Create(const Common::ParamPackage& params) { | 100 | std::unique_ptr<Input::ButtonDevice> Keyboard::Create(const Common::ParamPackage& params) { |
| 77 | const int key_code = params.Get("code", 0); | 101 | const int key_code = params.Get("code", 0); |
| 78 | std::unique_ptr<KeyButton> button = std::make_unique<KeyButton>(key_button_list); | 102 | const bool toggle = params.Get("toggle", false); |
| 103 | std::unique_ptr<KeyButton> button = std::make_unique<KeyButton>(key_button_list, toggle); | ||
| 79 | key_button_list->AddKeyButton(key_code, button.get()); | 104 | key_button_list->AddKeyButton(key_code, button.get()); |
| 80 | return button; | 105 | return button; |
| 81 | } | 106 | } |
diff --git a/src/input_common/mouse/mouse_input.cpp b/src/input_common/mouse/mouse_input.cpp index 10786a541..329e416c7 100644 --- a/src/input_common/mouse/mouse_input.cpp +++ b/src/input_common/mouse/mouse_input.cpp | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | // Licensed under GPLv2+ | 2 | // Licensed under GPLv2+ |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include "core/settings.h" | ||
| 5 | #include "input_common/mouse/mouse_input.h" | 6 | #include "input_common/mouse/mouse_input.h" |
| 6 | 7 | ||
| 7 | namespace MouseInput { | 8 | namespace MouseInput { |
| @@ -32,10 +33,18 @@ void Mouse::UpdateThread() { | |||
| 32 | info.motion.UpdateOrientation(update_time * 1000); | 33 | info.motion.UpdateOrientation(update_time * 1000); |
| 33 | info.tilt_speed = 0; | 34 | info.tilt_speed = 0; |
| 34 | info.data.motion = info.motion.GetMotion(); | 35 | info.data.motion = info.motion.GetMotion(); |
| 36 | if (Settings::values.mouse_panning) { | ||
| 37 | info.last_mouse_change *= 0.96f; | ||
| 38 | info.data.axis = {static_cast<int>(16 * info.last_mouse_change.x), | ||
| 39 | static_cast<int>(16 * -info.last_mouse_change.y)}; | ||
| 40 | } | ||
| 35 | } | 41 | } |
| 36 | if (configuring) { | 42 | if (configuring) { |
| 37 | UpdateYuzuSettings(); | 43 | UpdateYuzuSettings(); |
| 38 | } | 44 | } |
| 45 | if (mouse_panning_timout++ > 20) { | ||
| 46 | StopPanning(); | ||
| 47 | } | ||
| 39 | std::this_thread::sleep_for(std::chrono::milliseconds(update_time)); | 48 | std::this_thread::sleep_for(std::chrono::milliseconds(update_time)); |
| 40 | } | 49 | } |
| 41 | } | 50 | } |
| @@ -50,7 +59,7 @@ void Mouse::UpdateYuzuSettings() { | |||
| 50 | }); | 59 | }); |
| 51 | } | 60 | } |
| 52 | 61 | ||
| 53 | void Mouse::PressButton(int x, int y, int button_) { | 62 | void Mouse::PressButton(int x, int y, MouseButton button_) { |
| 54 | const auto button_index = static_cast<std::size_t>(button_); | 63 | const auto button_index = static_cast<std::size_t>(button_); |
| 55 | if (button_index >= mouse_info.size()) { | 64 | if (button_index >= mouse_info.size()) { |
| 56 | return; | 65 | return; |
| @@ -58,15 +67,52 @@ void Mouse::PressButton(int x, int y, int button_) { | |||
| 58 | 67 | ||
| 59 | const auto button = 1U << button_index; | 68 | const auto button = 1U << button_index; |
| 60 | buttons |= static_cast<u16>(button); | 69 | buttons |= static_cast<u16>(button); |
| 61 | last_button = static_cast<MouseButton>(button_index); | 70 | last_button = button_; |
| 62 | 71 | ||
| 63 | mouse_info[button_index].mouse_origin = Common::MakeVec(x, y); | 72 | mouse_info[button_index].mouse_origin = Common::MakeVec(x, y); |
| 64 | mouse_info[button_index].last_mouse_position = Common::MakeVec(x, y); | 73 | mouse_info[button_index].last_mouse_position = Common::MakeVec(x, y); |
| 65 | mouse_info[button_index].data.pressed = true; | 74 | mouse_info[button_index].data.pressed = true; |
| 66 | } | 75 | } |
| 67 | 76 | ||
| 68 | void Mouse::MouseMove(int x, int y) { | 77 | void Mouse::StopPanning() { |
| 69 | for (MouseInfo& info : mouse_info) { | 78 | for (MouseInfo& info : mouse_info) { |
| 79 | if (Settings::values.mouse_panning) { | ||
| 80 | info.data.axis = {}; | ||
| 81 | info.tilt_speed = 0; | ||
| 82 | info.last_mouse_change = {}; | ||
| 83 | } | ||
| 84 | } | ||
| 85 | } | ||
| 86 | |||
| 87 | void Mouse::MouseMove(int x, int y, int center_x, int center_y) { | ||
| 88 | for (MouseInfo& info : mouse_info) { | ||
| 89 | if (Settings::values.mouse_panning) { | ||
| 90 | auto mouse_change = | ||
| 91 | (Common::MakeVec(x, y) - Common::MakeVec(center_x, center_y)).Cast<float>(); | ||
| 92 | mouse_panning_timout = 0; | ||
| 93 | |||
| 94 | if (mouse_change.y == 0 && mouse_change.x == 0) { | ||
| 95 | continue; | ||
| 96 | } | ||
| 97 | const auto mouse_change_length = mouse_change.Length(); | ||
| 98 | if (mouse_change_length < 3.0f) { | ||
| 99 | mouse_change /= mouse_change_length / 3.0f; | ||
| 100 | } | ||
| 101 | |||
| 102 | info.last_mouse_change = (info.last_mouse_change * 0.91f) + (mouse_change * 0.09f); | ||
| 103 | |||
| 104 | const auto last_mouse_change_length = info.last_mouse_change.Length(); | ||
| 105 | if (last_mouse_change_length > 8.0f) { | ||
| 106 | info.last_mouse_change /= last_mouse_change_length / 8.0f; | ||
| 107 | } else if (last_mouse_change_length < 1.0f) { | ||
| 108 | info.last_mouse_change = mouse_change / mouse_change.Length(); | ||
| 109 | } | ||
| 110 | |||
| 111 | info.tilt_direction = info.last_mouse_change; | ||
| 112 | info.tilt_speed = info.tilt_direction.Normalize() * info.sensitivity; | ||
| 113 | continue; | ||
| 114 | } | ||
| 115 | |||
| 70 | if (info.data.pressed) { | 116 | if (info.data.pressed) { |
| 71 | const auto mouse_move = Common::MakeVec(x, y) - info.mouse_origin; | 117 | const auto mouse_move = Common::MakeVec(x, y) - info.mouse_origin; |
| 72 | const auto mouse_change = Common::MakeVec(x, y) - info.last_mouse_position; | 118 | const auto mouse_change = Common::MakeVec(x, y) - info.last_mouse_position; |
| @@ -83,7 +129,7 @@ void Mouse::MouseMove(int x, int y) { | |||
| 83 | } | 129 | } |
| 84 | } | 130 | } |
| 85 | 131 | ||
| 86 | void Mouse::ReleaseButton(int button_) { | 132 | void Mouse::ReleaseButton(MouseButton button_) { |
| 87 | const auto button_index = static_cast<std::size_t>(button_); | 133 | const auto button_index = static_cast<std::size_t>(button_); |
| 88 | if (button_index >= mouse_info.size()) { | 134 | if (button_index >= mouse_info.size()) { |
| 89 | return; | 135 | return; |
| @@ -106,11 +152,52 @@ void Mouse::BeginConfiguration() { | |||
| 106 | 152 | ||
| 107 | void Mouse::EndConfiguration() { | 153 | void Mouse::EndConfiguration() { |
| 108 | buttons = 0; | 154 | buttons = 0; |
| 155 | for (MouseInfo& info : mouse_info) { | ||
| 156 | info.tilt_speed = 0; | ||
| 157 | info.data.pressed = false; | ||
| 158 | info.data.axis = {0, 0}; | ||
| 159 | } | ||
| 109 | last_button = MouseButton::Undefined; | 160 | last_button = MouseButton::Undefined; |
| 110 | mouse_queue.Clear(); | 161 | mouse_queue.Clear(); |
| 111 | configuring = false; | 162 | configuring = false; |
| 112 | } | 163 | } |
| 113 | 164 | ||
| 165 | bool Mouse::ToggleButton(std::size_t button_) { | ||
| 166 | if (button_ >= mouse_info.size()) { | ||
| 167 | return false; | ||
| 168 | } | ||
| 169 | const auto button = 1U << button_; | ||
| 170 | const bool button_state = (toggle_buttons & button) != 0; | ||
| 171 | const bool button_lock = (lock_buttons & button) != 0; | ||
| 172 | |||
| 173 | if (button_lock) { | ||
| 174 | return button_state; | ||
| 175 | } | ||
| 176 | |||
| 177 | lock_buttons |= static_cast<u16>(button); | ||
| 178 | |||
| 179 | if (button_state) { | ||
| 180 | toggle_buttons &= static_cast<u16>(0xFF - button); | ||
| 181 | } else { | ||
| 182 | toggle_buttons |= static_cast<u16>(button); | ||
| 183 | } | ||
| 184 | |||
| 185 | return !button_state; | ||
| 186 | } | ||
| 187 | |||
| 188 | bool Mouse::UnlockButton(std::size_t button_) { | ||
| 189 | if (button_ >= mouse_info.size()) { | ||
| 190 | return false; | ||
| 191 | } | ||
| 192 | |||
| 193 | const auto button = 1U << button_; | ||
| 194 | const bool button_state = (toggle_buttons & button) != 0; | ||
| 195 | |||
| 196 | lock_buttons &= static_cast<u16>(0xFF - button); | ||
| 197 | |||
| 198 | return button_state; | ||
| 199 | } | ||
| 200 | |||
| 114 | Common::SPSCQueue<MouseStatus>& Mouse::GetMouseQueue() { | 201 | Common::SPSCQueue<MouseStatus>& Mouse::GetMouseQueue() { |
| 115 | return mouse_queue; | 202 | return mouse_queue; |
| 116 | } | 203 | } |
diff --git a/src/input_common/mouse/mouse_input.h b/src/input_common/mouse/mouse_input.h index 58803c1bf..750d9b011 100644 --- a/src/input_common/mouse/mouse_input.h +++ b/src/input_common/mouse/mouse_input.h | |||
| @@ -18,10 +18,12 @@ namespace MouseInput { | |||
| 18 | 18 | ||
| 19 | enum class MouseButton { | 19 | enum class MouseButton { |
| 20 | Left, | 20 | Left, |
| 21 | Wheel, | ||
| 22 | Right, | 21 | Right, |
| 23 | Forward, | 22 | Wheel, |
| 24 | Backward, | 23 | Backward, |
| 24 | Forward, | ||
| 25 | Task, | ||
| 26 | Extra, | ||
| 25 | Undefined, | 27 | Undefined, |
| 26 | }; | 28 | }; |
| 27 | 29 | ||
| @@ -51,19 +53,24 @@ public: | |||
| 51 | * @param y the y-coordinate of the cursor | 53 | * @param y the y-coordinate of the cursor |
| 52 | * @param button_ the button pressed | 54 | * @param button_ the button pressed |
| 53 | */ | 55 | */ |
| 54 | void PressButton(int x, int y, int button_); | 56 | void PressButton(int x, int y, MouseButton button_); |
| 55 | 57 | ||
| 56 | /** | 58 | /** |
| 57 | * Signals that mouse has moved. | 59 | * Signals that mouse has moved. |
| 58 | * @param x the x-coordinate of the cursor | 60 | * @param x the x-coordinate of the cursor |
| 59 | * @param y the y-coordinate of the cursor | 61 | * @param y the y-coordinate of the cursor |
| 62 | * @param center_x the x-coordinate of the middle of the screen | ||
| 63 | * @param center_y the y-coordinate of the middle of the screen | ||
| 60 | */ | 64 | */ |
| 61 | void MouseMove(int x, int y); | 65 | void MouseMove(int x, int y, int center_x, int center_y); |
| 62 | 66 | ||
| 63 | /** | 67 | /** |
| 64 | * Signals that a motion sensor tilt has ended. | 68 | * Signals that a motion sensor tilt has ended. |
| 65 | */ | 69 | */ |
| 66 | void ReleaseButton(int button_); | 70 | void ReleaseButton(MouseButton button_); |
| 71 | |||
| 72 | [[nodiscard]] bool ToggleButton(std::size_t button_); | ||
| 73 | [[nodiscard]] bool UnlockButton(std::size_t button_); | ||
| 67 | 74 | ||
| 68 | [[nodiscard]] Common::SPSCQueue<MouseStatus>& GetMouseQueue(); | 75 | [[nodiscard]] Common::SPSCQueue<MouseStatus>& GetMouseQueue(); |
| 69 | [[nodiscard]] const Common::SPSCQueue<MouseStatus>& GetMouseQueue() const; | 76 | [[nodiscard]] const Common::SPSCQueue<MouseStatus>& GetMouseQueue() const; |
| @@ -74,11 +81,13 @@ public: | |||
| 74 | private: | 81 | private: |
| 75 | void UpdateThread(); | 82 | void UpdateThread(); |
| 76 | void UpdateYuzuSettings(); | 83 | void UpdateYuzuSettings(); |
| 84 | void StopPanning(); | ||
| 77 | 85 | ||
| 78 | struct MouseInfo { | 86 | struct MouseInfo { |
| 79 | InputCommon::MotionInput motion{0.0f, 0.0f, 0.0f}; | 87 | InputCommon::MotionInput motion{0.0f, 0.0f, 0.0f}; |
| 80 | Common::Vec2<int> mouse_origin; | 88 | Common::Vec2<int> mouse_origin; |
| 81 | Common::Vec2<int> last_mouse_position; | 89 | Common::Vec2<int> last_mouse_position; |
| 90 | Common::Vec2<float> last_mouse_change; | ||
| 82 | bool is_tilting = false; | 91 | bool is_tilting = false; |
| 83 | float sensitivity{0.120f}; | 92 | float sensitivity{0.120f}; |
| 84 | 93 | ||
| @@ -88,11 +97,14 @@ private: | |||
| 88 | }; | 97 | }; |
| 89 | 98 | ||
| 90 | u16 buttons{}; | 99 | u16 buttons{}; |
| 100 | u16 toggle_buttons{}; | ||
| 101 | u16 lock_buttons{}; | ||
| 91 | std::thread update_thread; | 102 | std::thread update_thread; |
| 92 | MouseButton last_button{MouseButton::Undefined}; | 103 | MouseButton last_button{MouseButton::Undefined}; |
| 93 | std::array<MouseInfo, 5> mouse_info; | 104 | std::array<MouseInfo, 7> mouse_info; |
| 94 | Common::SPSCQueue<MouseStatus> mouse_queue; | 105 | Common::SPSCQueue<MouseStatus> mouse_queue; |
| 95 | bool configuring{false}; | 106 | bool configuring{false}; |
| 96 | bool update_thread_running{true}; | 107 | bool update_thread_running{true}; |
| 108 | int mouse_panning_timout{}; | ||
| 97 | }; | 109 | }; |
| 98 | } // namespace MouseInput | 110 | } // namespace MouseInput |
diff --git a/src/input_common/mouse/mouse_poller.cpp b/src/input_common/mouse/mouse_poller.cpp index 508eb0c7d..0e1db54fb 100644 --- a/src/input_common/mouse/mouse_poller.cpp +++ b/src/input_common/mouse/mouse_poller.cpp | |||
| @@ -6,6 +6,7 @@ | |||
| 6 | #include <utility> | 6 | #include <utility> |
| 7 | 7 | ||
| 8 | #include "common/threadsafe_queue.h" | 8 | #include "common/threadsafe_queue.h" |
| 9 | #include "core/settings.h" | ||
| 9 | #include "input_common/mouse/mouse_input.h" | 10 | #include "input_common/mouse/mouse_input.h" |
| 10 | #include "input_common/mouse/mouse_poller.h" | 11 | #include "input_common/mouse/mouse_poller.h" |
| 11 | 12 | ||
| @@ -13,16 +14,25 @@ namespace InputCommon { | |||
| 13 | 14 | ||
| 14 | class MouseButton final : public Input::ButtonDevice { | 15 | class MouseButton final : public Input::ButtonDevice { |
| 15 | public: | 16 | public: |
| 16 | explicit MouseButton(u32 button_, const MouseInput::Mouse* mouse_input_) | 17 | explicit MouseButton(u32 button_, bool toggle_, MouseInput::Mouse* mouse_input_) |
| 17 | : button(button_), mouse_input(mouse_input_) {} | 18 | : button(button_), toggle(toggle_), mouse_input(mouse_input_) {} |
| 18 | 19 | ||
| 19 | bool GetStatus() const override { | 20 | bool GetStatus() const override { |
| 20 | return mouse_input->GetMouseState(button).pressed; | 21 | const bool button_state = mouse_input->GetMouseState(button).pressed; |
| 22 | if (!toggle) { | ||
| 23 | return button_state; | ||
| 24 | } | ||
| 25 | |||
| 26 | if (button_state) { | ||
| 27 | return mouse_input->ToggleButton(button); | ||
| 28 | } | ||
| 29 | return mouse_input->UnlockButton(button); | ||
| 21 | } | 30 | } |
| 22 | 31 | ||
| 23 | private: | 32 | private: |
| 24 | const u32 button; | 33 | const u32 button; |
| 25 | const MouseInput::Mouse* mouse_input; | 34 | const bool toggle; |
| 35 | MouseInput::Mouse* mouse_input; | ||
| 26 | }; | 36 | }; |
| 27 | 37 | ||
| 28 | MouseButtonFactory::MouseButtonFactory(std::shared_ptr<MouseInput::Mouse> mouse_input_) | 38 | MouseButtonFactory::MouseButtonFactory(std::shared_ptr<MouseInput::Mouse> mouse_input_) |
| @@ -31,8 +41,9 @@ MouseButtonFactory::MouseButtonFactory(std::shared_ptr<MouseInput::Mouse> mouse_ | |||
| 31 | std::unique_ptr<Input::ButtonDevice> MouseButtonFactory::Create( | 41 | std::unique_ptr<Input::ButtonDevice> MouseButtonFactory::Create( |
| 32 | const Common::ParamPackage& params) { | 42 | const Common::ParamPackage& params) { |
| 33 | const auto button_id = params.Get("button", 0); | 43 | const auto button_id = params.Get("button", 0); |
| 44 | const auto toggle = params.Get("toggle", false); | ||
| 34 | 45 | ||
| 35 | return std::make_unique<MouseButton>(button_id, mouse_input.get()); | 46 | return std::make_unique<MouseButton>(button_id, toggle, mouse_input.get()); |
| 36 | } | 47 | } |
| 37 | 48 | ||
| 38 | Common::ParamPackage MouseButtonFactory::GetNextInput() const { | 49 | Common::ParamPackage MouseButtonFactory::GetNextInput() const { |
| @@ -71,7 +82,7 @@ public: | |||
| 71 | std::lock_guard lock{mutex}; | 82 | std::lock_guard lock{mutex}; |
| 72 | const auto axis_value = | 83 | const auto axis_value = |
| 73 | static_cast<float>(mouse_input->GetMouseState(button).axis.at(axis)); | 84 | static_cast<float>(mouse_input->GetMouseState(button).axis.at(axis)); |
| 74 | return axis_value / (100.0f * range); | 85 | return axis_value * Settings::values.mouse_panning_sensitivity / (100.0f * range); |
| 75 | } | 86 | } |
| 76 | 87 | ||
| 77 | std::pair<float, float> GetAnalog(u32 analog_axis_x, u32 analog_axis_y) const { | 88 | std::pair<float, float> GetAnalog(u32 analog_axis_x, u32 analog_axis_y) const { |
| @@ -106,6 +117,16 @@ public: | |||
| 106 | return {0.0f, 0.0f}; | 117 | return {0.0f, 0.0f}; |
| 107 | } | 118 | } |
| 108 | 119 | ||
| 120 | std::tuple<float, float> GetRawStatus() const override { | ||
| 121 | const float x = GetAxis(axis_x); | ||
| 122 | const float y = GetAxis(axis_y); | ||
| 123 | return {x, y}; | ||
| 124 | } | ||
| 125 | |||
| 126 | Input::AnalogProperties GetAnalogProperties() const override { | ||
| 127 | return {deadzone, range, 0.5f}; | ||
| 128 | } | ||
| 129 | |||
| 109 | private: | 130 | private: |
| 110 | const u32 button; | 131 | const u32 button; |
| 111 | const u32 axis_x; | 132 | const u32 axis_x; |
diff --git a/src/input_common/sdl/sdl_impl.cpp b/src/input_common/sdl/sdl_impl.cpp index d32eb732a..f67de37e3 100644 --- a/src/input_common/sdl/sdl_impl.cpp +++ b/src/input_common/sdl/sdl_impl.cpp | |||
| @@ -81,10 +81,14 @@ public: | |||
| 81 | } | 81 | } |
| 82 | 82 | ||
| 83 | bool RumblePlay(u16 amp_low, u16 amp_high) { | 83 | bool RumblePlay(u16 amp_low, u16 amp_high) { |
| 84 | constexpr u32 rumble_max_duration_ms = 1000; | ||
| 85 | |||
| 84 | if (sdl_controller) { | 86 | if (sdl_controller) { |
| 85 | return SDL_GameControllerRumble(sdl_controller.get(), amp_low, amp_high, 0) == 0; | 87 | return SDL_GameControllerRumble(sdl_controller.get(), amp_low, amp_high, |
| 88 | rumble_max_duration_ms) == 0; | ||
| 86 | } else if (sdl_joystick) { | 89 | } else if (sdl_joystick) { |
| 87 | return SDL_JoystickRumble(sdl_joystick.get(), amp_low, amp_high, 0) == 0; | 90 | return SDL_JoystickRumble(sdl_joystick.get(), amp_low, amp_high, |
| 91 | rumble_max_duration_ms) == 0; | ||
| 88 | } | 92 | } |
| 89 | 93 | ||
| 90 | return false; | 94 | return false; |
| @@ -373,6 +377,16 @@ public: | |||
| 373 | return {}; | 377 | return {}; |
| 374 | } | 378 | } |
| 375 | 379 | ||
| 380 | std::tuple<float, float> GetRawStatus() const override { | ||
| 381 | const float x = joystick->GetAxis(axis_x, range); | ||
| 382 | const float y = joystick->GetAxis(axis_y, range); | ||
| 383 | return {x, -y}; | ||
| 384 | } | ||
| 385 | |||
| 386 | Input::AnalogProperties GetAnalogProperties() const override { | ||
| 387 | return {deadzone, range, 0.5f}; | ||
| 388 | } | ||
| 389 | |||
| 376 | bool GetAnalogDirectionStatus(Input::AnalogDirection direction) const override { | 390 | bool GetAnalogDirectionStatus(Input::AnalogDirection direction) const override { |
| 377 | const auto [x, y] = GetStatus(); | 391 | const auto [x, y] = GetStatus(); |
| 378 | const float directional_deadzone = 0.5f; | 392 | const float directional_deadzone = 0.5f; |
diff --git a/src/input_common/settings.h b/src/input_common/settings.h index 75486554b..a59f5d461 100644 --- a/src/input_common/settings.h +++ b/src/input_common/settings.h | |||
| @@ -340,6 +340,7 @@ enum class ControllerType { | |||
| 340 | LeftJoycon, | 340 | LeftJoycon, |
| 341 | RightJoycon, | 341 | RightJoycon, |
| 342 | Handheld, | 342 | Handheld, |
| 343 | GameCube, | ||
| 343 | }; | 344 | }; |
| 344 | 345 | ||
| 345 | struct PlayerInput { | 346 | struct PlayerInput { |
diff --git a/src/input_common/touch_from_button.cpp b/src/input_common/touch_from_button.cpp index a07124a86..ffbe4f2ed 100644 --- a/src/input_common/touch_from_button.cpp +++ b/src/input_common/touch_from_button.cpp | |||
| @@ -25,18 +25,19 @@ public: | |||
| 25 | } | 25 | } |
| 26 | } | 26 | } |
| 27 | 27 | ||
| 28 | std::tuple<float, float, bool> GetStatus() const override { | 28 | Input::TouchStatus GetStatus() const override { |
| 29 | for (const auto& m : map) { | 29 | Input::TouchStatus touch_status{}; |
| 30 | const bool state = std::get<0>(m)->GetStatus(); | 30 | for (std::size_t id = 0; id < map.size() && id < touch_status.size(); ++id) { |
| 31 | const bool state = std::get<0>(map[id])->GetStatus(); | ||
| 31 | if (state) { | 32 | if (state) { |
| 32 | const float x = static_cast<float>(std::get<1>(m)) / | 33 | const float x = static_cast<float>(std::get<1>(map[id])) / |
| 33 | static_cast<int>(Layout::ScreenUndocked::Width); | 34 | static_cast<int>(Layout::ScreenUndocked::Width); |
| 34 | const float y = static_cast<float>(std::get<2>(m)) / | 35 | const float y = static_cast<float>(std::get<2>(map[id])) / |
| 35 | static_cast<int>(Layout::ScreenUndocked::Height); | 36 | static_cast<int>(Layout::ScreenUndocked::Height); |
| 36 | return {x, y, true}; | 37 | touch_status[id] = {x, y, true}; |
| 37 | } | 38 | } |
| 38 | } | 39 | } |
| 39 | return {}; | 40 | return touch_status; |
| 40 | } | 41 | } |
| 41 | 42 | ||
| 42 | private: | 43 | private: |
diff --git a/src/input_common/udp/client.cpp b/src/input_common/udp/client.cpp index 412d57896..df73f9ff7 100644 --- a/src/input_common/udp/client.cpp +++ b/src/input_common/udp/client.cpp | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #include <chrono> | 5 | #include <chrono> |
| 6 | #include <cstring> | 6 | #include <cstring> |
| 7 | #include <functional> | 7 | #include <functional> |
| 8 | #include <random> | ||
| 8 | #include <thread> | 9 | #include <thread> |
| 9 | #include <boost/asio.hpp> | 10 | #include <boost/asio.hpp> |
| 10 | #include "common/logging/log.h" | 11 | #include "common/logging/log.h" |
| @@ -26,10 +27,10 @@ class Socket { | |||
| 26 | public: | 27 | public: |
| 27 | using clock = std::chrono::system_clock; | 28 | using clock = std::chrono::system_clock; |
| 28 | 29 | ||
| 29 | explicit Socket(const std::string& host, u16 port, std::size_t pad_index_, u32 client_id_, | 30 | explicit Socket(const std::string& host, u16 port, std::size_t pad_index_, |
| 30 | SocketCallback callback_) | 31 | SocketCallback callback_) |
| 31 | : callback(std::move(callback_)), timer(io_service), | 32 | : callback(std::move(callback_)), timer(io_service), |
| 32 | socket(io_service, udp::endpoint(udp::v4(), 0)), client_id(client_id_), | 33 | socket(io_service, udp::endpoint(udp::v4(), 0)), client_id(GenerateRandomClientId()), |
| 33 | pad_index(pad_index_) { | 34 | pad_index(pad_index_) { |
| 34 | boost::system::error_code ec{}; | 35 | boost::system::error_code ec{}; |
| 35 | auto ipv4 = boost::asio::ip::make_address_v4(host, ec); | 36 | auto ipv4 = boost::asio::ip::make_address_v4(host, ec); |
| @@ -63,6 +64,11 @@ public: | |||
| 63 | } | 64 | } |
| 64 | 65 | ||
| 65 | private: | 66 | private: |
| 67 | u32 GenerateRandomClientId() const { | ||
| 68 | std::random_device device; | ||
| 69 | return device(); | ||
| 70 | } | ||
| 71 | |||
| 66 | void HandleReceive(const boost::system::error_code&, std::size_t bytes_transferred) { | 72 | void HandleReceive(const boost::system::error_code&, std::size_t bytes_transferred) { |
| 67 | if (auto type = Response::Validate(receive_buffer.data(), bytes_transferred)) { | 73 | if (auto type = Response::Validate(receive_buffer.data(), bytes_transferred)) { |
| 68 | switch (*type) { | 74 | switch (*type) { |
| @@ -115,7 +121,7 @@ private: | |||
| 115 | boost::asio::basic_waitable_timer<clock> timer; | 121 | boost::asio::basic_waitable_timer<clock> timer; |
| 116 | udp::socket socket; | 122 | udp::socket socket; |
| 117 | 123 | ||
| 118 | u32 client_id{}; | 124 | const u32 client_id; |
| 119 | std::size_t pad_index{}; | 125 | std::size_t pad_index{}; |
| 120 | 126 | ||
| 121 | static constexpr std::size_t PORT_INFO_SIZE = sizeof(Message<Request::PortInfo>); | 127 | static constexpr std::size_t PORT_INFO_SIZE = sizeof(Message<Request::PortInfo>); |
| @@ -136,6 +142,7 @@ static void SocketLoop(Socket* socket) { | |||
| 136 | 142 | ||
| 137 | Client::Client() { | 143 | Client::Client() { |
| 138 | LOG_INFO(Input, "Udp Initialization started"); | 144 | LOG_INFO(Input, "Udp Initialization started"); |
| 145 | finger_id.fill(MAX_TOUCH_FINGERS); | ||
| 139 | ReloadSockets(); | 146 | ReloadSockets(); |
| 140 | } | 147 | } |
| 141 | 148 | ||
| @@ -143,6 +150,10 @@ Client::~Client() { | |||
| 143 | Reset(); | 150 | Reset(); |
| 144 | } | 151 | } |
| 145 | 152 | ||
| 153 | Client::ClientData::ClientData() = default; | ||
| 154 | |||
| 155 | Client::ClientData::~ClientData() = default; | ||
| 156 | |||
| 146 | std::vector<Common::ParamPackage> Client::GetInputDevices() const { | 157 | std::vector<Common::ParamPackage> Client::GetInputDevices() const { |
| 147 | std::vector<Common::ParamPackage> devices; | 158 | std::vector<Common::ParamPackage> devices; |
| 148 | for (std::size_t client = 0; client < clients.size(); client++) { | 159 | for (std::size_t client = 0; client < clients.size(); client++) { |
| @@ -176,7 +187,7 @@ void Client::ReloadSockets() { | |||
| 176 | std::string server_token; | 187 | std::string server_token; |
| 177 | std::size_t client = 0; | 188 | std::size_t client = 0; |
| 178 | while (std::getline(servers_ss, server_token, ',')) { | 189 | while (std::getline(servers_ss, server_token, ',')) { |
| 179 | if (client == max_udp_clients) { | 190 | if (client == MAX_UDP_CLIENTS) { |
| 180 | break; | 191 | break; |
| 181 | } | 192 | } |
| 182 | std::stringstream server_ss(server_token); | 193 | std::stringstream server_ss(server_token); |
| @@ -194,11 +205,11 @@ void Client::ReloadSockets() { | |||
| 194 | for (std::size_t pad = 0; pad < 4; ++pad) { | 205 | for (std::size_t pad = 0; pad < 4; ++pad) { |
| 195 | const std::size_t client_number = | 206 | const std::size_t client_number = |
| 196 | GetClientNumber(udp_input_address, udp_input_port, pad); | 207 | GetClientNumber(udp_input_address, udp_input_port, pad); |
| 197 | if (client_number != max_udp_clients) { | 208 | if (client_number != MAX_UDP_CLIENTS) { |
| 198 | LOG_ERROR(Input, "Duplicated UDP servers found"); | 209 | LOG_ERROR(Input, "Duplicated UDP servers found"); |
| 199 | continue; | 210 | continue; |
| 200 | } | 211 | } |
| 201 | StartCommunication(client++, udp_input_address, udp_input_port, pad, 24872); | 212 | StartCommunication(client++, udp_input_address, udp_input_port, pad); |
| 202 | } | 213 | } |
| 203 | } | 214 | } |
| 204 | } | 215 | } |
| @@ -213,7 +224,7 @@ std::size_t Client::GetClientNumber(std::string_view host, u16 port, std::size_t | |||
| 213 | return client; | 224 | return client; |
| 214 | } | 225 | } |
| 215 | } | 226 | } |
| 216 | return max_udp_clients; | 227 | return MAX_UDP_CLIENTS; |
| 217 | } | 228 | } |
| 218 | 229 | ||
| 219 | void Client::OnVersion([[maybe_unused]] Response::Version data) { | 230 | void Client::OnVersion([[maybe_unused]] Response::Version data) { |
| @@ -259,39 +270,20 @@ void Client::OnPadData(Response::PadData data, std::size_t client) { | |||
| 259 | std::lock_guard guard(clients[client].status.update_mutex); | 270 | std::lock_guard guard(clients[client].status.update_mutex); |
| 260 | clients[client].status.motion_status = clients[client].motion.GetMotion(); | 271 | clients[client].status.motion_status = clients[client].motion.GetMotion(); |
| 261 | 272 | ||
| 262 | // TODO: add a setting for "click" touch. Click touch refers to a device that differentiates | 273 | for (std::size_t id = 0; id < data.touch.size(); ++id) { |
| 263 | // between a simple "tap" and a hard press that causes the touch screen to click. | 274 | UpdateTouchInput(data.touch[id], client, id); |
| 264 | const bool is_active = data.touch_1.is_active != 0; | ||
| 265 | |||
| 266 | float x = 0; | ||
| 267 | float y = 0; | ||
| 268 | |||
| 269 | if (is_active && clients[client].status.touch_calibration) { | ||
| 270 | const u16 min_x = clients[client].status.touch_calibration->min_x; | ||
| 271 | const u16 max_x = clients[client].status.touch_calibration->max_x; | ||
| 272 | const u16 min_y = clients[client].status.touch_calibration->min_y; | ||
| 273 | const u16 max_y = clients[client].status.touch_calibration->max_y; | ||
| 274 | |||
| 275 | x = static_cast<float>(std::clamp(static_cast<u16>(data.touch_1.x), min_x, max_x) - | ||
| 276 | min_x) / | ||
| 277 | static_cast<float>(max_x - min_x); | ||
| 278 | y = static_cast<float>(std::clamp(static_cast<u16>(data.touch_1.y), min_y, max_y) - | ||
| 279 | min_y) / | ||
| 280 | static_cast<float>(max_y - min_y); | ||
| 281 | } | 275 | } |
| 282 | 276 | ||
| 283 | clients[client].status.touch_status = {x, y, is_active}; | ||
| 284 | |||
| 285 | if (configuring) { | 277 | if (configuring) { |
| 286 | const Common::Vec3f gyroscope = clients[client].motion.GetGyroscope(); | 278 | const Common::Vec3f gyroscope = clients[client].motion.GetGyroscope(); |
| 287 | const Common::Vec3f accelerometer = clients[client].motion.GetAcceleration(); | 279 | const Common::Vec3f accelerometer = clients[client].motion.GetAcceleration(); |
| 288 | UpdateYuzuSettings(client, accelerometer, gyroscope, is_active); | 280 | UpdateYuzuSettings(client, accelerometer, gyroscope); |
| 289 | } | 281 | } |
| 290 | } | 282 | } |
| 291 | } | 283 | } |
| 292 | 284 | ||
| 293 | void Client::StartCommunication(std::size_t client, const std::string& host, u16 port, | 285 | void Client::StartCommunication(std::size_t client, const std::string& host, u16 port, |
| 294 | std::size_t pad_index, u32 client_id) { | 286 | std::size_t pad_index) { |
| 295 | SocketCallback callback{[this](Response::Version version) { OnVersion(version); }, | 287 | SocketCallback callback{[this](Response::Version version) { OnVersion(version); }, |
| 296 | [this](Response::PortInfo info) { OnPortInfo(info); }, | 288 | [this](Response::PortInfo info) { OnPortInfo(info); }, |
| 297 | [this, client](Response::PadData data) { OnPadData(data, client); }}; | 289 | [this, client](Response::PadData data) { OnPadData(data, client); }}; |
| @@ -301,7 +293,7 @@ void Client::StartCommunication(std::size_t client, const std::string& host, u16 | |||
| 301 | clients[client].port = port; | 293 | clients[client].port = port; |
| 302 | clients[client].pad_index = pad_index; | 294 | clients[client].pad_index = pad_index; |
| 303 | clients[client].active = 0; | 295 | clients[client].active = 0; |
| 304 | clients[client].socket = std::make_unique<Socket>(host, port, pad_index, client_id, callback); | 296 | clients[client].socket = std::make_unique<Socket>(host, port, pad_index, callback); |
| 305 | clients[client].thread = std::thread{SocketLoop, clients[client].socket.get()}; | 297 | clients[client].thread = std::thread{SocketLoop, clients[client].socket.get()}; |
| 306 | // Set motion parameters | 298 | // Set motion parameters |
| 307 | // SetGyroThreshold value should be dependent on GyroscopeZeroDriftMode | 299 | // SetGyroThreshold value should be dependent on GyroscopeZeroDriftMode |
| @@ -320,21 +312,17 @@ void Client::Reset() { | |||
| 320 | } | 312 | } |
| 321 | 313 | ||
| 322 | void Client::UpdateYuzuSettings(std::size_t client, const Common::Vec3<float>& acc, | 314 | void Client::UpdateYuzuSettings(std::size_t client, const Common::Vec3<float>& acc, |
| 323 | const Common::Vec3<float>& gyro, bool touch) { | 315 | const Common::Vec3<float>& gyro) { |
| 324 | if (gyro.Length() > 0.2f) { | 316 | if (gyro.Length() > 0.2f) { |
| 325 | LOG_DEBUG(Input, "UDP Controller {}: gyro=({}, {}, {}), accel=({}, {}, {}), touch={}", | 317 | LOG_DEBUG(Input, "UDP Controller {}: gyro=({}, {}, {}), accel=({}, {}, {})", client, |
| 326 | client, gyro[0], gyro[1], gyro[2], acc[0], acc[1], acc[2], touch); | 318 | gyro[0], gyro[1], gyro[2], acc[0], acc[1], acc[2]); |
| 327 | } | 319 | } |
| 328 | UDPPadStatus pad{ | 320 | UDPPadStatus pad{ |
| 329 | .host = clients[client].host, | 321 | .host = clients[client].host, |
| 330 | .port = clients[client].port, | 322 | .port = clients[client].port, |
| 331 | .pad_index = clients[client].pad_index, | 323 | .pad_index = clients[client].pad_index, |
| 332 | }; | 324 | }; |
| 333 | if (touch) { | 325 | for (std::size_t i = 0; i < 3; ++i) { |
| 334 | pad.touch = PadTouch::Click; | ||
| 335 | pad_queue.Push(pad); | ||
| 336 | } | ||
| 337 | for (size_t i = 0; i < 3; ++i) { | ||
| 338 | if (gyro[i] > 5.0f || gyro[i] < -5.0f) { | 326 | if (gyro[i] > 5.0f || gyro[i] < -5.0f) { |
| 339 | pad.motion = static_cast<PadMotion>(i); | 327 | pad.motion = static_cast<PadMotion>(i); |
| 340 | pad.motion_value = gyro[i]; | 328 | pad.motion_value = gyro[i]; |
| @@ -348,6 +336,50 @@ void Client::UpdateYuzuSettings(std::size_t client, const Common::Vec3<float>& a | |||
| 348 | } | 336 | } |
| 349 | } | 337 | } |
| 350 | 338 | ||
| 339 | std::optional<std::size_t> Client::GetUnusedFingerID() const { | ||
| 340 | std::size_t first_free_id = 0; | ||
| 341 | while (first_free_id < MAX_TOUCH_FINGERS) { | ||
| 342 | if (!std::get<2>(touch_status[first_free_id])) { | ||
| 343 | return first_free_id; | ||
| 344 | } else { | ||
| 345 | first_free_id++; | ||
| 346 | } | ||
| 347 | } | ||
| 348 | return std::nullopt; | ||
| 349 | } | ||
| 350 | |||
| 351 | void Client::UpdateTouchInput(Response::TouchPad& touch_pad, std::size_t client, std::size_t id) { | ||
| 352 | // TODO: Use custom calibration per device | ||
| 353 | const Common::ParamPackage touch_param(Settings::values.touch_device); | ||
| 354 | const u16 min_x = static_cast<u16>(touch_param.Get("min_x", 100)); | ||
| 355 | const u16 min_y = static_cast<u16>(touch_param.Get("min_y", 50)); | ||
| 356 | const u16 max_x = static_cast<u16>(touch_param.Get("max_x", 1800)); | ||
| 357 | const u16 max_y = static_cast<u16>(touch_param.Get("max_y", 850)); | ||
| 358 | const std::size_t touch_id = client * 2 + id; | ||
| 359 | if (touch_pad.is_active) { | ||
| 360 | if (finger_id[touch_id] == MAX_TOUCH_FINGERS) { | ||
| 361 | const auto first_free_id = GetUnusedFingerID(); | ||
| 362 | if (!first_free_id) { | ||
| 363 | // Invalid finger id skip to next input | ||
| 364 | return; | ||
| 365 | } | ||
| 366 | finger_id[touch_id] = *first_free_id; | ||
| 367 | } | ||
| 368 | auto& [x, y, pressed] = touch_status[finger_id[touch_id]]; | ||
| 369 | x = static_cast<float>(std::clamp(static_cast<u16>(touch_pad.x), min_x, max_x) - min_x) / | ||
| 370 | static_cast<float>(max_x - min_x); | ||
| 371 | y = static_cast<float>(std::clamp(static_cast<u16>(touch_pad.y), min_y, max_y) - min_y) / | ||
| 372 | static_cast<float>(max_y - min_y); | ||
| 373 | pressed = true; | ||
| 374 | return; | ||
| 375 | } | ||
| 376 | |||
| 377 | if (finger_id[touch_id] != MAX_TOUCH_FINGERS) { | ||
| 378 | touch_status[finger_id[touch_id]] = {}; | ||
| 379 | finger_id[touch_id] = MAX_TOUCH_FINGERS; | ||
| 380 | } | ||
| 381 | } | ||
| 382 | |||
| 351 | void Client::BeginConfiguration() { | 383 | void Client::BeginConfiguration() { |
| 352 | pad_queue.Clear(); | 384 | pad_queue.Clear(); |
| 353 | configuring = true; | 385 | configuring = true; |
| @@ -360,7 +392,7 @@ void Client::EndConfiguration() { | |||
| 360 | 392 | ||
| 361 | DeviceStatus& Client::GetPadState(const std::string& host, u16 port, std::size_t pad) { | 393 | DeviceStatus& Client::GetPadState(const std::string& host, u16 port, std::size_t pad) { |
| 362 | const std::size_t client_number = GetClientNumber(host, port, pad); | 394 | const std::size_t client_number = GetClientNumber(host, port, pad); |
| 363 | if (client_number == max_udp_clients) { | 395 | if (client_number == MAX_UDP_CLIENTS) { |
| 364 | return clients[0].status; | 396 | return clients[0].status; |
| 365 | } | 397 | } |
| 366 | return clients[client_number].status; | 398 | return clients[client_number].status; |
| @@ -368,12 +400,20 @@ DeviceStatus& Client::GetPadState(const std::string& host, u16 port, std::size_t | |||
| 368 | 400 | ||
| 369 | const DeviceStatus& Client::GetPadState(const std::string& host, u16 port, std::size_t pad) const { | 401 | const DeviceStatus& Client::GetPadState(const std::string& host, u16 port, std::size_t pad) const { |
| 370 | const std::size_t client_number = GetClientNumber(host, port, pad); | 402 | const std::size_t client_number = GetClientNumber(host, port, pad); |
| 371 | if (client_number == max_udp_clients) { | 403 | if (client_number == MAX_UDP_CLIENTS) { |
| 372 | return clients[0].status; | 404 | return clients[0].status; |
| 373 | } | 405 | } |
| 374 | return clients[client_number].status; | 406 | return clients[client_number].status; |
| 375 | } | 407 | } |
| 376 | 408 | ||
| 409 | Input::TouchStatus& Client::GetTouchState() { | ||
| 410 | return touch_status; | ||
| 411 | } | ||
| 412 | |||
| 413 | const Input::TouchStatus& Client::GetTouchState() const { | ||
| 414 | return touch_status; | ||
| 415 | } | ||
| 416 | |||
| 377 | Common::SPSCQueue<UDPPadStatus>& Client::GetPadQueue() { | 417 | Common::SPSCQueue<UDPPadStatus>& Client::GetPadQueue() { |
| 378 | return pad_queue; | 418 | return pad_queue; |
| 379 | } | 419 | } |
| @@ -382,7 +422,7 @@ const Common::SPSCQueue<UDPPadStatus>& Client::GetPadQueue() const { | |||
| 382 | return pad_queue; | 422 | return pad_queue; |
| 383 | } | 423 | } |
| 384 | 424 | ||
| 385 | void TestCommunication(const std::string& host, u16 port, std::size_t pad_index, u32 client_id, | 425 | void TestCommunication(const std::string& host, u16 port, std::size_t pad_index, |
| 386 | const std::function<void()>& success_callback, | 426 | const std::function<void()>& success_callback, |
| 387 | const std::function<void()>& failure_callback) { | 427 | const std::function<void()>& failure_callback) { |
| 388 | std::thread([=] { | 428 | std::thread([=] { |
| @@ -392,7 +432,7 @@ void TestCommunication(const std::string& host, u16 port, std::size_t pad_index, | |||
| 392 | .port_info = [](Response::PortInfo) {}, | 432 | .port_info = [](Response::PortInfo) {}, |
| 393 | .pad_data = [&](Response::PadData) { success_event.Set(); }, | 433 | .pad_data = [&](Response::PadData) { success_event.Set(); }, |
| 394 | }; | 434 | }; |
| 395 | Socket socket{host, port, pad_index, client_id, std::move(callback)}; | 435 | Socket socket{host, port, pad_index, std::move(callback)}; |
| 396 | std::thread worker_thread{SocketLoop, &socket}; | 436 | std::thread worker_thread{SocketLoop, &socket}; |
| 397 | const bool result = success_event.WaitFor(std::chrono::seconds(5)); | 437 | const bool result = success_event.WaitFor(std::chrono::seconds(5)); |
| 398 | socket.Stop(); | 438 | socket.Stop(); |
| @@ -406,7 +446,7 @@ void TestCommunication(const std::string& host, u16 port, std::size_t pad_index, | |||
| 406 | } | 446 | } |
| 407 | 447 | ||
| 408 | CalibrationConfigurationJob::CalibrationConfigurationJob( | 448 | CalibrationConfigurationJob::CalibrationConfigurationJob( |
| 409 | const std::string& host, u16 port, std::size_t pad_index, u32 client_id, | 449 | const std::string& host, u16 port, std::size_t pad_index, |
| 410 | std::function<void(Status)> status_callback, | 450 | std::function<void(Status)> status_callback, |
| 411 | std::function<void(u16, u16, u16, u16)> data_callback) { | 451 | std::function<void(u16, u16, u16, u16)> data_callback) { |
| 412 | 452 | ||
| @@ -426,24 +466,24 @@ CalibrationConfigurationJob::CalibrationConfigurationJob( | |||
| 426 | current_status = Status::Ready; | 466 | current_status = Status::Ready; |
| 427 | status_callback(current_status); | 467 | status_callback(current_status); |
| 428 | } | 468 | } |
| 429 | if (data.touch_1.is_active == 0) { | 469 | if (data.touch[0].is_active == 0) { |
| 430 | return; | 470 | return; |
| 431 | } | 471 | } |
| 432 | LOG_DEBUG(Input, "Current touch: {} {}", data.touch_1.x, | 472 | LOG_DEBUG(Input, "Current touch: {} {}", data.touch[0].x, |
| 433 | data.touch_1.y); | 473 | data.touch[0].y); |
| 434 | min_x = std::min(min_x, static_cast<u16>(data.touch_1.x)); | 474 | min_x = std::min(min_x, static_cast<u16>(data.touch[0].x)); |
| 435 | min_y = std::min(min_y, static_cast<u16>(data.touch_1.y)); | 475 | min_y = std::min(min_y, static_cast<u16>(data.touch[0].y)); |
| 436 | if (current_status == Status::Ready) { | 476 | if (current_status == Status::Ready) { |
| 437 | // First touch - min data (min_x/min_y) | 477 | // First touch - min data (min_x/min_y) |
| 438 | current_status = Status::Stage1Completed; | 478 | current_status = Status::Stage1Completed; |
| 439 | status_callback(current_status); | 479 | status_callback(current_status); |
| 440 | } | 480 | } |
| 441 | if (data.touch_1.x - min_x > CALIBRATION_THRESHOLD && | 481 | if (data.touch[0].x - min_x > CALIBRATION_THRESHOLD && |
| 442 | data.touch_1.y - min_y > CALIBRATION_THRESHOLD) { | 482 | data.touch[0].y - min_y > CALIBRATION_THRESHOLD) { |
| 443 | // Set the current position as max value and finishes | 483 | // Set the current position as max value and finishes |
| 444 | // configuration | 484 | // configuration |
| 445 | max_x = data.touch_1.x; | 485 | max_x = data.touch[0].x; |
| 446 | max_y = data.touch_1.y; | 486 | max_y = data.touch[0].y; |
| 447 | current_status = Status::Completed; | 487 | current_status = Status::Completed; |
| 448 | data_callback(min_x, min_y, max_x, max_y); | 488 | data_callback(min_x, min_y, max_x, max_y); |
| 449 | status_callback(current_status); | 489 | status_callback(current_status); |
| @@ -451,7 +491,7 @@ CalibrationConfigurationJob::CalibrationConfigurationJob( | |||
| 451 | complete_event.Set(); | 491 | complete_event.Set(); |
| 452 | } | 492 | } |
| 453 | }}; | 493 | }}; |
| 454 | Socket socket{host, port, pad_index, client_id, std::move(callback)}; | 494 | Socket socket{host, port, pad_index, std::move(callback)}; |
| 455 | std::thread worker_thread{SocketLoop, &socket}; | 495 | std::thread worker_thread{SocketLoop, &socket}; |
| 456 | complete_event.Wait(); | 496 | complete_event.Wait(); |
| 457 | socket.Stop(); | 497 | socket.Stop(); |
diff --git a/src/input_common/udp/client.h b/src/input_common/udp/client.h index 00c8b09f5..e9e438e88 100644 --- a/src/input_common/udp/client.h +++ b/src/input_common/udp/client.h | |||
| @@ -28,6 +28,7 @@ class Socket; | |||
| 28 | namespace Response { | 28 | namespace Response { |
| 29 | struct PadData; | 29 | struct PadData; |
| 30 | struct PortInfo; | 30 | struct PortInfo; |
| 31 | struct TouchPad; | ||
| 31 | struct Version; | 32 | struct Version; |
| 32 | } // namespace Response | 33 | } // namespace Response |
| 33 | 34 | ||
| @@ -50,7 +51,6 @@ struct UDPPadStatus { | |||
| 50 | std::string host{"127.0.0.1"}; | 51 | std::string host{"127.0.0.1"}; |
| 51 | u16 port{26760}; | 52 | u16 port{26760}; |
| 52 | std::size_t pad_index{}; | 53 | std::size_t pad_index{}; |
| 53 | PadTouch touch{PadTouch::Undefined}; | ||
| 54 | PadMotion motion{PadMotion::Undefined}; | 54 | PadMotion motion{PadMotion::Undefined}; |
| 55 | f32 motion_value{0.0f}; | 55 | f32 motion_value{0.0f}; |
| 56 | }; | 56 | }; |
| @@ -93,8 +93,14 @@ public: | |||
| 93 | DeviceStatus& GetPadState(const std::string& host, u16 port, std::size_t pad); | 93 | DeviceStatus& GetPadState(const std::string& host, u16 port, std::size_t pad); |
| 94 | const DeviceStatus& GetPadState(const std::string& host, u16 port, std::size_t pad) const; | 94 | const DeviceStatus& GetPadState(const std::string& host, u16 port, std::size_t pad) const; |
| 95 | 95 | ||
| 96 | Input::TouchStatus& GetTouchState(); | ||
| 97 | const Input::TouchStatus& GetTouchState() const; | ||
| 98 | |||
| 96 | private: | 99 | private: |
| 97 | struct ClientData { | 100 | struct ClientData { |
| 101 | ClientData(); | ||
| 102 | ~ClientData(); | ||
| 103 | |||
| 98 | std::string host{"127.0.0.1"}; | 104 | std::string host{"127.0.0.1"}; |
| 99 | u16 port{26760}; | 105 | u16 port{26760}; |
| 100 | std::size_t pad_index{}; | 106 | std::size_t pad_index{}; |
| @@ -120,16 +126,27 @@ private: | |||
| 120 | void OnPortInfo(Response::PortInfo); | 126 | void OnPortInfo(Response::PortInfo); |
| 121 | void OnPadData(Response::PadData, std::size_t client); | 127 | void OnPadData(Response::PadData, std::size_t client); |
| 122 | void StartCommunication(std::size_t client, const std::string& host, u16 port, | 128 | void StartCommunication(std::size_t client, const std::string& host, u16 port, |
| 123 | std::size_t pad_index, u32 client_id); | 129 | std::size_t pad_index); |
| 124 | void UpdateYuzuSettings(std::size_t client, const Common::Vec3<float>& acc, | 130 | void UpdateYuzuSettings(std::size_t client, const Common::Vec3<float>& acc, |
| 125 | const Common::Vec3<float>& gyro, bool touch); | 131 | const Common::Vec3<float>& gyro); |
| 132 | |||
| 133 | // Returns an unused finger id, if there is no fingers available std::nullopt will be | ||
| 134 | // returned | ||
| 135 | std::optional<std::size_t> GetUnusedFingerID() const; | ||
| 136 | |||
| 137 | // Merges and updates all touch inputs into the touch_status array | ||
| 138 | void UpdateTouchInput(Response::TouchPad& touch_pad, std::size_t client, std::size_t id); | ||
| 126 | 139 | ||
| 127 | bool configuring = false; | 140 | bool configuring = false; |
| 128 | 141 | ||
| 129 | // Allocate clients for 8 udp servers | 142 | // Allocate clients for 8 udp servers |
| 130 | const std::size_t max_udp_clients = 32; | 143 | static constexpr std::size_t MAX_UDP_CLIENTS = 4 * 8; |
| 131 | std::array<ClientData, 4 * 8> clients; | 144 | // Each client can have up 2 touch inputs |
| 132 | Common::SPSCQueue<UDPPadStatus> pad_queue; | 145 | static constexpr std::size_t MAX_TOUCH_FINGERS = MAX_UDP_CLIENTS * 2; |
| 146 | std::array<ClientData, MAX_UDP_CLIENTS> clients{}; | ||
| 147 | Common::SPSCQueue<UDPPadStatus> pad_queue{}; | ||
| 148 | Input::TouchStatus touch_status{}; | ||
| 149 | std::array<std::size_t, MAX_TOUCH_FINGERS> finger_id{}; | ||
| 133 | }; | 150 | }; |
| 134 | 151 | ||
| 135 | /// An async job allowing configuration of the touchpad calibration. | 152 | /// An async job allowing configuration of the touchpad calibration. |
| @@ -148,7 +165,7 @@ public: | |||
| 148 | * @param data_callback Called when calibration data is ready | 165 | * @param data_callback Called when calibration data is ready |
| 149 | */ | 166 | */ |
| 150 | explicit CalibrationConfigurationJob(const std::string& host, u16 port, std::size_t pad_index, | 167 | explicit CalibrationConfigurationJob(const std::string& host, u16 port, std::size_t pad_index, |
| 151 | u32 client_id, std::function<void(Status)> status_callback, | 168 | std::function<void(Status)> status_callback, |
| 152 | std::function<void(u16, u16, u16, u16)> data_callback); | 169 | std::function<void(u16, u16, u16, u16)> data_callback); |
| 153 | ~CalibrationConfigurationJob(); | 170 | ~CalibrationConfigurationJob(); |
| 154 | void Stop(); | 171 | void Stop(); |
| @@ -157,7 +174,7 @@ private: | |||
| 157 | Common::Event complete_event; | 174 | Common::Event complete_event; |
| 158 | }; | 175 | }; |
| 159 | 176 | ||
| 160 | void TestCommunication(const std::string& host, u16 port, std::size_t pad_index, u32 client_id, | 177 | void TestCommunication(const std::string& host, u16 port, std::size_t pad_index, |
| 161 | const std::function<void()>& success_callback, | 178 | const std::function<void()>& success_callback, |
| 162 | const std::function<void()>& failure_callback); | 179 | const std::function<void()>& failure_callback); |
| 163 | 180 | ||
diff --git a/src/input_common/udp/protocol.h b/src/input_common/udp/protocol.h index fc1aea4b9..a3d276697 100644 --- a/src/input_common/udp/protocol.h +++ b/src/input_common/udp/protocol.h | |||
| @@ -140,6 +140,14 @@ static_assert(sizeof(PortInfo) == 12, "UDP Response PortInfo struct has wrong si | |||
| 140 | static_assert(std::is_trivially_copyable_v<PortInfo>, | 140 | static_assert(std::is_trivially_copyable_v<PortInfo>, |
| 141 | "UDP Response PortInfo is not trivially copyable"); | 141 | "UDP Response PortInfo is not trivially copyable"); |
| 142 | 142 | ||
| 143 | struct TouchPad { | ||
| 144 | u8 is_active{}; | ||
| 145 | u8 id{}; | ||
| 146 | u16_le x{}; | ||
| 147 | u16_le y{}; | ||
| 148 | }; | ||
| 149 | static_assert(sizeof(TouchPad) == 6, "UDP Response TouchPad struct has wrong size "); | ||
| 150 | |||
| 143 | #pragma pack(push, 1) | 151 | #pragma pack(push, 1) |
| 144 | struct PadData { | 152 | struct PadData { |
| 145 | PortInfo info{}; | 153 | PortInfo info{}; |
| @@ -190,12 +198,7 @@ struct PadData { | |||
| 190 | u8 button_13{}; | 198 | u8 button_13{}; |
| 191 | } analog_button; | 199 | } analog_button; |
| 192 | 200 | ||
| 193 | struct TouchPad { | 201 | std::array<TouchPad, 2> touch; |
| 194 | u8 is_active{}; | ||
| 195 | u8 id{}; | ||
| 196 | u16_le x{}; | ||
| 197 | u16_le y{}; | ||
| 198 | } touch_1, touch_2; | ||
| 199 | 202 | ||
| 200 | u64_le motion_timestamp; | 203 | u64_le motion_timestamp; |
| 201 | 204 | ||
| @@ -222,7 +225,6 @@ static_assert(sizeof(Message<PadData>) == MAX_PACKET_SIZE, | |||
| 222 | 225 | ||
| 223 | static_assert(sizeof(PadData::AnalogButton) == 12, | 226 | static_assert(sizeof(PadData::AnalogButton) == 12, |
| 224 | "UDP Response AnalogButton struct has wrong size "); | 227 | "UDP Response AnalogButton struct has wrong size "); |
| 225 | static_assert(sizeof(PadData::TouchPad) == 6, "UDP Response TouchPad struct has wrong size "); | ||
| 226 | static_assert(sizeof(PadData::Accelerometer) == 12, | 228 | static_assert(sizeof(PadData::Accelerometer) == 12, |
| 227 | "UDP Response Accelerometer struct has wrong size "); | 229 | "UDP Response Accelerometer struct has wrong size "); |
| 228 | static_assert(sizeof(PadData::Gyroscope) == 12, "UDP Response Gyroscope struct has wrong size "); | 230 | static_assert(sizeof(PadData::Gyroscope) == 12, "UDP Response Gyroscope struct has wrong size "); |
diff --git a/src/input_common/udp/udp.cpp b/src/input_common/udp/udp.cpp index c5da27a38..9829da6f0 100644 --- a/src/input_common/udp/udp.cpp +++ b/src/input_common/udp/udp.cpp | |||
| @@ -78,14 +78,14 @@ public: | |||
| 78 | explicit UDPTouch(std::string ip_, u16 port_, u16 pad_, CemuhookUDP::Client* client_) | 78 | explicit UDPTouch(std::string ip_, u16 port_, u16 pad_, CemuhookUDP::Client* client_) |
| 79 | : ip(std::move(ip_)), port(port_), pad(pad_), client(client_) {} | 79 | : ip(std::move(ip_)), port(port_), pad(pad_), client(client_) {} |
| 80 | 80 | ||
| 81 | std::tuple<float, float, bool> GetStatus() const override { | 81 | Input::TouchStatus GetStatus() const override { |
| 82 | return client->GetPadState(ip, port, pad).touch_status; | 82 | return client->GetTouchState(); |
| 83 | } | 83 | } |
| 84 | 84 | ||
| 85 | private: | 85 | private: |
| 86 | const std::string ip; | 86 | const std::string ip; |
| 87 | const u16 port; | 87 | [[maybe_unused]] const u16 port; |
| 88 | const u16 pad; | 88 | [[maybe_unused]] const u16 pad; |
| 89 | CemuhookUDP::Client* client; | 89 | CemuhookUDP::Client* client; |
| 90 | mutable std::mutex mutex; | 90 | mutable std::mutex mutex; |
| 91 | }; | 91 | }; |
| @@ -107,32 +107,4 @@ std::unique_ptr<Input::TouchDevice> UDPTouchFactory::Create(const Common::ParamP | |||
| 107 | return std::make_unique<UDPTouch>(std::move(ip), port, pad, client.get()); | 107 | return std::make_unique<UDPTouch>(std::move(ip), port, pad, client.get()); |
| 108 | } | 108 | } |
| 109 | 109 | ||
| 110 | void UDPTouchFactory::BeginConfiguration() { | ||
| 111 | polling = true; | ||
| 112 | client->BeginConfiguration(); | ||
| 113 | } | ||
| 114 | |||
| 115 | void UDPTouchFactory::EndConfiguration() { | ||
| 116 | polling = false; | ||
| 117 | client->EndConfiguration(); | ||
| 118 | } | ||
| 119 | |||
| 120 | Common::ParamPackage UDPTouchFactory::GetNextInput() { | ||
| 121 | Common::ParamPackage params; | ||
| 122 | CemuhookUDP::UDPPadStatus pad; | ||
| 123 | auto& queue = client->GetPadQueue(); | ||
| 124 | while (queue.Pop(pad)) { | ||
| 125 | if (pad.touch == CemuhookUDP::PadTouch::Undefined) { | ||
| 126 | continue; | ||
| 127 | } | ||
| 128 | params.Set("engine", "cemuhookudp"); | ||
| 129 | params.Set("ip", pad.host); | ||
| 130 | params.Set("port", static_cast<u16>(pad.port)); | ||
| 131 | params.Set("pad_index", static_cast<u16>(pad.pad_index)); | ||
| 132 | params.Set("touch", static_cast<u16>(pad.touch)); | ||
| 133 | return params; | ||
| 134 | } | ||
| 135 | return params; | ||
| 136 | } | ||
| 137 | |||
| 138 | } // namespace InputCommon | 110 | } // namespace InputCommon |