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