зеркало из https://github.com/mozilla/gecko-dev.git
bug 441794: properly convert dom key events into keyspecs and thence to readable strings
This commit is contained in:
Родитель
034e502cac
Коммит
6b5253da97
|
@ -58,14 +58,16 @@
|
||||||
<stringbundle id="bundle_browser" src="chrome://browser/locale/browser.properties"/>
|
<stringbundle id="bundle_browser" src="chrome://browser/locale/browser.properties"/>
|
||||||
<stringbundle id="bundle-keys" src="chrome://global/locale/keys.properties"/>
|
<stringbundle id="bundle-keys" src="chrome://global/locale/keys.properties"/>
|
||||||
<stringbundle id="bundle-platformKeys" src="chrome://global-platform/locale/platformKeys.properties"/>
|
<stringbundle id="bundle-platformKeys" src="chrome://global-platform/locale/platformKeys.properties"/>
|
||||||
<stringbundle id="bundle-shortcuts" src="chrome://browser/locale/shortcuts.properties"/>
|
</stringbundleset>
|
||||||
|
<stringbundleset id="shortcut-bundles">
|
||||||
|
<stringbundle src="chrome://browser/locale/shortcuts.properties"/>
|
||||||
</stringbundleset>
|
</stringbundleset>
|
||||||
|
|
||||||
<script type="application/x-javascript" src="chrome://global/content/inlineSpellCheckUI.js"/>
|
<script type="application/x-javascript" src="chrome://global/content/inlineSpellCheckUI.js"/>
|
||||||
<script type="application/x-javascript" src="chrome://browser/content/commandUtil.js"/>
|
<script type="application/x-javascript" src="chrome://browser/content/commandUtil.js"/>
|
||||||
<script type="application/x-javascript" src="chrome://browser/content/browser.js"/>
|
<script type="application/x-javascript" src="chrome://browser/content/browser.js"/>
|
||||||
<script type="application/x-javascript" src="chrome://browser/content/browser-ui.js"/>
|
<script type="application/x-javascript" src="chrome://browser/content/browser-ui.js"/>
|
||||||
<script type="application/x-javascript" src="chrome://browser/content/shortcuts.js"/>
|
<script type="application/x-javascript;version=1.8" src="chrome://browser/content/shortcuts.js"/>
|
||||||
|
|
||||||
<commandset id="cmdset_main">
|
<commandset id="cmdset_main">
|
||||||
<!-- basic navigation -->
|
<!-- basic navigation -->
|
||||||
|
@ -115,7 +117,7 @@
|
||||||
|
|
||||||
<!-- misc -->
|
<!-- misc -->
|
||||||
<key id="key_fullscreen" keycode="VK_F6" command="cmd_fullscreen"/>
|
<key id="key_fullscreen" keycode="VK_F6" command="cmd_fullscreen"/>
|
||||||
<key id="key_addons" key="E" command="cmd_addons" modifiers="control"/>
|
<key id="key_addons" key="E" command="cmd_addons" modifiers="accel"/>
|
||||||
<key id="key_downloads" key="J" command="cmd_downloads" modifiers="control"/>
|
<key id="key_downloads" key="J" command="cmd_downloads" modifiers="control"/>
|
||||||
</keyset>
|
</keyset>
|
||||||
|
|
||||||
|
@ -242,6 +244,7 @@
|
||||||
<treechildren id="shortcuts-children"/>
|
<treechildren id="shortcuts-children"/>
|
||||||
</tree>
|
</tree>
|
||||||
<hbox pack="end">
|
<hbox pack="end">
|
||||||
|
<textbox id="test"/>
|
||||||
<button label="Dismiss" oncommand="Shortcuts.dismiss();"/>
|
<button label="Dismiss" oncommand="Shortcuts.dismiss();"/>
|
||||||
</hbox>
|
</hbox>
|
||||||
</vbox>
|
</vbox>
|
||||||
|
|
|
@ -40,7 +40,7 @@
|
||||||
// TODO: read the prefs when the window is opened, and make the required changes
|
// TODO: read the prefs when the window is opened, and make the required changes
|
||||||
// TODO: see about grouping the keys into categories
|
// TODO: see about grouping the keys into categories
|
||||||
|
|
||||||
//Components.utils.import("resource://gre/modules/json.jsm");
|
Components.utils.import("resource://gre/modules/JSON.jsm");
|
||||||
|
|
||||||
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
||||||
|
|
||||||
|
@ -125,19 +125,132 @@ function ShortcutEditor()
|
||||||
|
|
||||||
function makeKeySpec(modifiers, key, keycode)
|
function makeKeySpec(modifiers, key, keycode)
|
||||||
{
|
{
|
||||||
|
// TODO: make this check more specific, once key elements implement a unique interface
|
||||||
if (modifiers instanceof Components.interfaces.nsIDOMElement)
|
if (modifiers instanceof Components.interfaces.nsIDOMElement)
|
||||||
return {
|
return {
|
||||||
modifiers: modifiers.getAttribute("modifiers"),
|
modifiers: getFlagsForModifiers(modifiers.getAttribute("modifiers")),
|
||||||
key: modifiers.getAttribute("key"),
|
key: modifiers.getAttribute("key"),
|
||||||
keycode: modifiers.getAttribute("keycode")
|
keycode: modifiers.getAttribute("keycode")
|
||||||
};
|
};
|
||||||
|
if (modifiers instanceof Components.interfaces.nsIDOMKeyEvent)
|
||||||
|
return {
|
||||||
|
modifiers: getEventModifiers(modifiers),
|
||||||
|
key: getEventKey(modifiers),
|
||||||
|
keycode: getEventKeyCode(modifiers)
|
||||||
|
};
|
||||||
return {
|
return {
|
||||||
modifiers: modifiers,
|
modifiers: getFlagsForModifiers(modifiers),
|
||||||
key: key,
|
key: key,
|
||||||
keycode: keycode
|
keycode: keycode
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var modifierFlags = { alt: 1, control: 2, meta: 4, shift: 8 };
|
||||||
|
function getFlagsForModifiers(modifiers)
|
||||||
|
{
|
||||||
|
if (!modifiers)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
var result;
|
||||||
|
for each (m in modifiers.split(" "))
|
||||||
|
result |= modifierFlags[m];
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getEventModifiers(event)
|
||||||
|
{
|
||||||
|
var result, i = 1;
|
||||||
|
for each (m in [event.altKey, event.ctrlKey, event.metaKey, event.shiftKey])
|
||||||
|
{
|
||||||
|
result |= (m && i);
|
||||||
|
i += i;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getEventKey(event)
|
||||||
|
{
|
||||||
|
if (event.charCode)
|
||||||
|
return String.fromCharCode(event.charCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getEventKeyCode(event)
|
||||||
|
{
|
||||||
|
var keyCodeMap = { };
|
||||||
|
var nsIDOMKeyEvent = Components.interfaces.nsIDOMKeyEvent;
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_CANCEL] = "VK_CANCEL";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_HELP] = "VK_HELP";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_BACK_SPACE] = "VK_BACK_SPACE";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_TAB] = "VK_TAB";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_CLEAR] = "VK_CLEAR";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_RETURN] = "VK_RETURN";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_ENTER] = "VK_ENTER";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_SHIFT] = "VK_SHIFT";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_CONTROL] = "VK_CONTROL";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_ALT] = "VK_ALT";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_PAUSE] = "VK_PAUSE";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_CAPS_LOCK] = "VK_CAPS_LOCK";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_ESCAPE] = "VK_ESCAPE";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_SPACE] = "VK_SPACE";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_PAGE_UP] = "VK_PAGE_UP";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_PAGE_DOWN] = "VK_PAGE_DOWN";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_END] = "VK_END";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_HOME] = "VK_HOME";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_LEFT] = "VK_LEFT";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_UP] = "VK_UP";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_RIGHT] = "VK_RIGHT";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_DOWN] = "VK_DOWN";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_PRINTSCREEN] = "VK_PRINTSCREEN";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_INSERT] = "VK_INSERT";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_DELETE] = "VK_DELETE";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_SEMICOLON] = "VK_SEMICOLON";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_EQUALS] = "VK_EQUALS";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_CONTEXT_MENU] = "VK_CONTEXT_MENU";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_MULTIPLY] = "VK_MULTIPLY";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_ADD] = "VK_ADD";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_SEPARATOR] = "VK_SEPARATOR";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_SUBTRACT] = "VK_SUBTRACT";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_DECIMAL] = "VK_DECIMAL";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_DIVIDE] = "VK_DIVIDE";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_F1] = "VK_F1";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_F2] = "VK_F2";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_F3] = "VK_F3";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_F4] = "VK_F4";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_F5] = "VK_F5";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_F6] = "VK_F6";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_F7] = "VK_F7";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_F8] = "VK_F8";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_F9] = "VK_F9";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_F10] = "VK_F10";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_F11] = "VK_F11";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_F12] = "VK_F12";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_F13] = "VK_F13";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_F14] = "VK_F14";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_F15] = "VK_F15";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_F16] = "VK_F16";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_F17] = "VK_F17";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_F18] = "VK_F18";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_F19] = "VK_F19";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_F20] = "VK_F20";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_F21] = "VK_F21";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_F22] = "VK_F22";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_F23] = "VK_F23";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_F24] = "VK_F24";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_NUM_LOCK] = "VK_NUM_LOCK";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_SCROLL_LOCK] = "VK_SCROLL_LOCK";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_COMMA] = "VK_COMMA";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_PERIOD] = "VK_PERIOD";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_SLASH] = "VK_SLASH";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_BACK_QUOTE] = "VK_BACK_QUOTE";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_OPEN_BRACKET] = "VK_OPEN_BRACKET";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_BACK_SLASH] = "VK_BACK_SLASH";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_CLOSE_BRACKET] = "VK_CLOSE_BRACKET";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_QUOTE] = "VK_QUOTE";
|
||||||
|
keyCodeMap[nsIDOMKeyEvent.DOM_VK_META] = "VK_META";
|
||||||
|
|
||||||
|
return keyCodeMap[event.keyCode];
|
||||||
|
}
|
||||||
|
|
||||||
// This code is all about converting key elements into human-readable
|
// This code is all about converting key elements into human-readable
|
||||||
// descriptions of the keys they match. Copied essentially verbatim from
|
// descriptions of the keys they match. Copied essentially verbatim from
|
||||||
// nsMenuFrame::BuildAcceleratorText
|
// nsMenuFrame::BuildAcceleratorText
|
||||||
|
@ -170,25 +283,43 @@ function ShortcutEditor()
|
||||||
platformAccel[Components.interfaces.nsIDOMKeyEvent.DOM_VK_CONTROL] = platformKeys.control;
|
platformAccel[Components.interfaces.nsIDOMKeyEvent.DOM_VK_CONTROL] = platformKeys.control;
|
||||||
platformKeys.accel = platformAccel[accelKey] || platformKeys.control;
|
platformKeys.accel = platformAccel[accelKey] || platformKeys.control;
|
||||||
|
|
||||||
function getKeyName(key) {
|
function getKeyName(keySpec) {
|
||||||
// convert a key element into a string describing what keys to push.
|
// convert a key element into a string describing what keys to push.
|
||||||
// "Control-C" or "Control-Meta-Hyper-Shift-Q" or whatever
|
// "Control-C" or "Control-Meta-Hyper-Shift-Q" or whatever
|
||||||
if (!key)
|
if (!keySpec)
|
||||||
return "";
|
return "";
|
||||||
var keySpec = makeKeySpec(key);
|
if (keySpec instanceof Components.interfaces.nsIDOMElement)
|
||||||
|
keySpec = makeKeySpec(keySpec);
|
||||||
|
|
||||||
var accel = [];
|
var accel = [];
|
||||||
var keybundle = document.getElementById("bundle-keys");
|
var keybundle = document.getElementById("bundle-keys");
|
||||||
var keyName = keySpec.keytext || keySpec.key || keybundle.getString(keySpec.keycode);
|
|
||||||
var modifiers = keySpec.modifiers.split(" ");
|
// this is sorta dumb, but whatever
|
||||||
|
var modifiers = [], i = 1;
|
||||||
|
for each (m in ["alt", "control", "meta", "shift"])
|
||||||
|
{
|
||||||
|
if (keySpec.modifiers & i)
|
||||||
|
modifiers.push(m);
|
||||||
|
i += i;
|
||||||
|
}
|
||||||
|
|
||||||
for each (m in modifiers)
|
for each (m in modifiers)
|
||||||
if (m in platformKeys)
|
if (m in platformKeys)
|
||||||
accel.push(platformKeys[m]);
|
accel.push(platformKeys[m]);
|
||||||
accel.push(keyName);
|
accel.push(keySpec.keytext || keySpec.key || keybundle.getString(keySpec.keycode));
|
||||||
|
|
||||||
return accel.join(modifierSeparator);
|
return accel.join(modifierSeparator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// this listens to keyup events and converts them into the proper display name for the textbox
|
||||||
|
function keyListener(event)
|
||||||
|
{
|
||||||
|
if (!event instanceof Components.interfaces.nsIDOMKeyEvent)
|
||||||
|
return;
|
||||||
|
document.getElementById("test").value = getKeyName(makeKeySpec(event));
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
|
||||||
// show the window
|
// show the window
|
||||||
this.edit = function()
|
this.edit = function()
|
||||||
{
|
{
|
||||||
|
@ -196,53 +327,61 @@ function ShortcutEditor()
|
||||||
Array.forEach(nodes, function(n) { if (n.getAttribute("id") != "browser-container") { n.hidden = true; }});
|
Array.forEach(nodes, function(n) { if (n.getAttribute("id") != "browser-container") { n.hidden = true; }});
|
||||||
document.getElementById("shortcuts-container").hidden = false;
|
document.getElementById("shortcuts-container").hidden = false;
|
||||||
fillShortcutList();
|
fillShortcutList();
|
||||||
|
|
||||||
|
document.getElementById("test").addEventListener("keypress", keyListener, true);
|
||||||
};
|
};
|
||||||
|
|
||||||
this.dismiss = function()
|
this.dismiss = function()
|
||||||
{
|
{
|
||||||
|
document.getElementById("test").removeEventListener("keypress", keyListener, true);
|
||||||
document.getElementById("shortcuts-container").hidden = true;
|
document.getElementById("shortcuts-container").hidden = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
// also, updating the UI is helpful
|
// also, updating the UI is helpful
|
||||||
function fillShortcutList()
|
function fillShortcutList()
|
||||||
{
|
{
|
||||||
var tree = document.getElementById("shortcuts");
|
|
||||||
var commands = getCommandNames();
|
var commands = getCommandNames();
|
||||||
var sb = document.getElementById("bundle-shortcuts");
|
var sb = document.getElementById("shortcut-bundles").childNodes;
|
||||||
|
|
||||||
function doAppend(name, key)
|
function doAppend(command)
|
||||||
{
|
{
|
||||||
// TODO: alter the listbox xbl binding so that if appendItem is
|
// TODO: alter the listbox xbl binding so that if appendItem is
|
||||||
// given more than 2 arguments, it interprets the additional
|
// given more than 2 arguments, it interprets the additional
|
||||||
// arguments as labels for additional cells.
|
// arguments as labels for additional cells.
|
||||||
|
var key = findKeyForCommand(command)
|
||||||
var cell1 = document.createElementNS(XUL_NS, "treecell");
|
var cell1 = document.createElementNS(XUL_NS, "treecell");
|
||||||
cell1.setAttribute("label", name);
|
cell1.setAttribute("label", doGetString(command +".name") || command);
|
||||||
|
cell1.setAttribute("value", command);
|
||||||
var cell2 = document.createElementNS(XUL_NS, "treecell");
|
var cell2 = document.createElementNS(XUL_NS, "treecell");
|
||||||
cell2.setAttribute("label", key);
|
cell2.setAttribute("label", getKeyName(key));
|
||||||
|
cell2.setAttribute("value", makeKeySpec(key));
|
||||||
var row = document.createElementNS(XUL_NS, "treerow");
|
var row = document.createElementNS(XUL_NS, "treerow");
|
||||||
row.appendChild(cell1);
|
row.appendChild(cell1);
|
||||||
row.appendChild(cell2);
|
row.appendChild(cell2);
|
||||||
var item = document.createElementNS(XUL_NS, "treeitem");
|
var item = document.createElementNS(XUL_NS, "treeitem");
|
||||||
item.appendChild(row);
|
item.appendChild(row);
|
||||||
document.getElementById("shortcuts-children").appendChild(item);
|
children.appendChild(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
function doGetString(name)
|
function doGetString(name)
|
||||||
{
|
{
|
||||||
try
|
var l = sb.length;
|
||||||
{
|
for (var i = 0; i < l; i++)
|
||||||
return sb.getString(name);
|
try
|
||||||
}
|
{
|
||||||
catch (e) { }
|
return sb[i].getString(name);
|
||||||
|
}
|
||||||
|
catch (e) { }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var tree = document.getElementById("shortcuts");
|
||||||
var children = document.getElementById("shortcuts-children");
|
var children = document.getElementById("shortcuts-children");
|
||||||
tree.removeChild(children);
|
tree.removeChild(children);
|
||||||
children = document.createElementNS(XUL_NS, "treechildren");
|
children = document.createElementNS(XUL_NS, "treechildren");
|
||||||
children.setAttribute("id", "shortcuts-children");
|
children.setAttribute("id", "shortcuts-children");
|
||||||
tree.appendChild(children);
|
tree.appendChild(children);
|
||||||
|
|
||||||
commands.forEach(function(c) { doAppend(doGetString(c +".name") || c, getKeyName(findKeyForCommand(c)) || "—"); });
|
commands.forEach(doAppend);
|
||||||
}
|
}
|
||||||
|
|
||||||
// saving and restoring a key assignment to the prefs
|
// saving and restoring a key assignment to the prefs
|
||||||
|
|
Загрузка…
Ссылка в новой задаче