# lib/goog/events/keycodes.js

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