blob: f2e3724183b02739983cb1bcce06f7f222efc536 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// 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>
#import "base/mac/scoped_nsobject.h"
#include "base/optional.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 {
// Stores last received swipe gesture direction vector in
// |last_swipe_gesture()|.
class ThreeFingerSwipeView : public View {
public:
ThreeFingerSwipeView() = default;
// View:
void OnGestureEvent(ui::GestureEvent* event) override {
EXPECT_EQ(ui::ET_GESTURE_SWIPE, event->details().type());
int dx = 0, dy = 0;
if (event->details().swipe_left())
dx = -1;
if (event->details().swipe_right()) {
EXPECT_EQ(0, dx);
dx = 1;
}
if (event->details().swipe_down())
dy = 1;
if (event->details().swipe_up()) {
EXPECT_EQ(0, dy);
dy = -1;
}
last_swipe_gesture_ = gfx::Point(dx, dy);
}
base::Optional<gfx::Point> last_swipe_gesture() const {
return last_swipe_gesture_;
}
private:
base::Optional<gfx::Point> last_swipe_gesture_;
DISALLOW_COPY_AND_ASSIGN(ThreeFingerSwipeView);
};
} // namespace
class ViewMacTest : public test::WidgetTest {
public:
ViewMacTest() = default;
base::Optional<gfx::Point> SwipeGestureVector(int dx, int dy) {
base::scoped_nsobject<FakeSwipeEvent> swipe_event(
[[FakeSwipeEvent alloc] init]);
[swipe_event setDeltaX:dx];
[swipe_event setDeltaY:dy];
[swipe_event setWindow:widget_->GetNativeWindow().GetNativeNSWindow()];
[swipe_event setLocationInWindow:NSMakePoint(50, 50)];
[swipe_event setTimestamp:[[NSProcessInfo processInfo] systemUptime]];
// BridgedContentView should create an appropriate ui::GestureEvent and pass
// it to the Widget.
[[widget_->GetNativeWindow().GetNativeNSWindow() contentView]
swipeWithEvent:swipe_event];
return view_->last_swipe_gesture();
}
// testing::Test:
void SetUp() override {
WidgetTest::SetUp();
widget_ = CreateTopLevelPlatformWidget();
widget_->SetBounds(gfx::Rect(0, 0, 100, 100));
widget_->Show();
view_ = new ThreeFingerSwipeView;
view_->SetSize(widget_->GetClientAreaBoundsInScreen().size());
widget_->GetContentsView()->AddChildView(view_);
}
void TearDown() override {
widget_->CloseNow();
WidgetTest::TearDown();
}
private:
Widget* widget_ = nullptr;
ThreeFingerSwipeView* view_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(ViewMacTest);
};
// Three-finger swipes send immediate events and they cannot be tracked.
TEST_F(ViewMacTest, HandlesThreeFingerSwipeGestures) {
// Note that positive delta is left and up for NSEvent, which is the inverse
// of ui::GestureEventDetails.
EXPECT_EQ(gfx::Point(1, 0), *SwipeGestureVector(-1, 0));
EXPECT_EQ(gfx::Point(-1, 0), *SwipeGestureVector(1, 0));
EXPECT_EQ(gfx::Point(0, 1), *SwipeGestureVector(0, -1));
EXPECT_EQ(gfx::Point(0, -1), *SwipeGestureVector(0, 1));
}
} // namespace views