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

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

Powered by Google App Engine
This is Rietveld 408576698