NJKeysOpts =
{
	DEBUG:true,
	MOD_SHIFT:1,
	MOD_ALT:2,
	MOD_CONTROL:4,
	KEYCODES:
	{
		'SPACE':32,
		'ENTER':13,
		'TAB':9,
		'BACKSPACE':8,
		'SHIFT':16,
		'CONTROL':17,
		'ALT':18,
		'LEFT':37,
		'UP':38,
		'RIGHT':39,
		'DOWN':40,
		'SCROLL_LOCK':145,
		'NUM_LOCK':144,
		'CAPS_LOCK':20,
		'PAUSE':19,
		'BREAK':19,
		'INSERT':45,
		'HOME':36,
		'DELETE':46,
		'END':35,
		'PAGE_UP':33,
		'PAGE_DOWN':34,
		'F1':112,
		'F2':113,
		'F3':114,
		'F4':115,
		'F5':116,
		'F6':117,
		'F7':118,
		'F8':119,
		'F9':120,
		'F10':121,
		'F11':122,
		'F12':123,
		'CONTEXT':93,
		'0':48,
		'1':49,
		'2':50,
		'3':51,
		'4':52,
		'5':53,
		'6':54,
		'7':55,
		'8':56,
		'9':57
	}
};


if(window.event)
{
	// IE-specific mappings
	NJKeysOpts.KEYCODES['SEMICOLON']=186;
	NJKeysOpts.KEYCODES[';']=186;
	NJKeysOpts.KEYCODES['EQUALS']=187;
	NJKeysOpts.KEYCODES['=']=187;
	NJKeysOpts.KEYCODES['COMMA']=188;
	NJKeysOpts.KEYCODES[',']=188;
	NJKeysOpts.KEYCODES['MINUS']=189;
	NJKeysOpts.KEYCODES['-']=189;
	NJKeysOpts.KEYCODES['PERIOD']=190;
	NJKeysOpts.KEYCODES['.']=190;
	NJKeysOpts.KEYCODES['FORWARD_SLASH']=191;
	NJKeysOpts.KEYCODES['/']=191;
	NJKeysOpts.KEYCODES['BACK_APOSTROPHE']=192;
	NJKeysOpts.KEYCODES['`']=192;
	NJKeysOpts.KEYCODES['BACK_SLASH']=220;
	NJKeysOpts.KEYCODES['\\']=220;
	NJKeysOpts.KEYCODES['APOSTROPHE']=222;
	NJKeysOpts.KEYCODES['\'']=220;
	NJKeysOpts.KEYCODES['KP_DIVIDE']=111;
	NJKeysOpts.KEYCODES['KP_/']=111;
	NJKeysOpts.KEYCODES['KP_MULTIPLY']=106;
	NJKeysOpts.KEYCODES['KP_*']=106;
	NJKeysOpts.KEYCODES['KP_ADD']=107;
	NJKeysOpts.KEYCODES['KP_+']=107;
	NJKeysOpts.KEYCODES['KP_SUBTRACT']=109;
	NJKeysOpts.KEYCODES['KP_-']=109;
	NJKeysOpts.KEYCODES['KP_PERIOD']=46;
	NJKeysOpts.KEYCODES['KP_.']=46;
}
else
{
	// Mozilla mappings - some will fail in Opera/Safari
	NJKeysOpts.KEYCODES['SEMICOLON']=59;
	NJKeysOpts.KEYCODES[';']=59;
	NJKeysOpts.KEYCODES['EQUALS']=61;
	NJKeysOpts.KEYCODES['=']=61;
	NJKeysOpts.KEYCODES['COMMA']=188;
	NJKeysOpts.KEYCODES[',']=188;
	NJKeysOpts.KEYCODES['MINUS']=189;
	NJKeysOpts.KEYCODES['-']=189;
	NJKeysOpts.KEYCODES['PERIOD']=190;
	NJKeysOpts.KEYCODES['.']=190;
	NJKeysOpts.KEYCODES['FORWARD_SLASH']=191;
	NJKeysOpts.KEYCODES['/']=191;
	NJKeysOpts.KEYCODES['BACK_APOSTROPHE']=192;
	NJKeysOpts.KEYCODES['`']=192;
	NJKeysOpts.KEYCODES['BACK_SLASH']=220;
	NJKeysOpts.KEYCODES['\\']=220;
	NJKeysOpts.KEYCODES['APOSTROPHE']=222;
	NJKeysOpts.KEYCODES['\'']=220;
	NJKeysOpts.KEYCODES['KP_DIVIDE']=111;
	NJKeysOpts.KEYCODES['KP_/']=111;
	NJKeysOpts.KEYCODES['KP_MULTIPLY']=106;
	NJKeysOpts.KEYCODES['KP_*']=106;
	NJKeysOpts.KEYCODES['KP_ADD']=107;
	NJKeysOpts.KEYCODES['KP_+']=107;
	NJKeysOpts.KEYCODES['KP_SUBTRACT']=109;
	NJKeysOpts.KEYCODES['KP_-']=109;
	NJKeysOpts.KEYCODES['KP_PERIOD']=110;
	NJKeysOpts.KEYCODES['KP_.']=110;
}






