touch_exploration_controller.h 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565
  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. #ifndef ASH_ACCESSIBILITY_CHROMEVOX_TOUCH_EXPLORATION_CONTROLLER_H_
  5. #define ASH_ACCESSIBILITY_CHROMEVOX_TOUCH_EXPLORATION_CONTROLLER_H_
  6. #include <map>
  7. #include <memory>
  8. #include <vector>
  9. #include "ash/ash_export.h"
  10. #include "base/memory/weak_ptr.h"
  11. #include "base/time/time.h"
  12. #include "base/timer/timer.h"
  13. #include "ui/accessibility/ax_enums.mojom-forward.h"
  14. #include "ui/events/event.h"
  15. #include "ui/events/event_rewriter.h"
  16. #include "ui/events/gesture_detection/gesture_detector.h"
  17. #include "ui/events/gestures/gesture_provider_aura.h"
  18. #include "ui/gfx/geometry/point.h"
  19. namespace aura {
  20. class Window;
  21. }
  22. namespace ui {
  23. class Event;
  24. class GestureEvent;
  25. class GestureProviderAura;
  26. class TouchEvent;
  27. } // namespace ui
  28. namespace ash {
  29. class TouchAccessibilityEnabler;
  30. // A delegate to handle commands in response to detected accessibility gesture
  31. // events.
  32. class TouchExplorationControllerDelegate {
  33. public:
  34. virtual ~TouchExplorationControllerDelegate() {}
  35. // Takes an int from 0.0 to 100.0 that indicates the percent the volume
  36. // should be set to.
  37. virtual void SetOutputLevel(int volume) = 0;
  38. // Silences spoken feedback.
  39. virtual void SilenceSpokenFeedback() = 0;
  40. // This function should be called when the volume adjust earcon should be
  41. // played
  42. virtual void PlayVolumeAdjustEarcon() = 0;
  43. // This function should be called when the passthrough earcon should be
  44. // played.
  45. virtual void PlayPassthroughEarcon() = 0;
  46. // This function should be called when the long press right click earcon
  47. // should be played.
  48. virtual void PlayLongPressRightClickEarcon() = 0;
  49. // This function should be called when the enter screen earcon should be
  50. // played.
  51. virtual void PlayEnterScreenEarcon() = 0;
  52. // This function should be called when the touch type earcon should
  53. // be played.
  54. virtual void PlayTouchTypeEarcon() = 0;
  55. // Called when the user performed an accessibility gesture while in touch
  56. // accessibility mode, that should be forwarded to ChromeVox.
  57. virtual void HandleAccessibilityGesture(
  58. ax::mojom::Gesture gesture,
  59. gfx::PointF location = gfx::PointF()) = 0;
  60. };
  61. // TouchExplorationController is used in tandem with "Spoken Feedback" to
  62. // make the touch UI accessible. Gestures performed in the middle of the screen
  63. // are mapped to accessibility key shortcuts while gestures performed on the
  64. // edge of the screen can change settings.
  65. //
  66. // ** Short version **
  67. //
  68. // At a high-level, single-finger events are used for accessibility -
  69. // exploring the screen gets turned into touch explore gestures (which can then
  70. // be hit tested by an accessibility service running, result then to be spoken),
  71. // a single tap while the user is in touch exploration or a double-tap simulates
  72. // a click, and gestures can be used to send high-level accessibility commands.
  73. // For example, a swipe right would correspond to the keyboard short cut
  74. // shift+search+right. Swipes with up to four fingers are also mapped to
  75. // commands. Slide gestures performed on the edge of the screen can change
  76. // settings continuously. For example, sliding a finger along the right side of
  77. // the screen will change the volume. When a user double taps and holds with one
  78. // finger, the finger is passed through as if accessibility was turned off. If
  79. // the user taps the screen with two fingers, the user can silence spoken
  80. // feedback if it is playing.
  81. //
  82. // ** Long version **
  83. //
  84. // Here are the details of the implementation:
  85. //
  86. // When the first touch is pressed, a 300 ms grace period timer starts.
  87. //
  88. // If the user keeps their finger down for more than 300 ms and doesn't
  89. // perform a supported accessibility gesture in that time (e.g. swipe right),
  90. // they enter touch exploration mode, and all movements are routed
  91. // to ChromeVox with the touch location.
  92. //
  93. // Also, if the user moves their single finger outside a certain slop region
  94. // (without performing a gesture), they enter touch exploration mode earlier
  95. // than 300 ms.
  96. //
  97. // If the user taps and releases their finger, after 300 ms from the initial
  98. // touch, a single touch explore gesture is fired.
  99. //
  100. // The user can perform swipe gestures in one of the four cardinal directions
  101. // which will be interpreted and used to control the UI. All gestures will only
  102. // be registered if the fingers move outside the slop, and all fingers will only
  103. // be registered if they are completed within the grace period. If a single
  104. // finger gesture fails to be completed within the grace period, the state
  105. // changes to touch exploration mode. If a multi finger gesture fails to be
  106. // completed within the grace period, the user must lift all fingers before
  107. // completing any more actions.
  108. //
  109. // The user's initial tap sets the anchor point. Simulated events are
  110. // positioned relative to the anchor point, so that after exploring to find
  111. // an object the user can double-tap anywhere on the screen to activate it.
  112. // The anchor point is also set by ChromeVox every time it highlights an
  113. // object on the screen. During touch exploration this ensures that
  114. // any simulated events go to the center of the most recently highlighted
  115. // object, rather than to the exact tap location (which could have drifted
  116. // off of the object). This also ensures that when the current ChromeVox
  117. // object changes due to a gesture or input focus changing, simulated
  118. // events go to that object and not the last location touched by a finger.
  119. //
  120. // When the user double-taps, this is treated as a discrete gestures, and
  121. // and event is sent to ChromeVox to activate the current object, whatever
  122. // that is. However, when the user double-taps and holds, any event from that
  123. // finger is passed through, allowing the user to drag. These events are
  124. // passed through with a location that's relative to the anchor point.
  125. //
  126. // If any other fingers are added or removed during a passthrough, they are
  127. // ignored. Once the passthrough finger is released, passthrough stops and
  128. // the state is reset to the no fingers down state.
  129. //
  130. // If the user enters touch exploration mode, they can click without lifting
  131. // their touch exploration finger by tapping anywhere else on the screen with
  132. // a second finger, while the touch exploration finger is still pressed.
  133. //
  134. // Once touch exploration mode has been activated, it remains in that mode until
  135. // all fingers have been released.
  136. //
  137. // If the user places a finger on the edge of the screen and moves their finger
  138. // past slop, a slide gesture is performed. The user can then slide one finger
  139. // along an edge of the screen and continuously control a setting. Once the user
  140. // enters this state, the boundaries that define an edge expand so that the user
  141. // can now adjust the setting within a slightly bigger width along the screen.
  142. // If the user exits this area without lifting their finger, they will not be
  143. // able to perform any actions, however if they keep their finger down and
  144. // return to the "hot edge," then they can still adjust the setting. In order to
  145. // perform other touch accessibility movements, the user must lift their finger.
  146. // If additional fingers are added while in this state, the user will transition
  147. // to passthrough.
  148. //
  149. // Currently, only the right edge is mapped to control the volume. Volume
  150. // control along the edge of the screen is directly proportional to where the
  151. // user's finger is located on the screen. The top right corner of the screen
  152. // automatically sets the volume to 100% and the bottome right corner of the
  153. // screen automatically sets the volume to 0% once the user has moved past slop.
  154. //
  155. // If the user taps the screen with two fingers and lifts both fingers before
  156. // the grace period has passed, spoken feedback is silenced.
  157. //
  158. // The user can also enter passthrough by placing a finger on one of the bottom
  159. // corners of the screen until an earcon sounds. After the earcon sounds, the
  160. // user is in passthrough so all subsequent fingers placed on the screen will be
  161. // passed through. Once the finger in the corner has been released, the state
  162. // will switch to wait for no fingers.
  163. //
  164. // The caller is expected to retain ownership of instances of this class and
  165. // destroy them before |root_window| is destroyed.
  166. class ASH_EXPORT TouchExplorationController
  167. : public ui::EventRewriter,
  168. public ui::GestureProviderAuraClient,
  169. public ui::GestureConsumer {
  170. public:
  171. explicit TouchExplorationController(
  172. aura::Window* root_window,
  173. TouchExplorationControllerDelegate* delegate,
  174. base::WeakPtr<TouchAccessibilityEnabler> touch_accessibility_enabler);
  175. TouchExplorationController(const TouchExplorationController&) = delete;
  176. TouchExplorationController& operator=(const TouchExplorationController&) =
  177. delete;
  178. ~TouchExplorationController() override;
  179. // Make synthesized touch events are anchored at this point. This is
  180. // called when the object with accessibility focus is updated via something
  181. // other than touch exploration.
  182. void SetTouchAccessibilityAnchorPoint(const gfx::Point& anchor_point);
  183. // Events within the exclude bounds will not be rewritten.
  184. // |bounds| are in root window coordinates.
  185. void SetExcludeBounds(const gfx::Rect& bounds);
  186. // Updates |lift_activation_bounds_|. See |lift_activation_bounds_| for more
  187. // information.
  188. void SetLiftActivationBounds(const gfx::Rect& bounds);
  189. private:
  190. friend class TouchExplorationControllerTestApi;
  191. // Overridden from ui::EventRewriter
  192. ui::EventDispatchDetails RewriteEvent(
  193. const ui::Event& event,
  194. const Continuation continuation) override;
  195. // Event handlers based on the current state - see State, below.
  196. ui::EventDispatchDetails InNoFingersDown(const ui::TouchEvent& event,
  197. const Continuation continuation);
  198. ui::EventDispatchDetails InSingleTapPressed(const ui::TouchEvent& event,
  199. const Continuation continuation);
  200. ui::EventDispatchDetails InSingleTapOrTouchExploreReleased(
  201. const ui::TouchEvent& event,
  202. const Continuation continuation);
  203. ui::EventDispatchDetails InDoubleTapPending(const ui::TouchEvent& event,
  204. const Continuation continuation);
  205. ui::EventDispatchDetails InTouchReleasePending(
  206. const ui::TouchEvent& event,
  207. const Continuation continuation);
  208. ui::EventDispatchDetails InTouchExploration(const ui::TouchEvent& event,
  209. const Continuation continuation);
  210. ui::EventDispatchDetails InOneFingerPassthrough(
  211. const ui::TouchEvent& event,
  212. const Continuation continuation);
  213. ui::EventDispatchDetails InGestureInProgress(const ui::TouchEvent& event,
  214. const Continuation continuation);
  215. ui::EventDispatchDetails InTouchExploreSecondPress(
  216. const ui::TouchEvent& event,
  217. const Continuation continuation);
  218. ui::EventDispatchDetails InTouchExploreLongPress(
  219. const ui::TouchEvent& event,
  220. const Continuation continuation);
  221. ui::EventDispatchDetails InWaitForNoFingers(const ui::TouchEvent& event,
  222. const Continuation continuation);
  223. ui::EventDispatchDetails InSlideGesture(const ui::TouchEvent& event,
  224. const Continuation continuation);
  225. ui::EventDispatchDetails InTwoFingerTap(const ui::TouchEvent& event,
  226. const Continuation continuation);
  227. // Returns the current time of the tick clock.
  228. base::TimeTicks Now();
  229. // This timer is started every time we get the first press event, and
  230. // it fires after the double-click timeout elapses (300 ms by default).
  231. // If the user taps and releases within 300 ms and doesn't press again,
  232. // we treat that as a single touch explore gesture event.
  233. void StartTapTimer();
  234. void OnTapTimerFired();
  235. // This timer is reset every time the anchor point changes. It only triggers a
  236. // long press if the user is touch exploring in lift activated bounds.
  237. void ResetLiftActivationLongPressTimer();
  238. void OnLiftActivationLongPressTimerFired();
  239. // Dispatch a new event outside of the event rewriting flow.
  240. void DispatchEvent(ui::Event* event, const Continuation continuation);
  241. // Overridden from GestureProviderAuraClient.
  242. //
  243. // The gesture provider keeps track of all the touch events after
  244. // the user moves fast enough to trigger a gesture. After the user
  245. // completes their gesture, this method will decide what keyboard
  246. // input their gesture corresponded to.
  247. void OnGestureEvent(ui::GestureConsumer* raw_input_consumer,
  248. ui::GestureEvent* gesture) override;
  249. // ui::GestureConsumer:
  250. const std::string& GetName() const override;
  251. // Process the gesture events that have been created.
  252. void ProcessGestureEvents();
  253. void OnSwipeEvent(ui::GestureEvent* swipe_gesture);
  254. void SideSlideControl(ui::GestureEvent* gesture);
  255. // Dispatches a single key with the given flags.
  256. void DispatchKeyWithFlags(const ui::KeyboardCode key,
  257. int flags,
  258. const Continuation continuation);
  259. void EnterTouchToMouseMode();
  260. void PlaySoundForTimer();
  261. // Sends a simulated click.
  262. void SendSimulatedClick();
  263. // Sends a simulated tap at anchor point.
  264. void SendSimulatedTap(const Continuation continuation);
  265. // Sends a simulated tap, if the anchor point falls within lift activation
  266. // bounds.
  267. void MaybeSendSimulatedTapInLiftActivationBounds(
  268. const ui::TouchEvent& event,
  269. const Continuation continuation);
  270. // Some constants used in touch_exploration_controller:
  271. // Within this many dips of the screen edge, the release event generated will
  272. // reset the state to NoFingersDown.
  273. const float kLeavingScreenEdge = 6;
  274. // Swipe/scroll gestures within these bounds (in DIPs) will change preset
  275. // settings.
  276. const float kMaxDistanceFromEdge = 75;
  277. // After a slide gesture has been triggered, if the finger is still within
  278. // these bounds (in DIPs), the preset settings will still change.
  279. const float kSlopDistanceFromEdge = kMaxDistanceFromEdge + 40;
  280. // The split tap slop is a bit more generous since keeping two
  281. // fingers in place is a bit harder.
  282. float GetSplitTapTouchSlop();
  283. // Convert a gfx::PointF from DIP back to raw screen coordinates. Origin is
  284. // based on its root window host.
  285. gfx::PointF ConvertDIPToPixels(const gfx::PointF& location);
  286. // Returns true if the touch event is targeted to Arc virtual keyboard.
  287. bool IsTargetedToArcVirtualKeyboard(const gfx::Point& location_in_host);
  288. // Whether the right side of the screen should serve as a volume control.
  289. bool ShouldEnableVolumeSlideGesture(const ui::TouchEvent& event);
  290. enum State {
  291. // No fingers are down and no events are pending.
  292. NO_FINGERS_DOWN,
  293. // A single finger is down, but we're not yet sure if this is going
  294. // to be touch exploration or something else.
  295. SINGLE_TAP_PRESSED,
  296. // The user pressed and released a single finger - a tap - but we have
  297. // to wait until the end of the grace period to allow the user to tap the
  298. // second time. If the second tap doesn't occurs within the grace period,
  299. // we dispatch a touch explore gesture at the location of the first tap.
  300. SINGLE_TAP_RELEASED,
  301. // The user was in touch explore mode and released the finger.
  302. // If another touch press occurs within the grace period, a single
  303. // tap click occurs. This state differs from SINGLE_TAP_RELEASED
  304. // in that if a second tap doesn't occur within the grace period,
  305. // there is no touch explore gesture dispatched.
  306. TOUCH_EXPLORE_RELEASED,
  307. // The user tapped once, and before the grace period expired, pressed
  308. // one finger down to begin a double-tap, but has not released it yet.
  309. // This could become passthrough, so no touch press is dispatched yet.
  310. DOUBLE_TAP_PENDING,
  311. // The user was doing touch exploration, started split tap, but lifted the
  312. // touch exploration finger. Once they remove all fingers, a touch release
  313. // will go through.
  314. TOUCH_RELEASE_PENDING,
  315. // We're in touch exploration mode. Anything other than the first finger
  316. // is ignored, and movements of the first finger are sent as touch explore
  317. // gesture events. This mode is entered if a single finger is pressed and
  318. // after the grace period the user hasn't added a second finger or
  319. // moved the finger outside of the slop region. We'll stay in this
  320. // mode until all fingers are lifted.
  321. TOUCH_EXPLORATION,
  322. // If the user moves their finger faster than the threshold velocity after a
  323. // single tap, the touch events that follow will be translated into gesture
  324. // events. If the user successfully completes a gesture within the grace
  325. // period, the gesture will be interpreted and used to control the UI via
  326. // discrete actions - currently by synthesizing key events corresponding to
  327. // each gesture Otherwise, the collected gestures are discarded and the
  328. // state changes to touch_exploration.
  329. GESTURE_IN_PROGRESS,
  330. // The user was in touch exploration, but has placed down another finger.
  331. // If the user releases the second finger, a touch press and release
  332. // will go through at the last touch explore location. If the user
  333. // releases the touch explore finger, the touch press and release will
  334. // still go through once the split tap finger is also lifted. If any
  335. // fingers pressed past the first two, the touch press is cancelled and
  336. // the user enters the wait state for the fingers to be removed.
  337. TOUCH_EXPLORE_SECOND_PRESS,
  338. // The user was in touch exploration, but has remained in the same anchor
  339. // point for a long period of time. The first event to handled in this state
  340. // will be rewritten as a right mouse click and then re-enters touch
  341. // exploration state.
  342. TOUCH_EXPLORE_LONG_PRESS,
  343. // After the user double taps and holds with a single finger, all events
  344. // for that finger are passed through, displaced by an offset. Adding
  345. // extra fingers has no effect. This state is left when the user removes
  346. // all fingers.
  347. ONE_FINGER_PASSTHROUGH,
  348. // If the user added another finger in SINGLE_TAP_PRESSED, or if the user
  349. // has multiple fingers fingers down in any other state between
  350. // passthrough, touch exploration, and gestures, they must release
  351. // all fingers before completing any more actions. This state is
  352. // generally useful for developing new features, because it creates a
  353. // simple way to handle a dead end in user flow.
  354. WAIT_FOR_NO_FINGERS,
  355. // If the user is within the given bounds from an edge of the screen, not
  356. // including corners, then the resulting movements will be interpreted as
  357. // slide gestures.
  358. SLIDE_GESTURE,
  359. // If the user taps the screen with two fingers and releases both fingers
  360. // before the grace period has passed, spoken feedback will be silenced.
  361. TWO_FINGER_TAP,
  362. };
  363. enum AnchorPointState {
  364. ANCHOR_POINT_NONE,
  365. ANCHOR_POINT_FROM_TOUCH_EXPLORATION,
  366. ANCHOR_POINT_EXPLICITLY_SET
  367. };
  368. enum ScreenLocation {
  369. // Hot "edges" of the screen are each represented by a respective bit.
  370. NO_EDGE = 0,
  371. RIGHT_EDGE = 1 << 0,
  372. TOP_EDGE = 1 << 1,
  373. LEFT_EDGE = 1 << 2,
  374. BOTTOM_EDGE = 1 << 3,
  375. BOTTOM_LEFT_CORNER = LEFT_EDGE | BOTTOM_EDGE,
  376. BOTTOM_RIGHT_CORNER = RIGHT_EDGE | BOTTOM_EDGE,
  377. };
  378. // Given a point, if it is within the given inset of an edge, returns the
  379. // edge. If it is within the given inset of two edges, returns an int with
  380. // both bits that represent the respective edges turned on. Otherwise returns
  381. // SCREEN_CENTER.
  382. int FindEdgesWithinInset(gfx::Point point, float inset);
  383. // Set the state and modifies any variables related to the state change.
  384. // (e.g. resetting the gesture provider).
  385. void SetState(State new_state, const char* function_name);
  386. void VlogState(const char* function_name);
  387. void VlogEvent(const ui::TouchEvent& event, const char* function_name);
  388. // Gets enum name from integer value.
  389. const char* EnumStateToString(State state);
  390. void SetAnchorPointInternal(const gfx::PointF& anchor_point);
  391. aura::Window* root_window_;
  392. // Handles volume control. Not owned.
  393. TouchExplorationControllerDelegate* delegate_;
  394. // A set of touch ids for fingers currently touching the screen.
  395. std::vector<int> current_touch_ids_;
  396. // Map of touch ids to their last known location.
  397. std::map<int, gfx::PointF> touch_locations_;
  398. // The current state.
  399. State state_;
  400. // A copy of the event from the initial touch press.
  401. std::unique_ptr<ui::TouchEvent> initial_press_;
  402. Continuation initial_press_continuation_;
  403. // The timestamp of the most recent press event for the main touch id.
  404. // The difference between this and |initial_press_->time_stamp| is that
  405. // |most_recent_press_timestamp_| is reset in a double-tap.
  406. base::TimeTicks most_recent_press_timestamp_;
  407. // Map of touch ids to where its initial press occurred relative to the
  408. // screen.
  409. std::map<int, gfx::Point> initial_presses_;
  410. // In one finger passthrough, the touch is displaced relative to the
  411. // last touch exploration location.
  412. gfx::Vector2dF passthrough_offset_;
  413. // Stores the most recent event from a finger that is currently not
  414. // sending events through, but might in the future (e.g. before a finger
  415. // enters double-tap-hold passthrough, we need to update its location.)
  416. std::unique_ptr<ui::TouchEvent> last_unused_finger_event_;
  417. Continuation last_unused_finger_continuation_;
  418. // The anchor point used as the location of a synthesized tap when the
  419. // user double-taps anywhere on the screen, and similarly the initial
  420. // point used when the user double-taps, holds, and drags. This can be
  421. // set either via touch exploration, or by a call to
  422. // SetTouchAccessibilityAnchorPoint when focus moves due to something other
  423. // than touch exploration. Origin of this coordinate is its root window host.
  424. gfx::PointF anchor_point_dip_;
  425. // The current state of the anchor point.
  426. AnchorPointState anchor_point_state_;
  427. // The last touch exploration event.
  428. std::unique_ptr<ui::TouchEvent> last_touch_exploration_;
  429. // A timer that fires after the double-tap delay.
  430. base::OneShotTimer tap_timer_;
  431. // A timer that fires after holding the anchor point in place.
  432. // Only works within lift activation bounds.
  433. base::OneShotTimer long_press_timer_;
  434. // A timer to fire an indicating sound when sliding to change volume.
  435. base::RepeatingTimer sound_timer_;
  436. // A default gesture detector config, so we can share the same
  437. // timeout and pixel slop constants.
  438. ui::GestureDetector::Config gesture_detector_config_;
  439. // Gesture Handler to interpret the touch events.
  440. std::unique_ptr<ui::GestureProviderAura> gesture_provider_;
  441. // The previous state entered.
  442. State prev_state_;
  443. // A copy of the previous event passed.
  444. std::unique_ptr<ui::TouchEvent> prev_event_;
  445. // This toggles whether VLOGS are turned on or not.
  446. bool VLOG_on_;
  447. // LocatedEvents within this area should be left alone.
  448. // TODO(crbug.com/616793): Multi display support. With this implementation, we
  449. // cannot specify display.
  450. gfx::Rect exclude_bounds_;
  451. // Code that detects a touch-screen gesture to enable or disable
  452. // accessibility. That handler is always running, whereas this is not,
  453. // but events need to be sent to TouchAccessibilityEnabler before being
  454. // rewritten when TouchExplorationController is running.
  455. base::WeakPtr<TouchAccessibilityEnabler> touch_accessibility_enabler_;
  456. // Any touch exploration that both starts and ends (touch pressed, and
  457. // released) within this rectangle, triggers a simulated single finger tap at
  458. // the anchor point on release.
  459. // TODO(crbug.com/616793): Multi display support. With this implementation, we
  460. // cannot specify display.
  461. gfx::Rect lift_activation_bounds_;
  462. // Whether or not we've seen a touch press event yet.
  463. bool seen_press_ = false;
  464. // The maximum touch points seen in the current gesture.
  465. size_t max_gesture_touch_points_ = 0;
  466. };
  467. } // namespace ash
  468. #endif // ASH_ACCESSIBILITY_CHROMEVOX_TOUCH_EXPLORATION_CONTROLLER_H_