I have the following code
(function($){
$.fn.kb = function(evt, map, fn, options)
{
var _this = this;
var modifiers = [17, 18, 19];
function precise(a, b)
{
return b.Size - a.Size;
}
if (!this.data("Combos"))
this.data("Combos", []);
var combos = this.data("Combos");
var combo = { Size: map.Keys.length, Function: fn, Keys: map.Keys.join("").toLowerCase() };
combos.push(combo)
combos.sort(precise);
map = $.extend({ Modifiers: [], Keys: [] }, map);
var KeysTimerKey = "KeysTimer" + map.Modifiers.join("") + map.Keys.join("");
var KeysKeyKey = "Keys" + map.Modifiers.join("") + map.Keys.join("");
options = $.extend({NoInput:false, Delay: 350, PreventDefault:false}, options);
var specialKeys = { 27: 'esc', 9: 'tab', 32:'space', 13: 'return', 8:'backspace', 145: 'scroll',
20: 'capslock', 144: 'numlock', 19:'pause', 45:'insert', 36:'home', 46:'del',
35:'end', 33: 'pageup', 34:'pagedown', 37:'left', 38:'up', 39:'right',40:'down',
109: '-',
112:'f1',113:'f2', 114:'f3', 115:'f4', 116:'f5', 117:'f6', 118:'f7', 119:'f8',
120:'f9', 121:'f10', 122:'f11', 123:'f12', 191: '/'};
var FromCharCode =
function(code)
{
if (specialKeys[code] != undefined)
return specialKeys[code];
return String.fromCharCode(code);
};
this.bind
(
evt,
function(e)
{
if (modifiers.indexOf(e.keyCode) == -1)
{
if (options.NoInput && ["input", "textarea"].indexOf(e.target.tagName.toLowerCase()) > -1) return;
var ctrl = map.Modifiers.join("$").match(/ctrl/i) != null;
var shift = map.Modifiers.join("$").match(/shift/i) != null;
var alt = map.Modifiers.join("$").match(/alt/i) != null;
if (e.ctrlKey == ctrl &&
e.altKey == alt &&
e.shiftKey == shift)
{
var key = FromCharCode(e.keyCode);
if (((e.ctrlKey || e.altKey || e.shiftKey) || specialKeys[e.keyCode] != undefined) &&
options.PreventDefault) e.preventDefault();
if (_this.data(KeysTimerKey) != null) clearTimeout(_this.data(KeysTimerKey));
var keys = _this.data(KeysKeyKey) || [];
keys.push(FromCharCode(e.keyCode));
_this.data(KeysKeyKey, keys);
_this.data(KeysTimerKey, setTimeout(function(){ _this.data(KeysKeyKey, ""); }, options.Delay));
var input = _this.data(KeysKeyKey).join("").toLowerCase();
var keys = map.Keys.join("").toLowerCase();
if (input.slice(-keys.length) == keys)
{
var found = -1;
for (var i = 0; i < combos.length; ++i)
{
if (combos[i].Keys.slice(-keys.length) == input)
{
if (keys.length >= combos[i].Keys.length) found = i;
}
}
}
if (found >= 0)
{
combos[found].Function(e);
_this.data(KeysKeyKey, null);
}
}
}
}
);
}
})(jQuery);
/**/
$(window).kb("keydown", { Modifiers: [], Keys: ["down", "right", "a"] }, function () {alert("Hadouken");});
$(window).kb("keydown", { Modifiers: [], Keys: ["down", "right", "down", "right", "a"] }, function () {alert("Shouryuuken");});
It stores all combinations on the data of the element. When a sequence of keys match (it is checked by all keys pressed by the user than compared the end of this string to the sequence set to the element), I check an array which stores all sequences and callback functions to see if there is one more specific. If it finds the callback function will not be called.
Meaning, if I press ▼ ► ▼ ► A it will trigger Shouryuuken
and not Hadouken
.
I wonder if it can be faster, checking the array all the time to see if there is some more specific sequences seems expensive.
Update code
You could store your combos in a tree data structure. A key combination would just be a potential "path" through the tree. Then checking a combination would just mean trying to traverse that path of the tree:
▼
|
►
/\
/ \
a ▼
| |
"Hadouken" ►
|
a
|
"Shouryuuken"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With