| Index: ui/chromeos/touch_exploration_controller.h
|
| diff --git a/ui/chromeos/touch_exploration_controller.h b/ui/chromeos/touch_exploration_controller.h
|
| index d6fa8af0da7fd47ed933019d57ea2d1cece9efc0..4010a7d9c2ca576f77e260f0e9f89c3fb1d0e6aa 100644
|
| --- a/ui/chromeos/touch_exploration_controller.h
|
| +++ b/ui/chromeos/touch_exploration_controller.h
|
| @@ -5,9 +5,11 @@
|
| #ifndef UI_CHROMEOS_TOUCH_EXPLORATION_CONTROLLER_H_
|
| #define UI_CHROMEOS_TOUCH_EXPLORATION_CONTROLLER_H_
|
|
|
| +#include "base/timer/timer.h"
|
| #include "base/values.h"
|
| #include "ui/chromeos/ui_chromeos_export.h"
|
| #include "ui/events/event_rewriter.h"
|
| +#include "ui/events/gesture_detection/gesture_detector.h"
|
| #include "ui/gfx/geometry/point.h"
|
|
|
| namespace aura {
|
| @@ -17,17 +19,58 @@ class Window;
|
| namespace ui {
|
|
|
| class Event;
|
| +class EventHandler;
|
| +class TouchEvent;
|
|
|
| // TouchExplorationController is used in tandem with "Spoken Feedback" to
|
| -// make the touch UI accessible. TouchExplorationController rewrites the
|
| -// incoming touch events as follows:
|
| -// - When one finger is touching the screen, touch events are converted to mouse
|
| -// moves. This is the "Touch Exploration Mode". (The idea is that mouse moves
|
| -// will be subsequently used by another component to move focus between UI
|
| -// elements, and the elements will be read out to the user.)
|
| -// - When more than one finger is touching the screen, touches from the
|
| -// first (i.e. "oldest") finger are ignored, and the other touches go through
|
| -// as is.
|
| +// make the touch UI accessible.
|
| +//
|
| +// ** Short version **
|
| +//
|
| +// At a high-level, single-finger events are used for accessibility -
|
| +// exploring the screen gets turned into mouse moves (which can then be
|
| +// spoken by an accessibility service running), a double-tap simulates a
|
| +// click, and gestures can be used to send high-level accessibility commands.
|
| +// When two or more fingers are pressed initially, from then on the events
|
| +// are passed through, but with the initial finger removed - so if you swipe
|
| +// down with two fingers, the running app will see a one-finger swipe.
|
| +//
|
| +// ** Long version **
|
| +//
|
| +// Here are the details of the implementation:
|
| +//
|
| +// When the first touch is pressed, a 300 ms grace period timer starts.
|
| +//
|
| +// If the user keeps their finger down for more than 300 ms and doesn't
|
| +// perform a supported accessibility gesture in that time (e.g. swipe right),
|
| +// they enter touch exploration mode, and all movements are translated into
|
| +// synthesized mouse move events.
|
| +//
|
| +// Also, if the user moves their single finger outside a certain slop region
|
| +// (without performing a gesture), they enter touch exploration mode earlier
|
| +// than 300 ms.
|
| +//
|
| +// If the user taps and releases their finger, after 300 ms from the initial
|
| +// touch, a single mouse move is fired.
|
| +//
|
| +// If the user double-taps, the second tap is passed through, allowing the
|
| +// user to click - however, the double-tap location is changed to the location
|
| +// of the last successful touch exploration - that allows the user to explore
|
| +// anywhere on the screen, hear its description, then double-tap anywhere
|
| +// to activate it.
|
| +//
|
| +// If the user adds a second finger during the grace period, they enter
|
| +// passthrough mode. In this mode, the first finger is ignored but all
|
| +// additional touch events are mostly passed through unmodified. So a
|
| +// two-finger scroll gets passed through as a one-finger scroll. However,
|
| +// once in passthrough mode, if one finger is released, the remaining fingers
|
| +// continue to pass through events, allowing the user to start a scroll
|
| +// with two fingers but finish it with one. Sometimes this requires rewriting
|
| +// the touch ids.
|
| +//
|
| +// Once either touch exploration or passthrough mode has been activated,
|
| +// it remains in that mode until all fingers have been released.
|
| +//
|
| // The caller is expected to retain ownership of instances of this class and
|
| // destroy them before |root_window| is destroyed.
|
| class UI_CHROMEOS_EXPORT TouchExplorationController :
|
| @@ -36,28 +79,120 @@ class UI_CHROMEOS_EXPORT TouchExplorationController :
|
| explicit TouchExplorationController(aura::Window* root_window);
|
| virtual ~TouchExplorationController();
|
|
|
| - private:
|
| - scoped_ptr<ui::Event> CreateMouseMoveEvent(const gfx::PointF& location,
|
| - int flags);
|
| -
|
| - void EnterTouchToMouseMode();
|
| + void CallTapTimerNowForTesting();
|
| + void SetEventHandlerForTesting(ui::EventHandler* event_handler_for_testing);
|
| + bool IsInNoFingersDownStateForTesting() const;
|
|
|
| + private:
|
| // Overridden from ui::EventRewriter
|
| virtual ui::EventRewriteStatus RewriteEvent(
|
| const ui::Event& event, scoped_ptr<ui::Event>* rewritten_event) OVERRIDE;
|
| virtual ui::EventRewriteStatus NextDispatchEvent(
|
| const ui::Event& last_event, scoped_ptr<ui::Event>* new_event) OVERRIDE;
|
|
|
| + // Event handlers based on the current state - see State, below.
|
| + ui::EventRewriteStatus InNoFingersDown(
|
| + const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event);
|
| + ui::EventRewriteStatus InSingleTapPressed(
|
| + const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event);
|
| + ui::EventRewriteStatus InSingleTapReleased(
|
| + const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event);
|
| + ui::EventRewriteStatus InDoubleTapPressed(
|
| + const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event);
|
| + ui::EventRewriteStatus InTouchExploration(
|
| + const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event);
|
| + ui::EventRewriteStatus InPassthroughMinusOne(
|
| + const ui::TouchEvent& event, scoped_ptr<ui::Event>* rewritten_event);
|
| +
|
| + // This timer is started every time we get the first press event, and
|
| + // it fires after the double-click timeout elapses (300 ms by default).
|
| + // If the user taps and releases within 300 ms and doesn't press again,
|
| + // we treat that as a single mouse move (touch exploration) event.
|
| + void OnTapTimerFired();
|
| +
|
| + // Dispatch a new event outside of the event rewriting flow.
|
| + void DispatchEvent(ui::Event* event);
|
| +
|
| + scoped_ptr<ui::Event> CreateMouseMoveEvent(const gfx::PointF& location,
|
| + int flags);
|
| +
|
| + void EnterTouchToMouseMode();
|
| +
|
| + // Set the state to NO_FINGERS_DOWN and reset any other fields to their
|
| + // default value.
|
| + void ResetToNoFingersDown();
|
| +
|
| + enum State {
|
| + // No fingers are down and no events are pending.
|
| + NO_FINGERS_DOWN,
|
| +
|
| + // A single finger is down, but we're not yet sure if this is going
|
| + // to be touch exploration or something else.
|
| + SINGLE_TAP_PRESSED,
|
| +
|
| + // The user pressed and released a single finger - a tap - but we have
|
| + // to wait until the end of the grace period to allow the user to tap the
|
| + // second time. If the second tap doesn't occurs within the grace period,
|
| + // we dispatch a mouse move at the location of the first tap.
|
| + SINGLE_TAP_RELEASED,
|
| +
|
| + // The user tapped once, and before the grace period expired, pressed
|
| + // one finger down to begin a double-tap, but has not released it yet.
|
| + DOUBLE_TAP_PRESSED,
|
| +
|
| + // We're in touch exploration mode. Anything other than the first finger
|
| + // is ignored, and movements of the first finger are rewritten as mouse
|
| + // move events. This mode is entered if a single finger is pressed and
|
| + // after the grace period the user hasn't added a second finger or
|
| + // moved the finger outside of the slop region. We'll stay in this
|
| + // mode until all fingers are lifted.
|
| + TOUCH_EXPLORATION,
|
| +
|
| + // The user placed two or more fingers down within the grace period.
|
| + // We're now in passthrough mode until all fingers are lifted. Initially
|
| + // the first finger is ignored and other fingers are passed through
|
| + // as-is. If a finger other than the initial one is the first to be
|
| + // released, we rewrite the first finger with the touch id of the finger
|
| + // that was released, from now on. The motivation for this is that if
|
| + // the user starts a scroll with 2 fingers, they can release either one
|
| + // and continue the scrolling.
|
| + PASSTHROUGH_MINUS_ONE,
|
| + };
|
| +
|
| + aura::Window* root_window_;
|
| +
|
| // A set of touch ids for fingers currently touching the screen.
|
| - std::vector<int> touch_ids_;
|
| + std::vector<int> current_touch_ids_;
|
|
|
| // Map of touch ids to their last known location.
|
| std::map<int, gfx::PointF> touch_locations_;
|
|
|
| - // Initialized from RewriteEvent() and dispatched in NextDispatchEvent().
|
| - scoped_ptr<ui::Event> next_dispatch_event_;
|
| + // The touch id that any events on the initial finger should be rewritten
|
| + // as in passthrough-minus-one mode. If kTouchIdUnassigned, events on the
|
| + // initial finger are discarded. If kTouchIdNone, the initial finger
|
| + // has been released and no more rewriting will be done.
|
| + int initial_touch_id_passthrough_mapping_;
|
|
|
| - aura::Window* root_window_;
|
| + // The current state.
|
| + State state_;
|
| +
|
| + // A copy of the event from the initial touch press.
|
| + scoped_ptr<ui::TouchEvent> initial_press_;
|
| +
|
| + // The last location where we synthesized a mouse move event.
|
| + // When the user double-taps, we send the passed-through tap here.
|
| + gfx::PointF last_touch_exploration_location_;
|
| +
|
| + // A timer to fire the mouse move event after the double-tap delay.
|
| + base::OneShotTimer<TouchExplorationController> tap_timer_;
|
| +
|
| + // For testing only, an event handler to use for generated events
|
| + // outside of the normal event rewriting flow.
|
| + ui::EventHandler* event_handler_for_testing_;
|
| +
|
| + // A default gesture detector config, so we can share the same
|
| + // timeout and pixel slop constants.
|
| + ui::GestureDetector::Config gesture_detector_config_;
|
|
|
| DISALLOW_COPY_AND_ASSIGN(TouchExplorationController);
|
| };
|
|
|