| // 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, |
| }; |
| }); |