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

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: Addressed comments 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..a8c54ef03b420b5c4140356b261f2b3e55721d56 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,13 +19,29 @@
namespace ui {
namespace {
+
+// Delay between adjustment sounds.
+const base::TimeDelta kSoundDelay = base::TimeDelta::FromMilliseconds(150);
+
+const float kLeavingScreenEdge = 6;
dmazzoni 2014/07/16 16:54:40 Need comment for this too.
lisayin 2014/07/17 16:56:17 Done.
+
+// 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.
dmazzoni 2014/07/16 16:54:40 Note that this is in Dips too.
lisayin 2014/07/17 16:56:17 Done.
+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),
+ delegate_(delegate),
state_(NO_FINGERS_DOWN),
event_handler_for_testing_(NULL),
gesture_provider_(this),
@@ -67,7 +83,15 @@ bool TouchExplorationController::IsInGestureInProgressStateForTesting() const {
}
void TouchExplorationController::SuppressVLOGsForTesting(bool suppress) {
- VLOG_on_ = !suppress;
+ VLOG_on_ = !suppress;
+}
+
+gfx::Rect TouchExplorationController::BoundsOfRootWindowInDIPForTesting() {
+ return root_window_->GetBoundsInScreen();
+}
+
+bool TouchExplorationController::IsInSlideGestureStateForTesting() const {
+ return state_ == SLIDE_GESTURE;
}
ui::EventRewriteStatus TouchExplorationController::RewriteEvent(
@@ -108,6 +132,16 @@ ui::EventRewriteStatus TouchExplorationController::RewriteEvent(
current_touch_ids_.push_back(touch_id);
touch_locations_.insert(std::pair<int, gfx::PointF>(touch_id, location));
} else if (type == ui::ET_TOUCH_RELEASED || type == ui::ET_TOUCH_CANCELLED) {
+ // If the release is too close to the edge.
+ TouchEvent touch_event = static_cast<const TouchEvent&>(event);
+ if (WithinBoundsOfEdge(touch_event.location(), kLeavingScreenEdge) !=
+ SCREEN_CENTER) {
+ if (current_touch_ids_.size() == 0)
+ ResetToNoFingersDown();
+ else
+ state_ = WAIT_FOR_RELEASE;
+ }
+
std::vector<int>::iterator it = std::find(
current_touch_ids_.begin(), current_touch_ids_.end(), touch_id);
@@ -152,6 +186,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 +258,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) {
dmazzoni 2014/07/16 16:54:40 This took me a second - the more typical way I'd s
lisayin 2014/07/22 16:22:46 Done.
+ 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 +546,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 +573,77 @@ 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 go into two-to-one passthrough.
+ if (type == ui::ET_TOUCH_PRESSED ||
+ event.touch_id() != initial_press_->touch_id()) {
dmazzoni 2014/07/16 16:54:40 I'm not sure you should switch to the two-to-one p
lisayin 2014/07/17 16:56:17 Done.
+ if (tap_timer_.IsRunning())
+ tap_timer_.Stop();
+ if (sound_timer_.IsRunning())
+ sound_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();
dmazzoni 2014/07/16 16:54:40 Delete this log or add a bit more context so that
lisayin 2014/07/17 16:56:17 Done.
+ // 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)) {
dmazzoni 2014/07/16 16:54:40 same here with bit testing
lisayin 2014/07/17 16:56:17 Done.
+ 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())
dmazzoni 2014/07/16 16:54:40 You shouldn't need to stop it every time. Can you
lisayin 2014/07/17 16:56:17 Done.
+ 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 +668,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,12 +679,14 @@ 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;
}
@@ -581,11 +699,84 @@ void TouchExplorationController::ProcessGestureEvents() {
for (ScopedVector<GestureEvent>::iterator i = gestures->begin();
i != gestures->end();
++i) {
- OnGestureEvent(*i);
+ if (state_ == SLIDE_GESTURE)
+ SideSlideControl(*i);
+ else
+ OnGestureEvent(*i);
}
}
}
+void TouchExplorationController::SideSlideControl(ui::GestureEvent* gesture) {
+ ui::EventType type = gesture->type();
+ if (!gesture->IsScrollGestureEvent())
+ return;
+
+ 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;
dmazzoni 2014/07/16 16:54:39 Can you explain this one? When do you go from the
lisayin 2014/07/17 16:56:17 Done.
+ }
+ 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;
dmazzoni 2014/07/16 16:54:40 I think the root window bounds top may not be zero
lisayin 2014/07/22 16:22:46 Done.
+ VLOG(0) << "\n Volume = " << volume
+ << "\n Location = " << location.ToString()
+ << "\n Bounds = " << root_window_->bounds().right();
+
+ delegate_->SetOutputLevel(volume);
+ return;
+ }
+ else if ((where | TOP_EDGE) == where) {
+ delegate_->SetOutputLevel(100);
+ return;
+ } else if ((where | BOTTOM_EDGE) == where) {
+ delegate_->SetOutputLevel(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 +796,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
dmazzoni 2014/07/16 16:54:40 What is "p"?
lisayin 2014/07/17 16:56:17 Done.
+ // converted.
+ root_window_->GetHost()->ConvertPointFromNativeScreen(&point);
+ gfx::Rect window= root_window_->GetBoundsInScreen();
dmazzoni 2014/07/16 16:54:40 nit: spaces around = sign
lisayin 2014/07/17 16:56:17 Done.
+
+ 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;
dmazzoni 2014/07/16 16:54:40 nit: result |= LEFT_EDGE
lisayin 2014/07/22 16:22:46 Done.
+ 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 +873,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 +947,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