| 1 | // Copyright 2006 The Closure Library Authors. All Rights Reserved. |
| 2 | // |
| 3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | // you may not use this file except in compliance with the License. |
| 5 | // You may obtain a copy of the License at |
| 6 | // |
| 7 | // http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | // |
| 9 | // Unless required by applicable law or agreed to in writing, software |
| 10 | // distributed under the License is distributed on an "AS-IS" BASIS, |
| 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | // See the License for the specific language governing permissions and |
| 13 | // limitations under the License. |
| 14 | |
| 15 | /** |
| 16 | * @fileoverview Constant declarations for common key codes. |
| 17 | * |
| 18 | * @author eae@google.com (Emil A Eklund) |
| 19 | * @see ../demos/keyhandler.html |
| 20 | */ |
| 21 | |
| 22 | goog.provide('goog.events.KeyCodes'); |
| 23 | |
| 24 | goog.require('goog.userAgent'); |
| 25 | |
| 26 | |
| 27 | /** |
| 28 | * Key codes for common characters. |
| 29 | * |
| 30 | * This list is not localized and therefore some of the key codes are not |
| 31 | * correct for non US keyboard layouts. See comments below. |
| 32 | * |
| 33 | * @enum {number} |
| 34 | */ |
| 35 | goog.events.KeyCodes = { |
| 36 | WIN_KEY_FF_LINUX: 0, |
| 37 | MAC_ENTER: 3, |
| 38 | BACKSPACE: 8, |
| 39 | TAB: 9, |
| 40 | NUM_CENTER: 12, // NUMLOCK on FF/Safari Mac |
| 41 | ENTER: 13, |
| 42 | SHIFT: 16, |
| 43 | CTRL: 17, |
| 44 | ALT: 18, |
| 45 | PAUSE: 19, |
| 46 | CAPS_LOCK: 20, |
| 47 | ESC: 27, |
| 48 | SPACE: 32, |
| 49 | PAGE_UP: 33, // also NUM_NORTH_EAST |
| 50 | PAGE_DOWN: 34, // also NUM_SOUTH_EAST |
| 51 | END: 35, // also NUM_SOUTH_WEST |
| 52 | HOME: 36, // also NUM_NORTH_WEST |
| 53 | LEFT: 37, // also NUM_WEST |
| 54 | UP: 38, // also NUM_NORTH |
| 55 | RIGHT: 39, // also NUM_EAST |
| 56 | DOWN: 40, // also NUM_SOUTH |
| 57 | PRINT_SCREEN: 44, |
| 58 | INSERT: 45, // also NUM_INSERT |
| 59 | DELETE: 46, // also NUM_DELETE |
| 60 | ZERO: 48, |
| 61 | ONE: 49, |
| 62 | TWO: 50, |
| 63 | THREE: 51, |
| 64 | FOUR: 52, |
| 65 | FIVE: 53, |
| 66 | SIX: 54, |
| 67 | SEVEN: 55, |
| 68 | EIGHT: 56, |
| 69 | NINE: 57, |
| 70 | FF_SEMICOLON: 59, // Firefox (Gecko) fires this for semicolon instead of 186 |
| 71 | FF_EQUALS: 61, // Firefox (Gecko) fires this for equals instead of 187 |
| 72 | FF_DASH: 173, // Firefox (Gecko) fires this for dash instead of 189 |
| 73 | QUESTION_MARK: 63, // needs localization |
| 74 | A: 65, |
| 75 | B: 66, |
| 76 | C: 67, |
| 77 | D: 68, |
| 78 | E: 69, |
| 79 | F: 70, |
| 80 | G: 71, |
| 81 | H: 72, |
| 82 | I: 73, |
| 83 | J: 74, |
| 84 | K: 75, |
| 85 | L: 76, |
| 86 | M: 77, |
| 87 | N: 78, |
| 88 | O: 79, |
| 89 | P: 80, |
| 90 | Q: 81, |
| 91 | R: 82, |
| 92 | S: 83, |
| 93 | T: 84, |
| 94 | U: 85, |
| 95 | V: 86, |
| 96 | W: 87, |
| 97 | X: 88, |
| 98 | Y: 89, |
| 99 | Z: 90, |
| 100 | META: 91, // WIN_KEY_LEFT |
| 101 | WIN_KEY_RIGHT: 92, |
| 102 | CONTEXT_MENU: 93, |
| 103 | NUM_ZERO: 96, |
| 104 | NUM_ONE: 97, |
| 105 | NUM_TWO: 98, |
| 106 | NUM_THREE: 99, |
| 107 | NUM_FOUR: 100, |
| 108 | NUM_FIVE: 101, |
| 109 | NUM_SIX: 102, |
| 110 | NUM_SEVEN: 103, |
| 111 | NUM_EIGHT: 104, |
| 112 | NUM_NINE: 105, |
| 113 | NUM_MULTIPLY: 106, |
| 114 | NUM_PLUS: 107, |
| 115 | NUM_MINUS: 109, |
| 116 | NUM_PERIOD: 110, |
| 117 | NUM_DIVISION: 111, |
| 118 | F1: 112, |
| 119 | F2: 113, |
| 120 | F3: 114, |
| 121 | F4: 115, |
| 122 | F5: 116, |
| 123 | F6: 117, |
| 124 | F7: 118, |
| 125 | F8: 119, |
| 126 | F9: 120, |
| 127 | F10: 121, |
| 128 | F11: 122, |
| 129 | F12: 123, |
| 130 | NUMLOCK: 144, |
| 131 | SCROLL_LOCK: 145, |
| 132 | |
| 133 | // OS-specific media keys like volume controls and browser controls. |
| 134 | FIRST_MEDIA_KEY: 166, |
| 135 | LAST_MEDIA_KEY: 183, |
| 136 | |
| 137 | SEMICOLON: 186, // needs localization |
| 138 | DASH: 189, // needs localization |
| 139 | EQUALS: 187, // needs localization |
| 140 | COMMA: 188, // needs localization |
| 141 | PERIOD: 190, // needs localization |
| 142 | SLASH: 191, // needs localization |
| 143 | APOSTROPHE: 192, // needs localization |
| 144 | TILDE: 192, // needs localization |
| 145 | SINGLE_QUOTE: 222, // needs localization |
| 146 | OPEN_SQUARE_BRACKET: 219, // needs localization |
| 147 | BACKSLASH: 220, // needs localization |
| 148 | CLOSE_SQUARE_BRACKET: 221, // needs localization |
| 149 | WIN_KEY: 224, |
| 150 | MAC_FF_META: 224, // Firefox (Gecko) fires this for the meta key instead of 91 |
| 151 | MAC_WK_CMD_LEFT: 91, // WebKit Left Command key fired, same as META |
| 152 | MAC_WK_CMD_RIGHT: 93, // WebKit Right Command key fired, different from META |
| 153 | WIN_IME: 229, |
| 154 | |
| 155 | // We've seen users whose machines fire this keycode at regular one |
| 156 | // second intervals. The common thread among these users is that |
| 157 | // they're all using Dell Inspiron laptops, so we suspect that this |
| 158 | // indicates a hardware/bios problem. |
| 159 | // http://en.community.dell.com/support-forums/laptop/f/3518/p/19285957/19523128.aspx |
| 160 | PHANTOM: 255 |
| 161 | }; |
| 162 | |
| 163 | |
| 164 | /** |
| 165 | * Returns true if the event contains a text modifying key. |
| 166 | * @param {goog.events.BrowserEvent} e A key event. |
| 167 | * @return {boolean} Whether it's a text modifying key. |
| 168 | */ |
| 169 | goog.events.KeyCodes.isTextModifyingKeyEvent = function(e) { |
| 170 | if (e.altKey && !e.ctrlKey || |
| 171 | e.metaKey || |
| 172 | // Function keys don't generate text |
| 173 | e.keyCode >= goog.events.KeyCodes.F1 && |
| 174 | e.keyCode <= goog.events.KeyCodes.F12) { |
| 175 | return false; |
| 176 | } |
| 177 | |
| 178 | // The following keys are quite harmless, even in combination with |
| 179 | // CTRL, ALT or SHIFT. |
| 180 | switch (e.keyCode) { |
| 181 | case goog.events.KeyCodes.ALT: |
| 182 | case goog.events.KeyCodes.CAPS_LOCK: |
| 183 | case goog.events.KeyCodes.CONTEXT_MENU: |
| 184 | case goog.events.KeyCodes.CTRL: |
| 185 | case goog.events.KeyCodes.DOWN: |
| 186 | case goog.events.KeyCodes.END: |
| 187 | case goog.events.KeyCodes.ESC: |
| 188 | case goog.events.KeyCodes.HOME: |
| 189 | case goog.events.KeyCodes.INSERT: |
| 190 | case goog.events.KeyCodes.LEFT: |
| 191 | case goog.events.KeyCodes.MAC_FF_META: |
| 192 | case goog.events.KeyCodes.META: |
| 193 | case goog.events.KeyCodes.NUMLOCK: |
| 194 | case goog.events.KeyCodes.NUM_CENTER: |
| 195 | case goog.events.KeyCodes.PAGE_DOWN: |
| 196 | case goog.events.KeyCodes.PAGE_UP: |
| 197 | case goog.events.KeyCodes.PAUSE: |
| 198 | case goog.events.KeyCodes.PHANTOM: |
| 199 | case goog.events.KeyCodes.PRINT_SCREEN: |
| 200 | case goog.events.KeyCodes.RIGHT: |
| 201 | case goog.events.KeyCodes.SCROLL_LOCK: |
| 202 | case goog.events.KeyCodes.SHIFT: |
| 203 | case goog.events.KeyCodes.UP: |
| 204 | case goog.events.KeyCodes.WIN_KEY: |
| 205 | case goog.events.KeyCodes.WIN_KEY_RIGHT: |
| 206 | return false; |
| 207 | case goog.events.KeyCodes.WIN_KEY_FF_LINUX: |
| 208 | return !goog.userAgent.GECKO; |
| 209 | default: |
| 210 | return e.keyCode < goog.events.KeyCodes.FIRST_MEDIA_KEY || |
| 211 | e.keyCode > goog.events.KeyCodes.LAST_MEDIA_KEY; |
| 212 | } |
| 213 | }; |
| 214 | |
| 215 | |
| 216 | /** |
| 217 | * Returns true if the key fires a keypress event in the current browser. |
| 218 | * |
| 219 | * Accoridng to MSDN [1] IE only fires keypress events for the following keys: |
| 220 | * - Letters: A - Z (uppercase and lowercase) |
| 221 | * - Numerals: 0 - 9 |
| 222 | * - Symbols: ! @ # $ % ^ & * ( ) _ - + = < [ ] { } , . / ? \ | ' ` " ~ |
| 223 | * - System: ESC, SPACEBAR, ENTER |
| 224 | * |
| 225 | * That's not entirely correct though, for instance there's no distinction |
| 226 | * between upper and lower case letters. |
| 227 | * |
| 228 | * [1] http://msdn2.microsoft.com/en-us/library/ms536939(VS.85).aspx) |
| 229 | * |
| 230 | * Safari is similar to IE, but does not fire keypress for ESC. |
| 231 | * |
| 232 | * Additionally, IE6 does not fire keydown or keypress events for letters when |
| 233 | * the control or alt keys are held down and the shift key is not. IE7 does |
| 234 | * fire keydown in these cases, though, but not keypress. |
| 235 | * |
| 236 | * @param {number} keyCode A key code. |
| 237 | * @param {number=} opt_heldKeyCode Key code of a currently-held key. |
| 238 | * @param {boolean=} opt_shiftKey Whether the shift key is held down. |
| 239 | * @param {boolean=} opt_ctrlKey Whether the control key is held down. |
| 240 | * @param {boolean=} opt_altKey Whether the alt key is held down. |
| 241 | * @return {boolean} Whether it's a key that fires a keypress event. |
| 242 | */ |
| 243 | goog.events.KeyCodes.firesKeyPressEvent = function(keyCode, opt_heldKeyCode, |
| 244 | opt_shiftKey, opt_ctrlKey, opt_altKey) { |
| 245 | if (!goog.userAgent.IE && |
| 246 | !(goog.userAgent.WEBKIT && goog.userAgent.isVersionOrHigher('525'))) { |
| 247 | return true; |
| 248 | } |
| 249 | |
| 250 | if (goog.userAgent.MAC && opt_altKey) { |
| 251 | return goog.events.KeyCodes.isCharacterKey(keyCode); |
| 252 | } |
| 253 | |
| 254 | // Alt but not AltGr which is represented as Alt+Ctrl. |
| 255 | if (opt_altKey && !opt_ctrlKey) { |
| 256 | return false; |
| 257 | } |
| 258 | |
| 259 | // Saves Ctrl or Alt + key for IE and WebKit 525+, which won't fire keypress. |
| 260 | // Non-IE browsers and WebKit prior to 525 won't get this far so no need to |
| 261 | // check the user agent. |
| 262 | if (goog.isNumber(opt_heldKeyCode)) { |
| 263 | opt_heldKeyCode = goog.events.KeyCodes.normalizeKeyCode(opt_heldKeyCode); |
| 264 | } |
| 265 | if (!opt_shiftKey && |
| 266 | (opt_heldKeyCode == goog.events.KeyCodes.CTRL || |
| 267 | opt_heldKeyCode == goog.events.KeyCodes.ALT || |
| 268 | goog.userAgent.MAC && |
| 269 | opt_heldKeyCode == goog.events.KeyCodes.META)) { |
| 270 | return false; |
| 271 | } |
| 272 | |
| 273 | // Some keys with Ctrl/Shift do not issue keypress in WEBKIT. |
| 274 | if (goog.userAgent.WEBKIT && opt_ctrlKey && opt_shiftKey) { |
| 275 | switch (keyCode) { |
| 276 | case goog.events.KeyCodes.BACKSLASH: |
| 277 | case goog.events.KeyCodes.OPEN_SQUARE_BRACKET: |
| 278 | case goog.events.KeyCodes.CLOSE_SQUARE_BRACKET: |
| 279 | case goog.events.KeyCodes.TILDE: |
| 280 | case goog.events.KeyCodes.SEMICOLON: |
| 281 | case goog.events.KeyCodes.DASH: |
| 282 | case goog.events.KeyCodes.EQUALS: |
| 283 | case goog.events.KeyCodes.COMMA: |
| 284 | case goog.events.KeyCodes.PERIOD: |
| 285 | case goog.events.KeyCodes.SLASH: |
| 286 | case goog.events.KeyCodes.APOSTROPHE: |
| 287 | case goog.events.KeyCodes.SINGLE_QUOTE: |
| 288 | return false; |
| 289 | } |
| 290 | } |
| 291 | |
| 292 | // When Ctrl+<somekey> is held in IE, it only fires a keypress once, but it |
| 293 | // continues to fire keydown events as the event repeats. |
| 294 | if (goog.userAgent.IE && opt_ctrlKey && opt_heldKeyCode == keyCode) { |
| 295 | return false; |
| 296 | } |
| 297 | |
| 298 | switch (keyCode) { |
| 299 | case goog.events.KeyCodes.ENTER: |
| 300 | return true; |
| 301 | case goog.events.KeyCodes.ESC: |
| 302 | return !goog.userAgent.WEBKIT; |
| 303 | } |
| 304 | |
| 305 | return goog.events.KeyCodes.isCharacterKey(keyCode); |
| 306 | }; |
| 307 | |
| 308 | |
| 309 | /** |
| 310 | * Returns true if the key produces a character. |
| 311 | * This does not cover characters on non-US keyboards (Russian, Hebrew, etc.). |
| 312 | * |
| 313 | * @param {number} keyCode A key code. |
| 314 | * @return {boolean} Whether it's a character key. |
| 315 | */ |
| 316 | goog.events.KeyCodes.isCharacterKey = function(keyCode) { |
| 317 | if (keyCode >= goog.events.KeyCodes.ZERO && |
| 318 | keyCode <= goog.events.KeyCodes.NINE) { |
| 319 | return true; |
| 320 | } |
| 321 | |
| 322 | if (keyCode >= goog.events.KeyCodes.NUM_ZERO && |
| 323 | keyCode <= goog.events.KeyCodes.NUM_MULTIPLY) { |
| 324 | return true; |
| 325 | } |
| 326 | |
| 327 | if (keyCode >= goog.events.KeyCodes.A && |
| 328 | keyCode <= goog.events.KeyCodes.Z) { |
| 329 | return true; |
| 330 | } |
| 331 | |
| 332 | // Safari sends zero key code for non-latin characters. |
| 333 | if (goog.userAgent.WEBKIT && keyCode == 0) { |
| 334 | return true; |
| 335 | } |
| 336 | |
| 337 | switch (keyCode) { |
| 338 | case goog.events.KeyCodes.SPACE: |
| 339 | case goog.events.KeyCodes.QUESTION_MARK: |
| 340 | case goog.events.KeyCodes.NUM_PLUS: |
| 341 | case goog.events.KeyCodes.NUM_MINUS: |
| 342 | case goog.events.KeyCodes.NUM_PERIOD: |
| 343 | case goog.events.KeyCodes.NUM_DIVISION: |
| 344 | case goog.events.KeyCodes.SEMICOLON: |
| 345 | case goog.events.KeyCodes.FF_SEMICOLON: |
| 346 | case goog.events.KeyCodes.DASH: |
| 347 | case goog.events.KeyCodes.EQUALS: |
| 348 | case goog.events.KeyCodes.FF_EQUALS: |
| 349 | case goog.events.KeyCodes.COMMA: |
| 350 | case goog.events.KeyCodes.PERIOD: |
| 351 | case goog.events.KeyCodes.SLASH: |
| 352 | case goog.events.KeyCodes.APOSTROPHE: |
| 353 | case goog.events.KeyCodes.SINGLE_QUOTE: |
| 354 | case goog.events.KeyCodes.OPEN_SQUARE_BRACKET: |
| 355 | case goog.events.KeyCodes.BACKSLASH: |
| 356 | case goog.events.KeyCodes.CLOSE_SQUARE_BRACKET: |
| 357 | return true; |
| 358 | default: |
| 359 | return false; |
| 360 | } |
| 361 | }; |
| 362 | |
| 363 | |
| 364 | /** |
| 365 | * Normalizes key codes from OS/Browser-specific value to the general one. |
| 366 | * @param {number} keyCode The native key code. |
| 367 | * @return {number} The normalized key code. |
| 368 | */ |
| 369 | goog.events.KeyCodes.normalizeKeyCode = function(keyCode) { |
| 370 | if (goog.userAgent.GECKO) { |
| 371 | return goog.events.KeyCodes.normalizeGeckoKeyCode(keyCode); |
| 372 | } else if (goog.userAgent.MAC && goog.userAgent.WEBKIT) { |
| 373 | return goog.events.KeyCodes.normalizeMacWebKitKeyCode(keyCode); |
| 374 | } else { |
| 375 | return keyCode; |
| 376 | } |
| 377 | }; |
| 378 | |
| 379 | |
| 380 | /** |
| 381 | * Normalizes key codes from their Gecko-specific value to the general one. |
| 382 | * @param {number} keyCode The native key code. |
| 383 | * @return {number} The normalized key code. |
| 384 | */ |
| 385 | goog.events.KeyCodes.normalizeGeckoKeyCode = function(keyCode) { |
| 386 | switch (keyCode) { |
| 387 | case goog.events.KeyCodes.FF_EQUALS: |
| 388 | return goog.events.KeyCodes.EQUALS; |
| 389 | case goog.events.KeyCodes.FF_SEMICOLON: |
| 390 | return goog.events.KeyCodes.SEMICOLON; |
| 391 | case goog.events.KeyCodes.FF_DASH: |
| 392 | return goog.events.KeyCodes.DASH; |
| 393 | case goog.events.KeyCodes.MAC_FF_META: |
| 394 | return goog.events.KeyCodes.META; |
| 395 | case goog.events.KeyCodes.WIN_KEY_FF_LINUX: |
| 396 | return goog.events.KeyCodes.WIN_KEY; |
| 397 | default: |
| 398 | return keyCode; |
| 399 | } |
| 400 | }; |
| 401 | |
| 402 | |
| 403 | /** |
| 404 | * Normalizes key codes from their Mac WebKit-specific value to the general one. |
| 405 | * @param {number} keyCode The native key code. |
| 406 | * @return {number} The normalized key code. |
| 407 | */ |
| 408 | goog.events.KeyCodes.normalizeMacWebKitKeyCode = function(keyCode) { |
| 409 | switch (keyCode) { |
| 410 | case goog.events.KeyCodes.MAC_WK_CMD_RIGHT: // 93 |
| 411 | return goog.events.KeyCodes.META; // 91 |
| 412 | default: |
| 413 | return keyCode; |
| 414 | } |
| 415 | }; |