blob: ba9f9596ab776eb38ac5a4e4731809659450172f [file] [log] [blame]
/*
* Copyright (C) 2009 Apple Inc. All rights reserved.
* Copyright (C) 2009 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @constructor
*/
WebInspector.KeyboardShortcut = function()
{
}
/**
* Constants for encoding modifier key set as a bit mask.
* @see #_makeKeyFromCodeAndModifiers
*/
WebInspector.KeyboardShortcut.Modifiers = {
None: 0, // Constant for empty modifiers set.
Shift: 1,
Ctrl: 2,
Alt: 4,
Meta: 8, // Command key on Mac, Win key on other platforms.
get CtrlOrMeta()
{
// "default" command/ctrl key for platform, Command on Mac, Ctrl on other platforms
return WebInspector.isMac() ? this.Meta : this.Ctrl;
},
get ShiftOrOption()
{
// Option on Mac, Shift on other platforms
return WebInspector.isMac() ? this.Alt : this.Shift;
}
};
/** @typedef {!{code: number, name: (string|!Object.<string, string>)}} */
WebInspector.KeyboardShortcut.Key;
/** @type {!Object.<string, !WebInspector.KeyboardShortcut.Key>} */
WebInspector.KeyboardShortcut.Keys = {
Backspace: { code: 8, name: "\u21a4" },
Tab: { code: 9, name: { mac: "\u21e5", other: "Tab" } },
Enter: { code: 13, name: { mac: "\u21a9", other: "Enter" } },
Shift: { code: 16, name: { mac: "\u21e7", other: "Shift" } },
Ctrl: { code: 17, name: "Ctrl" },
Esc: { code: 27, name: "Esc" },
Space: { code: 32, name: "Space" },
PageUp: { code: 33, name: { mac: "\u21de", other: "PageUp" } }, // also NUM_NORTH_EAST
PageDown: { code: 34, name: { mac: "\u21df", other: "PageDown" } }, // also NUM_SOUTH_EAST
End: { code: 35, name: { mac: "\u2197", other: "End" } }, // also NUM_SOUTH_WEST
Home: { code: 36, name: { mac: "\u2196", other: "Home" } }, // also NUM_NORTH_WEST
Left: { code: 37, name: "\u2190" }, // also NUM_WEST
Up: { code: 38, name: "\u2191" }, // also NUM_NORTH
Right: { code: 39, name: "\u2192" }, // also NUM_EAST
Down: { code: 40, name: "\u2193" }, // also NUM_SOUTH
Delete: { code: 46, name: "Del" },
Zero: { code: 48, name: "0" },
H: { code: 72, name: "H" },
Meta: { code: 91, name: "Meta" },
F1: { code: 112, name: "F1" },
F2: { code: 113, name: "F2" },
F3: { code: 114, name: "F3" },
F4: { code: 115, name: "F4" },
F5: { code: 116, name: "F5" },
F6: { code: 117, name: "F6" },
F7: { code: 118, name: "F7" },
F8: { code: 119, name: "F8" },
F9: { code: 120, name: "F9" },
F10: { code: 121, name: "F10" },
F11: { code: 122, name: "F11" },
F12: { code: 123, name: "F12" },
Semicolon: { code: 186, name: ";" },
NumpadPlus: { code: 107, name: "Numpad +" },
NumpadMinus: { code: 109, name: "Numpad -" },
Numpad0: { code: 96, name: "Numpad 0" },
Plus: { code: 187, name: "+" },
Comma: { code: 188, name: "," },
Minus: { code: 189, name: "-" },
Period: { code: 190, name: "." },
Slash: { code: 191, name: "/" },
QuestionMark: { code: 191, name: "?" },
Apostrophe: { code: 192, name: "`" },
Tilde: { code: 192, name: "Tilde" },
LeftSquareBracket: { code: 219, name: "[" },
RightSquareBracket: { code: 221, name: "]" },
Backslash: { code: 220, name: "\\" },
SingleQuote: { code: 222, name: "\'" },
get CtrlOrMeta()
{
// "default" command/ctrl key for platform, Command on Mac, Ctrl on other platforms
return WebInspector.isMac() ? this.Meta : this.Ctrl;
},
};
WebInspector.KeyboardShortcut.KeyBindings = {};
(function() {
for (var key in WebInspector.KeyboardShortcut.Keys) {
var descriptor = WebInspector.KeyboardShortcut.Keys[key];
if (typeof descriptor === "object" && descriptor["code"]) {
var name = typeof descriptor["name"] === "string" ? descriptor["name"] : key;
WebInspector.KeyboardShortcut.KeyBindings[name] = descriptor;
}
}
})();
/**
* Creates a number encoding keyCode in the lower 8 bits and modifiers mask in the higher 8 bits.
* It is useful for matching pressed keys.
*
* @param {number|string} keyCode The code of the key, or a character "a-z" which is converted to a keyCode value.
* @param {number=} modifiers Optional list of modifiers passed as additional parameters.
* @return {number}
*/
WebInspector.KeyboardShortcut.makeKey = function(keyCode, modifiers)
{
if (typeof keyCode === "string")
keyCode = keyCode.charCodeAt(0) - (/^[a-z]/.test(keyCode) ? 32 : 0);
modifiers = modifiers || WebInspector.KeyboardShortcut.Modifiers.None;
return WebInspector.KeyboardShortcut._makeKeyFromCodeAndModifiers(keyCode, modifiers);
}
/**
* @param {?KeyboardEvent} keyboardEvent
* @return {number}
*/
WebInspector.KeyboardShortcut.makeKeyFromEvent = function(keyboardEvent)
{
var modifiers = WebInspector.KeyboardShortcut.Modifiers.None;
if (keyboardEvent.shiftKey)
modifiers |= WebInspector.KeyboardShortcut.Modifiers.Shift;
if (keyboardEvent.ctrlKey)
modifiers |= WebInspector.KeyboardShortcut.Modifiers.Ctrl;
if (keyboardEvent.altKey)
modifiers |= WebInspector.KeyboardShortcut.Modifiers.Alt;
if (keyboardEvent.metaKey)
modifiers |= WebInspector.KeyboardShortcut.Modifiers.Meta;
// Use either a real or a synthetic keyCode (for events originating from extensions).
var keyCode = keyboardEvent.keyCode || keyboardEvent["__keyCode"];
return WebInspector.KeyboardShortcut._makeKeyFromCodeAndModifiers(keyCode, modifiers);
}
/**
* @param {?KeyboardEvent} keyboardEvent
* @return {number}
*/
WebInspector.KeyboardShortcut.makeKeyFromEventIgnoringModifiers = function(keyboardEvent)
{
var keyCode = keyboardEvent.keyCode || keyboardEvent["__keyCode"];
return WebInspector.KeyboardShortcut._makeKeyFromCodeAndModifiers(keyCode, WebInspector.KeyboardShortcut.Modifiers.None);
}
/**
* @param {(?KeyboardEvent|?MouseEvent)} event
* @return {boolean}
*/
WebInspector.KeyboardShortcut.eventHasCtrlOrMeta = function(event)
{
return WebInspector.isMac() ? event.metaKey && !event.ctrlKey : event.ctrlKey && !event.metaKey;
}
/**
* @param {!Event} event
* @return {boolean}
*/
WebInspector.KeyboardShortcut.hasNoModifiers = function(event)
{
return !event.ctrlKey && !event.shiftKey && !event.altKey && !event.metaKey;
}
/** @typedef {!{key: number, name: string}} */
WebInspector.KeyboardShortcut.Descriptor;
/**
* @param {string|!WebInspector.KeyboardShortcut.Key} key
* @param {number=} modifiers
* @return {!WebInspector.KeyboardShortcut.Descriptor}
*/
WebInspector.KeyboardShortcut.makeDescriptor = function(key, modifiers)
{
return {
key: WebInspector.KeyboardShortcut.makeKey(typeof key === "string" ? key : key.code, modifiers),
name: WebInspector.KeyboardShortcut.shortcutToString(key, modifiers)
};
}
/**
* @param {string} shortcut
* @return {?WebInspector.KeyboardShortcut.Descriptor}
*/
WebInspector.KeyboardShortcut.makeDescriptorFromBindingShortcut = function(shortcut)
{
var parts = shortcut.split(/\+(?!$)/);
var modifiers = 0;
var keyString;
for (var i = 0; i < parts.length; ++i) {
if (typeof WebInspector.KeyboardShortcut.Modifiers[parts[i]] !== "undefined") {
modifiers |= WebInspector.KeyboardShortcut.Modifiers[parts[i]];
continue;
}
console.assert(i === parts.length - 1, "Only one key other than modifier is allowed in shortcut <" + shortcut + ">");
keyString = parts[i];
break;
}
console.assert(keyString, "Modifiers-only shortcuts are not allowed (encountered <" + shortcut + ">)");
if (!keyString)
return null;
var key = WebInspector.KeyboardShortcut.Keys[keyString] || WebInspector.KeyboardShortcut.KeyBindings[keyString];
if (key && key.shiftKey)
modifiers |= WebInspector.KeyboardShortcut.Modifiers.Shift;
return WebInspector.KeyboardShortcut.makeDescriptor(key ? key : keyString, modifiers);
}
/**
* @param {string|!WebInspector.KeyboardShortcut.Key} key
* @param {number=} modifiers
* @return {string}
*/
WebInspector.KeyboardShortcut.shortcutToString = function(key, modifiers)
{
return WebInspector.KeyboardShortcut._modifiersToString(modifiers) + WebInspector.KeyboardShortcut._keyName(key);
}
/**
* @param {string|!WebInspector.KeyboardShortcut.Key} key
* @return {string}
*/
WebInspector.KeyboardShortcut._keyName = function(key)
{
if (typeof key === "string")
return key.toUpperCase();
if (typeof key.name === "string")
return key.name;
return key.name[WebInspector.platform()] || key.name.other || '';
}
/**
* @param {number} keyCode
* @param {?number} modifiers
* @return {number}
*/
WebInspector.KeyboardShortcut._makeKeyFromCodeAndModifiers = function(keyCode, modifiers)
{
return (keyCode & 255) | (modifiers << 8);
};
/**
* @param {number} key
* @return {!{keyCode: number, modifiers: number}}
*/
WebInspector.KeyboardShortcut.keyCodeAndModifiersFromKey = function(key)
{
return { keyCode: key & 255, modifiers: key >> 8 };
}
/**
* @param {number|undefined} modifiers
* @return {string}
*/
WebInspector.KeyboardShortcut._modifiersToString = function(modifiers)
{
var isMac = WebInspector.isMac();
var m = WebInspector.KeyboardShortcut.Modifiers;
var modifierNames = new Map([
[m.Ctrl, isMac ? "Ctrl\u2004" : "Ctrl\u200A+\u200A"],
[m.Alt, isMac ? "opt\u2004" : "Alt\u200A+\u200A"],
[m.Shift, isMac ? "\u21e7\u2004" : "Shift\u200A+\u200A"],
[m.Meta, isMac ? "\u2318\u2004" : "Win\u200A+\u200A"]
]);
return [m.Meta, m.Ctrl, m.Alt, m.Shift].map(mapModifiers).join("");
/**
* @param {number} m
* @return {string}
*/
function mapModifiers(m)
{
return modifiers & m ? /** @type {string} */ (modifierNames.get(m)) : "";
}
};
WebInspector.KeyboardShortcut.SelectAll = WebInspector.KeyboardShortcut.makeKey("a", WebInspector.KeyboardShortcut.Modifiers.CtrlOrMeta);