Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/ui_controls/ui_controls.h" | 5 #include "ui/ui_controls/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 |
| (...skipping 195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 206 } | 206 } |
| 207 | 207 |
| 208 // 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 |
| 209 // when firing keyboard and mouse click events. | 209 // when firing keyboard and mouse click events. |
| 210 NSPoint g_mouse_location = { 0, 0 }; | 210 NSPoint g_mouse_location = { 0, 0 }; |
| 211 | 211 |
| 212 } // namespace | 212 } // namespace |
| 213 | 213 |
| 214 namespace ui_controls { | 214 namespace ui_controls { |
| 215 | 215 |
| 216 bool SendKeyPress(gfx::NativeWindow window, | 216 namespace { |
| 217 ui::KeyboardCode key, | |
| 218 bool control, | |
| 219 bool shift, | |
| 220 bool alt, | |
| 221 bool command) { | |
| 222 return SendKeyPressNotifyWhenDone(window, key, | |
| 223 control, shift, alt, command, | |
| 224 base::Closure()); | |
| 225 } | |
| 226 | 217 |
| 227 // Win and Linux implement a SendKeyPress() this as a | 218 class UIControlsMac : public UIControls { |
| 228 // SendKeyPressAndRelease(), so we should as well (despite the name). | |
| 229 bool SendKeyPressNotifyWhenDone(gfx::NativeWindow window, | |
| 230 ui::KeyboardCode key, | |
| 231 bool control, | |
| 232 bool shift, | |
| 233 bool alt, | |
| 234 bool command, | |
| 235 const base::Closure& task) { | |
| 236 DCHECK_EQ(MessageLoop::TYPE_UI, MessageLoop::current()->type()); | |
| 237 | 219 |
| 238 std::vector<NSEvent*> events; | 220 bool SendKeyPress(gfx::NativeWindow window, |
| 239 SynthesizeKeyEventsSequence( | 221 ui::KeyboardCode key, |
| 240 window, key, control, shift, alt, command, &events); | 222 bool control, |
| 241 | 223 bool shift, |
| 242 // TODO(suzhe): Using [NSApplication postEvent:atStart:] here causes | 224 bool alt, |
| 243 // BrowserKeyEventsTest.CommandKeyEvents to fail. See http://crbug.com/49270 | 225 bool command) OVERRIDE { |
| 244 // But using [NSApplication sendEvent:] should be safe for keyboard events, | 226 return SendKeyPressNotifyWhenDone(window, key, |
| 245 // because until now, no code wants to retrieve the next event when handling | 227 control, shift, alt, command, |
| 246 // a keyboard event. | 228 base::Closure()); |
| 247 for (std::vector<NSEvent*>::iterator iter = events.begin(); | |
| 248 iter != events.end(); ++iter) | |
| 249 [[NSApplication sharedApplication] sendEvent:*iter]; | |
| 250 | |
| 251 if (!task.is_null()) { | |
| 252 MessageLoop::current()->PostTask( | |
| 253 FROM_HERE, base::Bind(&EventQueueWatcher, task)); | |
| 254 } | 229 } |
| 255 | 230 |
| 256 return true; | 231 // Win and Linux implement a SendKeyPress() this as a |
| 257 } | 232 // SendKeyPressAndRelease(), so we should as well (despite the name). |
| 233 bool SendKeyPressNotifyWhenDone(gfx::NativeWindow window, | |
| 234 ui::KeyboardCode key, | |
| 235 bool control, | |
| 236 bool shift, | |
| 237 bool alt, | |
| 238 bool command, | |
| 239 const base::Closure& task) OVERRIDE { | |
| 240 DCHECK_EQ(MessageLoop::TYPE_UI, MessageLoop::current()->type()); | |
| 258 | 241 |
| 259 bool SendMouseMove(long x, long y) { | 242 std::vector<NSEvent*> events; |
| 260 return SendMouseMoveNotifyWhenDone(x, y, base::Closure()); | 243 SynthesizeKeyEventsSequence( |
| 261 } | 244 window, key, control, shift, alt, command, &events); |
| 262 | 245 |
| 263 // Input position is in screen coordinates. However, NSMouseMoved | 246 // TODO(suzhe): Using [NSApplication postEvent:atStart:] here causes |
| 264 // events require them window-relative, so we adjust. We *DO* flip | 247 // BrowserKeyEventsTest.CommandKeyEvents to fail. See http://crbug.com/49270 |
| 265 // the coordinate space, so input events can be the same for all | 248 // But using [NSApplication sendEvent:] should be safe for keyboard events, |
| 266 // platforms. E.g. (0,0) is upper-left. | 249 // because until now, no code wants to retrieve the next event when handling |
| 267 bool SendMouseMoveNotifyWhenDone(long x, long y, const base::Closure& task) { | 250 // a keyboard event. |
| 268 NSWindow* window = [[NSApplication sharedApplication] keyWindow]; | 251 for (std::vector<NSEvent*>::iterator iter = events.begin(); |
| 269 CGFloat screenHeight = | 252 iter != events.end(); ++iter) |
| 270 [[[NSScreen screens] objectAtIndex:0] frame].size.height; | 253 [[NSApplication sharedApplication] sendEvent:*iter]; |
| 271 g_mouse_location = NSMakePoint(x, screenHeight - y); // flip! | |
| 272 NSPoint pointInWindow = g_mouse_location; | |
| 273 if (window) | |
| 274 pointInWindow = [window convertScreenToBase:pointInWindow]; | |
| 275 NSTimeInterval timestamp = TimeIntervalSinceSystemStartup(); | |
| 276 | 254 |
| 277 NSEvent* event = | 255 if (!task.is_null()) { |
| 278 [NSEvent mouseEventWithType:NSMouseMoved | 256 MessageLoop::current()->PostTask( |
| 279 location:pointInWindow | 257 FROM_HERE, base::Bind(&EventQueueWatcher, task)); |
| 280 modifierFlags:0 | 258 } |
| 281 timestamp:timestamp | |
| 282 windowNumber:[window windowNumber] | |
| 283 context:nil | |
| 284 eventNumber:0 | |
| 285 clickCount:0 | |
| 286 pressure:0.0]; | |
| 287 [[NSApplication sharedApplication] postEvent:event atStart:NO]; | |
| 288 | 259 |
| 289 if (!task.is_null()) { | 260 return true; |
| 290 MessageLoop::current()->PostTask( | |
| 291 FROM_HERE, base::Bind(&EventQueueWatcher, task)); | |
| 292 } | 261 } |
| 293 | 262 |
| 294 return true; | 263 bool SendMouseMove(long x, long y) OVERRIDE { |
| 295 } | 264 return SendMouseMoveNotifyWhenDone(x, y, base::Closure()); |
| 296 | |
| 297 bool SendMouseEvents(MouseButton type, int state) { | |
| 298 return SendMouseEventsNotifyWhenDone(type, state, base::Closure()); | |
| 299 } | |
| 300 | |
| 301 bool SendMouseEventsNotifyWhenDone(MouseButton type, int state, | |
| 302 const base::Closure& task) { | |
| 303 // On windows it appears state can be (UP|DOWN). It is unclear if | |
| 304 // that'll happen here but prepare for it just in case. | |
| 305 if (state == (UP|DOWN)) { | |
| 306 return (SendMouseEventsNotifyWhenDone(type, DOWN, base::Closure()) && | |
| 307 SendMouseEventsNotifyWhenDone(type, UP, task)); | |
| 308 } | |
| 309 NSEventType etype = 0; | |
| 310 if (type == LEFT) { | |
| 311 if (state == UP) { | |
| 312 etype = NSLeftMouseUp; | |
| 313 } else { | |
| 314 etype = NSLeftMouseDown; | |
| 315 } | |
| 316 } else if (type == MIDDLE) { | |
| 317 if (state == UP) { | |
| 318 etype = NSOtherMouseUp; | |
| 319 } else { | |
| 320 etype = NSOtherMouseDown; | |
| 321 } | |
| 322 } else if (type == RIGHT) { | |
| 323 if (state == UP) { | |
| 324 etype = NSRightMouseUp; | |
| 325 } else { | |
| 326 etype = NSRightMouseDown; | |
| 327 } | |
| 328 } else { | |
| 329 return false; | |
| 330 } | |
| 331 NSWindow* window = [[NSApplication sharedApplication] keyWindow]; | |
| 332 NSPoint pointInWindow = g_mouse_location; | |
| 333 if (window) | |
| 334 pointInWindow = [window convertScreenToBase:pointInWindow]; | |
| 335 | |
| 336 NSEvent* event = | |
| 337 [NSEvent mouseEventWithType:etype | |
| 338 location:pointInWindow | |
| 339 modifierFlags:0 | |
| 340 timestamp:TimeIntervalSinceSystemStartup() | |
| 341 windowNumber:[window windowNumber] | |
| 342 context:nil | |
| 343 eventNumber:0 | |
| 344 clickCount:1 | |
| 345 pressure:(state == DOWN ? 1.0 : 0.0 )]; | |
| 346 [[NSApplication sharedApplication] postEvent:event atStart:NO]; | |
| 347 | |
| 348 if (!task.is_null()) { | |
| 349 MessageLoop::current()->PostTask( | |
| 350 FROM_HERE, base::Bind(&EventQueueWatcher, task)); | |
| 351 } | 265 } |
| 352 | 266 |
| 353 return true; | 267 // Input position is in screen coordinates. However, NSMouseMoved |
| 354 } | 268 // events require them window-relative, so we adjust. We *DO* flip |
| 269 // the coordinate space, so input events can be the same for all | |
| 270 // platforms. E.g. (0,0) is upper-left. | |
| 271 bool SendMouseMoveNotifyWhenDone( | |
| 272 long x, long y, const base::Closure& task) OVERRIDE { | |
| 273 NSWindow* window = [[NSApplication sharedApplication] keyWindow]; | |
| 274 CGFloat screenHeight = | |
| 275 [[[NSScreen screens] objectAtIndex:0] frame].size.height; | |
| 276 g_mouse_location = NSMakePoint(x, screenHeight - y); // flip! | |
| 277 NSPoint pointInWindow = g_mouse_location; | |
| 278 if (window) | |
| 279 pointInWindow = [window convertScreenToBase:pointInWindow]; | |
| 280 NSTimeInterval timestamp = TimeIntervalSinceSystemStartup(); | |
| 355 | 281 |
| 356 bool SendMouseClick(MouseButton type) { | 282 NSEvent* event = |
| 357 return SendMouseEventsNotifyWhenDone(type, UP|DOWN, base::Closure()); | 283 [NSEvent mouseEventWithType:NSMouseMoved |
| 284 location:pointInWindow | |
| 285 modifierFlags:0 | |
| 286 timestamp:timestamp | |
| 287 windowNumber:[window windowNumber] | |
| 288 context:nil | |
| 289 eventNumber:0 | |
| 290 clickCount:0 | |
| 291 pressure:0.0]; | |
| 292 [[NSApplication sharedApplication] postEvent:event atStart:NO]; | |
| 293 | |
| 294 if (!task.is_null()) { | |
| 295 MessageLoop::current()->PostTask( | |
| 296 FROM_HERE, base::Bind(&EventQueueWatcher, task)); | |
| 297 } | |
| 298 | |
| 299 return true; | |
| 300 } | |
| 301 | |
| 302 bool SendMouseEvents(MouseButton type, int state) OVERRIDE { | |
| 303 return SendMouseEventsNotifyWhenDone(type, state, base::Closure()); | |
| 304 } | |
| 305 | |
| 306 bool SendMouseEventsNotifyWhenDone(MouseButton type, int state, | |
| 307 const base::Closure& task) OVERRIDE { | |
| 308 // On windows it appears state can be (UP|DOWN). It is unclear if | |
| 309 // that'll happen here but prepare for it just in case. | |
| 310 if (state == (UP|DOWN)) { | |
| 311 return (SendMouseEventsNotifyWhenDone(type, DOWN, base::Closure()) && | |
| 312 SendMouseEventsNotifyWhenDone(type, UP, task)); | |
| 313 } | |
| 314 NSEventType etype = 0; | |
| 315 if (type == LEFT) { | |
| 316 if (state == UP) { | |
| 317 etype = NSLeftMouseUp; | |
| 318 } else { | |
| 319 etype = NSLeftMouseDown; | |
| 320 } | |
| 321 } else if (type == MIDDLE) { | |
| 322 if (state == UP) { | |
| 323 etype = NSOtherMouseUp; | |
| 324 } else { | |
| 325 etype = NSOtherMouseDown; | |
| 326 } | |
| 327 } else if (type == RIGHT) { | |
| 328 if (state == UP) { | |
| 329 etype = NSRightMouseUp; | |
| 330 } else { | |
| 331 etype = NSRightMouseDown; | |
| 332 } | |
| 333 } else { | |
| 334 return false; | |
| 335 } | |
| 336 NSWindow* window = [[NSApplication sharedApplication] keyWindow]; | |
| 337 NSPoint pointInWindow = g_mouse_location; | |
| 338 if (window) | |
| 339 pointInWindow = [window convertScreenToBase:pointInWindow]; | |
| 340 | |
| 341 NSEvent* event = | |
| 342 [NSEvent mouseEventWithType:etype | |
| 343 location:pointInWindow | |
| 344 modifierFlags:0 | |
| 345 timestamp:TimeIntervalSinceSystemStartup() | |
| 346 windowNumber:[window windowNumber] | |
| 347 context:nil | |
| 348 eventNumber:0 | |
| 349 clickCount:1 | |
| 350 pressure:(state == DOWN ? 1.0 : 0.0 )]; | |
| 351 [[NSApplication sharedApplication] postEvent:event atStart:NO]; | |
| 352 | |
| 353 if (!task.is_null()) { | |
| 354 MessageLoop::current()->PostTask( | |
| 355 FROM_HERE, base::Bind(&EventQueueWatcher, task)); | |
| 356 } | |
| 357 | |
| 358 return true; | |
| 359 } | |
| 360 | |
| 361 bool SendMouseClick(MouseButton type) OVERRIDE { | |
| 362 return SendMouseEventsNotifyWhenDone(type, UP|DOWN, base::Closure()); | |
| 363 } | |
|
oshima
2012/11/15 23:37:41
ditto
scottmg
2012/11/16 17:58:54
Done.
| |
| 364 }; | |
| 365 | |
| 366 } // namespace | |
| 367 | |
| 368 UIControls* CreateNativeUIControls() { | |
| 369 return new UIControlsMac; | |
| 358 } | 370 } |
| 359 | 371 |
| 360 } // namespace ui_controls | 372 } // namespace ui_controls |
| OLD | NEW |