Commit de515231 authored by erikchen's avatar erikchen Committed by Commit bot

Fix Magic Mouse history swiping bug.

Magic Mouse gestures don't cause -touches*WithEvent: events to be sent down the
responder chain. As such, all state related to Magic Mouse gestures needs to be
reset during -beginGestureWithEvent:.

BUG=317161

Review URL: https://codereview.chromium.org/821173003

Cr-Commit-Position: refs/heads/master@{#311762}
parent b1799751
...@@ -113,6 +113,18 @@ enum RecognitionState { ...@@ -113,6 +113,18 @@ enum RecognitionState {
// that it can decide whether to consume the events and prevent them from // that it can decide whether to consume the events and prevent them from
// being passed to the renderer. This API is used to transition from kPending // being passed to the renderer. This API is used to transition from kPending
// -> kPotential. // -> kPotential.
//
// This class is also responsible for handling gestures from a Magic Mouse.
// Magic Mouse gestures do not generate -touches*WithEvent: callbacks, so this
// class must use the API -[NSEvent trackSwipeEventWithOptions:...] to track
// the Magic Mouse gesture. Due to an AppKit bug, once this API is invoked,
// views no longer reliable receive -touches*WithEvent: callbacks. As such,
// once this class invokes the -[NSEvent trackSwipeEventWithOptions:...] API,
// it must continue to use that API, since it no longer receives touch events.
//
// TODO(erikchen): Even for users that do not have a Magic Mouse, this class
// will sometime transition into Magic Mouse mode. This is very undesirable.
// See http://crbug.com/317161 for more details.
@class HistoryOverlayController; @class HistoryOverlayController;
@interface HistorySwiper : NSObject { @interface HistorySwiper : NSObject {
@private @private
...@@ -149,7 +161,7 @@ enum RecognitionState { ...@@ -149,7 +161,7 @@ enum RecognitionState {
id<HistorySwiperDelegate> delegate_; id<HistorySwiperDelegate> delegate_;
// Cumulative scroll delta since scroll gesture start. Only valid during // Cumulative scroll delta since scroll gesture start. Only valid during
// scroll gesture handling. Used for history swiping. // scroll gesture handling. Only used to trigger Magic Mouse history swiping.
NSSize mouseScrollDelta_; NSSize mouseScrollDelta_;
} }
...@@ -162,10 +174,14 @@ enum RecognitionState { ...@@ -162,10 +174,14 @@ enum RecognitionState {
// The event passed in is a gesture event, and has touch data associated with // The event passed in is a gesture event, and has touch data associated with
// the trackpad. // the trackpad.
// Once the method -[NSEvent trackSwipeEventWithOptions:...] is invoked, the
// methods -touches*WithEvent: are no longer guaranteed to be called for
// subsequent gestures. http://crbug.com/317161
- (void)touchesBeganWithEvent:(NSEvent*)event; - (void)touchesBeganWithEvent:(NSEvent*)event;
- (void)touchesMovedWithEvent:(NSEvent*)event; - (void)touchesMovedWithEvent:(NSEvent*)event;
- (void)touchesCancelledWithEvent:(NSEvent*)event; - (void)touchesCancelledWithEvent:(NSEvent*)event;
- (void)touchesEndedWithEvent:(NSEvent*)event; - (void)touchesEndedWithEvent:(NSEvent*)event;
- (void)beginGestureWithEvent:(NSEvent*)event; - (void)beginGestureWithEvent:(NSEvent*)event;
- (void)endGestureWithEvent:(NSEvent*)event; - (void)endGestureWithEvent:(NSEvent*)event;
......
...@@ -163,6 +163,9 @@ BOOL forceMagicMouse = NO; ...@@ -163,6 +163,9 @@ BOOL forceMagicMouse = NO;
- (void)beginGestureWithEvent:(NSEvent*)event { - (void)beginGestureWithEvent:(NSEvent*)event {
inGesture_ = YES; inGesture_ = YES;
// Reset state pertaining to Magic Mouse swipe gestures.
mouseScrollDelta_ = NSZeroSize;
} }
- (void)endGestureWithEvent:(NSEvent*)event { - (void)endGestureWithEvent:(NSEvent*)event {
...@@ -213,10 +216,9 @@ BOOL forceMagicMouse = NO; ...@@ -213,10 +216,9 @@ BOOL forceMagicMouse = NO;
- (void)touchesBeganWithEvent:(NSEvent*)event { - (void)touchesBeganWithEvent:(NSEvent*)event {
receivingTouches_ = YES; receivingTouches_ = YES;
// Reset state pertaining to previous gestures. // Reset state pertaining to previous trackpad gestures.
gestureStartPointValid_ = NO; gestureStartPointValid_ = NO;
gestureTotalY_ = 0; gestureTotalY_ = 0;
mouseScrollDelta_ = NSZeroSize;
beganEventUnconsumed_ = NO; beganEventUnconsumed_ = NO;
recognitionState_ = history_swiper::kPending; recognitionState_ = history_swiper::kPending;
} }
......
...@@ -90,6 +90,7 @@ class MacHistorySwiperTest : public CocoaTest { ...@@ -90,6 +90,7 @@ class MacHistorySwiperTest : public CocoaTest {
CocoaTest::TearDown(); CocoaTest::TearDown();
} }
// These methods send all 3 types of events: gesture, scroll, and touch.
void startGestureInMiddle(); void startGestureInMiddle();
void moveGestureInMiddle(); void moveGestureInMiddle();
void moveGestureAtPoint(NSPoint point); void moveGestureAtPoint(NSPoint point);
...@@ -97,6 +98,10 @@ class MacHistorySwiperTest : public CocoaTest { ...@@ -97,6 +98,10 @@ class MacHistorySwiperTest : public CocoaTest {
void endGestureAtPoint(NSPoint point); void endGestureAtPoint(NSPoint point);
void rendererACKForBeganEvent(); void rendererACKForBeganEvent();
// These methods send a single type of event.
void sendBeginGestureEventInMiddle();
void sendEndGestureEventAtPoint(NSPoint point);
HistorySwiper* historySwiper_; HistorySwiper* historySwiper_;
NSView* view_; NSView* view_;
int begin_count_; int begin_count_;
...@@ -189,6 +194,8 @@ void MacHistorySwiperTest::endGestureAtPoint(NSPoint point) { ...@@ -189,6 +194,8 @@ void MacHistorySwiperTest::endGestureAtPoint(NSPoint point) {
NSEvent* scrollEvent = scrollWheelEventWithPhase(NSEventPhaseEnded); NSEvent* scrollEvent = scrollWheelEventWithPhase(NSEventPhaseEnded);
[historySwiper_ handleEvent:scrollEvent]; [historySwiper_ handleEvent:scrollEvent];
sendEndGestureEventAtPoint(point);
} }
void MacHistorySwiperTest::rendererACKForBeganEvent() { void MacHistorySwiperTest::rendererACKForBeganEvent() {
...@@ -197,6 +204,16 @@ void MacHistorySwiperTest::rendererACKForBeganEvent() { ...@@ -197,6 +204,16 @@ void MacHistorySwiperTest::rendererACKForBeganEvent() {
[historySwiper_ rendererHandledWheelEvent:event consumed:NO]; [historySwiper_ rendererHandledWheelEvent:event consumed:NO];
} }
void MacHistorySwiperTest::sendBeginGestureEventInMiddle() {
NSEvent* event = mockEventWithPoint(makePoint(0.5, 0.5), NSEventTypeGesture);
[historySwiper_ beginGestureWithEvent:event];
}
void MacHistorySwiperTest::sendEndGestureEventAtPoint(NSPoint point) {
NSEvent* event = mockEventWithPoint(point, NSEventTypeGesture);
[historySwiper_ endGestureWithEvent:event];
}
// Test that a simple left-swipe causes navigation. // Test that a simple left-swipe causes navigation.
TEST_F(MacHistorySwiperTest, SwipeLeft) { TEST_F(MacHistorySwiperTest, SwipeLeft) {
// These tests require 10.7+ APIs. // These tests require 10.7+ APIs.
...@@ -472,3 +489,59 @@ TEST_F(MacHistorySwiperTest, SubstantialVerticalThenHorizontal) { ...@@ -472,3 +489,59 @@ TEST_F(MacHistorySwiperTest, SubstantialVerticalThenHorizontal) {
EXPECT_FALSE(navigated_right_); EXPECT_FALSE(navigated_right_);
EXPECT_FALSE(navigated_left_); EXPECT_FALSE(navigated_left_);
} }
// Magic Mouse gestures don't send -touches*WithEvent: callbacks. The history
// swiper should still handle this gracefully. It should not turn vertical
// motion into history swipes.
TEST_F(MacHistorySwiperTest, MagicMouseStateResetsCorrectly) {
// These tests require 10.7+ APIs.
if (![NSEvent
respondsToSelector:@selector(isSwipeTrackingFromScrollEventsEnabled)])
return;
// Magic mouse events don't generate '-touches*WithEvent:' callbacks.
// Send the following events:
// - beginGesture
// - scrollWheel: (phase=Began)
// - scrollWheel: (phase=Changed), significant horizontal motion.
// - scrollWheel: (phase=Ended)
// - endGesture
sendBeginGestureEventInMiddle();
[historySwiper_ handleEvent:scrollWheelEventWithPhase(NSEventPhaseBegan)];
// Callback from Blink to set the relevant state for history swiping.
rendererACKForBeganEvent();
NSEvent* scrollEvent = scrollWheelEventWithPhase(NSEventPhaseChanged,
NSEventPhaseNone, 200.0, 0);
[historySwiper_ handleEvent:scrollEvent];
[historySwiper_ handleEvent:scrollWheelEventWithPhase(NSEventPhaseEnded)];
sendEndGestureEventAtPoint(makePoint(0.7, 0.5));
// Expect this sequence of events to trigger a magic mouse history swipe.
EXPECT_TRUE(magic_mouse_history_swipe_);
// Reset state.
magic_mouse_history_swipe_ = false;
// Send the following events:
// - beginGesture
// - scrollWheel: (phase=Began)
// - scrollWheel: (phase=Changed), significant vertical motion.
// - scrollWheel: (phase=Ended)
// - endGesture
sendBeginGestureEventInMiddle();
[historySwiper_ handleEvent:scrollWheelEventWithPhase(NSEventPhaseBegan)];
// Callback from Blink to set the relevant state for history swiping.
rendererACKForBeganEvent();
scrollEvent =
scrollWheelEventWithPhase(NSEventPhaseChanged, NSEventPhaseNone, 0, 20);
[historySwiper_ handleEvent:scrollEvent];
[historySwiper_ handleEvent:scrollWheelEventWithPhase(NSEventPhaseEnded)];
sendEndGestureEventAtPoint(makePoint(0.5, 0.7));
// Vertical motion should never trigger a history swipe!
EXPECT_FALSE(magic_mouse_history_swipe_);
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment