| 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 #import <Cocoa/Cocoa.h> | 5 #import <Cocoa/Cocoa.h> |
| 6 | 6 |
| 7 #import "base/mac/scoped_nsobject.h" | 7 #import "base/mac/scoped_nsobject.h" |
| 8 #import "base/mac/scoped_objc_class_swizzler.h" | 8 #import "base/mac/scoped_objc_class_swizzler.h" |
| 9 #include "base/memory/singleton.h" | 9 #include "base/memory/singleton.h" |
| 10 #include "ui/events/event_processor.h" | 10 #include "ui/events/event_processor.h" |
| 11 #include "ui/events/event_target.h" | 11 #include "ui/events/event_target.h" |
| 12 #include "ui/events/event_target_iterator.h" | 12 #include "ui/events/event_target_iterator.h" |
| 13 #include "ui/events/event_targeter.h" | 13 #include "ui/events/event_targeter.h" |
| 14 #import "ui/events/test/cocoa_test_event_utils.h" | 14 #import "ui/events/test/cocoa_test_event_utils.h" |
| 15 #include "ui/events/test/event_generator.h" | 15 #include "ui/events/test/event_generator.h" |
| 16 #include "ui/gfx/mac/coordinate_conversion.h" | 16 #include "ui/gfx/mac/coordinate_conversion.h" |
| 17 | 17 |
| 18 namespace { | 18 namespace { |
| 19 | 19 |
| 20 // Singleton to provide state for swizzled Objective C methods. | 20 // Singleton to provide state for swizzled Objective C methods. |
| 21 ui::test::EventGenerator* g_active_generator = NULL; | 21 ui::test::EventGenerator* g_active_generator = NULL; |
| 22 | 22 |
| 23 // Set (and always cleared) in EmulateSendEvent() to provide an answer for |
| 24 // [NSApp currentEvent]. |
| 25 NSEvent* g_current_event = nil; |
| 26 |
| 23 } // namespace | 27 } // namespace |
| 24 | 28 |
| 25 @interface NSEventDonor : NSObject | 29 @interface NSEventDonor : NSObject |
| 26 @end | 30 @end |
| 27 | 31 |
| 28 @implementation NSEventDonor | 32 @interface NSApplicationDonor : NSObject |
| 29 | |
| 30 // Donate +[NSEvent pressedMouseButtons] by retrieving the flags from the | |
| 31 // active generator. | |
| 32 + (NSUInteger)pressedMouseButtons { | |
| 33 if (!g_active_generator) | |
| 34 return [NSEventDonor pressedMouseButtons]; // Call original implementation. | |
| 35 | |
| 36 int flags = g_active_generator->flags(); | |
| 37 NSUInteger bitmask = 0; | |
| 38 if (flags & ui::EF_LEFT_MOUSE_BUTTON) | |
| 39 bitmask |= 1; | |
| 40 if (flags & ui::EF_RIGHT_MOUSE_BUTTON) | |
| 41 bitmask |= 1 << 1; | |
| 42 if (flags & ui::EF_MIDDLE_MOUSE_BUTTON) | |
| 43 bitmask |= 1 << 2; | |
| 44 return bitmask; | |
| 45 } | |
| 46 | |
| 47 @end | 33 @end |
| 48 | 34 |
| 49 namespace { | 35 namespace { |
| 50 | 36 |
| 51 NSPoint ConvertRootPointToTarget(NSWindow* target, | 37 NSPoint ConvertRootPointToTarget(NSWindow* target, |
| 52 const gfx::Point& point_in_root) { | 38 const gfx::Point& point_in_root) { |
| 53 // Normally this would do [NSWindow convertScreenToBase:]. However, Cocoa can | 39 // Normally this would do [NSWindow convertScreenToBase:]. However, Cocoa can |
| 54 // reposition the window on screen and make things flaky. Initially, just | 40 // reposition the window on screen and make things flaky. Initially, just |
| 55 // assume that the contentRect of |target| is at the top-left corner of the | 41 // assume that the contentRect of |target| is at the top-left corner of the |
| 56 // screen. | 42 // screen. |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 126 default: | 112 default: |
| 127 NOTREACHED(); | 113 NOTREACHED(); |
| 128 return 0; | 114 return 0; |
| 129 } | 115 } |
| 130 } | 116 } |
| 131 | 117 |
| 132 // Emulate the dispatching that would be performed by -[NSWindow sendEvent:]. | 118 // Emulate the dispatching that would be performed by -[NSWindow sendEvent:]. |
| 133 // sendEvent is a black box which (among other things) will try to peek at the | 119 // sendEvent is a black box which (among other things) will try to peek at the |
| 134 // event queue and can block indefinitely. | 120 // event queue and can block indefinitely. |
| 135 void EmulateSendEvent(NSWindow* window, NSEvent* event) { | 121 void EmulateSendEvent(NSWindow* window, NSEvent* event) { |
| 122 base::AutoReset<NSEvent*> reset(&g_current_event, event); |
| 136 NSResponder* responder = [window firstResponder]; | 123 NSResponder* responder = [window firstResponder]; |
| 137 switch ([event type]) { | 124 switch ([event type]) { |
| 138 case NSKeyDown: | 125 case NSKeyDown: |
| 139 [responder keyDown:event]; | 126 [responder keyDown:event]; |
| 140 return; | 127 return; |
| 141 case NSKeyUp: | 128 case NSKeyUp: |
| 142 [responder keyUp:event]; | 129 [responder keyUp:event]; |
| 143 return; | 130 return; |
| 144 } | 131 } |
| 145 | 132 |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 236 class EventGeneratorDelegateMac : public ui::EventTarget, | 223 class EventGeneratorDelegateMac : public ui::EventTarget, |
| 237 public ui::EventSource, | 224 public ui::EventSource, |
| 238 public ui::EventProcessor, | 225 public ui::EventProcessor, |
| 239 public ui::EventTargeter, | 226 public ui::EventTargeter, |
| 240 public ui::test::EventGeneratorDelegate { | 227 public ui::test::EventGeneratorDelegate { |
| 241 public: | 228 public: |
| 242 static EventGeneratorDelegateMac* GetInstance() { | 229 static EventGeneratorDelegateMac* GetInstance() { |
| 243 return Singleton<EventGeneratorDelegateMac>::get(); | 230 return Singleton<EventGeneratorDelegateMac>::get(); |
| 244 } | 231 } |
| 245 | 232 |
| 233 IMP CurrentEventMethod() { |
| 234 return swizzle_current_event_->GetOriginalImplementation(); |
| 235 } |
| 236 |
| 246 // Overridden from ui::EventTarget: | 237 // Overridden from ui::EventTarget: |
| 247 bool CanAcceptEvent(const ui::Event& event) override { return true; } | 238 bool CanAcceptEvent(const ui::Event& event) override { return true; } |
| 248 ui::EventTarget* GetParentTarget() override { return NULL; } | 239 ui::EventTarget* GetParentTarget() override { return NULL; } |
| 249 scoped_ptr<ui::EventTargetIterator> GetChildIterator() const override; | 240 scoped_ptr<ui::EventTargetIterator> GetChildIterator() const override; |
| 250 ui::EventTargeter* GetEventTargeter() override { return this; } | 241 ui::EventTargeter* GetEventTargeter() override { return this; } |
| 251 | 242 |
| 252 // Overridden from ui::EventHandler (via ui::EventTarget): | 243 // Overridden from ui::EventHandler (via ui::EventTarget): |
| 253 void OnMouseEvent(ui::MouseEvent* event) override; | 244 void OnMouseEvent(ui::MouseEvent* event) override; |
| 254 void OnKeyEvent(ui::KeyEvent* event) override; | 245 void OnKeyEvent(ui::KeyEvent* event) override; |
| 255 | 246 |
| (...skipping 28 matching lines...) Expand all Loading... |
| 284 | 275 |
| 285 private: | 276 private: |
| 286 friend struct DefaultSingletonTraits<EventGeneratorDelegateMac>; | 277 friend struct DefaultSingletonTraits<EventGeneratorDelegateMac>; |
| 287 | 278 |
| 288 EventGeneratorDelegateMac(); | 279 EventGeneratorDelegateMac(); |
| 289 ~EventGeneratorDelegateMac() override; | 280 ~EventGeneratorDelegateMac() override; |
| 290 | 281 |
| 291 ui::test::EventGenerator* owner_; | 282 ui::test::EventGenerator* owner_; |
| 292 NSWindow* window_; | 283 NSWindow* window_; |
| 293 scoped_ptr<base::mac::ScopedObjCClassSwizzler> swizzle_pressed_; | 284 scoped_ptr<base::mac::ScopedObjCClassSwizzler> swizzle_pressed_; |
| 285 scoped_ptr<base::mac::ScopedObjCClassSwizzler> swizzle_current_event_; |
| 294 base::scoped_nsobject<NSMenu> fake_menu_; | 286 base::scoped_nsobject<NSMenu> fake_menu_; |
| 295 | 287 |
| 296 DISALLOW_COPY_AND_ASSIGN(EventGeneratorDelegateMac); | 288 DISALLOW_COPY_AND_ASSIGN(EventGeneratorDelegateMac); |
| 297 }; | 289 }; |
| 298 | 290 |
| 299 EventGeneratorDelegateMac::EventGeneratorDelegateMac() | 291 EventGeneratorDelegateMac::EventGeneratorDelegateMac() |
| 300 : owner_(NULL), | 292 : owner_(NULL), |
| 301 window_(NULL) { | 293 window_(NULL) { |
| 302 DCHECK(!ui::test::EventGenerator::default_delegate); | 294 DCHECK(!ui::test::EventGenerator::default_delegate); |
| 303 ui::test::EventGenerator::default_delegate = this; | 295 ui::test::EventGenerator::default_delegate = this; |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 361 if ([fake_menu_ performKeyEquivalent:ns_event]) | 353 if ([fake_menu_ performKeyEquivalent:ns_event]) |
| 362 return; | 354 return; |
| 363 | 355 |
| 364 EmulateSendEvent(window_, ns_event); | 356 EmulateSendEvent(window_, ns_event); |
| 365 } | 357 } |
| 366 | 358 |
| 367 void EventGeneratorDelegateMac::SetContext(ui::test::EventGenerator* owner, | 359 void EventGeneratorDelegateMac::SetContext(ui::test::EventGenerator* owner, |
| 368 gfx::NativeWindow root_window, | 360 gfx::NativeWindow root_window, |
| 369 gfx::NativeWindow window) { | 361 gfx::NativeWindow window) { |
| 370 swizzle_pressed_.reset(); | 362 swizzle_pressed_.reset(); |
| 363 swizzle_current_event_.reset(); |
| 371 owner_ = owner; | 364 owner_ = owner; |
| 372 window_ = window; | 365 window_ = window; |
| 373 | 366 |
| 374 // Normally, edit menu items have a `nil` target. This results in -[NSMenu | 367 // Normally, edit menu items have a `nil` target. This results in -[NSMenu |
| 375 // performKeyEquivalent:] relying on -[NSApplication targetForAction:to:from:] | 368 // performKeyEquivalent:] relying on -[NSApplication targetForAction:to:from:] |
| 376 // to find a target starting at the first responder of the key window. Since | 369 // to find a target starting at the first responder of the key window. Since |
| 377 // non-interactive tests have no key window, that won't work. So set (or | 370 // non-interactive tests have no key window, that won't work. So set (or |
| 378 // clear) the target explicitly on all menu items. | 371 // clear) the target explicitly on all menu items. |
| 379 [[fake_menu_ itemArray] makeObjectsPerformSelector:@selector(setTarget:) | 372 [[fake_menu_ itemArray] makeObjectsPerformSelector:@selector(setTarget:) |
| 380 withObject:[window firstResponder]]; | 373 withObject:[window firstResponder]]; |
| 381 | 374 |
| 382 if (owner_) { | 375 if (owner_) { |
| 383 swizzle_pressed_.reset(new base::mac::ScopedObjCClassSwizzler( | 376 swizzle_pressed_.reset(new base::mac::ScopedObjCClassSwizzler( |
| 384 [NSEvent class], | 377 [NSEvent class], |
| 385 [NSEventDonor class], | 378 [NSEventDonor class], |
| 386 @selector(pressedMouseButtons))); | 379 @selector(pressedMouseButtons))); |
| 380 swizzle_current_event_.reset(new base::mac::ScopedObjCClassSwizzler( |
| 381 [NSApplication class], |
| 382 [NSApplicationDonor class], |
| 383 @selector(currentEvent))); |
| 387 } | 384 } |
| 388 } | 385 } |
| 389 | 386 |
| 390 gfx::Point EventGeneratorDelegateMac::CenterOfTarget( | 387 gfx::Point EventGeneratorDelegateMac::CenterOfTarget( |
| 391 const ui::EventTarget* target) const { | 388 const ui::EventTarget* target) const { |
| 392 DCHECK_EQ(target, this); | 389 DCHECK_EQ(target, this); |
| 393 return CenterOfWindow(window_); | 390 return CenterOfWindow(window_); |
| 394 } | 391 } |
| 395 | 392 |
| 396 gfx::Point EventGeneratorDelegateMac::CenterOfWindow( | 393 gfx::Point EventGeneratorDelegateMac::CenterOfWindow( |
| 397 gfx::NativeWindow window) const { | 394 gfx::NativeWindow window) const { |
| 398 DCHECK_EQ(window, window_); | 395 DCHECK_EQ(window, window_); |
| 399 return gfx::ScreenRectFromNSRect([window frame]).CenterPoint(); | 396 return gfx::ScreenRectFromNSRect([window frame]).CenterPoint(); |
| 400 } | 397 } |
| 401 | 398 |
| 402 } // namespace | 399 } // namespace |
| 403 | 400 |
| 404 namespace views { | 401 namespace views { |
| 405 namespace test { | 402 namespace test { |
| 406 | 403 |
| 407 void InitializeMacEventGeneratorDelegate() { | 404 void InitializeMacEventGeneratorDelegate() { |
| 408 EventGeneratorDelegateMac::GetInstance(); | 405 EventGeneratorDelegateMac::GetInstance(); |
| 409 } | 406 } |
| 410 | 407 |
| 411 } // namespace test | 408 } // namespace test |
| 412 } // namespace views | 409 } // namespace views |
| 410 |
| 411 @implementation NSEventDonor |
| 412 |
| 413 // Donate +[NSEvent pressedMouseButtons] by retrieving the flags from the |
| 414 // active generator. |
| 415 + (NSUInteger)pressedMouseButtons { |
| 416 if (!g_active_generator) |
| 417 return [NSEventDonor pressedMouseButtons]; // Call original implementation. |
| 418 |
| 419 int flags = g_active_generator->flags(); |
| 420 NSUInteger bitmask = 0; |
| 421 if (flags & ui::EF_LEFT_MOUSE_BUTTON) |
| 422 bitmask |= 1; |
| 423 if (flags & ui::EF_RIGHT_MOUSE_BUTTON) |
| 424 bitmask |= 1 << 1; |
| 425 if (flags & ui::EF_MIDDLE_MOUSE_BUTTON) |
| 426 bitmask |= 1 << 2; |
| 427 return bitmask; |
| 428 } |
| 429 |
| 430 @end |
| 431 |
| 432 @implementation NSApplicationDonor |
| 433 |
| 434 - (NSEvent*)currentEvent { |
| 435 if (g_current_event) |
| 436 return g_current_event; |
| 437 |
| 438 // Find the original implementation and invoke it. |
| 439 IMP original = EventGeneratorDelegateMac::GetInstance()->CurrentEventMethod(); |
| 440 return original(self, _cmd); |
| 441 } |
| 442 |
| 443 @end |
| OLD | NEW |