Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(372)

Unified Diff: ui/chromeos/touch_exploration_controller.cc

Issue 385073009: Side Slide Gestures for Accessibility (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Added Tests for Slide Gestures Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: ui/chromeos/touch_exploration_controller.cc
diff --git a/ui/chromeos/touch_exploration_controller.cc b/ui/chromeos/touch_exploration_controller.cc
index 287e59fd6d39626498b31342d6cde3915ff92020..ea349175d8c9dbe91a338a0cdc96d0a9c99775fa 100644
--- a/ui/chromeos/touch_exploration_controller.cc
+++ b/ui/chromeos/touch_exploration_controller.cc
@@ -4,7 +4,6 @@
#include "ui/chromeos/touch_exploration_controller.h"
-#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
#include "ui/aura/client/cursor_client.h"
#include "ui/aura/window.h"
@@ -12,6 +11,7 @@
#include "ui/aura/window_tree_host.h"
#include "ui/events/event.h"
#include "ui/events/event_processor.h"
+#include "ui/gfx/geometry/rect.h"
#define VLOG_STATE() if (VLOG_IS_ON(0)) VlogState(__func__)
#define VLOG_EVENT(event) if (VLOG_IS_ON(0)) VlogEvent(event, __func__)
@@ -19,12 +19,33 @@
namespace ui {
namespace {
+int SignOf(float number) {
+ if (number == 0)
+ return 0;
+ return number > 0 ? 1 : -1;
+}
+
+// Delay between adjustment sounds.
+const base::TimeDelta kSoundDelay = base::TimeDelta::FromMilliseconds(150);
+
+// Minimum Volume adjustment.
+const float kMinPercentVolumeChange = 1;
+
+// Swipe/scroll gestures within these bounds (in dips) will change preset
+// settings.
+const float kMaxDistanceFromEdge = 75;
+
+// After a slide gesture has been triggered, if the finger is still within these
+// bounds, the preset settings will still change.
+const float kSlopDistanceFromEdge = kMaxDistanceFromEdge + 40;
+
// In ChromeOS, VKEY_LWIN is synonymous for the search key.
const ui::KeyboardCode kChromeOSSearchKey = ui::VKEY_LWIN;
} // namespace
TouchExplorationController::TouchExplorationController(
- aura::Window* root_window)
+ aura::Window* root_window,
+ TouchExplorationControllerDelegate* delegate)
: root_window_(root_window),
state_(NO_FINGERS_DOWN),
event_handler_for_testing_(NULL),
@@ -33,6 +54,7 @@ TouchExplorationController::TouchExplorationController(
VLOG_on_(true) {
CHECK(root_window);
root_window->GetHost()->GetEventSource()->AddEventRewriter(this);
+ delegate_.reset(delegate);
dmazzoni 2014/07/14 18:00:34 Do this as an initializer before the initial {, as
lisayin 2014/07/14 22:38:38 Done.
}
@@ -67,7 +89,15 @@ bool TouchExplorationController::IsInGestureInProgressStateForTesting() const {
}
void TouchExplorationController::SuppressVLOGsForTesting(bool suppress) {
- VLOG_on_ = !suppress;
+ VLOG_on_ = !suppress;
+}
+
+gfx::Rect TouchExplorationController::BoundsOfWindowInDIPForTesting() {
dmazzoni 2014/07/14 18:00:33 This should be BoundsOfRootWindow...?
lisayin 2014/07/14 22:38:38 Done.
+ return root_window_->GetBoundsInScreen();
+}
+
+bool TouchExplorationController::IsInSlideGestureStateForTesting() const {
+ return state_ == SLIDE_GESTURE;
}
ui::EventRewriteStatus TouchExplorationController::RewriteEvent(
@@ -152,6 +182,8 @@ ui::EventRewriteStatus TouchExplorationController::RewriteEvent(
return InPassthrough(touch_event, rewritten_event);
case WAIT_FOR_RELEASE:
return InWaitForRelease(touch_event, rewritten_event);
+ case SLIDE_GESTURE:
+ return InSlideGesture(touch_event, rewritten_event);
}
NOTREACHED();
return ui::EVENT_REWRITE_CONTINUE;
@@ -222,6 +254,14 @@ ui::EventRewriteStatus TouchExplorationController::InSingleTapPressed(
<< "\n Minimum swipe velocity: "
<< gesture_detector_config_.minimum_swipe_velocity;
+ // Change to slide gesture if the slide occurred at the right edge.
+ int where = WithinBoundsOfEdge(event.location(), kMaxDistanceFromEdge);
+ if ((where | RIGHT_EDGE) == where) {
+ state_ = SLIDE_GESTURE;
+ VLOG_STATE();
+ return InSlideGesture(event, rewritten_event);
+ }
+
// If the user moves fast enough from the initial touch location, start
// gesture detection. Otherwise, jump to the touch exploration mode early.
if (velocity > gesture_detector_config_.minimum_swipe_velocity) {
@@ -502,6 +542,7 @@ ui::EventRewriteStatus TouchExplorationController::InTouchExploreSecondPress(
initial_press_->touch_id(),
event.time_stamp()));
(*rewritten_event)->set_flags(event.flags());
+ EnterTouchToMouseMode();
state_ = TOUCH_EXPLORATION;
EnterTouchToMouseMode();
VLOG_STATE();
@@ -528,6 +569,75 @@ ui::EventRewriteStatus TouchExplorationController::InWaitForRelease(
return EVENT_REWRITE_DISCARD;
}
+void TouchExplorationController::PlaySoundForTimer() {
+ delegate_->PlayVolumeAdjustSound();
+}
+
+ui::EventRewriteStatus TouchExplorationController::InSlideGesture(
+ const ui::TouchEvent& event,
+ scoped_ptr<ui::Event>* rewritten_event) {
+ ui::EventType type = event.type();
+ // If additional fingers are added before a swipe gesture has been registered,
+ // then wait until all fingers have been released.
dmazzoni 2014/07/14 18:00:34 This comment doesn't seem to describe what the cod
lisayin 2014/07/14 22:38:38 Done.
+ if (type == ui::ET_TOUCH_PRESSED ||
+ event.touch_id() != initial_press_->touch_id()) {
+ if (tap_timer_.IsRunning())
+ tap_timer_.Stop();
+ // Discard any pending gestures.
+ ignore_result(gesture_provider_.GetAndResetPendingGestures());
+ state_ = TWO_TO_ONE_FINGER;
+ last_two_to_one_.reset(new TouchEvent(event));
+ rewritten_event->reset(new ui::TouchEvent(ui::ET_TOUCH_PRESSED,
+ event.location(),
+ event.touch_id(),
+ event.time_stamp()));
+ (*rewritten_event)->set_flags(event.flags());
+ return EVENT_REWRITE_REWRITTEN;
+ }
+
+ VLOG(0) << "Location " << event.location().ToString();
+ // Allows user to return to the edge to adjust the sound if they have left the
+ // boundaries.
+ int where = WithinBoundsOfEdge(event.location(), kSlopDistanceFromEdge);
+ if (((where | RIGHT_EDGE) != where) && (type != ui::ET_TOUCH_RELEASED)) {
+ if (sound_timer_.IsRunning()) {
+ sound_timer_.Stop();
+ }
+ return EVENT_REWRITE_DISCARD;
+ }
+
+ // This can occur if the user leaves the screen edge and then returns to it to
+ // continue adjusting the sound.
+ if (!sound_timer_.IsRunning()) {
+ sound_timer_.Start(FROM_HERE,
+ kSoundDelay,
+ this,
+ &ui::TouchExplorationController::PlaySoundForTimer);
+ delegate_->PlayVolumeAdjustSound();
+ }
+ // The timer should not fire when sliding.
+ if (tap_timer_.IsRunning())
+ tap_timer_.Stop();
+
+ // There should not be more than one finger down.
+ DCHECK(current_touch_ids_.size() <= 1);
+ if (type == ui::ET_TOUCH_MOVED) {
+ gesture_provider_.OnTouchEvent(event);
+ gesture_provider_.OnTouchEventAck(false);
+ }
+ if (type == ui::ET_TOUCH_RELEASED || type == ui::ET_TOUCH_CANCELLED) {
+ gesture_provider_.OnTouchEvent(event);
+ gesture_provider_.OnTouchEventAck(false);
+ ignore_result(gesture_provider_.GetAndResetPendingGestures());
+ if (current_touch_ids_.size() == 0)
+ ResetToNoFingersDown();
+ return ui::EVENT_REWRITE_DISCARD;
+ }
+
+ ProcessGestureEvents();
+ return ui::EVENT_REWRITE_DISCARD;
+}
+
void TouchExplorationController::OnTapTimerFired() {
switch (state_) {
case SINGLE_TAP_RELEASED:
@@ -552,7 +662,7 @@ void TouchExplorationController::OnTapTimerFired() {
CreateMouseMoveEvent(initial_press_->location(), initial_press_->flags());
DispatchEvent(mouse_move.get());
last_touch_exploration_.reset(new TouchEvent(*initial_press_));
- }
+}
void TouchExplorationController::DispatchEvent(ui::Event* event) {
if (event_handler_for_testing_) {
@@ -563,15 +673,22 @@ void TouchExplorationController::DispatchEvent(ui::Event* event) {
root_window_->GetHost()->dispatcher()->OnEventFromSource(event);
}
-void TouchExplorationController::OnGestureEvent(ui::GestureEvent* gesture) {
+void TouchExplorationController::OnGestureEvent(
+ ui::GestureEvent* gesture) {
CHECK(gesture->IsGestureEvent());
+ ui::EventType type = gesture->type();
VLOG(0) << " \n Gesture Triggered: " << gesture->name();
- if (gesture->type() == ui::ET_GESTURE_SWIPE) {
- if (tap_timer_.IsRunning())
- tap_timer_.Stop();
+ if (type == ui::ET_GESTURE_SWIPE && state_ != SLIDE_GESTURE) {
+ VLOG(0) << "Swipe!";
+ ignore_result(gesture_provider_.GetAndResetPendingGestures());
OnSwipeEvent(gesture);
return;
}
+ if (gesture->IsScrollGestureEvent() && state_ == SLIDE_GESTURE) {
+ SideSlideControl(gesture);
dmazzoni 2014/07/14 18:00:33 Why are you using the gesture detector for slides?
lisayin 2014/07/14 22:38:38 Done.
+ VLOG(0) << "Sliding";
+ return;
+ }
}
void TouchExplorationController::ProcessGestureEvents() {
@@ -586,6 +703,73 @@ void TouchExplorationController::ProcessGestureEvents() {
}
}
+void TouchExplorationController::SideSlideControl(ui::GestureEvent* gesture) {
+ ui::EventType type = gesture->type();
+ gfx::Point location = gesture->location();
+ VLOG(0) << "Location " << location.ToString();
+ root_window_->GetHost()->ConvertPointToNativeScreen(&location);
+ if (WithinBoundsOfEdge(location, kSlopDistanceFromEdge) == SCREEN_CENTER) {
+ VLOG(0) << "No more Slide gesture ";
+ // Discard any pending gestures.
+ ignore_result(gesture_provider_.GetAndResetPendingGestures());
+ if (current_touch_ids_.size() > 1) {
+ state_ = WAIT_FOR_RELEASE;
+ } else if (current_touch_ids_.size() == 0) {
+ ResetToNoFingersDown();
+ } else {
+ EnterTouchToMouseMode();
+ state_ = TOUCH_EXPLORATION;
+ }
+ VLOG_STATE();
+ return;
+ }
+
+ if (type == ET_GESTURE_SCROLL_BEGIN) {
+ delegate_->PlayVolumeAdjustSound();
+ }
+
+ if (type == ET_GESTURE_SCROLL_END) {
+ if (sound_timer_.IsRunning())
+ sound_timer_.Stop();
+ delegate_->PlayVolumeAdjustSound();
+ }
+
+ location = gesture->location();
+ int where = WithinBoundsOfEdge(location, kSlopDistanceFromEdge);
+
+ // If the user is in the corner of the right side of the screen, the volume
+ // will be automatically set to 100% or muted depending on which corner they
+ // are in. Otherwise, the user will be able to adjust the volume by sliding
+ // their finger along the right side of the screen. Volume is relative to
+ // where they are on the right side of the screen.
+ if ((where | RIGHT_EDGE) != where)
+ return;
+
+ if (where == RIGHT_EDGE) {
+ location = gesture->location();
+ root_window_->GetHost()->ConvertPointFromNativeScreen(&location);
+ float volume =
+ 100 -
+ ((float)location.y() - kMaxDistanceFromEdge) /
+ (root_window_->bounds().bottom() - 2 * kMaxDistanceFromEdge) * 100;
+ VLOG(0) << "\n Volume = " << volume
+ << "\n Location = " << location.ToString()
+ << "\n Bounds = " << root_window_->bounds().right();
+
+ delegate_->AdjustSound(volume);
+ return;
+ }
+ else if ((where | TOP_EDGE) == where) {
+ delegate_->AdjustSound(100);
+ return;
+ } else if ((where | BOTTOM_EDGE) == where) {
+ delegate_->AdjustSound(0);
+ return;
+ }
+ NOTREACHED() << "Invalid location " << where;
+}
+
+
void TouchExplorationController::OnSwipeEvent(ui::GestureEvent* swipe_gesture) {
// A swipe gesture contains details for the direction in which the swipe
// occurred.
@@ -605,6 +789,34 @@ void TouchExplorationController::OnSwipeEvent(ui::GestureEvent* swipe_gesture) {
}
}
+int TouchExplorationController::WithinBoundsOfEdge(gfx::Point point,
+ float bounds) {
+ // Since GetBoundsInScreen is in DIPs but p is not, then p needs to be
+ // converted.
+ root_window_->GetHost()->ConvertPointFromNativeScreen(&point);
+ gfx::Rect window= root_window_->GetBoundsInScreen();
+
+ float left_edge_limit = window.x() + bounds;
+ float right_edge_limit = window.right() - bounds;
+ float top_edge_limit = window.y() + bounds;
+ float bottom_edge_limit = window.bottom() - bounds;
+
+ // Bitwise manipulation in order to determine where on the screen the point
+ // lies. If more than one bit is turned on, then it is a corner where the two
+ // bit/edges intersect. Otherwise, if no bits are turned on, the point must be
+ // in the center of the screen.
+ int result = SCREEN_CENTER;
+ if (point.x() < left_edge_limit)
+ result = result | LEFT_EDGE;
+ if (point.x() > right_edge_limit)
+ result = result | RIGHT_EDGE;
+ if (point.y() < top_edge_limit)
+ result = result | TOP_EDGE;
+ if (point.y() > bottom_edge_limit)
+ result = result | BOTTOM_EDGE;
+ return result;
+}
+
void TouchExplorationController::DispatchShiftSearchKeyEvent(
const ui::KeyboardCode direction) {
// In order to activate the shortcut shift+search+<arrow key>
@@ -654,6 +866,9 @@ void TouchExplorationController::EnterTouchToMouseMode() {
}
void TouchExplorationController::ResetToNoFingersDown() {
+ ProcessGestureEvents();
+ if (sound_timer_.IsRunning())
+ sound_timer_.Stop();
state_ = NO_FINGERS_DOWN;
VLOG_STATE();
if (tap_timer_.IsRunning())
@@ -725,6 +940,8 @@ const char* TouchExplorationController::EnumStateToString(State state) {
return "PASSTHROUGH";
case WAIT_FOR_RELEASE:
return "WAIT_FOR_RELEASE";
+ case SLIDE_GESTURE:
+ return "SLIDE_GESTURE";
}
return "Not a state";
}

Powered by Google App Engine
This is Rietveld 408576698