Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 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 | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "ui/events/event_utils.h" | |
| 6 | |
| 7 #import <Cocoa/Cocoa.h> | |
| 8 | |
| 9 #include "base/mac/scoped_cftyperef.h" | |
| 10 #include "base/memory/scoped_ptr.h" | |
| 11 #include "testing/gtest/include/gtest/gtest.h" | |
| 12 #include "ui/events/event_constants.h" | |
| 13 #import "ui/events/test/cocoa_test_event_utils.h" | |
| 14 #include "ui/gfx/point.h" | |
| 15 #import "ui/gfx/test/ui_cocoa_test_helper.h" | |
| 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 | |
| 42 namespace ui { | |
| 43 | |
| 44 namespace { | |
| 45 | |
| 46 class EventsMacTest : public CocoaTest { | |
| 47 public: | |
| 48 EventsMacTest() {} | |
|
Robert Sesek
2014/04/25 15:39:23
Don't need if you're not doing work in it.
tapted
2014/04/28 07:39:49
This is to get around "events_mac_unittest.mm:123:
| |
| 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); | |
| 121 }; | |
| 122 | |
| 123 } // namespace | |
| 124 | |
| 125 TEST_F(EventsMacTest, EventFlagsFromNative) { | |
| 126 // Left click. | |
| 127 NSEvent* left = cocoa_test_event_utils::MouseEventWithType(NSLeftMouseUp, 0); | |
| 128 EXPECT_EQ(EF_LEFT_MOUSE_BUTTON, EventFlagsFromNative(left)); | |
| 129 | |
| 130 // Right click. | |
| 131 NSEvent* right = cocoa_test_event_utils::MouseEventWithType(NSRightMouseUp, | |
| 132 0); | |
| 133 EXPECT_EQ(EF_RIGHT_MOUSE_BUTTON, EventFlagsFromNative(right)); | |
| 134 | |
| 135 // Middle click. | |
| 136 NSEvent* middle = cocoa_test_event_utils::MouseEventWithType(NSOtherMouseUp, | |
| 137 0); | |
| 138 EXPECT_EQ(EF_MIDDLE_MOUSE_BUTTON, EventFlagsFromNative(middle)); | |
| 139 | |
| 140 // Caps + Left | |
| 141 NSEvent* caps = cocoa_test_event_utils::MouseEventWithType( | |
| 142 NSLeftMouseUp, NSAlphaShiftKeyMask); | |
| 143 EXPECT_EQ(EF_LEFT_MOUSE_BUTTON | EF_CAPS_LOCK_DOWN, | |
| 144 EventFlagsFromNative(caps)); | |
| 145 | |
| 146 // Shift + Left | |
| 147 NSEvent* shift = cocoa_test_event_utils::MouseEventWithType(NSLeftMouseUp, | |
| 148 NSShiftKeyMask); | |
| 149 EXPECT_EQ(EF_LEFT_MOUSE_BUTTON | EF_SHIFT_DOWN, EventFlagsFromNative(shift)); | |
| 150 | |
| 151 // Ctrl + Left | |
| 152 NSEvent* ctrl = cocoa_test_event_utils::MouseEventWithType(NSLeftMouseUp, | |
| 153 NSControlKeyMask); | |
| 154 EXPECT_EQ(EF_LEFT_MOUSE_BUTTON | EF_CONTROL_DOWN, EventFlagsFromNative(ctrl)); | |
| 155 | |
| 156 // Alt + Left | |
| 157 NSEvent* alt = cocoa_test_event_utils::MouseEventWithType(NSLeftMouseUp, | |
| 158 NSAlternateKeyMask); | |
| 159 EXPECT_EQ(EF_LEFT_MOUSE_BUTTON | EF_ALT_DOWN, EventFlagsFromNative(alt)); | |
| 160 | |
| 161 // Cmd + Left | |
| 162 NSEvent* cmd = cocoa_test_event_utils::MouseEventWithType(NSLeftMouseUp, | |
| 163 NSCommandKeyMask); | |
| 164 EXPECT_EQ(EF_LEFT_MOUSE_BUTTON | EF_COMMAND_DOWN, EventFlagsFromNative(cmd)); | |
| 165 | |
| 166 // Shift + Ctrl + Left | |
| 167 NSEvent* shiftctrl = cocoa_test_event_utils::MouseEventWithType( | |
| 168 NSLeftMouseUp, NSShiftKeyMask | NSControlKeyMask); | |
| 169 EXPECT_EQ(EF_LEFT_MOUSE_BUTTON | EF_SHIFT_DOWN | EF_CONTROL_DOWN, | |
| 170 EventFlagsFromNative(shiftctrl)); | |
| 171 | |
| 172 // Cmd + Alt + Right | |
| 173 NSEvent* cmdalt = cocoa_test_event_utils::MouseEventWithType( | |
| 174 NSLeftMouseUp, NSCommandKeyMask | NSAlternateKeyMask); | |
| 175 EXPECT_EQ(EF_LEFT_MOUSE_BUTTON | EF_COMMAND_DOWN | EF_ALT_DOWN, | |
| 176 EventFlagsFromNative(cmdalt)); | |
| 177 } | |
| 178 | |
| 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 } | |
| 242 | |
| 243 } // namespace ui | |
| OLD | NEW |