1 /* 2 * Copyright (C) 2004, 2006, 2007 Apple Inc. All rights reserved. 3 * Copyright (C) 2006-2009 Google Inc. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #include "config.h" 28 #include "WebInputEventFactory.h" 29 30 #include <ApplicationServices/ApplicationServices.h> 31 #import <AvailabilityMacros.h> 32 #import <Cocoa/Cocoa.h> 33 34 #include "WebInputEvent.h" 35 #include "platform/WindowsKeyboardCodes.h" 36 #include "wtf/ASCIICType.h" 37 38 #if __MAC_OS_X_VERSION_MAX_ALLOWED == 1060 39 40 // Additional Lion APIs. 41 enum { 42 NSEventPhaseNone = 0, 43 NSEventPhaseBegan = 0x1 << 0, 44 NSEventPhaseStationary = 0x1 << 1, 45 NSEventPhaseChanged = 0x1 << 2, 46 NSEventPhaseEnded = 0x1 << 3, 47 NSEventPhaseCancelled = 0x1 << 4 48 }; 49 typedef NSUInteger NSEventPhase; 50 51 @interface NSEvent (LionSDKDeclarations) 52 - (NSEventPhase)phase; 53 - (NSEventPhase)momentumPhase; 54 @end 55 56 #endif // __MAC_OS_X_VERSION_MAX_ALLOWED == 1060 57 58 #if __MAC_OS_X_VERSION_MAX_ALLOWED < 1080 59 60 // Additional Mountain Lion APIs. 61 enum { 62 NSEventPhaseMayBegin = 0x1 << 5 63 }; 64 65 #endif // __MAC_OS_X_VERSION_MAX_ALLOWED < 1080 66 67 namespace blink { 68 69 static int windowsKeyCodeForKeyCode(uint16_t keyCode) 70 { 71 static const int windowsKeyCode[] = { 72 /* 0 */ VK_A, 73 /* 1 */ VK_S, 74 /* 2 */ VK_D, 75 /* 3 */ VK_F, 76 /* 4 */ VK_H, 77 /* 5 */ VK_G, 78 /* 6 */ VK_Z, 79 /* 7 */ VK_X, 80 /* 8 */ VK_C, 81 /* 9 */ VK_V, 82 /* 0x0A */ VK_OEM_3, // "Section" - key to the left from 1 (ISO Keyboard Only) 83 /* 0x0B */ VK_B, 84 /* 0x0C */ VK_Q, 85 /* 0x0D */ VK_W, 86 /* 0x0E */ VK_E, 87 /* 0x0F */ VK_R, 88 /* 0x10 */ VK_Y, 89 /* 0x11 */ VK_T, 90 /* 0x12 */ VK_1, 91 /* 0x13 */ VK_2, 92 /* 0x14 */ VK_3, 93 /* 0x15 */ VK_4, 94 /* 0x16 */ VK_6, 95 /* 0x17 */ VK_5, 96 /* 0x18 */ VK_OEM_PLUS, // =+ 97 /* 0x19 */ VK_9, 98 /* 0x1A */ VK_7, 99 /* 0x1B */ VK_OEM_MINUS, // -_ 100 /* 0x1C */ VK_8, 101 /* 0x1D */ VK_0, 102 /* 0x1E */ VK_OEM_6, // ]} 103 /* 0x1F */ VK_O, 104 /* 0x20 */ VK_U, 105 /* 0x21 */ VK_OEM_4, // {[ 106 /* 0x22 */ VK_I, 107 /* 0x23 */ VK_P, 108 /* 0x24 */ VK_RETURN, // Return 109 /* 0x25 */ VK_L, 110 /* 0x26 */ VK_J, 111 /* 0x27 */ VK_OEM_7, // '" 112 /* 0x28 */ VK_K, 113 /* 0x29 */ VK_OEM_1, // ;: 114 /* 0x2A */ VK_OEM_5, // \| 115 /* 0x2B */ VK_OEM_COMMA, // ,< 116 /* 0x2C */ VK_OEM_2, // /? 117 /* 0x2D */ VK_N, 118 /* 0x2E */ VK_M, 119 /* 0x2F */ VK_OEM_PERIOD, // .> 120 /* 0x30 */ VK_TAB, 121 /* 0x31 */ VK_SPACE, 122 /* 0x32 */ VK_OEM_3, // `~ 123 /* 0x33 */ VK_BACK, // Backspace 124 /* 0x34 */ 0, // n/a 125 /* 0x35 */ VK_ESCAPE, 126 /* 0x36 */ VK_APPS, // Right Command 127 /* 0x37 */ VK_LWIN, // Left Command 128 /* 0x38 */ VK_LSHIFT, // Left Shift 129 /* 0x39 */ VK_CAPITAL, // Caps Lock 130 /* 0x3A */ VK_LMENU, // Left Option 131 /* 0x3B */ VK_LCONTROL, // Left Ctrl 132 /* 0x3C */ VK_RSHIFT, // Right Shift 133 /* 0x3D */ VK_RMENU, // Right Option 134 /* 0x3E */ VK_RCONTROL, // Right Ctrl 135 /* 0x3F */ 0, // fn 136 /* 0x40 */ VK_F17, 137 /* 0x41 */ VK_DECIMAL, // Num Pad . 138 /* 0x42 */ 0, // n/a 139 /* 0x43 */ VK_MULTIPLY, // Num Pad * 140 /* 0x44 */ 0, // n/a 141 /* 0x45 */ VK_ADD, // Num Pad + 142 /* 0x46 */ 0, // n/a 143 /* 0x47 */ VK_CLEAR, // Num Pad Clear 144 /* 0x48 */ VK_VOLUME_UP, 145 /* 0x49 */ VK_VOLUME_DOWN, 146 /* 0x4A */ VK_VOLUME_MUTE, 147 /* 0x4B */ VK_DIVIDE, // Num Pad / 148 /* 0x4C */ VK_RETURN, // Num Pad Enter 149 /* 0x4D */ 0, // n/a 150 /* 0x4E */ VK_SUBTRACT, // Num Pad - 151 /* 0x4F */ VK_F18, 152 /* 0x50 */ VK_F19, 153 /* 0x51 */ VK_OEM_PLUS, // Num Pad =. There is no such key on common PC keyboards, mapping to normal "+=". 154 /* 0x52 */ VK_NUMPAD0, 155 /* 0x53 */ VK_NUMPAD1, 156 /* 0x54 */ VK_NUMPAD2, 157 /* 0x55 */ VK_NUMPAD3, 158 /* 0x56 */ VK_NUMPAD4, 159 /* 0x57 */ VK_NUMPAD5, 160 /* 0x58 */ VK_NUMPAD6, 161 /* 0x59 */ VK_NUMPAD7, 162 /* 0x5A */ VK_F20, 163 /* 0x5B */ VK_NUMPAD8, 164 /* 0x5C */ VK_NUMPAD9, 165 /* 0x5D */ 0, // Yen (JIS Keyboard Only) 166 /* 0x5E */ 0, // Underscore (JIS Keyboard Only) 167 /* 0x5F */ 0, // KeypadComma (JIS Keyboard Only) 168 /* 0x60 */ VK_F5, 169 /* 0x61 */ VK_F6, 170 /* 0x62 */ VK_F7, 171 /* 0x63 */ VK_F3, 172 /* 0x64 */ VK_F8, 173 /* 0x65 */ VK_F9, 174 /* 0x66 */ 0, // Eisu (JIS Keyboard Only) 175 /* 0x67 */ VK_F11, 176 /* 0x68 */ 0, // Kana (JIS Keyboard Only) 177 /* 0x69 */ VK_F13, 178 /* 0x6A */ VK_F16, 179 /* 0x6B */ VK_F14, 180 /* 0x6C */ 0, // n/a 181 /* 0x6D */ VK_F10, 182 /* 0x6E */ 0, // n/a (Windows95 key?) 183 /* 0x6F */ VK_F12, 184 /* 0x70 */ 0, // n/a 185 /* 0x71 */ VK_F15, 186 /* 0x72 */ VK_INSERT, // Help 187 /* 0x73 */ VK_HOME, // Home 188 /* 0x74 */ VK_PRIOR, // Page Up 189 /* 0x75 */ VK_DELETE, // Forward Delete 190 /* 0x76 */ VK_F4, 191 /* 0x77 */ VK_END, // End 192 /* 0x78 */ VK_F2, 193 /* 0x79 */ VK_NEXT, // Page Down 194 /* 0x7A */ VK_F1, 195 /* 0x7B */ VK_LEFT, // Left Arrow 196 /* 0x7C */ VK_RIGHT, // Right Arrow 197 /* 0x7D */ VK_DOWN, // Down Arrow 198 /* 0x7E */ VK_UP, // Up Arrow 199 /* 0x7F */ 0 // n/a 200 }; 201 202 if (keyCode >= 0x80) 203 return 0; 204 205 return windowsKeyCode[keyCode]; 206 } 207 208 static int windowsKeyCodeForCharCode(unichar charCode) 209 { 210 switch (charCode) { 211 212 case 'a': case 'A': return VK_A; 213 case 'b': case 'B': return VK_B; 214 case 'c': case 'C': return VK_C; 215 case 'd': case 'D': return VK_D; 216 case 'e': case 'E': return VK_E; 217 case 'f': case 'F': return VK_F; 218 case 'g': case 'G': return VK_G; 219 case 'h': case 'H': return VK_H; 220 case 'i': case 'I': return VK_I; 221 case 'j': case 'J': return VK_J; 222 case 'k': case 'K': return VK_K; 223 case 'l': case 'L': return VK_L; 224 case 'm': case 'M': return VK_M; 225 case 'n': case 'N': return VK_N; 226 case 'o': case 'O': return VK_O; 227 case 'p': case 'P': return VK_P; 228 case 'q': case 'Q': return VK_Q; 229 case 'r': case 'R': return VK_R; 230 case 's': case 'S': return VK_S; 231 case 't': case 'T': return VK_T; 232 case 'u': case 'U': return VK_U; 233 case 'v': case 'V': return VK_V; 234 case 'w': case 'W': return VK_W; 235 case 'x': case 'X': return VK_X; 236 case 'y': case 'Y': return VK_Y; 237 case 'z': case 'Z': return VK_Z; 238 239 // AppKit generates Unicode PUA character codes for some function keys; using these when key code is not known. 240 case NSPauseFunctionKey: return VK_PAUSE; 241 case NSSelectFunctionKey: return VK_SELECT; 242 case NSPrintFunctionKey: return VK_PRINT; 243 case NSExecuteFunctionKey: return VK_EXECUTE; 244 case NSPrintScreenFunctionKey: return VK_SNAPSHOT; 245 case NSInsertFunctionKey: return VK_INSERT; 246 247 case NSF21FunctionKey: return VK_F21; 248 case NSF22FunctionKey: return VK_F22; 249 case NSF23FunctionKey: return VK_F23; 250 case NSF24FunctionKey: return VK_F24; 251 case NSScrollLockFunctionKey: return VK_SCROLL; 252 253 // This is for U.S. keyboard mapping, and doesn't necessarily make sense for different keyboard layouts. 254 // For example, '"' on Windows Russian layout is VK_2, not VK_OEM_7. 255 case ';': case ':': return VK_OEM_1; 256 case '=': case '+': return VK_OEM_PLUS; 257 case ',': case '<': return VK_OEM_COMMA; 258 case '-': case '_': return VK_OEM_MINUS; 259 case '.': case '>': return VK_OEM_PERIOD; 260 case '/': case '?': return VK_OEM_2; 261 case '`': case '~': return VK_OEM_3; 262 case '[': case '{': return VK_OEM_4; 263 case '\\': case '|': return VK_OEM_5; 264 case ']': case '}': return VK_OEM_6; 265 case '\'': case '"': return VK_OEM_7; 266 267 } 268 269 return 0; 270 } 271 272 static inline bool isKeyUpEvent(NSEvent* event) 273 { 274 if ([event type] != NSFlagsChanged) 275 return [event type] == NSKeyUp; 276 // FIXME: This logic fails if the user presses both Shift keys at once, for example: 277 // we treat releasing one of them as keyDown. 278 switch ([event keyCode]) { 279 case 54: // Right Command 280 case 55: // Left Command 281 return ([event modifierFlags] & NSCommandKeyMask) == 0; 282 283 case 57: // Capslock 284 return ([event modifierFlags] & NSAlphaShiftKeyMask) == 0; 285 286 case 56: // Left Shift 287 case 60: // Right Shift 288 return ([event modifierFlags] & NSShiftKeyMask) == 0; 289 290 case 58: // Left Alt 291 case 61: // Right Alt 292 return ([event modifierFlags] & NSAlternateKeyMask) == 0; 293 294 case 59: // Left Ctrl 295 case 62: // Right Ctrl 296 return ([event modifierFlags] & NSControlKeyMask) == 0; 297 298 case 63: // Function 299 return ([event modifierFlags] & NSFunctionKeyMask) == 0; 300 } 301 return false; 302 } 303 304 static bool isKeypadEvent(NSEvent* event) 305 { 306 // Check that this is the type of event that has a keyCode. 307 switch ([event type]) { 308 case NSKeyDown: 309 case NSKeyUp: 310 case NSFlagsChanged: 311 break; 312 default: 313 return false; 314 } 315 316 switch ([event keyCode]) { 317 case 71: // Clear 318 case 81: // = 319 case 75: // / 320 case 67: // * 321 case 78: // - 322 case 69: // + 323 case 76: // Enter 324 case 65: // . 325 case 82: // 0 326 case 83: // 1 327 case 84: // 2 328 case 85: // 3 329 case 86: // 4 330 case 87: // 5 331 case 88: // 6 332 case 89: // 7 333 case 91: // 8 334 case 92: // 9 335 return true; 336 } 337 338 return false; 339 } 340 341 static int windowsKeyCodeForKeyEvent(NSEvent* event) 342 { 343 int code = 0; 344 // There are several kinds of characters for which we produce key code from char code: 345 // 1. Roman letters. Windows keyboard layouts affect both virtual key codes and character codes for these, 346 // so e.g. 'A' gets the same keyCode on QWERTY, AZERTY or Dvorak layouts. 347 // 2. Keys for which there is no known Mac virtual key codes, like PrintScreen. 348 // 3. Certain punctuation keys. On Windows, these are also remapped depending on current keyboard layout, 349 // but see comment in windowsKeyCodeForCharCode(). 350 if (!isKeypadEvent(event) && ([event type] == NSKeyDown || [event type] == NSKeyUp)) { 351 // Cmd switches Roman letters for Dvorak-QWERTY layout, so try modified characters first. 352 NSString* s = [event characters]; 353 code = [s length] > 0 ? windowsKeyCodeForCharCode([s characterAtIndex:0]) : 0; 354 if (code) 355 return code; 356 357 // Ctrl+A on an AZERTY keyboard would get VK_Q keyCode if we relied on -[NSEvent keyCode] below. 358 s = [event charactersIgnoringModifiers]; 359 code = [s length] > 0 ? windowsKeyCodeForCharCode([s characterAtIndex:0]) : 0; 360 if (code) 361 return code; 362 } 363 364 // Map Mac virtual key code directly to Windows one for any keys not handled above. 365 // E.g. the key next to Caps Lock has the same Event.keyCode on U.S. keyboard ('A') and on Russian keyboard (CYRILLIC LETTER EF). 366 return windowsKeyCodeForKeyCode([event keyCode]); 367 } 368 369 static WebInputEvent::Type gestureEventTypeForEvent(NSEvent *event) 370 { 371 switch ([event type]) { 372 case NSEventTypeBeginGesture: 373 return WebInputEvent::GestureScrollBegin; 374 case NSEventTypeEndGesture: 375 return WebInputEvent::GestureScrollEnd; 376 default: 377 ASSERT_NOT_REACHED(); 378 return WebInputEvent::GestureScrollEnd; 379 } 380 } 381 382 static inline NSString* textFromEvent(NSEvent* event) 383 { 384 if ([event type] == NSFlagsChanged) 385 return @""; 386 return [event characters]; 387 } 388 389 static inline NSString* unmodifiedTextFromEvent(NSEvent* event) 390 { 391 if ([event type] == NSFlagsChanged) 392 return @""; 393 return [event charactersIgnoringModifiers]; 394 } 395 396 static NSString* keyIdentifierForKeyEvent(NSEvent* event) 397 { 398 if ([event type] == NSFlagsChanged) { 399 switch ([event keyCode]) { 400 case 54: // Right Command 401 case 55: // Left Command 402 return @"Meta"; 403 404 case 57: // Capslock 405 return @"CapsLock"; 406 407 case 56: // Left Shift 408 case 60: // Right Shift 409 return @"Shift"; 410 411 case 58: // Left Alt 412 case 61: // Right Alt 413 return @"Alt"; 414 415 case 59: // Left Ctrl 416 case 62: // Right Ctrl 417 return @"Control"; 418 419 // Begin non-Apple addition/modification -------------------------------------- 420 case 63: // Function 421 return @"Function"; 422 423 default: // Unknown, but this may be a strange/new keyboard. 424 return @"Unidentified"; 425 // End non-Apple addition/modification ---------------------------------------- 426 } 427 } 428 429 NSString* s = [event charactersIgnoringModifiers]; 430 if ([s length] != 1) 431 return @"Unidentified"; 432 433 unichar c = [s characterAtIndex:0]; 434 switch (c) { 435 // Each identifier listed in the DOM spec is listed here. 436 // Many are simply commented out since they do not appear on standard Macintosh keyboards 437 // or are on a key that doesn't have a corresponding character. 438 439 // "Accept" 440 // "AllCandidates" 441 442 // "Alt" 443 case NSMenuFunctionKey: 444 return @"Alt"; 445 446 // "Apps" 447 // "BrowserBack" 448 // "BrowserForward" 449 // "BrowserHome" 450 // "BrowserRefresh" 451 // "BrowserSearch" 452 // "BrowserStop" 453 // "CapsLock" 454 455 // "Clear" 456 case NSClearLineFunctionKey: 457 return @"Clear"; 458 459 // "CodeInput" 460 // "Compose" 461 // "Control" 462 // "Crsel" 463 // "Convert" 464 // "Copy" 465 // "Cut" 466 467 // "Down" 468 case NSDownArrowFunctionKey: 469 return @"Down"; 470 // "End" 471 case NSEndFunctionKey: 472 return @"End"; 473 // "Enter" 474 case 0x3: case 0xA: case 0xD: // Macintosh calls the one on the main keyboard Return, but Windows calls it Enter, so we'll do the same for the DOM 475 return @"Enter"; 476 477 // "EraseEof" 478 479 // "Execute" 480 case NSExecuteFunctionKey: 481 return @"Execute"; 482 483 // "Exsel" 484 485 // "F1" 486 case NSF1FunctionKey: 487 return @"F1"; 488 // "F2" 489 case NSF2FunctionKey: 490 return @"F2"; 491 // "F3" 492 case NSF3FunctionKey: 493 return @"F3"; 494 // "F4" 495 case NSF4FunctionKey: 496 return @"F4"; 497 // "F5" 498 case NSF5FunctionKey: 499 return @"F5"; 500 // "F6" 501 case NSF6FunctionKey: 502 return @"F6"; 503 // "F7" 504 case NSF7FunctionKey: 505 return @"F7"; 506 // "F8" 507 case NSF8FunctionKey: 508 return @"F8"; 509 // "F9" 510 case NSF9FunctionKey: 511 return @"F9"; 512 // "F10" 513 case NSF10FunctionKey: 514 return @"F10"; 515 // "F11" 516 case NSF11FunctionKey: 517 return @"F11"; 518 // "F12" 519 case NSF12FunctionKey: 520 return @"F12"; 521 // "F13" 522 case NSF13FunctionKey: 523 return @"F13"; 524 // "F14" 525 case NSF14FunctionKey: 526 return @"F14"; 527 // "F15" 528 case NSF15FunctionKey: 529 return @"F15"; 530 // "F16" 531 case NSF16FunctionKey: 532 return @"F16"; 533 // "F17" 534 case NSF17FunctionKey: 535 return @"F17"; 536 // "F18" 537 case NSF18FunctionKey: 538 return @"F18"; 539 // "F19" 540 case NSF19FunctionKey: 541 return @"F19"; 542 // "F20" 543 case NSF20FunctionKey: 544 return @"F20"; 545 // "F21" 546 case NSF21FunctionKey: 547 return @"F21"; 548 // "F22" 549 case NSF22FunctionKey: 550 return @"F22"; 551 // "F23" 552 case NSF23FunctionKey: 553 return @"F23"; 554 // "F24" 555 case NSF24FunctionKey: 556 return @"F24"; 557 558 // "FinalMode" 559 560 // "Find" 561 case NSFindFunctionKey: 562 return @"Find"; 563 564 // "FullWidth" 565 // "HalfWidth" 566 // "HangulMode" 567 // "HanjaMode" 568 569 // "Help" 570 case NSHelpFunctionKey: 571 return @"Help"; 572 573 // "Hiragana" 574 575 // "Home" 576 case NSHomeFunctionKey: 577 return @"Home"; 578 // "Insert" 579 case NSInsertFunctionKey: 580 return @"Insert"; 581 582 // "JapaneseHiragana" 583 // "JapaneseKatakana" 584 // "JapaneseRomaji" 585 // "JunjaMode" 586 // "KanaMode" 587 // "KanjiMode" 588 // "Katakana" 589 // "LaunchApplication1" 590 // "LaunchApplication2" 591 // "LaunchMail" 592 593 // "Left" 594 case NSLeftArrowFunctionKey: 595 return @"Left"; 596 597 // "Meta" 598 // "MediaNextTrack" 599 // "MediaPlayPause" 600 // "MediaPreviousTrack" 601 // "MediaStop" 602 603 // "ModeChange" 604 case NSModeSwitchFunctionKey: 605 return @"ModeChange"; 606 607 // "Nonconvert" 608 // "NumLock" 609 610 // "PageDown" 611 case NSPageDownFunctionKey: 612 return @"PageDown"; 613 // "PageUp" 614 case NSPageUpFunctionKey: 615 return @"PageUp"; 616 617 // "Paste" 618 619 // "Pause" 620 case NSPauseFunctionKey: 621 return @"Pause"; 622 623 // "Play" 624 // "PreviousCandidate" 625 626 // "PrintScreen" 627 case NSPrintScreenFunctionKey: 628 return @"PrintScreen"; 629 630 // "Process" 631 // "Props" 632 633 // "Right" 634 case NSRightArrowFunctionKey: 635 return @"Right"; 636 637 // "RomanCharacters" 638 639 // "Scroll" 640 case NSScrollLockFunctionKey: 641 return @"Scroll"; 642 // "Select" 643 case NSSelectFunctionKey: 644 return @"Select"; 645 646 // "SelectMedia" 647 // "Shift" 648 649 // "Stop" 650 case NSStopFunctionKey: 651 return @"Stop"; 652 // "Up" 653 case NSUpArrowFunctionKey: 654 return @"Up"; 655 // "Undo" 656 case NSUndoFunctionKey: 657 return @"Undo"; 658 659 // "VolumeDown" 660 // "VolumeMute" 661 // "VolumeUp" 662 // "Win" 663 // "Zoom" 664 665 // More function keys, not in the key identifier specification. 666 case NSF25FunctionKey: 667 return @"F25"; 668 case NSF26FunctionKey: 669 return @"F26"; 670 case NSF27FunctionKey: 671 return @"F27"; 672 case NSF28FunctionKey: 673 return @"F28"; 674 case NSF29FunctionKey: 675 return @"F29"; 676 case NSF30FunctionKey: 677 return @"F30"; 678 case NSF31FunctionKey: 679 return @"F31"; 680 case NSF32FunctionKey: 681 return @"F32"; 682 case NSF33FunctionKey: 683 return @"F33"; 684 case NSF34FunctionKey: 685 return @"F34"; 686 case NSF35FunctionKey: 687 return @"F35"; 688 689 // Turn 0x7F into 0x08, because backspace needs to always be 0x08. 690 case 0x7F: 691 return @"U+0008"; 692 // Standard says that DEL becomes U+007F. 693 case NSDeleteFunctionKey: 694 return @"U+007F"; 695 696 // Always use 0x09 for tab instead of AppKit's backtab character. 697 case NSBackTabCharacter: 698 return @"U+0009"; 699 700 case NSBeginFunctionKey: 701 case NSBreakFunctionKey: 702 case NSClearDisplayFunctionKey: 703 case NSDeleteCharFunctionKey: 704 case NSDeleteLineFunctionKey: 705 case NSInsertCharFunctionKey: 706 case NSInsertLineFunctionKey: 707 case NSNextFunctionKey: 708 case NSPrevFunctionKey: 709 case NSPrintFunctionKey: 710 case NSRedoFunctionKey: 711 case NSResetFunctionKey: 712 case NSSysReqFunctionKey: 713 case NSSystemFunctionKey: 714 case NSUserFunctionKey: 715 // FIXME: We should use something other than the vendor-area Unicode values for the above keys. 716 // For now, just fall through to the default. 717 default: 718 return [NSString stringWithFormat:@"U+%04X", WTF::toASCIIUpper(c)]; 719 } 720 } 721 722 // End Apple code. 723 // ---------------------------------------------------------------------------- 724 725 static inline int modifiersFromEvent(NSEvent* event) { 726 int modifiers = 0; 727 728 if ([event modifierFlags] & NSControlKeyMask) 729 modifiers |= WebInputEvent::ControlKey; 730 if ([event modifierFlags] & NSShiftKeyMask) 731 modifiers |= WebInputEvent::ShiftKey; 732 if ([event modifierFlags] & NSAlternateKeyMask) 733 modifiers |= WebInputEvent::AltKey; 734 if ([event modifierFlags] & NSCommandKeyMask) 735 modifiers |= WebInputEvent::MetaKey; 736 if ([event modifierFlags] & NSAlphaShiftKeyMask) 737 modifiers |= WebInputEvent::CapsLockOn; 738 // TODO(port): Set mouse button states 739 740 return modifiers; 741 } 742 743 static inline void setWebEventLocationFromEventInView(WebMouseEvent* result, 744 NSEvent* event, 745 NSView* view) { 746 NSPoint windowLocal = [event locationInWindow]; 747 748 NSPoint screenLocal = [[view window] convertBaseToScreen:windowLocal]; 749 result->globalX = screenLocal.x; 750 // Flip y. 751 NSScreen* primaryScreen = ([[NSScreen screens] count] > 0) ? 752 [[NSScreen screens] objectAtIndex:0] : nil; 753 if (primaryScreen) 754 result->globalY = [primaryScreen frame].size.height - screenLocal.y; 755 else 756 result->globalY = screenLocal.y; 757 758 NSPoint contentLocal = [view convertPoint:windowLocal fromView:nil]; 759 result->x = contentLocal.x; 760 result->y = [view frame].size.height - contentLocal.y; // Flip y. 761 762 result->windowX = result->x; 763 result->windowY = result->y; 764 765 result->movementX = [event deltaX]; 766 result->movementY = [event deltaY]; 767 } 768 769 bool WebInputEventFactory::isSystemKeyEvent(const WebKeyboardEvent& event) 770 { 771 // Windows and Linux set |isSystemKey| if alt is down. Blink looks at this 772 // flag to decide if it should handle a key or not. E.g. alt-left/right 773 // shouldn't be used by Blink to scroll the current page, because we want 774 // to get that key back for it to do history navigation. Hence, the 775 // corresponding situation on OS X is to set this for cmd key presses. 776 // cmd-b and and cmd-i are system wide key bindings that OS X doesn't 777 // handle for us, so the editor handles them. 778 return event.modifiers & WebInputEvent::MetaKey 779 && event.windowsKeyCode != VK_B 780 && event.windowsKeyCode != VK_I; 781 } 782 783 WebKeyboardEvent WebInputEventFactory::keyboardEvent(NSEvent* event) 784 { 785 WebKeyboardEvent result; 786 787 result.type = 788 isKeyUpEvent(event) ? WebInputEvent::KeyUp : WebInputEvent::RawKeyDown; 789 790 result.modifiers = modifiersFromEvent(event); 791 792 if (isKeypadEvent(event)) 793 result.modifiers |= WebInputEvent::IsKeyPad; 794 795 if (([event type] != NSFlagsChanged) && [event isARepeat]) 796 result.modifiers |= WebInputEvent::IsAutoRepeat; 797 798 int windowsKeyCode = windowsKeyCodeForKeyEvent(event); 799 result.windowsKeyCode = WebKeyboardEvent::windowsKeyCodeWithoutLocation(windowsKeyCode); 800 result.modifiers |= WebKeyboardEvent::locationModifiersFromWindowsKeyCode(windowsKeyCode); 801 result.nativeKeyCode = [event keyCode]; 802 803 NSString* textStr = textFromEvent(event); 804 NSString* unmodifiedStr = unmodifiedTextFromEvent(event); 805 NSString* identifierStr = keyIdentifierForKeyEvent(event); 806 807 // Begin Apple code, copied from KeyEventMac.mm 808 809 // Always use 13 for Enter/Return -- we don't want to use AppKit's 810 // different character for Enter. 811 if (result.windowsKeyCode == '\r') { 812 textStr = @"\r"; 813 unmodifiedStr = @"\r"; 814 } 815 816 // The adjustments below are only needed in backward compatibility mode, 817 // but we cannot tell what mode we are in from here. 818 819 // Turn 0x7F into 8, because backspace needs to always be 8. 820 if ([textStr isEqualToString:@"\x7F"]) 821 textStr = @"\x8"; 822 if ([unmodifiedStr isEqualToString:@"\x7F"]) 823 unmodifiedStr = @"\x8"; 824 // Always use 9 for tab -- we don't want to use AppKit's different character 825 // for shift-tab. 826 if (result.windowsKeyCode == 9) { 827 textStr = @"\x9"; 828 unmodifiedStr = @"\x9"; 829 } 830 831 // End Apple code. 832 833 if ([textStr length] < WebKeyboardEvent::textLengthCap && 834 [unmodifiedStr length] < WebKeyboardEvent::textLengthCap) { 835 [textStr getCharacters:&result.text[0]]; 836 [unmodifiedStr getCharacters:&result.unmodifiedText[0]]; 837 } else 838 ASSERT_NOT_REACHED(); 839 840 [identifierStr getCString:&result.keyIdentifier[0] 841 maxLength:sizeof(result.keyIdentifier) 842 encoding:NSASCIIStringEncoding]; 843 844 result.timeStampSeconds = [event timestamp]; 845 result.isSystemKey = isSystemKeyEvent(result); 846 847 return result; 848 } 849 850 WebKeyboardEvent WebInputEventFactory::keyboardEvent(wchar_t character, 851 int modifiers, 852 double timeStampSeconds) 853 { 854 // keyboardEvent(NSEvent*) depends on the NSEvent object and 855 // it is hard to use it from methods of the NSTextInput protocol. For 856 // such methods, this function creates a WebInputEvent::Char event without 857 // using a NSEvent object. 858 WebKeyboardEvent result; 859 result.type = blink::WebInputEvent::Char; 860 result.timeStampSeconds = timeStampSeconds; 861 result.modifiers = modifiers; 862 result.windowsKeyCode = character; 863 result.nativeKeyCode = character; 864 result.text[0] = character; 865 result.unmodifiedText[0] = character; 866 result.isSystemKey = isSystemKeyEvent(result); 867 868 return result; 869 } 870 871 // WebMouseEvent -------------------------------------------------------------- 872 873 WebMouseEvent WebInputEventFactory::mouseEvent(NSEvent* event, NSView* view) 874 { 875 WebMouseEvent result; 876 877 result.clickCount = 0; 878 879 switch ([event type]) { 880 case NSMouseExited: 881 result.type = WebInputEvent::MouseLeave; 882 result.button = WebMouseEvent::ButtonNone; 883 break; 884 case NSLeftMouseDown: 885 result.type = WebInputEvent::MouseDown; 886 result.clickCount = [event clickCount]; 887 result.button = WebMouseEvent::ButtonLeft; 888 break; 889 case NSOtherMouseDown: 890 result.type = WebInputEvent::MouseDown; 891 result.clickCount = [event clickCount]; 892 result.button = WebMouseEvent::ButtonMiddle; 893 break; 894 case NSRightMouseDown: 895 result.type = WebInputEvent::MouseDown; 896 result.clickCount = [event clickCount]; 897 result.button = WebMouseEvent::ButtonRight; 898 break; 899 case NSLeftMouseUp: 900 result.type = WebInputEvent::MouseUp; 901 result.clickCount = [event clickCount]; 902 result.button = WebMouseEvent::ButtonLeft; 903 break; 904 case NSOtherMouseUp: 905 result.type = WebInputEvent::MouseUp; 906 result.clickCount = [event clickCount]; 907 result.button = WebMouseEvent::ButtonMiddle; 908 break; 909 case NSRightMouseUp: 910 result.type = WebInputEvent::MouseUp; 911 result.clickCount = [event clickCount]; 912 result.button = WebMouseEvent::ButtonRight; 913 break; 914 case NSMouseMoved: 915 case NSMouseEntered: 916 result.type = WebInputEvent::MouseMove; 917 break; 918 case NSLeftMouseDragged: 919 result.type = WebInputEvent::MouseMove; 920 result.button = WebMouseEvent::ButtonLeft; 921 break; 922 case NSOtherMouseDragged: 923 result.type = WebInputEvent::MouseMove; 924 result.button = WebMouseEvent::ButtonMiddle; 925 break; 926 case NSRightMouseDragged: 927 result.type = WebInputEvent::MouseMove; 928 result.button = WebMouseEvent::ButtonRight; 929 break; 930 default: 931 ASSERT_NOT_REACHED(); 932 } 933 934 setWebEventLocationFromEventInView(&result, event, view); 935 936 result.modifiers = modifiersFromEvent(event); 937 938 result.timeStampSeconds = [event timestamp]; 939 940 return result; 941 } 942 943 // WebMouseWheelEvent --------------------------------------------------------- 944 945 static WebMouseWheelEvent::Phase phaseForNSEventPhase(NSEventPhase eventPhase) 946 { 947 uint32_t phase = WebMouseWheelEvent::PhaseNone; 948 if (eventPhase & NSEventPhaseBegan) 949 phase |= WebMouseWheelEvent::PhaseBegan; 950 if (eventPhase & NSEventPhaseStationary) 951 phase |= WebMouseWheelEvent::PhaseStationary; 952 if (eventPhase & NSEventPhaseChanged) 953 phase |= WebMouseWheelEvent::PhaseChanged; 954 if (eventPhase & NSEventPhaseEnded) 955 phase |= WebMouseWheelEvent::PhaseEnded; 956 if (eventPhase & NSEventPhaseCancelled) 957 phase |= WebMouseWheelEvent::PhaseCancelled; 958 if (eventPhase & NSEventPhaseMayBegin) 959 phase |= WebMouseWheelEvent::PhaseMayBegin; 960 return static_cast<WebMouseWheelEvent::Phase>(phase); 961 } 962 963 static WebMouseWheelEvent::Phase phaseForEvent(NSEvent *event) 964 { 965 if (![event respondsToSelector:@selector(phase)]) 966 return WebMouseWheelEvent::PhaseNone; 967 968 NSEventPhase eventPhase = [event phase]; 969 return phaseForNSEventPhase(eventPhase); 970 } 971 972 static WebMouseWheelEvent::Phase momentumPhaseForEvent(NSEvent *event) 973 { 974 if (![event respondsToSelector:@selector(momentumPhase)]) 975 return WebMouseWheelEvent::PhaseNone; 976 977 NSEventPhase eventMomentumPhase = [event momentumPhase]; 978 return phaseForNSEventPhase(eventMomentumPhase); 979 } 980 981 WebMouseWheelEvent WebInputEventFactory::mouseWheelEvent(NSEvent* event, NSView* view) 982 { 983 WebMouseWheelEvent result; 984 985 result.type = WebInputEvent::MouseWheel; 986 result.button = WebMouseEvent::ButtonNone; 987 988 result.modifiers = modifiersFromEvent(event); 989 990 setWebEventLocationFromEventInView(&result, event, view); 991 992 // Of Mice and Men 993 // --------------- 994 // 995 // There are three types of scroll data available on a scroll wheel CGEvent. 996 // Apple's documentation ([1]) is rather vague in their differences, and not 997 // terribly helpful in deciding which to use. This is what's really going on. 998 // 999 // First, these events behave very differently depending on whether a standard 1000 // wheel mouse is used (one that scrolls in discrete units) or a 1001 // trackpad/Mighty Mouse is used (which both provide continuous scrolling). 1002 // You must check to see which was used for the event by testing the 1003 // kCGScrollWheelEventIsContinuous field. 1004 // 1005 // Second, these events refer to "axes". Axis 1 is the y-axis, and axis 2 is 1006 // the x-axis. 1007 // 1008 // Third, there is a concept of mouse acceleration. Scrolling the same amount 1009 // of physical distance will give you different results logically depending on 1010 // whether you scrolled a little at a time or in one continuous motion. Some 1011 // fields account for this while others do not. 1012 // 1013 // Fourth, for trackpads there is a concept of chunkiness. When scrolling 1014 // continuously, events can be delivered in chunks. That is to say, lots of 1015 // scroll events with delta 0 will be delivered, and every so often an event 1016 // with a non-zero delta will be delivered, containing the accumulated deltas 1017 // from all the intermediate moves. [2] 1018 // 1019 // For notchy wheel mice (kCGScrollWheelEventIsContinuous == 0) 1020 // ------------------------------------------------------------ 1021 // 1022 // kCGScrollWheelEventDeltaAxis* 1023 // This is the rawest of raw events. For each mouse notch you get a value of 1024 // +1/-1. This does not take acceleration into account and thus is less 1025 // useful for building UIs. 1026 // 1027 // kCGScrollWheelEventPointDeltaAxis* 1028 // This is smarter. In general, for each mouse notch you get a value of 1029 // +1/-1, but this _does_ take acceleration into account, so you will get 1030 // larger values on longer scrolls. This field would be ideal for building 1031 // UIs except for one nasty bug: when the shift key is pressed, this set of 1032 // fields fails to move the value into the axis2 field (the other two types 1033 // of data do). This wouldn't be so bad except for the fact that while the 1034 // number of axes is used in the creation of a CGScrollWheelEvent, there is 1035 // no way to get that information out of the event once created. 1036 // 1037 // kCGScrollWheelEventFixedPtDeltaAxis* 1038 // This is a fixed value, and for each mouse notch you get a value of 1039 // +0.1/-0.1 (but, like above, scaled appropriately for acceleration). This 1040 // value takes acceleration into account, and in fact is identical to the 1041 // results you get from -[NSEvent delta*]. (That is, if you linked on Tiger 1042 // or greater; see [2] for details.) 1043 // 1044 // A note about continuous devices 1045 // ------------------------------- 1046 // 1047 // There are two devices that provide continuous scrolling events (trackpads 1048 // and Mighty Mouses) and they behave rather differently. The Mighty Mouse 1049 // behaves a lot like a regular mouse. There is no chunking, and the 1050 // FixedPtDelta values are the PointDelta values multiplied by 0.1. With the 1051 // trackpad, though, there is chunking. While the FixedPtDelta values are 1052 // reasonable (they occur about every fifth event but have values five times 1053 // larger than usual) the Delta values are unreasonable. They don't appear to 1054 // accumulate properly. 1055 // 1056 // For continuous devices (kCGScrollWheelEventIsContinuous != 0) 1057 // ------------------------------------------------------------- 1058 // 1059 // kCGScrollWheelEventDeltaAxis* 1060 // This provides values with no acceleration. With a trackpad, these values 1061 // are chunked but each non-zero value does not appear to be cumulative. 1062 // This seems to be a bug. 1063 // 1064 // kCGScrollWheelEventPointDeltaAxis* 1065 // This provides values with acceleration. With a trackpad, these values are 1066 // not chunked and are highly accurate. 1067 // 1068 // kCGScrollWheelEventFixedPtDeltaAxis* 1069 // This provides values with acceleration. With a trackpad, these values are 1070 // chunked but unlike Delta events are properly cumulative. 1071 // 1072 // Summary 1073 // ------- 1074 // 1075 // In general the best approach to take is: determine if the event is 1076 // continuous. If it is not, then use the FixedPtDelta events (or just stick 1077 // with Cocoa events). They provide both acceleration and proper horizontal 1078 // scrolling. If the event is continuous, then doing pixel scrolling with the 1079 // PointDelta is the way to go. In general, avoid the Delta events. They're 1080 // the oldest (dating back to 10.4, before CGEvents were public) but they lack 1081 // acceleration and precision, making them useful only in specific edge cases. 1082 // 1083 // References 1084 // ---------- 1085 // 1086 // [1] <http://developer.apple.com/documentation/Carbon/Reference/QuartzEventServicesRef/Reference/reference.html> 1087 // [2] <http://developer.apple.com/releasenotes/Cocoa/AppKitOlderNotes.html> 1088 // Scroll to the section headed "NSScrollWheel events". 1089 // 1090 // P.S. The "smooth scrolling" option in the system preferences is utterly 1091 // unrelated to any of this. 1092 1093 CGEventRef cgEvent = [event CGEvent]; 1094 ASSERT(cgEvent); 1095 1096 // Wheel ticks are supposed to be raw, unaccelerated values, one per physical 1097 // mouse wheel notch. The delta event is perfect for this (being a good 1098 // "specific edge case" as mentioned above). Trackpads, unfortunately, do 1099 // event chunking, and sending mousewheel events with 0 ticks causes some 1100 // websites to malfunction. Therefore, for all continuous input devices we use 1101 // the point delta data instead, since we cannot distinguish trackpad data 1102 // from data from any other continuous device. 1103 1104 // Conversion between wheel delta amounts and number of pixels to scroll. 1105 static const double scrollbarPixelsPerCocoaTick = 40.0; 1106 1107 if (CGEventGetIntegerValueField(cgEvent, kCGScrollWheelEventIsContinuous)) { 1108 result.deltaX = CGEventGetIntegerValueField(cgEvent, kCGScrollWheelEventPointDeltaAxis2); 1109 result.deltaY = CGEventGetIntegerValueField(cgEvent, kCGScrollWheelEventPointDeltaAxis1); 1110 result.wheelTicksX = result.deltaX / scrollbarPixelsPerCocoaTick; 1111 result.wheelTicksY = result.deltaY / scrollbarPixelsPerCocoaTick; 1112 result.hasPreciseScrollingDeltas = true; 1113 } else { 1114 result.deltaX = [event deltaX] * scrollbarPixelsPerCocoaTick; 1115 result.deltaY = [event deltaY] * scrollbarPixelsPerCocoaTick; 1116 result.wheelTicksY = CGEventGetIntegerValueField(cgEvent, kCGScrollWheelEventDeltaAxis1); 1117 result.wheelTicksX = CGEventGetIntegerValueField(cgEvent, kCGScrollWheelEventDeltaAxis2); 1118 } 1119 1120 result.timeStampSeconds = [event timestamp]; 1121 1122 result.phase = phaseForEvent(event); 1123 result.momentumPhase = momentumPhaseForEvent(event); 1124 1125 return result; 1126 } 1127 1128 WebGestureEvent WebInputEventFactory::gestureEvent(NSEvent *event, NSView *view) 1129 { 1130 WebGestureEvent result; 1131 1132 // Use a temporary WebMouseEvent to get the location. 1133 WebMouseEvent temp; 1134 1135 setWebEventLocationFromEventInView(&temp, event, view); 1136 result.x = temp.x; 1137 result.y = temp.y; 1138 result.globalX = temp.globalX; 1139 result.globalY = temp.globalY; 1140 1141 result.type = gestureEventTypeForEvent(event); 1142 result.modifiers = modifiersFromEvent(event); 1143 result.timeStampSeconds = [event timestamp]; 1144 1145 return result; 1146 } 1147 1148 } // namespace blink 1149