【发布时间】:2012-01-07 09:29:02
【问题描述】:
function Keymap(bindings) {
this.map = {}; // Define the key identifier->handler map
if (bindings) { // Copy initial bindings into it
for(name in bindings) this.bind(name, bindings[name]);
}
}
// Bind the specified key identifier to the specified handler function
Keymap.prototype.bind = function(key, func) {
this.map[Keymap.normalize(key)] = func;
};
// Delete the binding for the specified key identifier
Keymap.prototype.unbind = function(key) {
delete this.map[Keymap.normalize(key)];
};
// 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, element); }
// Now install it
if (element.addEventListener)
element.addEventListener("keydown", handler, false);
else if (element.attachEvent)
element.attachEvent("onkeydown", handler);
};
// This method dispatches key events based on the keymap bindings.
Keymap.prototype.dispatch = function(event, element) {
// We start off with no modifiers and no key name
var modifiers = ""
var keyname = null;
// Build the modifier string in canonical lowercase alphabetical order.
if (event.altKey) modifiers += "alt_";
if (event.ctrlKey) modifiers += "ctrl_";
if (event.metaKey) modifiers += "meta_";
if (event.shiftKey) modifiers += "shift_";
// The keyname is easy if the DOM Level 3 key property is implemented:
if (event.key) keyname = event.key;
// Use the keyIdentifier on Safari and Chrome for function key names
else if (event.keyIdentifier && event.keyIdentifier.substring(0,2) !== "U+")
keyname = event.keyIdentifier;
// Otherwise, use the keyCode property and the code-to-name map below
else keyname = Keymap.keyCodeToKeyName[event.keyCode];
// If we couldn't figure out a key name, just return and ignore the event.
if (!keyname) return;
// The canonical key id is modifiers plus lowercase key name
var keyid = modifiers + keyname.toLowerCase();
// Now see if the key identifier is bound to anything
var handler = this.map[keyid];
if (handler) { // If there is a handler for this key, handle it
// Invoke the handler function
var retval = handler.call(element, event, keyid);
// If the handler returns false, cancel default and prevent bubbling
if (retval === false) {
if (event.stopPropagation) event.stopPropagation(); // DOM model
else event.cancelBubble = true; // IE model
if (event.preventDefault) event.preventDefault(); // DOM
else event.returnValue = false; // IE
}
// Return whatever the handler returned
return retval;
}
};
// Utility function to convert a key identifier to canonical form.
// On non-Macintosh hardware, we could map "meta" to "ctrl" here, so that
// Meta-C would be "Command-C" on the Mac and "Ctrl-C" everywhere else.
Keymap.normalize = function(keyid) {
keyid = keyid.toLowerCase(); // Everything lowercase
var words = keyid.split(/\s+|[\-+_]/); // Split modifiers from name
var keyname = words.pop(); // keyname is the last word
keyname = Keymap.aliases[keyname] || keyname; // Is it an alias?
words.sort(); // Sort remaining modifiers
words.push(keyname); // Add the normalized name back
return words.join("_"); // Concatenate them all
};
Keymap.aliases = { // Map common key aliases to their "official"
"escape":"esc", // key names used by DOM Level 3 and by
"delete":"del", // the key code to key name map below.
"return":"enter", // Both keys and values must be lowercase here.
"ctrl":"control",
"space":"spacebar",
"ins":"insert"
};
// The legacy keyCode property of the keydown event object is not standardized
// But the following values seem to work for most browsers and OSes.
Keymap.keyCodeToKeyName = {
// Keys with words or arrows on them
8:"Backspace", 9:"Tab", 13:"Enter", 16:"Shift", 17:"Control", 18:"Alt",
19:"Pause", 20:"CapsLock", 27:"Esc", 32:"Spacebar", 33:"PageUp",
34:"PageDown", 35:"End", 36:"Home", 37:"Left", 38:"Up", 39:"Right",
40:"Down", 45:"Insert", 46:"Del",
// Number keys on main keyboard (not keypad)
48:"0",49:"1",50:"2",51:"3",52:"4",53:"5",54:"6",55:"7",56:"8",57:"9",
// Letter keys. Note that we don't distinguish upper and lower case
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",
// Keypad numbers and punctuation keys. (Opera does not support these.)
96:"0",97:"1",98:"2",99:"3",100:"4",101:"5",102:"6",103:"7",104:"8",105:"9",
106:"Multiply", 107:"Add", 109:"Subtract", 110:"Decimal", 111:"Divide",
// Function keys
112:"F1", 113:"F2", 114:"F3", 115:"F4", 116:"F5", 117:"F6",
118:"F7", 119:"F8", 120:"F9", 121:"F10", 122:"F11", 123:"F12",
124:"F13", 125:"F14", 126:"F15", 127:"F16", 128:"F17", 129:"F18",
130:"F19", 131:"F20", 132:"F21", 133:"F22", 134:"F23", 135:"F24",
// Punctuation keys that don't require holding down Shift
// Hyphen is nonportable: FF returns same code as Subtract
59:";", 61:"=", 186:";", 187:"=", // Firefox and Opera return 59,61
188:",", 190:".", 191:"/", 192:"`", 219:"[", 220:"\\", 221:"]", 222:"'"
};
JavaScript:权威指南:6th Keymap.js
Keymap.js:将键事件绑定到处理函数。
这个模块定义了一个 Keymap 类。这个类的一个实例代表一个 键标识符(定义如下)到处理函数的映射。键盘映射 可以安装在 HTML 元素上以处理 keydown 事件。当这样一个 事件发生时,Keymap 使用其映射来调用适当的处理程序。
当你创建一个 Keymap 时,你可以传递一个 JavaScript 对象来表示 Keymap 的初始绑定集。此对象的属性名称 是关键标识符,属性值是处理函数。 创建 Keymap 后,您可以通过传递一个键来添加新的绑定 bind() 方法的标识符和处理函数。您可以删除一个 通过将键标识符传递给 unbind() 方法进行绑定。
要使用 Keymap,调用它的 install() 方法,传递一个 HTML 元素, 比如文档对象。 install() 将 onkeydown 事件处理程序添加到 指定的对象。调用此处理程序时,它确定键 被按下的键的标识符并调用处理函数(如果有), 绑定到该密钥标识符。一个 Keymap 可以安装在多个 一个 HTML 元素。
关键标识符
键标识符是键加的不区分大小写的字符串表示 同时按住的任何修饰键。键名是 通常是键上的(未移位的)文本。合法键名包括“A”、“7”、 “F2”、“PageUp”、“Left”、“Backspace”和“Esc”。
请参阅此模块中的 Keymap.keyCodeToKeyName 对象以获取名称列表。 这些是 DOM Level 3 标准定义的名称的子集,并且 该类在实现时会使用事件对象的key属性。
键标识符还可以包括修饰键前缀。这些前缀是 Alt、Ctrl、Meta 和 Shift。它们不区分大小写,必须分开 从键名和彼此之间使用空格或下划线, 连字符或 +。例如:“SHIFT+A”、“Alt_F2”、“meta-v”和“ctrl alt left”。 在 Mac 上,Meta 是 Command 键,Alt 是 Option 键。一些浏览器 将 Windows 键映射到 Meta 修饰符。
处理函数
处理程序作为文档或文档元素的方法调用 键盘映射已安装并传递两个参数: 1) keydown 事件的事件对象 2) 被按下的键的键标识符 处理程序返回值成为 keydown 处理程序的返回值。 如果处理函数返回 false,则键盘映射将停止冒泡并 取消与 keydown 事件关联的任何默认操作。
...
【问题讨论】:
标签: javascript keymapping