Index: ui/base/test/ui_controls_mac.mm |
diff --git a/ui/base/test/ui_controls_mac.mm b/ui/base/test/ui_controls_mac.mm |
index b7615b6c2fd78eab1ddbb87a351cf33f47c4efd1..17e272fb15fb65abffef6c4ef98a4c90e80d976c 100644 |
--- a/ui/base/test/ui_controls_mac.mm |
+++ b/ui/base/test/ui_controls_mac.mm |
@@ -9,10 +9,14 @@ |
#include "base/bind.h" |
#include "base/callback.h" |
+#import "base/mac/foundation_util.h" |
+#import "base/mac/scoped_objc_class_swizzler.h" |
#include "base/message_loop/message_loop.h" |
#include "ui/base/cocoa/cocoa_base_utils.h" |
#include "ui/events/keycodes/keyboard_code_conversion_mac.h" |
#import "ui/events/test/cocoa_test_event_utils.h" |
+#include "ui/gfx/geometry/point.h" |
+#import "ui/gfx/mac/coordinate_conversion.h" |
// Implementation details: We use [NSApplication sendEvent:] instead |
// of [NSApplication postEvent:atStart:] so that the event gets sent |
@@ -52,6 +56,10 @@ namespace { |
// when firing keyboard and mouse click events. |
NSPoint g_mouse_location = { 0, 0 }; |
+// Stores the current pressed mouse buttons. Indexed by |
+// ui_controls::MouseButton. |
+bool g_mouse_button_down[3] = {false, false, false}; |
+ |
bool g_ui_controls_enabled = false; |
// Creates the proper sequence of autoreleased key events for a key down + up. |
@@ -173,6 +181,80 @@ NSWindow* WindowAtCurrentMouseLocation() { |
} // namespace |
+// Donates testing implementations of NSEvent methods. |
+@interface FakeNSEventTestingDonor : NSObject |
+@end |
+ |
+@implementation FakeNSEventTestingDonor |
++ (NSPoint)mouseLocation { |
+ return g_mouse_location; |
+} |
+ |
++ (NSUInteger)pressedMouseButtons { |
+ NSUInteger result = 0; |
+ const int buttons[3] = { |
+ ui_controls::LEFT, ui_controls::RIGHT, ui_controls::MIDDLE}; |
+ for (size_t i = 0; i < arraysize(buttons); ++i) { |
+ if (g_mouse_button_down[buttons[i]]) |
+ result |= (1 << i); |
+ } |
+ return result; |
+} |
+@end |
+ |
+// Donates testing implementations of NSWindow methods. |
+@interface FakeNSWindowTestingDonor : NSObject |
+@end |
+ |
+@implementation FakeNSWindowTestingDonor |
+- (NSPoint)mouseLocationOutsideOfEventStream { |
+ NSWindow* window = base::mac::ObjCCastStrict<NSWindow>(self); |
+ return ui::ConvertPointFromWindowToScreen(window, g_mouse_location); |
+} |
+@end |
+ |
+namespace { |
+ |
+// Swizzles several Cocoa functions that are used to directly get mouse state, |
+// so that they will return the current simulated mouse position and pressed |
+// mouse buttons. |
+class NSEventSwizzler { |
+ public: |
+ static void Install() { |
+ static NSEventSwizzler* swizzler = nullptr; |
+ if (!swizzler) { |
+ swizzler = new NSEventSwizzler(); |
+ } |
+ } |
+ |
+ protected: |
+ NSEventSwizzler() |
+ : mouse_location_swizzler_(new base::mac::ScopedObjCClassSwizzler( |
+ [NSEvent class], |
+ [FakeNSEventTestingDonor class], |
+ @selector(mouseLocation))), |
+ pressed_mouse_buttons_swizzler_(new base::mac::ScopedObjCClassSwizzler( |
+ [NSEvent class], |
+ [FakeNSEventTestingDonor class], |
+ @selector(pressedMouseButtons))), |
+ mouse_location_outside_of_event_stream_swizzler_( |
+ new base::mac::ScopedObjCClassSwizzler( |
+ [NSWindow class], |
+ [FakeNSWindowTestingDonor class], |
+ @selector(mouseLocationOutsideOfEventStream))) {} |
+ |
+ private: |
+ std::unique_ptr<base::mac::ScopedObjCClassSwizzler> mouse_location_swizzler_; |
+ std::unique_ptr<base::mac::ScopedObjCClassSwizzler> |
+ pressed_mouse_buttons_swizzler_; |
+ std::unique_ptr<base::mac::ScopedObjCClassSwizzler> |
+ mouse_location_outside_of_event_stream_swizzler_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(NSEventSwizzler); |
+}; |
+ |
+} // namespace |
+ |
namespace ui_controls { |
void EnableUIControls() { |
@@ -239,9 +321,8 @@ bool SendMouseMove(long x, long y) { |
// platforms. E.g. (0,0) is upper-left. |
bool SendMouseMoveNotifyWhenDone(long x, long y, const base::Closure& task) { |
CHECK(g_ui_controls_enabled); |
- CGFloat screenHeight = |
- [[[NSScreen screens] firstObject] frame].size.height; |
- g_mouse_location = NSMakePoint(x, screenHeight - y); // flip! |
+ g_mouse_location = gfx::ScreenPointToNSPoint(gfx::Point(x, y)); // flip! |
+ NSEventSwizzler::Install(); |
NSWindow* window = WindowAtCurrentMouseLocation(); |
@@ -250,16 +331,25 @@ bool SendMouseMoveNotifyWhenDone(long x, long y, const base::Closure& task) { |
pointInWindow = ui::ConvertPointFromScreenToWindow(window, pointInWindow); |
NSTimeInterval timestamp = TimeIntervalSinceSystemStartup(); |
+ NSEventType event_type = NSMouseMoved; |
+ if (g_mouse_button_down[LEFT]) { |
+ event_type = NSLeftMouseDragged; |
+ } else if (g_mouse_button_down[RIGHT]) { |
+ event_type = NSRightMouseDragged; |
+ } else if (g_mouse_button_down[MIDDLE]) { |
+ event_type = NSOtherMouseDragged; |
+ } |
+ |
NSEvent* event = |
- [NSEvent mouseEventWithType:NSMouseMoved |
+ [NSEvent mouseEventWithType:event_type |
location:pointInWindow |
modifierFlags:0 |
timestamp:timestamp |
windowNumber:[window windowNumber] |
context:nil |
eventNumber:0 |
- clickCount:0 |
- pressure:0.0]; |
+ clickCount:event_type == NSMouseMoved ? 0 : 1 |
+ pressure:event_type == NSMouseMoved ? 0.0 : 1.0]; |
[[NSApplication sharedApplication] postEvent:event atStart:NO]; |
if (!task.is_null()) { |
@@ -284,35 +374,40 @@ bool SendMouseEventsNotifyWhenDone(MouseButton type, int state, |
return (SendMouseEventsNotifyWhenDone(type, DOWN, base::Closure()) && |
SendMouseEventsNotifyWhenDone(type, UP, task)); |
} |
- NSEventType etype = NSLeftMouseDown; |
+ NSEventType event_type = NSLeftMouseDown; |
if (type == LEFT) { |
if (state == UP) { |
- etype = NSLeftMouseUp; |
+ event_type = NSLeftMouseUp; |
} else { |
- etype = NSLeftMouseDown; |
+ event_type = NSLeftMouseDown; |
} |
} else if (type == MIDDLE) { |
if (state == UP) { |
- etype = NSOtherMouseUp; |
+ event_type = NSOtherMouseUp; |
} else { |
- etype = NSOtherMouseDown; |
+ event_type = NSOtherMouseDown; |
} |
} else if (type == RIGHT) { |
if (state == UP) { |
- etype = NSRightMouseUp; |
+ event_type = NSRightMouseUp; |
} else { |
- etype = NSRightMouseDown; |
+ event_type = NSRightMouseDown; |
} |
} else { |
+ NOTREACHED(); |
return false; |
} |
+ g_mouse_button_down[type] = state == DOWN; |
+ |
NSWindow* window = WindowAtCurrentMouseLocation(); |
NSPoint pointInWindow = g_mouse_location; |
if (window) |
pointInWindow = ui::ConvertPointFromScreenToWindow(window, pointInWindow); |
+ NSEventSwizzler::Install(); |
+ |
NSEvent* event = |
- [NSEvent mouseEventWithType:etype |
+ [NSEvent mouseEventWithType:event_type |
location:pointInWindow |
modifierFlags:0 |
timestamp:TimeIntervalSinceSystemStartup() |