bug 441794: properly convert dom key events into keyspecs and thence to readable strings

This commit is contained in:
Daniel Brooks 2008-07-17 16:45:08 -05:00
Родитель 034e502cac
Коммит 6b5253da97
2 изменённых файлов: 166 добавлений и 24 удалений

Просмотреть файл

@ -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