OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ui/events/cocoa/cocoa_event_utils.h" | 5 #include "ui/events/event_utils.h" |
6 | 6 |
7 #import <objc/objc-class.h> | 7 #import <Cocoa/Cocoa.h> |
8 | 8 |
| 9 #include "base/mac/scoped_cftyperef.h" |
| 10 #include "base/memory/scoped_ptr.h" |
9 #include "testing/gtest/include/gtest/gtest.h" | 11 #include "testing/gtest/include/gtest/gtest.h" |
10 #include "testing/platform_test.h" | |
11 #include "ui/events/event_constants.h" | 12 #include "ui/events/event_constants.h" |
12 #include "ui/events/event_utils.h" | |
13 #import "ui/events/test/cocoa_test_event_utils.h" | 13 #import "ui/events/test/cocoa_test_event_utils.h" |
| 14 #include "ui/gfx/point.h" |
14 #import "ui/gfx/test/ui_cocoa_test_helper.h" | 15 #import "ui/gfx/test/ui_cocoa_test_helper.h" |
15 | 16 |
| 17 namespace { |
| 18 |
| 19 NSWindow* g_test_window = nil; |
| 20 |
| 21 } // namespace |
| 22 |
| 23 // Mac APIs for creating test events are frustrating. Quartz APIs have, e.g., |
| 24 // CGEventCreateMouseEvent() which can't set a window or modifier flags. |
| 25 // Cocoa APIs have +[NSEvent mouseEventWithType:..] which can't set |
| 26 // buttonNumber or scroll deltas. To work around this, these tests use some |
| 27 // Objective C magic to donate member functions to NSEvent temporarily. |
| 28 @interface MiddleMouseButtonNumberDonor : NSObject |
| 29 @end |
| 30 |
| 31 @interface TestWindowDonor : NSObject |
| 32 @end |
| 33 |
| 34 @implementation MiddleMouseButtonNumberDonor |
| 35 - (NSUInteger)buttonNumber { return 2; } |
| 36 @end |
| 37 |
| 38 @implementation TestWindowDonor |
| 39 - (NSWindow*)window { return g_test_window; } |
| 40 @end |
| 41 |
16 namespace ui { | 42 namespace ui { |
17 | 43 |
18 namespace { | 44 namespace { |
19 | 45 |
20 class CocoaEventUtilsTest : public CocoaTest { | 46 class EventsMacTest : public CocoaTest { |
| 47 public: |
| 48 EventsMacTest() {} |
| 49 |
| 50 gfx::Point Flip(gfx::Point window_location) { |
| 51 window_location.set_y( |
| 52 NSHeight([test_window() frame]) - window_location.y()); |
| 53 return window_location; |
| 54 } |
| 55 |
| 56 void SwizzleMiddleMouseButton() { |
| 57 DCHECK(!swizzler_); |
| 58 swizzler_.reset(new ScopedClassSwizzler( |
| 59 [NSEvent class], |
| 60 [MiddleMouseButtonNumberDonor class], |
| 61 @selector(buttonNumber))); |
| 62 } |
| 63 |
| 64 void SwizzleTestWindow() { |
| 65 DCHECK(!g_test_window); |
| 66 DCHECK(!swizzler_); |
| 67 g_test_window = test_window(); |
| 68 swizzler_.reset(new ScopedClassSwizzler( |
| 69 [NSEvent class], |
| 70 [TestWindowDonor class], |
| 71 @selector(window))); |
| 72 } |
| 73 |
| 74 void ClearSwizzle() { |
| 75 swizzler_.reset(); |
| 76 g_test_window = nil; |
| 77 } |
| 78 |
| 79 NSEvent* TestMouseEvent(NSEventType type, |
| 80 const gfx::Point &window_location, |
| 81 NSInteger modifier_flags) { |
| 82 NSPoint point = NSPointFromCGPoint(Flip(window_location).ToCGPoint()); |
| 83 return [NSEvent mouseEventWithType:type |
| 84 location:point |
| 85 modifierFlags:modifier_flags |
| 86 timestamp:0 |
| 87 windowNumber:[test_window() windowNumber] |
| 88 context:nil |
| 89 eventNumber:0 |
| 90 clickCount:0 |
| 91 pressure:1.0]; |
| 92 } |
| 93 |
| 94 NSEvent* TestScrollEvent(const gfx::Point& window_location, |
| 95 int32_t delta_x, |
| 96 int32_t delta_y) { |
| 97 SwizzleTestWindow(); |
| 98 base::ScopedCFTypeRef<CGEventRef> scroll( |
| 99 CGEventCreateScrollWheelEvent(NULL, |
| 100 kCGScrollEventUnitLine, |
| 101 2, |
| 102 delta_y, |
| 103 delta_x)); |
| 104 // CGEvents are always in global display coordinates. These are like screen |
| 105 // coordinates, but flipped. But first the point needs to be converted out |
| 106 // of window coordinates (which also requires flipping). |
| 107 NSPoint window_point = |
| 108 NSPointFromCGPoint(Flip(window_location).ToCGPoint()); |
| 109 NSPoint screen_point = [test_window() convertBaseToScreen:window_point]; |
| 110 CGFloat primary_screen_height = |
| 111 NSHeight([[[NSScreen screens] objectAtIndex:0] frame]); |
| 112 screen_point.y = primary_screen_height - screen_point.y; |
| 113 CGEventSetLocation(scroll, NSPointToCGPoint(screen_point)); |
| 114 return [NSEvent eventWithCGEvent:scroll]; |
| 115 } |
| 116 |
| 117 private: |
| 118 scoped_ptr<ScopedClassSwizzler> swizzler_; |
| 119 |
| 120 DISALLOW_COPY_AND_ASSIGN(EventsMacTest); |
21 }; | 121 }; |
22 | 122 |
23 TEST_F(CocoaEventUtilsTest, EventFlagsFromNative) { | 123 } // namespace |
| 124 |
| 125 TEST_F(EventsMacTest, EventFlagsFromNative) { |
24 // Left click. | 126 // Left click. |
25 NSEvent* left = cocoa_test_event_utils::MouseEventWithType(NSLeftMouseUp, 0); | 127 NSEvent* left = cocoa_test_event_utils::MouseEventWithType(NSLeftMouseUp, 0); |
26 EXPECT_EQ(EF_LEFT_MOUSE_BUTTON, EventFlagsFromNative(left)); | 128 EXPECT_EQ(EF_LEFT_MOUSE_BUTTON, EventFlagsFromNative(left)); |
27 | 129 |
28 // Right click. | 130 // Right click. |
29 NSEvent* right = cocoa_test_event_utils::MouseEventWithType(NSRightMouseUp, | 131 NSEvent* right = cocoa_test_event_utils::MouseEventWithType(NSRightMouseUp, |
30 0); | 132 0); |
31 EXPECT_EQ(EF_RIGHT_MOUSE_BUTTON, EventFlagsFromNative(right)); | 133 EXPECT_EQ(EF_RIGHT_MOUSE_BUTTON, EventFlagsFromNative(right)); |
32 | 134 |
33 // Middle click. | 135 // Middle click. |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
67 EXPECT_EQ(EF_LEFT_MOUSE_BUTTON | EF_SHIFT_DOWN | EF_CONTROL_DOWN, | 169 EXPECT_EQ(EF_LEFT_MOUSE_BUTTON | EF_SHIFT_DOWN | EF_CONTROL_DOWN, |
68 EventFlagsFromNative(shiftctrl)); | 170 EventFlagsFromNative(shiftctrl)); |
69 | 171 |
70 // Cmd + Alt + Right | 172 // Cmd + Alt + Right |
71 NSEvent* cmdalt = cocoa_test_event_utils::MouseEventWithType( | 173 NSEvent* cmdalt = cocoa_test_event_utils::MouseEventWithType( |
72 NSLeftMouseUp, NSCommandKeyMask | NSAlternateKeyMask); | 174 NSLeftMouseUp, NSCommandKeyMask | NSAlternateKeyMask); |
73 EXPECT_EQ(EF_LEFT_MOUSE_BUTTON | EF_COMMAND_DOWN | EF_ALT_DOWN, | 175 EXPECT_EQ(EF_LEFT_MOUSE_BUTTON | EF_COMMAND_DOWN | EF_ALT_DOWN, |
74 EventFlagsFromNative(cmdalt)); | 176 EventFlagsFromNative(cmdalt)); |
75 } | 177 } |
76 | 178 |
77 } // namespace | 179 // Tests mouse button presses and mouse wheel events. |
| 180 TEST_F(EventsMacTest, ButtonEvents) { |
| 181 gfx::Point location(5, 10); |
| 182 gfx::Vector2d offset; |
| 183 |
| 184 NSEvent* event = TestMouseEvent(NSLeftMouseDown, location, 0); |
| 185 EXPECT_EQ(ui::ET_MOUSE_PRESSED, ui::EventTypeFromNative(event)); |
| 186 EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON, ui::EventFlagsFromNative(event)); |
| 187 EXPECT_EQ(location, ui::EventLocationFromNative(event)); |
| 188 |
| 189 SwizzleMiddleMouseButton(); |
| 190 event = TestMouseEvent(NSOtherMouseDown, location, NSShiftKeyMask); |
| 191 EXPECT_EQ(ui::ET_MOUSE_PRESSED, ui::EventTypeFromNative(event)); |
| 192 EXPECT_EQ(ui::EF_MIDDLE_MOUSE_BUTTON | ui::EF_SHIFT_DOWN, |
| 193 ui::EventFlagsFromNative(event)); |
| 194 EXPECT_EQ(location, ui::EventLocationFromNative(event)); |
| 195 ClearSwizzle(); |
| 196 |
| 197 event = TestMouseEvent(NSRightMouseUp, location, 0); |
| 198 EXPECT_EQ(ui::ET_MOUSE_RELEASED, ui::EventTypeFromNative(event)); |
| 199 EXPECT_EQ(ui::EF_RIGHT_MOUSE_BUTTON, ui::EventFlagsFromNative(event)); |
| 200 EXPECT_EQ(location, ui::EventLocationFromNative(event)); |
| 201 |
| 202 // Scroll up. |
| 203 event = TestScrollEvent(location, 0, 1); |
| 204 EXPECT_EQ(ui::ET_MOUSEWHEEL, ui::EventTypeFromNative(event)); |
| 205 EXPECT_EQ(0, ui::EventFlagsFromNative(event)); |
| 206 EXPECT_EQ(location.ToString(), ui::EventLocationFromNative(event).ToString()); |
| 207 offset = ui::GetMouseWheelOffset(event); |
| 208 EXPECT_GT(offset.y(), 0); |
| 209 EXPECT_EQ(0, offset.x()); |
| 210 ClearSwizzle(); |
| 211 |
| 212 // Scroll down. |
| 213 event = TestScrollEvent(location, 0, -1); |
| 214 EXPECT_EQ(ui::ET_MOUSEWHEEL, ui::EventTypeFromNative(event)); |
| 215 EXPECT_EQ(0, ui::EventFlagsFromNative(event)); |
| 216 EXPECT_EQ(location, ui::EventLocationFromNative(event)); |
| 217 offset = ui::GetMouseWheelOffset(event); |
| 218 EXPECT_LT(offset.y(), 0); |
| 219 EXPECT_EQ(0, offset.x()); |
| 220 ClearSwizzle(); |
| 221 |
| 222 // Scroll left. |
| 223 event = TestScrollEvent(location, 1, 0); |
| 224 EXPECT_EQ(ui::ET_MOUSEWHEEL, ui::EventTypeFromNative(event)); |
| 225 EXPECT_EQ(0, ui::EventFlagsFromNative(event)); |
| 226 EXPECT_EQ(location, ui::EventLocationFromNative(event)); |
| 227 offset = ui::GetMouseWheelOffset(event); |
| 228 EXPECT_EQ(0, offset.y()); |
| 229 EXPECT_GT(offset.x(), 0); |
| 230 ClearSwizzle(); |
| 231 |
| 232 // Scroll right. |
| 233 event = TestScrollEvent(location, -1, 0); |
| 234 EXPECT_EQ(ui::ET_MOUSEWHEEL, ui::EventTypeFromNative(event)); |
| 235 EXPECT_EQ(0, ui::EventFlagsFromNative(event)); |
| 236 EXPECT_EQ(location, ui::EventLocationFromNative(event)); |
| 237 offset = ui::GetMouseWheelOffset(event); |
| 238 EXPECT_EQ(0, offset.y()); |
| 239 EXPECT_LT(offset.x(), 0); |
| 240 ClearSwizzle(); |
| 241 } |
78 | 242 |
79 } // namespace ui | 243 } // namespace ui |
OLD | NEW |