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