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

Side by Side Diff: chrome/browser/automation/ui_controls_mac.mm

Issue 8212006: base::Bind: Cleanup in automation. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Mac build fixes. Created 9 years, 2 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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 "chrome/browser/automation/ui_controls.h" 5 #include "chrome/browser/automation/ui_controls.h"
6 6
7 #import <Cocoa/Cocoa.h> 7 #import <Cocoa/Cocoa.h>
8 #include <mach/mach_time.h> 8 #include <mach/mach_time.h>
9 #include <vector> 9 #include <vector>
10 10
11 #include "base/callback.h"
11 #include "base/message_loop.h" 12 #include "base/message_loop.h"
12 #include "chrome/browser/automation/ui_controls_internal.h" 13 #include "chrome/browser/automation/ui_controls_internal.h"
13 #include "content/browser/browser_thread.h" 14 #include "content/browser/browser_thread.h"
14 #include "ui/base/keycodes/keyboard_code_conversion_mac.h" 15 #include "ui/base/keycodes/keyboard_code_conversion_mac.h"
15 16
16 // Implementation details: We use [NSApplication sendEvent:] instead 17 // Implementation details: We use [NSApplication sendEvent:] instead
17 // of [NSApplication postEvent:atStart:] so that the event gets sent 18 // of [NSApplication postEvent:atStart:] so that the event gets sent
18 // immediately. This lets us run the post-event task right 19 // immediately. This lets us run the post-event task right
19 // immediately as well. Unfortunately I cannot subclass NSEvent (it's 20 // immediately as well. Unfortunately I cannot subclass NSEvent (it's
20 // probably a class cluster) to allow other easy answers. For 21 // probably a class cluster) to allow other easy answers. For
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after
180 events->push_back(event); 181 events->push_back(event);
181 } 182 }
182 if (control) { 183 if (control) {
183 flags &= ~NSControlKeyMask; 184 flags &= ~NSControlKeyMask;
184 event = SynthesizeKeyEvent(window, false, ui::VKEY_CONTROL, flags); 185 event = SynthesizeKeyEvent(window, false, ui::VKEY_CONTROL, flags);
185 DCHECK(event); 186 DCHECK(event);
186 events->push_back(event); 187 events->push_back(event);
187 } 188 }
188 } 189 }
189 190
190 // A task class to watch for the event queue. The specific task will be fired 191 // A helper function to watch for the event queue. The specific task will be
191 // when there is no more event in the queue. 192 // fired when there is no more event in the queue.
192 class EventQueueWatcher : public Task { 193 void EventQueueWatcher(const base::Closure& task) {
193 public: 194 NSEvent* event = [NSApp nextEventMatchingMask:NSAnyEventMask
194 EventQueueWatcher(Task* task) : task_(task) {} 195 untilDate:nil
195 196 inMode:NSDefaultRunLoopMode
196 virtual ~EventQueueWatcher() {} 197 dequeue:NO];
197 198 // If there is still event in the queue, then we need to check again.
198 virtual void Run() { 199 if (event) {
199 NSEvent* event = [NSApp nextEventMatchingMask:NSAnyEventMask 200 MessageLoop::current()->PostTask(
200 untilDate:nil 201 FROM_HERE,
201 inMode:NSDefaultRunLoopMode 202 base::Bind(&EventQueueWatcher, task));
202 dequeue:NO]; 203 } else {
203 // If there is still event in the queue, then we need to check again. 204 MessageLoop::current()->PostTask(FROM_HERE, task);
204 if (event)
205 MessageLoop::current()->PostTask(FROM_HERE, new EventQueueWatcher(task_));
206 else
207 MessageLoop::current()->PostTask(FROM_HERE, task_);
208 } 205 }
209 206 }
210 private:
211 Task* task_;
212 };
213 207
214 // Stores the current mouse location on the screen. So that we can use it 208 // Stores the current mouse location on the screen. So that we can use it
215 // when firing keyboard and mouse click events. 209 // when firing keyboard and mouse click events.
216 NSPoint g_mouse_location = { 0, 0 }; 210 NSPoint g_mouse_location = { 0, 0 };
217 211
218 } // anonymous namespace 212 } // anonymous namespace
219 213
220
221 namespace ui_controls { 214 namespace ui_controls {
222 215
223 bool SendKeyPress(gfx::NativeWindow window, 216 bool SendKeyPress(gfx::NativeWindow window,
224 ui::KeyboardCode key, 217 ui::KeyboardCode key,
225 bool control, 218 bool control,
226 bool shift, 219 bool shift,
227 bool alt, 220 bool alt,
228 bool command) { 221 bool command) {
229 return SendKeyPressNotifyWhenDone(window, key, 222 return SendKeyPressNotifyWhenDone(window, key,
230 control, shift, alt, command, 223 control, shift, alt, command,
231 NULL); 224 MessageLoop::QuitClosure());
awong 2011/10/12 08:20:03 Are we sure we want to change this to QuitClosure(
James Hawkins 2011/10/12 17:12:39 Oops. Done.
232 } 225 }
233 226
234 // Win and Linux implement a SendKeyPress() this as a 227 // Win and Linux implement a SendKeyPress() this as a
235 // SendKeyPressAndRelease(), so we should as well (despite the name). 228 // SendKeyPressAndRelease(), so we should as well (despite the name).
236 bool SendKeyPressNotifyWhenDone(gfx::NativeWindow window, 229 bool SendKeyPressNotifyWhenDone(gfx::NativeWindow window,
237 ui::KeyboardCode key, 230 ui::KeyboardCode key,
238 bool control, 231 bool control,
239 bool shift, 232 bool shift,
240 bool alt, 233 bool alt,
241 bool command, 234 bool command,
242 Task* task) { 235 const base::Closure& task) {
243 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 236 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
244 237
245 std::vector<NSEvent*> events; 238 std::vector<NSEvent*> events;
246 SynthesizeKeyEventsSequence( 239 SynthesizeKeyEventsSequence(
247 window, key, control, shift, alt, command, &events); 240 window, key, control, shift, alt, command, &events);
248 241
249 // TODO(suzhe): Using [NSApplication postEvent:atStart:] here causes 242 // TODO(suzhe): Using [NSApplication postEvent:atStart:] here causes
250 // BrowserKeyEventsTest.CommandKeyEvents to fail. See http://crbug.com/49270 243 // BrowserKeyEventsTest.CommandKeyEvents to fail. See http://crbug.com/49270
251 // But using [NSApplication sendEvent:] should be safe for keyboard events, 244 // But using [NSApplication sendEvent:] should be safe for keyboard events,
252 // because until now, no code wants to retrieve the next event when handling 245 // because until now, no code wants to retrieve the next event when handling
253 // a keyboard event. 246 // a keyboard event.
254 for (std::vector<NSEvent*>::iterator iter = events.begin(); 247 for (std::vector<NSEvent*>::iterator iter = events.begin();
255 iter != events.end(); ++iter) 248 iter != events.end(); ++iter)
256 [[NSApplication sharedApplication] sendEvent:*iter]; 249 [[NSApplication sharedApplication] sendEvent:*iter];
257 250
258 if (task) 251 if (!task.is_null()) {
259 MessageLoop::current()->PostTask(FROM_HERE, new EventQueueWatcher(task)); 252 MessageLoop::current()->PostTask(
253 FROM_HERE, base::Bind(&EventQueueWatcher, task));
254 }
260 255
261 return true; 256 return true;
262 } 257 }
263 258
264 bool SendMouseMove(long x, long y) { 259 bool SendMouseMove(long x, long y) {
265 return SendMouseMoveNotifyWhenDone(x, y, NULL); 260 return SendMouseMoveNotifyWhenDone(x, y, base::Closure());
266 } 261 }
267 262
268 // Input position is in screen coordinates. However, NSMouseMoved 263 // Input position is in screen coordinates. However, NSMouseMoved
269 // events require them window-relative, so we adjust. We *DO* flip 264 // events require them window-relative, so we adjust. We *DO* flip
270 // the coordinate space, so input events can be the same for all 265 // the coordinate space, so input events can be the same for all
271 // platforms. E.g. (0,0) is upper-left. 266 // platforms. E.g. (0,0) is upper-left.
272 bool SendMouseMoveNotifyWhenDone(long x, long y, Task* task) { 267 bool SendMouseMoveNotifyWhenDone(long x, long y, const base::Closure& task) {
273 NSWindow* window = [[NSApplication sharedApplication] keyWindow]; 268 NSWindow* window = [[NSApplication sharedApplication] keyWindow];
274 CGFloat screenHeight = 269 CGFloat screenHeight =
275 [[[NSScreen screens] objectAtIndex:0] frame].size.height; 270 [[[NSScreen screens] objectAtIndex:0] frame].size.height;
276 g_mouse_location = NSMakePoint(x, screenHeight - y); // flip! 271 g_mouse_location = NSMakePoint(x, screenHeight - y); // flip!
277 NSPoint pointInWindow = g_mouse_location; 272 NSPoint pointInWindow = g_mouse_location;
278 if (window) 273 if (window)
279 pointInWindow = [window convertScreenToBase:pointInWindow]; 274 pointInWindow = [window convertScreenToBase:pointInWindow];
280 NSTimeInterval timestamp = TimeIntervalSinceSystemStartup(); 275 NSTimeInterval timestamp = TimeIntervalSinceSystemStartup();
281 276
282 NSEvent* event = 277 NSEvent* event =
283 [NSEvent mouseEventWithType:NSMouseMoved 278 [NSEvent mouseEventWithType:NSMouseMoved
284 location:pointInWindow 279 location:pointInWindow
285 modifierFlags:0 280 modifierFlags:0
286 timestamp:timestamp 281 timestamp:timestamp
287 windowNumber:[window windowNumber] 282 windowNumber:[window windowNumber]
288 context:nil 283 context:nil
289 eventNumber:0 284 eventNumber:0
290 clickCount:0 285 clickCount:0
291 pressure:0.0]; 286 pressure:0.0];
292 [[NSApplication sharedApplication] postEvent:event atStart:NO]; 287 [[NSApplication sharedApplication] postEvent:event atStart:NO];
293 288
294 if (task) 289 if (!task.is_null()) {
295 MessageLoop::current()->PostTask(FROM_HERE, new EventQueueWatcher(task)); 290 MessageLoop::current()->PostTask(
291 FROM_HERE, base::Bind(&EventQueueWatcher, task));
292 }
296 293
297 return true; 294 return true;
298 } 295 }
299 296
300 bool SendMouseEvents(MouseButton type, int state) { 297 bool SendMouseEvents(MouseButton type, int state) {
301 return SendMouseEventsNotifyWhenDone(type, state, NULL); 298 return SendMouseEventsNotifyWhenDone(type, state, base::Closure());
302 } 299 }
303 300
304 bool SendMouseEventsNotifyWhenDone(MouseButton type, int state, Task* task) { 301 bool SendMouseEventsNotifyWhenDone(MouseButton type, int state,
302 const base::Closure& task) {
305 // On windows it appears state can be (UP|DOWN). It is unclear if 303 // On windows it appears state can be (UP|DOWN). It is unclear if
306 // that'll happen here but prepare for it just in case. 304 // that'll happen here but prepare for it just in case.
307 if (state == (UP|DOWN)) { 305 if (state == (UP|DOWN)) {
308 return (SendMouseEventsNotifyWhenDone(type, DOWN, NULL) && 306 return (SendMouseEventsNotifyWhenDone(type, DOWN, NULL) &&
csilv 2011/10/11 22:20:52 NULL -> base::Closure()
James Hawkins 2011/10/12 17:12:39 Done.
309 SendMouseEventsNotifyWhenDone(type, UP, task)); 307 SendMouseEventsNotifyWhenDone(type, UP, task));
310 } 308 }
311 NSEventType etype = 0; 309 NSEventType etype = 0;
312 if (type == LEFT) { 310 if (type == LEFT) {
313 if (state == UP) { 311 if (state == UP) {
314 etype = NSLeftMouseUp; 312 etype = NSLeftMouseUp;
315 } else { 313 } else {
316 etype = NSLeftMouseDown; 314 etype = NSLeftMouseDown;
317 } 315 }
318 } else if (type == MIDDLE) { 316 } else if (type == MIDDLE) {
(...skipping 21 matching lines...) Expand all
340 location:pointInWindow 338 location:pointInWindow
341 modifierFlags:0 339 modifierFlags:0
342 timestamp:TimeIntervalSinceSystemStartup() 340 timestamp:TimeIntervalSinceSystemStartup()
343 windowNumber:[window windowNumber] 341 windowNumber:[window windowNumber]
344 context:nil 342 context:nil
345 eventNumber:0 343 eventNumber:0
346 clickCount:1 344 clickCount:1
347 pressure:(state == DOWN ? 1.0 : 0.0 )]; 345 pressure:(state == DOWN ? 1.0 : 0.0 )];
348 [[NSApplication sharedApplication] postEvent:event atStart:NO]; 346 [[NSApplication sharedApplication] postEvent:event atStart:NO];
349 347
350 if (task) 348 if (!task.is_null()) {
351 MessageLoop::current()->PostTask(FROM_HERE, new EventQueueWatcher(task)); 349 MessageLoop::current()->PostTask(
350 FROM_HERE, base::Bind(&EventQueueWatcher, task));
351 }
352 352
353 return true; 353 return true;
354 } 354 }
355 355
356 bool SendMouseClick(MouseButton type) { 356 bool SendMouseClick(MouseButton type) {
357 return SendMouseEventsNotifyWhenDone(type, UP|DOWN, NULL); 357 return SendMouseEventsNotifyWhenDone(type, UP|DOWN, base::Closure());
358 } 358 }
359 359
360 void MoveMouseToCenterAndPress( 360 void MoveMouseToCenterAndPress(
361 NSView* view, 361 NSView* view,
362 MouseButton button, 362 MouseButton button,
363 int state, 363 int state,
364 Task* task) { 364 const base::Closure& task) {
365 DCHECK(view); 365 DCHECK(view);
366 NSWindow* window = [view window]; 366 NSWindow* window = [view window];
367 DCHECK(window); 367 DCHECK(window);
368 NSScreen* screen = [window screen]; 368 NSScreen* screen = [window screen];
369 DCHECK(screen); 369 DCHECK(screen);
370 370
371 // Converts the center position of the view into the coordinates accepted 371 // Converts the center position of the view into the coordinates accepted
372 // by SendMouseMoveNotifyWhenDone() method. 372 // by SendMouseMoveNotifyWhenDone() method.
373 NSRect bounds = [view bounds]; 373 NSRect bounds = [view bounds];
374 NSPoint center = NSMakePoint(NSMidX(bounds), NSMidY(bounds)); 374 NSPoint center = NSMakePoint(NSMidX(bounds), NSMidY(bounds));
375 center = [view convertPoint:center toView:nil]; 375 center = [view convertPoint:center toView:nil];
376 center = [window convertBaseToScreen:center]; 376 center = [window convertBaseToScreen:center];
377 center = NSMakePoint(center.x, [screen frame].size.height - center.y); 377 center = NSMakePoint(center.x, [screen frame].size.height - center.y);
378 378
379 SendMouseMoveNotifyWhenDone(center.x, center.y, 379 SendMouseMoveNotifyWhenDone(
380 new ClickTask(button, state, task)); 380 center.x, center.y,
381 base::Bind(&ui_controls::ClickTask, button, state, task));
381 } 382 }
382 383
383 } // ui_controls 384 } // ui_controls
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698