event_utils.cc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379
  1. // Copyright (c) 2012 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "ui/events/event_utils.h"
  5. #include <limits>
  6. #include <map>
  7. #include <vector>
  8. #include "base/check.h"
  9. #include "base/metrics/histogram_macros.h"
  10. #include "base/notreached.h"
  11. #include "base/time/time.h"
  12. #include "base/trace_event/trace_id_helper.h"
  13. #include "base/trace_event/typed_macros.h"
  14. #include "build/build_config.h"
  15. #include "third_party/perfetto/include/perfetto/tracing/string_helpers.h"
  16. #include "third_party/perfetto/include/perfetto/tracing/track.h"
  17. #include "ui/display/display.h"
  18. #include "ui/display/screen.h"
  19. #include "ui/events/base_event_utils.h"
  20. #if BUILDFLAG(IS_WIN)
  21. #include <windows.h>
  22. #include "ui/events/win/events_win_utils.h"
  23. #endif
  24. namespace ui {
  25. namespace {
  26. int g_custom_event_types = ET_LAST;
  27. #define UMA_HISTOGRAM_EVENT_LATENCY_TIMES(name, sample) \
  28. UMA_HISTOGRAM_CUSTOM_TIMES(name, sample, base::Milliseconds(1), \
  29. base::Minutes(1), 50)
  30. // Record a trace if the `current_time` - `time_stamp` is above a threshold.
  31. // `name` must be a static string so that the trace is not privacy filtered.
  32. void RecordEventLatencyTrace(perfetto::StaticString name,
  33. base::TimeTicks time_stamp,
  34. base::TimeTicks current_time) {
  35. // 20 msec will catch the 90th percentile of most events on most platforms,
  36. // the 95th percentile of a few (eg. touch events on Windows, mouse events on
  37. // Mac).
  38. constexpr base::TimeDelta kMinJank = base::Milliseconds(20);
  39. if (current_time - time_stamp >= kMinJank) {
  40. // Nest the event in the current process, using the global trace id only for
  41. // uniqueness.
  42. const perfetto::Track track(base::trace_event::GetNextGlobalTraceId(),
  43. perfetto::ProcessTrack::Current());
  44. TRACE_EVENT_BEGIN("latency", name, track, time_stamp);
  45. TRACE_EVENT_END("latency", track, current_time);
  46. }
  47. }
  48. } // namespace
  49. std::unique_ptr<Event> EventFromNative(const PlatformEvent& native_event) {
  50. std::unique_ptr<Event> event;
  51. EventType type = EventTypeFromNative(native_event);
  52. switch(type) {
  53. case ET_KEY_PRESSED:
  54. case ET_KEY_RELEASED:
  55. event = std::make_unique<KeyEvent>(native_event);
  56. break;
  57. case ET_MOUSE_PRESSED:
  58. case ET_MOUSE_DRAGGED:
  59. case ET_MOUSE_RELEASED:
  60. case ET_MOUSE_MOVED:
  61. case ET_MOUSE_ENTERED:
  62. case ET_MOUSE_EXITED:
  63. event = std::make_unique<MouseEvent>(native_event);
  64. break;
  65. case ET_MOUSEWHEEL:
  66. event = std::make_unique<MouseWheelEvent>(native_event);
  67. break;
  68. case ET_SCROLL_FLING_START:
  69. case ET_SCROLL_FLING_CANCEL:
  70. case ET_SCROLL:
  71. event = std::make_unique<ScrollEvent>(native_event);
  72. break;
  73. case ET_TOUCH_RELEASED:
  74. case ET_TOUCH_PRESSED:
  75. case ET_TOUCH_MOVED:
  76. case ET_TOUCH_CANCELLED:
  77. event = std::make_unique<TouchEvent>(native_event);
  78. break;
  79. default:
  80. break;
  81. }
  82. return event;
  83. }
  84. int RegisterCustomEventType() {
  85. return ++g_custom_event_types;
  86. }
  87. bool ShouldDefaultToNaturalScroll() {
  88. return GetInternalDisplayTouchSupport() ==
  89. display::Display::TouchSupport::AVAILABLE;
  90. }
  91. display::Display::TouchSupport GetInternalDisplayTouchSupport() {
  92. display::Screen* screen = display::Screen::GetScreen();
  93. // No screen in some unit tests.
  94. if (!screen)
  95. return display::Display::TouchSupport::UNKNOWN;
  96. const std::vector<display::Display>& displays = screen->GetAllDisplays();
  97. for (auto it = displays.begin(); it != displays.end(); ++it) {
  98. if (it->IsInternal())
  99. return it->touch_support();
  100. }
  101. return display::Display::TouchSupport::UNAVAILABLE;
  102. }
  103. void ComputeEventLatencyOS(const PlatformEvent& native_event) {
  104. base::TimeTicks current_time = EventTimeForNow();
  105. base::TimeTicks time_stamp =
  106. EventLatencyTimeFromNative(native_event, current_time);
  107. EventType type = EventTypeFromNative(native_event);
  108. ComputeEventLatencyOS(type, time_stamp, current_time);
  109. }
  110. void ComputeEventLatencyOS(EventType type,
  111. base::TimeTicks time_stamp,
  112. base::TimeTicks current_time) {
  113. base::TimeDelta delta = current_time - time_stamp;
  114. switch (type) {
  115. #if BUILDFLAG(IS_APPLE)
  116. // On Mac, ET_SCROLL and ET_MOUSEWHEEL represent the same class of events.
  117. case ET_SCROLL:
  118. #endif
  119. case ET_MOUSEWHEEL:
  120. UMA_HISTOGRAM_EVENT_LATENCY_TIMES("Event.Latency.OS2.MOUSE_WHEEL", delta);
  121. // Do not record traces for wheel events to avoid spam.
  122. return;
  123. case ET_TOUCH_MOVED:
  124. UMA_HISTOGRAM_EVENT_LATENCY_TIMES("Event.Latency.OS2.TOUCH_MOVED", delta);
  125. // Do not record traces for move events to avoid spam.
  126. return;
  127. case ET_TOUCH_PRESSED:
  128. UMA_HISTOGRAM_EVENT_LATENCY_TIMES("Event.Latency.OS2.TOUCH_PRESSED",
  129. delta);
  130. RecordEventLatencyTrace("InputEventLatency.TOUCH_PRESSED", time_stamp,
  131. current_time);
  132. return;
  133. case ET_TOUCH_RELEASED:
  134. UMA_HISTOGRAM_EVENT_LATENCY_TIMES("Event.Latency.OS2.TOUCH_RELEASED",
  135. delta);
  136. RecordEventLatencyTrace("InputEventLatency.TOUCH_RELEASED", time_stamp,
  137. current_time);
  138. return;
  139. case ET_TOUCH_CANCELLED:
  140. UMA_HISTOGRAM_EVENT_LATENCY_TIMES("Event.Latency.OS2.TOUCH_CANCELLED",
  141. delta);
  142. RecordEventLatencyTrace("InputEventLatency.TOUCH_CANCELLED", time_stamp,
  143. current_time);
  144. return;
  145. case ET_KEY_PRESSED:
  146. UMA_HISTOGRAM_EVENT_LATENCY_TIMES("Event.Latency.OS2.KEY_PRESSED", delta);
  147. RecordEventLatencyTrace("InputEventLatency.KEY_PRESSED", time_stamp,
  148. current_time);
  149. return;
  150. case ET_MOUSE_PRESSED:
  151. UMA_HISTOGRAM_EVENT_LATENCY_TIMES("Event.Latency.OS2.MOUSE_PRESSED",
  152. delta);
  153. RecordEventLatencyTrace("InputEventLatency.MOUSE_PRESSED", time_stamp,
  154. current_time);
  155. return;
  156. default:
  157. return;
  158. }
  159. }
  160. #if BUILDFLAG(IS_WIN)
  161. void ComputeEventLatencyOSFromTOUCHINPUT(EventType event_type,
  162. TOUCHINPUT touch_input,
  163. base::TimeTicks current_time) {
  164. base::TimeTicks time_stamp =
  165. EventLatencyTimeFromTickClock(touch_input.dwTime, current_time);
  166. ComputeEventLatencyOS(event_type, time_stamp, current_time);
  167. }
  168. void ComputeEventLatencyOSFromPOINTER_INFO(EventType event_type,
  169. POINTER_INFO pointer_info,
  170. base::TimeTicks current_time) {
  171. base::TimeTicks time_stamp;
  172. if (pointer_info.PerformanceCount) {
  173. if (!base::TimeTicks::IsHighResolution()) {
  174. // The tick clock will be incompatible with |event_time|.
  175. return;
  176. }
  177. time_stamp =
  178. EventLatencyTimeFromPerformanceCounter(pointer_info.PerformanceCount);
  179. } else if (pointer_info.dwTime) {
  180. time_stamp =
  181. EventLatencyTimeFromTickClock(pointer_info.dwTime, current_time);
  182. } else {
  183. // Bad POINTER_INFO with no timestamp.
  184. return;
  185. }
  186. ComputeEventLatencyOS(event_type, time_stamp, current_time);
  187. }
  188. #endif // BUILDFLAG(IS_WIN)
  189. void ConvertEventLocationToTargetWindowLocation(
  190. const gfx::Point& target_window_origin,
  191. const gfx::Point& current_window_origin,
  192. ui::LocatedEvent* located_event) {
  193. if (current_window_origin == target_window_origin)
  194. return;
  195. DCHECK(located_event);
  196. gfx::Vector2d offset = current_window_origin - target_window_origin;
  197. gfx::PointF location_in_pixel_in_host =
  198. located_event->location_f() + gfx::Vector2dF(offset);
  199. located_event->set_location_f(location_in_pixel_in_host);
  200. }
  201. base::StringPiece EventTypeName(EventType type) {
  202. if (type >= ET_LAST)
  203. return "";
  204. #define CASE_TYPE(t) \
  205. case t: \
  206. return #t
  207. switch (type) {
  208. CASE_TYPE(ET_UNKNOWN);
  209. CASE_TYPE(ET_MOUSE_PRESSED);
  210. CASE_TYPE(ET_MOUSE_DRAGGED);
  211. CASE_TYPE(ET_MOUSE_RELEASED);
  212. CASE_TYPE(ET_MOUSE_MOVED);
  213. CASE_TYPE(ET_MOUSE_ENTERED);
  214. CASE_TYPE(ET_MOUSE_EXITED);
  215. CASE_TYPE(ET_KEY_PRESSED);
  216. CASE_TYPE(ET_KEY_RELEASED);
  217. CASE_TYPE(ET_MOUSEWHEEL);
  218. CASE_TYPE(ET_MOUSE_CAPTURE_CHANGED);
  219. CASE_TYPE(ET_TOUCH_RELEASED);
  220. CASE_TYPE(ET_TOUCH_PRESSED);
  221. CASE_TYPE(ET_TOUCH_MOVED);
  222. CASE_TYPE(ET_TOUCH_CANCELLED);
  223. CASE_TYPE(ET_DROP_TARGET_EVENT);
  224. CASE_TYPE(ET_GESTURE_SCROLL_BEGIN);
  225. CASE_TYPE(ET_GESTURE_SCROLL_END);
  226. CASE_TYPE(ET_GESTURE_SCROLL_UPDATE);
  227. CASE_TYPE(ET_GESTURE_SHOW_PRESS);
  228. CASE_TYPE(ET_GESTURE_TAP);
  229. CASE_TYPE(ET_GESTURE_TAP_DOWN);
  230. CASE_TYPE(ET_GESTURE_TAP_CANCEL);
  231. CASE_TYPE(ET_GESTURE_BEGIN);
  232. CASE_TYPE(ET_GESTURE_END);
  233. CASE_TYPE(ET_GESTURE_TWO_FINGER_TAP);
  234. CASE_TYPE(ET_GESTURE_PINCH_BEGIN);
  235. CASE_TYPE(ET_GESTURE_PINCH_END);
  236. CASE_TYPE(ET_GESTURE_PINCH_UPDATE);
  237. CASE_TYPE(ET_GESTURE_SHORT_PRESS);
  238. CASE_TYPE(ET_GESTURE_LONG_PRESS);
  239. CASE_TYPE(ET_GESTURE_LONG_TAP);
  240. CASE_TYPE(ET_GESTURE_SWIPE);
  241. CASE_TYPE(ET_GESTURE_TAP_UNCONFIRMED);
  242. CASE_TYPE(ET_GESTURE_DOUBLE_TAP);
  243. CASE_TYPE(ET_SCROLL);
  244. CASE_TYPE(ET_SCROLL_FLING_START);
  245. CASE_TYPE(ET_SCROLL_FLING_CANCEL);
  246. CASE_TYPE(ET_CANCEL_MODE);
  247. CASE_TYPE(ET_UMA_DATA);
  248. case ET_LAST:
  249. NOTREACHED();
  250. return "";
  251. // Don't include default, so that we get an error when new type is added.
  252. }
  253. #undef CASE_TYPE
  254. NOTREACHED();
  255. return "";
  256. }
  257. std::vector<base::StringPiece> EventFlagsNames(int event_flags) {
  258. std::vector<base::StringPiece> names;
  259. names.reserve(5); // Seems like a good starting point.
  260. if (!event_flags) {
  261. names.push_back("NONE");
  262. return names;
  263. }
  264. if (event_flags & EF_IS_SYNTHESIZED)
  265. names.push_back("IS_SYNTHESIZED");
  266. if (event_flags & EF_SHIFT_DOWN)
  267. names.push_back("SHIFT_DOWN");
  268. if (event_flags & EF_CONTROL_DOWN)
  269. names.push_back("CONTROL_DOWN");
  270. if (event_flags & EF_ALT_DOWN)
  271. names.push_back("ALT_DOWN");
  272. if (event_flags & EF_COMMAND_DOWN)
  273. names.push_back("COMMAND_DOWN");
  274. if (event_flags & EF_ALTGR_DOWN)
  275. names.push_back("ALTGR_DOWN");
  276. if (event_flags & EF_MOD3_DOWN)
  277. names.push_back("MOD3_DOWN");
  278. if (event_flags & EF_NUM_LOCK_ON)
  279. names.push_back("NUM_LOCK_ON");
  280. if (event_flags & EF_CAPS_LOCK_ON)
  281. names.push_back("CAPS_LOCK_ON");
  282. if (event_flags & EF_SCROLL_LOCK_ON)
  283. names.push_back("SCROLL_LOCK_ON");
  284. if (event_flags & EF_LEFT_MOUSE_BUTTON)
  285. names.push_back("LEFT_MOUSE_BUTTON");
  286. if (event_flags & EF_MIDDLE_MOUSE_BUTTON)
  287. names.push_back("MIDDLE_MOUSE_BUTTON");
  288. if (event_flags & EF_RIGHT_MOUSE_BUTTON)
  289. names.push_back("RIGHT_MOUSE_BUTTON");
  290. if (event_flags & EF_BACK_MOUSE_BUTTON)
  291. names.push_back("BACK_MOUSE_BUTTON");
  292. if (event_flags & EF_FORWARD_MOUSE_BUTTON)
  293. names.push_back("FORWARD_MOUSE_BUTTON");
  294. return names;
  295. }
  296. std::vector<base::StringPiece> KeyEventFlagsNames(int event_flags) {
  297. std::vector<base::StringPiece> names = EventFlagsNames(event_flags);
  298. if (!event_flags)
  299. return names;
  300. if (event_flags & EF_IME_FABRICATED_KEY)
  301. names.push_back("IME_FABRICATED_KEY");
  302. if (event_flags & EF_IS_REPEAT)
  303. names.push_back("IS_REPEAT");
  304. if (event_flags & EF_FINAL)
  305. names.push_back("FINAL");
  306. if (event_flags & EF_IS_EXTENDED_KEY)
  307. names.push_back("IS_EXTENDED_KEY");
  308. if (event_flags & EF_IS_STYLUS_BUTTON)
  309. names.push_back("IS_STYLUS_BUTTON");
  310. return names;
  311. }
  312. std::vector<base::StringPiece> MouseEventFlagsNames(int event_flags) {
  313. std::vector<base::StringPiece> names = EventFlagsNames(event_flags);
  314. if (!event_flags)
  315. return names;
  316. if (event_flags & EF_IS_DOUBLE_CLICK)
  317. names.push_back("IS_DOUBLE_CLICK");
  318. if (event_flags & EF_IS_TRIPLE_CLICK)
  319. names.push_back("IS_TRIPLE_CLICK");
  320. if (event_flags & EF_IS_NON_CLIENT)
  321. names.push_back("IS_NON_CLIENT");
  322. if (event_flags & EF_FROM_TOUCH)
  323. names.push_back("FROM_TOUCH");
  324. if (event_flags & EF_TOUCH_ACCESSIBILITY)
  325. names.push_back("TOUCH_ACCESSIBILITY");
  326. if (event_flags & EF_CURSOR_HIDE)
  327. names.push_back("CURSOR_HIDE");
  328. if (event_flags & EF_PRECISION_SCROLLING_DELTA)
  329. names.push_back("PRECISION_SCROLLING_DELTA");
  330. if (event_flags & EF_SCROLL_BY_PAGE)
  331. names.push_back("SCROLL_BY_PAGE");
  332. if (event_flags & EF_UNADJUSTED_MOUSE)
  333. names.push_back("UNADJUSTED_MOUSE");
  334. return names;
  335. }
  336. } // namespace ui