Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / chrome / browser / resources / chromeos / keyboard_overlay.js
blob3447f7dec981a639e4e6ba2e3503e7979a464cc3
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 <include src="keyboard_overlay_data.js">
6 <include src="keyboard_overlay_accessibility_helper.js">
8 var BASE_KEYBOARD = {
9   top: 0,
10   left: 0,
11   width: 1237,
12   height: 514
15 var BASE_INSTRUCTIONS = {
16   top: 194,
17   left: 370,
18   width: 498,
19   height: 142
22 var MODIFIER_TO_CLASS = {
23   'SHIFT': 'modifier-shift',
24   'CTRL': 'modifier-ctrl',
25   'ALT': 'modifier-alt',
26   'SEARCH': 'modifier-search'
29 var IDENTIFIER_TO_CLASS = {
30   '2A': 'is-shift',
31   '36': 'is-shift',
32   '1D': 'is-ctrl',
33   'E0 1D': 'is-ctrl',
34   '38': 'is-alt',
35   'E0 38': 'is-alt',
36   'E0 5B': 'is-search'
39 var LABEL_TO_IDENTIFIER = {
40   'search': 'E0 5B',
41   'ctrl': '1D',
42   'alt': '38',
43   'caps lock': '3A',
44   'esc': '01',
45   'disabled': 'DISABLED'
48 var KEYCODE_TO_LABEL = {
49   8: 'backspace',
50   9: 'tab',
51   13: 'enter',
52   27: 'esc',
53   32: 'space',
54   33: 'pageup',
55   34: 'pagedown',
56   35: 'end',
57   36: 'home',
58   37: 'left',
59   38: 'up',
60   39: 'right',
61   40: 'down',
62   46: 'delete',
63   91: 'search',
64   92: 'search',
65   96: '0',
66   97: '1',
67   98: '2',
68   99: '3',
69   100: '4',
70   101: '5',
71   102: '6',
72   103: '7',
73   104: '8',
74   105: '9',
75   106: '*',
76   107: '+',
77   109: '-',
78   110: '.',
79   111: '/',
80   112: 'back',
81   113: 'forward',
82   114: 'reload',
83   115: 'full screen',
84   116: 'switch window',
85   117: 'bright down',
86   118: 'bright up',
87   119: 'mute',
88   120: 'vol. down',
89   121: 'vol. up',
90   186: ';',
91   187: '+',
92   188: ',',
93   189: '-',
94   190: '.',
95   191: '/',
96   192: '`',
97   219: '[',
98   220: '\\',
99   221: ']',
100   222: '\'',
104  * Some key labels define actions (like for example 'vol. up' or 'mute').
105  * These labels should be localized. (crbug.com/471025).
106  */
107 var LABEL_TO_LOCALIZED_LABEL_ID = {
108   'esc' : 'keyboardOverlayEscKeyLabel',
109   'back' : 'keyboardOverlayBackKeyLabel',
110   'forward' : 'keyboardOverlayForwardKeyLabel',
111   'reload' : 'keyboardOverlayReloadKeyLabel',
112   'full screen' : 'keyboardOverlayFullScreenKeyLabel',
113   'switch window' : 'keyboardOverlaySwitchWinKeyLabel',
114   'bright down' : 'keyboardOverlayBrightDownKeyLabel',
115   'bright up' : 'keyboardOverlayBrightUpKeyLabel',
116   'mute' : 'keyboardOverlayMuteKeyLabel',
117   'vol. down' : 'keyboardOverlayVolDownKeyLabel',
118   'vol. up' : 'keyboardOverlayVolUpKeyLabel',
119   'power' : 'keyboardOverlayPowerKeyLabel',
120   'backspace' : 'keyboardOverlayBackspaceKeyLabel',
121   'tab' : 'keyboardOverlayTabKeyLabel',
122   'search' : 'keyboardOverlaySearchKeyLabel',
123   'enter' : 'keyboardOverlayEnterKeyLabel',
124   'shift' : 'keyboardOverlayShiftKeyLabel',
125   'ctrl' : 'keyboardOverlayCtrlKeyLabel',
126   'alt' : 'keyboardOverlayAltKeyLabel',
127   'left' : 'keyboardOverlayLeftKeyLabel',
128   'right' : 'keyboardOverlayRightKeyLabel',
129   'up' : 'keyboardOverlayUpKeyLabel',
130   'down' : 'keyboardOverlayDownKeyLabel',
133 var IME_ID_PREFIX = '_comp_ime_';
134 var EXTENSION_ID_LEN = 32;
136 var keyboardOverlayId = 'en_US';
137 var identifierMap = {};
140  * True after at least one keydown event has been received.
141  */
142 var gotKeyDown = false;
145  * Returns the layout name.
146  * @return {string} layout name.
147  */
148 function getLayoutName() {
149   return getKeyboardGlyphData().layoutName;
153  * Returns layout data.
154  * @return {Array} Keyboard layout data.
155  */
156 function getLayout() {
157   return keyboardOverlayData['layouts'][getLayoutName()];
160 // Cache the shortcut data after it is constructed.
161 var shortcutDataCache;
164  * Returns shortcut data.
165  * @return {Object} Keyboard shortcut data.
166  */
167 function getShortcutData() {
168   if (shortcutDataCache)
169     return shortcutDataCache;
171   shortcutDataCache = keyboardOverlayData['shortcut'];
173   if (!isDisplayUIScalingEnabled()) {
174     // Zoom screen in
175     delete shortcutDataCache['+<>CTRL<>SHIFT'];
176     // Zoom screen out
177     delete shortcutDataCache['-<>CTRL<>SHIFT'];
178     // Reset screen zoom
179     delete shortcutDataCache['0<>CTRL<>SHIFT'];
180   }
182   return shortcutDataCache;
186  * Returns the keyboard overlay ID.
187  * @return {string} Keyboard overlay ID.
188  */
189 function getKeyboardOverlayId() {
190   return keyboardOverlayId;
194  * Returns keyboard glyph data.
195  * @return {Object} Keyboard glyph data.
196  */
197 function getKeyboardGlyphData() {
198   return keyboardOverlayData['keyboardGlyph'][getKeyboardOverlayId()];
202  * Converts a single hex number to a character.
203  * @param {string} hex Hexadecimal string.
204  * @return {string} Unicode values of hexadecimal string.
205  */
206 function hex2char(hex) {
207   if (!hex) {
208     return '';
209   }
210   var result = '';
211   var n = parseInt(hex, 16);
212   if (n <= 0xFFFF) {
213     result += String.fromCharCode(n);
214   } else if (n <= 0x10FFFF) {
215     n -= 0x10000;
216     result += (String.fromCharCode(0xD800 | (n >> 10)) +
217                String.fromCharCode(0xDC00 | (n & 0x3FF)));
218   } else {
219     console.error('hex2Char error: Code point out of range :' + hex);
220   }
221   return result;
225  * Returns a list of modifiers normalized to ignore the distinction between
226  * right or left keys.
227  * @param {Array} modifiers List of modifiers with distinction between right
228  *        and left keys.
229  * @return {Array} List of normalized modifiers ignoring the difference between
230  *         right or left keys.
231  */
232 function normalizeModifiers(modifiers) {
233   var result = [];
234   if (contains(modifiers, 'L_SHIFT') || contains(modifiers, 'R_SHIFT')) {
235     result.push('SHIFT');
236   }
237   if (contains(modifiers, 'L_CTRL') || contains(modifiers, 'R_CTRL')) {
238     result.push('CTRL');
239   }
240   if (contains(modifiers, 'L_ALT') || contains(modifiers, 'R_ALT')) {
241     result.push('ALT');
242   }
243   if (contains(modifiers, 'SEARCH')) {
244     result.push('SEARCH');
245   }
246   return result.sort();
250  * This table will contain the status of the modifiers.
251  */
252 var isPressed = {
253   'L_SHIFT': false,
254   'R_SHIFT': false,
255   'L_CTRL': false,
256   'R_CTRL': false,
257   'L_ALT': false,
258   'R_ALT': false,
259   'SEARCH': false,
263  * Returns a list of modifiers from the key event distinguishing right and left
264  * keys.
265  * @param {Event} e The key event.
266  * @return {Array} List of modifiers based on key event.
267  */
268 function getModifiers(e) {
269   if (!e)
270     return [];
272   var keyCodeToModifier = {
273     16: 'SHIFT',
274     17: 'CTRL',
275     18: 'ALT',
276     91: 'SEARCH',
277   };
278   var modifierWithKeyCode = keyCodeToModifier[e.keyCode];
279   /** @const */ var DOM_KEY_LOCATION_LEFT = 1;
280   var side = (e.location == DOM_KEY_LOCATION_LEFT) ? 'L_' : 'R_';
281   var isKeyDown = (e.type == 'keydown');
283   if (modifierWithKeyCode == 'SEARCH') {
284     isPressed['SEARCH'] = isKeyDown;
285   } else {
286     isPressed[side + modifierWithKeyCode] = isKeyDown;
287   }
289   // make the result array
290   return result = ['L_SHIFT', 'R_SHIFT', 'L_CTRL', 'R_CTRL', 'L_ALT', 'R_ALT',
291           'SEARCH'].filter(
292       function(modifier) {
293         return isPressed[modifier];
294       }).sort();
298  * Returns an ID of the key.
299  * @param {string} identifier Key identifier.
300  * @param {number} i Key number.
301  * @return {string} Key ID.
302  */
303 function keyId(identifier, i) {
304   return identifier + '-key-' + i;
308  * Returns an ID of the text on the key.
309  * @param {string} identifier Key identifier.
310  * @param {number} i Key number.
311  * @return {string} Key text ID.
312  */
313 function keyTextId(identifier, i) {
314   return identifier + '-key-text-' + i;
318  * Returns an ID of the shortcut text.
319  * @param {string} identifier Key identifier.
320  * @param {number} i Key number.
321  * @return {string} Key shortcut text ID.
322  */
323 function shortcutTextId(identifier, i) {
324   return identifier + '-shortcut-text-' + i;
328  * Returns true if |list| contains |e|.
329  * @param {Array} list Container list.
330  * @param {string} e Element string.
331  * @return {boolean} Returns true if the list contains the element.
332  */
333 function contains(list, e) {
334   return list.indexOf(e) != -1;
338  * Returns a list of the class names corresponding to the identifier and
339  * modifiers.
340  * @param {string} identifier Key identifier.
341  * @param {Array} modifiers List of key modifiers (with distinction between
342  *                right and left keys).
343  * @param {Array} normalizedModifiers List of key modifiers (without distinction
344  *                between right or left keys).
345  * @return {Array} List of class names corresponding to specified params.
346  */
347 function getKeyClasses(identifier, modifiers, normalizedModifiers) {
348   var classes = ['keyboard-overlay-key'];
349   for (var i = 0; i < normalizedModifiers.length; ++i) {
350     classes.push(MODIFIER_TO_CLASS[normalizedModifiers[i]]);
351   }
353   if ((identifier == '2A' && contains(modifiers, 'L_SHIFT')) ||
354       (identifier == '36' && contains(modifiers, 'R_SHIFT')) ||
355       (identifier == '1D' && contains(modifiers, 'L_CTRL')) ||
356       (identifier == 'E0 1D' && contains(modifiers, 'R_CTRL')) ||
357       (identifier == '38' && contains(modifiers, 'L_ALT')) ||
358       (identifier == 'E0 38' && contains(modifiers, 'R_ALT')) ||
359       (identifier == 'E0 5B' && contains(modifiers, 'SEARCH'))) {
360     classes.push('pressed');
361     classes.push(IDENTIFIER_TO_CLASS[identifier]);
362   }
363   return classes;
367  * Returns true if a character is a ASCII character.
368  * @param {string} c A character to be checked.
369  * @return {boolean} True if the character is an ASCII character.
370  */
371 function isAscii(c) {
372   var charCode = c.charCodeAt(0);
373   return 0x00 <= charCode && charCode <= 0x7F;
377  * Returns a remapped identiifer based on the preference.
378  * @param {string} identifier Key identifier.
379  * @return {string} Remapped identifier.
380  */
381 function remapIdentifier(identifier) {
382   return identifierMap[identifier] || identifier;
386  * Returns a label of the key.
387  * @param {string} keyData Key glyph data.
388  * @param {Array} modifiers Key Modifier list.
389  * @return {string} Label of the key.
390  */
391 function getKeyLabel(keyData, modifiers) {
392   if (!keyData) {
393     return '';
394   }
395   if (keyData.label) {
396     return keyData.label;
397   }
398   var keyLabel = '';
399   for (var j = 1; j <= 9; j++) {
400     var pos = keyData['p' + j];
401     if (!pos) {
402       continue;
403     }
404     keyLabel = hex2char(pos);
405     if (!keyLabel) {
406       continue;
407      }
408     if (isAscii(keyLabel) &&
409         getShortcutData()[getAction(keyLabel, modifiers)]) {
410       break;
411     }
412   }
413   return keyLabel;
417  * Returns a normalized string used for a key of shortcutData.
419  * Examples:
420  *   keyCode: 'd', modifiers: ['CTRL', 'SHIFT'] => 'd<>CTRL<>SHIFT'
421  *   keyCode: 'alt', modifiers: ['ALT', 'SHIFT'] => 'ALT<>SHIFT'
423  * @param {string} keyCode Key code.
424  * @param {Array} modifiers Key Modifier list.
425  * @return {string} Normalized key shortcut data string.
426  */
427 function getAction(keyCode, modifiers) {
428   /** @const */ var separatorStr = '<>';
429   if (keyCode.toUpperCase() in MODIFIER_TO_CLASS) {
430     keyCode = keyCode.toUpperCase();
431     if (keyCode in modifiers) {
432       return modifiers.join(separatorStr);
433     } else {
434       var action = [keyCode].concat(modifiers);
435       action.sort();
436       return action.join(separatorStr);
437     }
438   }
439   return [keyCode].concat(modifiers).join(separatorStr);
443  * Returns a text which displayed on a key.
444  * @param {string} keyData Key glyph data.
445  * @return {string} Key text value.
446  */
447 function getKeyTextValue(keyData) {
448   if (keyData.label) {
449     // Do not show text on the space key.
450     if (keyData.label == 'space') {
451       return '';
452     }
453     // some key labels define actions such as 'mute' or 'vol. up'. Those actions
454     // should be localized (crbug.com/471025).
455     var localizedLabel = LABEL_TO_LOCALIZED_LABEL_ID[keyData.label];
456     if (localizedLabel)
457       return loadTimeData.getString(localizedLabel);
459     return keyData.label;
460   }
462   var chars = [];
463   for (var j = 1; j <= 9; ++j) {
464     var pos = keyData['p' + j];
465     if (pos && pos.length > 0) {
466       chars.push(hex2char(pos));
467     }
468   }
469   return chars.join(' ');
473  * Updates the whole keyboard.
474  * @param {Array} modifiers Key Modifier list.
475  * @param {Array} normModifiers Key Modifier list ignoring the distinction
476  *                between right and left keys.
477  */
478 function update(modifiers, normModifiers) {
479   var instructions = $('instructions');
480   if (modifiers.length == 0) {
481     instructions.style.visibility = 'visible';
482   } else {
483     instructions.style.visibility = 'hidden';
484   }
486   var keyboardGlyphData = getKeyboardGlyphData();
487   var shortcutData = getShortcutData();
488   var layout = getLayout();
489   for (var i = 0; i < layout.length; ++i) {
490     var identifier = remapIdentifier(layout[i][0]);
491     var keyData = keyboardGlyphData.keys[identifier];
492     var classes = getKeyClasses(identifier, modifiers, normModifiers);
493     var keyLabel = getKeyLabel(keyData, normModifiers);
494     var shortcutId = shortcutData[getAction(keyLabel, normModifiers)];
495     if (modifiers.length == 0 &&
496         (identifier == '2A' || identifier == '36')) {
497       // Either the right or left shift keys are used to disable the caps lock
498       // if it was enabled. To fix crbug.com/453623.
499       shortcutId = 'keyboardOverlayDisableCapsLock';
500     }
501     if (shortcutId) {
502       classes.push('is-shortcut');
503     }
505     var key = $(keyId(identifier, i));
506     key.className = classes.join(' ');
508     if (!keyData) {
509       continue;
510     }
512     var keyText = $(keyTextId(identifier, i));
513     var keyTextValue = getKeyTextValue(keyData);
514     if (keyTextValue) {
515        keyText.style.visibility = 'visible';
516     } else {
517        keyText.style.visibility = 'hidden';
518     }
519     keyText.textContent = keyTextValue;
521     var shortcutText = $(shortcutTextId(identifier, i));
522     if (shortcutId) {
523       shortcutText.style.visibility = 'visible';
524       shortcutText.textContent = loadTimeData.getString(shortcutId);
525     } else {
526       shortcutText.style.visibility = 'hidden';
527     }
529     var format = keyboardGlyphData.keys[layout[i][0]].format;
530     if (format) {
531       if (format == 'left' || format == 'right') {
532         shortcutText.style.textAlign = format;
533         keyText.style.textAlign = format;
534       }
535     }
536   }
540  * A callback function for onkeydown and onkeyup events.
541  * @param {Event} e Key event.
542  */
543 function handleKeyEvent(e) {
544   if (!getKeyboardOverlayId()) {
545     return;
546   }
548   var modifiers = getModifiers(e);
550   // To avoid flickering as the user releases the modifier keys that were held
551   // to trigger the overlay, avoid updating in response to keyup events until at
552   // least one keydown event has been received.
553   if (!gotKeyDown) {
554     if (e.type == 'keyup') {
555       return;
556     } else if (e.type == 'keydown') {
557       gotKeyDown = true;
558     }
559   }
561   var normModifiers = normalizeModifiers(modifiers);
562   update(modifiers, normModifiers);
563   KeyboardOverlayAccessibilityHelper.maybeSpeakAllShortcuts(normModifiers);
564   e.preventDefault();
568  * Initializes the layout of the keys.
569  */
570 function initLayout() {
571   // Add data for the caps lock key
572   var keys = getKeyboardGlyphData().keys;
573   if (!('3A' in keys)) {
574     keys['3A'] = {label: 'caps lock', format: 'left'};
575   }
576   // Add data for the special key representing a disabled key
577   keys['DISABLED'] = {label: 'disabled', format: 'left'};
579   var layout = getLayout();
580   var keyboard = document.body;
581   var minX = window.innerWidth;
582   var maxX = 0;
583   var minY = window.innerHeight;
584   var maxY = 0;
585   var multiplier = 1.38 * window.innerWidth / BASE_KEYBOARD.width;
586   var keyMargin = 7;
587   var offsetX = 10;
588   var offsetY = 7;
589   for (var i = 0; i < layout.length; i++) {
590     var array = layout[i];
591     var identifier = remapIdentifier(array[0]);
592     var x = Math.round((array[1] + offsetX) * multiplier);
593     var y = Math.round((array[2] + offsetY) * multiplier);
594     var w = Math.round((array[3] - keyMargin) * multiplier);
595     var h = Math.round((array[4] - keyMargin) * multiplier);
597     var key = document.createElement('div');
598     key.id = keyId(identifier, i);
599     key.className = 'keyboard-overlay-key';
600     key.style.left = x + 'px';
601     key.style.top = y + 'px';
602     key.style.width = w + 'px';
603     key.style.height = h + 'px';
605     var keyText = document.createElement('div');
606     keyText.id = keyTextId(identifier, i);
607     keyText.className = 'keyboard-overlay-key-text';
608     keyText.style.visibility = 'hidden';
609     key.appendChild(keyText);
611     var shortcutText = document.createElement('div');
612     shortcutText.id = shortcutTextId(identifier, i);
613     shortcutText.className = 'keyboard-overlay-shortcut-text';
614     shortcutText.style.visilibity = 'hidden';
615     key.appendChild(shortcutText);
616     keyboard.appendChild(key);
618     minX = Math.min(minX, x);
619     maxX = Math.max(maxX, x + w);
620     minY = Math.min(minY, y);
621     maxY = Math.max(maxY, y + h);
622   }
624   var width = maxX - minX + 1;
625   var height = maxY - minY + 1;
626   keyboard.style.width = (width + 2 * (minX + 1)) + 'px';
627   keyboard.style.height = (height + 2 * (minY + 1)) + 'px';
629   var instructions = document.createElement('div');
630   instructions.id = 'instructions';
631   instructions.className = 'keyboard-overlay-instructions';
632   instructions.style.left = ((BASE_INSTRUCTIONS.left - BASE_KEYBOARD.left) *
633                              width / BASE_KEYBOARD.width + minX) + 'px';
634   instructions.style.top = ((BASE_INSTRUCTIONS.top - BASE_KEYBOARD.top) *
635                             height / BASE_KEYBOARD.height + minY) + 'px';
636   instructions.style.width = (width * BASE_INSTRUCTIONS.width /
637                               BASE_KEYBOARD.width) + 'px';
638   instructions.style.height = (height * BASE_INSTRUCTIONS.height /
639                                BASE_KEYBOARD.height) + 'px';
641   var instructionsText = document.createElement('div');
642   instructionsText.id = 'instructions-text';
643   instructionsText.className = 'keyboard-overlay-instructions-text';
644   instructionsText.innerHTML =
645       loadTimeData.getString('keyboardOverlayInstructions');
646   instructions.appendChild(instructionsText);
647   var instructionsHideText = document.createElement('div');
648   instructionsHideText.id = 'instructions-hide-text';
649   instructionsHideText.className = 'keyboard-overlay-instructions-hide-text';
650   instructionsHideText.innerHTML =
651       loadTimeData.getString('keyboardOverlayInstructionsHide');
652   instructions.appendChild(instructionsHideText);
653   var learnMoreLinkText = document.createElement('div');
654   learnMoreLinkText.id = 'learn-more-text';
655   learnMoreLinkText.className = 'keyboard-overlay-learn-more-text';
656   learnMoreLinkText.addEventListener('click', learnMoreClicked);
657   var learnMoreLinkAnchor = document.createElement('a');
658   learnMoreLinkAnchor.href =
659       loadTimeData.getString('keyboardOverlayLearnMoreURL');
660   learnMoreLinkAnchor.textContent =
661       loadTimeData.getString('keyboardOverlayLearnMore');
662   learnMoreLinkText.appendChild(learnMoreLinkAnchor);
663   instructions.appendChild(learnMoreLinkText);
664   keyboard.appendChild(instructions);
668  * Returns true if the device has a diamond key.
669  * @return {boolean} Returns true if the device has a diamond key.
670  */
671 function hasDiamondKey() {
672   return loadTimeData.getBoolean('keyboardOverlayHasChromeOSDiamondKey');
676  * Returns true if display scaling feature is enabled.
677  * @return {boolean} True if display scaling feature is enabled.
678  */
679 function isDisplayUIScalingEnabled() {
680   return loadTimeData.getBoolean('keyboardOverlayIsDisplayUIScalingEnabled');
684  * Initializes the layout and the key labels for the keyboard that has a diamond
685  * key.
686  */
687 function initDiamondKey() {
688   var newLayoutData = {
689     '1D': [65.0, 287.0, 60.0, 60.0],  // left Ctrl
690     '38': [185.0, 287.0, 60.0, 60.0],  // left Alt
691     'E0 5B': [125.0, 287.0, 60.0, 60.0],  // search
692     '3A': [5.0, 167.0, 105.0, 60.0],  // caps lock
693     '5B': [803.0, 6.0, 72.0, 35.0],  // lock key
694     '5D': [5.0, 287.0, 60.0, 60.0]  // diamond key
695   };
697   var layout = getLayout();
698   var powerKeyIndex = -1;
699   var powerKeyId = '00';
700   for (var i = 0; i < layout.length; i++) {
701     var keyId = layout[i][0];
702     if (keyId in newLayoutData) {
703       layout[i] = [keyId].concat(newLayoutData[keyId]);
704       delete newLayoutData[keyId];
705     }
706     if (keyId == powerKeyId)
707       powerKeyIndex = i;
708   }
709   for (var keyId in newLayoutData)
710     layout.push([keyId].concat(newLayoutData[keyId]));
712   // Remove the power key.
713   if (powerKeyIndex != -1)
714     layout.splice(powerKeyIndex, 1);
716   var keyData = getKeyboardGlyphData()['keys'];
717   var newKeyData = {
718     '3A': {'label': 'caps lock', 'format': 'left'},
719     '5B': {'label': 'lock'},
720     '5D': {'label': 'diamond', 'format': 'left'}
721   };
722   for (var keyId in newKeyData)
723     keyData[keyId] = newKeyData[keyId];
727  * A callback function for the onload event of the body element.
728  */
729 function init() {
730   document.addEventListener('keydown', handleKeyEvent);
731   document.addEventListener('keyup', handleKeyEvent);
732   chrome.send('getLabelMap');
736  * Initializes the global map for remapping identifiers of modifier keys based
737  * on the preference.
738  * Called after sending the 'getLabelMap' message.
739  * @param {Object} remap Identifier map.
740  */
741 function initIdentifierMap(remap) {
742   for (var key in remap) {
743     var val = remap[key];
744     if ((key in LABEL_TO_IDENTIFIER) &&
745         (val in LABEL_TO_IDENTIFIER)) {
746       identifierMap[LABEL_TO_IDENTIFIER[key]] =
747           LABEL_TO_IDENTIFIER[val];
748     } else {
749       console.error('Invalid label map element: ' + key + ', ' + val);
750     }
751   }
752   chrome.send('getInputMethodId');
756  * Initializes the global keyboad overlay ID and the layout of keys.
757  * Called after sending the 'getInputMethodId' message.
758  * @param {inputMethodId} inputMethodId Input Method Identifier.
759  */
760 function initKeyboardOverlayId(inputMethodId) {
761   // Libcros returns an empty string when it cannot find the keyboard overlay ID
762   // corresponding to the current input method.
763   // In such a case, fallback to the default ID (en_US).
764   var inputMethodIdToOverlayId =
765       keyboardOverlayData['inputMethodIdToOverlayId'];
766   if (inputMethodId) {
767     if (inputMethodId.indexOf(IME_ID_PREFIX) == 0) {
768       // If the input method is a component extension IME, remove the prefix:
769       //   _comp_ime_<ext_id>
770       // The extension id is a hash value with 32 characters.
771       inputMethodId = inputMethodId.slice(
772           IME_ID_PREFIX.length + EXTENSION_ID_LEN);
773     }
774     keyboardOverlayId = inputMethodIdToOverlayId[inputMethodId];
775   }
776   if (!keyboardOverlayId) {
777     console.error('No keyboard overlay ID for ' + inputMethodId);
778     keyboardOverlayId = 'en_US';
779   }
780   while (document.body.firstChild) {
781     document.body.removeChild(document.body.firstChild);
782   }
783   // We show Japanese layout as-is because the user has chosen the layout
784   // that is quite diffrent from the physical layout that has a diamond key.
785   if (hasDiamondKey() && getLayoutName() != 'J')
786     initDiamondKey();
787   initLayout();
788   update([], []);
789   window.webkitRequestAnimationFrame(function() {
790     chrome.send('didPaint');
791   });
795  * Handles click events of the learn more link.
796  * @param {Event} e Mouse click event.
797  */
798 function learnMoreClicked(e) {
799   chrome.send('openLearnMorePage');
800   chrome.send('dialogClose');
801   e.preventDefault();
804 document.addEventListener('DOMContentLoaded', init);