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"; |
} |