| 
									
										
										
										
											2013-02-26 01:52:57 +04:00
										 |  |  | /********************************************************************** | 
					
						
							|  |  |  | *  | 
					
						
							|  |  |  | * | 
					
						
							|  |  |  | * | 
					
						
							|  |  |  | **********************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //var DEBUG = DEBUG != null ? DEBUG : true
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*********************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-09 15:25:42 +04:00
										 |  |  | // Neither _SPECIAL_KEYS nor _KEY_CODES are meant for direct access, use
 | 
					
						
							|  |  |  | // toKeyName(<code>) and toKeyCode(<name>) for a more uniform access.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // NOTE: these are un-shifted ASCII key names rather than actual key 
 | 
					
						
							|  |  |  | // 		code values.
 | 
					
						
							|  |  |  | // NOTE: ASCII letters (capital) are not present because they actually 
 | 
					
						
							|  |  |  | // 		match their key codes and are accessible via:
 | 
					
						
							|  |  |  | // 			String.fromCharCode(<code>) or <letter>.charCodeAt(0)
 | 
					
						
							|  |  |  | // NOTE: the lower case letters are accessible by adding 32 to the 
 | 
					
						
							|  |  |  | // 		capital key code.
 | 
					
						
							| 
									
										
										
										
											2013-02-26 01:52:57 +04:00
										 |  |  | // NOTE: don't understand why am I the one who has to write this...
 | 
					
						
							| 
									
										
										
										
											2013-03-09 15:25:42 +04:00
										 |  |  | var _SPECIAL_KEYS = { | 
					
						
							| 
									
										
										
										
											2013-02-26 01:52:57 +04:00
										 |  |  | 	// Special Keys...
 | 
					
						
							|  |  |  | 	9:		'Tab',		33:		'PgUp',		45:		'Ins',		 | 
					
						
							|  |  |  | 	13:		'Enter',	34:		'PgDown',	46:		'Del',		 | 
					
						
							|  |  |  | 	16:		'Shift',	35:		'End',		80:		'Backspace', | 
					
						
							|  |  |  | 	17:		'Ctrl',		36:		'Home',		91:		'Win',		 | 
					
						
							| 
									
										
										
										
											2013-03-02 20:08:41 +04:00
										 |  |  | 	18:		'Alt',		37:		'Left',		93:		'Menu',		 | 
					
						
							| 
									
										
										
										
											2013-02-26 01:52:57 +04:00
										 |  |  | 	20:		'Caps Lock',38:		'Up',	  | 
					
						
							| 
									
										
										
										
											2013-03-02 20:08:41 +04:00
										 |  |  | 	27:		'Esc',		39:		'Right',   | 
					
						
							| 
									
										
										
										
											2013-02-26 01:52:57 +04:00
										 |  |  | 	32:		'Space',	40:		'Down',   | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Function Keys...
 | 
					
						
							|  |  |  | 	112:	'F1',		116:	'F5',		120:	'F9',  | 
					
						
							|  |  |  | 	113:	'F2',		117:	'F6',		121:	'F10', | 
					
						
							|  |  |  | 	114:	'F3',		118:	'F7',		122:	'F11', | 
					
						
							|  |  |  | 	115:	'F4',		119:	'F8',		123:	'F12', | 
					
						
							| 
									
										
										
										
											2013-03-09 15:25:42 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// number row..
 | 
					
						
							|  |  |  | 	49: '1',	50: '2',	51: '3',	52: '4',	53: '5', | 
					
						
							|  |  |  | 	54: '6', 	55: '7',	56: '8',	57: '9',	48: '0', | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// punctuation...
 | 
					
						
							|  |  |  | 	// top row...
 | 
					
						
							|  |  |  | 	192: '`',	189: '-',	187: '=', | 
					
						
							|  |  |  | 	// right side of keyboard...
 | 
					
						
							|  |  |  | 	219: '[',	221: ']',	220: '\\', | 
					
						
							|  |  |  | 	186: ';',	222: '\'', | 
					
						
							|  |  |  | 	188: ',',	190: '.',	191: '/', | 
					
						
							| 
									
										
										
										
											2013-02-26 01:52:57 +04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-09 15:25:42 +04:00
										 |  |  | var _KEY_CODES = {} | 
					
						
							|  |  |  | for(var k in _SPECIAL_KEYS){ | 
					
						
							|  |  |  | 	_KEY_CODES[_SPECIAL_KEYS[k]] = k | 
					
						
							| 
									
										
										
										
											2013-03-05 22:19:48 +04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-28 02:50:55 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-26 01:52:57 +04:00
										 |  |  | // XXX some keys look really wrong...
 | 
					
						
							|  |  |  | function toKeyName(code){ | 
					
						
							|  |  |  | 	// check for special keys...
 | 
					
						
							| 
									
										
										
										
											2013-03-09 15:25:42 +04:00
										 |  |  | 	var k = _SPECIAL_KEYS[code] | 
					
						
							| 
									
										
										
										
											2013-02-26 01:52:57 +04:00
										 |  |  | 	if(k != null){ | 
					
						
							|  |  |  | 		return k | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// chars...
 | 
					
						
							|  |  |  | 	k = String.fromCharCode(code) | 
					
						
							|  |  |  | 	if(k != ''){ | 
					
						
							| 
									
										
										
										
											2013-03-02 19:57:26 +04:00
										 |  |  | 		//return k.toLowerCase()
 | 
					
						
							|  |  |  | 		return k | 
					
						
							| 
									
										
										
										
											2013-02-26 01:52:57 +04:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return null | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-05 22:19:48 +04:00
										 |  |  | function toKeyCode(c){ | 
					
						
							| 
									
										
										
										
											2013-03-09 15:25:42 +04:00
										 |  |  | 	if(c in _KEY_CODES){ | 
					
						
							|  |  |  | 		return _KEY_CODES[c] | 
					
						
							| 
									
										
										
										
											2013-03-05 22:19:48 +04:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2013-03-02 19:57:26 +04:00
										 |  |  | 	return c.charCodeAt(0) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-26 01:52:57 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | // if set to false the event handlers will always return false...
 | 
					
						
							|  |  |  | var KEYBOARD_HANDLER_PROPAGATE = true | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Basic key format: | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2013-03-02 20:43:49 +04:00
										 |  |  |  * 		<key-def> : <callback>, | 
					
						
							| 
									
										
										
										
											2013-02-26 01:52:57 +04:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2013-03-02 20:43:49 +04:00
										 |  |  |  * 		<key-def> : { | 
					
						
							| 
									
										
										
										
											2013-02-26 01:52:57 +04:00
										 |  |  |  * 			'default': <callback>, | 
					
						
							|  |  |  |  *			// a modifier can be any single modifier, like shift or a 
 | 
					
						
							|  |  |  |  *			// combination of modifers like 'ctrl+shift', given in order 
 | 
					
						
							|  |  |  |  *			// of priority.
 | 
					
						
							|  |  |  |  *			// supported modifiers are (in order of priority):
 | 
					
						
							|  |  |  |  *			//	- ctrl
 | 
					
						
							|  |  |  |  *			//	- alt
 | 
					
						
							|  |  |  |  *			//	- shift
 | 
					
						
							|  |  |  |  * 			<modifer>: [...] | 
					
						
							|  |  |  |  * 		}, | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2013-03-02 20:43:49 +04:00
										 |  |  |  * 		<key-def> : [ | 
					
						
							| 
									
										
										
										
											2013-02-26 01:52:57 +04:00
										 |  |  |  *			// this can be any type of handler except for an alias...
 | 
					
						
							|  |  |  |  * 			<handler>,  | 
					
						
							|  |  |  |  * 			<doc> | 
					
						
							|  |  |  |  * 		], | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *		// alias...
 | 
					
						
							| 
									
										
										
										
											2013-03-02 20:43:49 +04:00
										 |  |  |  * 		<key-def-a> : <key-def-b>, | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * <key-def> can be: | 
					
						
							|  |  |  |  * 	- explicit key code | 
					
						
							| 
									
										
										
										
											2013-03-09 15:25:42 +04:00
										 |  |  |  * 	- key name, if present in _SPECIAL_KEYS) | 
					
						
							| 
									
										
										
										
											2013-03-02 20:43:49 +04:00
										 |  |  |  * 	- key char (uppercase), as is returned by String.fromCharCode(...)  | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2013-02-26 01:52:57 +04:00
										 |  |  |  * | 
					
						
							| 
									
										
										
										
											2013-03-04 17:48:27 +04:00
										 |  |  |  * NOTE: if a handler explicitly returns false then that will break the  | 
					
						
							|  |  |  |  * 		event propagation chain and exit the handler. | 
					
						
							|  |  |  |  * 		i.e. no other matching handlers will be called. | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2013-02-26 01:52:57 +04:00
										 |  |  |  * XXX might need to add meta information to generate sensible help... | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | function makeKeyboardHandler(keybindings, unhandled){ | 
					
						
							|  |  |  | 	if(unhandled == null){ | 
					
						
							|  |  |  | 		//unhandled = function(){return false}
 | 
					
						
							|  |  |  | 		unhandled = function(){return KEYBOARD_HANDLER_PROPAGATE} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return function(evt){ | 
					
						
							|  |  |  | 		var did_handling = false | 
					
						
							|  |  |  | 		var res = null | 
					
						
							|  |  |  | 		for(var mode in keybindings){ | 
					
						
							|  |  |  | 			if($(mode).length > 0){ | 
					
						
							|  |  |  | 				var bindings = keybindings[mode] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				var key = evt.keyCode | 
					
						
							| 
									
										
										
										
											2013-03-02 19:57:26 +04:00
										 |  |  | 				var chr = toKeyName(evt.keyCode) | 
					
						
							| 
									
										
										
										
											2013-02-26 01:52:57 +04:00
										 |  |  | 				if(bindings.ignore == '*'  | 
					
						
							|  |  |  | 						|| bindings.ignore != null && bindings.ignore.indexOf(key) != -1){ | 
					
						
							|  |  |  | 					// return true
 | 
					
						
							|  |  |  | 					res = res == null ? true : res | 
					
						
							|  |  |  | 					did_handling = true | 
					
						
							|  |  |  | 					continue | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				// XXX ugly...
 | 
					
						
							|  |  |  | 				var modifers = evt.ctrlKey ? 'ctrl' : '' | 
					
						
							|  |  |  | 				modifers += evt.altKey ? (modifers != '' ? '+alt' : 'alt') : '' | 
					
						
							|  |  |  | 				modifers += evt.shiftKey ? (modifers != '' ? '+shift' : 'shift') : '' | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-02 19:57:26 +04:00
										 |  |  | 				if(chr in bindings){ | 
					
						
							|  |  |  | 					var handler = bindings[chr] | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					var handler = bindings[key] | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2013-02-26 01:52:57 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				// alias...
 | 
					
						
							| 
									
										
										
										
											2013-03-05 22:19:48 +04:00
										 |  |  | 				while (typeof(handler) == typeof(123) || typeof(handler) == typeof('str')) { | 
					
						
							|  |  |  | 					if(handler in bindings){ | 
					
						
							|  |  |  | 						// XXX need to take care of that we can always be a number or a string...
 | 
					
						
							|  |  |  | 						handler = bindings[handler] | 
					
						
							|  |  |  | 					} else if(typeof(h) == typeof(1)) { | 
					
						
							|  |  |  | 						handler = bindings[toKeyName(handler)] | 
					
						
							|  |  |  | 					} else { | 
					
						
							|  |  |  | 						handler = bindings[toKeyCode(handler)] | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											2013-02-26 01:52:57 +04:00
										 |  |  | 				} | 
					
						
							|  |  |  | 				// no handler...
 | 
					
						
							|  |  |  | 				if(handler == null){ | 
					
						
							|  |  |  | 					continue | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				// Array, lisp style with docs...
 | 
					
						
							|  |  |  | 				// XXX for some odd reason in chrome typeof([]) == typeof({})!!!
 | 
					
						
							|  |  |  | 				if(typeof(handler) == typeof([]) && handler.constructor.name == 'Array'){ | 
					
						
							|  |  |  | 					// we do not care about docs here, so just get the handler...
 | 
					
						
							|  |  |  | 					handler = handler[0] | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				// complex handler...
 | 
					
						
							|  |  |  | 				if(typeof(handler) == typeof({})){ | 
					
						
							|  |  |  | 					var callback = handler[modifers] | 
					
						
							|  |  |  | 					if(callback == null){ | 
					
						
							|  |  |  | 						callback = handler['default'] | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					if(callback != null){ | 
					
						
							|  |  |  | 						res = callback() | 
					
						
							|  |  |  | 						did_handling = true | 
					
						
							|  |  |  | 						continue | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					// simple callback...
 | 
					
						
							| 
									
										
										
										
											2013-03-07 03:23:20 +04:00
										 |  |  | 					//res = handler(evt) 
 | 
					
						
							| 
									
										
										
										
											2013-02-26 01:52:57 +04:00
										 |  |  | 					res = handler()  | 
					
						
							| 
									
										
										
										
											2013-03-04 17:36:24 +04:00
										 |  |  | 					// if the handler explicitly returned false break out...
 | 
					
						
							|  |  |  | 					if(res === false){ | 
					
						
							|  |  |  | 						// XXX is this corrent???
 | 
					
						
							|  |  |  | 						return KEYBOARD_HANDLER_PROPAGATE ? res : null | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											2013-02-26 01:52:57 +04:00
										 |  |  | 					did_handling = true | 
					
						
							|  |  |  | 					continue | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if(!did_handling){ | 
					
						
							|  |  |  | 			// key is unhandled by any modes...
 | 
					
						
							|  |  |  | 			return unhandled(key) | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			// XXX should we handle multiple hits???
 | 
					
						
							|  |  |  | 			return KEYBOARD_HANDLER_PROPAGATE&&res?true:false | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-03-05 22:19:48 +04:00
										 |  |  | // helper...
 | 
					
						
							|  |  |  | function doc(text, func){ | 
					
						
							|  |  |  | 	func.doc = text | 
					
						
							|  |  |  | 	return func | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Build structure ready for conversion to HTML help. | 
					
						
							|  |  |  | * Structure: | 
					
						
							|  |  |  | * 	{ | 
					
						
							|  |  |  | * 		<section-title>: { | 
					
						
							|  |  |  | * 			doc: ... | 
					
						
							|  |  |  | * | 
					
						
							|  |  |  | * 			<handler-doc>: <keys-spec> | 
					
						
							|  |  |  | * 			... | 
					
						
							|  |  |  | * 		} | 
					
						
							|  |  |  | * 	} | 
					
						
							|  |  |  | * | 
					
						
							|  |  |  | * 	<keys-spec> 	- list of key names. | 
					
						
							|  |  |  | * | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | function getKeyHandler(key, keybindings){ | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function buildKeyindingsHelp(keybindings){ | 
					
						
							|  |  |  | 	var res = {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for(var selector in keybindings){ | 
					
						
							|  |  |  | 		var section = keybindings[selector] | 
					
						
							|  |  |  | 		var title = section.title == null ? selector : section.title | 
					
						
							|  |  |  | 		var res_sec = { | 
					
						
							|  |  |  | 			doc: section.doc, | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		res.title = res_sec | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		for(var k in section){ | 
					
						
							|  |  |  | 			// handler...
 | 
					
						
							|  |  |  | 			var h = section[k] | 
					
						
							|  |  |  | 			var doc | 
					
						
							|  |  |  | 			var key = typeof(k) == typeof(1) ? toKeyName(k) : k | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// an alias...
 | 
					
						
							|  |  |  | 			while(typeof(h) == typeof(1) || typeof(h) == typeof('s')){ | 
					
						
							|  |  |  | 				if(h in section){ | 
					
						
							|  |  |  | 					// XXX need to take care of that we can always be a number or a string...
 | 
					
						
							|  |  |  | 					h = section[h] | 
					
						
							|  |  |  | 				} else if(typeof(h) == typeof(1)) { | 
					
						
							|  |  |  | 					h = section[toKeyName(h)] | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					h = section[toKeyCode(h)] | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// no handler... 
 | 
					
						
							|  |  |  | 			if(h == null){ | 
					
						
							|  |  |  | 				doc = 'Nothing'				 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// a handler with doc (array)...
 | 
					
						
							|  |  |  | 			} else if(typeof(h) == typeof([]) && handler.constructor.name == 'Array'){ | 
					
						
							|  |  |  | 				doc = h[1] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// complex handler (object)...
 | 
					
						
							|  |  |  | 			} else if(typeof(h) == typeof({})){ | 
					
						
							|  |  |  | 				// XXX
 | 
					
						
							|  |  |  | 				 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// simple handler (function)...
 | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				doc = h.doc != null ? h.doc : h | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// push the actual data...
 | 
					
						
							|  |  |  | 			if(doc in res_sec){ | 
					
						
							|  |  |  | 				res_sec[doc].push(key) | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				res_sec[doc] = [key] | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return res | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-26 01:52:57 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | /********************************************************************** | 
					
						
							|  |  |  | * vim:set ts=4 sw=4 :                                                */ |