diff options
| author | 2021-09-20 20:33:50 -0500 | |
|---|---|---|
| committer | 2021-11-24 20:30:24 -0600 | |
| commit | afe2d667d95e74be8f401010fa31a9eeca77d93a (patch) | |
| tree | c738df7b0fbfb624b450f8aa46c669a8b3107d36 /src | |
| parent | service/hid: Update debug pad, xpad, stubbed and controller base to use ring ... (diff) | |
| download | yuzu-afe2d667d95e74be8f401010fa31a9eeca77d93a.tar.gz yuzu-afe2d667d95e74be8f401010fa31a9eeca77d93a.tar.xz yuzu-afe2d667d95e74be8f401010fa31a9eeca77d93a.zip | |
service/hid: Update touch and gestures to use ring lifo and the emulated console
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/hle/service/hid/controllers/gesture.cpp | 274 | ||||
| -rw-r--r-- | src/core/hle/service/hid/controllers/gesture.h | 80 | ||||
| -rw-r--r-- | src/core/hle/service/hid/controllers/touchscreen.cpp | 136 | ||||
| -rw-r--r-- | src/core/hle/service/hid/controllers/touchscreen.h | 71 |
4 files changed, 191 insertions, 370 deletions
diff --git a/src/core/hle/service/hid/controllers/gesture.cpp b/src/core/hle/service/hid/controllers/gesture.cpp index 764abb5b6..2f98cc54b 100644 --- a/src/core/hle/service/hid/controllers/gesture.cpp +++ b/src/core/hle/service/hid/controllers/gesture.cpp | |||
| @@ -5,8 +5,10 @@ | |||
| 5 | #include "common/logging/log.h" | 5 | #include "common/logging/log.h" |
| 6 | #include "common/math_util.h" | 6 | #include "common/math_util.h" |
| 7 | #include "common/settings.h" | 7 | #include "common/settings.h" |
| 8 | #include "core/core.h" | ||
| 8 | #include "core/core_timing.h" | 9 | #include "core/core_timing.h" |
| 9 | #include "core/frontend/emu_window.h" | 10 | #include "core/frontend/emu_window.h" |
| 11 | #include "core/hid/hid_core.h" | ||
| 10 | #include "core/hle/service/hid/controllers/gesture.h" | 12 | #include "core/hle/service/hid/controllers/gesture.h" |
| 11 | 13 | ||
| 12 | namespace Service::HID { | 14 | namespace Service::HID { |
| @@ -23,16 +25,15 @@ constexpr f32 Square(s32 num) { | |||
| 23 | return static_cast<f32>(num * num); | 25 | return static_cast<f32>(num * num); |
| 24 | } | 26 | } |
| 25 | 27 | ||
| 26 | Controller_Gesture::Controller_Gesture(Core::System& system_) : ControllerBase(system_) {} | 28 | Controller_Gesture::Controller_Gesture(Core::System& system_) : ControllerBase(system_) { |
| 29 | console = system.HIDCore().GetEmulatedConsole(); | ||
| 30 | } | ||
| 31 | |||
| 27 | Controller_Gesture::~Controller_Gesture() = default; | 32 | Controller_Gesture::~Controller_Gesture() = default; |
| 28 | 33 | ||
| 29 | void Controller_Gesture::OnInit() { | 34 | void Controller_Gesture::OnInit() { |
| 30 | for (std::size_t id = 0; id < MAX_FINGERS; ++id) { | 35 | gesture_lifo.entry_count = 0; |
| 31 | mouse_finger_id[id] = MAX_POINTS; | 36 | gesture_lifo.last_entry_index = 0; |
| 32 | keyboard_finger_id[id] = MAX_POINTS; | ||
| 33 | udp_finger_id[id] = MAX_POINTS; | ||
| 34 | } | ||
| 35 | shared_memory.header.entry_count = 0; | ||
| 36 | force_update = true; | 37 | force_update = true; |
| 37 | } | 38 | } |
| 38 | 39 | ||
| @@ -40,50 +41,43 @@ void Controller_Gesture::OnRelease() {} | |||
| 40 | 41 | ||
| 41 | void Controller_Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, | 42 | void Controller_Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, |
| 42 | std::size_t size) { | 43 | std::size_t size) { |
| 43 | shared_memory.header.timestamp = core_timing.GetCPUTicks(); | 44 | // TODO FIND WTF IS WRONG HERE!!!!!!!! |
| 44 | shared_memory.header.total_entry_count = 17; | 45 | return; |
| 45 | |||
| 46 | if (!IsControllerActivated()) { | 46 | if (!IsControllerActivated()) { |
| 47 | shared_memory.header.entry_count = 0; | 47 | gesture_lifo.entry_count = 0; |
| 48 | shared_memory.header.last_entry_index = 0; | 48 | gesture_lifo.last_entry_index = 0; |
| 49 | std::memcpy(data, &gesture_lifo, sizeof(gesture_lifo)); | ||
| 49 | return; | 50 | return; |
| 50 | } | 51 | } |
| 51 | 52 | ||
| 52 | ReadTouchInput(); | 53 | ReadTouchInput(); |
| 53 | 54 | ||
| 54 | GestureProperties gesture = GetGestureProperties(); | 55 | GestureProperties gesture = GetGestureProperties(); |
| 55 | f32 time_difference = static_cast<f32>(shared_memory.header.timestamp - last_update_timestamp) / | 56 | f32 time_difference = |
| 56 | (1000 * 1000 * 1000); | 57 | static_cast<f32>(gesture_lifo.timestamp - last_update_timestamp) / (1000 * 1000 * 1000); |
| 57 | 58 | ||
| 58 | // Only update if necesary | 59 | // Only update if necesary |
| 59 | if (!ShouldUpdateGesture(gesture, time_difference)) { | 60 | if (!ShouldUpdateGesture(gesture, time_difference)) { |
| 60 | return; | 61 | return; |
| 61 | } | 62 | } |
| 62 | 63 | ||
| 63 | last_update_timestamp = shared_memory.header.timestamp; | 64 | last_update_timestamp = gesture_lifo.timestamp; |
| 64 | UpdateGestureSharedMemory(data, size, gesture, time_difference); | 65 | UpdateGestureSharedMemory(data, size, gesture, time_difference); |
| 65 | } | 66 | } |
| 66 | 67 | ||
| 67 | void Controller_Gesture::ReadTouchInput() { | 68 | void Controller_Gesture::ReadTouchInput() { |
| 68 | const Input::TouchStatus& mouse_status = touch_mouse_device->GetStatus(); | 69 | const auto touch_status = console->GetTouch(); |
| 69 | const Input::TouchStatus& udp_status = touch_udp_device->GetStatus(); | 70 | for (std::size_t id = 0; id < fingers.size(); ++id) { |
| 70 | for (std::size_t id = 0; id < mouse_status.size(); ++id) { | 71 | const Core::HID::TouchFinger& status = touch_status[id]; |
| 71 | mouse_finger_id[id] = UpdateTouchInputEvent(mouse_status[id], mouse_finger_id[id]); | 72 | Finger& finger = fingers[id]; |
| 72 | udp_finger_id[id] = UpdateTouchInputEvent(udp_status[id], udp_finger_id[id]); | 73 | finger.pos = status.position; |
| 73 | } | 74 | finger.pressed = status.pressed; |
| 74 | |||
| 75 | if (Settings::values.use_touch_from_button) { | ||
| 76 | const Input::TouchStatus& keyboard_status = touch_btn_device->GetStatus(); | ||
| 77 | for (std::size_t id = 0; id < mouse_status.size(); ++id) { | ||
| 78 | keyboard_finger_id[id] = | ||
| 79 | UpdateTouchInputEvent(keyboard_status[id], keyboard_finger_id[id]); | ||
| 80 | } | ||
| 81 | } | 75 | } |
| 82 | } | 76 | } |
| 83 | 77 | ||
| 84 | bool Controller_Gesture::ShouldUpdateGesture(const GestureProperties& gesture, | 78 | bool Controller_Gesture::ShouldUpdateGesture(const GestureProperties& gesture, |
| 85 | f32 time_difference) { | 79 | f32 time_difference) { |
| 86 | const auto& last_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; | 80 | const auto& last_entry = gesture_lifo.ReadCurrentEntry().state; |
| 87 | if (force_update) { | 81 | if (force_update) { |
| 88 | force_update = false; | 82 | force_update = false; |
| 89 | return true; | 83 | return true; |
| @@ -97,7 +91,7 @@ bool Controller_Gesture::ShouldUpdateGesture(const GestureProperties& gesture, | |||
| 97 | } | 91 | } |
| 98 | 92 | ||
| 99 | // Update on press and hold event after 0.5 seconds | 93 | // Update on press and hold event after 0.5 seconds |
| 100 | if (last_entry.type == TouchType::Touch && last_entry.point_count == 1 && | 94 | if (last_entry.type == GestureType::Touch && last_entry.point_count == 1 && |
| 101 | time_difference > press_delay) { | 95 | time_difference > press_delay) { |
| 102 | return enable_press_and_tap; | 96 | return enable_press_and_tap; |
| 103 | } | 97 | } |
| @@ -108,27 +102,19 @@ bool Controller_Gesture::ShouldUpdateGesture(const GestureProperties& gesture, | |||
| 108 | void Controller_Gesture::UpdateGestureSharedMemory(u8* data, std::size_t size, | 102 | void Controller_Gesture::UpdateGestureSharedMemory(u8* data, std::size_t size, |
| 109 | GestureProperties& gesture, | 103 | GestureProperties& gesture, |
| 110 | f32 time_difference) { | 104 | f32 time_difference) { |
| 111 | TouchType type = TouchType::Idle; | 105 | GestureType type = GestureType::Idle; |
| 112 | Attribute attributes{}; | 106 | GestureAttribute attributes{}; |
| 113 | |||
| 114 | const auto& last_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; | ||
| 115 | shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17; | ||
| 116 | auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; | ||
| 117 | 107 | ||
| 118 | if (shared_memory.header.entry_count < 16) { | 108 | const auto& last_entry = gesture_lifo.ReadCurrentEntry().state; |
| 119 | shared_memory.header.entry_count++; | ||
| 120 | } | ||
| 121 | |||
| 122 | cur_entry.sampling_number = last_entry.sampling_number + 1; | ||
| 123 | cur_entry.sampling_number2 = cur_entry.sampling_number; | ||
| 124 | 109 | ||
| 125 | // Reset values to default | 110 | // Reset next state to default |
| 126 | cur_entry.delta = {}; | 111 | next_state.sampling_number = last_entry.sampling_number + 1; |
| 127 | cur_entry.vel_x = 0; | 112 | next_state.delta = {}; |
| 128 | cur_entry.vel_y = 0; | 113 | next_state.vel_x = 0; |
| 129 | cur_entry.direction = Direction::None; | 114 | next_state.vel_y = 0; |
| 130 | cur_entry.rotation_angle = 0; | 115 | next_state.direction = GestureDirection::None; |
| 131 | cur_entry.scale = 0; | 116 | next_state.rotation_angle = 0; |
| 117 | next_state.scale = 0; | ||
| 132 | 118 | ||
| 133 | if (gesture.active_points > 0) { | 119 | if (gesture.active_points > 0) { |
| 134 | if (last_gesture.active_points == 0) { | 120 | if (last_gesture.active_points == 0) { |
| @@ -141,46 +127,47 @@ void Controller_Gesture::UpdateGestureSharedMemory(u8* data, std::size_t size, | |||
| 141 | } | 127 | } |
| 142 | 128 | ||
| 143 | // Apply attributes | 129 | // Apply attributes |
| 144 | cur_entry.detection_count = gesture.detection_count; | 130 | next_state.detection_count = gesture.detection_count; |
| 145 | cur_entry.type = type; | 131 | next_state.type = type; |
| 146 | cur_entry.attributes = attributes; | 132 | next_state.attributes = attributes; |
| 147 | cur_entry.pos = gesture.mid_point; | 133 | next_state.pos = gesture.mid_point; |
| 148 | cur_entry.point_count = static_cast<s32>(gesture.active_points); | 134 | next_state.point_count = static_cast<s32>(gesture.active_points); |
| 149 | cur_entry.points = gesture.points; | 135 | next_state.points = gesture.points; |
| 150 | last_gesture = gesture; | 136 | last_gesture = gesture; |
| 151 | 137 | ||
| 152 | std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory)); | 138 | gesture_lifo.WriteNextEntry(next_state); |
| 139 | std::memcpy(data + SHARED_MEMORY_OFFSET, &gesture_lifo, sizeof(gesture_lifo)); | ||
| 153 | } | 140 | } |
| 154 | 141 | ||
| 155 | void Controller_Gesture::NewGesture(GestureProperties& gesture, TouchType& type, | 142 | void Controller_Gesture::NewGesture(GestureProperties& gesture, GestureType& type, |
| 156 | Attribute& attributes) { | 143 | GestureAttribute& attributes) { |
| 157 | const auto& last_entry = GetLastGestureEntry(); | 144 | const auto& last_entry = gesture_lifo.ReadCurrentEntry().state; |
| 158 | 145 | ||
| 159 | gesture.detection_count++; | 146 | gesture.detection_count++; |
| 160 | type = TouchType::Touch; | 147 | type = GestureType::Touch; |
| 161 | 148 | ||
| 162 | // New touch after cancel is not considered new | 149 | // New touch after cancel is not considered new |
| 163 | if (last_entry.type != TouchType::Cancel) { | 150 | if (last_entry.type != GestureType::Cancel) { |
| 164 | attributes.is_new_touch.Assign(1); | 151 | attributes.is_new_touch.Assign(1); |
| 165 | enable_press_and_tap = true; | 152 | enable_press_and_tap = true; |
| 166 | } | 153 | } |
| 167 | } | 154 | } |
| 168 | 155 | ||
| 169 | void Controller_Gesture::UpdateExistingGesture(GestureProperties& gesture, TouchType& type, | 156 | void Controller_Gesture::UpdateExistingGesture(GestureProperties& gesture, GestureType& type, |
| 170 | f32 time_difference) { | 157 | f32 time_difference) { |
| 171 | const auto& last_entry = GetLastGestureEntry(); | 158 | const auto& last_entry = gesture_lifo.ReadCurrentEntry().state; |
| 172 | 159 | ||
| 173 | // Promote to pan type if touch moved | 160 | // Promote to pan type if touch moved |
| 174 | for (size_t id = 0; id < MAX_POINTS; id++) { | 161 | for (size_t id = 0; id < MAX_POINTS; id++) { |
| 175 | if (gesture.points[id] != last_gesture.points[id]) { | 162 | if (gesture.points[id] != last_gesture.points[id]) { |
| 176 | type = TouchType::Pan; | 163 | type = GestureType::Pan; |
| 177 | break; | 164 | break; |
| 178 | } | 165 | } |
| 179 | } | 166 | } |
| 180 | 167 | ||
| 181 | // Number of fingers changed cancel the last event and clear data | 168 | // Number of fingers changed cancel the last event and clear data |
| 182 | if (gesture.active_points != last_gesture.active_points) { | 169 | if (gesture.active_points != last_gesture.active_points) { |
| 183 | type = TouchType::Cancel; | 170 | type = GestureType::Cancel; |
| 184 | enable_press_and_tap = false; | 171 | enable_press_and_tap = false; |
| 185 | gesture.active_points = 0; | 172 | gesture.active_points = 0; |
| 186 | gesture.mid_point = {}; | 173 | gesture.mid_point = {}; |
| @@ -189,41 +176,41 @@ void Controller_Gesture::UpdateExistingGesture(GestureProperties& gesture, Touch | |||
| 189 | } | 176 | } |
| 190 | 177 | ||
| 191 | // Calculate extra parameters of panning | 178 | // Calculate extra parameters of panning |
| 192 | if (type == TouchType::Pan) { | 179 | if (type == GestureType::Pan) { |
| 193 | UpdatePanEvent(gesture, last_gesture, type, time_difference); | 180 | UpdatePanEvent(gesture, last_gesture, type, time_difference); |
| 194 | return; | 181 | return; |
| 195 | } | 182 | } |
| 196 | 183 | ||
| 197 | // Promote to press type | 184 | // Promote to press type |
| 198 | if (last_entry.type == TouchType::Touch) { | 185 | if (last_entry.type == GestureType::Touch) { |
| 199 | type = TouchType::Press; | 186 | type = GestureType::Press; |
| 200 | } | 187 | } |
| 201 | } | 188 | } |
| 202 | 189 | ||
| 203 | void Controller_Gesture::EndGesture(GestureProperties& gesture, | 190 | void Controller_Gesture::EndGesture(GestureProperties& gesture, |
| 204 | GestureProperties& last_gesture_props, TouchType& type, | 191 | GestureProperties& last_gesture_props, GestureType& type, |
| 205 | Attribute& attributes, f32 time_difference) { | 192 | GestureAttribute& attributes, f32 time_difference) { |
| 206 | const auto& last_entry = GetLastGestureEntry(); | 193 | const auto& last_entry = gesture_lifo.ReadCurrentEntry().state; |
| 207 | 194 | ||
| 208 | if (last_gesture_props.active_points != 0) { | 195 | if (last_gesture_props.active_points != 0) { |
| 209 | switch (last_entry.type) { | 196 | switch (last_entry.type) { |
| 210 | case TouchType::Touch: | 197 | case GestureType::Touch: |
| 211 | if (enable_press_and_tap) { | 198 | if (enable_press_and_tap) { |
| 212 | SetTapEvent(gesture, last_gesture_props, type, attributes); | 199 | SetTapEvent(gesture, last_gesture_props, type, attributes); |
| 213 | return; | 200 | return; |
| 214 | } | 201 | } |
| 215 | type = TouchType::Cancel; | 202 | type = GestureType::Cancel; |
| 216 | force_update = true; | 203 | force_update = true; |
| 217 | break; | 204 | break; |
| 218 | case TouchType::Press: | 205 | case GestureType::Press: |
| 219 | case TouchType::Tap: | 206 | case GestureType::Tap: |
| 220 | case TouchType::Swipe: | 207 | case GestureType::Swipe: |
| 221 | case TouchType::Pinch: | 208 | case GestureType::Pinch: |
| 222 | case TouchType::Rotate: | 209 | case GestureType::Rotate: |
| 223 | type = TouchType::Complete; | 210 | type = GestureType::Complete; |
| 224 | force_update = true; | 211 | force_update = true; |
| 225 | break; | 212 | break; |
| 226 | case TouchType::Pan: | 213 | case GestureType::Pan: |
| 227 | EndPanEvent(gesture, last_gesture_props, type, time_difference); | 214 | EndPanEvent(gesture, last_gesture_props, type, time_difference); |
| 228 | break; | 215 | break; |
| 229 | default: | 216 | default: |
| @@ -231,15 +218,15 @@ void Controller_Gesture::EndGesture(GestureProperties& gesture, | |||
| 231 | } | 218 | } |
| 232 | return; | 219 | return; |
| 233 | } | 220 | } |
| 234 | if (last_entry.type == TouchType::Complete || last_entry.type == TouchType::Cancel) { | 221 | if (last_entry.type == GestureType::Complete || last_entry.type == GestureType::Cancel) { |
| 235 | gesture.detection_count++; | 222 | gesture.detection_count++; |
| 236 | } | 223 | } |
| 237 | } | 224 | } |
| 238 | 225 | ||
| 239 | void Controller_Gesture::SetTapEvent(GestureProperties& gesture, | 226 | void Controller_Gesture::SetTapEvent(GestureProperties& gesture, |
| 240 | GestureProperties& last_gesture_props, TouchType& type, | 227 | GestureProperties& last_gesture_props, GestureType& type, |
| 241 | Attribute& attributes) { | 228 | GestureAttribute& attributes) { |
| 242 | type = TouchType::Tap; | 229 | type = GestureType::Tap; |
| 243 | gesture = last_gesture_props; | 230 | gesture = last_gesture_props; |
| 244 | force_update = true; | 231 | force_update = true; |
| 245 | f32 tap_time_difference = | 232 | f32 tap_time_difference = |
| @@ -251,44 +238,42 @@ void Controller_Gesture::SetTapEvent(GestureProperties& gesture, | |||
| 251 | } | 238 | } |
| 252 | 239 | ||
| 253 | void Controller_Gesture::UpdatePanEvent(GestureProperties& gesture, | 240 | void Controller_Gesture::UpdatePanEvent(GestureProperties& gesture, |
| 254 | GestureProperties& last_gesture_props, TouchType& type, | 241 | GestureProperties& last_gesture_props, GestureType& type, |
| 255 | f32 time_difference) { | 242 | f32 time_difference) { |
| 256 | auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; | 243 | const auto& last_entry = gesture_lifo.ReadCurrentEntry().state; |
| 257 | const auto& last_entry = GetLastGestureEntry(); | ||
| 258 | 244 | ||
| 259 | cur_entry.delta = gesture.mid_point - last_entry.pos; | 245 | next_state.delta = gesture.mid_point - last_entry.pos; |
| 260 | cur_entry.vel_x = static_cast<f32>(cur_entry.delta.x) / time_difference; | 246 | next_state.vel_x = static_cast<f32>(next_state.delta.x) / time_difference; |
| 261 | cur_entry.vel_y = static_cast<f32>(cur_entry.delta.y) / time_difference; | 247 | next_state.vel_y = static_cast<f32>(next_state.delta.y) / time_difference; |
| 262 | last_pan_time_difference = time_difference; | 248 | last_pan_time_difference = time_difference; |
| 263 | 249 | ||
| 264 | // Promote to pinch type | 250 | // Promote to pinch type |
| 265 | if (std::abs(gesture.average_distance - last_gesture_props.average_distance) > | 251 | if (std::abs(gesture.average_distance - last_gesture_props.average_distance) > |
| 266 | pinch_threshold) { | 252 | pinch_threshold) { |
| 267 | type = TouchType::Pinch; | 253 | type = GestureType::Pinch; |
| 268 | cur_entry.scale = gesture.average_distance / last_gesture_props.average_distance; | 254 | next_state.scale = gesture.average_distance / last_gesture_props.average_distance; |
| 269 | } | 255 | } |
| 270 | 256 | ||
| 271 | const f32 angle_between_two_lines = std::atan((gesture.angle - last_gesture_props.angle) / | 257 | const f32 angle_between_two_lines = std::atan((gesture.angle - last_gesture_props.angle) / |
| 272 | (1 + (gesture.angle * last_gesture_props.angle))); | 258 | (1 + (gesture.angle * last_gesture_props.angle))); |
| 273 | // Promote to rotate type | 259 | // Promote to rotate type |
| 274 | if (std::abs(angle_between_two_lines) > angle_threshold) { | 260 | if (std::abs(angle_between_two_lines) > angle_threshold) { |
| 275 | type = TouchType::Rotate; | 261 | type = GestureType::Rotate; |
| 276 | cur_entry.scale = 0; | 262 | next_state.scale = 0; |
| 277 | cur_entry.rotation_angle = angle_between_two_lines * 180.0f / Common::PI; | 263 | next_state.rotation_angle = angle_between_two_lines * 180.0f / Common::PI; |
| 278 | } | 264 | } |
| 279 | } | 265 | } |
| 280 | 266 | ||
| 281 | void Controller_Gesture::EndPanEvent(GestureProperties& gesture, | 267 | void Controller_Gesture::EndPanEvent(GestureProperties& gesture, |
| 282 | GestureProperties& last_gesture_props, TouchType& type, | 268 | GestureProperties& last_gesture_props, GestureType& type, |
| 283 | f32 time_difference) { | 269 | f32 time_difference) { |
| 284 | auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; | 270 | const auto& last_entry = gesture_lifo.ReadCurrentEntry().state; |
| 285 | const auto& last_entry = GetLastGestureEntry(); | 271 | next_state.vel_x = |
| 286 | cur_entry.vel_x = | ||
| 287 | static_cast<f32>(last_entry.delta.x) / (last_pan_time_difference + time_difference); | 272 | static_cast<f32>(last_entry.delta.x) / (last_pan_time_difference + time_difference); |
| 288 | cur_entry.vel_y = | 273 | next_state.vel_y = |
| 289 | static_cast<f32>(last_entry.delta.y) / (last_pan_time_difference + time_difference); | 274 | static_cast<f32>(last_entry.delta.y) / (last_pan_time_difference + time_difference); |
| 290 | const f32 curr_vel = | 275 | const f32 curr_vel = |
| 291 | std::sqrt((cur_entry.vel_x * cur_entry.vel_x) + (cur_entry.vel_y * cur_entry.vel_y)); | 276 | std::sqrt((next_state.vel_x * next_state.vel_x) + (next_state.vel_y * next_state.vel_y)); |
| 292 | 277 | ||
| 293 | // Set swipe event with parameters | 278 | // Set swipe event with parameters |
| 294 | if (curr_vel > swipe_threshold) { | 279 | if (curr_vel > swipe_threshold) { |
| @@ -297,93 +282,34 @@ void Controller_Gesture::EndPanEvent(GestureProperties& gesture, | |||
| 297 | } | 282 | } |
| 298 | 283 | ||
| 299 | // End panning without swipe | 284 | // End panning without swipe |
| 300 | type = TouchType::Complete; | 285 | type = GestureType::Complete; |
| 301 | cur_entry.vel_x = 0; | 286 | next_state.vel_x = 0; |
| 302 | cur_entry.vel_y = 0; | 287 | next_state.vel_y = 0; |
| 303 | force_update = true; | 288 | force_update = true; |
| 304 | } | 289 | } |
| 305 | 290 | ||
| 306 | void Controller_Gesture::SetSwipeEvent(GestureProperties& gesture, | 291 | void Controller_Gesture::SetSwipeEvent(GestureProperties& gesture, |
| 307 | GestureProperties& last_gesture_props, TouchType& type) { | 292 | GestureProperties& last_gesture_props, GestureType& type) { |
| 308 | auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; | 293 | const auto& last_entry = gesture_lifo.ReadCurrentEntry().state; |
| 309 | const auto& last_entry = GetLastGestureEntry(); | ||
| 310 | 294 | ||
| 311 | type = TouchType::Swipe; | 295 | type = GestureType::Swipe; |
| 312 | gesture = last_gesture_props; | 296 | gesture = last_gesture_props; |
| 313 | force_update = true; | 297 | force_update = true; |
| 314 | cur_entry.delta = last_entry.delta; | 298 | next_state.delta = last_entry.delta; |
| 315 | 299 | ||
| 316 | if (std::abs(cur_entry.delta.x) > std::abs(cur_entry.delta.y)) { | 300 | if (std::abs(next_state.delta.x) > std::abs(next_state.delta.y)) { |
| 317 | if (cur_entry.delta.x > 0) { | 301 | if (next_state.delta.x > 0) { |
| 318 | cur_entry.direction = Direction::Right; | 302 | next_state.direction = GestureDirection::Right; |
| 319 | return; | 303 | return; |
| 320 | } | 304 | } |
| 321 | cur_entry.direction = Direction::Left; | 305 | next_state.direction = GestureDirection::Left; |
| 322 | return; | 306 | return; |
| 323 | } | 307 | } |
| 324 | if (cur_entry.delta.y > 0) { | 308 | if (next_state.delta.y > 0) { |
| 325 | cur_entry.direction = Direction::Down; | 309 | next_state.direction = GestureDirection::Down; |
| 326 | return; | 310 | return; |
| 327 | } | 311 | } |
| 328 | cur_entry.direction = Direction::Up; | 312 | next_state.direction = GestureDirection::Up; |
| 329 | } | ||
| 330 | |||
| 331 | void Controller_Gesture::OnLoadInputDevices() { | ||
| 332 | touch_mouse_device = Input::CreateDevice<Input::TouchDevice>("engine:emu_window"); | ||
| 333 | touch_udp_device = Input::CreateDevice<Input::TouchDevice>("engine:cemuhookudp"); | ||
| 334 | touch_btn_device = Input::CreateDevice<Input::TouchDevice>("engine:touch_from_button"); | ||
| 335 | } | ||
| 336 | |||
| 337 | std::optional<std::size_t> Controller_Gesture::GetUnusedFingerID() const { | ||
| 338 | // Dont assign any touch input to a point if disabled | ||
| 339 | if (!Settings::values.touchscreen.enabled) { | ||
| 340 | return std::nullopt; | ||
| 341 | } | ||
| 342 | std::size_t first_free_id = 0; | ||
| 343 | while (first_free_id < MAX_POINTS) { | ||
| 344 | if (!fingers[first_free_id].pressed) { | ||
| 345 | return first_free_id; | ||
| 346 | } else { | ||
| 347 | first_free_id++; | ||
| 348 | } | ||
| 349 | } | ||
| 350 | return std::nullopt; | ||
| 351 | } | ||
| 352 | |||
| 353 | Controller_Gesture::GestureState& Controller_Gesture::GetLastGestureEntry() { | ||
| 354 | return shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17]; | ||
| 355 | } | ||
| 356 | |||
| 357 | const Controller_Gesture::GestureState& Controller_Gesture::GetLastGestureEntry() const { | ||
| 358 | return shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17]; | ||
| 359 | } | ||
| 360 | |||
| 361 | std::size_t Controller_Gesture::UpdateTouchInputEvent( | ||
| 362 | const std::tuple<float, float, bool>& touch_input, std::size_t finger_id) { | ||
| 363 | const auto& [x, y, pressed] = touch_input; | ||
| 364 | if (finger_id > MAX_POINTS) { | ||
| 365 | LOG_ERROR(Service_HID, "Invalid finger id {}", finger_id); | ||
| 366 | return MAX_POINTS; | ||
| 367 | } | ||
| 368 | if (pressed) { | ||
| 369 | if (finger_id == MAX_POINTS) { | ||
| 370 | const auto first_free_id = GetUnusedFingerID(); | ||
| 371 | if (!first_free_id) { | ||
| 372 | // Invalid finger id do nothing | ||
| 373 | return MAX_POINTS; | ||
| 374 | } | ||
| 375 | finger_id = first_free_id.value(); | ||
| 376 | fingers[finger_id].pressed = true; | ||
| 377 | } | ||
| 378 | fingers[finger_id].pos = {x, y}; | ||
| 379 | return finger_id; | ||
| 380 | } | ||
| 381 | |||
| 382 | if (finger_id != MAX_POINTS) { | ||
| 383 | fingers[finger_id].pressed = false; | ||
| 384 | } | ||
| 385 | |||
| 386 | return MAX_POINTS; | ||
| 387 | } | 313 | } |
| 388 | 314 | ||
| 389 | Controller_Gesture::GestureProperties Controller_Gesture::GetGestureProperties() { | 315 | Controller_Gesture::GestureProperties Controller_Gesture::GetGestureProperties() { |
diff --git a/src/core/hle/service/hid/controllers/gesture.h b/src/core/hle/service/hid/controllers/gesture.h index 7e7ae6625..8e6f315a4 100644 --- a/src/core/hle/service/hid/controllers/gesture.h +++ b/src/core/hle/service/hid/controllers/gesture.h | |||
| @@ -8,8 +8,12 @@ | |||
| 8 | #include "common/bit_field.h" | 8 | #include "common/bit_field.h" |
| 9 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 10 | #include "common/point.h" | 10 | #include "common/point.h" |
| 11 | #include "core/frontend/input.h" | ||
| 12 | #include "core/hle/service/hid/controllers/controller_base.h" | 11 | #include "core/hle/service/hid/controllers/controller_base.h" |
| 12 | #include "core/hle/service/hid/ring_lifo.h" | ||
| 13 | |||
| 14 | namespace Core::HID { | ||
| 15 | class EmulatedController; | ||
| 16 | } // namespace Core::HID | ||
| 13 | 17 | ||
| 14 | namespace Service::HID { | 18 | namespace Service::HID { |
| 15 | class Controller_Gesture final : public ControllerBase { | 19 | class Controller_Gesture final : public ControllerBase { |
| @@ -26,14 +30,12 @@ public: | |||
| 26 | // When the controller is requesting an update for the shared memory | 30 | // When the controller is requesting an update for the shared memory |
| 27 | void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, size_t size) override; | 31 | void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, size_t size) override; |
| 28 | 32 | ||
| 29 | // Called when input devices should be loaded | ||
| 30 | void OnLoadInputDevices() override; | ||
| 31 | |||
| 32 | private: | 33 | private: |
| 33 | static constexpr size_t MAX_FINGERS = 16; | 34 | static constexpr size_t MAX_FINGERS = 16; |
| 34 | static constexpr size_t MAX_POINTS = 4; | 35 | static constexpr size_t MAX_POINTS = 4; |
| 35 | 36 | ||
| 36 | enum class TouchType : u32 { | 37 | // This is nn::hid::GestureType |
| 38 | enum class GestureType : u32 { | ||
| 37 | Idle, // Nothing touching the screen | 39 | Idle, // Nothing touching the screen |
| 38 | Complete, // Set at the end of a touch event | 40 | Complete, // Set at the end of a touch event |
| 39 | Cancel, // Set when the number of fingers change | 41 | Cancel, // Set when the number of fingers change |
| @@ -46,7 +48,8 @@ private: | |||
| 46 | Rotate, // All points rotating from the midpoint | 48 | Rotate, // All points rotating from the midpoint |
| 47 | }; | 49 | }; |
| 48 | 50 | ||
| 49 | enum class Direction : u32 { | 51 | // This is nn::hid::GestureDirection |
| 52 | enum class GestureDirection : u32 { | ||
| 50 | None, | 53 | None, |
| 51 | Left, | 54 | Left, |
| 52 | Up, | 55 | Up, |
| @@ -54,7 +57,8 @@ private: | |||
| 54 | Down, | 57 | Down, |
| 55 | }; | 58 | }; |
| 56 | 59 | ||
| 57 | struct Attribute { | 60 | // This is nn::hid::GestureAttribute |
| 61 | struct GestureAttribute { | ||
| 58 | union { | 62 | union { |
| 59 | u32_le raw{}; | 63 | u32_le raw{}; |
| 60 | 64 | ||
| @@ -62,31 +66,25 @@ private: | |||
| 62 | BitField<8, 1, u32> is_double_tap; | 66 | BitField<8, 1, u32> is_double_tap; |
| 63 | }; | 67 | }; |
| 64 | }; | 68 | }; |
| 65 | static_assert(sizeof(Attribute) == 4, "Attribute is an invalid size"); | 69 | static_assert(sizeof(GestureAttribute) == 4, "GestureAttribute is an invalid size"); |
| 66 | 70 | ||
| 71 | // This is nn::hid::GestureState | ||
| 67 | struct GestureState { | 72 | struct GestureState { |
| 68 | s64_le sampling_number; | 73 | s64_le sampling_number; |
| 69 | s64_le sampling_number2; | ||
| 70 | s64_le detection_count; | 74 | s64_le detection_count; |
| 71 | TouchType type; | 75 | GestureType type; |
| 72 | Direction direction; | 76 | GestureDirection direction; |
| 73 | Common::Point<s32_le> pos; | 77 | Common::Point<s32_le> pos; |
| 74 | Common::Point<s32_le> delta; | 78 | Common::Point<s32_le> delta; |
| 75 | f32 vel_x; | 79 | f32 vel_x; |
| 76 | f32 vel_y; | 80 | f32 vel_y; |
| 77 | Attribute attributes; | 81 | GestureAttribute attributes; |
| 78 | f32 scale; | 82 | f32 scale; |
| 79 | f32 rotation_angle; | 83 | f32 rotation_angle; |
| 80 | s32_le point_count; | 84 | s32_le point_count; |
| 81 | std::array<Common::Point<s32_le>, 4> points; | 85 | std::array<Common::Point<s32_le>, 4> points; |
| 82 | }; | 86 | }; |
| 83 | static_assert(sizeof(GestureState) == 0x68, "GestureState is an invalid size"); | 87 | static_assert(sizeof(GestureState) == 0x60, "GestureState is an invalid size"); |
| 84 | |||
| 85 | struct SharedMemory { | ||
| 86 | CommonHeader header; | ||
| 87 | std::array<GestureState, 17> gesture_states; | ||
| 88 | }; | ||
| 89 | static_assert(sizeof(SharedMemory) == 0x708, "SharedMemory is an invalid size"); | ||
| 90 | 88 | ||
| 91 | struct Finger { | 89 | struct Finger { |
| 92 | Common::Point<f32> pos{}; | 90 | Common::Point<f32> pos{}; |
| @@ -114,58 +112,42 @@ private: | |||
| 114 | f32 time_difference); | 112 | f32 time_difference); |
| 115 | 113 | ||
| 116 | // Initializes new gesture | 114 | // Initializes new gesture |
| 117 | void NewGesture(GestureProperties& gesture, TouchType& type, Attribute& attributes); | 115 | void NewGesture(GestureProperties& gesture, GestureType& type, GestureAttribute& attributes); |
| 118 | 116 | ||
| 119 | // Updates existing gesture state | 117 | // Updates existing gesture state |
| 120 | void UpdateExistingGesture(GestureProperties& gesture, TouchType& type, f32 time_difference); | 118 | void UpdateExistingGesture(GestureProperties& gesture, GestureType& type, f32 time_difference); |
| 121 | 119 | ||
| 122 | // Terminates exiting gesture | 120 | // Terminates exiting gesture |
| 123 | void EndGesture(GestureProperties& gesture, GestureProperties& last_gesture_props, | 121 | void EndGesture(GestureProperties& gesture, GestureProperties& last_gesture_props, |
| 124 | TouchType& type, Attribute& attributes, f32 time_difference); | 122 | GestureType& type, GestureAttribute& attributes, f32 time_difference); |
| 125 | 123 | ||
| 126 | // Set current event to a tap event | 124 | // Set current event to a tap event |
| 127 | void SetTapEvent(GestureProperties& gesture, GestureProperties& last_gesture_props, | 125 | void SetTapEvent(GestureProperties& gesture, GestureProperties& last_gesture_props, |
| 128 | TouchType& type, Attribute& attributes); | 126 | GestureType& type, GestureAttribute& attributes); |
| 129 | 127 | ||
| 130 | // Calculates and set the extra parameters related to a pan event | 128 | // Calculates and set the extra parameters related to a pan event |
| 131 | void UpdatePanEvent(GestureProperties& gesture, GestureProperties& last_gesture_props, | 129 | void UpdatePanEvent(GestureProperties& gesture, GestureProperties& last_gesture_props, |
| 132 | TouchType& type, f32 time_difference); | 130 | GestureType& type, f32 time_difference); |
| 133 | 131 | ||
| 134 | // Terminates the pan event | 132 | // Terminates the pan event |
| 135 | void EndPanEvent(GestureProperties& gesture, GestureProperties& last_gesture_props, | 133 | void EndPanEvent(GestureProperties& gesture, GestureProperties& last_gesture_props, |
| 136 | TouchType& type, f32 time_difference); | 134 | GestureType& type, f32 time_difference); |
| 137 | 135 | ||
| 138 | // Set current event to a swipe event | 136 | // Set current event to a swipe event |
| 139 | void SetSwipeEvent(GestureProperties& gesture, GestureProperties& last_gesture_props, | 137 | void SetSwipeEvent(GestureProperties& gesture, GestureProperties& last_gesture_props, |
| 140 | TouchType& type); | 138 | GestureType& type); |
| 141 | |||
| 142 | // Returns an unused finger id, if there is no fingers available std::nullopt is returned. | ||
| 143 | [[nodiscard]] std::optional<size_t> GetUnusedFingerID() const; | ||
| 144 | |||
| 145 | // Retrieves the last gesture entry, as indicated by shared memory indices. | ||
| 146 | [[nodiscard]] GestureState& GetLastGestureEntry(); | ||
| 147 | [[nodiscard]] const GestureState& GetLastGestureEntry() const; | ||
| 148 | |||
| 149 | /** | ||
| 150 | * If the touch is new it tries to assign a new finger id, if there is no fingers available no | ||
| 151 | * changes will be made. Updates the coordinates if the finger id it's already set. If the touch | ||
| 152 | * ends delays the output by one frame to set the end_touch flag before finally freeing the | ||
| 153 | * finger id | ||
| 154 | */ | ||
| 155 | size_t UpdateTouchInputEvent(const std::tuple<float, float, bool>& touch_input, | ||
| 156 | size_t finger_id); | ||
| 157 | 139 | ||
| 158 | // Returns the average distance, angle and middle point of the active fingers | 140 | // Returns the average distance, angle and middle point of the active fingers |
| 159 | GestureProperties GetGestureProperties(); | 141 | GestureProperties GetGestureProperties(); |
| 160 | 142 | ||
| 161 | SharedMemory shared_memory{}; | 143 | // This is nn::hid::detail::GestureLifo |
| 162 | std::unique_ptr<Input::TouchDevice> touch_mouse_device; | 144 | Lifo<GestureState> gesture_lifo{}; |
| 163 | std::unique_ptr<Input::TouchDevice> touch_udp_device; | 145 | static_assert(sizeof(gesture_lifo) == 0x708, "gesture_lifo is an invalid size"); |
| 164 | std::unique_ptr<Input::TouchDevice> touch_btn_device; | 146 | GestureState next_state{}; |
| 165 | std::array<size_t, MAX_FINGERS> mouse_finger_id{}; | 147 | |
| 166 | std::array<size_t, MAX_FINGERS> keyboard_finger_id{}; | ||
| 167 | std::array<size_t, MAX_FINGERS> udp_finger_id{}; | ||
| 168 | std::array<Finger, MAX_POINTS> fingers{}; | 148 | std::array<Finger, MAX_POINTS> fingers{}; |
| 149 | Core::HID::EmulatedConsole* console; | ||
| 150 | |||
| 169 | GestureProperties last_gesture{}; | 151 | GestureProperties last_gesture{}; |
| 170 | s64_le last_update_timestamp{}; | 152 | s64_le last_update_timestamp{}; |
| 171 | s64_le last_tap_timestamp{}; | 153 | s64_le last_tap_timestamp{}; |
diff --git a/src/core/hle/service/hid/controllers/touchscreen.cpp b/src/core/hle/service/hid/controllers/touchscreen.cpp index 6ef17acc5..e0a44d06b 100644 --- a/src/core/hle/service/hid/controllers/touchscreen.cpp +++ b/src/core/hle/service/hid/controllers/touchscreen.cpp | |||
| @@ -7,72 +7,79 @@ | |||
| 7 | #include "common/common_types.h" | 7 | #include "common/common_types.h" |
| 8 | #include "common/logging/log.h" | 8 | #include "common/logging/log.h" |
| 9 | #include "common/settings.h" | 9 | #include "common/settings.h" |
| 10 | #include "core/core.h" | ||
| 10 | #include "core/core_timing.h" | 11 | #include "core/core_timing.h" |
| 11 | #include "core/frontend/emu_window.h" | 12 | #include "core/frontend/emu_window.h" |
| 12 | #include "core/frontend/input.h" | ||
| 13 | #include "core/hle/service/hid/controllers/touchscreen.h" | 13 | #include "core/hle/service/hid/controllers/touchscreen.h" |
| 14 | 14 | ||
| 15 | namespace Service::HID { | 15 | namespace Service::HID { |
| 16 | constexpr std::size_t SHARED_MEMORY_OFFSET = 0x400; | 16 | constexpr std::size_t SHARED_MEMORY_OFFSET = 0x400; |
| 17 | 17 | ||
| 18 | Controller_Touchscreen::Controller_Touchscreen(Core::System& system_) : ControllerBase{system_} {} | 18 | Controller_Touchscreen::Controller_Touchscreen(Core::System& system_) : ControllerBase{system_} { |
| 19 | console = system.HIDCore().GetEmulatedConsole(); | ||
| 20 | } | ||
| 21 | |||
| 19 | Controller_Touchscreen::~Controller_Touchscreen() = default; | 22 | Controller_Touchscreen::~Controller_Touchscreen() = default; |
| 20 | 23 | ||
| 21 | void Controller_Touchscreen::OnInit() { | 24 | void Controller_Touchscreen::OnInit() {} |
| 22 | for (std::size_t id = 0; id < MAX_FINGERS; ++id) { | ||
| 23 | mouse_finger_id[id] = MAX_FINGERS; | ||
| 24 | keyboard_finger_id[id] = MAX_FINGERS; | ||
| 25 | udp_finger_id[id] = MAX_FINGERS; | ||
| 26 | } | ||
| 27 | } | ||
| 28 | 25 | ||
| 29 | void Controller_Touchscreen::OnRelease() {} | 26 | void Controller_Touchscreen::OnRelease() {} |
| 30 | 27 | ||
| 31 | void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, | 28 | void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, |
| 32 | std::size_t size) { | 29 | std::size_t size) { |
| 33 | shared_memory.header.timestamp = core_timing.GetCPUTicks(); | 30 | touch_screen_lifo.timestamp = core_timing.GetCPUTicks(); |
| 34 | shared_memory.header.total_entry_count = 17; | ||
| 35 | 31 | ||
| 36 | if (!IsControllerActivated()) { | 32 | if (!IsControllerActivated()) { |
| 37 | shared_memory.header.entry_count = 0; | 33 | touch_screen_lifo.entry_count = 0; |
| 38 | shared_memory.header.last_entry_index = 0; | 34 | touch_screen_lifo.last_entry_index = 0; |
| 35 | std::memcpy(data, &touch_screen_lifo, sizeof(touch_screen_lifo)); | ||
| 39 | return; | 36 | return; |
| 40 | } | 37 | } |
| 41 | shared_memory.header.entry_count = 16; | ||
| 42 | 38 | ||
| 43 | const auto& last_entry = | 39 | const auto touch_status = console->GetTouch(); |
| 44 | shared_memory.shared_memory_entries[shared_memory.header.last_entry_index]; | 40 | for (std::size_t id = 0; id < MAX_FINGERS; id++) { |
| 45 | shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17; | 41 | const auto& current_touch = touch_status[id]; |
| 46 | auto& cur_entry = shared_memory.shared_memory_entries[shared_memory.header.last_entry_index]; | 42 | auto& finger = fingers[id]; |
| 43 | finger.position = current_touch.position; | ||
| 44 | finger.id = current_touch.id; | ||
| 47 | 45 | ||
| 48 | cur_entry.sampling_number = last_entry.sampling_number + 1; | 46 | if (finger.attribute.start_touch) { |
| 49 | cur_entry.sampling_number2 = cur_entry.sampling_number; | 47 | finger.attribute.raw = 0; |
| 48 | continue; | ||
| 49 | } | ||
| 50 | 50 | ||
| 51 | const Input::TouchStatus& mouse_status = touch_mouse_device->GetStatus(); | 51 | if (finger.attribute.end_touch) { |
| 52 | const Input::TouchStatus& udp_status = touch_udp_device->GetStatus(); | 52 | finger.attribute.raw = 0; |
| 53 | for (std::size_t id = 0; id < mouse_status.size(); ++id) { | 53 | finger.pressed = false; |
| 54 | mouse_finger_id[id] = UpdateTouchInputEvent(mouse_status[id], mouse_finger_id[id]); | 54 | continue; |
| 55 | udp_finger_id[id] = UpdateTouchInputEvent(udp_status[id], udp_finger_id[id]); | 55 | } |
| 56 | } | 56 | |
| 57 | if (!finger.pressed && current_touch.pressed) { | ||
| 58 | finger.attribute.start_touch.Assign(1); | ||
| 59 | finger.pressed = true; | ||
| 60 | continue; | ||
| 61 | } | ||
| 57 | 62 | ||
| 58 | if (Settings::values.use_touch_from_button) { | 63 | if (finger.pressed && !current_touch.pressed) { |
| 59 | const Input::TouchStatus& keyboard_status = touch_btn_device->GetStatus(); | 64 | finger.attribute.raw = 0; |
| 60 | for (std::size_t id = 0; id < mouse_status.size(); ++id) { | 65 | finger.attribute.end_touch.Assign(1); |
| 61 | keyboard_finger_id[id] = | ||
| 62 | UpdateTouchInputEvent(keyboard_status[id], keyboard_finger_id[id]); | ||
| 63 | } | 66 | } |
| 64 | } | 67 | } |
| 65 | 68 | ||
| 66 | std::array<Finger, 16> active_fingers; | 69 | std::array<Finger, MAX_FINGERS> active_fingers; |
| 67 | const auto end_iter = std::copy_if(fingers.begin(), fingers.end(), active_fingers.begin(), | 70 | const auto end_iter = std::copy_if(fingers.begin(), fingers.end(), active_fingers.begin(), |
| 68 | [](const auto& finger) { return finger.pressed; }); | 71 | [](const auto& finger) { return finger.pressed; }); |
| 69 | const auto active_fingers_count = | 72 | const auto active_fingers_count = |
| 70 | static_cast<std::size_t>(std::distance(active_fingers.begin(), end_iter)); | 73 | static_cast<std::size_t>(std::distance(active_fingers.begin(), end_iter)); |
| 71 | 74 | ||
| 72 | const u64 tick = core_timing.GetCPUTicks(); | 75 | const u64 tick = core_timing.GetCPUTicks(); |
| 73 | cur_entry.entry_count = static_cast<s32_le>(active_fingers_count); | 76 | const auto& last_entry = touch_screen_lifo.ReadCurrentEntry().state; |
| 77 | |||
| 78 | next_state.sampling_number = last_entry.sampling_number + 1; | ||
| 79 | next_state.entry_count = static_cast<s32_le>(active_fingers_count); | ||
| 80 | |||
| 74 | for (std::size_t id = 0; id < MAX_FINGERS; ++id) { | 81 | for (std::size_t id = 0; id < MAX_FINGERS; ++id) { |
| 75 | auto& touch_entry = cur_entry.states[id]; | 82 | auto& touch_entry = next_state.states[id]; |
| 76 | if (id < active_fingers_count) { | 83 | if (id < active_fingers_count) { |
| 77 | const auto& [active_x, active_y] = active_fingers[id].position; | 84 | const auto& [active_x, active_y] = active_fingers[id].position; |
| 78 | touch_entry.position = { | 85 | touch_entry.position = { |
| @@ -97,66 +104,9 @@ void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timin | |||
| 97 | touch_entry.finger = 0; | 104 | touch_entry.finger = 0; |
| 98 | } | 105 | } |
| 99 | } | 106 | } |
| 100 | std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(TouchScreenSharedMemory)); | ||
| 101 | } | ||
| 102 | |||
| 103 | void Controller_Touchscreen::OnLoadInputDevices() { | ||
| 104 | touch_mouse_device = Input::CreateDevice<Input::TouchDevice>("engine:emu_window"); | ||
| 105 | touch_udp_device = Input::CreateDevice<Input::TouchDevice>("engine:cemuhookudp"); | ||
| 106 | touch_btn_device = Input::CreateDevice<Input::TouchDevice>("engine:touch_from_button"); | ||
| 107 | } | ||
| 108 | |||
| 109 | std::optional<std::size_t> Controller_Touchscreen::GetUnusedFingerID() const { | ||
| 110 | // Dont assign any touch input to a finger if disabled | ||
| 111 | if (!Settings::values.touchscreen.enabled) { | ||
| 112 | return std::nullopt; | ||
| 113 | } | ||
| 114 | std::size_t first_free_id = 0; | ||
| 115 | while (first_free_id < MAX_FINGERS) { | ||
| 116 | if (!fingers[first_free_id].pressed) { | ||
| 117 | return first_free_id; | ||
| 118 | } else { | ||
| 119 | first_free_id++; | ||
| 120 | } | ||
| 121 | } | ||
| 122 | return std::nullopt; | ||
| 123 | } | ||
| 124 | |||
| 125 | std::size_t Controller_Touchscreen::UpdateTouchInputEvent( | ||
| 126 | const std::tuple<float, float, bool>& touch_input, std::size_t finger_id) { | ||
| 127 | const auto& [x, y, pressed] = touch_input; | ||
| 128 | if (finger_id > MAX_FINGERS) { | ||
| 129 | LOG_ERROR(Service_HID, "Invalid finger id {}", finger_id); | ||
| 130 | return MAX_FINGERS; | ||
| 131 | } | ||
| 132 | if (pressed) { | ||
| 133 | Attributes attribute{}; | ||
| 134 | if (finger_id == MAX_FINGERS) { | ||
| 135 | const auto first_free_id = GetUnusedFingerID(); | ||
| 136 | if (!first_free_id) { | ||
| 137 | // Invalid finger id do nothing | ||
| 138 | return MAX_FINGERS; | ||
| 139 | } | ||
| 140 | finger_id = first_free_id.value(); | ||
| 141 | fingers[finger_id].pressed = true; | ||
| 142 | fingers[finger_id].id = static_cast<u32_le>(finger_id); | ||
| 143 | attribute.start_touch.Assign(1); | ||
| 144 | } | ||
| 145 | fingers[finger_id].position = {x, y}; | ||
| 146 | fingers[finger_id].attribute = attribute; | ||
| 147 | return finger_id; | ||
| 148 | } | ||
| 149 | |||
| 150 | if (finger_id != MAX_FINGERS) { | ||
| 151 | if (!fingers[finger_id].attribute.end_touch) { | ||
| 152 | fingers[finger_id].attribute.end_touch.Assign(1); | ||
| 153 | fingers[finger_id].attribute.start_touch.Assign(0); | ||
| 154 | return finger_id; | ||
| 155 | } | ||
| 156 | fingers[finger_id].pressed = false; | ||
| 157 | } | ||
| 158 | 107 | ||
| 159 | return MAX_FINGERS; | 108 | touch_screen_lifo.WriteNextEntry(next_state); |
| 109 | std::memcpy(data + SHARED_MEMORY_OFFSET, &touch_screen_lifo, sizeof(touch_screen_lifo)); | ||
| 160 | } | 110 | } |
| 161 | 111 | ||
| 162 | } // namespace Service::HID | 112 | } // namespace Service::HID |
diff --git a/src/core/hle/service/hid/controllers/touchscreen.h b/src/core/hle/service/hid/controllers/touchscreen.h index 8e9b40c0a..bcf79237d 100644 --- a/src/core/hle/service/hid/controllers/touchscreen.h +++ b/src/core/hle/service/hid/controllers/touchscreen.h | |||
| @@ -9,18 +9,22 @@ | |||
| 9 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 10 | #include "common/point.h" | 10 | #include "common/point.h" |
| 11 | #include "common/swap.h" | 11 | #include "common/swap.h" |
| 12 | #include "core/frontend/input.h" | 12 | #include "core/hid/hid_core.h" |
| 13 | #include "core/hid/hid_types.h" | ||
| 13 | #include "core/hle/service/hid/controllers/controller_base.h" | 14 | #include "core/hle/service/hid/controllers/controller_base.h" |
| 15 | #include "core/hle/service/hid/ring_lifo.h" | ||
| 14 | 16 | ||
| 15 | namespace Service::HID { | 17 | namespace Service::HID { |
| 16 | class Controller_Touchscreen final : public ControllerBase { | 18 | class Controller_Touchscreen final : public ControllerBase { |
| 17 | public: | 19 | public: |
| 20 | // This is nn::hid::TouchScreenModeForNx | ||
| 18 | enum class TouchScreenModeForNx : u8 { | 21 | enum class TouchScreenModeForNx : u8 { |
| 19 | UseSystemSetting, | 22 | UseSystemSetting, |
| 20 | Finger, | 23 | Finger, |
| 21 | Heat2, | 24 | Heat2, |
| 22 | }; | 25 | }; |
| 23 | 26 | ||
| 27 | // This is nn::hid::TouchScreenConfigurationForNx | ||
| 24 | struct TouchScreenConfigurationForNx { | 28 | struct TouchScreenConfigurationForNx { |
| 25 | TouchScreenModeForNx mode; | 29 | TouchScreenModeForNx mode; |
| 26 | INSERT_PADDING_BYTES_NOINIT(0x7); | 30 | INSERT_PADDING_BYTES_NOINIT(0x7); |
| @@ -41,73 +45,32 @@ public: | |||
| 41 | // When the controller is requesting an update for the shared memory | 45 | // When the controller is requesting an update for the shared memory |
| 42 | void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override; | 46 | void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override; |
| 43 | 47 | ||
| 44 | // Called when input devices should be loaded | ||
| 45 | void OnLoadInputDevices() override; | ||
| 46 | |||
| 47 | private: | 48 | private: |
| 48 | static constexpr std::size_t MAX_FINGERS = 16; | 49 | static constexpr std::size_t MAX_FINGERS = 16; |
| 49 | 50 | ||
| 50 | // Returns an unused finger id, if there is no fingers available std::nullopt will be returned | 51 | // This is nn::hid::TouchScreenState |
| 51 | std::optional<std::size_t> GetUnusedFingerID() const; | 52 | struct TouchScreenState { |
| 52 | |||
| 53 | // If the touch is new it tries to assing a new finger id, if there is no fingers avaliable no | ||
| 54 | // changes will be made. Updates the coordinates if the finger id it's already set. If the touch | ||
| 55 | // ends delays the output by one frame to set the end_touch flag before finally freeing the | ||
| 56 | // finger id | ||
| 57 | std::size_t UpdateTouchInputEvent(const std::tuple<float, float, bool>& touch_input, | ||
| 58 | std::size_t finger_id); | ||
| 59 | |||
| 60 | struct Attributes { | ||
| 61 | union { | ||
| 62 | u32 raw{}; | ||
| 63 | BitField<0, 1, u32> start_touch; | ||
| 64 | BitField<1, 1, u32> end_touch; | ||
| 65 | }; | ||
| 66 | }; | ||
| 67 | static_assert(sizeof(Attributes) == 0x4, "Attributes is an invalid size"); | ||
| 68 | |||
| 69 | struct TouchState { | ||
| 70 | u64_le delta_time; | ||
| 71 | Attributes attribute; | ||
| 72 | u32_le finger; | ||
| 73 | Common::Point<u32_le> position; | ||
| 74 | u32_le diameter_x; | ||
| 75 | u32_le diameter_y; | ||
| 76 | u32_le rotation_angle; | ||
| 77 | }; | ||
| 78 | static_assert(sizeof(TouchState) == 0x28, "Touchstate is an invalid size"); | ||
| 79 | |||
| 80 | struct TouchScreenEntry { | ||
| 81 | s64_le sampling_number; | 53 | s64_le sampling_number; |
| 82 | s64_le sampling_number2; | ||
| 83 | s32_le entry_count; | 54 | s32_le entry_count; |
| 84 | std::array<TouchState, MAX_FINGERS> states; | 55 | INSERT_PADDING_BYTES(4); // Reserved |
| 56 | std::array<Core::HID::TouchState, MAX_FINGERS> states; | ||
| 85 | }; | 57 | }; |
| 86 | static_assert(sizeof(TouchScreenEntry) == 0x298, "TouchScreenEntry is an invalid size"); | 58 | static_assert(sizeof(TouchScreenState) == 0x290, "TouchScreenState is an invalid size"); |
| 87 | |||
| 88 | struct TouchScreenSharedMemory { | ||
| 89 | CommonHeader header; | ||
| 90 | std::array<TouchScreenEntry, 17> shared_memory_entries{}; | ||
| 91 | INSERT_PADDING_BYTES(0x3c8); | ||
| 92 | }; | ||
| 93 | static_assert(sizeof(TouchScreenSharedMemory) == 0x3000, | ||
| 94 | "TouchScreenSharedMemory is an invalid size"); | ||
| 95 | 59 | ||
| 96 | struct Finger { | 60 | struct Finger { |
| 97 | u64_le last_touch{}; | 61 | u64_le last_touch{}; |
| 98 | Common::Point<float> position; | 62 | Common::Point<float> position; |
| 99 | u32_le id{}; | 63 | u32_le id{}; |
| 100 | bool pressed{}; | 64 | bool pressed{}; |
| 101 | Attributes attribute; | 65 | Core::HID::TouchAttribute attribute; |
| 102 | }; | 66 | }; |
| 103 | 67 | ||
| 104 | TouchScreenSharedMemory shared_memory{}; | 68 | // This is nn::hid::detail::TouchScreenLifo |
| 105 | std::unique_ptr<Input::TouchDevice> touch_mouse_device; | 69 | Lifo<TouchScreenState> touch_screen_lifo{}; |
| 106 | std::unique_ptr<Input::TouchDevice> touch_udp_device; | 70 | static_assert(sizeof(touch_screen_lifo) == 0x2C38, "touch_screen_lifo is an invalid size"); |
| 107 | std::unique_ptr<Input::TouchDevice> touch_btn_device; | 71 | TouchScreenState next_state{}; |
| 108 | std::array<std::size_t, MAX_FINGERS> mouse_finger_id; | 72 | |
| 109 | std::array<std::size_t, MAX_FINGERS> keyboard_finger_id; | ||
| 110 | std::array<std::size_t, MAX_FINGERS> udp_finger_id; | ||
| 111 | std::array<Finger, MAX_FINGERS> fingers; | 73 | std::array<Finger, MAX_FINGERS> fingers; |
| 74 | Core::HID::EmulatedConsole* console; | ||
| 112 | }; | 75 | }; |
| 113 | } // namespace Service::HID | 76 | } // namespace Service::HID |