diff options
-rw-r--r-- | base/event_types.h | 8 | ||||
-rw-r--r-- | chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller_unittest.mm | 7 | ||||
-rw-r--r-- | chrome/browser/ui/cocoa/event_utils_unittest.mm | 58 | ||||
-rw-r--r-- | ui/base/cocoa/events_mac.mm | 182 | ||||
-rw-r--r-- | ui/base/cocoa/events_mac_unittest.mm | 298 | ||||
-rw-r--r-- | ui/base/events.h | 5 | ||||
-rw-r--r-- | ui/base/keycodes/keyboard_code_conversion_mac.h | 9 | ||||
-rw-r--r-- | ui/base/keycodes/keyboard_code_conversion_mac.mm | 265 | ||||
-rw-r--r-- | ui/base/test/cocoa_test_event_utils.h | 11 | ||||
-rw-r--r-- | ui/base/test/cocoa_test_event_utils.mm | 39 | ||||
-rw-r--r-- | ui/ui.gyp | 1 | ||||
-rw-r--r-- | ui/ui_unittests.gypi | 1 |
12 files changed, 851 insertions, 33 deletions
diff --git a/base/event_types.h b/base/event_types.h index a1b78f6..ed0f02f 100644 --- a/base/event_types.h +++ b/base/event_types.h @@ -18,6 +18,12 @@ union WaylandEvent; } #elif defined(USE_X11) typedef union _XEvent XEvent; +#elif defined(OS_MACOSX) +#if defined(__OBJC__) +@class NSEvent; +#else // __OBJC__ +class NSEvent; +#endif // __OBJC__ #endif namespace base { @@ -29,6 +35,8 @@ typedef MSG NativeEvent; typedef wayland::WaylandEvent* NativeEvent; #elif defined(USE_X11) typedef XEvent* NativeEvent; +#elif defined(OS_MACOSX) +typedef NSEvent* NativeEvent; #else typedef void* NativeEvent; #endif diff --git a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller_unittest.mm b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller_unittest.mm index c6f06bd..0457fc6 100644 --- a/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller_unittest.mm +++ b/chrome/browser/ui/cocoa/bookmarks/bookmark_bar_controller_unittest.mm @@ -986,7 +986,7 @@ TEST_F(BookmarkBarControllerTest, MiddleClick) { EXPECT_TRUE(first); [first otherMouseUp: - cocoa_test_event_utils::MakeMouseEvent(NSOtherMouseUp, 0)]; + cocoa_test_event_utils::MouseEventWithType(NSOtherMouseUp, 0)]; EXPECT_EQ(noOpenBar()->urls_.size(), 1U); } @@ -1303,7 +1303,8 @@ TEST_F(BookmarkBarControllerTest, TestFolders) { EXPECT_EQ([[bar_ buttons] count], 2U); // First confirm mouseEntered does nothing if "menus" aren't active. - NSEvent* event = cocoa_test_event_utils::MakeMouseEvent(NSOtherMouseUp, 0); + NSEvent* event = + cocoa_test_event_utils::MouseEventWithType(NSOtherMouseUp, 0); [bar_ mouseEnteredButton:[[bar_ buttons] objectAtIndex:0] event:event]; EXPECT_FALSE([bar_ folderController]); @@ -1441,7 +1442,7 @@ TEST_F(BookmarkBarControllerTest, OffTheSideFolder) { } TEST_F(BookmarkBarControllerTest, EventToExitCheck) { - NSEvent* event = cocoa_test_event_utils::MakeMouseEvent(NSMouseMoved, 0); + NSEvent* event = cocoa_test_event_utils::MouseEventWithType(NSMouseMoved, 0); EXPECT_FALSE([bar_ isEventAnExitEvent:event]); BookmarkBarFolderWindow* folderWindow = [[[BookmarkBarFolderWindow alloc] diff --git a/chrome/browser/ui/cocoa/event_utils_unittest.mm b/chrome/browser/ui/cocoa/event_utils_unittest.mm index 376df50..972e74a 100644 --- a/chrome/browser/ui/cocoa/event_utils_unittest.mm +++ b/chrome/browser/ui/cocoa/event_utils_unittest.mm @@ -27,11 +27,11 @@ class EventUtilsTest : public CocoaTest { TEST_F(EventUtilsTest, TestWindowOpenDispositionFromNSEvent) { // Left Click = same tab. - NSEvent* me = cocoa_test_event_utils::MakeMouseEvent(NSLeftMouseUp, 0); + NSEvent* me = cocoa_test_event_utils::MouseEventWithType(NSLeftMouseUp, 0); EXPECT_EQ(CURRENT_TAB, event_utils::WindowOpenDispositionFromNSEvent(me)); // Middle Click = new background tab. - me = cocoa_test_event_utils::MakeMouseEvent(NSOtherMouseUp, 0); + me = cocoa_test_event_utils::MouseEventWithType(NSOtherMouseUp, 0); EXPECT_EQ(NEW_BACKGROUND_TAB, event_utils::WindowOpenDispositionFromNSEvent(me)); @@ -39,86 +39,94 @@ TEST_F(EventUtilsTest, TestWindowOpenDispositionFromNSEvent) { { ScopedClassSwizzler swizzler([NSEvent class], [TestEvent class], @selector(modifierFlags)); - me = cocoa_test_event_utils::MakeMouseEvent(NSOtherMouseUp, NSShiftKeyMask); + me = cocoa_test_event_utils::MouseEventWithType(NSOtherMouseUp, + NSShiftKeyMask); EXPECT_EQ(NEW_FOREGROUND_TAB, event_utils::WindowOpenDispositionFromNSEvent(me)); } // Cmd+Left Click = new background tab. - me = cocoa_test_event_utils::MakeMouseEvent(NSLeftMouseUp, NSCommandKeyMask); + me = cocoa_test_event_utils::MouseEventWithType(NSLeftMouseUp, + NSCommandKeyMask); EXPECT_EQ(NEW_BACKGROUND_TAB, event_utils::WindowOpenDispositionFromNSEvent(me)); // Cmd+Shift+Left Click = new foreground tab. - me = cocoa_test_event_utils::MakeMouseEvent(NSLeftMouseUp, + me = cocoa_test_event_utils::MouseEventWithType(NSLeftMouseUp, NSCommandKeyMask | NSShiftKeyMask); EXPECT_EQ(NEW_FOREGROUND_TAB, event_utils::WindowOpenDispositionFromNSEvent(me)); // Shift+Left Click = new window - me = cocoa_test_event_utils::MakeMouseEvent(NSLeftMouseUp, NSShiftKeyMask); + me = cocoa_test_event_utils::MouseEventWithType(NSLeftMouseUp, + NSShiftKeyMask); EXPECT_EQ(NEW_WINDOW, event_utils::WindowOpenDispositionFromNSEvent(me)); } TEST_F(EventUtilsTest, TestEventFlagsFromNSEvent) { // Left click. - NSEvent* left = cocoa_test_event_utils::MakeMouseEvent(NSLeftMouseUp, 0); + NSEvent* left = cocoa_test_event_utils::MouseEventWithType(NSLeftMouseUp, 0); EXPECT_EQ(ui::EF_LEFT_BUTTON_DOWN, event_utils::EventFlagsFromNSEvent(left)); // Right click. - NSEvent* right = cocoa_test_event_utils::MakeMouseEvent(NSRightMouseUp, 0); + NSEvent* right = cocoa_test_event_utils::MouseEventWithType(NSRightMouseUp, + 0); EXPECT_EQ(ui::EF_RIGHT_BUTTON_DOWN, event_utils::EventFlagsFromNSEvent(right)); // Middle click. - NSEvent* middle = cocoa_test_event_utils::MakeMouseEvent(NSOtherMouseUp, 0); + NSEvent* middle = cocoa_test_event_utils::MouseEventWithType(NSOtherMouseUp, + 0); EXPECT_EQ(ui::EF_MIDDLE_BUTTON_DOWN, event_utils::EventFlagsFromNSEvent(middle)); // Caps + Left - NSEvent* caps = cocoa_test_event_utils::MakeMouseEvent(NSLeftMouseUp, - NSAlphaShiftKeyMask); + NSEvent* caps = + cocoa_test_event_utils::MouseEventWithType(NSLeftMouseUp, + NSAlphaShiftKeyMask); EXPECT_EQ(ui::EF_LEFT_BUTTON_DOWN | ui::EF_CAPS_LOCK_DOWN, event_utils::EventFlagsFromNSEvent(caps)); // Shift + Left - NSEvent* shift = cocoa_test_event_utils::MakeMouseEvent(NSLeftMouseUp, - NSShiftKeyMask); + NSEvent* shift = cocoa_test_event_utils::MouseEventWithType(NSLeftMouseUp, + NSShiftKeyMask); EXPECT_EQ(ui::EF_LEFT_BUTTON_DOWN | ui::EF_SHIFT_DOWN, event_utils::EventFlagsFromNSEvent(shift)); // Ctrl + Left - NSEvent* ctrl = cocoa_test_event_utils::MakeMouseEvent(NSLeftMouseUp, - NSControlKeyMask); + NSEvent* ctrl = cocoa_test_event_utils::MouseEventWithType(NSLeftMouseUp, + NSControlKeyMask); EXPECT_EQ(ui::EF_LEFT_BUTTON_DOWN | ui::EF_CONTROL_DOWN, event_utils::EventFlagsFromNSEvent(ctrl)); // Alt + Left - NSEvent* alt = cocoa_test_event_utils::MakeMouseEvent(NSLeftMouseUp, - NSAlternateKeyMask); + NSEvent* alt = cocoa_test_event_utils::MouseEventWithType(NSLeftMouseUp, + NSAlternateKeyMask); EXPECT_EQ(ui::EF_LEFT_BUTTON_DOWN | ui::EF_ALT_DOWN, event_utils::EventFlagsFromNSEvent(alt)); // Cmd + Left - NSEvent* cmd = cocoa_test_event_utils::MakeMouseEvent(NSLeftMouseUp, - NSCommandKeyMask); + NSEvent* cmd = cocoa_test_event_utils::MouseEventWithType(NSLeftMouseUp, + NSCommandKeyMask); EXPECT_EQ(ui::EF_LEFT_BUTTON_DOWN | ui::EF_COMMAND_DOWN, event_utils::EventFlagsFromNSEvent(cmd)); // Shift + Ctrl + Left - NSEvent* shiftctrl = cocoa_test_event_utils::MakeMouseEvent(NSLeftMouseUp, - NSShiftKeyMask | - NSControlKeyMask); + NSEvent* shiftctrl = + cocoa_test_event_utils::MouseEventWithType(NSLeftMouseUp, + NSShiftKeyMask | + NSControlKeyMask); EXPECT_EQ(ui::EF_LEFT_BUTTON_DOWN | ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN, event_utils::EventFlagsFromNSEvent(shiftctrl)); // Cmd + Alt + Right - NSEvent* cmdalt = cocoa_test_event_utils::MakeMouseEvent(NSLeftMouseUp, - NSCommandKeyMask | - NSAlternateKeyMask); + NSEvent* cmdalt = + cocoa_test_event_utils::MouseEventWithType(NSLeftMouseUp, + NSCommandKeyMask | + NSAlternateKeyMask); EXPECT_EQ(ui::EF_LEFT_BUTTON_DOWN | ui::EF_COMMAND_DOWN | ui::EF_ALT_DOWN, event_utils::EventFlagsFromNSEvent(cmdalt)); } diff --git a/ui/base/cocoa/events_mac.mm b/ui/base/cocoa/events_mac.mm new file mode 100644 index 0000000..763e5a6 --- /dev/null +++ b/ui/base/cocoa/events_mac.mm @@ -0,0 +1,182 @@ +// Copyright (c) 2011 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 <Cocoa/Cocoa.h> + +#include "ui/base/events.h" + +#include "base/logging.h" +#import "ui/base/keycodes/keyboard_code_conversion_mac.h" +#include "ui/gfx/point.h" + +namespace ui { + +EventType EventTypeFromNative(const base::NativeEvent& native_event) { + NSEventType native_type = [native_event type]; + switch (native_type) { + case NSLeftMouseDown: + case NSRightMouseDown: + case NSOtherMouseDown: + return ET_MOUSE_PRESSED; + + case NSLeftMouseUp: + case NSRightMouseUp: + case NSOtherMouseUp: + return ET_MOUSE_RELEASED; + + case NSMouseMoved: + return ET_MOUSE_MOVED; + + case NSLeftMouseDragged: + case NSRightMouseDragged: + case NSOtherMouseDragged: + return ET_MOUSE_DRAGGED; + + case NSMouseEntered: + return ET_MOUSE_ENTERED; + + case NSMouseExited: + return ET_MOUSE_EXITED; + + case NSKeyDown: + return ET_KEY_PRESSED; + + case NSKeyUp: + return ET_KEY_RELEASED; + + case NSFlagsChanged: + return ET_KEY_PRESSED; + + case NSScrollWheel: + return ET_MOUSEWHEEL; + + case NSAppKitDefined: + case NSSystemDefined: + case NSApplicationDefined: + case NSPeriodic: + case NSCursorUpdate: + case NSTabletPoint: + case NSTabletProximity: + default: + return ET_UNKNOWN; + } +} + +int EventFlagsFromNative(const base::NativeEvent& native_event) { + int event_flags = 0; + NSUInteger modifiers = [native_event modifierFlags]; + + if (modifiers & NSAlphaShiftKeyMask) + event_flags = event_flags | EF_CAPS_LOCK_DOWN; + + if (modifiers & NSShiftKeyMask) + event_flags = event_flags | EF_SHIFT_DOWN; + + if (modifiers & NSControlKeyMask) + event_flags = event_flags | EF_CONTROL_DOWN; + + if (modifiers & NSAlternateKeyMask) + event_flags = event_flags | EF_ALT_DOWN; + + if (modifiers & NSCommandKeyMask) + event_flags = event_flags | EF_COMMAND_DOWN; + + NSEventType type = [native_event type]; + + if (type == NSLeftMouseDown || + type == NSLeftMouseUp || + type == NSLeftMouseDragged) { + event_flags = event_flags | EF_LEFT_BUTTON_DOWN; + } + + if (type == NSRightMouseDown || + type == NSRightMouseUp || + type == NSRightMouseDragged) { + event_flags = event_flags | EF_RIGHT_BUTTON_DOWN; + } + + if (type == NSOtherMouseDown || + type == NSOtherMouseUp || + type == NSOtherMouseDragged) { + event_flags = event_flags | EF_MIDDLE_BUTTON_DOWN; + } + + return event_flags; +} + +gfx::Point EventLocationFromNative(const base::NativeEvent& native_event) { + NSWindow* window = [native_event window]; + NSPoint location = [native_event locationInWindow]; + + // Convert |location| to be relative to coordinate system of |contentView|. + // Note: this assumes that ui::Event coordinates are rooted in the top-level + // view (with flipped coordinates). A more general (but costly) approach + // would be to hit-test the view of the event and use the found view's + // coordinate system. Currently there is no need for this generality, and + // speed is preferred. Flipped views are not suppported. + DCHECK([[window contentView] isFlipped] == NO); + location = [[window contentView] convertPoint:location fromView:nil]; + location.y = [[window contentView] bounds].size.height - location.y; + + return gfx::Point(NSPointToCGPoint(location)); +} + +KeyboardCode KeyboardCodeFromNative(const base::NativeEvent& native_event) { + return ui::KeyboardCodeFromNSEvent(native_event); +} + +bool IsMouseEvent(const base::NativeEvent& native_event) { + EventType type = EventTypeFromNative(native_event); + return type == ET_MOUSE_PRESSED || + type == ET_MOUSE_DRAGGED || + type == ET_MOUSE_RELEASED || + type == ET_MOUSE_MOVED || + type == ET_MOUSE_ENTERED || + type == ET_MOUSE_EXITED; +} + +int GetMouseWheelOffset(const base::NativeEvent& native_event) { + // TODO(dhollowa): Come back to this once comparisons can be made with other + // platforms. + return [native_event deltaY]; +} + +int GetTouchId(const base::NativeEvent& native_event) { + // Touch is currently unsupported. + return 0; +} + +float GetTouchRadiusX(const base::NativeEvent& native_event) { + // Touch is currently unsupported. + return 1.0; +} + +float GetTouchRadiusY(const base::NativeEvent& native_event) { + // Touch is currently unsupported. + return 1.0; +} + +float GetTouchAngle(const base::NativeEvent& native_event) { + // Touch is currently unsupported. + return 0.0; +} + +float GetTouchForce(const base::NativeEvent& native_event) { + // Touch is currently unsupported. + return 0.0; +} + +base::NativeEvent CreateNoopEvent() { + return [NSEvent otherEventWithType:NSApplicationDefined + location:NSZeroPoint + modifierFlags:0 + timestamp:[NSDate timeIntervalSinceReferenceDate] + windowNumber:0 + context:nil + subtype:0 + data1:0 + data2:0]; +} + +} // namespace ui diff --git a/ui/base/cocoa/events_mac_unittest.mm b/ui/base/cocoa/events_mac_unittest.mm new file mode 100644 index 0000000..ccb05dd --- /dev/null +++ b/ui/base/cocoa/events_mac_unittest.mm @@ -0,0 +1,298 @@ +// Copyright (c) 2011 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. + +#import <Cocoa/Cocoa.h> + +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/base/events.h" +#include "ui/base/test/cocoa_test_event_utils.h" +#import "ui/base/test/ui_cocoa_test_helper.h" +#include "ui/gfx/point.h" + +using namespace cocoa_test_event_utils; + +namespace { + +class EventsMacTest : public ui::CocoaTest { + public: + EventsMacTest() {} + + private: + DISALLOW_COPY_AND_ASSIGN(EventsMacTest); +}; + +TEST_F(EventsMacTest, EventTypeFromNative) { + NSEvent* native_event = nil; + ui::EventType type = ui::ET_UNKNOWN; + + native_event = MouseEventWithType(NSLeftMouseDown, 0); + type = ui::EventTypeFromNative(native_event); + EXPECT_EQ(ui::ET_MOUSE_PRESSED, type); + + native_event = MouseEventWithType(NSLeftMouseUp, 0); + type = ui::EventTypeFromNative(native_event); + EXPECT_EQ(ui::ET_MOUSE_RELEASED, type); + + native_event = MouseEventWithType(NSRightMouseDown, 0); + type = ui::EventTypeFromNative(native_event); + EXPECT_EQ(ui::ET_MOUSE_PRESSED, type); + + native_event = MouseEventWithType(NSRightMouseUp, 0); + type = ui::EventTypeFromNative(native_event); + EXPECT_EQ(ui::ET_MOUSE_RELEASED, type); + + native_event = MouseEventWithType(NSMouseMoved, 0); + type = ui::EventTypeFromNative(native_event); + EXPECT_EQ(ui::ET_MOUSE_MOVED, type); + + native_event = MouseEventWithType(NSLeftMouseDragged, 0); + type = ui::EventTypeFromNative(native_event); + EXPECT_EQ(ui::ET_MOUSE_DRAGGED, type); + + native_event = MouseEventWithType(NSRightMouseDragged, 0); + type = ui::EventTypeFromNative(native_event); + EXPECT_EQ(ui::ET_MOUSE_DRAGGED, type); + + native_event = EnterExitEventWithType(NSMouseEntered); + type = ui::EventTypeFromNative(native_event); + EXPECT_EQ(ui::ET_MOUSE_ENTERED, type); + + native_event = EnterExitEventWithType(NSMouseExited); + type = ui::EventTypeFromNative(native_event); + EXPECT_EQ(ui::ET_MOUSE_EXITED, type); + + native_event = KeyEventWithType(NSKeyDown, 0); + type = ui::EventTypeFromNative(native_event); + EXPECT_EQ(ui::ET_KEY_PRESSED, type); + + native_event = KeyEventWithType(NSKeyUp, 0); + type = ui::EventTypeFromNative(native_event); + EXPECT_EQ(ui::ET_KEY_RELEASED, type); + + native_event = KeyEventWithType(NSFlagsChanged, 0); + type = ui::EventTypeFromNative(native_event); + EXPECT_EQ(ui::ET_KEY_PRESSED, type); + + native_event = OtherEventWithType(NSAppKitDefined); + type = ui::EventTypeFromNative(native_event); + EXPECT_EQ(ui::ET_UNKNOWN, type); + + native_event = OtherEventWithType(NSSystemDefined); + type = ui::EventTypeFromNative(native_event); + EXPECT_EQ(ui::ET_UNKNOWN, type); + + native_event = OtherEventWithType(NSApplicationDefined); + type = ui::EventTypeFromNative(native_event); + EXPECT_EQ(ui::ET_UNKNOWN, type); + + native_event = OtherEventWithType(NSPeriodic); + type = ui::EventTypeFromNative(native_event); + EXPECT_EQ(ui::ET_UNKNOWN, type); + + native_event = EnterExitEventWithType(NSCursorUpdate); + type = ui::EventTypeFromNative(native_event); + EXPECT_EQ(ui::ET_UNKNOWN, type); + + native_event = MouseEventWithType(NSOtherMouseDown, 0); + type = ui::EventTypeFromNative(native_event); + EXPECT_EQ(ui::ET_MOUSE_PRESSED, type); + + native_event = MouseEventWithType(NSOtherMouseUp, 0); + type = ui::EventTypeFromNative(native_event); + EXPECT_EQ(ui::ET_MOUSE_RELEASED, type); + + native_event = MouseEventWithType(NSOtherMouseDragged, 0); + type = ui::EventTypeFromNative(native_event); + EXPECT_EQ(ui::ET_MOUSE_DRAGGED, type); +} + +TEST_F(EventsMacTest, EventFlagsFromNative) { + NSEvent* native_event = nil; + int flags = 0; + + // No key flags. + native_event = KeyEventWithType(NSKeyDown, 0); + flags = ui::EventFlagsFromNative(native_event); + EXPECT_EQ(0, flags); + + // All key flags. + native_event = KeyEventWithType(NSKeyDown, + NSAlphaShiftKeyMask | + NSShiftKeyMask | + NSControlKeyMask | + NSAlternateKeyMask | + NSCommandKeyMask); + flags = ui::EventFlagsFromNative(native_event); + EXPECT_EQ(ui::EF_CAPS_LOCK_DOWN | + ui::EF_SHIFT_DOWN | + ui::EF_CONTROL_DOWN | + ui::EF_ALT_DOWN | + ui::EF_COMMAND_DOWN, + flags); + + // Left mouse flags. + native_event = MouseEventWithType(NSLeftMouseDown, 0); + flags = ui::EventFlagsFromNative(native_event); + EXPECT_EQ(ui::EF_LEFT_BUTTON_DOWN, flags); + + // Right mouse flags. + native_event = MouseEventWithType(NSRightMouseDown, 0); + flags = ui::EventFlagsFromNative(native_event); + EXPECT_EQ(ui::EF_RIGHT_BUTTON_DOWN, flags); + + // Center mouse flags. + native_event = MouseEventWithType(NSOtherMouseDown, 0); + flags = ui::EventFlagsFromNative(native_event); + EXPECT_EQ(ui::EF_MIDDLE_BUTTON_DOWN, flags); +} + +TEST_F(EventsMacTest, EventLocationFromNative) { + NSWindow* window = [[NSWindow alloc] + initWithContentRect:NSMakeRect(10, 25, 200, 205) + styleMask:NSTitledWindowMask + backing:NSBackingStoreBuffered + defer:NO]; + [window orderFront:nil]; + + // Construct mouse event from window number having position at bottom-left. + // Cocoa origin is at bottom-left. ui::Event origin is top-left. + NSEvent* native_event = + [NSEvent mouseEventWithType:NSLeftMouseDown + location:NSMakePoint(10, 15) + modifierFlags:0 + timestamp:[NSDate timeIntervalSinceReferenceDate] + windowNumber:[window windowNumber] + context:[window graphicsContext] + eventNumber:0 + clickCount:1 + pressure:0.0f]; + + // Expect resulting event to be positioned relative to top-left. + gfx::Point location = ui::EventLocationFromNative(native_event); + EXPECT_EQ(gfx::Point(10, 190), location); + + [window orderOut:nil]; + [window close]; +} + +TEST_F(EventsMacTest, KeyboardCodeFromNative) { + NSEvent* native_event = nil; + ui::KeyboardCode code = ui::VKEY_UNKNOWN; + + // Simple "x". No modifiers. + native_event = + [NSEvent keyEventWithType:NSKeyDown + location:NSZeroPoint + modifierFlags:0 + timestamp:[NSDate timeIntervalSinceReferenceDate] + windowNumber:0 + context:nil + characters:@"x" + charactersIgnoringModifiers:@"x" + isARepeat:NO + keyCode:0x58]; + code = ui::KeyboardCodeFromNative(native_event); + EXPECT_EQ(ui::VKEY_X, code); + + // Option/Alt "x". + native_event = + [NSEvent keyEventWithType:NSKeyDown + location:NSZeroPoint + modifierFlags:NSAlternateKeyMask + timestamp:[NSDate timeIntervalSinceReferenceDate] + windowNumber:0 + context:nil + characters:@"\0x2248" // opt-x + charactersIgnoringModifiers:@"x" + isARepeat:NO + keyCode:0x58]; + code = ui::KeyboardCodeFromNative(native_event); + EXPECT_EQ(ui::VKEY_X, code); + + // Option/Alt (alone). + native_event = + [NSEvent keyEventWithType:NSFlagsChanged + location:NSZeroPoint + modifierFlags:NSAlternateKeyMask + timestamp:[NSDate timeIntervalSinceReferenceDate] + windowNumber:0 + context:nil + characters:@"" + charactersIgnoringModifiers:@"" + isARepeat:NO + keyCode:0x3a]; + code = ui::KeyboardCodeFromNative(native_event); + EXPECT_EQ(ui::VKEY_MENU, code); +} + +TEST_F(EventsMacTest, IsMouseEvent) { + NSEvent* native_event = nil; + + native_event = MouseEventWithType(NSLeftMouseDown, 0); + EXPECT_TRUE(ui::IsMouseEvent(native_event)); + + native_event = MouseEventWithType(NSLeftMouseUp, 0); + EXPECT_TRUE(ui::IsMouseEvent(native_event)); + + native_event = MouseEventWithType(NSRightMouseDown, 0); + EXPECT_TRUE(ui::IsMouseEvent(native_event)); + + native_event = MouseEventWithType(NSRightMouseUp, 0); + EXPECT_TRUE(ui::IsMouseEvent(native_event)); + + native_event = MouseEventWithType(NSMouseMoved, 0); + EXPECT_TRUE(ui::IsMouseEvent(native_event)); + + native_event = MouseEventWithType(NSLeftMouseDragged, 0); + EXPECT_TRUE(ui::IsMouseEvent(native_event)); + + native_event = MouseEventWithType(NSRightMouseDragged, 0); + EXPECT_TRUE(ui::IsMouseEvent(native_event)); + + native_event = EnterExitEventWithType(NSMouseEntered); + EXPECT_TRUE(ui::IsMouseEvent(native_event)); + + native_event = EnterExitEventWithType(NSMouseExited); + EXPECT_TRUE(ui::IsMouseEvent(native_event)); + + native_event = KeyEventWithType(NSKeyDown, 0); + EXPECT_FALSE(ui::IsMouseEvent(native_event)); + + native_event = KeyEventWithType(NSKeyUp, 0); + EXPECT_FALSE(ui::IsMouseEvent(native_event)); + + native_event = KeyEventWithType(NSFlagsChanged, 0); + EXPECT_FALSE(ui::IsMouseEvent(native_event)); + + native_event = OtherEventWithType(NSAppKitDefined); + EXPECT_FALSE(ui::IsMouseEvent(native_event)); + + native_event = OtherEventWithType(NSSystemDefined); + EXPECT_FALSE(ui::IsMouseEvent(native_event)); + + native_event = OtherEventWithType(NSApplicationDefined); + EXPECT_FALSE(ui::IsMouseEvent(native_event)); + + native_event = OtherEventWithType(NSPeriodic); + EXPECT_FALSE(ui::IsMouseEvent(native_event)); + + native_event = EnterExitEventWithType(NSCursorUpdate); + EXPECT_FALSE(ui::IsMouseEvent(native_event)); + + native_event = MouseEventWithType(NSOtherMouseDown, 0); + EXPECT_TRUE(ui::IsMouseEvent(native_event)); + + native_event = MouseEventWithType(NSOtherMouseUp, 0); + EXPECT_TRUE(ui::IsMouseEvent(native_event)); + + native_event = MouseEventWithType(NSOtherMouseDragged, 0); + EXPECT_TRUE(ui::IsMouseEvent(native_event)); +} + +TEST_F(EventsMacTest, CreateNoopEvent) { + NSEvent* native_event = ui::CreateNoopEvent(); + EXPECT_TRUE(native_event != nil); +} + +} // namespace diff --git a/ui/base/events.h b/ui/base/events.h index aab9366..539f922 100644 --- a/ui/base/events.h +++ b/ui/base/events.h @@ -80,7 +80,10 @@ UI_EXPORT EventType EventTypeFromNative(const base::NativeEvent& native_event); // Get the EventFlags from a native event. UI_EXPORT int EventFlagsFromNative(const base::NativeEvent& native_event); -// Get the location from a native event. +// Get the location from a native event. The coordinate system of the resultant +// |Point| has the origin at top-left of the "root window". The nature of +// this "root window" and how it maps to platform-specific drawing surfaces is +// defined in ui/aura/root_window.* and ui/aura/root_window_host*. UI_EXPORT gfx::Point EventLocationFromNative( const base::NativeEvent& native_event); diff --git a/ui/base/keycodes/keyboard_code_conversion_mac.h b/ui/base/keycodes/keyboard_code_conversion_mac.h index 74499b7..ef2bb5d 100644 --- a/ui/base/keycodes/keyboard_code_conversion_mac.h +++ b/ui/base/keycodes/keyboard_code_conversion_mac.h @@ -24,13 +24,18 @@ namespace ui { // |characterIgnoringModifiers|. // -1 will be returned if the keycode can't be converted. // This function is mainly for simulating keyboard events in unit tests. -// See third_party/WebKit/Source/WebKit/chromium/src/mac/WebInputEventFactory.mm for -// reverse conversion. +// See |KeyboardCodeFromNSEvent| for reverse conversion. UI_EXPORT int MacKeyCodeForWindowsKeyCode(KeyboardCode keycode, NSUInteger flags, unichar* character, unichar* characterIgnoringModifiers); +// This implementation cribbed from: +// third_party/WebKit/Source/WebKit/chromium/src/mac/WebInputEventFactory.mm +// Converts |event| into a |KeyboardCode|. The mapping is not direct as the Mac +// has a different notion of key codes. +UI_EXPORT KeyboardCode KeyboardCodeFromNSEvent(NSEvent* event); + } // namespace ui #endif // UI_BASE_KEYCODES_KEYBOARD_CODE_CONVERSION_MAC_H_ diff --git a/ui/base/keycodes/keyboard_code_conversion_mac.mm b/ui/base/keycodes/keyboard_code_conversion_mac.mm index bc9f070..c990255 100644 --- a/ui/base/keycodes/keyboard_code_conversion_mac.mm +++ b/ui/base/keycodes/keyboard_code_conversion_mac.mm @@ -200,6 +200,252 @@ const KeyCodeMap kKeyCodesMap[] = { // A convenient array for getting symbol characters on the number keys. const char kShiftCharsForNumberKeys[] = ")!@#$%^&*("; +// Translates from character code to keyboard code. +KeyboardCode KeyboardCodeFromCharCode(unichar charCode) { + switch (charCode) { + case 8: case 0x7F: return VKEY_BACK; + case 9: return VKEY_TAB; + case 0xD: case 3: return VKEY_RETURN; + case 0x1B: return VKEY_ESCAPE; + case ' ': return VKEY_SPACE; + case NSHomeFunctionKey: return VKEY_HOME; + case NSEndFunctionKey: return VKEY_END; + case NSPageUpFunctionKey: return VKEY_PRIOR; + case NSPageDownFunctionKey: return VKEY_NEXT; + case NSUpArrowFunctionKey: return VKEY_UP; + case NSDownArrowFunctionKey: return VKEY_DOWN; + case NSLeftArrowFunctionKey: return VKEY_LEFT; + case NSRightArrowFunctionKey: return VKEY_RIGHT; + case NSDeleteFunctionKey: return VKEY_DELETE; + + case '0': case ')': return VKEY_0; + case '1': case '!': return VKEY_1; + case '2': case '@': return VKEY_2; + case '3': case '#': return VKEY_3; + case '4': case '$': return VKEY_4; + case '5': case '%': return VKEY_5; + case '6': case '^': return VKEY_6; + case '7': case '&': return VKEY_7; + case '8': case '*': return VKEY_8; + case '9': case '(': return VKEY_9; + + case 'a': case 'A': return VKEY_A; + case 'b': case 'B': return VKEY_B; + case 'c': case 'C': return VKEY_C; + case 'd': case 'D': return VKEY_D; + case 'e': case 'E': return VKEY_E; + case 'f': case 'F': return VKEY_F; + case 'g': case 'G': return VKEY_G; + case 'h': case 'H': return VKEY_H; + case 'i': case 'I': return VKEY_I; + case 'j': case 'J': return VKEY_J; + case 'k': case 'K': return VKEY_K; + case 'l': case 'L': return VKEY_L; + case 'm': case 'M': return VKEY_M; + case 'n': case 'N': return VKEY_N; + case 'o': case 'O': return VKEY_O; + case 'p': case 'P': return VKEY_P; + case 'q': case 'Q': return VKEY_Q; + case 'r': case 'R': return VKEY_R; + case 's': case 'S': return VKEY_S; + case 't': case 'T': return VKEY_T; + case 'u': case 'U': return VKEY_U; + case 'v': case 'V': return VKEY_V; + case 'w': case 'W': return VKEY_W; + case 'x': case 'X': return VKEY_X; + case 'y': case 'Y': return VKEY_Y; + case 'z': case 'Z': return VKEY_Z; + + case NSPauseFunctionKey: return VKEY_PAUSE; + case NSSelectFunctionKey: return VKEY_SELECT; + case NSPrintFunctionKey: return VKEY_PRINT; + case NSExecuteFunctionKey: return VKEY_EXECUTE; + case NSPrintScreenFunctionKey: return VKEY_SNAPSHOT; + case NSInsertFunctionKey: return VKEY_INSERT; + case NSHelpFunctionKey: return VKEY_INSERT; + + case NSF1FunctionKey: return VKEY_F1; + case NSF2FunctionKey: return VKEY_F2; + case NSF3FunctionKey: return VKEY_F3; + case NSF4FunctionKey: return VKEY_F4; + case NSF5FunctionKey: return VKEY_F5; + case NSF6FunctionKey: return VKEY_F6; + case NSF7FunctionKey: return VKEY_F7; + case NSF8FunctionKey: return VKEY_F8; + case NSF9FunctionKey: return VKEY_F9; + case NSF10FunctionKey: return VKEY_F10; + case NSF11FunctionKey: return VKEY_F11; + case NSF12FunctionKey: return VKEY_F12; + case NSF13FunctionKey: return VKEY_F13; + case NSF14FunctionKey: return VKEY_F14; + case NSF15FunctionKey: return VKEY_F15; + case NSF16FunctionKey: return VKEY_F16; + case NSF17FunctionKey: return VKEY_F17; + case NSF18FunctionKey: return VKEY_F18; + case NSF19FunctionKey: return VKEY_F19; + case NSF20FunctionKey: return VKEY_F20; + + case NSF21FunctionKey: return VKEY_F21; + case NSF22FunctionKey: return VKEY_F22; + case NSF23FunctionKey: return VKEY_F23; + case NSF24FunctionKey: return VKEY_F24; + case NSScrollLockFunctionKey: return VKEY_SCROLL; + + // U.S. Specific mappings. Mileage may vary. + case ';': case ':': return VKEY_OEM_1; + case '=': case '+': return VKEY_OEM_PLUS; + case ',': case '<': return VKEY_OEM_COMMA; + case '-': case '_': return VKEY_OEM_MINUS; + case '.': case '>': return VKEY_OEM_PERIOD; + case '/': case '?': return VKEY_OEM_2; + case '`': case '~': return VKEY_OEM_3; + case '[': case '{': return VKEY_OEM_4; + case '\\': case '|': return VKEY_OEM_5; + case ']': case '}': return VKEY_OEM_6; + case '\'': case '"': return VKEY_OEM_7; + } + + return VKEY_UNKNOWN; +} + +KeyboardCode KeyboardCodeFromKeyCode(unsigned short keyCode) { + static const KeyboardCode kKeyboardCodes[] = { + /* 0 */ VKEY_A, + /* 1 */ VKEY_S, + /* 2 */ VKEY_D, + /* 3 */ VKEY_F, + /* 4 */ VKEY_H, + /* 5 */ VKEY_G, + /* 6 */ VKEY_Z, + /* 7 */ VKEY_X, + /* 8 */ VKEY_C, + /* 9 */ VKEY_V, + /* 0x0A */ VKEY_OEM_3, // Section key. + /* 0x0B */ VKEY_B, + /* 0x0C */ VKEY_Q, + /* 0x0D */ VKEY_W, + /* 0x0E */ VKEY_E, + /* 0x0F */ VKEY_R, + /* 0x10 */ VKEY_Y, + /* 0x11 */ VKEY_T, + /* 0x12 */ VKEY_1, + /* 0x13 */ VKEY_2, + /* 0x14 */ VKEY_3, + /* 0x15 */ VKEY_4, + /* 0x16 */ VKEY_6, + /* 0x17 */ VKEY_5, + /* 0x18 */ VKEY_OEM_PLUS, // =+ + /* 0x19 */ VKEY_9, + /* 0x1A */ VKEY_7, + /* 0x1B */ VKEY_OEM_MINUS, // -_ + /* 0x1C */ VKEY_8, + /* 0x1D */ VKEY_0, + /* 0x1E */ VKEY_OEM_6, // ]} + /* 0x1F */ VKEY_O, + /* 0x20 */ VKEY_U, + /* 0x21 */ VKEY_OEM_4, // {[ + /* 0x22 */ VKEY_I, + /* 0x23 */ VKEY_P, + /* 0x24 */ VKEY_RETURN, // Return + /* 0x25 */ VKEY_L, + /* 0x26 */ VKEY_J, + /* 0x27 */ VKEY_OEM_7, // '" + /* 0x28 */ VKEY_K, + /* 0x29 */ VKEY_OEM_1, // ;: + /* 0x2A */ VKEY_OEM_5, // \| + /* 0x2B */ VKEY_OEM_COMMA, // ,< + /* 0x2C */ VKEY_OEM_2, // /? + /* 0x2D */ VKEY_N, + /* 0x2E */ VKEY_M, + /* 0x2F */ VKEY_OEM_PERIOD, // .> + /* 0x30 */ VKEY_TAB, + /* 0x31 */ VKEY_SPACE, + /* 0x32 */ VKEY_OEM_3, // `~ + /* 0x33 */ VKEY_BACK, // Backspace + /* 0x34 */ VKEY_UNKNOWN, // n/a + /* 0x35 */ VKEY_ESCAPE, + /* 0x36 */ VKEY_APPS, // Right Command + /* 0x37 */ VKEY_LWIN, // Left Command + /* 0x38 */ VKEY_SHIFT, // Left Shift + /* 0x39 */ VKEY_CAPITAL, // Caps Lock + /* 0x3A */ VKEY_MENU, // Left Option + /* 0x3B */ VKEY_CONTROL, // Left Ctrl + /* 0x3C */ VKEY_SHIFT, // Right Shift + /* 0x3D */ VKEY_MENU, // Right Option + /* 0x3E */ VKEY_CONTROL, // Right Ctrl + /* 0x3F */ VKEY_UNKNOWN, // fn + /* 0x40 */ VKEY_F17, + /* 0x41 */ VKEY_DECIMAL, // Num Pad . + /* 0x42 */ VKEY_UNKNOWN, // n/a + /* 0x43 */ VKEY_MULTIPLY, // Num Pad * + /* 0x44 */ VKEY_UNKNOWN, // n/a + /* 0x45 */ VKEY_ADD, // Num Pad + + /* 0x46 */ VKEY_UNKNOWN, // n/a + /* 0x47 */ VKEY_CLEAR, // Num Pad Clear + /* 0x48 */ VKEY_VOLUME_UP, + /* 0x49 */ VKEY_VOLUME_DOWN, + /* 0x4A */ VKEY_VOLUME_MUTE, + /* 0x4B */ VKEY_DIVIDE, // Num Pad / + /* 0x4C */ VKEY_RETURN, // Num Pad Enter + /* 0x4D */ VKEY_UNKNOWN, // n/a + /* 0x4E */ VKEY_SUBTRACT, // Num Pad - + /* 0x4F */ VKEY_F18, + /* 0x50 */ VKEY_F19, + /* 0x51 */ VKEY_OEM_PLUS, // Num Pad =. + /* 0x52 */ VKEY_NUMPAD0, + /* 0x53 */ VKEY_NUMPAD1, + /* 0x54 */ VKEY_NUMPAD2, + /* 0x55 */ VKEY_NUMPAD3, + /* 0x56 */ VKEY_NUMPAD4, + /* 0x57 */ VKEY_NUMPAD5, + /* 0x58 */ VKEY_NUMPAD6, + /* 0x59 */ VKEY_NUMPAD7, + /* 0x5A */ VKEY_F20, + /* 0x5B */ VKEY_NUMPAD8, + /* 0x5C */ VKEY_NUMPAD9, + /* 0x5D */ VKEY_UNKNOWN, // Yen (JIS Keyboard Only) + /* 0x5E */ VKEY_UNKNOWN, // Underscore (JIS Keyboard Only) + /* 0x5F */ VKEY_UNKNOWN, // KeypadComma (JIS Keyboard Only) + /* 0x60 */ VKEY_F5, + /* 0x61 */ VKEY_F6, + /* 0x62 */ VKEY_F7, + /* 0x63 */ VKEY_F3, + /* 0x64 */ VKEY_F8, + /* 0x65 */ VKEY_F9, + /* 0x66 */ VKEY_UNKNOWN, // Eisu (JIS Keyboard Only) + /* 0x67 */ VKEY_F11, + /* 0x68 */ VKEY_UNKNOWN, // Kana (JIS Keyboard Only) + /* 0x69 */ VKEY_F13, + /* 0x6A */ VKEY_F16, + /* 0x6B */ VKEY_F14, + /* 0x6C */ VKEY_UNKNOWN, // n/a + /* 0x6D */ VKEY_F10, + /* 0x6E */ VKEY_UNKNOWN, // n/a (Windows95 key?) + /* 0x6F */ VKEY_F12, + /* 0x70 */ VKEY_UNKNOWN, // n/a + /* 0x71 */ VKEY_F15, + /* 0x72 */ VKEY_INSERT, // Help + /* 0x73 */ VKEY_HOME, // Home + /* 0x74 */ VKEY_PRIOR, // Page Up + /* 0x75 */ VKEY_DELETE, // Forward Delete + /* 0x76 */ VKEY_F4, + /* 0x77 */ VKEY_END, // End + /* 0x78 */ VKEY_F2, + /* 0x79 */ VKEY_NEXT, // Page Down + /* 0x7A */ VKEY_F1, + /* 0x7B */ VKEY_LEFT, // Left Arrow + /* 0x7C */ VKEY_RIGHT, // Right Arrow + /* 0x7D */ VKEY_DOWN, // Down Arrow + /* 0x7E */ VKEY_UP, // Up Arrow + /* 0x7F */ VKEY_UNKNOWN // n/a + }; + + if (keyCode >= 0x80) + return VKEY_UNKNOWN; + + return kKeyboardCodes[keyCode]; +} + } // anonymous namespace int MacKeyCodeForWindowsKeyCode(KeyboardCode keycode, @@ -288,4 +534,23 @@ int MacKeyCodeForWindowsKeyCode(KeyboardCode keycode, return macKeycode; } +KeyboardCode KeyboardCodeFromNSEvent(NSEvent* event) { + KeyboardCode code = VKEY_UNKNOWN; + + if ([event type] == NSKeyDown || [event type] == NSKeyUp) { + NSString* characters = [event characters]; + if ([characters length] > 0) + code = KeyboardCodeFromCharCode([characters characterAtIndex:0]); + if (code) + return code; + + characters = [event charactersIgnoringModifiers]; + if ([characters length] > 0) + code = KeyboardCodeFromCharCode([characters characterAtIndex:0]); + if (code) + return code; + } + return KeyboardCodeFromKeyCode([event keyCode]); +} + } // namespace ui diff --git a/ui/base/test/cocoa_test_event_utils.h b/ui/base/test/cocoa_test_event_utils.h index 121f33e..a16aa63 100644 --- a/ui/base/test/cocoa_test_event_utils.h +++ b/ui/base/test/cocoa_test_event_utils.h @@ -32,7 +32,7 @@ namespace cocoa_test_event_utils { // basic, flesh out as needed. Points are all in window coordinates; // where the window is not specified, coordinate system is undefined // (but will be repeated when the event is queried). -NSEvent* MakeMouseEvent(NSEventType type, NSUInteger modifiers); +NSEvent* MouseEventWithType(NSEventType type, NSUInteger modifiers); NSEvent* MouseEventAtPoint(NSPoint point, NSEventType type, NSUInteger modifiers); NSEvent* LeftMouseDownAtPoint(NSPoint point); @@ -46,6 +46,15 @@ std::pair<NSEvent*, NSEvent*> MouseClickInView(NSView* view, // Returns a key event with the given character. NSEvent* KeyEventWithCharacter(unichar c); +// Returns a key event with the given type and modifier flags. +NSEvent* KeyEventWithType(NSEventType event_type, NSUInteger modifiers); + +// Returns a mouse enter/exit event with the given type. +NSEvent* EnterExitEventWithType(NSEventType event_type); + +// Return an "other" event with the given type. +NSEvent* OtherEventWithType(NSEventType event_type); + } // namespace cocoa_test_event_utils #endif // UI_BASE_TEST_COCOA_TEST_EVENT_UTILS_H_ diff --git a/ui/base/test/cocoa_test_event_utils.mm b/ui/base/test/cocoa_test_event_utils.mm index f9ef04f..cea886c 100644 --- a/ui/base/test/cocoa_test_event_utils.mm +++ b/ui/base/test/cocoa_test_event_utils.mm @@ -45,7 +45,7 @@ NSEvent* MouseEventAtPoint(NSPoint point, NSEventType type, pressure:1.0]; } -NSEvent* MakeMouseEvent(NSEventType type, NSUInteger modifiers) { +NSEvent* MouseEventWithType(NSEventType type, NSUInteger modifiers) { return MouseEventAtPoint(NSMakePoint(0, 0), type, modifiers); } @@ -97,4 +97,41 @@ NSEvent* KeyEventWithCharacter(unichar c) { keyCode:0]; } +NSEvent* KeyEventWithType(NSEventType event_type, NSUInteger modifiers) { + return [NSEvent keyEventWithType:event_type + location:NSZeroPoint + modifierFlags:modifiers + timestamp:0 + windowNumber:0 + context:nil + characters:@"x" + charactersIgnoringModifiers:@"x" + isARepeat:NO + keyCode:0x78]; +} + +NSEvent* EnterExitEventWithType(NSEventType event_type) { + return [NSEvent enterExitEventWithType:event_type + location:NSZeroPoint + modifierFlags:0 + timestamp:0 + windowNumber:0 + context:nil + eventNumber:0 + trackingNumber:0 + userData:NULL]; +} + +NSEvent* OtherEventWithType(NSEventType event_type) { + return [NSEvent otherEventWithType:event_type + location:NSZeroPoint + modifierFlags:0 + timestamp:0 + windowNumber:0 + context:nil + subtype:0 + data1:0 + data2:0]; +} + } // namespace cocoa_test_event_utils @@ -85,6 +85,7 @@ 'base/clipboard/scoped_clipboard_writer.h', 'base/cocoa/base_view.h', 'base/cocoa/base_view.mm', + 'base/cocoa/events_mac.mm', 'base/dragdrop/cocoa_dnd_util.h', 'base/dragdrop/cocoa_dnd_util.mm', 'base/dragdrop/drag_drop_types_gtk.cc', diff --git a/ui/ui_unittests.gypi b/ui/ui_unittests.gypi index 359dc89..356b974 100644 --- a/ui/ui_unittests.gypi +++ b/ui/ui_unittests.gypi @@ -51,6 +51,7 @@ 'base/clipboard/clipboard_unittest.cc', 'base/clipboard/custom_data_helper_unittest.cc', 'base/cocoa/base_view_unittest.mm', + 'base/cocoa/events_mac_unittest.mm', 'base/gtk/gtk_expanded_container_unittest.cc', 'base/gtk/gtk_im_context_util_unittest.cc', 'base/ime/character_composer_unittest.cc', |