Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(762)

Side by Side Diff: ui/base/test/ui_controls_mac.mm

Issue 1747803003: MacViews: Implement Tab Dragging (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Replace GCD with DelegateSimpleThread, remove ConstrainToEnclosingRect function, cleanup code. Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2013 The Chromium Authors. All rights reserved. 1 // Copyright 2013 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/base/test/ui_controls.h" 5 #include "ui/base/test/ui_controls.h"
6 6
7 #import <Cocoa/Cocoa.h> 7 #import <Cocoa/Cocoa.h>
8 #include <vector> 8 #include <vector>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
11 #include "base/callback.h" 11 #include "base/callback.h"
12 #import "base/mac/foundation_util.h"
13 #import "base/mac/scoped_nsobject.h"
14 #import "base/mac/scoped_objc_class_swizzler.h"
12 #include "base/message_loop/message_loop.h" 15 #include "base/message_loop/message_loop.h"
16 #include "base/thread_task_runner_handle.h"
13 #include "ui/base/cocoa/cocoa_base_utils.h" 17 #include "ui/base/cocoa/cocoa_base_utils.h"
14 #include "ui/events/keycodes/keyboard_code_conversion_mac.h" 18 #include "ui/events/keycodes/keyboard_code_conversion_mac.h"
15 #import "ui/events/test/cocoa_test_event_utils.h" 19 #import "ui/events/test/cocoa_test_event_utils.h"
20 #import "ui/gfx/mac/coordinate_conversion.h"
21 #include "ui/gfx/screen.h"
16 22
17 // Implementation details: We use [NSApplication sendEvent:] instead 23 // Implementation details: We use [NSApplication sendEvent:] instead
18 // of [NSApplication postEvent:atStart:] so that the event gets sent 24 // of [NSApplication postEvent:atStart:] so that the event gets sent
19 // immediately. This lets us run the post-event task right 25 // immediately. This lets us run the post-event task right
20 // immediately as well. Unfortunately I cannot subclass NSEvent (it's 26 // immediately as well. Unfortunately I cannot subclass NSEvent (it's
21 // probably a class cluster) to allow other easy answers. For 27 // probably a class cluster) to allow other easy answers. For
22 // example, if I could subclass NSEvent, I could run the Task in it's 28 // example, if I could subclass NSEvent, I could run the Task in it's
23 // dealloc routine (which necessarily happens after the event is 29 // dealloc routine (which necessarily happens after the event is
24 // dispatched). Unlike Linux, Mac does not have message loop 30 // dispatched). Unlike Linux, Mac does not have message loop
25 // observer/notification. Unlike windows, I cannot post non-events 31 // observer/notification. Unlike windows, I cannot post non-events
(...skipping 15 matching lines...) Expand all
41 // events causes BrowserKeyEventsTest.CommandKeyEvents to fail. 47 // events causes BrowserKeyEventsTest.CommandKeyEvents to fail.
42 // See http://crbug.com/49270 48 // See http://crbug.com/49270
43 // 2. On OSX 10.6, [NSEvent addLocalMonitorForEventsMatchingMask:handler:] may 49 // 2. On OSX 10.6, [NSEvent addLocalMonitorForEventsMatchingMask:handler:] may
44 // be used, so that we don't need to poll the event queue time to time. 50 // be used, so that we don't need to poll the event queue time to time.
45 51
46 using cocoa_test_event_utils::SynthesizeKeyEvent; 52 using cocoa_test_event_utils::SynthesizeKeyEvent;
47 using cocoa_test_event_utils::TimeIntervalSinceSystemStartup; 53 using cocoa_test_event_utils::TimeIntervalSinceSystemStartup;
48 54
49 namespace { 55 namespace {
50 56
57 // When enabled, all simulated mouse events will be posted to
58 // the WindowServer, and the actual mouse will move on the screen.
59 bool g_use_cgevents = false;
60
51 // Stores the current mouse location on the screen. So that we can use it 61 // Stores the current mouse location on the screen. So that we can use it
52 // when firing keyboard and mouse click events. 62 // when firing keyboard and mouse click events.
53 NSPoint g_mouse_location = { 0, 0 }; 63 NSPoint g_mouse_location = { 0, 0 };
54 64
65 // If enabled overrides results returned by +[NSEvent mouseLocation] and
66 // -[NSWindow mouseLocationOutsideOfEventStream]
67 NSPoint g_mouse_location_override = {0, 0};
68 bool g_mouse_location_override_enabled = false;
69
70 // Stores the current pressed mouse buttons. Indexed by
71 // ui_controls::MouseButton.
72 bool g_mouse_button_down[3] = {false, false, false};
73
55 bool g_ui_controls_enabled = false; 74 bool g_ui_controls_enabled = false;
56 75
57 // Creates the proper sequence of autoreleased key events for a key down + up. 76 // Creates the proper sequence of autoreleased key events for a key down + up.
58 void SynthesizeKeyEventsSequence(NSWindow* window, 77 void SynthesizeKeyEventsSequence(NSWindow* window,
59 ui::KeyboardCode keycode, 78 ui::KeyboardCode keycode,
60 bool control, 79 bool control,
61 bool shift, 80 bool shift,
62 bool alt, 81 bool alt,
63 bool command, 82 bool command,
64 std::vector<NSEvent*>* events) { 83 std::vector<NSEvent*>* events) {
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
115 events->push_back(event); 134 events->push_back(event);
116 } 135 }
117 if (control) { 136 if (control) {
118 flags &= ~NSControlKeyMask; 137 flags &= ~NSControlKeyMask;
119 event = SynthesizeKeyEvent(window, false, ui::VKEY_CONTROL, flags); 138 event = SynthesizeKeyEvent(window, false, ui::VKEY_CONTROL, flags);
120 DCHECK(event); 139 DCHECK(event);
121 events->push_back(event); 140 events->push_back(event);
122 } 141 }
123 } 142 }
124 143
144 void RunTaskInTaskRunner(
145 scoped_refptr<base::SingleThreadTaskRunner> task_runner,
146 const base::Closure& task) {
147 task_runner->PostTask(FROM_HERE, task);
148 }
149
125 // A helper function to watch for the event queue. The specific task will be 150 // A helper function to watch for the event queue. The specific task will be
126 // fired when there is no more event in the queue. 151 // fired when there is no more event in the queue.
127 void EventQueueWatcher(const base::Closure& task) { 152 void EventQueueWatcher(const base::Closure& task) {
153 DCHECK_EQ(dispatch_get_current_queue(), dispatch_get_main_queue())
154 << "It should be run on the UI thread, as otherwise it will always "
155 "report there are no pending events";
128 NSEvent* event = [NSApp nextEventMatchingMask:NSAnyEventMask 156 NSEvent* event = [NSApp nextEventMatchingMask:NSAnyEventMask
129 untilDate:nil 157 untilDate:nil
130 inMode:NSDefaultRunLoopMode 158 inMode:NSDefaultRunLoopMode
131 dequeue:NO]; 159 dequeue:NO];
132 // If there is still event in the queue, then we need to check again. 160 // If there is still event in the queue, then we need to check again.
133 if (event) { 161 if (event) {
134 base::MessageLoop::current()->PostTask( 162 base::MessageLoop::current()->PostTask(
135 FROM_HERE, 163 FROM_HERE,
136 base::Bind(&EventQueueWatcher, task)); 164 base::Bind(&EventQueueWatcher, task));
137 } else { 165 } else {
(...skipping 28 matching lines...) Expand all
166 return window; 194 return window;
167 } 195 }
168 196
169 // Note that -[NSApplication orderedWindows] won't include NSPanels. If a test 197 // Note that -[NSApplication orderedWindows] won't include NSPanels. If a test
170 // uses those, it will need to handle that itself. 198 // uses those, it will need to handle that itself.
171 return nil; 199 return nil;
172 } 200 }
173 201
174 } // namespace 202 } // namespace
175 203
204 // Since CGEvents take some time to reach -[NSApplication sendEvent:] we use
205 // this class to wait for the events to start being processed before sending
206 // finish notifications.
207 class EventMonitor {
208 public:
209 void NotifyWhenEventIsProcessed(NSEvent* event, const base::Closure& task) {
210 if (g_use_cgevents) {
211 CHECK([[NSApplication sharedApplication] isActive])
212 << "If we generate CGEvents and the application is not active, we'll "
213 "deadlock waiting for NSMouseMoved events. Use "
214 "ui_test_utils::BringBrowserWindowToFront() to activate the "
215 "browser window prior to generating CGEvents.";
216 }
217
218 base::AutoLock auto_lock(lock_);
219 tasks_.emplace_back(Task(event, task));
220 }
221
222 void ProcessingEvent(NSEvent* event) {
223 base::AutoLock auto_lock(lock_);
224 auto it = std::find_if(
225 tasks_.begin(), tasks_.end(),
226 [&event](const Task& task) { return task.MatchesEvent(event); });
227 if (it != tasks_.end()) {
228 it->Run();
229 tasks_.erase(it);
230 }
231 }
232
233 static EventMonitor* Instance() {
234 static EventMonitor* monitor = nullptr;
235 if (!monitor) {
236 monitor = new EventMonitor();
237 }
238 return monitor;
239 }
240
241 private:
242 class Task {
243 public:
244 Task(NSEvent* event, const base::Closure& task)
245 : task_runner_(base::ThreadTaskRunnerHandle::Get()),
246 event_([event retain]),
247 finish_closure_(task) {}
248
249 bool MatchesEvent(NSEvent* event) const {
250 // When moving the window using BridgedNativeWidget::RunMoveLoop the
251 // locationInWindow can be a little inconsistent with what we expect.
252 // Seems that only comparing event type is fine.
253 return
254 [event_ type] == [event type] && [event_ subtype] == [event subtype];
255 }
256
257 void Run() {
258 // We get here before the event is actually processed. Run the
259 // EventQueueWatcher on the main thread in order to wait for all events to
260 // finish processing.
261 base::MessageLoop::current()->PostTask(
262 FROM_HERE, base::Bind(&EventQueueWatcher,
263 base::Bind(&RunTaskInTaskRunner, task_runner_,
264 finish_closure_)));
265 }
266
267 private:
268 // Events could be spawned on background threads. Be sure to invoke the
269 // |finish_closure_| on an appropriate thread.
270 scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
271 base::scoped_nsobject<NSEvent> event_;
272 base::Closure finish_closure_;
273 };
274
275 EventMonitor()
276 : send_event_swizzler_(
277 new base::mac::ScopedObjCClassSwizzler([NSApplication class],
278 @selector(sendEvent:),
279 @selector(cr_sendEvent:))) {}
280
281 std::vector<Task> tasks_;
282
283 // synchronizes access to the |tasks_| in case we spawn the events on a
284 // different thread
285 base::Lock lock_;
286
287 std::unique_ptr<base::mac::ScopedObjCClassSwizzler> send_event_swizzler_;
288
289 DISALLOW_COPY_AND_ASSIGN(EventMonitor);
290 };
291
292 // Donates testing implementations of NSApplication methods. We can't simply
293 // use -[NSEvent addLocalMonitorForEventsMatchingMask:handler:], as other event
294 // monitors could have precedence, and they could filter the events before we
295 // can see them. But since nobody swizzles -[NSApplication sendEvent:] we should
296 // be safe.
297 @interface NSApplication (TestingDonor)
298 @end
299
300 @implementation NSApplication (TestingDonor)
301 - (void)cr_sendEvent:(NSEvent*)event {
302 // Invoke the finish handler before the event is processed, since we can get
303 // stuck in BridgedNativeWidget::RunMoveLoop and would never see the event
304 // otherwise.
305 EventMonitor::Instance()->ProcessingEvent(event);
306
307 [self cr_sendEvent:event];
308 }
309 @end
310
311 // Donates testing implementations of NSEvent methods.
312 @interface FakeNSEventTestingDonor : NSObject
313 @end
314
315 @implementation FakeNSEventTestingDonor
316 + (NSPoint)mouseLocation {
317 if (g_mouse_location_override_enabled)
318 return g_mouse_location_override;
319
320 return g_mouse_location;
321 }
322
323 + (NSUInteger)pressedMouseButtons {
324 NSUInteger result = 0;
325 const int buttons[3] = {
326 ui_controls::LEFT, ui_controls::RIGHT, ui_controls::MIDDLE};
327 for (unsigned int i = 0; i < arraysize(buttons); ++i) {
328 if (g_mouse_button_down[buttons[i]])
329 result |= (1 << i);
330 }
331 return result;
332 }
333 @end
334
335 // Donates testing implementations of NSWindow methods.
336 @interface FakeNSWindowTestingDonor : NSObject
337 @end
338
339 @implementation FakeNSWindowTestingDonor
340 - (NSPoint)mouseLocationOutsideOfEventStream {
341 NSWindow* window = base::mac::ObjCCastStrict<NSWindow>(self);
342 if (g_mouse_location_override_enabled)
343 return ui::ConvertPointFromWindowToScreen(window,
344 g_mouse_location_override);
345
346 return ui::ConvertPointFromWindowToScreen(window, g_mouse_location);
347 }
348 @end
349
350 namespace {
351 class NSEventSwizzler {
352 public:
353 static void Install() {
354 static NSEventSwizzler* swizzler = nullptr;
355 if (!swizzler) {
356 swizzler = new NSEventSwizzler();
357 }
358 }
359
360 protected:
361 NSEventSwizzler()
362 : mouse_location_swizzler_(new base::mac::ScopedObjCClassSwizzler(
363 [NSEvent class],
364 [FakeNSEventTestingDonor class],
365 @selector(mouseLocation))),
366 pressed_mouse_buttons_swizzler_(new base::mac::ScopedObjCClassSwizzler(
367 [NSEvent class],
368 [FakeNSEventTestingDonor class],
369 @selector(pressedMouseButtons))),
370 mouse_location_outside_of_event_stream_swizzler_(
371 new base::mac::ScopedObjCClassSwizzler(
372 [NSWindow class],
373 [FakeNSWindowTestingDonor class],
374 @selector(mouseLocationOutsideOfEventStream))) {}
375
376 private:
377 std::unique_ptr<base::mac::ScopedObjCClassSwizzler> mouse_location_swizzler_;
378 std::unique_ptr<base::mac::ScopedObjCClassSwizzler>
379 pressed_mouse_buttons_swizzler_;
380 std::unique_ptr<base::mac::ScopedObjCClassSwizzler>
381 mouse_location_outside_of_event_stream_swizzler_;
382 };
383 } // namespace
384
176 namespace ui_controls { 385 namespace ui_controls {
177 386
178 void EnableUIControls() { 387 void EnableUIControls() {
179 g_ui_controls_enabled = true; 388 g_ui_controls_enabled = true;
180 } 389 }
181 390
182 bool IsUIControlsEnabled() { 391 bool IsUIControlsEnabled() {
183 return g_ui_controls_enabled; 392 return g_ui_controls_enabled;
184 } 393 }
185 394
(...skipping 11 matching lines...) Expand all
197 406
198 // Win and Linux implement a SendKeyPress() this as a 407 // Win and Linux implement a SendKeyPress() this as a
199 // SendKeyPressAndRelease(), so we should as well (despite the name). 408 // SendKeyPressAndRelease(), so we should as well (despite the name).
200 bool SendKeyPressNotifyWhenDone(gfx::NativeWindow window, 409 bool SendKeyPressNotifyWhenDone(gfx::NativeWindow window,
201 ui::KeyboardCode key, 410 ui::KeyboardCode key,
202 bool control, 411 bool control,
203 bool shift, 412 bool shift,
204 bool alt, 413 bool alt,
205 bool command, 414 bool command,
206 const base::Closure& task) { 415 const base::Closure& task) {
416 DCHECK(!g_use_cgevents) << "Not implemented";
207 CHECK(g_ui_controls_enabled); 417 CHECK(g_ui_controls_enabled);
208 DCHECK(base::MessageLoopForUI::IsCurrent()); 418 DCHECK(base::MessageLoopForUI::IsCurrent());
209 419
210 std::vector<NSEvent*> events; 420 std::vector<NSEvent*> events;
211 SynthesizeKeyEventsSequence( 421 SynthesizeKeyEventsSequence(
212 window, key, control, shift, alt, command, &events); 422 window, key, control, shift, alt, command, &events);
213 423
214 // TODO(suzhe): Using [NSApplication postEvent:atStart:] here causes 424 // TODO(suzhe): Using [NSApplication postEvent:atStart:] here causes
215 // BrowserKeyEventsTest.CommandKeyEvents to fail. See http://crbug.com/49270 425 // BrowserKeyEventsTest.CommandKeyEvents to fail. See http://crbug.com/49270
216 // But using [NSApplication sendEvent:] should be safe for keyboard events, 426 // But using [NSApplication sendEvent:] should be safe for keyboard events,
(...skipping 15 matching lines...) Expand all
232 CHECK(g_ui_controls_enabled); 442 CHECK(g_ui_controls_enabled);
233 return SendMouseMoveNotifyWhenDone(x, y, base::Closure()); 443 return SendMouseMoveNotifyWhenDone(x, y, base::Closure());
234 } 444 }
235 445
236 // Input position is in screen coordinates. However, NSMouseMoved 446 // Input position is in screen coordinates. However, NSMouseMoved
237 // events require them window-relative, so we adjust. We *DO* flip 447 // events require them window-relative, so we adjust. We *DO* flip
238 // the coordinate space, so input events can be the same for all 448 // the coordinate space, so input events can be the same for all
239 // platforms. E.g. (0,0) is upper-left. 449 // platforms. E.g. (0,0) is upper-left.
240 bool SendMouseMoveNotifyWhenDone(long x, long y, const base::Closure& task) { 450 bool SendMouseMoveNotifyWhenDone(long x, long y, const base::Closure& task) {
241 CHECK(g_ui_controls_enabled); 451 CHECK(g_ui_controls_enabled);
242 CGFloat screenHeight = 452 g_mouse_location = gfx::ScreenPointToNSPoint(gfx::Point(x, y)); // flip!
243 [[[NSScreen screens] firstObject] frame].size.height; 453 NSEventSwizzler::Install();
244 g_mouse_location = NSMakePoint(x, screenHeight - y); // flip!
245 454
246 NSWindow* window = WindowAtCurrentMouseLocation(); 455 NSWindow* window = WindowAtCurrentMouseLocation();
247 456
248 NSPoint pointInWindow = g_mouse_location; 457 NSPoint pointInWindow = g_mouse_location;
249 if (window) 458 if (window)
250 pointInWindow = ui::ConvertPointFromScreenToWindow(window, pointInWindow); 459 pointInWindow = ui::ConvertPointFromScreenToWindow(window, pointInWindow);
251 NSTimeInterval timestamp = TimeIntervalSinceSystemStartup(); 460 NSTimeInterval timestamp = TimeIntervalSinceSystemStartup();
252 461
462 NSEventType event_type = NSMouseMoved;
463 if (g_mouse_button_down[LEFT]) {
464 event_type = NSLeftMouseDragged;
465 } else if (g_mouse_button_down[RIGHT]) {
466 event_type = NSRightMouseDragged;
467 } else if (g_mouse_button_down[MIDDLE]) {
468 event_type = NSOtherMouseDragged;
469 }
470
253 NSEvent* event = 471 NSEvent* event =
254 [NSEvent mouseEventWithType:NSMouseMoved 472 [NSEvent mouseEventWithType:event_type
255 location:pointInWindow 473 location:pointInWindow
256 modifierFlags:0 474 modifierFlags:0
257 timestamp:timestamp 475 timestamp:timestamp
258 windowNumber:[window windowNumber] 476 windowNumber:[window windowNumber]
259 context:nil 477 context:nil
260 eventNumber:0 478 eventNumber:0
261 clickCount:0 479 clickCount:(event_type == NSMouseMoved ? 0 : 1)
262 pressure:0.0]; 480 pressure:(event_type == NSMouseMoved ? 0.0 : 1.0)];
263 [[NSApplication sharedApplication] postEvent:event atStart:NO];
264 481
265 if (!task.is_null()) { 482 if (!task.is_null()) {
266 base::MessageLoop::current()->PostTask( 483 EventMonitor::Instance()->NotifyWhenEventIsProcessed(event, task);
267 FROM_HERE, base::Bind(&EventQueueWatcher, task)); 484 }
485
486 gfx::Point gp = gfx::ScreenPointFromNSPoint(g_mouse_location);
487 CGWarpMouseCursorPosition(CGPointMake(gp.x(), gp.y()));
488
489 if (g_use_cgevents) {
490 CGEventPost(kCGSessionEventTap, [event CGEvent]);
491 } else {
492 [[NSApplication sharedApplication] postEvent:event atStart:NO];
268 } 493 }
269 494
270 return true; 495 return true;
271 } 496 }
272 497
273 bool SendMouseEvents(MouseButton type, int state) { 498 bool SendMouseEvents(MouseButton type, int state) {
274 CHECK(g_ui_controls_enabled); 499 CHECK(g_ui_controls_enabled);
275 return SendMouseEventsNotifyWhenDone(type, state, base::Closure()); 500 return SendMouseEventsNotifyWhenDone(type, state, base::Closure());
276 } 501 }
277 502
278 bool SendMouseEventsNotifyWhenDone(MouseButton type, int state, 503 bool SendMouseEventsNotifyWhenDone(MouseButton type, int state,
279 const base::Closure& task) { 504 const base::Closure& task) {
280 CHECK(g_ui_controls_enabled); 505 CHECK(g_ui_controls_enabled);
281 // On windows it appears state can be (UP|DOWN). It is unclear if 506 // On windows it appears state can be (UP|DOWN). It is unclear if
282 // that'll happen here but prepare for it just in case. 507 // that'll happen here but prepare for it just in case.
283 if (state == (UP|DOWN)) { 508 if (state == (UP|DOWN)) {
284 return (SendMouseEventsNotifyWhenDone(type, DOWN, base::Closure()) && 509 return (SendMouseEventsNotifyWhenDone(type, DOWN, base::Closure()) &&
285 SendMouseEventsNotifyWhenDone(type, UP, task)); 510 SendMouseEventsNotifyWhenDone(type, UP, task));
286 } 511 }
287 NSEventType etype = NSLeftMouseDown; 512 NSEventType event_type = NSLeftMouseDown;
288 if (type == LEFT) { 513 if (type == LEFT) {
289 if (state == UP) { 514 if (state == UP) {
290 etype = NSLeftMouseUp; 515 event_type = NSLeftMouseUp;
291 } else { 516 } else {
292 etype = NSLeftMouseDown; 517 event_type = NSLeftMouseDown;
293 } 518 }
294 } else if (type == MIDDLE) { 519 } else if (type == MIDDLE) {
295 if (state == UP) { 520 if (state == UP) {
296 etype = NSOtherMouseUp; 521 event_type = NSOtherMouseUp;
297 } else { 522 } else {
298 etype = NSOtherMouseDown; 523 event_type = NSOtherMouseDown;
299 } 524 }
300 } else if (type == RIGHT) { 525 } else if (type == RIGHT) {
301 if (state == UP) { 526 if (state == UP) {
302 etype = NSRightMouseUp; 527 event_type = NSRightMouseUp;
303 } else { 528 } else {
304 etype = NSRightMouseDown; 529 event_type = NSRightMouseDown;
305 } 530 }
306 } else { 531 } else {
532 NOTREACHED();
307 return false; 533 return false;
308 } 534 }
535 g_mouse_button_down[type] = state == DOWN;
536
309 NSWindow* window = WindowAtCurrentMouseLocation(); 537 NSWindow* window = WindowAtCurrentMouseLocation();
310 NSPoint pointInWindow = g_mouse_location; 538 NSPoint pointInWindow = g_mouse_location;
311 if (window) 539 if (window)
312 pointInWindow = ui::ConvertPointFromScreenToWindow(window, pointInWindow); 540 pointInWindow = ui::ConvertPointFromScreenToWindow(window, pointInWindow);
313 541
542 NSEventSwizzler::Install();
543
314 NSEvent* event = 544 NSEvent* event =
315 [NSEvent mouseEventWithType:etype 545 [NSEvent mouseEventWithType:event_type
316 location:pointInWindow 546 location:pointInWindow
317 modifierFlags:0 547 modifierFlags:0
318 timestamp:TimeIntervalSinceSystemStartup() 548 timestamp:TimeIntervalSinceSystemStartup()
319 windowNumber:[window windowNumber] 549 windowNumber:[window windowNumber]
320 context:nil 550 context:nil
321 eventNumber:0 551 eventNumber:0
322 clickCount:1 552 clickCount:1
323 pressure:(state == DOWN ? 1.0 : 0.0 )]; 553 pressure:(state == DOWN ? 1.0 : 0.0 )];
324 [[NSApplication sharedApplication] postEvent:event atStart:NO];
325 554
326 if (!task.is_null()) { 555 if (!task.is_null()) {
327 base::MessageLoop::current()->PostTask( 556 EventMonitor::Instance()->NotifyWhenEventIsProcessed(event, task);
328 FROM_HERE, base::Bind(&EventQueueWatcher, task)); 557 }
558
559 if (g_use_cgevents) {
560 CGEventPost(kCGSessionEventTap, [event CGEvent]);
561 } else {
562 [[NSApplication sharedApplication] postEvent:event atStart:NO];
329 } 563 }
330 564
331 return true; 565 return true;
332 } 566 }
333 567
334 bool SendMouseClick(MouseButton type) { 568 bool SendMouseClick(MouseButton type) {
335 CHECK(g_ui_controls_enabled); 569 CHECK(g_ui_controls_enabled);
336 return SendMouseEventsNotifyWhenDone(type, UP|DOWN, base::Closure()); 570 return SendMouseEventsNotifyWhenDone(type, UP|DOWN, base::Closure());
337 } 571 }
338 572
339 void RunClosureAfterAllPendingUIEvents(const base::Closure& closure) { 573 void RunClosureAfterAllPendingUIEvents(const base::Closure& closure) {
340 base::MessageLoop::current()->PostTask( 574 base::MessageLoop::current()->PostTask(
341 FROM_HERE, base::Bind(&EventQueueWatcher, closure)); 575 FROM_HERE, base::Bind(&EventQueueWatcher, closure));
342 } 576 }
343 577
344 bool IsFullKeyboardAccessEnabled() { 578 bool IsFullKeyboardAccessEnabled() {
345 return [NSApp isFullKeyboardAccessEnabled]; 579 return [NSApp isFullKeyboardAccessEnabled];
346 } 580 }
347 581
582 void SetSendMouseEventsAsCGEvents(bool enable_cgevents) {
583 g_use_cgevents = enable_cgevents;
584 }
585
586 bool SendMouseEventsAsCGEvents() {
587 return g_use_cgevents;
588 }
589
590 void NotifyWhenEventIsProcessed(NSEvent* event, const base::Closure& task) {
591 EventMonitor::Instance()->NotifyWhenEventIsProcessed(event, task);
592 }
593
594 void SetMousePositionOverride(bool enable_override, const gfx::Point& p) {
595 g_mouse_location_override_enabled = enable_override;
596 g_mouse_location_override = gfx::ScreenPointToNSPoint(p); // flip!
597 }
598
348 } // namespace ui_controls 599 } // namespace ui_controls
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698