Alien-GvaScript
view release on metacpan or search on metacpan
src/keyMap.js view on Meta::CPAN
//constructor
GvaScript.KeyMap = function (rules) {
if (!(rules instanceof Object)) throw "KeyMap: invalid argument";
this.rules = [rules];
return this;
};
GvaScript.KeyMap.prototype = {
destroy: function() {
Event.stopObserving(this.elem, this.eventType, this.eventHandler);
},
eventHandler: function(event) {
var keymap = this;
// translate key code into key name
event.keyName = GvaScript.KeyMap.KEYS.BUILTIN_NAMES[event.keyCode]
|| String.fromCharCode(event.keyCode);
// add Control|Shift|Alt modifiers
event.keyModifiers = "";
if (event.ctrlKey && !this.options.ignoreCtrl) event.keyModifiers += "C_";
if (event.shiftKey && !this.options.ignoreShift) event.keyModifiers += "S_";
if (event.altKey && !this.options.ignoreAlt) event.keyModifiers += "A_";
// but cancel all modifiers if main key is Control|Shift|Alt
if (event.keyName.search(/^(CTRL|SHIFT|ALT)$/) == 0)
event.keyModifiers = "";
// try to get the corresponding handler, and call it if found
var handler = keymap._findInStack(event, keymap.rules);
if (handler) {
var toStop = handler.call(keymap, event);
Event.detailedStop(event, toStop || this.options);
}
},
observe: function(eventType, elem, options) {
this.eventType = eventType || 'keydown';
this.elem = elem || document;
// "Shift" modifier usually does not make sense for keypress events
if (eventType == 'keypress' && !options)
options = {ignoreShift: true};
this.options = Class.checkOptions(Event.stopNone, this.options || {});
this.eventHandler = this.eventHandler.bindAsEventListener(this);
Event.observe(this.elem, this.eventType, this.eventHandler);
},
_findInStack: function(event, stack) {
for (var i = stack.length - 1; i >= 0; i--) {
var rules = stack[i];
// trick to differentiate between C_9 (digit) and C_09 (TAB)
var keyCode = event.keyCode>9 ? event.keyCode : ("0"+event.keyCode);
var handler = rules[event.keyModifiers + event.keyName]
|| rules[event.keyModifiers + keyCode]
|| this._regex_handler(event, rules.REGEX, true)
|| this._regex_handler(event, rules.ANTIREGEX, false);
if (handler)
return handler;
}
return null;
},
_regex_handler: function(event, regex_rules, want_match) {
if (!regex_rules) return null;
for (var j = 0; j < regex_rules.length; j++) {
var rule = regex_rules[j];
var modifiers = rule[0];
var regex = rule[1];
var handler = rule[2];
var same_modifiers = modifiers == null
|| modifiers == event.keyModifiers;
// build regex if it was passed as a string
if (typeof(regex) == "string")
regex = new RegExp("^(" + regex + ")$");
var match = same_modifiers && regex.test(event.keyName);
if ((match && want_match) || (!match && !want_match))
return handler;
}
return null;
}
};
GvaScript.KeyMap.MapAllKeys = function(handler) {
return {REGEX:[[null, /.*/, handler]]}
};
GvaScript.KeyMap.Prefix = function(rules) {
// create a specific handler for the next character ...
var one_time_handler = function (event) {
this.rules.pop(); // cancel prefix
var handler = this._findInStack(event, [rules]);
if (handler) handler.call(this, event);
}
// ... and push that handler on top of the current rules
return function(event) {
this.rules.push(GvaScript.KeyMap.MapAllKeys(one_time_handler));
}
};
// helpers for identifying keys
GvaScript.KeyMap.KEYS = {
BUILTIN_NAMES : {
8: "BACKSPACE",
9: "TAB",
10: "LINEFEED",
13: "RETURN",
16: "SHIFT",
17: "CTRL",
18: "ALT",
19: "PAUSE",
20: "CAPS_LOCK",
27: "ESCAPE",
32: "SPACE",
33: "PAGE_UP",
34: "PAGE_DOWN",
35: "END",
36: "HOME",
37: "LEFT",
38: "UP",
( run in 0.321 second using v1.01-cache-2.11-cpan-02777c243ea )