gesture.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. // Copyright 2021 yuzu Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include "common/logging/log.h"
  5. #include "common/math_util.h"
  6. #include "common/settings.h"
  7. #include "core/core.h"
  8. #include "core/core_timing.h"
  9. #include "core/frontend/emu_window.h"
  10. #include "core/hid/hid_core.h"
  11. #include "core/hle/service/hid/controllers/gesture.h"
  12. namespace Service::HID {
  13. constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3BA00;
  14. // HW is around 700, value is set to 400 to make it easier to trigger with mouse
  15. constexpr f32 swipe_threshold = 400.0f; // Threshold in pixels/s
  16. constexpr f32 angle_threshold = 0.015f; // Threshold in radians
  17. constexpr f32 pinch_threshold = 0.5f; // Threshold in pixels
  18. constexpr f32 press_delay = 0.5f; // Time in seconds
  19. constexpr f32 double_tap_delay = 0.35f; // Time in seconds
  20. constexpr f32 Square(s32 num) {
  21. return static_cast<f32>(num * num);
  22. }
  23. Controller_Gesture::Controller_Gesture(Core::System& system_) : ControllerBase(system_) {
  24. console = system.HIDCore().GetEmulatedConsole();
  25. }
  26. Controller_Gesture::~Controller_Gesture() = default;
  27. void Controller_Gesture::OnInit() {
  28. gesture_lifo.entry_count = 0;
  29. gesture_lifo.last_entry_index = 0;
  30. force_update = true;
  31. }
  32. void Controller_Gesture::OnRelease() {}
  33. void Controller_Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
  34. std::size_t size) {
  35. if (!IsControllerActivated()) {
  36. gesture_lifo.entry_count = 0;
  37. gesture_lifo.last_entry_index = 0;
  38. std::memcpy(data + SHARED_MEMORY_OFFSET, &gesture_lifo, sizeof(gesture_lifo));
  39. return;
  40. }
  41. ReadTouchInput();
  42. GestureProperties gesture = GetGestureProperties();
  43. f32 time_difference =
  44. static_cast<f32>(gesture_lifo.timestamp - last_update_timestamp) / (1000 * 1000 * 1000);
  45. // Only update if necesary
  46. if (!ShouldUpdateGesture(gesture, time_difference)) {
  47. return;
  48. }
  49. last_update_timestamp = gesture_lifo.timestamp;
  50. UpdateGestureSharedMemory(data, size, gesture, time_difference);
  51. }
  52. void Controller_Gesture::ReadTouchInput() {
  53. const auto touch_status = console->GetTouch();
  54. for (std::size_t id = 0; id < fingers.size(); ++id) {
  55. fingers[id] = touch_status[id];
  56. }
  57. }
  58. bool Controller_Gesture::ShouldUpdateGesture(const GestureProperties& gesture,
  59. f32 time_difference) {
  60. const auto& last_entry = GetLastGestureEntry();
  61. if (force_update) {
  62. force_update = false;
  63. return true;
  64. }
  65. // Update if coordinates change
  66. for (size_t id = 0; id < MAX_POINTS; id++) {
  67. if (gesture.points[id] != last_gesture.points[id]) {
  68. return true;
  69. }
  70. }
  71. // Update on press and hold event after 0.5 seconds
  72. if (last_entry.type == GestureType::Touch && last_entry.point_count == 1 &&
  73. time_difference > press_delay) {
  74. return enable_press_and_tap;
  75. }
  76. return false;
  77. }
  78. void Controller_Gesture::UpdateGestureSharedMemory(u8* data, std::size_t size,
  79. GestureProperties& gesture,
  80. f32 time_difference) {
  81. GestureType type = GestureType::Idle;
  82. GestureAttribute attributes{};
  83. const auto& last_entry = gesture_lifo.ReadCurrentEntry().state;
  84. // Reset next state to default
  85. next_state.sampling_number = last_entry.sampling_number + 1;
  86. next_state.delta = {};
  87. next_state.vel_x = 0;
  88. next_state.vel_y = 0;
  89. next_state.direction = GestureDirection::None;
  90. next_state.rotation_angle = 0;
  91. next_state.scale = 0;
  92. if (gesture.active_points > 0) {
  93. if (last_gesture.active_points == 0) {
  94. NewGesture(gesture, type, attributes);
  95. } else {
  96. UpdateExistingGesture(gesture, type, time_difference);
  97. }
  98. } else {
  99. EndGesture(gesture, last_gesture, type, attributes, time_difference);
  100. }
  101. // Apply attributes
  102. next_state.detection_count = gesture.detection_count;
  103. next_state.type = type;
  104. next_state.attributes = attributes;
  105. next_state.pos = gesture.mid_point;
  106. next_state.point_count = static_cast<s32>(gesture.active_points);
  107. next_state.points = gesture.points;
  108. last_gesture = gesture;
  109. gesture_lifo.WriteNextEntry(next_state);
  110. std::memcpy(data + SHARED_MEMORY_OFFSET, &gesture_lifo, sizeof(gesture_lifo));
  111. }
  112. void Controller_Gesture::NewGesture(GestureProperties& gesture, GestureType& type,
  113. GestureAttribute& attributes) {
  114. const auto& last_entry = GetLastGestureEntry();
  115. gesture.detection_count++;
  116. type = GestureType::Touch;
  117. // New touch after cancel is not considered new
  118. if (last_entry.type != GestureType::Cancel) {
  119. attributes.is_new_touch.Assign(1);
  120. enable_press_and_tap = true;
  121. }
  122. }
  123. void Controller_Gesture::UpdateExistingGesture(GestureProperties& gesture, GestureType& type,
  124. f32 time_difference) {
  125. const auto& last_entry = GetLastGestureEntry();
  126. // Promote to pan type if touch moved
  127. for (size_t id = 0; id < MAX_POINTS; id++) {
  128. if (gesture.points[id] != last_gesture.points[id]) {
  129. type = GestureType::Pan;
  130. break;
  131. }
  132. }
  133. // Number of fingers changed cancel the last event and clear data
  134. if (gesture.active_points != last_gesture.active_points) {
  135. type = GestureType::Cancel;
  136. enable_press_and_tap = false;
  137. gesture.active_points = 0;
  138. gesture.mid_point = {};
  139. gesture.points.fill({});
  140. return;
  141. }
  142. // Calculate extra parameters of panning
  143. if (type == GestureType::Pan) {
  144. UpdatePanEvent(gesture, last_gesture, type, time_difference);
  145. return;
  146. }
  147. // Promote to press type
  148. if (last_entry.type == GestureType::Touch) {
  149. type = GestureType::Press;
  150. }
  151. }
  152. void Controller_Gesture::EndGesture(GestureProperties& gesture,
  153. GestureProperties& last_gesture_props, GestureType& type,
  154. GestureAttribute& attributes, f32 time_difference) {
  155. const auto& last_entry = GetLastGestureEntry();
  156. if (last_gesture_props.active_points != 0) {
  157. switch (last_entry.type) {
  158. case GestureType::Touch:
  159. if (enable_press_and_tap) {
  160. SetTapEvent(gesture, last_gesture_props, type, attributes);
  161. return;
  162. }
  163. type = GestureType::Cancel;
  164. force_update = true;
  165. break;
  166. case GestureType::Press:
  167. case GestureType::Tap:
  168. case GestureType::Swipe:
  169. case GestureType::Pinch:
  170. case GestureType::Rotate:
  171. type = GestureType::Complete;
  172. force_update = true;
  173. break;
  174. case GestureType::Pan:
  175. EndPanEvent(gesture, last_gesture_props, type, time_difference);
  176. break;
  177. default:
  178. break;
  179. }
  180. return;
  181. }
  182. if (last_entry.type == GestureType::Complete || last_entry.type == GestureType::Cancel) {
  183. gesture.detection_count++;
  184. }
  185. }
  186. void Controller_Gesture::SetTapEvent(GestureProperties& gesture,
  187. GestureProperties& last_gesture_props, GestureType& type,
  188. GestureAttribute& attributes) {
  189. type = GestureType::Tap;
  190. gesture = last_gesture_props;
  191. force_update = true;
  192. f32 tap_time_difference =
  193. static_cast<f32>(last_update_timestamp - last_tap_timestamp) / (1000 * 1000 * 1000);
  194. last_tap_timestamp = last_update_timestamp;
  195. if (tap_time_difference < double_tap_delay) {
  196. attributes.is_double_tap.Assign(1);
  197. }
  198. }
  199. void Controller_Gesture::UpdatePanEvent(GestureProperties& gesture,
  200. GestureProperties& last_gesture_props, GestureType& type,
  201. f32 time_difference) {
  202. const auto& last_entry = GetLastGestureEntry();
  203. next_state.delta = gesture.mid_point - last_entry.pos;
  204. next_state.vel_x = static_cast<f32>(next_state.delta.x) / time_difference;
  205. next_state.vel_y = static_cast<f32>(next_state.delta.y) / time_difference;
  206. last_pan_time_difference = time_difference;
  207. // Promote to pinch type
  208. if (std::abs(gesture.average_distance - last_gesture_props.average_distance) >
  209. pinch_threshold) {
  210. type = GestureType::Pinch;
  211. next_state.scale = gesture.average_distance / last_gesture_props.average_distance;
  212. }
  213. const f32 angle_between_two_lines = std::atan((gesture.angle - last_gesture_props.angle) /
  214. (1 + (gesture.angle * last_gesture_props.angle)));
  215. // Promote to rotate type
  216. if (std::abs(angle_between_two_lines) > angle_threshold) {
  217. type = GestureType::Rotate;
  218. next_state.scale = 0;
  219. next_state.rotation_angle = angle_between_two_lines * 180.0f / Common::PI;
  220. }
  221. }
  222. void Controller_Gesture::EndPanEvent(GestureProperties& gesture,
  223. GestureProperties& last_gesture_props, GestureType& type,
  224. f32 time_difference) {
  225. const auto& last_entry = GetLastGestureEntry();
  226. next_state.vel_x =
  227. static_cast<f32>(last_entry.delta.x) / (last_pan_time_difference + time_difference);
  228. next_state.vel_y =
  229. static_cast<f32>(last_entry.delta.y) / (last_pan_time_difference + time_difference);
  230. const f32 curr_vel =
  231. std::sqrt((next_state.vel_x * next_state.vel_x) + (next_state.vel_y * next_state.vel_y));
  232. // Set swipe event with parameters
  233. if (curr_vel > swipe_threshold) {
  234. SetSwipeEvent(gesture, last_gesture_props, type);
  235. return;
  236. }
  237. // End panning without swipe
  238. type = GestureType::Complete;
  239. next_state.vel_x = 0;
  240. next_state.vel_y = 0;
  241. force_update = true;
  242. }
  243. void Controller_Gesture::SetSwipeEvent(GestureProperties& gesture,
  244. GestureProperties& last_gesture_props, GestureType& type) {
  245. const auto& last_entry = GetLastGestureEntry();
  246. type = GestureType::Swipe;
  247. gesture = last_gesture_props;
  248. force_update = true;
  249. next_state.delta = last_entry.delta;
  250. if (std::abs(next_state.delta.x) > std::abs(next_state.delta.y)) {
  251. if (next_state.delta.x > 0) {
  252. next_state.direction = GestureDirection::Right;
  253. return;
  254. }
  255. next_state.direction = GestureDirection::Left;
  256. return;
  257. }
  258. if (next_state.delta.y > 0) {
  259. next_state.direction = GestureDirection::Down;
  260. return;
  261. }
  262. next_state.direction = GestureDirection::Up;
  263. }
  264. const Controller_Gesture::GestureState& Controller_Gesture::GetLastGestureEntry() const {
  265. return gesture_lifo.ReadCurrentEntry().state;
  266. }
  267. Controller_Gesture::GestureProperties Controller_Gesture::GetGestureProperties() {
  268. GestureProperties gesture;
  269. std::array<Core::HID::TouchFinger, MAX_POINTS> active_fingers;
  270. const auto end_iter = std::copy_if(fingers.begin(), fingers.end(), active_fingers.begin(),
  271. [](const auto& finger) { return finger.pressed; });
  272. gesture.active_points =
  273. static_cast<std::size_t>(std::distance(active_fingers.begin(), end_iter));
  274. for (size_t id = 0; id < gesture.active_points; ++id) {
  275. const auto& [active_x, active_y] = active_fingers[id].position;
  276. gesture.points[id] = {
  277. .x = static_cast<s32>(active_x * Layout::ScreenUndocked::Width),
  278. .y = static_cast<s32>(active_y * Layout::ScreenUndocked::Height),
  279. };
  280. // Hack: There is no touch in docked but games still allow it
  281. if (Settings::values.use_docked_mode.GetValue()) {
  282. gesture.points[id] = {
  283. .x = static_cast<s32>(active_x * Layout::ScreenDocked::Width),
  284. .y = static_cast<s32>(active_y * Layout::ScreenDocked::Height),
  285. };
  286. }
  287. gesture.mid_point.x += static_cast<s32>(gesture.points[id].x / gesture.active_points);
  288. gesture.mid_point.y += static_cast<s32>(gesture.points[id].y / gesture.active_points);
  289. }
  290. for (size_t id = 0; id < gesture.active_points; ++id) {
  291. const f32 distance = std::sqrt(Square(gesture.mid_point.x - gesture.points[id].x) +
  292. Square(gesture.mid_point.y - gesture.points[id].y));
  293. gesture.average_distance += distance / static_cast<f32>(gesture.active_points);
  294. }
  295. gesture.angle = std::atan2(static_cast<f32>(gesture.mid_point.y - gesture.points[0].y),
  296. static_cast<f32>(gesture.mid_point.x - gesture.points[0].x));
  297. gesture.detection_count = last_gesture.detection_count;
  298. return gesture;
  299. }
  300. } // namespace Service::HID