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

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: Removed debug logging, use CGEvents for drag-n-drop. Created 4 years, 9 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 #include "base/debug/stack_trace.h"
13 #include "base/mac/foundation_util.h"
14 #include "base/mac/scoped_nsautorelease_pool.h"
15 #include "base/mac/scoped_nsobject.h"
tapted 2016/03/04 06:33:08 the objc headers should be #imported
themblsha 2016/03/09 17:40:22 Done.
16 #include "base/mac/scoped_objc_class_swizzler.h"
12 #include "base/message_loop/message_loop.h" 17 #include "base/message_loop/message_loop.h"
18 #include "base/thread_task_runner_handle.h"
19 #include "content/public/browser/browser_thread.h"
13 #include "ui/events/keycodes/keyboard_code_conversion_mac.h" 20 #include "ui/events/keycodes/keyboard_code_conversion_mac.h"
14 #import "ui/events/test/cocoa_test_event_utils.h" 21 #import "ui/events/test/cocoa_test_event_utils.h"
22 #include "ui/gfx/mac/coordinate_conversion.h"
23 #include "ui/gfx/screen.h"
15 24
16 // Implementation details: We use [NSApplication sendEvent:] instead 25 // Implementation details: We use [NSApplication sendEvent:] instead
17 // of [NSApplication postEvent:atStart:] so that the event gets sent 26 // of [NSApplication postEvent:atStart:] so that the event gets sent
18 // immediately. This lets us run the post-event task right 27 // immediately. This lets us run the post-event task right
19 // immediately as well. Unfortunately I cannot subclass NSEvent (it's 28 // immediately as well. Unfortunately I cannot subclass NSEvent (it's
20 // probably a class cluster) to allow other easy answers. For 29 // probably a class cluster) to allow other easy answers. For
21 // example, if I could subclass NSEvent, I could run the Task in it's 30 // example, if I could subclass NSEvent, I could run the Task in it's
22 // dealloc routine (which necessarily happens after the event is 31 // dealloc routine (which necessarily happens after the event is
23 // dispatched). Unlike Linux, Mac does not have message loop 32 // dispatched). Unlike Linux, Mac does not have message loop
24 // observer/notification. Unlike windows, I cannot post non-events 33 // observer/notification. Unlike windows, I cannot post non-events
(...skipping 15 matching lines...) Expand all
40 // events causes BrowserKeyEventsTest.CommandKeyEvents to fail. 49 // events causes BrowserKeyEventsTest.CommandKeyEvents to fail.
41 // See http://crbug.com/49270 50 // See http://crbug.com/49270
42 // 2. On OSX 10.6, [NSEvent addLocalMonitorForEventsMatchingMask:handler:] may 51 // 2. On OSX 10.6, [NSEvent addLocalMonitorForEventsMatchingMask:handler:] may
43 // be used, so that we don't need to poll the event queue time to time. 52 // be used, so that we don't need to poll the event queue time to time.
44 53
45 using cocoa_test_event_utils::SynthesizeKeyEvent; 54 using cocoa_test_event_utils::SynthesizeKeyEvent;
46 using cocoa_test_event_utils::TimeIntervalSinceSystemStartup; 55 using cocoa_test_event_utils::TimeIntervalSinceSystemStartup;
47 56
48 namespace { 57 namespace {
49 58
59 // When enabled, all simulated mouse events will be posted to
60 // the WindowServer, and the actual mouse will move on the screen.
61 bool g_use_cgevents = false;
62
50 // Stores the current mouse location on the screen. So that we can use it 63 // Stores the current mouse location on the screen. So that we can use it
51 // when firing keyboard and mouse click events. 64 // when firing keyboard and mouse click events.
52 NSPoint g_mouse_location = { 0, 0 }; 65 NSPoint g_mouse_location = { 0, 0 };
66 bool g_mouse_button_down[3] = { false, false, false };
53 67
54 bool g_ui_controls_enabled = false; 68 bool g_ui_controls_enabled = false;
55 69
56 // Creates the proper sequence of autoreleased key events for a key down + up. 70 // Creates the proper sequence of autoreleased key events for a key down + up.
57 void SynthesizeKeyEventsSequence(NSWindow* window, 71 void SynthesizeKeyEventsSequence(NSWindow* window,
58 ui::KeyboardCode keycode, 72 ui::KeyboardCode keycode,
59 bool control, 73 bool control,
60 bool shift, 74 bool shift,
61 bool alt, 75 bool alt,
62 bool command, 76 bool command,
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
114 events->push_back(event); 128 events->push_back(event);
115 } 129 }
116 if (control) { 130 if (control) {
117 flags &= ~NSControlKeyMask; 131 flags &= ~NSControlKeyMask;
118 event = SynthesizeKeyEvent(window, false, ui::VKEY_CONTROL, flags); 132 event = SynthesizeKeyEvent(window, false, ui::VKEY_CONTROL, flags);
119 DCHECK(event); 133 DCHECK(event);
120 events->push_back(event); 134 events->push_back(event);
121 } 135 }
122 } 136 }
123 137
138 void RunTaskInTaskRunner(
139 scoped_refptr<base::SingleThreadTaskRunner> task_runner,
140 const base::Closure& task) {
141 task_runner->PostTask(FROM_HERE, task);
142 }
143
124 // A helper function to watch for the event queue. The specific task will be 144 // A helper function to watch for the event queue. The specific task will be
125 // fired when there is no more event in the queue. 145 // fired when there is no more event in the queue.
126 void EventQueueWatcher(const base::Closure& task) { 146 void EventQueueWatcher(const base::Closure& task) {
127 NSEvent* event = [NSApp nextEventMatchingMask:NSAnyEventMask 147 NSEvent* event = [NSApp nextEventMatchingMask:NSAnyEventMask
128 untilDate:nil 148 untilDate:nil
129 inMode:NSDefaultRunLoopMode 149 inMode:NSDefaultRunLoopMode
130 dequeue:NO]; 150 dequeue:NO];
131 // If there is still event in the queue, then we need to check again. 151 // If there is still event in the queue, then we need to check again.
132 if (event) { 152 if (event) {
133 base::MessageLoop::current()->PostTask( 153 base::MessageLoop::current()->PostTask(
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
165 return window; 185 return window;
166 } 186 }
167 187
168 // Note that -[NSApplication orderedWindows] won't include NSPanels. If a test 188 // Note that -[NSApplication orderedWindows] won't include NSPanels. If a test
169 // uses those, it will need to handle that itself. 189 // uses those, it will need to handle that itself.
170 return nil; 190 return nil;
171 } 191 }
172 192
173 } // namespace 193 } // namespace
174 194
195 // Since CGEvents take some time to reach -[NSApplication sendEvent:] we use
196 // this class to wait for the events to start being processed before sending
197 // finish notifications.
198 class EventMonitor {
199 public:
200 void NotifyWhenEventIsProcessed(NSEvent* event, const base::Closure& task) {
201 dispatch_sync(queue_, ^{
202 tasks_.emplace_back(Task(event, task));
203 });
204 }
205
206 void ProcessingEvent(NSEvent* event) {
207 dispatch_sync(queue_, ^{
208 auto it = std::find_if(
209 tasks_.begin(), tasks_.end(),
210 [&event](const Task& task) { return task.MatchesEvent(event); });
211 if (it != tasks_.end()) {
212 it->Run();
213 tasks_.erase(it);
214 }
215 });
216 }
217
218 static EventMonitor* Instance() {
219 static EventMonitor* monitor = nullptr;
220 if (!monitor) {
221 monitor = new EventMonitor();
222 }
223 return monitor;
224 }
225
226 private:
227 class Task {
228 public:
229 Task(NSEvent* event, const base::Closure& task)
230 : task_runner_(base::ThreadTaskRunnerHandle::Get()),
231 event_([event retain]),
232 finish_closure_(task) {}
233
234 bool MatchesEvent(NSEvent* event) const {
235 // When moving the window using BridgedNativeWidget::RunMoveLoop the
236 // locationInWindow can be a little inconsistent with what we expect.
237 return [event_ type] == [event type] /*&&
238 CGPointEqualToPoint([event_ locationInWindow],
239 [event locationInWindow]) */;
240 }
241
242 void Run() {
243 // We get here before the event is actually processed. Run the
244 // EventQueueWatcher on the main thread in order to wait for all events to
245 // finish processing.
246 content::BrowserThread::PostTask(
247 content::BrowserThread::UI, FROM_HERE,
248 base::Bind(
249 &EventQueueWatcher,
250 base::Bind(&RunTaskInTaskRunner, task_runner_, finish_closure_)));
251 }
252
253 private:
254 // Events could be spawned on background threads. Be sure to invoke the
255 // |finish_closure_| on an appropriate thread.
256 scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
257 base::scoped_nsobject<NSEvent> event_;
258 base::Closure finish_closure_;
259 };
260
261 EventMonitor()
262 : queue_(dispatch_queue_create("ui_controls_mac.EventMonitor",
263 DISPATCH_QUEUE_SERIAL)),
264 send_event_swizzler_(
265 new base::mac::ScopedObjCClassSwizzler([NSApplication class],
266 @selector(sendEvent:),
267 @selector(cr_sendEvent:))) {
268 }
269
270 std::vector<Task> tasks_;
271
272 // synchronizes access to the |tasks_| in case we spawn the events on a
273 // different thread
274 dispatch_queue_t queue_ = 0;
275
276 scoped_ptr<base::mac::ScopedObjCClassSwizzler>
277 send_event_swizzler_;
278 };
279
280 // Donates testing implementations of NSApplication methods. We can't simply
281 // use -[NSEvent addLocalMonitorForEventsMatchingMask:handler:], as other event
282 // monitors could have precedence, and they could filter the events before we
283 // can see them. But since nobody swizzles -[NSApplication sendEvent:] we should
284 // be safe.
285 @interface NSApplication(TestingDonor)
286 @end
287
288 @implementation NSApplication(TestingDonor)
289 - (void)cr_sendEvent:(NSEvent*)event {
290 // Invoke the finish handler before the event is processed, since we can get
291 // stuck in BridgedNativeWidget::RunMoveLoop and would never see the event
292 // otherwise.
293 EventMonitor::Instance()->ProcessingEvent(event);
294
295 [self cr_sendEvent:event];
296 }
297 @end
298
299 // Donates testing implementations of NSEvent methods.
300 @interface FakeNSEventTestingDonor : NSObject
301 @end
302
303 @implementation FakeNSEventTestingDonor
304 + (NSPoint)mouseLocation {
305 return g_mouse_location;
306 }
307
308 + (NSUInteger)pressedMouseButtons {
309 NSUInteger result = 0;
310 const int buttons[3] = {
311 ui_controls::LEFT, ui_controls::RIGHT, ui_controls::MIDDLE};
312 for (unsigned int i = 0; i < arraysize(buttons); ++i) {
313 if (g_mouse_button_down[buttons[i]])
314 result |= (1 << i);
315 }
316 return result;
317 }
318 @end
319
320 // Donates testing implementations of NSWindow methods.
321 @interface FakeNSWindowTestingDonor : NSObject
322 @end
323
324 @implementation FakeNSWindowTestingDonor
325 - (NSPoint)mouseLocationOutsideOfEventStream {
326 NSWindow* window = base::mac::ObjCCastStrict<NSWindow>(self);
327 return [window convertScreenToBase:g_mouse_location];
328 }
329 @end
330
331 namespace {
332 class NSEventSwizzler {
333 public:
334 static void Install() {
335 static NSEventSwizzler* swizzler = nullptr;
336 if (!swizzler) {
337 swizzler = new NSEventSwizzler();
338 }
339 }
340
341 protected:
342 NSEventSwizzler()
343 : mouse_location_swizzler_(new base::mac::ScopedObjCClassSwizzler(
344 [NSEvent class],
345 [FakeNSEventTestingDonor class],
346 @selector(mouseLocation))),
347 pressed_mouse_buttons_swizzler_(new base::mac::ScopedObjCClassSwizzler(
348 [NSEvent class],
349 [FakeNSEventTestingDonor class],
350 @selector(pressedMouseButtons))),
351 mouse_location_outside_of_event_stream_swizzler_(
352 new base::mac::ScopedObjCClassSwizzler(
353 [NSWindow class],
354 [FakeNSWindowTestingDonor class],
355 @selector(mouseLocationOutsideOfEventStream))) {}
356
357 private:
358 scoped_ptr<base::mac::ScopedObjCClassSwizzler> mouse_location_swizzler_;
359 scoped_ptr<base::mac::ScopedObjCClassSwizzler>
360 pressed_mouse_buttons_swizzler_;
361 scoped_ptr<base::mac::ScopedObjCClassSwizzler>
362 mouse_location_outside_of_event_stream_swizzler_;
363 };
364 } // namespace
365
175 namespace ui_controls { 366 namespace ui_controls {
176 367
177 void EnableUIControls() { 368 void EnableUIControls() {
178 g_ui_controls_enabled = true; 369 g_ui_controls_enabled = true;
179 } 370 }
180 371
181 bool SendKeyPress(gfx::NativeWindow window, 372 bool SendKeyPress(gfx::NativeWindow window,
182 ui::KeyboardCode key, 373 ui::KeyboardCode key,
183 bool control, 374 bool control,
184 bool shift, 375 bool shift,
(...skipping 10 matching lines...) Expand all
195 bool SendKeyPressNotifyWhenDone(gfx::NativeWindow window, 386 bool SendKeyPressNotifyWhenDone(gfx::NativeWindow window,
196 ui::KeyboardCode key, 387 ui::KeyboardCode key,
197 bool control, 388 bool control,
198 bool shift, 389 bool shift,
199 bool alt, 390 bool alt,
200 bool command, 391 bool command,
201 const base::Closure& task) { 392 const base::Closure& task) {
202 CHECK(g_ui_controls_enabled); 393 CHECK(g_ui_controls_enabled);
203 DCHECK(base::MessageLoopForUI::IsCurrent()); 394 DCHECK(base::MessageLoopForUI::IsCurrent());
204 395
396 // we want to destroy the autoreleased event ASAP
397 base::mac::ScopedNSAutoreleasePool pool;
398
205 std::vector<NSEvent*> events; 399 std::vector<NSEvent*> events;
206 SynthesizeKeyEventsSequence( 400 SynthesizeKeyEventsSequence(
207 window, key, control, shift, alt, command, &events); 401 window, key, control, shift, alt, command, &events);
208 402
209 // TODO(suzhe): Using [NSApplication postEvent:atStart:] here causes 403 // TODO(suzhe): Using [NSApplication postEvent:atStart:] here causes
210 // BrowserKeyEventsTest.CommandKeyEvents to fail. See http://crbug.com/49270 404 // BrowserKeyEventsTest.CommandKeyEvents to fail. See http://crbug.com/49270
211 // But using [NSApplication sendEvent:] should be safe for keyboard events, 405 // But using [NSApplication sendEvent:] should be safe for keyboard events,
212 // because until now, no code wants to retrieve the next event when handling 406 // because until now, no code wants to retrieve the next event when handling
213 // a keyboard event. 407 // a keyboard event.
214 for (std::vector<NSEvent*>::iterator iter = events.begin(); 408 for (std::vector<NSEvent*>::iterator iter = events.begin();
(...skipping 12 matching lines...) Expand all
227 CHECK(g_ui_controls_enabled); 421 CHECK(g_ui_controls_enabled);
228 return SendMouseMoveNotifyWhenDone(x, y, base::Closure()); 422 return SendMouseMoveNotifyWhenDone(x, y, base::Closure());
229 } 423 }
230 424
231 // Input position is in screen coordinates. However, NSMouseMoved 425 // Input position is in screen coordinates. However, NSMouseMoved
232 // events require them window-relative, so we adjust. We *DO* flip 426 // events require them window-relative, so we adjust. We *DO* flip
233 // the coordinate space, so input events can be the same for all 427 // the coordinate space, so input events can be the same for all
234 // platforms. E.g. (0,0) is upper-left. 428 // platforms. E.g. (0,0) is upper-left.
235 bool SendMouseMoveNotifyWhenDone(long x, long y, const base::Closure& task) { 429 bool SendMouseMoveNotifyWhenDone(long x, long y, const base::Closure& task) {
236 CHECK(g_ui_controls_enabled); 430 CHECK(g_ui_controls_enabled);
237 CGFloat screenHeight = 431 g_mouse_location = gfx::ScreenPointToNSPoint(gfx::Point(x, y)); // flip!
238 [[[NSScreen screens] firstObject] frame].size.height; 432 NSEventSwizzler::Install();
239 g_mouse_location = NSMakePoint(x, screenHeight - y); // flip!
240 433
241 NSWindow* window = WindowAtCurrentMouseLocation(); 434 NSWindow* window = WindowAtCurrentMouseLocation();
242 435
243 NSPoint pointInWindow = g_mouse_location; 436 NSPoint pointInWindow = g_mouse_location;
244 if (window) 437 if (window)
245 pointInWindow = [window convertScreenToBase:pointInWindow]; 438 pointInWindow = [window convertScreenToBase:pointInWindow];
246 NSTimeInterval timestamp = TimeIntervalSinceSystemStartup(); 439 NSTimeInterval timestamp = TimeIntervalSinceSystemStartup();
247 440
441 NSEventType etype = NSMouseMoved;
442 if (g_mouse_button_down[LEFT]) {
443 etype = NSLeftMouseDragged;
444 } else if (g_mouse_button_down[RIGHT]) {
445 etype = NSRightMouseDragged;
446 } else if (g_mouse_button_down[MIDDLE]) {
447 etype = NSOtherMouseDragged;
448 }
449
450 // we want to destroy the autoreleased event ASAP
451 base::mac::ScopedNSAutoreleasePool pool;
452
248 NSEvent* event = 453 NSEvent* event =
249 [NSEvent mouseEventWithType:NSMouseMoved 454 [NSEvent mouseEventWithType:etype
250 location:pointInWindow 455 location:pointInWindow
251 modifierFlags:0 456 modifierFlags:0
252 timestamp:timestamp 457 timestamp:timestamp
253 windowNumber:[window windowNumber] 458 windowNumber:[window windowNumber]
254 context:nil 459 context:nil
255 eventNumber:0 460 eventNumber:0
256 clickCount:0 461 clickCount:(etype == NSMouseMoved ? 0 : 1)
257 pressure:0.0]; 462 pressure:(etype == NSMouseMoved ? 0.0 : 1.0)];
258 [[NSApplication sharedApplication] postEvent:event atStart:NO];
259 463
260 if (!task.is_null()) { 464 if (!task.is_null()) {
261 base::MessageLoop::current()->PostTask( 465 EventMonitor::Instance()->NotifyWhenEventIsProcessed(event, task);
262 FROM_HERE, base::Bind(&EventQueueWatcher, task)); 466 }
467
468 gfx::Point gp = gfx::ScreenPointFromNSPoint(g_mouse_location);
469 CGWarpMouseCursorPosition(CGPointMake(gp.x(), gp.y()));
470
471 if (g_use_cgevents) {
472 CGEventPost(kCGSessionEventTap, [event CGEvent]);
473 } else {
474 [[NSApplication sharedApplication] postEvent:event atStart:NO];
263 } 475 }
264 476
265 return true; 477 return true;
266 } 478 }
267 479
268 bool SendMouseEvents(MouseButton type, int state) { 480 bool SendMouseEvents(MouseButton type, int state) {
269 CHECK(g_ui_controls_enabled); 481 CHECK(g_ui_controls_enabled);
270 return SendMouseEventsNotifyWhenDone(type, state, base::Closure()); 482 return SendMouseEventsNotifyWhenDone(type, state, base::Closure());
271 } 483 }
272 484
273 bool SendMouseEventsNotifyWhenDone(MouseButton type, int state, 485 bool SendMouseEventsNotifyWhenDone(MouseButton type, int state,
274 const base::Closure& task) { 486 const base::Closure& task) {
275 CHECK(g_ui_controls_enabled); 487 CHECK(g_ui_controls_enabled);
276 // On windows it appears state can be (UP|DOWN). It is unclear if 488 // On windows it appears state can be (UP|DOWN). It is unclear if
277 // that'll happen here but prepare for it just in case. 489 // that'll happen here but prepare for it just in case.
278 if (state == (UP|DOWN)) { 490 if (state == (UP|DOWN)) {
279 return (SendMouseEventsNotifyWhenDone(type, DOWN, base::Closure()) && 491 return (SendMouseEventsNotifyWhenDone(type, DOWN, base::Closure()) &&
280 SendMouseEventsNotifyWhenDone(type, UP, task)); 492 SendMouseEventsNotifyWhenDone(type, UP, task));
281 } 493 }
282 NSEventType etype = NSLeftMouseDown; 494 NSEventType etype = NSLeftMouseDown;
283 if (type == LEFT) { 495 if (type == LEFT) {
284 if (state == UP) { 496 if (state == UP) {
285 etype = NSLeftMouseUp; 497 etype = NSLeftMouseUp;
498 g_mouse_button_down[LEFT] = false;
286 } else { 499 } else {
287 etype = NSLeftMouseDown; 500 etype = NSLeftMouseDown;
501 g_mouse_button_down[LEFT] = true;
288 } 502 }
289 } else if (type == MIDDLE) { 503 } else if (type == MIDDLE) {
290 if (state == UP) { 504 if (state == UP) {
291 etype = NSOtherMouseUp; 505 etype = NSOtherMouseUp;
506 g_mouse_button_down[MIDDLE] = false;
292 } else { 507 } else {
293 etype = NSOtherMouseDown; 508 etype = NSOtherMouseDown;
509 g_mouse_button_down[MIDDLE] = true;
294 } 510 }
295 } else if (type == RIGHT) { 511 } else if (type == RIGHT) {
296 if (state == UP) { 512 if (state == UP) {
297 etype = NSRightMouseUp; 513 etype = NSRightMouseUp;
514 g_mouse_button_down[RIGHT] = false;
298 } else { 515 } else {
299 etype = NSRightMouseDown; 516 etype = NSRightMouseDown;
517 g_mouse_button_down[RIGHT] = true;
300 } 518 }
301 } else { 519 } else {
302 return false; 520 return false;
303 } 521 }
304 NSWindow* window = WindowAtCurrentMouseLocation(); 522 NSWindow* window = WindowAtCurrentMouseLocation();
305 NSPoint pointInWindow = g_mouse_location; 523 NSPoint pointInWindow = g_mouse_location;
306 if (window) 524 if (window)
307 pointInWindow = [window convertScreenToBase:pointInWindow]; 525 pointInWindow = [window convertScreenToBase:pointInWindow];
308 526
527 NSEventSwizzler::Install();
528
529 // we want to destroy the autoreleased event ASAP
530 base::mac::ScopedNSAutoreleasePool pool;
531
309 NSEvent* event = 532 NSEvent* event =
310 [NSEvent mouseEventWithType:etype 533 [NSEvent mouseEventWithType:etype
311 location:pointInWindow 534 location:pointInWindow
312 modifierFlags:0 535 modifierFlags:0
313 timestamp:TimeIntervalSinceSystemStartup() 536 timestamp:TimeIntervalSinceSystemStartup()
314 windowNumber:[window windowNumber] 537 windowNumber:[window windowNumber]
315 context:nil 538 context:nil
316 eventNumber:0 539 eventNumber:0
317 clickCount:1 540 clickCount:1
318 pressure:(state == DOWN ? 1.0 : 0.0 )]; 541 pressure:(state == DOWN ? 1.0 : 0.0 )];
319 [[NSApplication sharedApplication] postEvent:event atStart:NO];
320 542
321 if (!task.is_null()) { 543 if (!task.is_null()) {
322 base::MessageLoop::current()->PostTask( 544 EventMonitor::Instance()->NotifyWhenEventIsProcessed(event, task);
323 FROM_HERE, base::Bind(&EventQueueWatcher, task)); 545 }
546
547 if (g_use_cgevents) {
548 CGEventPost(kCGSessionEventTap, [event CGEvent]);
549 } else {
550 [[NSApplication sharedApplication] postEvent:event atStart:NO];
324 } 551 }
325 552
326 return true; 553 return true;
327 } 554 }
328 555
329 bool SendMouseClick(MouseButton type) { 556 bool SendMouseClick(MouseButton type) {
330 CHECK(g_ui_controls_enabled); 557 CHECK(g_ui_controls_enabled);
331 return SendMouseEventsNotifyWhenDone(type, UP|DOWN, base::Closure()); 558 return SendMouseEventsNotifyWhenDone(type, UP|DOWN, base::Closure());
332 } 559 }
333 560
334 void RunClosureAfterAllPendingUIEvents(const base::Closure& closure) { 561 void RunClosureAfterAllPendingUIEvents(const base::Closure& closure) {
335 base::MessageLoop::current()->PostTask( 562 base::MessageLoop::current()->PostTask(
336 FROM_HERE, base::Bind(&EventQueueWatcher, closure)); 563 FROM_HERE, base::Bind(&EventQueueWatcher, closure));
337 } 564 }
338 565
339 bool IsFullKeyboardAccessEnabled() { 566 bool IsFullKeyboardAccessEnabled() {
340 return [NSApp isFullKeyboardAccessEnabled]; 567 return [NSApp isFullKeyboardAccessEnabled];
341 } 568 }
342 569
570 void SetSendMouseEventsAsCGEvents(bool enable_cgevents) {
571 g_use_cgevents = enable_cgevents;
572 }
573
574 bool SendMouseEventsAsCGEvents() {
575 return g_use_cgevents;
576 }
577
343 } // namespace ui_controls 578 } // namespace ui_controls
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698