diff options
| m--------- | externals/ffmpeg | 0 | ||||
| -rw-r--r-- | src/core/hle/service/hid/controllers/gesture.cpp | 347 | ||||
| -rw-r--r-- | src/core/hle/service/hid/controllers/gesture.h | 69 | ||||
| -rw-r--r-- | src/core/hle/service/ssl/ssl.cpp | 42 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_ui.cpp | 1 |
5 files changed, 381 insertions, 78 deletions
diff --git a/externals/ffmpeg b/externals/ffmpeg | |||
| Subproject 6b6b9e593dd4d3aaf75f48d40a13ef03bdef9fd | Subproject 79e8d17024e6c6328a40fcee191ffd70798a9c6 | ||
diff --git a/src/core/hle/service/hid/controllers/gesture.cpp b/src/core/hle/service/hid/controllers/gesture.cpp index bb77d8959..9e5df3bb7 100644 --- a/src/core/hle/service/hid/controllers/gesture.cpp +++ b/src/core/hle/service/hid/controllers/gesture.cpp | |||
| @@ -1,10 +1,9 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | 1 | // Copyright 2021 yuzu Emulator Project |
| 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 <cstring> | ||
| 6 | #include "common/common_types.h" | ||
| 7 | #include "common/logging/log.h" | 5 | #include "common/logging/log.h" |
| 6 | #include "common/math_util.h" | ||
| 8 | #include "common/settings.h" | 7 | #include "common/settings.h" |
| 9 | #include "core/core_timing.h" | 8 | #include "core/core_timing.h" |
| 10 | #include "core/frontend/emu_window.h" | 9 | #include "core/frontend/emu_window.h" |
| @@ -12,10 +11,19 @@ | |||
| 12 | 11 | ||
| 13 | namespace Service::HID { | 12 | namespace Service::HID { |
| 14 | constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3BA00; | 13 | constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3BA00; |
| 15 | constexpr f32 angle_threshold = 0.08f; | ||
| 16 | constexpr f32 pinch_threshold = 100.0f; | ||
| 17 | 14 | ||
| 18 | Controller_Gesture::Controller_Gesture(Core::System& system_) : ControllerBase{system_} {} | 15 | // HW is around 700, value is set to 400 to make it easier to trigger with mouse |
| 16 | constexpr f32 swipe_threshold = 400.0f; // Threshold in pixels/s | ||
| 17 | constexpr f32 angle_threshold = 0.015f; // Threshold in radians | ||
| 18 | constexpr f32 pinch_threshold = 0.5f; // Threshold in pixels | ||
| 19 | constexpr f32 press_delay = 0.5f; // Time in seconds | ||
| 20 | constexpr f32 double_tap_delay = 0.35f; // Time in seconds | ||
| 21 | |||
| 22 | constexpr f32 Square(s32 num) { | ||
| 23 | return static_cast<f32>(num * num); | ||
| 24 | } | ||
| 25 | |||
| 26 | Controller_Gesture::Controller_Gesture(Core::System& system) : ControllerBase(system) {} | ||
| 19 | Controller_Gesture::~Controller_Gesture() = default; | 27 | Controller_Gesture::~Controller_Gesture() = default; |
| 20 | 28 | ||
| 21 | void Controller_Gesture::OnInit() { | 29 | void Controller_Gesture::OnInit() { |
| @@ -24,6 +32,8 @@ void Controller_Gesture::OnInit() { | |||
| 24 | keyboard_finger_id[id] = MAX_POINTS; | 32 | keyboard_finger_id[id] = MAX_POINTS; |
| 25 | udp_finger_id[id] = MAX_POINTS; | 33 | udp_finger_id[id] = MAX_POINTS; |
| 26 | } | 34 | } |
| 35 | shared_memory.header.entry_count = 0; | ||
| 36 | force_update = true; | ||
| 27 | } | 37 | } |
| 28 | 38 | ||
| 29 | void Controller_Gesture::OnRelease() {} | 39 | void Controller_Gesture::OnRelease() {} |
| @@ -38,17 +48,23 @@ void Controller_Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing, u | |||
| 38 | shared_memory.header.last_entry_index = 0; | 48 | shared_memory.header.last_entry_index = 0; |
| 39 | return; | 49 | return; |
| 40 | } | 50 | } |
| 41 | shared_memory.header.entry_count = 16; | ||
| 42 | 51 | ||
| 43 | const auto& last_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; | 52 | ReadTouchInput(); |
| 44 | shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17; | ||
| 45 | auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; | ||
| 46 | 53 | ||
| 47 | cur_entry.sampling_number = last_entry.sampling_number + 1; | 54 | GestureProperties gesture = GetGestureProperties(); |
| 48 | cur_entry.sampling_number2 = cur_entry.sampling_number; | 55 | f32 time_difference = static_cast<f32>(shared_memory.header.timestamp - last_update_timestamp) / |
| 56 | (1000 * 1000 * 1000); | ||
| 49 | 57 | ||
| 50 | // TODO(german77): Implement all gesture types | 58 | // Only update if necesary |
| 59 | if (!ShouldUpdateGesture(gesture, time_difference)) { | ||
| 60 | return; | ||
| 61 | } | ||
| 51 | 62 | ||
| 63 | last_update_timestamp = shared_memory.header.timestamp; | ||
| 64 | UpdateGestureSharedMemory(data, size, gesture, time_difference); | ||
| 65 | } | ||
| 66 | |||
| 67 | void Controller_Gesture::ReadTouchInput() { | ||
| 52 | const Input::TouchStatus& mouse_status = touch_mouse_device->GetStatus(); | 68 | const Input::TouchStatus& mouse_status = touch_mouse_device->GetStatus(); |
| 53 | const Input::TouchStatus& udp_status = touch_udp_device->GetStatus(); | 69 | const Input::TouchStatus& udp_status = touch_udp_device->GetStatus(); |
| 54 | for (std::size_t id = 0; id < mouse_status.size(); ++id) { | 70 | for (std::size_t id = 0; id < mouse_status.size(); ++id) { |
| @@ -63,50 +79,71 @@ void Controller_Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing, u | |||
| 63 | UpdateTouchInputEvent(keyboard_status[id], keyboard_finger_id[id]); | 79 | UpdateTouchInputEvent(keyboard_status[id], keyboard_finger_id[id]); |
| 64 | } | 80 | } |
| 65 | } | 81 | } |
| 82 | } | ||
| 66 | 83 | ||
| 67 | TouchType type = TouchType::Idle; | 84 | bool Controller_Gesture::ShouldUpdateGesture(const GestureProperties& gesture, |
| 68 | Attribute attributes{}; | 85 | f32 time_difference) { |
| 69 | GestureProperties gesture = GetGestureProperties(); | 86 | const auto& last_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; |
| 70 | if (last_gesture.active_points != gesture.active_points) { | 87 | if (force_update) { |
| 71 | ++last_gesture.detection_count; | 88 | force_update = false; |
| 89 | return true; | ||
| 72 | } | 90 | } |
| 73 | if (gesture.active_points > 0) { | ||
| 74 | if (last_gesture.active_points == 0) { | ||
| 75 | attributes.is_new_touch.Assign(true); | ||
| 76 | last_gesture.average_distance = gesture.average_distance; | ||
| 77 | last_gesture.angle = gesture.angle; | ||
| 78 | } | ||
| 79 | 91 | ||
| 80 | type = TouchType::Touch; | 92 | // Update if coordinates change |
| 81 | if (gesture.mid_point.x != last_entry.x || gesture.mid_point.y != last_entry.y) { | 93 | for (size_t id = 0; id < MAX_POINTS; id++) { |
| 82 | type = TouchType::Pan; | 94 | if (gesture.points[id].x != last_gesture.points[id].x || |
| 83 | } | 95 | gesture.points[id].y != last_gesture.points[id].y) { |
| 84 | if (std::abs(gesture.average_distance - last_gesture.average_distance) > pinch_threshold) { | 96 | return true; |
| 85 | type = TouchType::Pinch; | ||
| 86 | } | ||
| 87 | if (std::abs(gesture.angle - last_gesture.angle) > angle_threshold) { | ||
| 88 | type = TouchType::Rotate; | ||
| 89 | } | 97 | } |
| 98 | } | ||
| 99 | |||
| 100 | // Update on press and hold event after 0.5 seconds | ||
| 101 | if (last_entry.type == TouchType::Touch && last_entry.point_count == 1 && | ||
| 102 | time_difference > press_delay) { | ||
| 103 | return enable_press_and_tap; | ||
| 104 | } | ||
| 105 | |||
| 106 | return false; | ||
| 107 | } | ||
| 108 | |||
| 109 | void Controller_Gesture::UpdateGestureSharedMemory(u8* data, std::size_t size, | ||
| 110 | GestureProperties& gesture, | ||
| 111 | f32 time_difference) { | ||
| 112 | TouchType type = TouchType::Idle; | ||
| 113 | Attribute attributes{}; | ||
| 114 | |||
| 115 | const auto& last_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; | ||
| 116 | shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17; | ||
| 117 | auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; | ||
| 90 | 118 | ||
| 91 | cur_entry.delta_x = gesture.mid_point.x - last_entry.x; | 119 | if (shared_memory.header.entry_count < 16) { |
| 92 | cur_entry.delta_y = gesture.mid_point.y - last_entry.y; | 120 | shared_memory.header.entry_count++; |
| 93 | // TODO: Find how velocities are calculated | 121 | } |
| 94 | cur_entry.vel_x = static_cast<float>(cur_entry.delta_x) * 150.1f; | ||
| 95 | cur_entry.vel_y = static_cast<float>(cur_entry.delta_y) * 150.1f; | ||
| 96 | 122 | ||
| 97 | // Slowdown the rate of change for less flapping | 123 | cur_entry.sampling_number = last_entry.sampling_number + 1; |
| 98 | last_gesture.average_distance = | 124 | cur_entry.sampling_number2 = cur_entry.sampling_number; |
| 99 | (last_gesture.average_distance * 0.9f) + (gesture.average_distance * 0.1f); | ||
| 100 | last_gesture.angle = (last_gesture.angle * 0.9f) + (gesture.angle * 0.1f); | ||
| 101 | 125 | ||
| 126 | // Reset values to default | ||
| 127 | cur_entry.delta_x = 0; | ||
| 128 | cur_entry.delta_y = 0; | ||
| 129 | cur_entry.vel_x = 0; | ||
| 130 | cur_entry.vel_y = 0; | ||
| 131 | cur_entry.direction = Direction::None; | ||
| 132 | cur_entry.rotation_angle = 0; | ||
| 133 | cur_entry.scale = 0; | ||
| 134 | |||
| 135 | if (gesture.active_points > 0) { | ||
| 136 | if (last_gesture.active_points == 0) { | ||
| 137 | NewGesture(gesture, type, attributes); | ||
| 138 | } else { | ||
| 139 | UpdateExistingGesture(gesture, type, time_difference); | ||
| 140 | } | ||
| 102 | } else { | 141 | } else { |
| 103 | cur_entry.delta_x = 0; | 142 | EndGesture(gesture, last_gesture, type, attributes, time_difference); |
| 104 | cur_entry.delta_y = 0; | ||
| 105 | cur_entry.vel_x = 0; | ||
| 106 | cur_entry.vel_y = 0; | ||
| 107 | } | 143 | } |
| 108 | last_gesture.active_points = gesture.active_points; | 144 | |
| 109 | cur_entry.detection_count = last_gesture.detection_count; | 145 | // Apply attributes |
| 146 | cur_entry.detection_count = gesture.detection_count; | ||
| 110 | cur_entry.type = type; | 147 | cur_entry.type = type; |
| 111 | cur_entry.attributes = attributes; | 148 | cur_entry.attributes = attributes; |
| 112 | cur_entry.x = gesture.mid_point.x; | 149 | cur_entry.x = gesture.mid_point.x; |
| @@ -116,12 +153,190 @@ void Controller_Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing, u | |||
| 116 | cur_entry.points[id].x = gesture.points[id].x; | 153 | cur_entry.points[id].x = gesture.points[id].x; |
| 117 | cur_entry.points[id].y = gesture.points[id].y; | 154 | cur_entry.points[id].y = gesture.points[id].y; |
| 118 | } | 155 | } |
| 119 | cur_entry.rotation_angle = 0; | 156 | last_gesture = gesture; |
| 120 | cur_entry.scale = 0; | ||
| 121 | 157 | ||
| 122 | std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory)); | 158 | std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory)); |
| 123 | } | 159 | } |
| 124 | 160 | ||
| 161 | void Controller_Gesture::NewGesture(GestureProperties& gesture, TouchType& type, | ||
| 162 | Attribute& attributes) { | ||
| 163 | const auto& last_entry = | ||
| 164 | shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17]; | ||
| 165 | gesture.detection_count++; | ||
| 166 | type = TouchType::Touch; | ||
| 167 | |||
| 168 | // New touch after cancel is not considered new | ||
| 169 | if (last_entry.type != TouchType::Cancel) { | ||
| 170 | attributes.is_new_touch.Assign(1); | ||
| 171 | enable_press_and_tap = true; | ||
| 172 | } | ||
| 173 | } | ||
| 174 | |||
| 175 | void Controller_Gesture::UpdateExistingGesture(GestureProperties& gesture, TouchType& type, | ||
| 176 | f32 time_difference) { | ||
| 177 | const auto& last_entry = | ||
| 178 | shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17]; | ||
| 179 | |||
| 180 | // Promote to pan type if touch moved | ||
| 181 | for (size_t id = 0; id < MAX_POINTS; id++) { | ||
| 182 | if (gesture.points[id].x != last_gesture.points[id].x || | ||
| 183 | gesture.points[id].y != last_gesture.points[id].y) { | ||
| 184 | type = TouchType::Pan; | ||
| 185 | break; | ||
| 186 | } | ||
| 187 | } | ||
| 188 | |||
| 189 | // Number of fingers changed cancel the last event and clear data | ||
| 190 | if (gesture.active_points != last_gesture.active_points) { | ||
| 191 | type = TouchType::Cancel; | ||
| 192 | enable_press_and_tap = false; | ||
| 193 | gesture.active_points = 0; | ||
| 194 | gesture.mid_point = {}; | ||
| 195 | for (size_t id = 0; id < MAX_POINTS; id++) { | ||
| 196 | gesture.points[id].x = 0; | ||
| 197 | gesture.points[id].y = 0; | ||
| 198 | } | ||
| 199 | return; | ||
| 200 | } | ||
| 201 | |||
| 202 | // Calculate extra parameters of panning | ||
| 203 | if (type == TouchType::Pan) { | ||
| 204 | UpdatePanEvent(gesture, last_gesture, type, time_difference); | ||
| 205 | return; | ||
| 206 | } | ||
| 207 | |||
| 208 | // Promote to press type | ||
| 209 | if (last_entry.type == TouchType::Touch) { | ||
| 210 | type = TouchType::Press; | ||
| 211 | } | ||
| 212 | } | ||
| 213 | |||
| 214 | void Controller_Gesture::EndGesture(GestureProperties& gesture, GestureProperties& last_gesture, | ||
| 215 | TouchType& type, Attribute& attributes, f32 time_difference) { | ||
| 216 | const auto& last_entry = | ||
| 217 | shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17]; | ||
| 218 | if (last_gesture.active_points != 0) { | ||
| 219 | switch (last_entry.type) { | ||
| 220 | case TouchType::Touch: | ||
| 221 | if (enable_press_and_tap) { | ||
| 222 | SetTapEvent(gesture, last_gesture, type, attributes); | ||
| 223 | return; | ||
| 224 | } | ||
| 225 | type = TouchType::Cancel; | ||
| 226 | force_update = true; | ||
| 227 | break; | ||
| 228 | case TouchType::Press: | ||
| 229 | case TouchType::Tap: | ||
| 230 | case TouchType::Swipe: | ||
| 231 | case TouchType::Pinch: | ||
| 232 | case TouchType::Rotate: | ||
| 233 | type = TouchType::Complete; | ||
| 234 | force_update = true; | ||
| 235 | break; | ||
| 236 | case TouchType::Pan: | ||
| 237 | EndPanEvent(gesture, last_gesture, type, time_difference); | ||
| 238 | break; | ||
| 239 | default: | ||
| 240 | break; | ||
| 241 | } | ||
| 242 | return; | ||
| 243 | } | ||
| 244 | if (last_entry.type == TouchType::Complete || last_entry.type == TouchType::Cancel) { | ||
| 245 | gesture.detection_count++; | ||
| 246 | } | ||
| 247 | } | ||
| 248 | |||
| 249 | void Controller_Gesture::SetTapEvent(GestureProperties& gesture, GestureProperties& last_gesture, | ||
| 250 | TouchType& type, Attribute& attributes) { | ||
| 251 | type = TouchType::Tap; | ||
| 252 | gesture = last_gesture; | ||
| 253 | force_update = true; | ||
| 254 | f32 tap_time_difference = | ||
| 255 | static_cast<f32>(last_update_timestamp - last_tap_timestamp) / (1000 * 1000 * 1000); | ||
| 256 | last_tap_timestamp = last_update_timestamp; | ||
| 257 | if (tap_time_difference < double_tap_delay) { | ||
| 258 | attributes.is_double_tap.Assign(1); | ||
| 259 | } | ||
| 260 | } | ||
| 261 | |||
| 262 | void Controller_Gesture::UpdatePanEvent(GestureProperties& gesture, GestureProperties& last_gesture, | ||
| 263 | TouchType& type, f32 time_difference) { | ||
| 264 | auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; | ||
| 265 | const auto& last_entry = | ||
| 266 | shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17]; | ||
| 267 | cur_entry.delta_x = gesture.mid_point.x - last_entry.x; | ||
| 268 | cur_entry.delta_y = gesture.mid_point.y - last_entry.y; | ||
| 269 | |||
| 270 | cur_entry.vel_x = static_cast<f32>(cur_entry.delta_x) / time_difference; | ||
| 271 | cur_entry.vel_y = static_cast<f32>(cur_entry.delta_y) / time_difference; | ||
| 272 | last_pan_time_difference = time_difference; | ||
| 273 | |||
| 274 | // Promote to pinch type | ||
| 275 | if (std::abs(gesture.average_distance - last_gesture.average_distance) > pinch_threshold) { | ||
| 276 | type = TouchType::Pinch; | ||
| 277 | cur_entry.scale = gesture.average_distance / last_gesture.average_distance; | ||
| 278 | } | ||
| 279 | |||
| 280 | const f32 angle_between_two_lines = std::atan((gesture.angle - last_gesture.angle) / | ||
| 281 | (1 + (gesture.angle * last_gesture.angle))); | ||
| 282 | // Promote to rotate type | ||
| 283 | if (std::abs(angle_between_two_lines) > angle_threshold) { | ||
| 284 | type = TouchType::Rotate; | ||
| 285 | cur_entry.scale = 0; | ||
| 286 | cur_entry.rotation_angle = angle_between_two_lines * 180.0f / Common::PI; | ||
| 287 | } | ||
| 288 | } | ||
| 289 | |||
| 290 | void Controller_Gesture::EndPanEvent(GestureProperties& gesture, GestureProperties& last_gesture, | ||
| 291 | TouchType& type, f32 time_difference) { | ||
| 292 | auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; | ||
| 293 | const auto& last_entry = | ||
| 294 | shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17]; | ||
| 295 | cur_entry.vel_x = | ||
| 296 | static_cast<f32>(last_entry.delta_x) / (last_pan_time_difference + time_difference); | ||
| 297 | cur_entry.vel_y = | ||
| 298 | static_cast<f32>(last_entry.delta_y) / (last_pan_time_difference + time_difference); | ||
| 299 | const f32 curr_vel = | ||
| 300 | std::sqrt((cur_entry.vel_x * cur_entry.vel_x) + (cur_entry.vel_y * cur_entry.vel_y)); | ||
| 301 | |||
| 302 | // Set swipe event with parameters | ||
| 303 | if (curr_vel > swipe_threshold) { | ||
| 304 | SetSwipeEvent(gesture, last_gesture, type); | ||
| 305 | return; | ||
| 306 | } | ||
| 307 | |||
| 308 | // End panning without swipe | ||
| 309 | type = TouchType::Complete; | ||
| 310 | cur_entry.vel_x = 0; | ||
| 311 | cur_entry.vel_y = 0; | ||
| 312 | force_update = true; | ||
| 313 | } | ||
| 314 | |||
| 315 | void Controller_Gesture::SetSwipeEvent(GestureProperties& gesture, GestureProperties& last_gesture, | ||
| 316 | TouchType& type) { | ||
| 317 | auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; | ||
| 318 | const auto& last_entry = | ||
| 319 | shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17]; | ||
| 320 | type = TouchType::Swipe; | ||
| 321 | gesture = last_gesture; | ||
| 322 | force_update = true; | ||
| 323 | cur_entry.delta_x = last_entry.delta_x; | ||
| 324 | cur_entry.delta_y = last_entry.delta_y; | ||
| 325 | if (std::abs(cur_entry.delta_x) > std::abs(cur_entry.delta_y)) { | ||
| 326 | if (cur_entry.delta_x > 0) { | ||
| 327 | cur_entry.direction = Direction::Right; | ||
| 328 | return; | ||
| 329 | } | ||
| 330 | cur_entry.direction = Direction::Left; | ||
| 331 | return; | ||
| 332 | } | ||
| 333 | if (cur_entry.delta_y > 0) { | ||
| 334 | cur_entry.direction = Direction::Down; | ||
| 335 | return; | ||
| 336 | } | ||
| 337 | cur_entry.direction = Direction::Up; | ||
| 338 | } | ||
| 339 | |||
| 125 | void Controller_Gesture::OnLoadInputDevices() { | 340 | void Controller_Gesture::OnLoadInputDevices() { |
| 126 | touch_mouse_device = Input::CreateDevice<Input::TouchDevice>("engine:emu_window"); | 341 | touch_mouse_device = Input::CreateDevice<Input::TouchDevice>("engine:emu_window"); |
| 127 | touch_udp_device = Input::CreateDevice<Input::TouchDevice>("engine:cemuhookudp"); | 342 | touch_udp_device = Input::CreateDevice<Input::TouchDevice>("engine:cemuhookudp"); |
| @@ -183,23 +398,33 @@ Controller_Gesture::GestureProperties Controller_Gesture::GetGestureProperties() | |||
| 183 | 398 | ||
| 184 | for (size_t id = 0; id < gesture.active_points; ++id) { | 399 | for (size_t id = 0; id < gesture.active_points; ++id) { |
| 185 | gesture.points[id].x = | 400 | gesture.points[id].x = |
| 186 | static_cast<int>(active_fingers[id].x * Layout::ScreenUndocked::Width); | 401 | static_cast<s32>(active_fingers[id].x * Layout::ScreenUndocked::Width); |
| 187 | gesture.points[id].y = | 402 | gesture.points[id].y = |
| 188 | static_cast<int>(active_fingers[id].y * Layout::ScreenUndocked::Height); | 403 | static_cast<s32>(active_fingers[id].y * Layout::ScreenUndocked::Height); |
| 189 | gesture.mid_point.x += static_cast<int>(gesture.points[id].x / gesture.active_points); | 404 | |
| 190 | gesture.mid_point.y += static_cast<int>(gesture.points[id].y / gesture.active_points); | 405 | // Hack: There is no touch in docked but games still allow it |
| 406 | if (Settings::values.use_docked_mode.GetValue()) { | ||
| 407 | gesture.points[id].x = | ||
| 408 | static_cast<s32>(active_fingers[id].x * Layout::ScreenDocked::Width); | ||
| 409 | gesture.points[id].y = | ||
| 410 | static_cast<s32>(active_fingers[id].y * Layout::ScreenDocked::Height); | ||
| 411 | } | ||
| 412 | |||
| 413 | gesture.mid_point.x += static_cast<s32>(gesture.points[id].x / gesture.active_points); | ||
| 414 | gesture.mid_point.y += static_cast<s32>(gesture.points[id].y / gesture.active_points); | ||
| 191 | } | 415 | } |
| 192 | 416 | ||
| 193 | for (size_t id = 0; id < gesture.active_points; ++id) { | 417 | for (size_t id = 0; id < gesture.active_points; ++id) { |
| 194 | const double distance = | 418 | const f32 distance = std::sqrt(Square(gesture.mid_point.x - gesture.points[id].x) + |
| 195 | std::pow(static_cast<float>(gesture.mid_point.x - gesture.points[id].x), 2) + | 419 | Square(gesture.mid_point.y - gesture.points[id].y)); |
| 196 | std::pow(static_cast<float>(gesture.mid_point.y - gesture.points[id].y), 2); | 420 | gesture.average_distance += distance / static_cast<f32>(gesture.active_points); |
| 197 | gesture.average_distance += | ||
| 198 | static_cast<float>(distance) / static_cast<float>(gesture.active_points); | ||
| 199 | } | 421 | } |
| 200 | 422 | ||
| 201 | gesture.angle = std::atan2(static_cast<float>(gesture.mid_point.y - gesture.points[0].y), | 423 | gesture.angle = std::atan2(static_cast<f32>(gesture.mid_point.y - gesture.points[0].y), |
| 202 | static_cast<float>(gesture.mid_point.x - gesture.points[0].x)); | 424 | static_cast<f32>(gesture.mid_point.x - gesture.points[0].x)); |
| 425 | |||
| 426 | gesture.detection_count = last_gesture.detection_count; | ||
| 427 | |||
| 203 | return gesture; | 428 | return gesture; |
| 204 | } | 429 | } |
| 205 | 430 | ||
diff --git a/src/core/hle/service/hid/controllers/gesture.h b/src/core/hle/service/hid/controllers/gesture.h index 7c357b977..18110a6ad 100644 --- a/src/core/hle/service/hid/controllers/gesture.h +++ b/src/core/hle/service/hid/controllers/gesture.h | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | 1 | // Copyright 2021 yuzu Emulator Project |
| 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 | ||
| @@ -7,7 +7,6 @@ | |||
| 7 | #include <array> | 7 | #include <array> |
| 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/swap.h" | ||
| 11 | #include "core/frontend/input.h" | 10 | #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" |
| 13 | 12 | ||
| @@ -35,10 +34,10 @@ private: | |||
| 35 | 34 | ||
| 36 | enum class TouchType : u32 { | 35 | enum class TouchType : u32 { |
| 37 | Idle, // Nothing touching the screen | 36 | Idle, // Nothing touching the screen |
| 38 | Complete, // Unknown. End of touch? | 37 | Complete, // Set at the end of a touch event |
| 39 | Cancel, // Never triggered | 38 | Cancel, // Set when the number of fingers change |
| 40 | Touch, // Pressing without movement | 39 | Touch, // A finger just touched the screen |
| 41 | Press, // Never triggered | 40 | Press, // Set if last type is touch and the finger hasn't moved |
| 42 | Tap, // Fast press then release | 41 | Tap, // Fast press then release |
| 43 | Pan, // All points moving together across the screen | 42 | Pan, // All points moving together across the screen |
| 44 | Swipe, // Fast press movement and release of a single point | 43 | Swipe, // Fast press movement and release of a single point |
| @@ -58,8 +57,8 @@ private: | |||
| 58 | union { | 57 | union { |
| 59 | u32_le raw{}; | 58 | u32_le raw{}; |
| 60 | 59 | ||
| 61 | BitField<0, 1, u32> is_new_touch; | 60 | BitField<4, 1, u32> is_new_touch; |
| 62 | BitField<1, 1, u32> is_double_tap; | 61 | BitField<8, 1, u32> is_double_tap; |
| 63 | }; | 62 | }; |
| 64 | }; | 63 | }; |
| 65 | static_assert(sizeof(Attribute) == 4, "Attribute is an invalid size"); | 64 | static_assert(sizeof(Attribute) == 4, "Attribute is an invalid size"); |
| @@ -73,10 +72,9 @@ private: | |||
| 73 | struct GestureState { | 72 | struct GestureState { |
| 74 | s64_le sampling_number; | 73 | s64_le sampling_number; |
| 75 | s64_le sampling_number2; | 74 | s64_le sampling_number2; |
| 76 | |||
| 77 | s64_le detection_count; | 75 | s64_le detection_count; |
| 78 | TouchType type; | 76 | TouchType type; |
| 79 | Direction dir; | 77 | Direction direction; |
| 80 | s32_le x; | 78 | s32_le x; |
| 81 | s32_le y; | 79 | s32_le y; |
| 82 | s32_le delta_x; | 80 | s32_le delta_x; |
| @@ -84,8 +82,8 @@ private: | |||
| 84 | f32 vel_x; | 82 | f32 vel_x; |
| 85 | f32 vel_y; | 83 | f32 vel_y; |
| 86 | Attribute attributes; | 84 | Attribute attributes; |
| 87 | u32 scale; | 85 | f32 scale; |
| 88 | u32 rotation_angle; | 86 | f32 rotation_angle; |
| 89 | s32_le point_count; | 87 | s32_le point_count; |
| 90 | std::array<Points, 4> points; | 88 | std::array<Points, 4> points; |
| 91 | }; | 89 | }; |
| @@ -109,10 +107,46 @@ private: | |||
| 109 | Points mid_point{}; | 107 | Points mid_point{}; |
| 110 | s64_le detection_count{}; | 108 | s64_le detection_count{}; |
| 111 | u64_le delta_time{}; | 109 | u64_le delta_time{}; |
| 112 | float average_distance{}; | 110 | f32 average_distance{}; |
| 113 | float angle{}; | 111 | f32 angle{}; |
| 114 | }; | 112 | }; |
| 115 | 113 | ||
| 114 | // Reads input from all available input engines | ||
| 115 | void ReadTouchInput(); | ||
| 116 | |||
| 117 | // Returns true if gesture state needs to be updated | ||
| 118 | bool ShouldUpdateGesture(const GestureProperties& gesture, f32 time_difference); | ||
| 119 | |||
| 120 | // Updates the shared memory to the next state | ||
| 121 | void UpdateGestureSharedMemory(u8* data, std::size_t size, GestureProperties& gesture, | ||
| 122 | f32 time_difference); | ||
| 123 | |||
| 124 | // Initializes new gesture | ||
| 125 | void NewGesture(GestureProperties& gesture, TouchType& type, Attribute& attributes); | ||
| 126 | |||
| 127 | // Updates existing gesture state | ||
| 128 | void UpdateExistingGesture(GestureProperties& gesture, TouchType& type, f32 time_difference); | ||
| 129 | |||
| 130 | // Terminates exiting gesture | ||
| 131 | void EndGesture(GestureProperties& gesture, GestureProperties& last_gesture, TouchType& type, | ||
| 132 | Attribute& attributes, f32 time_difference); | ||
| 133 | |||
| 134 | // Set current event to a tap event | ||
| 135 | void SetTapEvent(GestureProperties& gesture, GestureProperties& last_gesture, TouchType& type, | ||
| 136 | Attribute& attributes); | ||
| 137 | |||
| 138 | // Calculates and set the extra parameters related to a pan event | ||
| 139 | void UpdatePanEvent(GestureProperties& gesture, GestureProperties& last_gesture, | ||
| 140 | TouchType& type, f32 time_difference); | ||
| 141 | |||
| 142 | // Terminates the pan event | ||
| 143 | void EndPanEvent(GestureProperties& gesture, GestureProperties& last_gesture, TouchType& type, | ||
| 144 | f32 time_difference); | ||
| 145 | |||
| 146 | // Set current event to a swipe event | ||
| 147 | void SetSwipeEvent(GestureProperties& gesture, GestureProperties& last_gesture, | ||
| 148 | TouchType& type); | ||
| 149 | |||
| 116 | // Returns an unused finger id, if there is no fingers avaliable MAX_FINGERS will be returned | 150 | // Returns an unused finger id, if there is no fingers avaliable MAX_FINGERS will be returned |
| 117 | std::optional<size_t> GetUnusedFingerID() const; | 151 | std::optional<size_t> GetUnusedFingerID() const; |
| 118 | 152 | ||
| @@ -134,6 +168,11 @@ private: | |||
| 134 | std::array<size_t, MAX_FINGERS> keyboard_finger_id; | 168 | std::array<size_t, MAX_FINGERS> keyboard_finger_id; |
| 135 | std::array<size_t, MAX_FINGERS> udp_finger_id; | 169 | std::array<size_t, MAX_FINGERS> udp_finger_id; |
| 136 | std::array<Finger, MAX_POINTS> fingers; | 170 | std::array<Finger, MAX_POINTS> fingers; |
| 137 | GestureProperties last_gesture; | 171 | GestureProperties last_gesture{}; |
| 172 | s64_le last_update_timestamp{}; | ||
| 173 | s64_le last_tap_timestamp{}; | ||
| 174 | f32 last_pan_time_difference{}; | ||
| 175 | bool force_update{false}; | ||
| 176 | bool enable_press_and_tap{false}; | ||
| 138 | }; | 177 | }; |
| 139 | } // namespace Service::HID | 178 | } // namespace Service::HID |
diff --git a/src/core/hle/service/ssl/ssl.cpp b/src/core/hle/service/ssl/ssl.cpp index dc2baca4a..2c8899ae0 100644 --- a/src/core/hle/service/ssl/ssl.cpp +++ b/src/core/hle/service/ssl/ssl.cpp | |||
| @@ -10,6 +10,11 @@ | |||
| 10 | 10 | ||
| 11 | namespace Service::SSL { | 11 | namespace Service::SSL { |
| 12 | 12 | ||
| 13 | enum class CertificateFormat : u32 { | ||
| 14 | Pem = 1, | ||
| 15 | Der = 2, | ||
| 16 | }; | ||
| 17 | |||
| 13 | class ISslConnection final : public ServiceFramework<ISslConnection> { | 18 | class ISslConnection final : public ServiceFramework<ISslConnection> { |
| 14 | public: | 19 | public: |
| 15 | explicit ISslConnection(Core::System& system_) : ServiceFramework{system_, "ISslConnection"} { | 20 | explicit ISslConnection(Core::System& system_) : ServiceFramework{system_, "ISslConnection"} { |
| @@ -58,8 +63,8 @@ public: | |||
| 58 | {1, nullptr, "GetOption"}, | 63 | {1, nullptr, "GetOption"}, |
| 59 | {2, &ISslContext::CreateConnection, "CreateConnection"}, | 64 | {2, &ISslContext::CreateConnection, "CreateConnection"}, |
| 60 | {3, nullptr, "GetConnectionCount"}, | 65 | {3, nullptr, "GetConnectionCount"}, |
| 61 | {4, nullptr, "ImportServerPki"}, | 66 | {4, &ISslContext::ImportServerPki, "ImportServerPki"}, |
| 62 | {5, nullptr, "ImportClientPki"}, | 67 | {5, &ISslContext::ImportClientPki, "ImportClientPki"}, |
| 63 | {6, nullptr, "RemoveServerPki"}, | 68 | {6, nullptr, "RemoveServerPki"}, |
| 64 | {7, nullptr, "RemoveClientPki"}, | 69 | {7, nullptr, "RemoveClientPki"}, |
| 65 | {8, nullptr, "RegisterInternalPki"}, | 70 | {8, nullptr, "RegisterInternalPki"}, |
| @@ -94,6 +99,39 @@ private: | |||
| 94 | rb.Push(RESULT_SUCCESS); | 99 | rb.Push(RESULT_SUCCESS); |
| 95 | rb.PushIpcInterface<ISslConnection>(system); | 100 | rb.PushIpcInterface<ISslConnection>(system); |
| 96 | } | 101 | } |
| 102 | |||
| 103 | void ImportServerPki(Kernel::HLERequestContext& ctx) { | ||
| 104 | IPC::RequestParser rp{ctx}; | ||
| 105 | const auto certificate_format = rp.PopEnum<CertificateFormat>(); | ||
| 106 | const auto pkcs_12_certificates = ctx.ReadBuffer(0); | ||
| 107 | |||
| 108 | constexpr u64 server_id = 0; | ||
| 109 | |||
| 110 | LOG_WARNING(Service_SSL, "(STUBBED) called, certificate_format={}", certificate_format); | ||
| 111 | |||
| 112 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 113 | rb.Push(RESULT_SUCCESS); | ||
| 114 | rb.Push(server_id); | ||
| 115 | } | ||
| 116 | |||
| 117 | void ImportClientPki(Kernel::HLERequestContext& ctx) { | ||
| 118 | const auto pkcs_12_certificate = ctx.ReadBuffer(0); | ||
| 119 | const auto ascii_password = [&ctx] { | ||
| 120 | if (ctx.CanReadBuffer(1)) { | ||
| 121 | return ctx.ReadBuffer(1); | ||
| 122 | } | ||
| 123 | |||
| 124 | return std::vector<u8>{}; | ||
| 125 | }(); | ||
| 126 | |||
| 127 | constexpr u64 client_id = 0; | ||
| 128 | |||
| 129 | LOG_WARNING(Service_SSL, "(STUBBED) called"); | ||
| 130 | |||
| 131 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 132 | rb.Push(RESULT_SUCCESS); | ||
| 133 | rb.Push(client_id); | ||
| 134 | } | ||
| 97 | }; | 135 | }; |
| 98 | 136 | ||
| 99 | class SSL final : public ServiceFramework<SSL> { | 137 | class SSL final : public ServiceFramework<SSL> { |
diff --git a/src/yuzu/configuration/configure_ui.cpp b/src/yuzu/configuration/configure_ui.cpp index f35c89e04..0cdaea8a4 100644 --- a/src/yuzu/configuration/configure_ui.cpp +++ b/src/yuzu/configuration/configure_ui.cpp | |||
| @@ -46,6 +46,7 @@ ConfigureUi::ConfigureUi(QWidget* parent) : QWidget(parent), ui(new Ui::Configur | |||
| 46 | SetConfiguration(); | 46 | SetConfiguration(); |
| 47 | 47 | ||
| 48 | // Force game list reload if any of the relevant settings are changed. | 48 | // Force game list reload if any of the relevant settings are changed. |
| 49 | connect(ui->show_add_ons, &QCheckBox::stateChanged, this, &ConfigureUi::RequestGameListUpdate); | ||
| 49 | connect(ui->icon_size_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, | 50 | connect(ui->icon_size_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, |
| 50 | &ConfigureUi::RequestGameListUpdate); | 51 | &ConfigureUi::RequestGameListUpdate); |
| 51 | connect(ui->row_1_text_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, | 52 | connect(ui->row_1_text_combobox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, |