// Copyright 2016 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. cr.define('extensions', function() { 'use strict'; /** @enum {number} */ const Key = { Comma: 188, Del: 46, Down: 40, End: 35, Escape: 27, Home: 36, Ins: 45, Left: 37, MediaNextTrack: 176, MediaPlayPause: 179, MediaPrevTrack: 177, MediaStop: 178, PageDown: 34, PageUp: 33, Period: 190, Right: 39, Space: 32, Tab: 9, Up: 38, }; /** * Enum for whether we require modifiers of a keycode. * @enum {number} */ const ModifierPolicy = {NOT_ALLOWED: 0, REQUIRED: 1}; /** * Gets the ModifierPolicy. Currently only "MediaNextTrack", "MediaPrevTrack", * "MediaStop", "MediaPlayPause" are required to be used without any modifier. * @param {number} keyCode * @return {ModifierPolicy} */ function getModifierPolicy(keyCode) { switch (keyCode) { case Key.MediaNextTrack: case Key.MediaPlayPause: case Key.MediaPrevTrack: case Key.MediaStop: return ModifierPolicy.NOT_ALLOWED; default: return ModifierPolicy.REQUIRED; } } /** * Returns whether the keyboard event has a key modifier, which could affect * how it's handled. * @param {!KeyboardEvent} e * @param {boolean} countShiftAsModifier Whether the 'Shift' key should be * counted as modifier. * @return {boolean} True if the event has any modifiers. */ function hasModifier(e, countShiftAsModifier) { return e.ctrlKey || e.altKey || // Meta key is only relevant on Mac and CrOS, where we treat Command // and Search (respectively) as modifiers. (cr.isMac && e.metaKey) || (cr.isChromeOS && e.metaKey) || (countShiftAsModifier && e.shiftKey); } /** * Checks whether the passed in |keyCode| is a valid extension command key. * @param {number} keyCode * @return {boolean} Whether the key is valid. */ function isValidKeyCode(keyCode) { if (keyCode == Key.Escape) { return false; } for (const k in Key) { if (Key[k] == keyCode) { return true; } } return (keyCode >= 'A'.charCodeAt(0) && keyCode <= 'Z'.charCodeAt(0)) || (keyCode >= '0'.charCodeAt(0) && keyCode <= '9'.charCodeAt(0)); } /** * Converts a keystroke event to string form, ignoring invalid extension * commands. * @param {!KeyboardEvent} e * @return {string} The keystroke as a string. */ function keystrokeToString(e) { const output = []; // TODO(devlin): Should this be i18n'd? if (cr.isMac && e.metaKey) { output.push('Command'); } if (cr.isChromeOS && e.metaKey) { output.push('Search'); } if (e.ctrlKey) { output.push('Ctrl'); } if (!e.ctrlKey && e.altKey) { output.push('Alt'); } if (e.shiftKey) { output.push('Shift'); } const keyCode = e.keyCode; if (isValidKeyCode(keyCode)) { if ((keyCode >= 'A'.charCodeAt(0) && keyCode <= 'Z'.charCodeAt(0)) || (keyCode >= '0'.charCodeAt(0) && keyCode <= '9'.charCodeAt(0))) { output.push(String.fromCharCode(keyCode)); } else { switch (keyCode) { case Key.Comma: output.push('Comma'); break; case Key.Del: output.push('Delete'); break; case Key.Down: output.push('Down'); break; case Key.End: output.push('End'); break; case Key.Home: output.push('Home'); break; case Key.Ins: output.push('Insert'); break; case Key.Left: output.push('Left'); break; case Key.MediaNextTrack: output.push('MediaNextTrack'); break; case Key.MediaPlayPause: output.push('MediaPlayPause'); break; case Key.MediaPrevTrack: output.push('MediaPrevTrack'); break; case Key.MediaStop: output.push('MediaStop'); break; case Key.PageDown: output.push('PageDown'); break; case Key.PageUp: output.push('PageUp'); break; case Key.Period: output.push('Period'); break; case Key.Right: output.push('Right'); break; case Key.Space: output.push('Space'); break; case Key.Tab: output.push('Tab'); break; case Key.Up: output.push('Up'); break; } } } return output.join('+'); } /** * Returns true if the event has valid modifiers. * @param {!KeyboardEvent} e The keyboard event to consider. * @return {boolean} True if the event is valid. */ function hasValidModifiers(e) { switch (getModifierPolicy(e.keyCode)) { case ModifierPolicy.REQUIRED: return hasModifier(e, false); case ModifierPolicy.NOT_ALLOWED: return !hasModifier(e, true); } assertNotReached(); } return { isValidKeyCode: isValidKeyCode, keystrokeToString: keystrokeToString, hasValidModifiers: hasValidModifiers, Key: Key, }; });