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

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

Powered by Google App Engine
This is Rietveld 408576698