diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/frontend/emu_window.cpp | 8 | ||||
| -rw-r--r-- | src/core/frontend/input.h | 7 | ||||
| -rw-r--r-- | src/core/hle/service/hid/controllers/touchscreen.cpp | 114 | ||||
| -rw-r--r-- | src/core/hle/service/hid/controllers/touchscreen.h | 16 | ||||
| -rw-r--r-- | src/input_common/touch_from_button.cpp | 15 | ||||
| -rw-r--r-- | src/input_common/udp/client.cpp | 121 | ||||
| -rw-r--r-- | src/input_common/udp/client.h | 24 | ||||
| -rw-r--r-- | src/input_common/udp/protocol.h | 16 | ||||
| -rw-r--r-- | src/input_common/udp/udp.cpp | 32 | ||||
| -rw-r--r-- | src/yuzu/configuration/config.cpp | 3 |
10 files changed, 202 insertions, 154 deletions
diff --git a/src/core/frontend/emu_window.cpp b/src/core/frontend/emu_window.cpp index 8c1193894..589842917 100644 --- a/src/core/frontend/emu_window.cpp +++ b/src/core/frontend/emu_window.cpp | |||
| @@ -30,12 +30,14 @@ private: | |||
| 30 | class Device : public Input::TouchDevice { | 30 | class Device : public Input::TouchDevice { |
| 31 | public: | 31 | public: |
| 32 | explicit Device(std::weak_ptr<TouchState>&& touch_state) : touch_state(touch_state) {} | 32 | explicit Device(std::weak_ptr<TouchState>&& touch_state) : touch_state(touch_state) {} |
| 33 | std::tuple<float, float, bool> GetStatus() const override { | 33 | Input::TouchStatus GetStatus() const override { |
| 34 | Input::TouchStatus touch_status = {}; | ||
| 34 | if (auto state = touch_state.lock()) { | 35 | if (auto state = touch_state.lock()) { |
| 35 | std::lock_guard guard{state->mutex}; | 36 | std::lock_guard guard{state->mutex}; |
| 36 | return std::make_tuple(state->touch_x, state->touch_y, state->touch_pressed); | 37 | touch_status[0] = |
| 38 | std::make_tuple(state->touch_x, state->touch_y, state->touch_pressed); | ||
| 37 | } | 39 | } |
| 38 | return std::make_tuple(0.0f, 0.0f, false); | 40 | return touch_status; |
| 39 | } | 41 | } |
| 40 | 42 | ||
| 41 | private: | 43 | private: |
diff --git a/src/core/frontend/input.h b/src/core/frontend/input.h index de51a754e..f014dfea3 100644 --- a/src/core/frontend/input.h +++ b/src/core/frontend/input.h | |||
| @@ -163,10 +163,11 @@ using MotionStatus = std::tuple<Common::Vec3<float>, Common::Vec3<float>, Common | |||
| 163 | using MotionDevice = InputDevice<MotionStatus>; | 163 | using MotionDevice = InputDevice<MotionStatus>; |
| 164 | 164 | ||
| 165 | /** | 165 | /** |
| 166 | * A touch status is an object that returns a tuple of two floats and a bool. The floats are | 166 | * A touch status is an object that returns an array of 16 tuple elements of two floats and a bool. |
| 167 | * x and y coordinates in the range 0.0 - 1.0, and the bool indicates whether it is pressed. | 167 | * The floats are x and y coordinates in the range 0.0 - 1.0, and the bool indicates whether it is |
| 168 | * pressed. | ||
| 168 | */ | 169 | */ |
| 169 | using TouchStatus = std::tuple<float, float, bool>; | 170 | using TouchStatus = std::array<std::tuple<float, float, bool>, 16>; |
| 170 | 171 | ||
| 171 | /** | 172 | /** |
| 172 | * A touch device is an input device that returns a touch status object | 173 | * A touch device is an input device that returns a touch status object |
diff --git a/src/core/hle/service/hid/controllers/touchscreen.cpp b/src/core/hle/service/hid/controllers/touchscreen.cpp index 13f75b48a..dc0d2c712 100644 --- a/src/core/hle/service/hid/controllers/touchscreen.cpp +++ b/src/core/hle/service/hid/controllers/touchscreen.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 <algorithm> | ||
| 5 | #include <cstring> | 6 | #include <cstring> |
| 6 | #include "common/common_types.h" | 7 | #include "common/common_types.h" |
| 7 | #include "core/core_timing.h" | 8 | #include "core/core_timing.h" |
| @@ -16,7 +17,13 @@ constexpr std::size_t SHARED_MEMORY_OFFSET = 0x400; | |||
| 16 | Controller_Touchscreen::Controller_Touchscreen(Core::System& system) : ControllerBase(system) {} | 17 | Controller_Touchscreen::Controller_Touchscreen(Core::System& system) : ControllerBase(system) {} |
| 17 | Controller_Touchscreen::~Controller_Touchscreen() = default; | 18 | Controller_Touchscreen::~Controller_Touchscreen() = default; |
| 18 | 19 | ||
| 19 | void Controller_Touchscreen::OnInit() {} | 20 | void Controller_Touchscreen::OnInit() { |
| 21 | for (size_t id = 0; id < MAX_FINGERS; id++) { | ||
| 22 | mouse_finger_id[id] = MAX_FINGERS; | ||
| 23 | keyboard_finger_id[id] = MAX_FINGERS; | ||
| 24 | udp_finger_id[id] = MAX_FINGERS; | ||
| 25 | } | ||
| 26 | } | ||
| 20 | 27 | ||
| 21 | void Controller_Touchscreen::OnRelease() {} | 28 | void Controller_Touchscreen::OnRelease() {} |
| 22 | 29 | ||
| @@ -40,32 +47,35 @@ void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timin | |||
| 40 | cur_entry.sampling_number = last_entry.sampling_number + 1; | 47 | cur_entry.sampling_number = last_entry.sampling_number + 1; |
| 41 | cur_entry.sampling_number2 = cur_entry.sampling_number; | 48 | cur_entry.sampling_number2 = cur_entry.sampling_number; |
| 42 | 49 | ||
| 43 | updateTouchInputEvent(touch_mouse_device->GetStatus(), mouse_finger_id); | 50 | const Input::TouchStatus& mouse_status = touch_mouse_device->GetStatus(); |
| 44 | updateTouchInputEvent(touch_btn_device->GetStatus(), keyboard_finger_id); | 51 | const Input::TouchStatus& keyboard_status = touch_btn_device->GetStatus(); |
| 45 | updateTouchInputEvent(touch_udp_device->GetStatus(), udp_finger_id); | 52 | const Input::TouchStatus& udp_status = touch_udp_device->GetStatus(); |
| 46 | 53 | for (size_t id = 0; id < mouse_status.size(); id++) { | |
| 47 | std::array<Finger, 16> sorted_fingers; | 54 | mouse_finger_id[id] = UpdateTouchInputEvent(mouse_status[id], mouse_finger_id[id]); |
| 48 | size_t active_fingers = 0; | 55 | keyboard_finger_id[id] = UpdateTouchInputEvent(keyboard_status[id], keyboard_finger_id[id]); |
| 49 | for (Finger finger : fingers) { | 56 | udp_finger_id[id] = UpdateTouchInputEvent(udp_status[id], udp_finger_id[id]); |
| 50 | if (finger.pressed) { | ||
| 51 | sorted_fingers[active_fingers++] = finger; | ||
| 52 | } | ||
| 53 | } | 57 | } |
| 54 | 58 | ||
| 59 | std::array<Finger, 16> active_fingers; | ||
| 60 | const auto end_iter = std::copy_if(fingers.begin(), fingers.end(), active_fingers.begin(), | ||
| 61 | [](const auto& finger) { return finger.pressed; }); | ||
| 62 | const auto active_fingers_count = | ||
| 63 | static_cast<size_t>(std::distance(active_fingers.begin(), end_iter)); | ||
| 64 | |||
| 55 | const u64 tick = core_timing.GetCPUTicks(); | 65 | const u64 tick = core_timing.GetCPUTicks(); |
| 56 | cur_entry.entry_count = static_cast<s32_le>(active_fingers); | 66 | cur_entry.entry_count = static_cast<s32_le>(active_fingers_count); |
| 57 | for (size_t id = 0; id < MAX_FINGERS; id++) { | 67 | for (size_t id = 0; id < MAX_FINGERS; id++) { |
| 58 | auto& touch_entry = cur_entry.states[id]; | 68 | auto& touch_entry = cur_entry.states[id]; |
| 59 | if (id < active_fingers) { | 69 | if (id < active_fingers_count) { |
| 60 | touch_entry.x = static_cast<u16>(sorted_fingers[id].x * Layout::ScreenUndocked::Width); | 70 | touch_entry.x = static_cast<u16>(active_fingers[id].x * Layout::ScreenUndocked::Width); |
| 61 | touch_entry.y = static_cast<u16>(sorted_fingers[id].y * Layout::ScreenUndocked::Height); | 71 | touch_entry.y = static_cast<u16>(active_fingers[id].y * Layout::ScreenUndocked::Height); |
| 62 | touch_entry.diameter_x = Settings::values.touchscreen.diameter_x; | 72 | touch_entry.diameter_x = Settings::values.touchscreen.diameter_x; |
| 63 | touch_entry.diameter_y = Settings::values.touchscreen.diameter_y; | 73 | touch_entry.diameter_y = Settings::values.touchscreen.diameter_y; |
| 64 | touch_entry.rotation_angle = Settings::values.touchscreen.rotation_angle; | 74 | touch_entry.rotation_angle = Settings::values.touchscreen.rotation_angle; |
| 65 | touch_entry.delta_time = tick - sorted_fingers[id].last_touch; | 75 | touch_entry.delta_time = tick - active_fingers[id].last_touch; |
| 66 | sorted_fingers[id].last_touch = tick; | 76 | active_fingers[id].last_touch = tick; |
| 67 | touch_entry.finger = sorted_fingers[id].id; | 77 | touch_entry.finger = active_fingers[id].id; |
| 68 | touch_entry.attribute.raw = sorted_fingers[id].attribute.raw; | 78 | touch_entry.attribute.raw = active_fingers[id].attribute.raw; |
| 69 | } else { | 79 | } else { |
| 70 | // Clear touch entry | 80 | // Clear touch entry |
| 71 | touch_entry.attribute.raw = 0; | 81 | touch_entry.attribute.raw = 0; |
| @@ -91,44 +101,50 @@ void Controller_Touchscreen::OnLoadInputDevices() { | |||
| 91 | } | 101 | } |
| 92 | } | 102 | } |
| 93 | 103 | ||
| 94 | void Controller_Touchscreen::updateTouchInputEvent( | 104 | std::optional<size_t> Controller_Touchscreen::GetUnusedFingerID() const { |
| 95 | const std::tuple<float, float, bool>& touch_input, size_t& finger_id) { | 105 | size_t first_free_id = 0; |
| 96 | bool pressed = false; | 106 | while (first_free_id < MAX_FINGERS) { |
| 97 | float x, y; | 107 | if (!fingers[first_free_id].pressed) { |
| 98 | std::tie(x, y, pressed) = touch_input; | 108 | return first_free_id; |
| 109 | } else { | ||
| 110 | first_free_id++; | ||
| 111 | } | ||
| 112 | } | ||
| 113 | return std::nullopt; | ||
| 114 | } | ||
| 115 | |||
| 116 | size_t Controller_Touchscreen::UpdateTouchInputEvent( | ||
| 117 | const std::tuple<float, float, bool>& touch_input, size_t finger_id) { | ||
| 118 | const auto& [x, y, pressed] = touch_input; | ||
| 99 | if (pressed) { | 119 | if (pressed) { |
| 100 | if (finger_id == -1) { | 120 | Attributes attribute = {}; |
| 101 | int first_free_id = 0; | 121 | if (finger_id == MAX_FINGERS) { |
| 102 | int found = false; | 122 | const auto first_free_id = GetUnusedFingerID(); |
| 103 | while (!found && first_free_id < MAX_FINGERS) { | 123 | if (!first_free_id) { |
| 104 | if (!fingers[first_free_id].pressed) { | 124 | // Invalid finger id do nothing |
| 105 | found = true; | 125 | return MAX_FINGERS; |
| 106 | } else { | ||
| 107 | first_free_id++; | ||
| 108 | } | ||
| 109 | } | 126 | } |
| 110 | if (found) { | 127 | finger_id = first_free_id.value(); |
| 111 | finger_id = first_free_id; | 128 | fingers[finger_id].pressed = true; |
| 112 | fingers[finger_id].x = x; | 129 | fingers[finger_id].id = static_cast<u32_le>(finger_id); |
| 113 | fingers[finger_id].y = y; | 130 | attribute.start_touch.Assign(1); |
| 114 | fingers[finger_id].pressed = true; | ||
| 115 | fingers[finger_id].id = static_cast<u32_le>(finger_id); | ||
| 116 | fingers[finger_id].attribute.start_touch.Assign(1); | ||
| 117 | } | ||
| 118 | } else { | ||
| 119 | fingers[finger_id].x = x; | ||
| 120 | fingers[finger_id].y = y; | ||
| 121 | fingers[finger_id].attribute.raw = 0; | ||
| 122 | } | 131 | } |
| 123 | } else if (finger_id != -1) { | 132 | fingers[finger_id].x = x; |
| 133 | fingers[finger_id].y = y; | ||
| 134 | fingers[finger_id].attribute = attribute; | ||
| 135 | return finger_id; | ||
| 136 | } | ||
| 137 | |||
| 138 | if (finger_id != MAX_FINGERS) { | ||
| 124 | if (!fingers[finger_id].attribute.end_touch) { | 139 | if (!fingers[finger_id].attribute.end_touch) { |
| 125 | fingers[finger_id].attribute.end_touch.Assign(1); | 140 | fingers[finger_id].attribute.end_touch.Assign(1); |
| 126 | fingers[finger_id].attribute.start_touch.Assign(0); | 141 | fingers[finger_id].attribute.start_touch.Assign(0); |
| 127 | } else { | 142 | return finger_id; |
| 128 | fingers[finger_id].pressed = false; | ||
| 129 | finger_id = -1; | ||
| 130 | } | 143 | } |
| 144 | fingers[finger_id].pressed = false; | ||
| 131 | } | 145 | } |
| 146 | |||
| 147 | return MAX_FINGERS; | ||
| 132 | } | 148 | } |
| 133 | 149 | ||
| 134 | } // namespace Service::HID | 150 | } // namespace Service::HID |
diff --git a/src/core/hle/service/hid/controllers/touchscreen.h b/src/core/hle/service/hid/controllers/touchscreen.h index 03f399344..e39ab89ee 100644 --- a/src/core/hle/service/hid/controllers/touchscreen.h +++ b/src/core/hle/service/hid/controllers/touchscreen.h | |||
| @@ -30,13 +30,17 @@ public: | |||
| 30 | void OnLoadInputDevices() override; | 30 | void OnLoadInputDevices() override; |
| 31 | 31 | ||
| 32 | private: | 32 | private: |
| 33 | static constexpr size_t MAX_FINGERS = 16; | ||
| 34 | |||
| 35 | // Returns an unused finger id, if there is no fingers available std::nullopt will be returned | ||
| 36 | std::optional<size_t> GetUnusedFingerID() const; | ||
| 37 | |||
| 33 | // If the touch is new it tries to assing a new finger id, if there is no fingers avaliable no | 38 | // If the touch is new it tries to assing a new finger id, if there is no fingers avaliable no |
| 34 | // changes will be made. Updates the coordinates if the finger id it's already set. If the touch | 39 | // changes will be made. Updates the coordinates if the finger id it's already set. If the touch |
| 35 | // ends delays the output by one frame to set the end_touch flag before finally freeing the | 40 | // ends delays the output by one frame to set the end_touch flag before finally freeing the |
| 36 | // finger id | 41 | // finger id |
| 37 | void updateTouchInputEvent(const std::tuple<float, float, bool>& touch_input, | 42 | size_t UpdateTouchInputEvent(const std::tuple<float, float, bool>& touch_input, |
| 38 | size_t& finger_id); | 43 | size_t finger_id); |
| 39 | static const size_t MAX_FINGERS = 16; | ||
| 40 | 44 | ||
| 41 | struct Attributes { | 45 | struct Attributes { |
| 42 | union { | 46 | union { |
| @@ -88,9 +92,9 @@ private: | |||
| 88 | std::unique_ptr<Input::TouchDevice> touch_mouse_device; | 92 | std::unique_ptr<Input::TouchDevice> touch_mouse_device; |
| 89 | std::unique_ptr<Input::TouchDevice> touch_udp_device; | 93 | std::unique_ptr<Input::TouchDevice> touch_udp_device; |
| 90 | std::unique_ptr<Input::TouchDevice> touch_btn_device; | 94 | std::unique_ptr<Input::TouchDevice> touch_btn_device; |
| 91 | size_t mouse_finger_id{-1}; | 95 | std::array<size_t, MAX_FINGERS> mouse_finger_id; |
| 92 | size_t keyboard_finger_id{-1}; | 96 | std::array<size_t, MAX_FINGERS> keyboard_finger_id; |
| 93 | size_t udp_finger_id{-1}; | 97 | std::array<size_t, MAX_FINGERS> udp_finger_id; |
| 94 | std::array<Finger, MAX_FINGERS> fingers; | 98 | std::array<Finger, MAX_FINGERS> fingers; |
| 95 | }; | 99 | }; |
| 96 | } // namespace Service::HID | 100 | } // namespace Service::HID |
diff --git a/src/input_common/touch_from_button.cpp b/src/input_common/touch_from_button.cpp index a07124a86..5226e70df 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 (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..53648cb53 100644 --- a/src/input_common/udp/client.cpp +++ b/src/input_common/udp/client.cpp | |||
| @@ -136,6 +136,9 @@ static void SocketLoop(Socket* socket) { | |||
| 136 | 136 | ||
| 137 | Client::Client() { | 137 | Client::Client() { |
| 138 | LOG_INFO(Input, "Udp Initialization started"); | 138 | LOG_INFO(Input, "Udp Initialization started"); |
| 139 | for (size_t id = 0; id < MAX_TOUCH_FINGERS; id++) { | ||
| 140 | finger_id[id] = MAX_UDP_CLIENTS * 2; | ||
| 141 | } | ||
| 139 | ReloadSockets(); | 142 | ReloadSockets(); |
| 140 | } | 143 | } |
| 141 | 144 | ||
| @@ -176,7 +179,7 @@ void Client::ReloadSockets() { | |||
| 176 | std::string server_token; | 179 | std::string server_token; |
| 177 | std::size_t client = 0; | 180 | std::size_t client = 0; |
| 178 | while (std::getline(servers_ss, server_token, ',')) { | 181 | while (std::getline(servers_ss, server_token, ',')) { |
| 179 | if (client == max_udp_clients) { | 182 | if (client == MAX_UDP_CLIENTS) { |
| 180 | break; | 183 | break; |
| 181 | } | 184 | } |
| 182 | std::stringstream server_ss(server_token); | 185 | std::stringstream server_ss(server_token); |
| @@ -194,7 +197,7 @@ void Client::ReloadSockets() { | |||
| 194 | for (std::size_t pad = 0; pad < 4; ++pad) { | 197 | for (std::size_t pad = 0; pad < 4; ++pad) { |
| 195 | const std::size_t client_number = | 198 | const std::size_t client_number = |
| 196 | GetClientNumber(udp_input_address, udp_input_port, pad); | 199 | GetClientNumber(udp_input_address, udp_input_port, pad); |
| 197 | if (client_number != max_udp_clients) { | 200 | if (client_number != MAX_UDP_CLIENTS) { |
| 198 | LOG_ERROR(Input, "Duplicated UDP servers found"); | 201 | LOG_ERROR(Input, "Duplicated UDP servers found"); |
| 199 | continue; | 202 | continue; |
| 200 | } | 203 | } |
| @@ -213,7 +216,7 @@ std::size_t Client::GetClientNumber(std::string_view host, u16 port, std::size_t | |||
| 213 | return client; | 216 | return client; |
| 214 | } | 217 | } |
| 215 | } | 218 | } |
| 216 | return max_udp_clients; | 219 | return MAX_UDP_CLIENTS; |
| 217 | } | 220 | } |
| 218 | 221 | ||
| 219 | void Client::OnVersion([[maybe_unused]] Response::Version data) { | 222 | void Client::OnVersion([[maybe_unused]] Response::Version data) { |
| @@ -259,33 +262,14 @@ void Client::OnPadData(Response::PadData data, std::size_t client) { | |||
| 259 | std::lock_guard guard(clients[client].status.update_mutex); | 262 | std::lock_guard guard(clients[client].status.update_mutex); |
| 260 | clients[client].status.motion_status = clients[client].motion.GetMotion(); | 263 | clients[client].status.motion_status = clients[client].motion.GetMotion(); |
| 261 | 264 | ||
| 262 | // TODO: add a setting for "click" touch. Click touch refers to a device that differentiates | 265 | for (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. | 266 | 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 | } | 267 | } |
| 282 | 268 | ||
| 283 | clients[client].status.touch_status = {x, y, is_active}; | ||
| 284 | |||
| 285 | if (configuring) { | 269 | if (configuring) { |
| 286 | const Common::Vec3f gyroscope = clients[client].motion.GetGyroscope(); | 270 | const Common::Vec3f gyroscope = clients[client].motion.GetGyroscope(); |
| 287 | const Common::Vec3f accelerometer = clients[client].motion.GetAcceleration(); | 271 | const Common::Vec3f accelerometer = clients[client].motion.GetAcceleration(); |
| 288 | UpdateYuzuSettings(client, accelerometer, gyroscope, is_active); | 272 | UpdateYuzuSettings(client, accelerometer, gyroscope); |
| 289 | } | 273 | } |
| 290 | } | 274 | } |
| 291 | } | 275 | } |
| @@ -320,20 +304,16 @@ void Client::Reset() { | |||
| 320 | } | 304 | } |
| 321 | 305 | ||
| 322 | void Client::UpdateYuzuSettings(std::size_t client, const Common::Vec3<float>& acc, | 306 | void Client::UpdateYuzuSettings(std::size_t client, const Common::Vec3<float>& acc, |
| 323 | const Common::Vec3<float>& gyro, bool touch) { | 307 | const Common::Vec3<float>& gyro) { |
| 324 | if (gyro.Length() > 0.2f) { | 308 | if (gyro.Length() > 0.2f) { |
| 325 | LOG_DEBUG(Input, "UDP Controller {}: gyro=({}, {}, {}), accel=({}, {}, {}), touch={}", | 309 | LOG_DEBUG(Input, "UDP Controller {}: gyro=({}, {}, {}), accel=({}, {}, {})", client, |
| 326 | client, gyro[0], gyro[1], gyro[2], acc[0], acc[1], acc[2], touch); | 310 | gyro[0], gyro[1], gyro[2], acc[0], acc[1], acc[2]); |
| 327 | } | 311 | } |
| 328 | UDPPadStatus pad{ | 312 | UDPPadStatus pad{ |
| 329 | .host = clients[client].host, | 313 | .host = clients[client].host, |
| 330 | .port = clients[client].port, | 314 | .port = clients[client].port, |
| 331 | .pad_index = clients[client].pad_index, | 315 | .pad_index = clients[client].pad_index, |
| 332 | }; | 316 | }; |
| 333 | if (touch) { | ||
| 334 | pad.touch = PadTouch::Click; | ||
| 335 | pad_queue.Push(pad); | ||
| 336 | } | ||
| 337 | for (size_t i = 0; i < 3; ++i) { | 317 | for (size_t i = 0; i < 3; ++i) { |
| 338 | if (gyro[i] > 5.0f || gyro[i] < -5.0f) { | 318 | if (gyro[i] > 5.0f || gyro[i] < -5.0f) { |
| 339 | pad.motion = static_cast<PadMotion>(i); | 319 | pad.motion = static_cast<PadMotion>(i); |
| @@ -348,6 +328,53 @@ void Client::UpdateYuzuSettings(std::size_t client, const Common::Vec3<float>& a | |||
| 348 | } | 328 | } |
| 349 | } | 329 | } |
| 350 | 330 | ||
| 331 | std::optional<size_t> Client::GetUnusedFingerID() const { | ||
| 332 | size_t first_free_id = 0; | ||
| 333 | while (first_free_id < MAX_TOUCH_FINGERS) { | ||
| 334 | if (!std::get<2>(touch_status[first_free_id])) { | ||
| 335 | return first_free_id; | ||
| 336 | } else { | ||
| 337 | first_free_id++; | ||
| 338 | } | ||
| 339 | } | ||
| 340 | return std::nullopt; | ||
| 341 | } | ||
| 342 | |||
| 343 | void Client::UpdateTouchInput(Response::TouchPad& touch_pad, size_t client, size_t id) { | ||
| 344 | // TODO: Use custom calibration per device | ||
| 345 | const Common::ParamPackage touch_param(Settings::values.touch_device); | ||
| 346 | const u16 min_x = static_cast<u16>(touch_param.Get("min_x", 100)); | ||
| 347 | const u16 min_y = static_cast<u16>(touch_param.Get("min_y", 50)); | ||
| 348 | const u16 max_x = static_cast<u16>(touch_param.Get("max_x", 1800)); | ||
| 349 | const u16 max_y = static_cast<u16>(touch_param.Get("max_y", 850)); | ||
| 350 | |||
| 351 | if (touch_pad.is_active) { | ||
| 352 | if (finger_id[client * 2 + id] == MAX_TOUCH_FINGERS) { | ||
| 353 | const auto first_free_id = GetUnusedFingerID(); | ||
| 354 | if (!first_free_id) { | ||
| 355 | // Invalid finger id skip to next input | ||
| 356 | return; | ||
| 357 | } | ||
| 358 | finger_id[client * 2 + id] = first_free_id.value(); | ||
| 359 | } | ||
| 360 | auto& [x, y, pressed] = touch_status[finger_id[client * 2 + id]]; | ||
| 361 | x = static_cast<float>(std::clamp(static_cast<u16>(touch_pad.x), min_x, max_x) - min_x) / | ||
| 362 | static_cast<float>(max_x - min_x); | ||
| 363 | y = static_cast<float>(std::clamp(static_cast<u16>(touch_pad.y), min_y, max_y) - min_y) / | ||
| 364 | static_cast<float>(max_y - min_y); | ||
| 365 | pressed = true; | ||
| 366 | return; | ||
| 367 | } | ||
| 368 | |||
| 369 | if (finger_id[client * 2 + id] != MAX_TOUCH_FINGERS) { | ||
| 370 | auto& [x, y, pressed] = touch_status[finger_id[client * 2 + id]]; | ||
| 371 | x = 0; | ||
| 372 | y = 0; | ||
| 373 | pressed = false; | ||
| 374 | finger_id[client * 2 + id] = MAX_TOUCH_FINGERS; | ||
| 375 | } | ||
| 376 | } | ||
| 377 | |||
| 351 | void Client::BeginConfiguration() { | 378 | void Client::BeginConfiguration() { |
| 352 | pad_queue.Clear(); | 379 | pad_queue.Clear(); |
| 353 | configuring = true; | 380 | configuring = true; |
| @@ -360,7 +387,7 @@ void Client::EndConfiguration() { | |||
| 360 | 387 | ||
| 361 | DeviceStatus& Client::GetPadState(const std::string& host, u16 port, std::size_t pad) { | 388 | DeviceStatus& Client::GetPadState(const std::string& host, u16 port, std::size_t pad) { |
| 362 | const std::size_t client_number = GetClientNumber(host, port, pad); | 389 | const std::size_t client_number = GetClientNumber(host, port, pad); |
| 363 | if (client_number == max_udp_clients) { | 390 | if (client_number == MAX_UDP_CLIENTS) { |
| 364 | return clients[0].status; | 391 | return clients[0].status; |
| 365 | } | 392 | } |
| 366 | return clients[client_number].status; | 393 | return clients[client_number].status; |
| @@ -368,12 +395,20 @@ DeviceStatus& Client::GetPadState(const std::string& host, u16 port, std::size_t | |||
| 368 | 395 | ||
| 369 | const DeviceStatus& Client::GetPadState(const std::string& host, u16 port, std::size_t pad) const { | 396 | 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); | 397 | const std::size_t client_number = GetClientNumber(host, port, pad); |
| 371 | if (client_number == max_udp_clients) { | 398 | if (client_number == MAX_UDP_CLIENTS) { |
| 372 | return clients[0].status; | 399 | return clients[0].status; |
| 373 | } | 400 | } |
| 374 | return clients[client_number].status; | 401 | return clients[client_number].status; |
| 375 | } | 402 | } |
| 376 | 403 | ||
| 404 | Input::TouchStatus& Client::GetTouchState() { | ||
| 405 | return touch_status; | ||
| 406 | } | ||
| 407 | |||
| 408 | const Input::TouchStatus& Client::GetTouchState() const { | ||
| 409 | return touch_status; | ||
| 410 | } | ||
| 411 | |||
| 377 | Common::SPSCQueue<UDPPadStatus>& Client::GetPadQueue() { | 412 | Common::SPSCQueue<UDPPadStatus>& Client::GetPadQueue() { |
| 378 | return pad_queue; | 413 | return pad_queue; |
| 379 | } | 414 | } |
| @@ -426,24 +461,24 @@ CalibrationConfigurationJob::CalibrationConfigurationJob( | |||
| 426 | current_status = Status::Ready; | 461 | current_status = Status::Ready; |
| 427 | status_callback(current_status); | 462 | status_callback(current_status); |
| 428 | } | 463 | } |
| 429 | if (data.touch_1.is_active == 0) { | 464 | if (data.touch[0].is_active == 0) { |
| 430 | return; | 465 | return; |
| 431 | } | 466 | } |
| 432 | LOG_DEBUG(Input, "Current touch: {} {}", data.touch_1.x, | 467 | LOG_DEBUG(Input, "Current touch: {} {}", data.touch[0].x, |
| 433 | data.touch_1.y); | 468 | data.touch[0].y); |
| 434 | min_x = std::min(min_x, static_cast<u16>(data.touch_1.x)); | 469 | 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)); | 470 | min_y = std::min(min_y, static_cast<u16>(data.touch[0].y)); |
| 436 | if (current_status == Status::Ready) { | 471 | if (current_status == Status::Ready) { |
| 437 | // First touch - min data (min_x/min_y) | 472 | // First touch - min data (min_x/min_y) |
| 438 | current_status = Status::Stage1Completed; | 473 | current_status = Status::Stage1Completed; |
| 439 | status_callback(current_status); | 474 | status_callback(current_status); |
| 440 | } | 475 | } |
| 441 | if (data.touch_1.x - min_x > CALIBRATION_THRESHOLD && | 476 | if (data.touch[0].x - min_x > CALIBRATION_THRESHOLD && |
| 442 | data.touch_1.y - min_y > CALIBRATION_THRESHOLD) { | 477 | data.touch[0].y - min_y > CALIBRATION_THRESHOLD) { |
| 443 | // Set the current position as max value and finishes | 478 | // Set the current position as max value and finishes |
| 444 | // configuration | 479 | // configuration |
| 445 | max_x = data.touch_1.x; | 480 | max_x = data.touch[0].x; |
| 446 | max_y = data.touch_1.y; | 481 | max_y = data.touch[0].y; |
| 447 | current_status = Status::Completed; | 482 | current_status = Status::Completed; |
| 448 | data_callback(min_x, min_y, max_x, max_y); | 483 | data_callback(min_x, min_y, max_x, max_y); |
| 449 | status_callback(current_status); | 484 | status_callback(current_status); |
diff --git a/src/input_common/udp/client.h b/src/input_common/udp/client.h index 00c8b09f5..1cd251ec8 100644 --- a/src/input_common/udp/client.h +++ b/src/input_common/udp/client.h | |||
| @@ -29,6 +29,7 @@ namespace Response { | |||
| 29 | struct PadData; | 29 | struct PadData; |
| 30 | struct PortInfo; | 30 | struct PortInfo; |
| 31 | struct Version; | 31 | struct Version; |
| 32 | struct TouchPad; | ||
| 32 | } // namespace Response | 33 | } // namespace Response |
| 33 | 34 | ||
| 34 | enum class PadMotion { | 35 | enum class PadMotion { |
| @@ -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,6 +93,9 @@ 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 { |
| 98 | std::string host{"127.0.0.1"}; | 101 | std::string host{"127.0.0.1"}; |
| @@ -122,14 +125,25 @@ private: | |||
| 122 | void StartCommunication(std::size_t client, const std::string& host, u16 port, | 125 | void StartCommunication(std::size_t client, const std::string& host, u16 port, |
| 123 | std::size_t pad_index, u32 client_id); | 126 | std::size_t pad_index, u32 client_id); |
| 124 | void UpdateYuzuSettings(std::size_t client, const Common::Vec3<float>& acc, | 127 | void UpdateYuzuSettings(std::size_t client, const Common::Vec3<float>& acc, |
| 125 | const Common::Vec3<float>& gyro, bool touch); | 128 | const Common::Vec3<float>& gyro); |
| 129 | |||
| 130 | // Returns an unused finger id, if there is no fingers available std::nullopt will be | ||
| 131 | // returned | ||
| 132 | std::optional<size_t> GetUnusedFingerID() const; | ||
| 133 | |||
| 134 | // Merges and updates all touch inputs into the touch_status array | ||
| 135 | void UpdateTouchInput(Response::TouchPad& touch_pad, size_t client, size_t id); | ||
| 126 | 136 | ||
| 127 | bool configuring = false; | 137 | bool configuring = false; |
| 128 | 138 | ||
| 129 | // Allocate clients for 8 udp servers | 139 | // Allocate clients for 8 udp servers |
| 130 | const std::size_t max_udp_clients = 32; | 140 | static constexpr std::size_t MAX_UDP_CLIENTS = 4 * 8; |
| 131 | std::array<ClientData, 4 * 8> clients; | 141 | // Each client can have up 2 touch inputs |
| 132 | Common::SPSCQueue<UDPPadStatus> pad_queue; | 142 | static constexpr std::size_t MAX_TOUCH_FINGERS = MAX_UDP_CLIENTS * 2; |
| 143 | std::array<ClientData, MAX_UDP_CLIENTS> clients{}; | ||
| 144 | Common::SPSCQueue<UDPPadStatus> pad_queue{}; | ||
| 145 | Input::TouchStatus touch_status{}; | ||
| 146 | std::array<size_t, MAX_TOUCH_FINGERS> finger_id{}; | ||
| 133 | }; | 147 | }; |
| 134 | 148 | ||
| 135 | /// An async job allowing configuration of the touchpad calibration. | 149 | /// An async job allowing configuration of the touchpad calibration. |
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..b630281a0 100644 --- a/src/input_common/udp/udp.cpp +++ b/src/input_common/udp/udp.cpp | |||
| @@ -78,8 +78,8 @@ 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: |
| @@ -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 |
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index 0ec358225..5e4d22299 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp | |||
| @@ -557,7 +557,8 @@ void Config::ReadMotionTouchValues() { | |||
| 557 | .toString() | 557 | .toString() |
| 558 | .toStdString(); | 558 | .toStdString(); |
| 559 | Settings::values.touch_device = | 559 | Settings::values.touch_device = |
| 560 | ReadSetting(QStringLiteral("touch_device"), QStringLiteral("engine:emu_window")) | 560 | ReadSetting(QStringLiteral("touch_device"), |
| 561 | QStringLiteral("min_x:100,min_y:50,max_x:1800,max_y:850")) | ||
| 561 | .toString() | 562 | .toString() |
| 562 | .toStdString(); | 563 | .toStdString(); |
| 563 | Settings::values.use_touch_from_button = | 564 | Settings::values.use_touch_from_button = |