forked from ghosert/VimProject
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathKeymap.js
More file actions
executable file
·198 lines (197 loc) · 9.07 KB
/
Keymap.js
File metadata and controls
executable file
·198 lines (197 loc) · 9.07 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
/*
* Keymap.js: bind key events to handler functions.
*
* This module defines a Keymap class. An instance of this class represents a
* mapping of key identifiers (defined below) to handler functions. A
* Keymap can be installed on an HTML element to handle keydown and keypress
* events. When such an event occurs, the Keymap uses its mapping to invoke
* the appropriate handler function.
*
* When you create a Keymap, pass a JavaScript object that represents the
* initial set of bindings for the Keymap. The property names of this object
* are key identifers, and the property values are the handler functions.
*
* After a Keymap has been created, you can add new bindings by passing a key
* identifer and handler function to the bind( ) method.
You can remove a
* binding by passing a key identifier to the unbind( ) method.
*
* To make use of a Keymap, call its install( ) method, passing an HTML element,
* such as the document object. install( ) adds an onkeypress and onkeydown
* event handler to the specified object, replacing any handlers previously set
* on those properties. When these handlers are invoked, they determine the
* key identifier from the key event and invoke the handler function, if any,
* bound to that key identifier. If there is no mapping for the event, it uses
* the default handler function (see below), if one is defined. A single
* Keymap may be installed on more than one HTML element.
*
* Key Identifiers
*
* A key identifier is a case-insensitive string representation of a key plus
* any modifier keys that are held down at the same time. The key name is the
* name of the key: this is often the text that appears on the physical key of
* an English keyboard. Legal key names include "A", "7", "F2", "PageUp",
* "Left", "Delete", "/", "~". For printable keys, the key name is simply the
* character that the key generates. For nonprinting keys, the names are
* derived from the KeyEvent.DOM_VK_ constants defined by Firefox. They are
* simply the constant name, with the "DOM_VK_" portion and any underscores
* removed. For example, the KeyEvent constant DOM_VK_BACK_SPACE becomes
* BACKSPACE. See the Keymap.keyCodeToFunctionKey object in this module for a
* complete list of names.
*
* A key identifier may also include modifier key prefixes. These prefixes are
* Alt_, Ctrl_, and Shift_. They are case-insensitive, but if there is more
* than one, they must appear in alphabetical order. Some key identifiers that
* include modifiers include "Shift_A", "ALT_F2", and "alt_ctrl_delete". Note
* that "ctrl_alt_delete" is not legal because the modifiers are not in
* alphabetical order.
*
* Shifted punctuation characters are normally returned as the appropriate
* character. Shift-2 generates a key identifier of "@", for example. But if
* Alt or Ctrl is also held down, the unshifted symbol is used instead.
* We get a key identifier of Ctrl_Shift_2 instead of Ctrl_@, for example.
*
* Handler Functions
*
* When a handler function is invoked, it is passed three arguments:
* 1) the HTML element on which the key event occurred
* 2) the key identifier of the key that was pressed
* 3) the event object for the keydown event
*
* Default Handler
*
* The reserved key name "default" may be mapped to a handler function. That
* function will be invoked when no other key-specific binding exists.
*
* Limitations
*
* It is not possible to bind a handler function to all keys. The operating
* system traps some key sequences (Alt-F4, for example). And the browser
* itself may trap others (Ctrl-S, for example). This code is browser, OS,
* and locale-dependent. Function keys and modified function keys work well,
* and unmodified printable keys work well. The combination of Ctrl and Alt
* with printable characters, and particularly with punctuation characters, is
* less robust.
*/
// This is the constructor function
function Keymap(bindings) {
this.map = {}; // Define the key identifier->handler map
if (bindings) { // Copy initial bindings into it, converting to lowercase
for(name in bindings) this.map[name.toLowerCase( )] = bindings[name];
}
}
// Bind the specified key identifier to the specified handler function
Keymap.prototype.bind = function(key, func) {
this.map[key.toLowerCase( )] = func;
};
// Delete the binding for the specified key identifier
Keymap.prototype.unbind = function(key) {
delete this.map[key.toLowerCase( )];
};
// Install this Keymap on the specified HTML element
Keymap.prototype.install = function(element) {
// This is the event-handler function
var keymap = this;
function handler(event) { return keymap.dispatch(event); }
// Now install it
if (element.addEventListener) {
element.addEventListener("keydown", handler, false);
element.addEventListener("keypress", handler, false);
}
else if (element.attachEvent) {
element.attachEvent("onkeydown", handler);
element.attachEvent("onkeypress", handler);
}
else {
element.onkeydown = element.onkeypress = handler;
}
};
// This object maps keyCode values to key names for common nonprinting
// function keys. IE and Firefox use mostly compatible keycodes for these.
// Note, however that these keycodes may be device-dependent and different
// keyboard layouts may have different values.
Keymap.keyCodeToFunctionKey = {
8:"backspace", 9:"tab", 13:"return", 19:"pause", 27:"escape", 32:"space",
33:"pageup", 34:"pagedown", 35:"end", 36:"home", 37:"left", 38:"up",
39:"right", 40:"down", 44:"printscreen", 45:"insert", 46:"delete",
112:"f1", 113:"f2", 114:"f3", 115:"f4", 116:"f5", 117:"f6", 118:"f7",
119:"f8", 120:"f9", 121:"f10", 122:"f11", 123:"f12",
144:"numlock", 145:"scrolllock"
};
// This object maps keydown keycode values to key names for printable
// characters. Alphanumeric characters have their ASCII code, but
// punctuation characters do not. Note that this may be locale-dependent
// and may not work correctly on international keyboards.
Keymap.keyCodeToPrintableChar = {
48:"0", 49:"1", 50:"2", 51:"3", 52:"4", 53:"5", 54:"6", 55:"7", 56:"8",
57:"9", 59:";", 61:"=", 65:"a", 66:"b", 67:"c", 68:"d",
69:"e", 70:"f", 71:"g", 72:"h", 73:"i", 74:"j", 75:"k", 76:"l", 77:"m",
78:"n", 79:"o", 80:"p", 81:"q", 82:"r", 83:"s", 84:"t", 85:"u", 86:"v",
87:"w", 88:"x", 89:"y", 90:"z", 107:"+", 109:"-", 110:".", 188:",",
190:".", 191:"/", 192:"'", 219:"[", 220:"\\", 221:"]", 222:"\""
};
// This method dispatches key events based on the keymap bindings.
Keymap.prototype.dispatch = function(event) {
var e = event || window.event; // Handle IE event model
// We start off with no modifiers and no key name
var modifiers = ""
var keyname = null;
if (e.type == "keydown") {
var code = e.keyCode;
// Ignore keydown events for Shift, Ctrl, and Alt
if (code == 16 || code == 17 || code == 18) return;
// Get the key name from our mapping
keyname = Keymap.keyCodeToFunctionKey[code];
// If this wasn't a function key, but the ctrl or alt modifiers are
// down, we want to treat it like a function key
if (!keyname && (e.altKey || e.ctrlKey))
keyname = Keymap.keyCodeToPrintableChar[code];
// If we found a name for this key, figure out its modifiers.
// Otherwise just return and ignore this keydown event.
if (keyname) {
if (e.altKey) modifiers += "alt_";
if (e.ctrlKey) modifiers += "ctrl_";
if (e.shiftKey) modifiers += "shift_";
}
else return;
}
else if (e.type == "keypress") {
// If ctrl or alt are down, we've already handled it.
if (e.altKey || e.ctrlKey) return;
// In Firefox we get keypress events even for nonprinting keys.
// In this case, just return and pretend it didn't happen.
if (e.charCode != undefined && e.charCode == 0) return;
// Firefox gives us printing keys in e.charCode, IE in e.charCode
var code = e.charCode || e.keyCode;
// The code is an ASCII code, so just convert to a string.
keyname=String.fromCharCode(code);
// If the key name is uppercase, convert to lower and add shift
// We do it this way to handle CAPS LOCK; it sends capital letters
// without having the shift modifier set.
var lowercase = keyname.toLowerCase( );
if (keyname != lowercase) {
keyname = lowercase; // Use the lowercase form of the name
modifiers = "shift_"; // and add the shift modifier.
}
}
// Now that we've determined the modifiers and key name, we look for
// a handler function for the key and modifier combination
var func = this.map[modifiers+keyname];
// If we didn't find one, use the default handler, if it exists
if (!func) func = this.map["default"];
if (func) { // If there is a handler for this key, handle it
// Figure out what element the event occurred on
var target = e.target; // DOM standard event model
if (!target) target = e.srcElement; // IE event model
// Invoke the handler function
func(target, modifiers+keyname, e);
// Stop the event from propagating, and prevent the default action for
// the event. Note that preventDefault doesn't usually prevent
// top-level browser commands like F1 for help.
if (e.stopPropagation) e.stopPropagation( ); // DOM model
else e.cancelBubble = true; // IE model
if (e.preventDefault) e.preventDefault( ); // DOM
else e.returnValue = false; // IE
return false; // Legacy event model
}
};