Skip to content

Commit

Permalink
Use "keydown" event to handle hotkeys on non-Latin keyboard layouts
Browse files Browse the repository at this point in the history
+ "keysUseKeydownEvent" preference
(should fix #19)
Note: tested only on Windows and Linux
  • Loading branch information
Infocatcher committed Apr 9, 2013
1 parent 267b1fd commit 47d1852
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 11 deletions.
38 changes: 30 additions & 8 deletions bootstrap.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ var windowsObserver = {
case "popupshowing": this.popupShowingHandler(e); break;
case "command": this.commandHandler(e); break;
case "click": this.clickHandler(e); break;
case "keydown":
case "keypress": this.keypressHandler(e); break;
case "PrivateTab:PrivateChanged": this.privateChangedHandler(e); break;
case "SSWindowStateBusy": this.setWindowBusy(e, true); break;
Expand Down Expand Up @@ -143,7 +144,7 @@ var windowsObserver = {
window.addEventListener("SSWindowStateBusy", this, true);
window.addEventListener("SSWindowStateReady", this, true);
if(this.hotkeys)
window.addEventListener("keypress", this, true);
window.addEventListener(this.keyEvent, this, true);
window.setTimeout(function() {
this.initControls(document);
window.setTimeout(function() {
Expand Down Expand Up @@ -186,7 +187,7 @@ var windowsObserver = {
window.removeEventListener("dragstart", this, true);
window.removeEventListener("dragend", this, true);
window.removeEventListener("drop", this, true);
window.removeEventListener("keypress", this, true);
window.removeEventListener(this.keyEvent, this, true);
window.removeEventListener("PrivateTab:PrivateChanged", this, false);
window.removeEventListener("SSWindowStateBusy", this, true);
window.removeEventListener("SSWindowStateReady", this, true);
Expand Down Expand Up @@ -243,6 +244,8 @@ var windowsObserver = {

prefChanged: function(pName, pVal) {
if(pName.startsWith("key."))
this.updateHotkeys(true);
else if(pName == "keysUseKeydownEvent")
this.updateHotkeys();
else if(pName == "fixAppButtonWidth") {
this.appButtonDontChange = !pVal;
Expand Down Expand Up @@ -750,7 +753,7 @@ var windowsObserver = {
&& e.metaKey == k.metaKey
&& e.getModifierState("OS") == k.osKey
&& (
k.char && String.fromCharCode(e.charCode).toUpperCase() == k.char
k.char && String.fromCharCode(e.charCode || e.keyCode).toUpperCase() == k.char
|| k.code && e.keyCode == k.code
)
) {
Expand Down Expand Up @@ -1322,6 +1325,11 @@ var windowsObserver = {
force && node.parentNode.removeChild(node);
},

get keyEvent() {
return prefs.get("keysUseKeydownEvent")
? "keydown"
: "keypress";
},
hotkeys: null,
_hotkeysHasText: false,
get accelKey() {
Expand All @@ -1339,6 +1347,12 @@ var windowsObserver = {
this._hotkeysHasText = false;
var hasKeys = false;
var keys = { __proto__: null };
function getVKChar(vk) {
var tmp = {};
Services.scriptloader.loadSubScript("chrome://privatetab/content/virtualKeyCodes.js", tmp);
getVKChar = tmp.getVKChar;
return getVKChar(vk);
}
function initHotkey(kId) {
var keyStr = prefs.get("key." + kId);
_log("initHotkey: " + kId + " = " + keyStr);
Expand Down Expand Up @@ -1367,7 +1381,11 @@ var windowsObserver = {
}
else { // VK_*
k.code = Components.interfaces.nsIDOMKeyEvent["DOM_" + key];
k._keyCode = key;
var char = getVKChar(key);
if(char)
k._key = char;
else
k._keyCode = key;
}
k._modifiers = tokens.join(",");
tokens.forEach(function(token) {
Expand Down Expand Up @@ -1479,13 +1497,17 @@ var windowsObserver = {
});
}
},
updateHotkeys: function() {
_log("updateHotkeys()");
this.initHotkeys();
updateHotkeys: function(updateAll) {
_log("updateHotkeys(" + (updateAll || "") + ")");
updateAll && this.initHotkeys();
var hasHotkeys = !!this.hotkeys;
var keyEvent = this.keyEvent;
this.windows.forEach(function(window) {
window.removeEventListener("keydown", this, true);
window.removeEventListener("keypress", this, true);
hasHotkeys && window.addEventListener("keypress", this, true);
hasHotkeys && window.addEventListener(keyEvent, this, true);
if(!updateAll)
return;
var document = window.document;
this.getHotkeysNodes(document, "*").forEach(function(node) {
var cl = node.classList;
Expand Down
8 changes: 5 additions & 3 deletions defaults/preferences/prefs.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,16 @@ pref("extensions.privateTab.loadInBackground", -1);
// 0 - load in foreground
// 1 - load in background

pref("extensions.privateTab.keysIgnoreDefaultPrevented", false); // Ignore, if someone stops "keypress" event
pref("extensions.privateTab.keysUseKeydownEvent", true); // Use "keydown" event instead of "keypress"
pref("extensions.privateTab.keysIgnoreDefaultPrevented", false); // Ignore, if someone stops key* event
// See https://developer.mozilla.org/en-US/docs/XUL/Tutorial/Keyboard_Shortcuts
// and https://developer.mozilla.org/en-US/docs/DOM/KeyboardEvent#Virtual_key_codes
// Syntax: [<modifiers> ]<key or keycode>
// It's better to use VK_* codes for keysUseKeydownEvent = true.
// You can also create alias for hotkey using extensions.privateTab.key.%command%#%alias_name%, example:
// pref("extensions.privateTab.key.openNewPrivateTab#2", "VK_F8")
pref("extensions.privateTab.key.openNewPrivateTab", "control alt p");
pref("extensions.privateTab.key.toggleTabPrivate", "control alt v");
pref("extensions.privateTab.key.openNewPrivateTab", "control alt VK_P");
pref("extensions.privateTab.key.toggleTabPrivate", "control alt VK_V");

pref("extensions.privateTab.dragAndDropBehavior", 0);
// 0 - make new (or target) tab private, if source or target are private
Expand Down
47 changes: 47 additions & 0 deletions virtualKeyCodes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
function getVKChar(vk) {
// Firefox doesn't have string representation for some codes...
// https://developer.mozilla.org/en-US/docs/DOM/KeyboardEvent#Virtual_key_codes
if(/^VK_(?:NUMPAD)?([\d+A-Z])$/.test(vk))
return RegExp.$1;
switch(vk) {
case "VK_SPACE": return " "; //32
case "VK_COLON": return ":"; //58
case "VK_SEMICOLON": return ";"; //59
case "VK_LESS_THAN": return "<"; //60
case "VK_EQUALS": return "="; //61
case "VK_GREATER_THAN": return ">"; //62
case "VK_QUESTION_MARK": return "?"; //63
case "VK_AT": return "@"; //64
case "VK_MULTIPLY": return "*"; //106
case "VK_ADD": return "+"; //107
case "VK_SUBTRACT": return "-"; //109
case "VK_DECIMAL": return "."; //110
case "VK_DIVIDE": return "/"; //111
case "VK_CIRCUMFLEX": return "^"; //160
case "VK_EXCLAMATION": return "!"; //161
case "VK_DOUBLE_QUOTE": return '"'; //162
case "VK_HASH": return "#"; //163
case "VK_DOLLAR": return "$"; //164
case "VK_PERCENT": return "%"; //165
case "VK_AMPERSAND": return "&"; //166
case "VK_UNDERSCORE": return "_"; //167
case "OPEN_PAREN": return "("; //168
case "CLOSE_PAREN": return ")"; //169
case "VK_ASTERISK": return "*"; //170
case "VK_PLUS": return "+"; //171
case "VK_PIPE": return "|"; //172
case "VK_HYPHEN_MINUS": return "-"; //173
case "VK_OPEN_CURLY_BRACKET": return "{"; //174
case "VK_CLOSE_CURLY_BRACKET": return "}"; //175
case "VK_TILDE": return "~"; //176
case "VK_COMMA": return ","; //188
case "VK_PERIOD": return "."; //190
case "VK_SLASH": return "/"; //191
case "VK_BACK_QUOTE": return "`"; //192
case "VK_OPEN_BRACKET": return "["; //219
case "VK_BACK_SLASH": return "\\"; //220
case "VK_CLOSE_BRACKET": return "]"; //221
case "VK_QUOTE": return "'"; //222
}
return undefined;
}

0 comments on commit 47d1852

Please sign in to comment.