Home | History | Annotate | Download | only in chromeos
      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.
      4 
      5 <include src="keyboard_overlay_data.js"/>
      6 <include src="keyboard_overlay_accessibility_helper.js"/>
      7 
      8 var BASE_KEYBOARD = {
      9   top: 0,
     10   left: 0,
     11   width: 1237,
     12   height: 514
     13 };
     14 
     15 var BASE_INSTRUCTIONS = {
     16   top: 194,
     17   left: 370,
     18   width: 498,
     19   height: 142
     20 };
     21 
     22 var MODIFIER_TO_CLASS = {
     23   'SHIFT': 'modifier-shift',
     24   'CTRL': 'modifier-ctrl',
     25   'ALT': 'modifier-alt',
     26   'SEARCH': 'modifier-search'
     27 };
     28 
     29 var IDENTIFIER_TO_CLASS = {
     30   '2A': 'is-shift',
     31   '1D': 'is-ctrl',
     32   '38': 'is-alt',
     33   'E0 5B': 'is-search'
     34 };
     35 
     36 var LABEL_TO_IDENTIFIER = {
     37   'search': 'E0 5B',
     38   'ctrl': '1D',
     39   'alt': '38',
     40   'caps lock': '3A',
     41   'disabled': 'DISABLED'
     42 };
     43 
     44 var KEYCODE_TO_LABEL = {
     45   8: 'backspace',
     46   9: 'tab',
     47   13: 'enter',
     48   27: 'esc',
     49   32: 'space',
     50   33: 'pageup',
     51   34: 'pagedown',
     52   35: 'end',
     53   36: 'home',
     54   37: 'left',
     55   38: 'up',
     56   39: 'right',
     57   40: 'down',
     58   46: 'delete',
     59   91: 'search',
     60   92: 'search',
     61   96: '0',
     62   97: '1',
     63   98: '2',
     64   99: '3',
     65   100: '4',
     66   101: '5',
     67   102: '6',
     68   103: '7',
     69   104: '8',
     70   105: '9',
     71   106: '*',
     72   107: '+',
     73   109: '-',
     74   110: '.',
     75   111: '/',
     76   112: 'back',
     77   113: 'forward',
     78   114: 'reload',
     79   115: 'full screen',
     80   116: 'switch window',
     81   117: 'bright down',
     82   118: 'bright up',
     83   119: 'mute',
     84   120: 'vol. down',
     85   121: 'vol. up',
     86   186: ';',
     87   187: '+',
     88   188: ',',
     89   189: '-',
     90   190: '.',
     91   191: '/',
     92   192: '`',
     93   219: '[',
     94   220: '\\',
     95   221: ']',
     96   222: '\'',
     97 };
     98 
     99 var keyboardOverlayId = 'en_US';
    100 var identifierMap = {};
    101 
    102 /**
    103  * Returns the layout name.
    104  * @return {string} layout name.
    105  */
    106 function getLayoutName() {
    107   return getKeyboardGlyphData().layoutName;
    108 }
    109 
    110 /**
    111  * Returns layout data.
    112  * @return {Array} Keyboard layout data.
    113  */
    114 function getLayout() {
    115   return keyboardOverlayData['layouts'][getLayoutName()];
    116 }
    117 
    118 // Cache the shortcut data after it is constructed.
    119 var shortcutDataCache;
    120 
    121 /**
    122  * Returns shortcut data.
    123  * @return {Object} Keyboard shortcut data.
    124  */
    125 function getShortcutData() {
    126   if (shortcutDataCache)
    127     return shortcutDataCache;
    128 
    129   shortcutDataCache = keyboardOverlayData['shortcut'];
    130 
    131   if (!isDisplayRotationEnabled()) {
    132     // Rotate screen
    133     delete shortcutDataCache['reload<>CTRL<>SHIFT'];
    134   }
    135   if (!isDisplayUIScalingEnabled()) {
    136     // Zoom screen in
    137     delete shortcutDataCache['+<>CTRL<>SHIFT'];
    138     // Zoom screen out
    139     delete shortcutDataCache['-<>CTRL<>SHIFT'];
    140     // Reset screen zoom
    141     delete shortcutDataCache['0<>CTRL<>SHIFT'];
    142   }
    143 
    144   return shortcutDataCache;
    145 }
    146 
    147 /**
    148  * Returns the keyboard overlay ID.
    149  * @return {string} Keyboard overlay ID.
    150  */
    151 function getKeyboardOverlayId() {
    152   return keyboardOverlayId;
    153 }
    154 
    155 /**
    156  * Returns keyboard glyph data.
    157  * @return {Object} Keyboard glyph data.
    158  */
    159 function getKeyboardGlyphData() {
    160   return keyboardOverlayData['keyboardGlyph'][getKeyboardOverlayId()];
    161 }
    162 
    163 /**
    164  * Converts a single hex number to a character.
    165  * @param {string} hex Hexadecimal string.
    166  * @return {string} Unicode values of hexadecimal string.
    167  */
    168 function hex2char(hex) {
    169   if (!hex) {
    170     return '';
    171   }
    172   var result = '';
    173   var n = parseInt(hex, 16);
    174   if (n <= 0xFFFF) {
    175     result += String.fromCharCode(n);
    176   } else if (n <= 0x10FFFF) {
    177     n -= 0x10000;
    178     result += (String.fromCharCode(0xD800 | (n >> 10)) +
    179                String.fromCharCode(0xDC00 | (n & 0x3FF)));
    180   } else {
    181     console.error('hex2Char error: Code point out of range :' + hex);
    182   }
    183   return result;
    184 }
    185 
    186 var searchIsPressed = false;
    187 
    188 /**
    189  * Returns a list of modifiers from the key event.
    190  * @param {Event} e The key event.
    191  * @return {Array} List of modifiers based on key event.
    192  */
    193 function getModifiers(e) {
    194   if (!e)
    195     return [];
    196 
    197   var isKeyDown = (e.type == 'keydown');
    198   var keyCodeToModifier = {
    199     16: 'SHIFT',
    200     17: 'CTRL',
    201     18: 'ALT',
    202     91: 'SEARCH',
    203   };
    204   var modifierWithKeyCode = keyCodeToModifier[e.keyCode];
    205   var isPressed = {
    206       'SHIFT': e.shiftKey,
    207       'CTRL': e.ctrlKey,
    208       'ALT': e.altKey,
    209       'SEARCH': searchIsPressed
    210   };
    211   if (modifierWithKeyCode)
    212     isPressed[modifierWithKeyCode] = isKeyDown;
    213 
    214   searchIsPressed = isPressed['SEARCH'];
    215 
    216   // make the result array
    217   return ['SHIFT', 'CTRL', 'ALT', 'SEARCH'].filter(
    218       function(modifier) {
    219         return isPressed[modifier];
    220       }).sort();
    221 }
    222 
    223 /**
    224  * Returns an ID of the key.
    225  * @param {string} identifier Key identifier.
    226  * @param {number} i Key number.
    227  * @return {string} Key ID.
    228  */
    229 function keyId(identifier, i) {
    230   return identifier + '-key-' + i;
    231 }
    232 
    233 /**
    234  * Returns an ID of the text on the key.
    235  * @param {string} identifier Key identifier.
    236  * @param {number} i Key number.
    237  * @return {string} Key text ID.
    238  */
    239 function keyTextId(identifier, i) {
    240   return identifier + '-key-text-' + i;
    241 }
    242 
    243 /**
    244  * Returns an ID of the shortcut text.
    245  * @param {string} identifier Key identifier.
    246  * @param {number} i Key number.
    247  * @return {string} Key shortcut text ID.
    248  */
    249 function shortcutTextId(identifier, i) {
    250   return identifier + '-shortcut-text-' + i;
    251 }
    252 
    253 /**
    254  * Returns true if |list| contains |e|.
    255  * @param {Array} list Container list.
    256  * @param {string} e Element string.
    257  * @return {boolean} Returns true if the list contains the element.
    258  */
    259 function contains(list, e) {
    260   return list.indexOf(e) != -1;
    261 }
    262 
    263 /**
    264  * Returns a list of the class names corresponding to the identifier and
    265  * modifiers.
    266  * @param {string} identifier Key identifier.
    267  * @param {Array} modifiers List of key modifiers.
    268  * @return {Array} List of class names corresponding to specified params.
    269  */
    270 function getKeyClasses(identifier, modifiers) {
    271   var classes = ['keyboard-overlay-key'];
    272   for (var i = 0; i < modifiers.length; ++i) {
    273     classes.push(MODIFIER_TO_CLASS[modifiers[i]]);
    274   }
    275 
    276   if ((identifier == '2A' && contains(modifiers, 'SHIFT')) ||
    277       (identifier == '1D' && contains(modifiers, 'CTRL')) ||
    278       (identifier == '38' && contains(modifiers, 'ALT')) ||
    279       (identifier == 'E0 5B' && contains(modifiers, 'SEARCH'))) {
    280     classes.push('pressed');
    281     classes.push(IDENTIFIER_TO_CLASS[identifier]);
    282   }
    283   return classes;
    284 }
    285 
    286 /**
    287  * Returns true if a character is a ASCII character.
    288  * @param {string} c A character to be checked.
    289  * @return {boolean} True if the character is an ASCII character.
    290  */
    291 function isAscii(c) {
    292   var charCode = c.charCodeAt(0);
    293   return 0x00 <= charCode && charCode <= 0x7F;
    294 }
    295 
    296 /**
    297  * Returns a remapped identiifer based on the preference.
    298  * @param {string} identifier Key identifier.
    299  * @return {string} Remapped identifier.
    300  */
    301 function remapIdentifier(identifier) {
    302   return identifierMap[identifier] || identifier;
    303 }
    304 
    305 /**
    306  * Returns a label of the key.
    307  * @param {string} keyData Key glyph data.
    308  * @param {Array} modifiers Key Modifier list.
    309  * @return {string} Label of the key.
    310  */
    311 function getKeyLabel(keyData, modifiers) {
    312   if (!keyData) {
    313     return '';
    314   }
    315   if (keyData.label) {
    316     return keyData.label;
    317   }
    318   var keyLabel = '';
    319   for (var j = 1; j <= 9; j++) {
    320     var pos = keyData['p' + j];
    321     if (!pos) {
    322       continue;
    323     }
    324     keyLabel = hex2char(pos);
    325     if (!keyLabel) {
    326       continue;
    327      }
    328     if (isAscii(keyLabel) &&
    329         getShortcutData()[getAction(keyLabel, modifiers)]) {
    330       break;
    331     }
    332   }
    333   return keyLabel;
    334 }
    335 
    336 /**
    337  * Returns a normalized string used for a key of shortcutData.
    338  *
    339  * Examples:
    340  *   keyCode: 'd', modifiers: ['CTRL', 'SHIFT'] => 'd<>CTRL<>SHIFT'
    341  *   keyCode: 'alt', modifiers: ['ALT', 'SHIFT'] => 'ALT<>SHIFT'
    342  *
    343  * @param {string} keyCode Key code.
    344  * @param {Array} modifiers Key Modifier list.
    345  * @return {string} Normalized key shortcut data string.
    346  */
    347 function getAction(keyCode, modifiers) {
    348   /** @const */ var separatorStr = '<>';
    349   if (keyCode.toUpperCase() in MODIFIER_TO_CLASS) {
    350     keyCode = keyCode.toUpperCase();
    351     if (keyCode in modifiers) {
    352       return modifiers.join(separatorStr);
    353     } else {
    354       var action = [keyCode].concat(modifiers);
    355       action.sort();
    356       return action.join(separatorStr);
    357     }
    358   }
    359   return [keyCode].concat(modifiers).join(separatorStr);
    360 }
    361 
    362 /**
    363  * Returns a text which displayed on a key.
    364  * @param {string} keyData Key glyph data.
    365  * @return {string} Key text value.
    366  */
    367 function getKeyTextValue(keyData) {
    368   if (keyData.label) {
    369     // Do not show text on the space key.
    370     if (keyData.label == 'space') {
    371       return '';
    372     }
    373     return keyData.label;
    374   }
    375 
    376   var chars = [];
    377   for (var j = 1; j <= 9; ++j) {
    378     var pos = keyData['p' + j];
    379     if (pos && pos.length > 0) {
    380       chars.push(hex2char(pos));
    381     }
    382   }
    383   return chars.join(' ');
    384 }
    385 
    386 /**
    387  * Updates the whole keyboard.
    388  * @param {Array} modifiers Key Modifier list.
    389  */
    390 function update(modifiers) {
    391   var instructions = $('instructions');
    392   if (modifiers.length == 0) {
    393     instructions.style.visibility = 'visible';
    394   } else {
    395     instructions.style.visibility = 'hidden';
    396   }
    397 
    398   var keyboardGlyphData = getKeyboardGlyphData();
    399   var shortcutData = getShortcutData();
    400   var layout = getLayout();
    401   for (var i = 0; i < layout.length; ++i) {
    402     var identifier = remapIdentifier(layout[i][0]);
    403     var keyData = keyboardGlyphData.keys[identifier];
    404     var classes = getKeyClasses(identifier, modifiers, keyData);
    405     var keyLabel = getKeyLabel(keyData, modifiers);
    406     var shortcutId = shortcutData[getAction(keyLabel, modifiers)];
    407     if (modifiers.length == 1 && modifiers[0] == 'SHIFT' &&
    408         identifier == '2A') {
    409       // Currently there is no way to identify whether the left shift or the
    410       // right shift is preesed from the key event, so I assume the left shift
    411       // key is pressed here and do not show keyboard shortcut description for
    412       // 'Shift - Shift' (Toggle caps lock) on the left shift key, the
    413       // identifier of which is '2A'.
    414       // TODO(mazda): Remove this workaround (http://crosbug.com/18047)
    415       shortcutId = null;
    416     }
    417     if (shortcutId) {
    418       classes.push('is-shortcut');
    419     }
    420 
    421     var key = $(keyId(identifier, i));
    422     key.className = classes.join(' ');
    423 
    424     if (!keyData) {
    425       continue;
    426     }
    427 
    428     var keyText = $(keyTextId(identifier, i));
    429     var keyTextValue = getKeyTextValue(keyData);
    430     if (keyTextValue) {
    431        keyText.style.visibility = 'visible';
    432     } else {
    433        keyText.style.visibility = 'hidden';
    434     }
    435     keyText.textContent = keyTextValue;
    436 
    437     var shortcutText = $(shortcutTextId(identifier, i));
    438     if (shortcutId) {
    439       shortcutText.style.visibility = 'visible';
    440       shortcutText.textContent = loadTimeData.getString(shortcutId);
    441     } else {
    442       shortcutText.style.visibility = 'hidden';
    443     }
    444 
    445     if (keyData.format) {
    446       var format = keyData.format;
    447       if (format == 'left' || format == 'right') {
    448         shortcutText.style.textAlign = format;
    449         keyText.style.textAlign = format;
    450       }
    451     }
    452   }
    453 }
    454 
    455 /**
    456  * A callback function for onkeydown and onkeyup events.
    457  * @param {Event} e Key event.
    458  */
    459 function handleKeyEvent(e) {
    460   if (!getKeyboardOverlayId()) {
    461     return;
    462   }
    463   var modifiers = getModifiers(e);
    464   update(modifiers);
    465   KeyboardOverlayAccessibilityHelper.maybeSpeakAllShortcuts(modifiers);
    466   e.preventDefault();
    467 }
    468 
    469 /**
    470  * Initializes the layout of the keys.
    471  */
    472 function initLayout() {
    473   // Add data for the caps lock key
    474   var keys = getKeyboardGlyphData().keys;
    475   if (!('3A' in keys)) {
    476     keys['3A'] = {label: 'caps lock', format: 'left'};
    477   }
    478   // Add data for the special key representing a disabled key
    479   keys['DISABLED'] = {label: 'disabled', format: 'left'};
    480 
    481   var layout = getLayout();
    482   var keyboard = document.body;
    483   var minX = window.innerWidth;
    484   var maxX = 0;
    485   var minY = window.innerHeight;
    486   var maxY = 0;
    487   var multiplier = 1.38 * window.innerWidth / BASE_KEYBOARD.width;
    488   var keyMargin = 7;
    489   var offsetX = 10;
    490   var offsetY = 7;
    491   for (var i = 0; i < layout.length; i++) {
    492     var array = layout[i];
    493     var identifier = remapIdentifier(array[0]);
    494     var x = Math.round((array[1] + offsetX) * multiplier);
    495     var y = Math.round((array[2] + offsetY) * multiplier);
    496     var w = Math.round((array[3] - keyMargin) * multiplier);
    497     var h = Math.round((array[4] - keyMargin) * multiplier);
    498 
    499     var key = document.createElement('div');
    500     key.id = keyId(identifier, i);
    501     key.className = 'keyboard-overlay-key';
    502     key.style.left = x + 'px';
    503     key.style.top = y + 'px';
    504     key.style.width = w + 'px';
    505     key.style.height = h + 'px';
    506 
    507     var keyText = document.createElement('div');
    508     keyText.id = keyTextId(identifier, i);
    509     keyText.className = 'keyboard-overlay-key-text';
    510     keyText.style.visibility = 'hidden';
    511     key.appendChild(keyText);
    512 
    513     var shortcutText = document.createElement('div');
    514     shortcutText.id = shortcutTextId(identifier, i);
    515     shortcutText.className = 'keyboard-overlay-shortcut-text';
    516     shortcutText.style.visilibity = 'hidden';
    517     key.appendChild(shortcutText);
    518     keyboard.appendChild(key);
    519 
    520     minX = Math.min(minX, x);
    521     maxX = Math.max(maxX, x + w);
    522     minY = Math.min(minY, y);
    523     maxY = Math.max(maxY, y + h);
    524   }
    525 
    526   var width = maxX - minX + 1;
    527   var height = maxY - minY + 1;
    528   keyboard.style.width = (width + 2 * (minX + 1)) + 'px';
    529   keyboard.style.height = (height + 2 * (minY + 1)) + 'px';
    530 
    531   var instructions = document.createElement('div');
    532   instructions.id = 'instructions';
    533   instructions.className = 'keyboard-overlay-instructions';
    534   instructions.style.left = ((BASE_INSTRUCTIONS.left - BASE_KEYBOARD.left) *
    535                              width / BASE_KEYBOARD.width + minX) + 'px';
    536   instructions.style.top = ((BASE_INSTRUCTIONS.top - BASE_KEYBOARD.top) *
    537                             height / BASE_KEYBOARD.height + minY) + 'px';
    538   instructions.style.width = (width * BASE_INSTRUCTIONS.width /
    539                               BASE_KEYBOARD.width) + 'px';
    540   instructions.style.height = (height * BASE_INSTRUCTIONS.height /
    541                                BASE_KEYBOARD.height) + 'px';
    542 
    543   var instructionsText = document.createElement('div');
    544   instructionsText.id = 'instructions-text';
    545   instructionsText.className = 'keyboard-overlay-instructions-text';
    546   instructionsText.innerHTML =
    547       loadTimeData.getString('keyboardOverlayInstructions');
    548   instructions.appendChild(instructionsText);
    549   var instructionsHideText = document.createElement('div');
    550   instructionsHideText.id = 'instructions-hide-text';
    551   instructionsHideText.className = 'keyboard-overlay-instructions-hide-text';
    552   instructionsHideText.innerHTML =
    553       loadTimeData.getString('keyboardOverlayInstructionsHide');
    554   instructions.appendChild(instructionsHideText);
    555   var learnMoreLinkText = document.createElement('div');
    556   learnMoreLinkText.id = 'learn-more-text';
    557   learnMoreLinkText.className = 'keyboard-overlay-learn-more-text';
    558   learnMoreLinkText.addEventListener('click', learnMoreClicked);
    559   var learnMoreLinkAnchor = document.createElement('a');
    560   learnMoreLinkAnchor.href =
    561       loadTimeData.getString('keyboardOverlayLearnMoreURL');
    562   learnMoreLinkAnchor.textContent =
    563       loadTimeData.getString('keyboardOverlayLearnMore');
    564   learnMoreLinkText.appendChild(learnMoreLinkAnchor);
    565   instructions.appendChild(learnMoreLinkText);
    566   keyboard.appendChild(instructions);
    567 }
    568 
    569 /**
    570  * Returns true if the device has a diamond key.
    571  * @return {boolean} Returns true if the device has a diamond key.
    572  */
    573 function hasDiamondKey() {
    574   return loadTimeData.getBoolean('keyboardOverlayHasChromeOSDiamondKey');
    575 }
    576 
    577 /**
    578  * Returns true if display rotation feature is enabled.
    579  * @return {boolean} True if display rotation feature is enabled.
    580  */
    581 function isDisplayRotationEnabled() {
    582   return loadTimeData.getBoolean('keyboardOverlayIsDisplayRotationEnabled');
    583 }
    584 
    585 /**
    586  * Returns true if display scaling feature is enabled.
    587  * @return {boolean} True if display scaling feature is enabled.
    588  */
    589 function isDisplayUIScalingEnabled() {
    590   return loadTimeData.getBoolean('keyboardOverlayIsDisplayUIScalingEnabled');
    591 }
    592 
    593 /**
    594  * Initializes the layout and the key labels for the keyboard that has a diamond
    595  * key.
    596  */
    597 function initDiamondKey() {
    598   var newLayoutData = {
    599     '1D': [65.0, 287.0, 60.0, 60.0],  // left Ctrl
    600     '38': [185.0, 287.0, 60.0, 60.0],  // left Alt
    601     'E0 5B': [125.0, 287.0, 60.0, 60.0],  // search
    602     '3A': [5.0, 167.0, 105.0, 60.0],  // caps lock
    603     '5B': [803.0, 6.0, 72.0, 35.0],  // lock key
    604     '5D': [5.0, 287.0, 60.0, 60.0]  // diamond key
    605   };
    606 
    607   var layout = getLayout();
    608   var powerKeyIndex = -1;
    609   var powerKeyId = '00';
    610   for (var i = 0; i < layout.length; i++) {
    611     var keyId = layout[i][0];
    612     if (keyId in newLayoutData) {
    613       layout[i] = [keyId].concat(newLayoutData[keyId]);
    614       delete newLayoutData[keyId];
    615     }
    616     if (keyId == powerKeyId)
    617       powerKeyIndex = i;
    618   }
    619   for (var keyId in newLayoutData)
    620     layout.push([keyId].concat(newLayoutData[keyId]));
    621 
    622   // Remove the power key.
    623   if (powerKeyIndex != -1)
    624     layout.splice(powerKeyIndex, 1);
    625 
    626   var keyData = getKeyboardGlyphData()['keys'];
    627   var newKeyData = {
    628     '3A': {'label': 'caps lock', 'format': 'left'},
    629     '5B': {'label': 'lock'},
    630     '5D': {'label': 'diamond', 'format': 'left'}
    631   };
    632   for (var keyId in newKeyData)
    633     keyData[keyId] = newKeyData[keyId];
    634 }
    635 
    636 /**
    637  * A callback function for the onload event of the body element.
    638  */
    639 function init() {
    640   document.addEventListener('keydown', handleKeyEvent);
    641   document.addEventListener('keyup', handleKeyEvent);
    642   chrome.send('getLabelMap');
    643 }
    644 
    645 /**
    646  * Initializes the global map for remapping identifiers of modifier keys based
    647  * on the preference.
    648  * Called after sending the 'getLabelMap' message.
    649  * @param {Object} remap Identifier map.
    650  */
    651 function initIdentifierMap(remap) {
    652   for (var key in remap) {
    653     var val = remap[key];
    654     if ((key in LABEL_TO_IDENTIFIER) &&
    655         (val in LABEL_TO_IDENTIFIER)) {
    656       identifierMap[LABEL_TO_IDENTIFIER[key]] =
    657           LABEL_TO_IDENTIFIER[val];
    658     } else {
    659       console.error('Invalid label map element: ' + key + ', ' + val);
    660     }
    661   }
    662   chrome.send('getInputMethodId');
    663 }
    664 
    665 /**
    666  * Initializes the global keyboad overlay ID and the layout of keys.
    667  * Called after sending the 'getInputMethodId' message.
    668  * @param {inputMethodId} inputMethodId Input Method Identifier.
    669  */
    670 function initKeyboardOverlayId(inputMethodId) {
    671   // Libcros returns an empty string when it cannot find the keyboard overlay ID
    672   // corresponding to the current input method.
    673   // In such a case, fallback to the default ID (en_US).
    674   var inputMethodIdToOverlayId =
    675       keyboardOverlayData['inputMethodIdToOverlayId'];
    676   if (inputMethodId) {
    677     keyboardOverlayId = inputMethodIdToOverlayId[inputMethodId];
    678   }
    679   if (!keyboardOverlayId) {
    680     console.error('No keyboard overlay ID for ' + inputMethodId);
    681     keyboardOverlayId = 'en_US';
    682   }
    683   while (document.body.firstChild) {
    684     document.body.removeChild(document.body.firstChild);
    685   }
    686   // We show Japanese layout as-is because the user has chosen the layout
    687   // that is quite diffrent from the physical layout that has a diamond key.
    688   if (hasDiamondKey() && getLayoutName() != 'J')
    689     initDiamondKey();
    690   initLayout();
    691   update([]);
    692   window.webkitRequestAnimationFrame(function() {
    693     chrome.send('didPaint');
    694   });
    695 }
    696 
    697 /**
    698  * Handles click events of the learn more link.
    699  * @param {Event} e Mouse click event.
    700  */
    701 function learnMoreClicked(e) {
    702   chrome.send('openLearnMorePage');
    703   chrome.send('DialogClose');
    704   e.preventDefault();
    705 }
    706 
    707 document.addEventListener('DOMContentLoaded', init);
    708