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

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

Powered by Google App Engine
This is Rietveld 408576698