| // Copyright 2017 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "ui/views/view.h" |
| |
| #import <Cocoa/Cocoa.h> |
| |
| #include "ui/base/metadata/metadata_header_macros.h" |
| #include "ui/base/metadata/metadata_impl_macros.h" |
| #include "ui/events/gesture_event_details.h" |
| #include "ui/views/test/widget_test.h" |
| |
| // We can't create NSEventTypeSwipe using normal means, and rely on duck typing |
| // instead. |
| @interface FakeSwipeEvent : NSEvent |
| @property CGFloat deltaX; |
| @property CGFloat deltaY; |
| @property(assign) NSWindow* window; |
| @property NSPoint locationInWindow; |
| @property NSEventModifierFlags modifierFlags; |
| @property NSTimeInterval timestamp; |
| @end |
| |
| @implementation FakeSwipeEvent |
| @synthesize deltaX; |
| @synthesize deltaY; |
| @synthesize window; |
| @synthesize locationInWindow; |
| @synthesize modifierFlags; |
| @synthesize timestamp; |
| |
| - (NSEventType)type { |
| return NSEventTypeSwipe; |
| } |
| |
| - (NSEventSubtype)subtype { |
| // themblsha: In my testing, all native three-finger NSEventTypeSwipe events |
| // all had 0 as their subtype. |
| return static_cast<NSEventSubtype>(0); |
| } |
| @end |
| |
| namespace views { |
| |
| namespace { |
| |
| enum SwipeType { |
| SWIPE_NONE, |
| SWIPE_LEFT, |
| SWIPE_RIGHT, |
| SWIPE_UP, |
| SWIPE_DOWN, |
| }; |
| |
| // Stores last received swipe gesture direction. |
| class ThreeFingerSwipeView : public View { |
| METADATA_HEADER(ThreeFingerSwipeView, View) |
| |
| public: |
| // View: |
| void OnGestureEvent(ui::GestureEvent* event) override { |
| EXPECT_EQ(ui::ET_GESTURE_SWIPE, event->details().type()); |
| |
| if (event->details().swipe_left()) { |
| last_swipe_ = SWIPE_LEFT; |
| } else if (event->details().swipe_right()) { |
| last_swipe_ = SWIPE_RIGHT; |
| } else if (event->details().swipe_up()) { |
| last_swipe_ = SWIPE_UP; |
| } else if (event->details().swipe_down()) { |
| last_swipe_ = SWIPE_DOWN; |
| } else { |
| NOTREACHED(); |
| } |
| } |
| |
| SwipeType last_swipe() const { return last_swipe_; } |
| |
| private: |
| SwipeType last_swipe_{SWIPE_NONE}; |
| }; |
| |
| BEGIN_METADATA(ThreeFingerSwipeView) |
| END_METADATA |
| |
| using ViewMacTest = test::WidgetTest; |
| |
| SwipeType SendSwipeGesture(ThreeFingerSwipeView* view, NSPoint gesture) { |
| NSWindow* window = view->GetWidget()->GetNativeWindow().GetNativeNSWindow(); |
| FakeSwipeEvent* swipe_event = [[FakeSwipeEvent alloc] init]; |
| swipe_event.deltaX = gesture.x; |
| swipe_event.deltaY = gesture.y; |
| swipe_event.window = window; |
| swipe_event.locationInWindow = NSMakePoint(50, 50); |
| swipe_event.timestamp = NSProcessInfo.processInfo.systemUptime; |
| |
| // BridgedContentView should create an appropriate ui::GestureEvent and pass |
| // it to the Widget. |
| [window.contentView swipeWithEvent:swipe_event]; |
| return view->last_swipe(); |
| } |
| |
| // Test that three-finger swipe events are translated by BridgedContentView. |
| TEST_F(ViewMacTest, HandlesThreeFingerSwipeGestures) { |
| WidgetAutoclosePtr widget(CreateTopLevelPlatformWidget()); |
| widget->SetBounds(gfx::Rect(0, 0, 100, 100)); |
| widget->Show(); |
| |
| auto* view = widget->non_client_view()->frame_view()->AddChildView( |
| std::make_unique<ThreeFingerSwipeView>()); |
| view->SetSize(widget->GetClientAreaBoundsInScreen().size()); |
| |
| // Remember that in AppKit coordinates, x and y increase towards the top-left. |
| const NSPoint nsleft = NSMakePoint(1, 0); |
| const NSPoint nsright = NSMakePoint(-1, 0); |
| const NSPoint nsup = NSMakePoint(0, 1); |
| const NSPoint nsdown = NSMakePoint(0, -1); |
| |
| EXPECT_EQ(SWIPE_LEFT, SendSwipeGesture(view, nsleft)); |
| EXPECT_EQ(SWIPE_RIGHT, SendSwipeGesture(view, nsright)); |
| EXPECT_EQ(SWIPE_DOWN, SendSwipeGesture(view, nsdown)); |
| EXPECT_EQ(SWIPE_UP, SendSwipeGesture(view, nsup)); |
| } |
| |
| } // namespace |
| |
| } // namespace views |