      1 xq.Shortcut = Class.create({
      2 	initialize: function(keymapOrExpression) {
      3 		this.keymap = (typeof keymapOrExpression == "string") ?
      4 			xq.Shortcut.interprete(keymapOrExpression).keymap :
      5 			keymapOrExpression;
      6 	},
      7 	matches: function(e) {
      8 		var which = xq.Browser.isGecko && xq.Browser.isMac ? (e.keyCode + "_" + e.charCode) : e.keyCode;
      9
     10 		var keyMatches =
     11 			(this.keymap.which == which) ||
     12 			(this.keymap.which == 32 && which == 25); // 25 is SPACE in Type-3 keyboard.
     13
     14 		if(typeof e.metaKey == "undefined") e.metaKey = false;
     15
     16 		var modifierMatches =
     17 			(typeof this.keymap.shiftKey == "undefined" || this.keymap.shiftKey == e.shiftKey) &&
     18 			(typeof this.keymap.altKey == "undefined" || this.keymap.altKey == e.altKey) &&
     19 			(typeof this.keymap.ctrlKey == "undefined" || this.keymap.ctrlKey == e.ctrlKey) &&
     20 			(typeof this.keymap.metaKey == "undefined" || this.keymap.metaKey == e.metaKey)
     21
     22 		return modifierMatches && keyMatches;
     23 	}
     24 });
     25
     26 xq.Shortcut.interprete = function(expression) {
     27 	expression = expression.toUpperCase();
     28
     29 	var which = xq.Shortcut._interpreteWhich(expression.split("+").pop());
     30 	var ctrlKey = xq.Shortcut._interpreteModifier(expression, "CTRL");
     31 	var altKey = xq.Shortcut._interpreteModifier(expression, "ALT");
     32 	var shiftKey = xq.Shortcut._interpreteModifier(expression, "SHIFT");
     33 	var metaKey = xq.Shortcut._interpreteModifier(expression, "META");
     34
     35 	var keymap = {};
     36
     37 	keymap.which = which;
     38 	if(typeof ctrlKey != "undefined") keymap.ctrlKey = ctrlKey;
     39 	if(typeof altKey != "undefined") keymap.altKey = altKey;
     40 	if(typeof shiftKey != "undefined") keymap.shiftKey = shiftKey;
     41 	if(typeof metaKey != "undefined") keymap.metaKey = metaKey;
     42
     43 	return new xq.Shortcut(keymap);
     44 }
     45
     46 xq.Shortcut._interpreteModifier = function(expression, modifierName) {
     47 	return expression.match("\\(" + modifierName + "\\)") ?
     48 		undefined :
     49 			expression.match(modifierName) ?
     50 			true : false;
     51 }
     52 xq.Shortcut._interpreteWhich = function(keyName) {
     53 	var which = keyName.length == 1 ?
     54 		((xq.Browser.isMac && xq.Browser.isGecko) ? "0_" + keyName.toLowerCase().charCodeAt(0) : keyName.charCodeAt(0)) :
     55 		xq.Shortcut._keyNames[keyName];
     56
     57 	if(typeof which == "undefined") throw "Unknown special key name: [" + keyName + "]"
     58
     59 	return which;
     60 }
     61 xq.Shortcut._keyNames =
     62 	xq.Browser.isMac && xq.Browser.isGecko ?
     63 	{
     64 		BACKSPACE: "8_0",
     65 		TAB: "9_0",
     66 		RETURN: "13_0",
     67 		ENTER: "13_0",
     68 		ESC: "27_0",
     69 		SPACE: "0_32",
     70 		LEFT: "37_0",
     71 		UP: "38_0",
     72 		RIGHT: "39_0",
     73 		DOWN: "40_0",
     74 		DELETE: "46_0",
     75 		HOME: "36_0",
     76 		END: "35_0",
     77 		PAGEUP: "33_0",
     78 		PAGEDOWN: "34_0",
     79 		COMMA: "0_44",
     80 		HYPHEN: "0_45",
     81 		EQUAL: "0_61",
     82 		PERIOD: "0_46",
     83 		SLASH: "0_47",
     84 		F1: "112_0",
     85 		F2: "113_0",
     86 		F3: "114_0",
     87 		F4: "115_0",
     88 		F5: "116_0",
     89 		F6: "117_0",
     90 		F7: "118_0",
     91 		F8: "119_0"
     92 	}
     93 	:
     94 	{
     95 		BACKSPACE: 8,
     96 		TAB: 9,
     97 		RETURN: 13,
     98 		ENTER: 13,
     99 		ESC: 27,
    100 		SPACE: 32,
    101 		LEFT: 37,
    102 		UP: 38,
    103 		RIGHT: 39,
    104 		DOWN: 40,
    105 		DELETE: 46,
    106 		HOME: 36,
    107 		END: 35,
    108 		PAGEUP: 33,
    109 		PAGEDOWN: 34,
    110 		COMMA: 188,
    111 		HYPHEN: xq.Browser.isTrident ? 189 : 109,
    112 		EQUAL: xq.Browser.isTrident ? 187 : 61,
    113 		PERIOD: 190,
    114 		SLASH: 191,
    115 		F1:112,
    116 		F2:113,
    117 		F3:114,
    118 		F4:115,
    119 		F5:116,
    120 		F6:117,
    121 		F7:118,
    122 		F8:119,
    123 		F9:120,
    124 		F10:121,
    125 		F11:122,
    126 		F12:123
    127 	}
    128