blob: 644c3e3ad188b46633f81a0613c75c9e6c14099b [file] [log] [blame]
// 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,
};
});