NJKeys = function()
{
	this.keyHandlers = new Array();
	
	var NJKthis = this;

	this.addKeyHandler = function(keyHandler)
	{
		if(keyHandler.keynum!=undefined)
		{
			NJKthis.keyHandlers[NJKthis.keyHandlers.length] = keyHandler;
		}
	}


	this.findKeyHandler = function(keynum,shift,alt,control)
	{
		for(var n=0;n<NJKthis.keyHandlers.length;n++)
		{
			var kh = NJKthis.keyHandlers[n];
			if(kh.keynum==keynum && kh.shift==shift && kh.alt==alt && kh.control==control) return kh;
		}
	}


	if(NJKeysOpts.DEBUG)
	{
		NJKthis.addKeyHandler(new NJKeyHandler('/',NJKeysOpts.MOD_CONTROL+NJKeysOpts.MOD_SHIFT,function() {NJKthis.listKeyHandlers();}));
	}


	
	
	this.kp = function()
	{
//		var NJKthis = this;
		
		return function(e)
		{
			//alert('meow');
			
			var keynum
			var keychar
			var target
			var docNodeName
			var alt = false;
			var shift = false;
			var control = false;
	
			if(window.event) // IE
			{
				keynum = window.event.keyCode;
				target = window.event.srcElement;
				docNodeName = 'BODY';
				alt = window.event.altKey; //modifiers & Event.ALT_MASK;
				shift = window.event.shiftKey; //modifiers & Event.SHIFT_MASK;
				control = window.event.ctrlKey; //modifiers & Event.CONTROL_MASK;
			}
			else if(e.which) // Netscape/Firefox/Opera
			{
				keynum = e.which;
				target = e.target;
				if (target.nodeType == 3)
				{
					// defeat Safari bug
					target = target.parentNode;
				}
				docNodeName = 'HTML';
				alt = e.altKey;
				shift = e.shiftKey;
				control = e.ctrlKey;
			}
			else
			{
				return true;
			}
			
			keychar = String.fromCharCode(keynum).toLowerCase();
			
			//alert(keynum+'; '+shift+'; '+alt+'; '+control);
			//alert(NJKthis.keyHandlers.length);
			
			kh = NJKthis.findKeyHandler(keynum,shift,alt,control);
			
			//if(keynum<16||keynum>18) alert(target.nodeName+'; '+keynum+'; \''+keychar+'\'; '+'('+alt+','+shift+','+control+'); '+kh);
			
			if(kh!=undefined&&kh.func!=undefined&&(kh.global||NJKthis.isValidTarget(target))&&kh.shift==shift&&kh.alt==alt&&kh.control==control)
			{
				kh.func();
				NJKthis.swallowEvent(e);
				return false;
			}
			
			return true;
		}
		
	}
	
	

	
	this.isValidTarget = function(target)
	{
		// target is valid if it is not an INPUT or TEXTAREA 
		if(target.nodeName=='TEXTAREA') return false;
		if(target.nodeName=='INPUT' && (target.type=='text'||target.type=='password')) return false;
		return true;
	}
	

	
	this.swallowEvent = function(e)
	{
		if (!e) var e = window.event;
		e.cancelBubble = true;
		if (e.stopPropagation)
		{
			e.stopPropagation();
			e.preventDefault();
		}
	}
	
	
	
	this.listKeyHandlers = function()
	{
		var s = '';
		
		for(k in NJKthis.keyHandlers)
		{
			kh = NJKthis.keyHandlers[k]
			if(kh.func!=NJKthis.listKeyHandlers)
			{
				s+=kh.keynum+'(';
				name=String.fromCharCode(kh.keynum);
				for(n in NJKeysOpts.KEYCODES)
				{
					if(NJKeysOpts.KEYCODES[n]==kh.keynum)
					{
						name=n;
						break;
					}
				}
				s+=name;
				s+=')';
				if(kh.shift) s+='+shift';
				if(kh.alt) s+='+alt';
				if(kh.control) s+='+control';
				s+=' -> '+kh.func+'\n';
			}
		}
		alert(s);
	}

//	this.getref = function()
//	{
//		var ref = this;
//		return function() {/*alert('plop: '+ref.kp);*/ ref.kp();}
//	}
	
	document.onkeydown = this.kp(); //this.getref; //NJKeys.kp;
//	NJ.addEventHandler(document,'keydown',this.kp()); //this.getref());
	

	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
}




/*
*
* NJKeyHandler(keyNameOrNum, func, modifiers, docOnly) - creates a new KeyHandler object
*
* keyNameOrNum - 'A-Z' | 'a-z' | '0-9' | KEYCODES key
* func - callback function to call when handling a matching event
* modifiers - bitwise sum of MOD_* constants
* global - true if handler should intercept key events on all page elements;
*			false (default) if handler should only respond to events on the document object or non-input elements
*
*/
NJKeyHandler = function (keyNameOrNum, modifiers, func, global)
{
	if(keyNameOrNum.length==1)
	{
		if( (keyNameOrNum>='A'&&keyNameOrNum<='Z') || (keyNameOrNum>='0'&&keyNameOrNum<='9') )
		{
			var kn = keyNameOrNum.charCodeAt(0);
		}
		else if(keyNameOrNum>='a'&&keyNameOrNum<='z')
		{
			var kn = keyNameOrNum.charCodeAt(0)-32;
		}
	}
	if(!kn)
	{
		var kn = NJKeysOpts.KEYCODES[keyNameOrNum];
	}
	this.keynum = kn!=undefined?kn:keyNameOrNum;
	this.func = func;
	if(modifiers)
	{
		this.shift = (modifiers & NJKeysOpts.MOD_SHIFT) > 0;
		this.alt = (modifiers & NJKeysOpts.MOD_ALT) > 0;
		this.control = (modifiers & NJKeysOpts.MOD_CONTROL) > 0;
	}
	else
	{
		this.shift = this.alt = this.control = false;
	}
	this.global = global!=undefined?global:false;
}




