There are a couple things you can do but I see no reason for memory leaks.
I have commented my edits.
var keys = [];
// Integers takes less space than strings, and we might as well put it in an array already
var shortcut = [
17, // ctrl
16, // shift
83 // s
];
window.addGlobalHotkey = function(callback, keyValues){
if(typeof keyValues === "number")
keyValues = [keyValues];
// Unfortunately, because you need the cb argument we can't define it outside the addGlobalHotkey method.
var fnc = function(cb, val){
return function(e){
keys[e.keyCode] = true;
executeHotkeyTest(cb, val);
};
}(callback, keyValues);
window.addEventListener('keydown', fnc);
return fnc;
};
window.executeHotkeyTest = function(callback, keyValues) {
var i = keyValues.length;
while(i--) {
// If key is not pressed, we might as well abort
if(!keys[keyValues[i]]) return;
}
callback();
};
window.addEventListener('keyup',function(e) {
// Remove key instead of setting it to false
keys.splice(e.keyCode, 1);
});
addGlobalHotkey(function() {
var x = getIn("What Task?");
// If x is empty there's no point in resuming
if(!x) return;
// If-statements are faster than switches, just saying.
switch(x)
{
case "a":
//...
break;
case "t":
//...
break;
default:
//...;
}
}, shortcut);
function getIn(text){
var x = prompt(text);
// Altered if statement
if(typeof x === 'string' && x.length > 0) return x;
}
The most potential leak is the fact that the array keys will only grow as you press more different keys. Hence the .splice()
method.
Edit
I have reviewed your code again. I couldn't help noticing that you create a new onkeydown
listener whenever you register a new hotkey. I've changed that. Try the following code instead, and see if it still runs slow.
/* VARIABLES */
var keysPressed = [];
var hotkeys = [];
/* EVENT LISTENERS */
// Listen for keydown once instead for every hotkey
window.addEventListener('keydown', function(e) {
// A button was pressed
keysPressed[e.keyCode] = true;
checkHotkeys();
}, false);
window.addEventListener('keyup', function(e) {
// Remove key
keysPressed.splice(e.keyCode, 1);
}, false);
/* FUNCTIONS */
function checkHotkeys() {
var i = hotkeys.length;
while(i--) {
executeHotkeyTest(
hotkeys[i].callback,
hotkeys[i].keys
);
}
};
function addGlobalHotkey(callback, keys) {
if(typeof keys === "number")
keys = [keys];
hotkeys.push({
callback: callback,
keys: keys
});
};
function executeHotkeyTest(callback, keys) {
var i = keys.length;
while(i--) {
// If key is not pressed, we might as well abort
if(!keysPressed[keys[i]]) return;
}
callback();
};
function getIn(text){
var x = prompt(text);
// Altered if statement
if(typeof x === 'string' && x.length > 0) return x;
}
/* OTHER */
// Integers takes less space than strings
var shortcut = [
17, // ctrl
16, // shift
83 // s
];
addGlobalHotkey(function() {
var x = getIn("What Task?");
// If-statements are faster than switches, just saying.
switch(x)
{
case "a":
//...
break;
case "t":
//...
break;
default:
//...;
}
}, shortcut);
Edit #2
I've found the issue!
So we've been using the keycode as index for the array - a numeric index. These are not associative. Have a look at the following example.
0: 'abc',
1: 'def',
2: 'ghi'
Delete 1
0: 'abc',
1: 'ghi'
Delete 2
0: 'abc',
1: 'ghi'
By converting them to a string, your array becomes an associate array and the right keys will be deleted.
// Listen for keydown once instead for every hotkey
window.addEventListener('keydown', function(e) {
// A button was pressed
keysPressed[e.keyCode.toString()] = true;
checkHotkeys();
}, false);
window.addEventListener('keyup', function(e) {
// Remove key
delete keysPressed[e.keyCode.toString()];
}, false);
Check out the working demo: http://jsfiddle.net/rQePB/1/