touch_exploration_controller.cc 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239
  1. // Copyright 2014 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 "ash/accessibility/chromevox/touch_exploration_controller.h"
  5. #include <algorithm>
  6. #include <memory>
  7. #include <string>
  8. #include <utility>
  9. #include "ash/accessibility/accessibility_controller_impl.h"
  10. #include "ash/accessibility/chromevox/touch_accessibility_enabler.h"
  11. #include "ash/public/cpp/shell_window_ids.h"
  12. #include "ash/shell.h"
  13. #include "ash/wm/container_finder.h"
  14. #include "ash/wm/tablet_mode/tablet_mode_controller.h"
  15. #include "base/bind.h"
  16. #include "base/logging.h"
  17. #include "base/strings/string_number_conversions.h"
  18. #include "ui/accessibility/ax_enums.mojom.h"
  19. #include "ui/aura/client/cursor_client.h"
  20. #include "ui/aura/window.h"
  21. #include "ui/aura/window_event_dispatcher.h"
  22. #include "ui/aura/window_targeter.h"
  23. #include "ui/aura/window_tree_host.h"
  24. #include "ui/events/event.h"
  25. #include "ui/events/event_processor.h"
  26. #include "ui/events/event_utils.h"
  27. #include "ui/events/gesture_detection/gesture_configuration.h"
  28. #include "ui/events/gesture_detection/gesture_provider_config_helper.h"
  29. #include "ui/gfx/geometry/rect.h"
  30. #include "ui/wm/core/coordinate_conversion.h"
  31. #define SET_STATE(state) SetState(state, __func__)
  32. #define VLOG_EVENT(event) \
  33. if (VLOG_IS_ON(1)) \
  34. VlogEvent(event, __func__)
  35. namespace ash {
  36. namespace {
  37. // Delay between adjustment sounds.
  38. const int kSoundDelayInMS = 150;
  39. // How long the user must stay in the same anchor point in touch exploration
  40. // before a right-click is triggered.
  41. const base::TimeDelta kLongPressTimerDelay = base::Seconds(5);
  42. void SetTouchAccessibilityFlag(ui::Event* event) {
  43. // This flag is used to identify mouse move events that were generated from
  44. // touch exploration in Chrome code.
  45. event->set_flags(event->flags() | ui::EF_TOUCH_ACCESSIBILITY);
  46. }
  47. std::unique_ptr<ui::GestureProviderAura> BuildGestureProviderAura(
  48. TouchExplorationController* owner) {
  49. // Tune some aspects of gesture detection for ChromeVox.
  50. ui::GestureProvider::Config config =
  51. GetGestureProviderConfig(ui::GestureProviderConfigType::CURRENT_PLATFORM);
  52. config.gesture_detector_config.maximum_swipe_deviation_angle = 45;
  53. auto gesture_provider =
  54. std::make_unique<ui::GestureProviderAura>(owner, owner);
  55. gesture_provider->filtered_gesture_provider().UpdateConfig(config);
  56. return gesture_provider;
  57. }
  58. } // namespace
  59. TouchExplorationController::TouchExplorationController(
  60. aura::Window* root_window,
  61. TouchExplorationControllerDelegate* delegate,
  62. base::WeakPtr<TouchAccessibilityEnabler> touch_accessibility_enabler)
  63. : root_window_(root_window),
  64. delegate_(delegate),
  65. state_(NO_FINGERS_DOWN),
  66. anchor_point_state_(ANCHOR_POINT_NONE),
  67. gesture_provider_(BuildGestureProviderAura(this)),
  68. prev_state_(NO_FINGERS_DOWN),
  69. VLOG_on_(true),
  70. touch_accessibility_enabler_(touch_accessibility_enabler) {
  71. DCHECK(root_window);
  72. root_window->GetHost()->GetEventSource()->AddEventRewriter(this);
  73. if (touch_accessibility_enabler_)
  74. touch_accessibility_enabler_->RemoveEventHandler();
  75. }
  76. TouchExplorationController::~TouchExplorationController() {
  77. root_window_->GetHost()->GetEventSource()->RemoveEventRewriter(this);
  78. if (touch_accessibility_enabler_)
  79. touch_accessibility_enabler_->AddEventHandler();
  80. }
  81. void TouchExplorationController::SetTouchAccessibilityAnchorPoint(
  82. const gfx::Point& anchor_point_dip) {
  83. gfx::Point native_point = anchor_point_dip;
  84. SetAnchorPointInternal(gfx::PointF(native_point.x(), native_point.y()));
  85. anchor_point_state_ = ANCHOR_POINT_EXPLICITLY_SET;
  86. }
  87. void TouchExplorationController::SetExcludeBounds(const gfx::Rect& bounds) {
  88. exclude_bounds_ = bounds;
  89. }
  90. void TouchExplorationController::SetLiftActivationBounds(
  91. const gfx::Rect& bounds) {
  92. lift_activation_bounds_ = bounds;
  93. }
  94. ui::EventDispatchDetails TouchExplorationController::RewriteEvent(
  95. const ui::Event& event,
  96. const Continuation continuation) {
  97. if (!event.IsTouchEvent()) {
  98. if (event.IsKeyEvent()) {
  99. const ui::KeyEvent& key_event = static_cast<const ui::KeyEvent&>(event);
  100. VLOG(1) << "\nKeyboard event: " << key_event.GetName()
  101. << "\n Key code: " << key_event.key_code()
  102. << ", Flags: " << key_event.flags()
  103. << ", Is char: " << key_event.is_char();
  104. }
  105. return SendEvent(continuation, &event);
  106. }
  107. const ui::TouchEvent& touch_event = static_cast<const ui::TouchEvent&>(event);
  108. // Let TouchAccessibilityEnabler process the unrewritten event.
  109. if (touch_accessibility_enabler_)
  110. touch_accessibility_enabler_->HandleTouchEvent(touch_event);
  111. if (event.type() == ui::ET_TOUCH_PRESSED)
  112. seen_press_ = true;
  113. // Touch event comes in un-rotated, screen pixels. Convert it to rotated DIP
  114. // one.
  115. gfx::Point location = touch_event.location();
  116. gfx::Point root_location = touch_event.root_location();
  117. root_window_->GetHost()->ConvertPixelsToDIP(&location);
  118. root_window_->GetHost()->ConvertPixelsToDIP(&root_location);
  119. bool exclude =
  120. IsTargetedToArcVirtualKeyboard(location) ||
  121. (!exclude_bounds_.IsEmpty() && exclude_bounds_.Contains(location));
  122. if (exclude) {
  123. if (state_ == NO_FINGERS_DOWN)
  124. return SendEvent(continuation, &event);
  125. if (touch_event.type() == ui::ET_TOUCH_MOVED ||
  126. touch_event.type() == ui::ET_TOUCH_PRESSED) {
  127. return DiscardEvent(continuation);
  128. }
  129. // Otherwise, continue handling events. Basically, we want to let
  130. // CANCELLED or RELEASE events through so this can get back to
  131. // the NO_FINGERS_DOWN state.
  132. }
  133. // If the tap timer should have fired by now but hasn't, run it now and
  134. // stop the timer. This is important so that behavior is consistent with
  135. // the timestamps of the events, and not dependent on the granularity of
  136. // the timer.
  137. if (tap_timer_.IsRunning() &&
  138. touch_event.time_stamp() - most_recent_press_timestamp_ >
  139. gesture_detector_config_.double_tap_timeout) {
  140. tap_timer_.Stop();
  141. OnTapTimerFired();
  142. // Note: this may change the state. We should now continue and process
  143. // this event under this new state.
  144. }
  145. const ui::EventType type = touch_event.type();
  146. const int touch_id = touch_event.pointer_details().id;
  147. // Always update touch ids and touch locations, so we can use those
  148. // no matter what state we're in.
  149. if (type == ui::ET_TOUCH_PRESSED) {
  150. current_touch_ids_.push_back(touch_id);
  151. touch_locations_.insert(std::pair<int, gfx::PointF>(touch_id, location));
  152. } else if (type == ui::ET_TOUCH_RELEASED || type == ui::ET_TOUCH_CANCELLED) {
  153. std::vector<int>::iterator it = std::find(
  154. current_touch_ids_.begin(), current_touch_ids_.end(), touch_id);
  155. // Can happen if touch exploration is enabled while fingers were down
  156. // or if an additional press occurred within the exclusion bounds.
  157. if (it == current_touch_ids_.end()) {
  158. // If we get a RELEASE event and we've never seen a PRESS event
  159. // since TouchExplorationController was instantiated, cancel the
  160. // event so that touch gestures that enable spoken feedback
  161. // don't accidentally trigger other behaviors on release.
  162. if (!seen_press_) {
  163. ui::TouchEvent new_event(ui::ET_TOUCH_CANCELLED, gfx::Point(),
  164. touch_event.time_stamp(),
  165. touch_event.pointer_details());
  166. new_event.set_location(location);
  167. new_event.set_root_location(root_location);
  168. new_event.set_flags(touch_event.flags());
  169. return SendEventFinally(continuation, &new_event);
  170. }
  171. // Otherwise just pass it through.
  172. return SendEvent(continuation, &event);
  173. }
  174. current_touch_ids_.erase(it);
  175. touch_locations_.erase(touch_id);
  176. } else if (type == ui::ET_TOUCH_MOVED) {
  177. std::vector<int>::iterator it = std::find(
  178. current_touch_ids_.begin(), current_touch_ids_.end(), touch_id);
  179. // Can happen if touch exploration is enabled while fingers were down.
  180. if (it == current_touch_ids_.end())
  181. return SendEvent(continuation, &event);
  182. touch_locations_[*it] = gfx::PointF(location);
  183. } else {
  184. NOTREACHED() << "Unexpected event type received: " << event.GetName();
  185. return SendEvent(continuation, &event);
  186. }
  187. VLOG_EVENT(touch_event);
  188. // In order to avoid accidentally double tapping when moving off the edge
  189. // of the screen, the state will be rewritten to NoFingersDown.
  190. if ((type == ui::ET_TOUCH_RELEASED || type == ui::ET_TOUCH_CANCELLED) &&
  191. FindEdgesWithinInset(location, kLeavingScreenEdge) != NO_EDGE) {
  192. if (VLOG_on_)
  193. VLOG(1) << "Leaving screen";
  194. if (current_touch_ids_.size() == 0) {
  195. SET_STATE(NO_FINGERS_DOWN);
  196. if (VLOG_on_) {
  197. VLOG(1) << "Reset to no fingers in Rewrite event because the touch "
  198. "release or cancel was on the edge of the screen.";
  199. }
  200. return DiscardEvent(continuation);
  201. }
  202. }
  203. // We now need a TouchEvent that has its coordinates mapped into root window
  204. // DIP.
  205. ui::TouchEvent touch_event_dip = touch_event;
  206. touch_event_dip.set_location(location);
  207. // If the user is in a gesture state, or if there is a possiblity that the
  208. // user will enter it in the future, we send the event to the gesture
  209. // provider so it can keep track of the state of the fingers. When the user
  210. // leaves one of these states, SET_STATE will set the gesture provider to
  211. // NULL.
  212. if (gesture_provider_.get()) {
  213. if (gesture_provider_->OnTouchEvent(&touch_event_dip)) {
  214. gesture_provider_->OnTouchEventAck(
  215. touch_event_dip.unique_event_id(), false /* event_consumed */,
  216. false /* is_source_touch_event_set_blocking */);
  217. }
  218. ProcessGestureEvents();
  219. }
  220. // The rest of the processing depends on what state we're in.
  221. switch (state_) {
  222. case NO_FINGERS_DOWN:
  223. return InNoFingersDown(touch_event_dip, continuation);
  224. case SINGLE_TAP_PRESSED:
  225. return InSingleTapPressed(touch_event_dip, continuation);
  226. case SINGLE_TAP_RELEASED:
  227. case TOUCH_EXPLORE_RELEASED:
  228. return InSingleTapOrTouchExploreReleased(touch_event_dip, continuation);
  229. case DOUBLE_TAP_PENDING:
  230. return InDoubleTapPending(touch_event_dip, continuation);
  231. case TOUCH_RELEASE_PENDING:
  232. return InTouchReleasePending(touch_event_dip, continuation);
  233. case TOUCH_EXPLORATION:
  234. return InTouchExploration(touch_event_dip, continuation);
  235. case GESTURE_IN_PROGRESS:
  236. return InGestureInProgress(touch_event_dip, continuation);
  237. case TOUCH_EXPLORE_SECOND_PRESS:
  238. return InTouchExploreSecondPress(touch_event_dip, continuation);
  239. case TOUCH_EXPLORE_LONG_PRESS:
  240. return InTouchExploreLongPress(touch_event_dip, continuation);
  241. case SLIDE_GESTURE:
  242. return InSlideGesture(touch_event_dip, continuation);
  243. case ONE_FINGER_PASSTHROUGH:
  244. return InOneFingerPassthrough(touch_event_dip, continuation);
  245. case WAIT_FOR_NO_FINGERS:
  246. return InWaitForNoFingers(touch_event_dip, continuation);
  247. case TWO_FINGER_TAP:
  248. return InTwoFingerTap(touch_event_dip, continuation);
  249. }
  250. NOTREACHED();
  251. return SendEvent(continuation, &event);
  252. }
  253. ui::EventDispatchDetails TouchExplorationController::InNoFingersDown(
  254. const ui::TouchEvent& event,
  255. const Continuation continuation) {
  256. const ui::EventType type = event.type();
  257. if (type != ui::ET_TOUCH_PRESSED) {
  258. NOTREACHED() << "Unexpected event type received: " << event.GetName();
  259. return SendEvent(continuation, &event);
  260. }
  261. initial_press_ = std::make_unique<ui::TouchEvent>(event);
  262. initial_press_continuation_ = continuation;
  263. most_recent_press_timestamp_ = initial_press_->time_stamp();
  264. initial_presses_[event.pointer_details().id] = event.location();
  265. last_unused_finger_event_ = std::make_unique<ui::TouchEvent>(event);
  266. last_unused_finger_continuation_ = continuation;
  267. StartTapTimer();
  268. SET_STATE(SINGLE_TAP_PRESSED);
  269. return DiscardEvent(continuation);
  270. }
  271. ui::EventDispatchDetails TouchExplorationController::InSingleTapPressed(
  272. const ui::TouchEvent& event,
  273. const Continuation continuation) {
  274. const ui::EventType type = event.type();
  275. if (type == ui::ET_TOUCH_PRESSED) {
  276. initial_presses_[event.pointer_details().id] = event.location();
  277. SET_STATE(TWO_FINGER_TAP);
  278. return DiscardEvent(continuation);
  279. }
  280. if (type == ui::ET_TOUCH_RELEASED || type == ui::ET_TOUCH_CANCELLED) {
  281. if (current_touch_ids_.size() == 0 &&
  282. event.pointer_details().id == initial_press_->pointer_details().id) {
  283. MaybeSendSimulatedTapInLiftActivationBounds(event, continuation);
  284. SET_STATE(SINGLE_TAP_RELEASED);
  285. } else if (current_touch_ids_.size() == 0) {
  286. SET_STATE(NO_FINGERS_DOWN);
  287. }
  288. return DiscardEvent(continuation);
  289. }
  290. if (type == ui::ET_TOUCH_MOVED) {
  291. float distance = (event.location() - initial_press_->location()).Length();
  292. // If the user does not move far enough from the original position, then the
  293. // resulting movement should not be considered to be a deliberate gesture or
  294. // touch exploration.
  295. if (distance <= gesture_detector_config_.touch_slop)
  296. return DiscardEvent(continuation);
  297. float delta_time =
  298. (event.time_stamp() - most_recent_press_timestamp_).InSecondsF();
  299. float velocity = distance / delta_time;
  300. if (VLOG_on_) {
  301. VLOG(1) << "\n Delta time: " << delta_time << "\n Distance: " << distance
  302. << "\n Velocity of click: " << velocity
  303. << "\n Minimum swipe velocity: "
  304. << gesture_detector_config_.minimum_swipe_velocity;
  305. }
  306. // Change to slide gesture if the slide occurred at the right edge.
  307. if (ShouldEnableVolumeSlideGesture(event)) {
  308. SET_STATE(SLIDE_GESTURE);
  309. return InSlideGesture(event, continuation);
  310. }
  311. // If the user moves fast enough from the initial touch location, start
  312. // gesture detection. Otherwise, jump to the touch exploration mode early.
  313. if (velocity > gesture_detector_config_.minimum_swipe_velocity) {
  314. SET_STATE(GESTURE_IN_PROGRESS);
  315. return InGestureInProgress(event, continuation);
  316. }
  317. anchor_point_state_ = ANCHOR_POINT_FROM_TOUCH_EXPLORATION;
  318. EnterTouchToMouseMode();
  319. SET_STATE(TOUCH_EXPLORATION);
  320. return InTouchExploration(event, continuation);
  321. }
  322. NOTREACHED();
  323. return SendEvent(continuation, &event);
  324. }
  325. ui::EventDispatchDetails
  326. TouchExplorationController::InSingleTapOrTouchExploreReleased(
  327. const ui::TouchEvent& event,
  328. const Continuation continuation) {
  329. const ui::EventType type = event.type();
  330. // If there is more than one finger down, then discard to wait until no
  331. // fingers are down.
  332. if (current_touch_ids_.size() > 1) {
  333. SET_STATE(WAIT_FOR_NO_FINGERS);
  334. return DiscardEvent(continuation);
  335. }
  336. if (type == ui::ET_TOUCH_PRESSED) {
  337. // If there is no anchor point for synthesized events because the
  338. // user hasn't touch-explored or focused anything yet, we can't
  339. // send a click, so discard.
  340. if (anchor_point_state_ == ANCHOR_POINT_NONE) {
  341. tap_timer_.Stop();
  342. return DiscardEvent(continuation);
  343. }
  344. // This is the second tap in a double-tap (or double tap-hold).
  345. // We set the tap timer. If it fires before the user lifts their finger,
  346. // one-finger passthrough begins. Otherwise, there is a touch press and
  347. // release at the location of the last touch exploration.
  348. SET_STATE(DOUBLE_TAP_PENDING);
  349. // The old tap timer (from the initial click) is stopped if it is still
  350. // going, and the new one is set.
  351. tap_timer_.Stop();
  352. StartTapTimer();
  353. most_recent_press_timestamp_ = event.time_stamp();
  354. // This will update as the finger moves before a possible passthrough, and
  355. // will determine the offset.
  356. last_unused_finger_event_ = std::make_unique<ui::TouchEvent>(event);
  357. last_unused_finger_continuation_ = continuation;
  358. return DiscardEvent(continuation);
  359. }
  360. if (type == ui::ET_TOUCH_RELEASED &&
  361. anchor_point_state_ == ANCHOR_POINT_NONE) {
  362. // If the previous press was discarded, we need to also handle its
  363. // release.
  364. if (current_touch_ids_.size() == 0) {
  365. SET_STATE(NO_FINGERS_DOWN);
  366. }
  367. return DiscardEvent(continuation);
  368. }
  369. if (type == ui::ET_TOUCH_MOVED)
  370. return DiscardEvent(continuation);
  371. NOTREACHED();
  372. return SendEvent(continuation, &event);
  373. }
  374. ui::EventDispatchDetails TouchExplorationController::InDoubleTapPending(
  375. const ui::TouchEvent& event,
  376. const Continuation continuation) {
  377. const ui::EventType type = event.type();
  378. if (type == ui::ET_TOUCH_PRESSED) {
  379. return DiscardEvent(continuation);
  380. }
  381. if (type == ui::ET_TOUCH_MOVED) {
  382. // If the user moves far enough from the initial touch location (outside
  383. // the "slop" region, jump to passthrough mode early.
  384. float delta = (event.location() - initial_press_->location()).Length();
  385. if (delta > gesture_detector_config_.double_tap_slop) {
  386. tap_timer_.Stop();
  387. OnTapTimerFired();
  388. }
  389. return DiscardEvent(continuation);
  390. } else if (type == ui::ET_TOUCH_RELEASED || type == ui::ET_TOUCH_CANCELLED) {
  391. if (current_touch_ids_.size() != 0)
  392. return DiscardEvent(continuation);
  393. SendSimulatedClick();
  394. SET_STATE(NO_FINGERS_DOWN);
  395. return DiscardEvent(continuation);
  396. }
  397. NOTREACHED();
  398. return SendEvent(continuation, &event);
  399. }
  400. ui::EventDispatchDetails TouchExplorationController::InTouchReleasePending(
  401. const ui::TouchEvent& event,
  402. const Continuation continuation) {
  403. const ui::EventType type = event.type();
  404. if (type == ui::ET_TOUCH_PRESSED || type == ui::ET_TOUCH_MOVED) {
  405. return DiscardEvent(continuation);
  406. } else if (type == ui::ET_TOUCH_RELEASED || type == ui::ET_TOUCH_CANCELLED) {
  407. if (current_touch_ids_.size() != 0)
  408. return DiscardEvent(continuation);
  409. SendSimulatedClick();
  410. SET_STATE(NO_FINGERS_DOWN);
  411. return DiscardEvent(continuation);
  412. }
  413. NOTREACHED();
  414. return SendEvent(continuation, &event);
  415. }
  416. ui::EventDispatchDetails TouchExplorationController::InTouchExploration(
  417. const ui::TouchEvent& event,
  418. const Continuation continuation) {
  419. const ui::EventType type = event.type();
  420. if (type == ui::ET_TOUCH_PRESSED) {
  421. // Enter split-tap mode.
  422. initial_press_ = std::make_unique<ui::TouchEvent>(event);
  423. initial_press_continuation_ = continuation;
  424. tap_timer_.Stop();
  425. SET_STATE(TOUCH_EXPLORE_SECOND_PRESS);
  426. return DiscardEvent(continuation);
  427. } else if (type == ui::ET_TOUCH_RELEASED || type == ui::ET_TOUCH_CANCELLED) {
  428. initial_press_ = std::make_unique<ui::TouchEvent>(event);
  429. initial_press_continuation_ = continuation;
  430. StartTapTimer();
  431. most_recent_press_timestamp_ = event.time_stamp();
  432. MaybeSendSimulatedTapInLiftActivationBounds(event, continuation);
  433. SET_STATE(TOUCH_EXPLORE_RELEASED);
  434. } else if (type != ui::ET_TOUCH_MOVED) {
  435. NOTREACHED();
  436. return SendEvent(continuation, &event);
  437. }
  438. // |location| is in window DIP coordinates.
  439. gfx::PointF location(event.location());
  440. // APIs taking this point e.g.
  441. // chrome.accessibilityPrivate.sendSyntheticMouseEvent,
  442. // chrome.automation.AutomationNode.prototype.hitTest, all take screen
  443. // coordinates.
  444. ::wm::ConvertPointToScreen(root_window_, &location);
  445. delegate_->HandleAccessibilityGesture(ax::mojom::Gesture::kTouchExplore,
  446. location);
  447. last_touch_exploration_ = std::make_unique<ui::TouchEvent>(event);
  448. if (anchor_point_state_ != ANCHOR_POINT_EXPLICITLY_SET)
  449. SetAnchorPointInternal(last_touch_exploration_->location_f());
  450. return DiscardEvent(continuation);
  451. }
  452. ui::EventDispatchDetails TouchExplorationController::InGestureInProgress(
  453. const ui::TouchEvent& event,
  454. const Continuation continuation) {
  455. // The events were sent to the gesture provider in RewriteEvent already.
  456. // If no gesture is registered before the tap timer times out, the state
  457. // will change to "wait for no fingers down" or "touch exploration" depending
  458. // on the number of fingers down, and this function will stop being called.
  459. if (current_touch_ids_.size() == 0) {
  460. SET_STATE(NO_FINGERS_DOWN);
  461. }
  462. return DiscardEvent(continuation);
  463. }
  464. ui::EventDispatchDetails TouchExplorationController::InOneFingerPassthrough(
  465. const ui::TouchEvent& event,
  466. const Continuation continuation) {
  467. if (event.pointer_details().id != initial_press_->pointer_details().id) {
  468. if (current_touch_ids_.size() == 0) {
  469. SET_STATE(NO_FINGERS_DOWN);
  470. }
  471. return DiscardEvent(continuation);
  472. }
  473. // |event| locations are in DIP; see |RewriteEvent|. We need to dispatch
  474. // screen coordinates.
  475. gfx::PointF location_f(
  476. ConvertDIPToPixels(event.location_f() - passthrough_offset_));
  477. ui::TouchEvent new_event(event.type(), gfx::Point(), event.time_stamp(),
  478. event.pointer_details(), event.flags());
  479. new_event.set_location_f(location_f);
  480. new_event.set_root_location_f(location_f);
  481. SetTouchAccessibilityFlag(&new_event);
  482. if (current_touch_ids_.size() == 0) {
  483. SET_STATE(NO_FINGERS_DOWN);
  484. }
  485. return SendEventFinally(continuation, &new_event);
  486. }
  487. ui::EventDispatchDetails TouchExplorationController::InTouchExploreSecondPress(
  488. const ui::TouchEvent& event,
  489. const Continuation continuation) {
  490. ui::EventType type = event.type();
  491. if (type == ui::ET_TOUCH_PRESSED) {
  492. // A third finger being pressed means that a split tap can no longer go
  493. // through. The user enters the wait state, Since there has already been
  494. // a press dispatched when split tap began, the touch needs to be
  495. // cancelled.
  496. ui::TouchEvent new_event(ui::ET_TOUCH_CANCELLED, gfx::Point(),
  497. event.time_stamp(),
  498. initial_press_->pointer_details(), event.flags());
  499. // |event| locations are in DIP; see |RewriteEvent|. We need to dispatch
  500. // screen coordinates.
  501. gfx::PointF location_f(ConvertDIPToPixels(anchor_point_dip_));
  502. new_event.set_location_f(location_f);
  503. new_event.set_root_location_f(location_f);
  504. SetTouchAccessibilityFlag(&new_event);
  505. SET_STATE(WAIT_FOR_NO_FINGERS);
  506. return SendEventFinally(continuation, &new_event);
  507. }
  508. if (type == ui::ET_TOUCH_MOVED) {
  509. // If the fingers have moved too far from their original locations,
  510. // the user can no longer split tap.
  511. ui::TouchEvent* original_touch;
  512. if (event.pointer_details().id ==
  513. last_touch_exploration_->pointer_details().id) {
  514. original_touch = last_touch_exploration_.get();
  515. } else if (event.pointer_details().id ==
  516. initial_press_->pointer_details().id) {
  517. original_touch = initial_press_.get();
  518. } else {
  519. NOTREACHED();
  520. SET_STATE(WAIT_FOR_NO_FINGERS);
  521. return DiscardEvent(continuation);
  522. }
  523. // Check the distance between the current finger location and the original
  524. // location. The slop for this is a bit more generous since keeping two
  525. // fingers in place is a bit harder. If the user has left the slop, the
  526. // user enters the wait state.
  527. if ((event.location_f() - original_touch->location_f()).Length() >
  528. GetSplitTapTouchSlop()) {
  529. SET_STATE(WAIT_FOR_NO_FINGERS);
  530. }
  531. return DiscardEvent(continuation);
  532. }
  533. if (type == ui::ET_TOUCH_RELEASED || type == ui::ET_TOUCH_CANCELLED) {
  534. // If the touch exploration finger is lifted, there is no option to return
  535. // to touch explore anymore. The remaining finger acts as a pending
  536. // tap or long tap for the last touch explore location.
  537. if (event.pointer_details().id ==
  538. last_touch_exploration_->pointer_details().id) {
  539. SET_STATE(TOUCH_RELEASE_PENDING);
  540. return DiscardEvent(continuation);
  541. }
  542. // Continue to release the touch only if the touch explore finger is the
  543. // only finger remaining.
  544. if (current_touch_ids_.size() != 1) {
  545. return DiscardEvent(continuation);
  546. }
  547. SendSimulatedClick();
  548. SET_STATE(TOUCH_EXPLORATION);
  549. EnterTouchToMouseMode();
  550. return DiscardEvent(continuation);
  551. }
  552. NOTREACHED();
  553. return SendEvent(continuation, &event);
  554. }
  555. ui::EventDispatchDetails TouchExplorationController::InTouchExploreLongPress(
  556. const ui::TouchEvent& event,
  557. const Continuation continuation) {
  558. // Simulate a right mouse click.
  559. auto mouse_pressed = std::make_unique<ui::MouseEvent>(
  560. ui::ET_MOUSE_PRESSED, anchor_point_dip_, anchor_point_dip_, Now(),
  561. ui::EF_IS_SYNTHESIZED | ui::EF_TOUCH_ACCESSIBILITY |
  562. ui::EF_RIGHT_MOUSE_BUTTON,
  563. ui::EF_RIGHT_MOUSE_BUTTON);
  564. auto mouse_released = std::make_unique<ui::MouseEvent>(
  565. ui::ET_MOUSE_RELEASED, anchor_point_dip_, anchor_point_dip_, Now(),
  566. ui::EF_IS_SYNTHESIZED | ui::EF_TOUCH_ACCESSIBILITY,
  567. ui::EF_LEFT_MOUSE_BUTTON);
  568. DispatchEvent(mouse_pressed.get(), continuation);
  569. DispatchEvent(mouse_released.get(), continuation);
  570. SET_STATE(TOUCH_EXPLORATION);
  571. EnterTouchToMouseMode();
  572. return InTouchExploration(event, continuation);
  573. }
  574. ui::EventDispatchDetails TouchExplorationController::InWaitForNoFingers(
  575. const ui::TouchEvent& event,
  576. const Continuation continuation) {
  577. if (current_touch_ids_.size() == 0)
  578. SET_STATE(NO_FINGERS_DOWN);
  579. return DiscardEvent(continuation);
  580. }
  581. void TouchExplorationController::PlaySoundForTimer() {
  582. delegate_->PlayVolumeAdjustEarcon();
  583. }
  584. void TouchExplorationController::SendSimulatedClick() {
  585. // Always send a double tap gesture to ChromeVox.
  586. delegate_->HandleAccessibilityGesture(ax::mojom::Gesture::kClick);
  587. }
  588. void TouchExplorationController::SendSimulatedTap(
  589. const Continuation continuation) {
  590. auto touch_press = std::make_unique<ui::TouchEvent>(
  591. ui::ET_TOUCH_PRESSED, gfx::Point(), Now(),
  592. initial_press_->pointer_details());
  593. touch_press->set_location_f(anchor_point_dip_);
  594. touch_press->set_root_location_f(anchor_point_dip_);
  595. DispatchEvent(touch_press.get(), continuation);
  596. auto touch_release = std::make_unique<ui::TouchEvent>(
  597. ui::ET_TOUCH_RELEASED, gfx::Point(), Now(),
  598. initial_press_->pointer_details());
  599. touch_release->set_location_f(anchor_point_dip_);
  600. touch_release->set_root_location_f(anchor_point_dip_);
  601. DispatchEvent(touch_release.get(), continuation);
  602. }
  603. void TouchExplorationController::MaybeSendSimulatedTapInLiftActivationBounds(
  604. const ui::TouchEvent& event,
  605. const Continuation continuation) {
  606. gfx::Point location = event.location();
  607. gfx::Point anchor_location(anchor_point_dip_.x(), anchor_point_dip_.y());
  608. if (lift_activation_bounds_.Contains(anchor_location.x(),
  609. anchor_location.y()) &&
  610. lift_activation_bounds_.Contains(location)) {
  611. delegate_->PlayTouchTypeEarcon();
  612. SendSimulatedTap(continuation);
  613. }
  614. }
  615. ui::EventDispatchDetails TouchExplorationController::InSlideGesture(
  616. const ui::TouchEvent& event,
  617. const Continuation continuation) {
  618. // The timer should not fire when sliding.
  619. tap_timer_.Stop();
  620. ui::EventType type = event.type();
  621. // If additional fingers are added before a swipe gesture has been registered,
  622. // then wait until all fingers have been lifted.
  623. if (type == ui::ET_TOUCH_PRESSED ||
  624. event.pointer_details().id != initial_press_->pointer_details().id) {
  625. if (sound_timer_.IsRunning())
  626. sound_timer_.Stop();
  627. SET_STATE(WAIT_FOR_NO_FINGERS);
  628. return DiscardEvent(continuation);
  629. }
  630. // There should not be more than one finger down.
  631. DCHECK_LE(current_touch_ids_.size(), 1U);
  632. // Allows user to return to the edge to adjust the sound if they have left the
  633. // boundaries.
  634. int edge = FindEdgesWithinInset(event.location(), kSlopDistanceFromEdge);
  635. if (!(edge & RIGHT_EDGE) && (type != ui::ET_TOUCH_RELEASED)) {
  636. if (sound_timer_.IsRunning()) {
  637. sound_timer_.Stop();
  638. }
  639. return DiscardEvent(continuation);
  640. }
  641. // This can occur if the user leaves the screen edge and then returns to it to
  642. // continue adjusting the sound.
  643. if (!sound_timer_.IsRunning()) {
  644. sound_timer_.Start(FROM_HERE, base::Milliseconds(kSoundDelayInMS), this,
  645. &TouchExplorationController::PlaySoundForTimer);
  646. delegate_->PlayVolumeAdjustEarcon();
  647. }
  648. if (current_touch_ids_.size() == 0) {
  649. SET_STATE(NO_FINGERS_DOWN);
  650. }
  651. return DiscardEvent(continuation);
  652. }
  653. ui::EventDispatchDetails TouchExplorationController::InTwoFingerTap(
  654. const ui::TouchEvent& event,
  655. const Continuation continuation) {
  656. ui::EventType type = event.type();
  657. if (type == ui::ET_TOUCH_PRESSED) {
  658. // This is now a three finger gesture.
  659. SET_STATE(GESTURE_IN_PROGRESS);
  660. return DiscardEvent(continuation);
  661. }
  662. if (type == ui::ET_TOUCH_MOVED) {
  663. // Determine if it was a swipe.
  664. gfx::Point original_location = initial_presses_[event.pointer_details().id];
  665. float distance = (event.location() - original_location).Length();
  666. // If the user moves too far from the original position, consider the
  667. // movement a swipe.
  668. if (distance > gesture_detector_config_.touch_slop) {
  669. SET_STATE(GESTURE_IN_PROGRESS);
  670. }
  671. return DiscardEvent(continuation);
  672. }
  673. if (current_touch_ids_.size() != 0) {
  674. return DiscardEvent(continuation);
  675. }
  676. if (type == ui::ET_TOUCH_RELEASED) {
  677. delegate_->HandleAccessibilityGesture(ax::mojom::Gesture::kTap2);
  678. SET_STATE(NO_FINGERS_DOWN);
  679. return DiscardEvent(continuation);
  680. }
  681. return DiscardEvent(continuation);
  682. }
  683. base::TimeTicks TouchExplorationController::Now() {
  684. return ui::EventTimeForNow();
  685. }
  686. void TouchExplorationController::StartTapTimer() {
  687. tap_timer_.Start(FROM_HERE, gesture_detector_config_.double_tap_timeout, this,
  688. &TouchExplorationController::OnTapTimerFired);
  689. }
  690. void TouchExplorationController::OnTapTimerFired() {
  691. switch (state_) {
  692. case SINGLE_TAP_RELEASED:
  693. SET_STATE(NO_FINGERS_DOWN);
  694. break;
  695. case TOUCH_EXPLORE_RELEASED:
  696. SET_STATE(NO_FINGERS_DOWN);
  697. last_touch_exploration_ =
  698. std::make_unique<ui::TouchEvent>(*initial_press_);
  699. SetAnchorPointInternal(last_touch_exploration_->location_f());
  700. anchor_point_state_ = ANCHOR_POINT_FROM_TOUCH_EXPLORATION;
  701. return;
  702. case DOUBLE_TAP_PENDING: {
  703. SET_STATE(ONE_FINGER_PASSTHROUGH);
  704. delegate_->PlayPassthroughEarcon();
  705. passthrough_offset_ =
  706. last_unused_finger_event_->location_f() - anchor_point_dip_;
  707. std::unique_ptr<ui::TouchEvent> passthrough_press(
  708. new ui::TouchEvent(ui::ET_TOUCH_PRESSED, gfx::Point(), Now(),
  709. last_unused_finger_event_->pointer_details()));
  710. passthrough_press->set_location_f(anchor_point_dip_);
  711. passthrough_press->set_root_location_f(anchor_point_dip_);
  712. DispatchEvent(passthrough_press.get(), last_unused_finger_continuation_);
  713. return;
  714. }
  715. case SINGLE_TAP_PRESSED:
  716. [[fallthrough]];
  717. case GESTURE_IN_PROGRESS:
  718. // If only one finger is down, go into touch exploration.
  719. if (current_touch_ids_.size() == 1) {
  720. anchor_point_state_ = ANCHOR_POINT_FROM_TOUCH_EXPLORATION;
  721. EnterTouchToMouseMode();
  722. SET_STATE(TOUCH_EXPLORATION);
  723. break;
  724. }
  725. // Otherwise wait for all fingers to be lifted.
  726. SET_STATE(WAIT_FOR_NO_FINGERS);
  727. return;
  728. case TWO_FINGER_TAP:
  729. SET_STATE(WAIT_FOR_NO_FINGERS);
  730. break;
  731. default:
  732. return;
  733. }
  734. EnterTouchToMouseMode();
  735. delegate_->HandleAccessibilityGesture(ax::mojom::Gesture::kTouchExplore,
  736. initial_press_->location_f());
  737. last_touch_exploration_ = std::make_unique<ui::TouchEvent>(*initial_press_);
  738. SetAnchorPointInternal(last_touch_exploration_->location_f());
  739. anchor_point_state_ = ANCHOR_POINT_FROM_TOUCH_EXPLORATION;
  740. }
  741. void TouchExplorationController::ResetLiftActivationLongPressTimer() {
  742. long_press_timer_.Stop();
  743. if (state_ == TOUCH_EXPLORATION &&
  744. lift_activation_bounds_.Contains(
  745. gfx::ToFlooredPoint(anchor_point_dip_))) {
  746. long_press_timer_.Start(
  747. FROM_HERE, kLongPressTimerDelay, this,
  748. &TouchExplorationController::OnLiftActivationLongPressTimerFired);
  749. }
  750. }
  751. void TouchExplorationController::OnLiftActivationLongPressTimerFired() {
  752. if (state_ == TOUCH_EXPLORATION &&
  753. lift_activation_bounds_.Contains(
  754. gfx::ToFlooredPoint(anchor_point_dip_))) {
  755. delegate_->PlayLongPressRightClickEarcon();
  756. SET_STATE(TOUCH_EXPLORE_LONG_PRESS);
  757. }
  758. }
  759. void TouchExplorationController::DispatchEvent(
  760. ui::Event* event,
  761. const Continuation continuation) {
  762. SetTouchAccessibilityFlag(event);
  763. if (event->IsLocatedEvent()) {
  764. ui::LocatedEvent* located_event = event->AsLocatedEvent();
  765. gfx::PointF screen_point(ConvertDIPToPixels(located_event->location_f()));
  766. located_event->set_location_f(screen_point);
  767. located_event->set_root_location_f(screen_point);
  768. }
  769. if (SendEventFinally(continuation, event).dispatcher_destroyed)
  770. VLOG(0) << "Undispatched event due to destroyed dispatcher.";
  771. }
  772. // This is an override for a function that is only called for timer-based events
  773. // like long press. Events that are created synchronously as a result of
  774. // certain touch events are added to the vector accessible via
  775. // GetAndResetPendingGestures(). We only care about swipes (which are created
  776. // synchronously), so we ignore this callback.
  777. void TouchExplorationController::OnGestureEvent(ui::GestureConsumer* consumer,
  778. ui::GestureEvent* gesture) {}
  779. const std::string& TouchExplorationController::GetName() const {
  780. static const std::string name("TouchExplorationController");
  781. return name;
  782. }
  783. void TouchExplorationController::ProcessGestureEvents() {
  784. std::vector<std::unique_ptr<ui::GestureEvent>> gestures =
  785. gesture_provider_->GetAndResetPendingGestures();
  786. bool resolved_gesture = false;
  787. max_gesture_touch_points_ =
  788. std::max(max_gesture_touch_points_, current_touch_ids_.size());
  789. for (const auto& gesture : gestures) {
  790. if (gesture->type() == ui::ET_GESTURE_SWIPE &&
  791. state_ == GESTURE_IN_PROGRESS) {
  792. OnSwipeEvent(gesture.get());
  793. // The tap timer to leave gesture state is ended, and we now wait for
  794. // all fingers to be released.
  795. tap_timer_.Stop();
  796. SET_STATE(WAIT_FOR_NO_FINGERS);
  797. return;
  798. }
  799. if (state_ == SLIDE_GESTURE && gesture->IsScrollGestureEvent()) {
  800. SideSlideControl(gesture.get());
  801. resolved_gesture = true;
  802. }
  803. }
  804. if (resolved_gesture)
  805. return;
  806. if (current_touch_ids_.size() == 0) {
  807. switch (max_gesture_touch_points_) {
  808. case 3:
  809. delegate_->HandleAccessibilityGesture(ax::mojom::Gesture::kTap3);
  810. break;
  811. case 4:
  812. delegate_->HandleAccessibilityGesture(ax::mojom::Gesture::kTap4);
  813. break;
  814. default:
  815. break;
  816. }
  817. max_gesture_touch_points_ = 0;
  818. }
  819. }
  820. void TouchExplorationController::SideSlideControl(ui::GestureEvent* gesture) {
  821. ui::EventType type = gesture->type();
  822. if (type == ui::ET_GESTURE_SCROLL_BEGIN) {
  823. delegate_->PlayVolumeAdjustEarcon();
  824. }
  825. if (type == ui::ET_GESTURE_SCROLL_END) {
  826. if (sound_timer_.IsRunning())
  827. sound_timer_.Stop();
  828. delegate_->PlayVolumeAdjustEarcon();
  829. }
  830. // If the user is in the corner of the right side of the screen, the volume
  831. // will be automatically set to 100% or muted depending on which corner they
  832. // are in. Otherwise, the user will be able to adjust the volume by sliding
  833. // their finger along the right side of the screen. Volume is relative to
  834. // where they are on the right side of the screen.
  835. gfx::Point location = gesture->location();
  836. int edge = FindEdgesWithinInset(location, kSlopDistanceFromEdge);
  837. if (!(edge & RIGHT_EDGE))
  838. return;
  839. if (edge & TOP_EDGE) {
  840. delegate_->SetOutputLevel(100);
  841. return;
  842. }
  843. if (edge & BOTTOM_EDGE) {
  844. delegate_->SetOutputLevel(0);
  845. return;
  846. }
  847. location = gesture->location();
  848. gfx::RectF bounds(root_window_->bounds());
  849. float volume_adjust_height = bounds.height() - 2 * kMaxDistanceFromEdge;
  850. float ratio = (location.y() - kMaxDistanceFromEdge) / volume_adjust_height;
  851. float volume = 100 - 100 * ratio;
  852. if (VLOG_on_) {
  853. VLOG(1) << "\n Volume = " << volume
  854. << "\n Location = " << location.ToString()
  855. << "\n Bounds = " << bounds.right();
  856. }
  857. delegate_->SetOutputLevel(static_cast<int>(volume));
  858. }
  859. void TouchExplorationController::OnSwipeEvent(ui::GestureEvent* swipe_gesture) {
  860. // A swipe gesture contains details for the direction in which the swipe
  861. // occurred. TODO(evy) : Research which swipe results users most want and
  862. // remap these swipes to the best events. Hopefully in the near future
  863. // there will also be a menu for users to pick custom mappings.
  864. ui::GestureEventDetails event_details = swipe_gesture->details();
  865. int num_fingers = event_details.touch_points();
  866. if (VLOG_on_)
  867. VLOG(1) << "\nSwipe with " << num_fingers << " fingers.";
  868. ax::mojom::Gesture gesture = ax::mojom::Gesture::kNone;
  869. if (event_details.swipe_left()) {
  870. switch (num_fingers) {
  871. case 1:
  872. gesture = ax::mojom::Gesture::kSwipeLeft1;
  873. break;
  874. case 2:
  875. gesture = ax::mojom::Gesture::kSwipeLeft2;
  876. break;
  877. case 3:
  878. gesture = ax::mojom::Gesture::kSwipeLeft3;
  879. break;
  880. case 4:
  881. gesture = ax::mojom::Gesture::kSwipeLeft4;
  882. break;
  883. default:
  884. break;
  885. }
  886. } else if (event_details.swipe_up()) {
  887. switch (num_fingers) {
  888. case 1:
  889. gesture = ax::mojom::Gesture::kSwipeUp1;
  890. break;
  891. case 2:
  892. gesture = ax::mojom::Gesture::kSwipeUp2;
  893. break;
  894. case 3:
  895. gesture = ax::mojom::Gesture::kSwipeUp3;
  896. break;
  897. case 4:
  898. gesture = ax::mojom::Gesture::kSwipeUp4;
  899. break;
  900. default:
  901. break;
  902. }
  903. } else if (event_details.swipe_right()) {
  904. switch (num_fingers) {
  905. case 1:
  906. gesture = ax::mojom::Gesture::kSwipeRight1;
  907. break;
  908. case 2:
  909. gesture = ax::mojom::Gesture::kSwipeRight2;
  910. break;
  911. case 3:
  912. gesture = ax::mojom::Gesture::kSwipeRight3;
  913. break;
  914. case 4:
  915. gesture = ax::mojom::Gesture::kSwipeRight4;
  916. break;
  917. default:
  918. break;
  919. }
  920. } else if (event_details.swipe_down()) {
  921. switch (num_fingers) {
  922. case 1:
  923. gesture = ax::mojom::Gesture::kSwipeDown1;
  924. break;
  925. case 2:
  926. gesture = ax::mojom::Gesture::kSwipeDown2;
  927. break;
  928. case 3:
  929. gesture = ax::mojom::Gesture::kSwipeDown3;
  930. break;
  931. case 4:
  932. gesture = ax::mojom::Gesture::kSwipeDown4;
  933. break;
  934. default:
  935. break;
  936. }
  937. }
  938. if (gesture != ax::mojom::Gesture::kNone)
  939. delegate_->HandleAccessibilityGesture(gesture);
  940. }
  941. int TouchExplorationController::FindEdgesWithinInset(gfx::Point point_dip,
  942. float inset) {
  943. gfx::RectF inner_bounds_dip(root_window_->bounds());
  944. inner_bounds_dip.Inset(inset);
  945. // Bitwise manipulation in order to determine where on the screen the point
  946. // lies. If more than one bit is turned on, then it is a corner where the two
  947. // bit/edges intersect. Otherwise, if no bits are turned on, the point must be
  948. // in the center of the screen.
  949. int result = NO_EDGE;
  950. if (point_dip.x() < inner_bounds_dip.x())
  951. result |= LEFT_EDGE;
  952. if (point_dip.x() > inner_bounds_dip.right())
  953. result |= RIGHT_EDGE;
  954. if (point_dip.y() < inner_bounds_dip.y())
  955. result |= TOP_EDGE;
  956. if (point_dip.y() > inner_bounds_dip.bottom())
  957. result |= BOTTOM_EDGE;
  958. return result;
  959. }
  960. void TouchExplorationController::DispatchKeyWithFlags(
  961. const ui::KeyboardCode key,
  962. int flags,
  963. const Continuation continuation) {
  964. ui::KeyEvent key_down(ui::ET_KEY_PRESSED, key, flags);
  965. ui::KeyEvent key_up(ui::ET_KEY_RELEASED, key, flags);
  966. DispatchEvent(&key_down, continuation);
  967. DispatchEvent(&key_up, continuation);
  968. if (VLOG_on_) {
  969. VLOG(1) << "\nKey down: key code : " << key_down.key_code()
  970. << ", flags: " << key_down.flags()
  971. << "\nKey up: key code : " << key_up.key_code()
  972. << ", flags: " << key_up.flags();
  973. }
  974. }
  975. void TouchExplorationController::EnterTouchToMouseMode() {
  976. aura::client::CursorClient* cursor_client =
  977. aura::client::GetCursorClient(root_window_);
  978. if (cursor_client && !cursor_client->IsMouseEventsEnabled())
  979. cursor_client->EnableMouseEvents();
  980. if (cursor_client && cursor_client->IsCursorVisible())
  981. cursor_client->HideCursor();
  982. }
  983. void TouchExplorationController::SetState(State new_state,
  984. const char* function_name) {
  985. state_ = new_state;
  986. VlogState(function_name);
  987. // These are the states the user can be in that will never result in a
  988. // gesture before the user returns to NO_FINGERS_DOWN. Therefore, if the
  989. // gesture provider still exists, it's reset to NULL until the user returns
  990. // to NO_FINGERS_DOWN.
  991. switch (new_state) {
  992. case SINGLE_TAP_RELEASED:
  993. case TOUCH_EXPLORE_RELEASED:
  994. case DOUBLE_TAP_PENDING:
  995. case TOUCH_RELEASE_PENDING:
  996. case TOUCH_EXPLORATION:
  997. case TOUCH_EXPLORE_SECOND_PRESS:
  998. case TOUCH_EXPLORE_LONG_PRESS:
  999. case ONE_FINGER_PASSTHROUGH:
  1000. case WAIT_FOR_NO_FINGERS:
  1001. if (gesture_provider_.get())
  1002. gesture_provider_.reset(NULL);
  1003. max_gesture_touch_points_ = 0;
  1004. break;
  1005. case NO_FINGERS_DOWN:
  1006. gesture_provider_ = BuildGestureProviderAura(this);
  1007. if (sound_timer_.IsRunning())
  1008. sound_timer_.Stop();
  1009. tap_timer_.Stop();
  1010. break;
  1011. case SINGLE_TAP_PRESSED:
  1012. case GESTURE_IN_PROGRESS:
  1013. case SLIDE_GESTURE:
  1014. case TWO_FINGER_TAP:
  1015. break;
  1016. }
  1017. }
  1018. void TouchExplorationController::VlogState(const char* function_name) {
  1019. if (!VLOG_on_)
  1020. return;
  1021. if (prev_state_ == state_)
  1022. return;
  1023. prev_state_ = state_;
  1024. const char* state_string = EnumStateToString(state_);
  1025. VLOG(1) << "\n Function name: " << function_name
  1026. << "\n State: " << state_string;
  1027. }
  1028. void TouchExplorationController::VlogEvent(const ui::TouchEvent& touch_event,
  1029. const char* function_name) {
  1030. if (!VLOG_on_)
  1031. return;
  1032. if (prev_event_ && prev_event_->type() == touch_event.type() &&
  1033. prev_event_->pointer_details().id == touch_event.pointer_details().id) {
  1034. return;
  1035. }
  1036. // The above statement prevents events of the same type and id from being
  1037. // printed in a row. However, if two fingers are down, they would both be
  1038. // moving and alternating printing move events unless we check for this.
  1039. if (prev_event_ && prev_event_->type() == ui::ET_TOUCH_MOVED &&
  1040. touch_event.type() == ui::ET_TOUCH_MOVED) {
  1041. return;
  1042. }
  1043. const std::string& type = touch_event.GetName();
  1044. const gfx::PointF& location = touch_event.location_f();
  1045. const int touch_id = touch_event.pointer_details().id;
  1046. VLOG(1) << "\n Function name: " << function_name << "\n Event Type: " << type
  1047. << "\n Location: " << location.ToString()
  1048. << "\n Touch ID: " << touch_id;
  1049. prev_event_ = std::make_unique<ui::TouchEvent>(touch_event);
  1050. }
  1051. const char* TouchExplorationController::EnumStateToString(State state) {
  1052. switch (state) {
  1053. case NO_FINGERS_DOWN:
  1054. return "NO_FINGERS_DOWN";
  1055. case SINGLE_TAP_PRESSED:
  1056. return "SINGLE_TAP_PRESSED";
  1057. case SINGLE_TAP_RELEASED:
  1058. return "SINGLE_TAP_RELEASED";
  1059. case TOUCH_EXPLORE_RELEASED:
  1060. return "TOUCH_EXPLORE_RELEASED";
  1061. case DOUBLE_TAP_PENDING:
  1062. return "DOUBLE_TAP_PENDING";
  1063. case TOUCH_RELEASE_PENDING:
  1064. return "TOUCH_RELEASE_PENDING";
  1065. case TOUCH_EXPLORATION:
  1066. return "TOUCH_EXPLORATION";
  1067. case GESTURE_IN_PROGRESS:
  1068. return "GESTURE_IN_PROGRESS";
  1069. case TOUCH_EXPLORE_SECOND_PRESS:
  1070. return "TOUCH_EXPLORE_SECOND_PRESS";
  1071. case TOUCH_EXPLORE_LONG_PRESS:
  1072. return "TOUCH_EXPLORE_LONG_PRESS";
  1073. case SLIDE_GESTURE:
  1074. return "SLIDE_GESTURE";
  1075. case ONE_FINGER_PASSTHROUGH:
  1076. return "ONE_FINGER_PASSTHROUGH";
  1077. case WAIT_FOR_NO_FINGERS:
  1078. return "WAIT_FOR_NO_FINGERS";
  1079. case TWO_FINGER_TAP:
  1080. return "TWO_FINGER_TAP";
  1081. }
  1082. return "Not a state";
  1083. }
  1084. void TouchExplorationController::SetAnchorPointInternal(
  1085. const gfx::PointF& anchor_point) {
  1086. anchor_point_dip_ = anchor_point;
  1087. ResetLiftActivationLongPressTimer();
  1088. }
  1089. float TouchExplorationController::GetSplitTapTouchSlop() {
  1090. return gesture_detector_config_.touch_slop * 3;
  1091. }
  1092. gfx::PointF TouchExplorationController::ConvertDIPToPixels(
  1093. const gfx::PointF& location_f) {
  1094. gfx::Point location(gfx::ToFlooredPoint(location_f));
  1095. root_window_->GetHost()->ConvertDIPToPixels(&location);
  1096. return gfx::PointF(location);
  1097. }
  1098. bool TouchExplorationController::IsTargetedToArcVirtualKeyboard(
  1099. const gfx::Point& location) {
  1100. // Copy event here as WindowTargeter::FindTargetForEvent modify touch event.
  1101. ui::TouchEvent event(ui::ET_TOUCH_MOVED, gfx::Point(), Now(),
  1102. ui::PointerDetails(ui::EventPointerType::kTouch, 0));
  1103. event.set_location(location);
  1104. // It's safe to static cast to aura::Window here. As current implementation of
  1105. // WindowTargeter::FindTargetForEvent only returns aura::Window.
  1106. aura::Window* target = static_cast<aura::Window*>(
  1107. root_window_->targeter()->FindTargetForEvent(root_window_, &event));
  1108. aura::Window* container = GetContainerForWindow(target);
  1109. if (!container)
  1110. return false;
  1111. return container->GetId() == kShellWindowId_ArcVirtualKeyboardContainer;
  1112. }
  1113. bool TouchExplorationController::ShouldEnableVolumeSlideGesture(
  1114. const ui::TouchEvent& event) {
  1115. // Can be nullptr in unit tests.
  1116. int edge = FindEdgesWithinInset(event.location(), kMaxDistanceFromEdge);
  1117. return edge & RIGHT_EDGE && edge != BOTTOM_RIGHT_CORNER &&
  1118. (!Shell::HasInstance() ||
  1119. Shell::Get()->tablet_mode_controller()->InTabletMode() ||
  1120. Shell::Get()
  1121. ->accessibility_controller()
  1122. ->enable_chromevox_volume_slide_gesture());
  1123. }
  1124. } // namespace ash