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 "public/web/mac/WebInputEventFactory.h" 29 30 #include <ApplicationServices/ApplicationServices.h> 31 #import <AvailabilityMacros.h> 32 #import <Cocoa/Cocoa.h> 33 34 #include "platform/WindowsKeyboardCodes.h" 35 #include "public/web/WebInputEvent.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 inline NSString* textFromEvent(NSEvent* event) 370 { 371 if ([event type] == NSFlagsChanged) 372 return @""; 373 return [event characters]; 374 } 375 376 static inline NSString* unmodifiedTextFromEvent(NSEvent* event) 377 { 378 if ([event type] == NSFlagsChanged) 379 return @""; 380 return [event charactersIgnoringModifiers]; 381 } 382 383 static NSString* keyIdentifierForKeyEvent(NSEvent* event) 384 { 385 if ([event type] == NSFlagsChanged) { 386 switch ([event keyCode]) { 387 case 54: // Right Command 388 case 55: // Left Command 389 return @"Meta"; 390 391 case 57: // Capslock 392 return @"CapsLock"; 393 394 case 56: // Left Shift 395 case 60: // Right Shift 396 return @"Shift"; 397 398 case 58: // Left Alt 399 case 61: // Right Alt 400 return @"Alt"; 401 402 case 59: // Left Ctrl 403 case 62: // Right Ctrl 404 return @"Control"; 405 406 // Begin non-Apple addition/modification -------------------------------------- 407 case 63: // Function 408 return @"Function"; 409 410 default: // Unknown, but this may be a strange/new keyboard. 411 return @"Unidentified"; 412 // End non-Apple addition/modification ---------------------------------------- 413 } 414 } 415 416 NSString* s = [event charactersIgnoringModifiers]; 417 if ([s length] != 1) 418 return @"Unidentified"; 419 420 unichar c = [s characterAtIndex:0]; 421 switch (c) { 422 // Each identifier listed in the DOM spec is listed here. 423 // Many are simply commented out since they do not appear on standard Macintosh keyboards 424 // or are on a key that doesn't have a corresponding character. 425 426 // "Accept" 427 // "AllCandidates" 428 429 // "Alt" 430 case NSMenuFunctionKey: 431 return @"Alt"; 432 433 // "Apps" 434 // "BrowserBack" 435 // "BrowserForward" 436 // "BrowserHome" 437 // "BrowserRefresh" 438 // "BrowserSearch" 439 // "BrowserStop" 440 // "CapsLock" 441 442 // "Clear" 443 case NSClearLineFunctionKey: 444 return @"Clear"; 445 446 // "CodeInput" 447 // "Compose" 448 // "Control" 449 // "Crsel" 450 // "Convert" 451 // "Copy" 452 // "Cut" 453 454 // "Down" 455 case NSDownArrowFunctionKey: 456 return @"Down"; 457 // "End" 458 case NSEndFunctionKey: 459 return @"End"; 460 // "Enter" 461 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 462 return @"Enter"; 463 464 // "EraseEof" 465 466 // "Execute" 467 case NSExecuteFunctionKey: 468 return @"Execute"; 469 470 // "Exsel" 471 472 // "F1" 473 case NSF1FunctionKey: 474 return @"F1"; 475 // "F2" 476 case NSF2FunctionKey: 477 return @"F2"; 478 // "F3" 479 case NSF3FunctionKey: 480 return @"F3"; 481 // "F4" 482 case NSF4FunctionKey: 483 return @"F4"; 484 // "F5" 485 case NSF5FunctionKey: 486 return @"F5"; 487 // "F6" 488 case NSF6FunctionKey: 489 return @"F6"; 490 // "F7" 491 case NSF7FunctionKey: 492 return @"F7"; 493 // "F8" 494 case NSF8FunctionKey: 495 return @"F8"; 496 // "F9" 497 case NSF9FunctionKey: 498 return @"F9"; 499 // "F10" 500 case NSF10FunctionKey: 501 return @"F10"; 502 // "F11" 503 case NSF11FunctionKey: 504 return @"F11"; 505 // "F12" 506 case NSF12FunctionKey: 507 return @"F12"; 508 // "F13" 509 case NSF13FunctionKey: 510 return @"F13"; 511 // "F14" 512 case NSF14FunctionKey: 513 return @"F14"; 514 // "F15" 515 case NSF15FunctionKey: 516 return @"F15"; 517 // "F16" 518 case NSF16FunctionKey: 519 return @"F16"; 520 // "F17" 521 case NSF17FunctionKey: 522 return @"F17"; 523 // "F18" 524 case NSF18FunctionKey: 525 return @"F18"; 526 // "F19" 527 case NSF19FunctionKey: 528 return @"F19"; 529 // "F20" 530 case NSF20FunctionKey: 531 return @"F20"; 532 // "F21" 533 case NSF21FunctionKey: 534 return @"F21"; 535 // "F22" 536 case NSF22FunctionKey: 537 return @"F22"; 538 // "F23" 539 case NSF23FunctionKey: 540 return @"F23"; 541 // "F24" 542 case NSF24FunctionKey: 543 return @"F24"; 544 545 // "FinalMode" 546 547 // "Find" 548 case NSFindFunctionKey: 549 return @"Find"; 550 551 // "FullWidth" 552 // "HalfWidth" 553 // "HangulMode" 554 // "HanjaMode" 555 556 // "Help" 557 case NSHelpFunctionKey: 558 return @"Help"; 559 560 // "Hiragana" 561 562 // "Home" 563 case NSHomeFunctionKey: 564 return @"Home"; 565 // "Insert" 566 case NSInsertFunctionKey: 567 return @"Insert"; 568 569 // "JapaneseHiragana" 570 // "JapaneseKatakana" 571 // "JapaneseRomaji" 572 // "JunjaMode" 573 // "KanaMode" 574 // "KanjiMode" 575 // "Katakana" 576 // "LaunchApplication1" 577 // "LaunchApplication2" 578 // "LaunchMail" 579 580 // "Left" 581 case NSLeftArrowFunctionKey: 582 return @"Left"; 583 584 // "Meta" 585 // "MediaNextTrack" 586 // "MediaPlayPause" 587 // "MediaPreviousTrack" 588 // "MediaStop" 589 590 // "ModeChange" 591 case NSModeSwitchFunctionKey: 592 return @"ModeChange"; 593 594 // "Nonconvert" 595 // "NumLock" 596 597 // "PageDown" 598 case NSPageDownFunctionKey: 599 return @"PageDown"; 600 // "PageUp" 601 case NSPageUpFunctionKey: 602 return @"PageUp"; 603 604 // "Paste" 605 606 // "Pause" 607 case NSPauseFunctionKey: 608 return @"Pause"; 609 610 // "Play" 611 // "PreviousCandidate" 612 613 // "PrintScreen" 614 case NSPrintScreenFunctionKey: 615 return @"PrintScreen"; 616 617 // "Process" 618 // "Props" 619 620 // "Right" 621 case NSRightArrowFunctionKey: 622 return @"Right"; 623 624 // "RomanCharacters" 625 626 // "Scroll" 627 case NSScrollLockFunctionKey: 628 return @"Scroll"; 629 // "Select" 630 case NSSelectFunctionKey: 631 return @"Select"; 632 633 // "SelectMedia" 634 // "Shift" 635 636 // "Stop" 637 case NSStopFunctionKey: 638 return @"Stop"; 639 // "Up" 640 case NSUpArrowFunctionKey: 641 return @"Up"; 642 // "Undo" 643 case NSUndoFunctionKey: 644 return @"Undo"; 645 646 // "VolumeDown" 647 // "VolumeMute" 648 // "VolumeUp" 649 // "Win" 650 // "Zoom" 651 652 // More function keys, not in the key identifier specification. 653 case NSF25FunctionKey: 654 return @"F25"; 655 case NSF26FunctionKey: 656 return @"F26"; 657 case NSF27FunctionKey: 658 return @"F27"; 659 case NSF28FunctionKey: 660 return @"F28"; 661 case NSF29FunctionKey: 662 return @"F29"; 663 case NSF30FunctionKey: 664 return @"F30"; 665 case NSF31FunctionKey: 666 return @"F31"; 667 case NSF32FunctionKey: 668 return @"F32"; 669 case NSF33FunctionKey: 670 return @"F33"; 671 case NSF34FunctionKey: 672 return @"F34"; 673 case NSF35FunctionKey: 674 return @"F35"; 675 676 // Turn 0x7F into 0x08, because backspace needs to always be 0x08. 677 case 0x7F: 678 return @"U+0008"; 679 // Standard says that DEL becomes U+007F. 680 case NSDeleteFunctionKey: 681 return @"U+007F"; 682 683 // Always use 0x09 for tab instead of AppKit's backtab character. 684 case NSBackTabCharacter: 685 return @"U+0009"; 686 687 case NSBeginFunctionKey: 688 case NSBreakFunctionKey: 689 case NSClearDisplayFunctionKey: 690 case NSDeleteCharFunctionKey: 691 case NSDeleteLineFunctionKey: 692 case NSInsertCharFunctionKey: 693 case NSInsertLineFunctionKey: 694 case NSNextFunctionKey: 695 case NSPrevFunctionKey: 696 case NSPrintFunctionKey: 697 case NSRedoFunctionKey: 698 case NSResetFunctionKey: 699 case NSSysReqFunctionKey: 700 case NSSystemFunctionKey: 701 case NSUserFunctionKey: 702 // FIXME: We should use something other than the vendor-area Unicode values for the above keys. 703 // For now, just fall through to the default. 704 default: 705 return [NSString stringWithFormat:@"U+%04X", WTF::toASCIIUpper(c)]; 706 } 707 } 708 709 // End Apple code. 710 // ---------------------------------------------------------------------------- 711 712 static inline int modifiersFromEvent(NSEvent* event) { 713 int modifiers = 0; 714 715 if ([event modifierFlags] & NSControlKeyMask) 716 modifiers |= WebInputEvent::ControlKey; 717 if ([event modifierFlags] & NSShiftKeyMask) 718 modifiers |= WebInputEvent::ShiftKey; 719 if ([event modifierFlags] & NSAlternateKeyMask) 720 modifiers |= WebInputEvent::AltKey; 721 if ([event modifierFlags] & NSCommandKeyMask) 722 modifiers |= WebInputEvent::MetaKey; 723 if ([event modifierFlags] & NSAlphaShiftKeyMask) 724 modifiers |= WebInputEvent::CapsLockOn; 725 // TODO(port): Set mouse button states 726 727 return modifiers; 728 } 729 730 static inline void setWebEventLocationFromEventInView(WebMouseEvent* result, 731 NSEvent* event, 732 NSView* view) { 733 NSPoint windowLocal = [event locationInWindow]; 734 735 NSPoint screenLocal = [[view window] convertBaseToScreen:windowLocal]; 736 result->globalX = screenLocal.x; 737 // Flip y. 738 NSScreen* primaryScreen = ([[NSScreen screens] count] > 0) ? 739 [[NSScreen screens] objectAtIndex:0] : nil; 740 if (primaryScreen) 741 result->globalY = [primaryScreen frame].size.height - screenLocal.y; 742 else 743 result->globalY = screenLocal.y; 744 745 NSPoint contentLocal = [view convertPoint:windowLocal fromView:nil]; 746 result->x = contentLocal.x; 747 result->y = [view frame].size.height - contentLocal.y; // Flip y. 748 749 result->windowX = result->x; 750 result->windowY = result->y; 751 752 result->movementX = [event deltaX]; 753 result->movementY = [event deltaY]; 754 } 755 756 bool WebInputEventFactory::isSystemKeyEvent(const WebKeyboardEvent& event) 757 { 758 // Windows and Linux set |isSystemKey| if alt is down. Blink looks at this 759 // flag to decide if it should handle a key or not. E.g. alt-left/right 760 // shouldn't be used by Blink to scroll the current page, because we want 761 // to get that key back for it to do history navigation. Hence, the 762 // corresponding situation on OS X is to set this for cmd key presses. 763 // cmd-b and and cmd-i are system wide key bindings that OS X doesn't 764 // handle for us, so the editor handles them. 765 return event.modifiers & WebInputEvent::MetaKey 766 && event.windowsKeyCode != VK_B 767 && event.windowsKeyCode != VK_I; 768 } 769 770 WebKeyboardEvent WebInputEventFactory::keyboardEvent(NSEvent* event) 771 { 772 WebKeyboardEvent result; 773 774 result.type = 775 isKeyUpEvent(event) ? WebInputEvent::KeyUp : WebInputEvent::RawKeyDown; 776 777 result.modifiers = modifiersFromEvent(event); 778 779 if (isKeypadEvent(event)) 780 result.modifiers |= WebInputEvent::IsKeyPad; 781 782 if (([event type] != NSFlagsChanged) && [event isARepeat]) 783 result.modifiers |= WebInputEvent::IsAutoRepeat; 784 785 int windowsKeyCode = windowsKeyCodeForKeyEvent(event); 786 result.windowsKeyCode = WebKeyboardEvent::windowsKeyCodeWithoutLocation(windowsKeyCode); 787 result.modifiers |= WebKeyboardEvent::locationModifiersFromWindowsKeyCode(windowsKeyCode); 788 result.nativeKeyCode = [event keyCode]; 789 790 NSString* textStr = textFromEvent(event); 791 NSString* unmodifiedStr = unmodifiedTextFromEvent(event); 792 NSString* identifierStr = keyIdentifierForKeyEvent(event); 793 794 // Begin Apple code, copied from KeyEventMac.mm 795 796 // Always use 13 for Enter/Return -- we don't want to use AppKit's 797 // different character for Enter. 798 if (result.windowsKeyCode == '\r') { 799 textStr = @"\r"; 800 unmodifiedStr = @"\r"; 801 } 802 803 // The adjustments below are only needed in backward compatibility mode, 804 // but we cannot tell what mode we are in from here. 805 806 // Turn 0x7F into 8, because backspace needs to always be 8. 807 if ([textStr isEqualToString:@"\x7F"]) 808 textStr = @"\x8"; 809 if ([unmodifiedStr isEqualToString:@"\x7F"]) 810 unmodifiedStr = @"\x8"; 811 // Always use 9 for tab -- we don't want to use AppKit's different character 812 // for shift-tab. 813 if (result.windowsKeyCode == 9) { 814 textStr = @"\x9"; 815 unmodifiedStr = @"\x9"; 816 } 817 818 // End Apple code. 819 820 if ([textStr length] < WebKeyboardEvent::textLengthCap && 821 [unmodifiedStr length] < WebKeyboardEvent::textLengthCap) { 822 [textStr getCharacters:&result.text[0]]; 823 [unmodifiedStr getCharacters:&result.unmodifiedText[0]]; 824 } else 825 ASSERT_NOT_REACHED(); 826 827 [identifierStr getCString:&result.keyIdentifier[0] 828 maxLength:sizeof(result.keyIdentifier) 829 encoding:NSASCIIStringEncoding]; 830 831 result.timeStampSeconds = [event timestamp]; 832 result.isSystemKey = isSystemKeyEvent(result); 833 834 return result; 835 } 836 837 WebKeyboardEvent WebInputEventFactory::keyboardEvent(wchar_t character, 838 int modifiers, 839 double timeStampSeconds) 840 { 841 // keyboardEvent(NSEvent*) depends on the NSEvent object and 842 // it is hard to use it from methods of the NSTextInput protocol. For 843 // such methods, this function creates a WebInputEvent::Char event without 844 // using a NSEvent object. 845 WebKeyboardEvent result; 846 result.type = blink::WebInputEvent::Char; 847 result.timeStampSeconds = timeStampSeconds; 848 result.modifiers = modifiers; 849 result.windowsKeyCode = character; 850 result.nativeKeyCode = character; 851 result.text[0] = character; 852 result.unmodifiedText[0] = character; 853 result.isSystemKey = isSystemKeyEvent(result); 854 855 return result; 856 } 857 858 // WebMouseEvent -------------------------------------------------------------- 859 860 WebMouseEvent WebInputEventFactory::mouseEvent(NSEvent* event, NSView* view) 861 { 862 WebMouseEvent result; 863 864 result.clickCount = 0; 865 866 switch ([event type]) { 867 case NSMouseExited: 868 result.type = WebInputEvent::MouseLeave; 869 result.button = WebMouseEvent::ButtonNone; 870 break; 871 case NSLeftMouseDown: 872 result.type = WebInputEvent::MouseDown; 873 result.clickCount = [event clickCount]; 874 result.button = WebMouseEvent::ButtonLeft; 875 break; 876 case NSOtherMouseDown: 877 result.type = WebInputEvent::MouseDown; 878 result.clickCount = [event clickCount]; 879 result.button = WebMouseEvent::ButtonMiddle; 880 break; 881 case NSRightMouseDown: 882 result.type = WebInputEvent::MouseDown; 883 result.clickCount = [event clickCount]; 884 result.button = WebMouseEvent::ButtonRight; 885 break; 886 case NSLeftMouseUp: 887 result.type = WebInputEvent::MouseUp; 888 result.clickCount = [event clickCount]; 889 result.button = WebMouseEvent::ButtonLeft; 890 break; 891 case NSOtherMouseUp: 892 result.type = WebInputEvent::MouseUp; 893 result.clickCount = [event clickCount]; 894 result.button = WebMouseEvent::ButtonMiddle; 895 break; 896 case NSRightMouseUp: 897 result.type = WebInputEvent::MouseUp; 898 result.clickCount = [event clickCount]; 899 result.button = WebMouseEvent::ButtonRight; 900 break; 901 case NSMouseMoved: 902 case NSMouseEntered: 903 result.type = WebInputEvent::MouseMove; 904 break; 905 case NSLeftMouseDragged: 906 result.type = WebInputEvent::MouseMove; 907 result.button = WebMouseEvent::ButtonLeft; 908 break; 909 case NSOtherMouseDragged: 910 result.type = WebInputEvent::MouseMove; 911 result.button = WebMouseEvent::ButtonMiddle; 912 break; 913 case NSRightMouseDragged: 914 result.type = WebInputEvent::MouseMove; 915 result.button = WebMouseEvent::ButtonRight; 916 break; 917 default: 918 ASSERT_NOT_REACHED(); 919 } 920 921 setWebEventLocationFromEventInView(&result, event, view); 922 923 result.modifiers = modifiersFromEvent(event); 924 925 result.timeStampSeconds = [event timestamp]; 926 927 return result; 928 } 929 930 // WebMouseWheelEvent --------------------------------------------------------- 931 932 static WebMouseWheelEvent::Phase phaseForNSEventPhase(NSEventPhase eventPhase) 933 { 934 uint32_t phase = WebMouseWheelEvent::PhaseNone; 935 if (eventPhase & NSEventPhaseBegan) 936 phase |= WebMouseWheelEvent::PhaseBegan; 937 if (eventPhase & NSEventPhaseStationary) 938 phase |= WebMouseWheelEvent::PhaseStationary; 939 if (eventPhase & NSEventPhaseChanged) 940 phase |= WebMouseWheelEvent::PhaseChanged; 941 if (eventPhase & NSEventPhaseEnded) 942 phase |= WebMouseWheelEvent::PhaseEnded; 943 if (eventPhase & NSEventPhaseCancelled) 944 phase |= WebMouseWheelEvent::PhaseCancelled; 945 if (eventPhase & NSEventPhaseMayBegin) 946 phase |= WebMouseWheelEvent::PhaseMayBegin; 947 return static_cast<WebMouseWheelEvent::Phase>(phase); 948 } 949 950 static WebMouseWheelEvent::Phase phaseForEvent(NSEvent *event) 951 { 952 if (![event respondsToSelector:@selector(phase)]) 953 return WebMouseWheelEvent::PhaseNone; 954 955 NSEventPhase eventPhase = [event phase]; 956 return phaseForNSEventPhase(eventPhase); 957 } 958 959 static WebMouseWheelEvent::Phase momentumPhaseForEvent(NSEvent *event) 960 { 961 if (![event respondsToSelector:@selector(momentumPhase)]) 962 return WebMouseWheelEvent::PhaseNone; 963 964 NSEventPhase eventMomentumPhase = [event momentumPhase]; 965 return phaseForNSEventPhase(eventMomentumPhase); 966 } 967 968 WebMouseWheelEvent WebInputEventFactory::mouseWheelEvent(NSEvent* event, NSView* view, bool canRubberbandLeft, bool canRubberbandRight) 969 { 970 WebMouseWheelEvent result; 971 972 result.type = WebInputEvent::MouseWheel; 973 result.button = WebMouseEvent::ButtonNone; 974 975 result.modifiers = modifiersFromEvent(event); 976 977 setWebEventLocationFromEventInView(&result, event, view); 978 979 result.canRubberbandLeft = canRubberbandLeft; 980 result.canRubberbandRight = canRubberbandRight; 981 982 // Of Mice and Men 983 // --------------- 984 // 985 // There are three types of scroll data available on a scroll wheel CGEvent. 986 // Apple's documentation ([1]) is rather vague in their differences, and not 987 // terribly helpful in deciding which to use. This is what's really going on. 988 // 989 // First, these events behave very differently depending on whether a standard 990 // wheel mouse is used (one that scrolls in discrete units) or a 991 // trackpad/Mighty Mouse is used (which both provide continuous scrolling). 992 // You must check to see which was used for the event by testing the 993 // kCGScrollWheelEventIsContinuous field. 994 // 995 // Second, these events refer to "axes". Axis 1 is the y-axis, and axis 2 is 996 // the x-axis. 997 // 998 // Third, there is a concept of mouse acceleration. Scrolling the same amount 999 // of physical distance will give you different results logically depending on 1000 // whether you scrolled a little at a time or in one continuous motion. Some 1001 // fields account for this while others do not. 1002 // 1003 // Fourth, for trackpads there is a concept of chunkiness. When scrolling 1004 // continuously, events can be delivered in chunks. That is to say, lots of 1005 // scroll events with delta 0 will be delivered, and every so often an event 1006 // with a non-zero delta will be delivered, containing the accumulated deltas 1007 // from all the intermediate moves. [2] 1008 // 1009 // For notchy wheel mice (kCGScrollWheelEventIsContinuous == 0) 1010 // ------------------------------------------------------------ 1011 // 1012 // kCGScrollWheelEventDeltaAxis* 1013 // This is the rawest of raw events. For each mouse notch you get a value of 1014 // +1/-1. This does not take acceleration into account and thus is less 1015 // useful for building UIs. 1016 // 1017 // kCGScrollWheelEventPointDeltaAxis* 1018 // This is smarter. In general, for each mouse notch you get a value of 1019 // +1/-1, but this _does_ take acceleration into account, so you will get 1020 // larger values on longer scrolls. This field would be ideal for building 1021 // UIs except for one nasty bug: when the shift key is pressed, this set of 1022 // fields fails to move the value into the axis2 field (the other two types 1023 // of data do). This wouldn't be so bad except for the fact that while the 1024 // number of axes is used in the creation of a CGScrollWheelEvent, there is 1025 // no way to get that information out of the event once created. 1026 // 1027 // kCGScrollWheelEventFixedPtDeltaAxis* 1028 // This is a fixed value, and for each mouse notch you get a value of 1029 // +0.1/-0.1 (but, like above, scaled appropriately for acceleration). This 1030 // value takes acceleration into account, and in fact is identical to the 1031 // results you get from -[NSEvent delta*]. (That is, if you linked on Tiger 1032 // or greater; see [2] for details.) 1033 // 1034 // A note about continuous devices 1035 // ------------------------------- 1036 // 1037 // There are two devices that provide continuous scrolling events (trackpads 1038 // and Mighty Mouses) and they behave rather differently. The Mighty Mouse 1039 // behaves a lot like a regular mouse. There is no chunking, and the 1040 // FixedPtDelta values are the PointDelta values multiplied by 0.1. With the 1041 // trackpad, though, there is chunking. While the FixedPtDelta values are 1042 // reasonable (they occur about every fifth event but have values five times 1043 // larger than usual) the Delta values are unreasonable. They don't appear to 1044 // accumulate properly. 1045 // 1046 // For continuous devices (kCGScrollWheelEventIsContinuous != 0) 1047 // ------------------------------------------------------------- 1048 // 1049 // kCGScrollWheelEventDeltaAxis* 1050 // This provides values with no acceleration. With a trackpad, these values 1051 // are chunked but each non-zero value does not appear to be cumulative. 1052 // This seems to be a bug. 1053 // 1054 // kCGScrollWheelEventPointDeltaAxis* 1055 // This provides values with acceleration. With a trackpad, these values are 1056 // not chunked and are highly accurate. 1057 // 1058 // kCGScrollWheelEventFixedPtDeltaAxis* 1059 // This provides values with acceleration. With a trackpad, these values are 1060 // chunked but unlike Delta events are properly cumulative. 1061 // 1062 // Summary 1063 // ------- 1064 // 1065 // In general the best approach to take is: determine if the event is 1066 // continuous. If it is not, then use the FixedPtDelta events (or just stick 1067 // with Cocoa events). They provide both acceleration and proper horizontal 1068 // scrolling. If the event is continuous, then doing pixel scrolling with the 1069 // PointDelta is the way to go. In general, avoid the Delta events. They're 1070 // the oldest (dating back to 10.4, before CGEvents were public) but they lack 1071 // acceleration and precision, making them useful only in specific edge cases. 1072 // 1073 // References 1074 // ---------- 1075 // 1076 // [1] <http://developer.apple.com/documentation/Carbon/Reference/QuartzEventServicesRef/Reference/reference.html> 1077 // [2] <http://developer.apple.com/releasenotes/Cocoa/AppKitOlderNotes.html> 1078 // Scroll to the section headed "NSScrollWheel events". 1079 // 1080 // P.S. The "smooth scrolling" option in the system preferences is utterly 1081 // unrelated to any of this. 1082 1083 CGEventRef cgEvent = [event CGEvent]; 1084 ASSERT(cgEvent); 1085 1086 // Wheel ticks are supposed to be raw, unaccelerated values, one per physical 1087 // mouse wheel notch. The delta event is perfect for this (being a good 1088 // "specific edge case" as mentioned above). Trackpads, unfortunately, do 1089 // event chunking, and sending mousewheel events with 0 ticks causes some 1090 // websites to malfunction. Therefore, for all continuous input devices we use 1091 // the point delta data instead, since we cannot distinguish trackpad data 1092 // from data from any other continuous device. 1093 1094 // Conversion between wheel delta amounts and number of pixels to scroll. 1095 static const double scrollbarPixelsPerCocoaTick = 40.0; 1096 1097 if (CGEventGetIntegerValueField(cgEvent, kCGScrollWheelEventIsContinuous)) { 1098 result.deltaX = CGEventGetIntegerValueField(cgEvent, kCGScrollWheelEventPointDeltaAxis2); 1099 result.deltaY = CGEventGetIntegerValueField(cgEvent, kCGScrollWheelEventPointDeltaAxis1); 1100 result.wheelTicksX = result.deltaX / scrollbarPixelsPerCocoaTick; 1101 result.wheelTicksY = result.deltaY / scrollbarPixelsPerCocoaTick; 1102 result.hasPreciseScrollingDeltas = true; 1103 } else { 1104 result.deltaX = [event deltaX] * scrollbarPixelsPerCocoaTick; 1105 result.deltaY = [event deltaY] * scrollbarPixelsPerCocoaTick; 1106 result.wheelTicksY = CGEventGetIntegerValueField(cgEvent, kCGScrollWheelEventDeltaAxis1); 1107 result.wheelTicksX = CGEventGetIntegerValueField(cgEvent, kCGScrollWheelEventDeltaAxis2); 1108 } 1109 1110 result.timeStampSeconds = [event timestamp]; 1111 1112 result.phase = phaseForEvent(event); 1113 result.momentumPhase = momentumPhaseForEvent(event); 1114 1115 return result; 1116 } 1117 1118 WebGestureEvent WebInputEventFactory::gestureEvent(NSEvent *event, NSView *view) 1119 { 1120 WebGestureEvent result; 1121 1122 // Use a temporary WebMouseEvent to get the location. 1123 WebMouseEvent temp; 1124 1125 setWebEventLocationFromEventInView(&temp, event, view); 1126 result.x = temp.x; 1127 result.y = temp.y; 1128 result.globalX = temp.globalX; 1129 result.globalY = temp.globalY; 1130 1131 result.modifiers = modifiersFromEvent(event); 1132 result.timeStampSeconds = [event timestamp]; 1133 1134 // MacOS X gestures are used only for pinch support. 1135 result.sourceDevice = WebGestureDeviceTouchpad; 1136 switch ([event type]) { 1137 case NSEventTypeMagnify: 1138 result.type = WebInputEvent::GesturePinchUpdate; 1139 result.data.pinchUpdate.scale = [event magnification] + 1.0; 1140 break; 1141 default: 1142 ASSERT_NOT_REACHED(); 1143 result.type = WebInputEvent::Undefined; 1144 } 1145 1146 return result; 1147 } 1148 1149 } // namespace blink 1150