// virtual keyboard (based on JS/UIX v0.44)
// (c) mass:werk (N.Landsteiner) 2003-2007; http://www.masswerk.at
// all rights reserved

/*
	TermKeyboard - virtual keyboard gui for termlib.js
	This is not a really instanciated object, since all instances share the same data.
	So the constructor is just used to transfer a configuration object.
	
	Requires "termlib.js v.1.4".
	
	config opts:
	------------
	imgPath:          String: path to image directory with trailing slash (images for options go here)
	keycapsPath:      String: path to the keycaps-images with trailing slash
	kbdDiv:           String: id of the division to write the keyboard graphics to
	kbdBgColor:       String: bgColor for the kbdDiv (default emopty == transparent)
	outputXHTML:      Boolean: controls the syntax of unary tags
	useOpts:          Boolean: if false, no images are defined and loaded for the options
	                  Use this only, if you do not intend to show an options bar.
	optsShowEsc:      Boolean: show an ESC button in opts
	optsColorHandler: Function: Handler for a "Change Color" button
	extWinHandler:    Function: Handler to be called at showing/hiding
	                  The handler will recieve a boolean argument for show (true) and hide (false).
	
	myKbd = new TermKbd( { kbdDiv: 'myKbdDivId', optsShowEsc: true } );
	myKbd.showOpts( 'myOptsDivId' );
	// these are optional since show and hide is controlled via the options bar:
	myKbd.show();
	myKbd.hide();
*/
	

var TermKeyboard = function(opts) {
	// this is not a real instance, since all instances share the same data
	// we just use the constructor to transfer a configuration object
	if ((!opts) || (typeof opts != 'object')) opts={};
	TermKeyboard.prototype.init(opts);
}

TermKeyboard.prototype = {

	imgPath: 'kbd/',
	keycapsPath: 'kbd/keycaps/',

	kbdDiv: 'kbdDiv',
	kbdBgColor: '', //'#222222'
	outputXHTML: false,
	useOpts: true,
	optsShowEsc: false,
	optsColorHandler: null,
	extWinHandler: null,

	docNS4: null,
	kbdDocNS4: null,
	layers: null,
	kbdOn: false,
	shift: false,
	cpslk: false,
	shiftRef: new Array(),
	cpslkRef: new Array(),
	unaryTagEnd: '',
	
	initProperties: [ 'imgPath', 'keycapsPath', 'kbdDiv', 'kbdBgColor', 'outputXHTML', 'useOpts', 'optsShowEsc', 'optsColorHandler', 'extWinHandler' ],
	
	init: function(opts) {
		for (var i=0; i<this.initProperties.length; i++) {
			var p=this.initProperties[i];
			if (typeof opts[p] != 'undefined') this[p]=opts[p];
		}
		this.unaryTagEnd= (this.outputXHTML)? ' /':'';
		if (this.useOpts) {
			if (this.optsShowEsc) {
				this.optsImgs.push('esc_lo');
				this.optsImgs.push('esc_hi');
			}
			if (this.optsColorHandler) {
				this.optsImgs.push('color_lo');
				this.optsImgs.push('color_hi');
			}
			if (document.images) this.imgPreload(this.imgPath,this.optsImgs);
		}
	},


	// buttons

	optsImgs: [
		'left_lo', 'left_hi', 'right_lo', 'right_hi', 'delete_lo', 'delete_hi',
		'kbd_show_lo', 'kbd_show_hi', 'kbd_hide_lo', 'kbd_hide_hi'
	],
	imgRef: new Array(),

	imgPreload: function(path,imgnames) {
		for (var i=0; i<imgnames.length; i++) {
			var n=imgnames[i];
			this.imgRef[n]=new Image();
			this.imgRef[n].src=path+n+'.gif';
		}
	},

	setImg: function(n,v) {
		if (document.images) {
			var img=(this.layers)? this.docNS4.images['kbd__'+n] : document.images['kbd__'+n];
			var stat=(v)? '_hi' : '_lo';
			img.src=this.imgRef[n+stat].src;
		}
	},

	// key maps (200=left shift, 202=right shift, 204=CpsLock)

	keyMap: [
		[96,49,50,51,52,53,54,55,56,57,48,45,61,8],
		[27,113,119,101,114,116,121,117,105,111,112,91,93,13],
		[204,97,115,100,102,103,104,106,107,108,59,39,35],
		[200,92,122,120,99,118,98,110,109,44,46,47,30,202],
		[32,28,31,29]
	],
	keyMapShift:[
		[126,33,34,35,36,37,94,38,42,40,41,95,43,8],
		[27,81,87,69,82,84,89,85,73,79,80,123,125,13],
		[204,65,83,68,70,71,72,74,75,76,58,34,64],
		[200,124,90,88,67,86,66,78,77,60,62,63,30,202],
		[32,28,31,29]
	],
	keyMapCpslk: [
		[96,49,50,51,52,53,54,55,56,57,48,45,61,8],
		[27,81,87,69,82,84,89,85,73,79,80,91,93,13],
		[204,65,83,68,70,71,72,74,75,76,59,39,35],
		[200,92,90,88,67,86,66,78,77,44,46,47,30,202],
		[32,28,31,29]
	],
	keyWidth: [
		[35,35,35,35,35,35,35,35,35,35,35,35,35,69],
		[55,35,35,35,35,35,35,35,35,35,35,35,35,0],
		[65,35,35,35,35,35,35,35,35,35,35,35,35],
		[49,35,35,35,35,35,35,35,35,35,35,35,35,54],
		[252,35,35,35]
	],

	keyImages: [200,201,202,203,204,205],

	keyCaps: function(k) {
		if (k==204) {
			this.cpslk=(!this.cpslk);
			var cnr=(this.cpslk)? 205:204;
			this.setKbdImg(204,cnr);
		}
		else if ((k==200) || (k==202)) {
			this.shift=(!this.shift);
			var m=(this.shift)? 1:0;
			this.setKbdImg(200,200+m);
			this.setKbdImg(202,202+m);
		}
		else {
			var ch=0;
			if (this.shift) {
				this.shift=false;
				this.setKbdImg(200,200);
				this.setKbdImg(202,202);
				TermGlobals.keyHandler({which:this.shiftRef[k], _remapped:true, _repeat:true});
			}
			else if (this.cpslk) {
				TermGlobals.keyHandler({which:this.cpslkRef[k], _remapped:true, _repeat:true});
			}
			else {
				TermGlobals.keyHandler({which:k, _remapped:true, _repeat:true});
			}
		}
	},

	setKbdImg: function(n,v) {
		if (document.images) {
			var img=(this.layers)? this.kbdDocNS4.images['key'+n] : document.images['key'+n];
			img.src=this.imgRef[v].src;
		}
	},


	setKbdButton: function(v) {
		if (document.images) {
			var img=(this.layers)? this.docNS4.images.kbd__show : document.images.kbd__show;
			var n=(this.kbdOn)? 'kbd_hide' : 'kbd_show';
			var stat=(v)? '_hi' : '_lo';
			img.src=this.imgRef[n+stat].src;
		}
	},

	show: function() {
		if (this.kbdOn) {
			if (this.extWinHandler) {
				this.extWinHandler(false);
			}
			else {
				TermGlobals.setVisible(this.kbdDiv,0);
				TermGlobals.setDisplay(this.kbdDiv,'none');
			}
			this.kbdOn=false;
			this.setKbdButton(0);
		}
		else {
			this.imgPreload(this.keycapsPath,this.keyImages);
			this.shift=false;
			this.cpslk=false;
			var s='<table border="0" cellspacing="0" cellpadding="0">\n';
			s+='<tr><td width="7"><img src="'+this.keycapsPath+'spacer.gif" width="7" height="2" alt=""'+this.unaryTagEnd+'><\/td>\n';
			s+='<td>'+this.makeKbd()+'</td>\n';
			s+'<td width="7"><img src="'+this.keycapsPath+'spacer.gif" width="7" height="2" alt=""'+this.unaryTagEnd+'><\/td><\tr>\n';
			s+='<tr><td height="10" colspan="3"><img src="'+this.keycapsPath+'spacer.gif" width="2" height="10" alt=""'+this.unaryTagEnd+'><\/td><\/tr>\n';
			s+='<\/table>';
			TermGlobals.writeElement(this.kbdDiv,s);
			if (this.layers) this.kbdDocNS4=document.layers[this.kbdDiv].document;
			this.kbdOn=true;
			if (this.extWinHandler) {
				this.extWinHandler(true);
			}
			else {
				TermGlobals.setVisible(this.kbdDiv,1);
				TermGlobals.setDisplay(this.kbdDiv,'block');
			}
			this.setKbdButton(0);
		}
	},

	makeKbd: function() {
		var s='<table border="0" cellspacing="0" cellpadding="0">\n';
		var tagend=this.unaryTagEnd;
		var path=this.keycapsPath;
		for (var i=0; i<this.keyMap.length; i++) {
			s+='<tr><td nowrap'+((this.outputXHTML)? '="nowrap"':'')+' height="39" valign="top"'+((this.kbdBgColor)? ' bgcolor="'+this.kbdBgColor+'"':'')+'>';
			for (var k=0; k<this.keyMap[i].length; k++) {
				var kc=this.keyMap[i][k];
				this.shiftRef[kc]=this.keyMapShift[i][k];
				this.cpslkRef[kc]=this.keyMapCpslk[i][k];
				if (kc==13) {
					s+='<a href="javas'+'cript://" onmousedown="TermKeyboard.prototype.keyCaps(13); return true;" onfocus="if(this.blur)this.blur()" onmouseup="TermKeyboard.prototype.keyUp(); return true;"><img src="'+path+'13_1.gif" hspace="0" vspace="0" align="top" border="0" width="47" height="39" alt=""'+tagend+'><\/a>';
					continue;
				};
				if (kc==32) s+='<img src="'+path+'spacer.gif" width="139" height="35" hspace="1" vspace="1" align="top" alt=""'+tagend+'>'
				else if (kc==28) {
					s+='<img src="'+path+'spacer.gif" width="23" height="35" hspace="1" vspace="1" align="top" alt=""'+tagend+'>';
					s+='<a href="javasc'+'ript://" onmousedown="TermKeyboard.prototype.cursorLeft(); return true;" onfocus="if(this.blur)this.blur()" onmouseup="TermKeyboard.prototype.keyUp(); return true;"><img src="'+path+kc+'.gif" name="key'+kc+'" hspace="1" vspace="1" align="top" border="0" width="'+this.keyWidth[i][k]+'" height="35" alt=""'+tagend+'><\/a>';
					continue;
				}
				else if (kc==29) {
					s+='<a href="javasc'+'ript://" onmousedown="TermKeyboard.prototype.cursorRight(); return true;" onfocus="if(this.blur)this.blur()" onmouseup="TermKeyboard.prototype.keyUp(); return true;"><img src="'+path+kc+'.gif" name="key'+kc+'" hspace="1" vspace="1" align="top" border="0" width="'+this.keyWidth[i][k]+'" height="35" alt=""'+tagend+'><\/a>';
					continue;
				}
				else if (kc==8) {
					s+='<a href="javasc'+'ript://" onmousedown="TermKeyboard.prototype.backspace(); return true;" onfocus="if(this.blur)this.blur()" onmouseup="TermKeyboard.prototype.keyUp(); return true;"><img src="'+path+kc+'.gif" name="key'+kc+'" hspace="1" vspace="1" align="top" border="0" width="'+this.keyWidth[i][k]+'" height="35" alt=""'+tagend+'><\/a>';
					continue;
				}
				s+='<a href="javas'+'cript://" onmousedown="TermKeyboard.prototype.keyCaps('+kc+'); return true;" onfocus="if(this.blur)this.blur()" onmouseup="TermKeyboard.prototype.keyUp(); return true;"><img src="'+path+kc+'.gif" name="key'+kc+'" hspace="1" vspace="1" align="top" border="0" width="'+this.keyWidth[i][k]+'" height="35" alt=""'+tagend+'><\/a>';
				if (kc==35) s+='<a href="javas'+'cript://" onmousedown="TermKeyboard.prototype.keyCaps(13); return true;" onfocus="if(this.blur)this.blur()" onmouseup="TermKeyboard.prototype.keyUp(); return true;"><img src="'+path+'13_2.gif" hspace="0" vspace="0" align="top" border="0" width="37" height="36" alt=""'+tagend+'><\/a>';
			};
			s+='<\/td><\/tr>\n';
		};
		s+='<\/table>';
		return s;
	},

	hide: function() {
		if (this.kbdOn) this.show();
		if (this.extWinHandler) {
			this.extWinHandler(false);
		}
		else {
			TermGlobals.setVisible(this.kbdDiv,0);
			TermGlobals.setDisplay(this.kbdDiv,'none');
		}
	},
	
	colorHandler: function() {
		if (this.optsColorHandler) this.optsColorHandler();
	},

	showOpts: function(divId) {
		var tagend=this.unaryTagEnd;
		var path=this.imgPath;
		s='<table border="0" cellspacing="0" cellpadding="0" width="100%"><tr valign="middle">\n<td>';
		s+='<a href="javasc'+'ript:TermKeyboard.prototype.show()" onmouseover="TermKeyboard.prototype.setKbdButton(1); window.status=\'show/hide full graphic keyboard\'; return true" onmouseout="TermKeyboard.prototype.setKbdButton(0); window.status=\'\'; return true" onfocus="if(this.blur)this.blur()" title="show/hide virtual keyboard"><img src="'+path+'kbd_show_lo.gif" name="kbd__show" width="77" height="19" border="0" hspace="3" alt="show/hide virtual keyboard"'+tagend+'><\/a>';
		if (this.optsColorHandler) {
			s+='<a href="javasc'+'ript:TermKeyboard.prototype.colorHandler()" onmouseover="TermKeyboard.prototype.setImg(\'color\',1); window.status=\'change the color theme\'; return true" onmouseout="TermKeyboard.prototype.setImg(\'color\',0); window.status=\'\'; return true" onfocus="if(this.blur)this.blur()" title="change color theme"><img src="'+path+'color_lo.gif" name="kbd__color" width="57" height="19" border="0" hspace="4" alt=""'+tagend+'><\/a>';
		}
		s+='<\/td>\n<td align="right"><table border="0" cellspacing="0" cellpadding="1" style="padding-right: 2px !important;"><tr>\n';
		s+='<td><a href="javasc'+'ript://" onmousedown="TermKeyboard.prototype.cursorLeft(); return true;" onmouseover="TermKeyboard.prototype.setImg(\'left\',1); window.status=\'left\'; return true" onmouseout="TermKeyboard.prototype.setImg(\'left\',0); window.status=\'\'; return true" onfocus="if(this.blur)this.blur()" title="cursor left" onmouseup="TermKeyboard.prototype.keyUp(); return true;"><img src="'+path+'left_lo.gif" name="kbd__left" width="23" height="23" alt="cursor left" border="0"'+tagend+'><\/a><\/td>\n';
		s+='<td><a href="javasc'+'ript://" onmousedown="TermKeyboard.prototype.cursorRight(); return true;" onmouseover="TermKeyboard.prototype.setImg(\'right\',1); window.status=\'right\'; return true" onmouseout="TermKeyboard.prototype.setImg(\'right\',0); window.status=\'\'; return true" onfocus="if(this.blur)this.blur()" title="cursor right" onmouseup="TermKeyboard.prototype.keyUp(); return true;"><img src="'+path+'right_lo.gif" name="kbd__right" width="23" height="23" alt="cursor right" border="0"'+tagend+'><\/a><\/td>\n';
		s+='<td><a href="javasc'+'ript://" onmousedown="TermKeyboard.prototype.backspace(); return true;" onmouseover="TermKeyboard.prototype.setImg(\'delete\',1); window.status=\'backspace\'; return true" onmouseout="TermKeyboard.prototype.setImg(\'delete\',0); window.status=\'\'; return true" onfocus="if(this.blur)this.blur()" title="backspace" onmouseup="TermKeyboard.prototype.keyUp(); return true;"><img src="'+path+'delete_lo.gif" name="kbd__delete" width="23" height="23" alt="backspace" border="0"'+tagend+'><\/a><\/td>\n';
		if (this.optsShowEsc) {
			s+='<td><a href="javasc'+'ript://" onmousedown="TermKeyboard.prototype.esc(); return true;" onmouseover="TermKeyboard.prototype.setImg(\'esc\',1); window.status=\'esc\'; return true" onmouseout="TermKeyboard.prototype.setImg(\'esc\',0); window.status=\'\'; return true" onfocus="if(this.blur)this.blur()" title="esc" onmouseup="TermKeyboard.prototype.keyUp(); return true;"><img src="'+path+'esc_lo.gif" name="kbd__esc" width="23" height="23" alt="esc" border="0"'+tagend+'><\/a><\/td>\n';
		}
		s+='<\/tr><\/table><\/td><\/tr><\/table>';
		TermGlobals.writeElement(divId,s);
	},

	cursorLeft: function() {
		TermGlobals.keyHandler({which:28, _repeat: true});
	},

	cursorRight: function() {
		TermGlobals.keyHandler({which:29, _repeat: true});
	},
	
	backspace: function() {
		TermGlobals.keyHandler({which:8, _repeat: true});
	},
	
	esc: function() {
		TermGlobals.keyHandler({which:27, _repeat: true});
	},
	
	keyUp: function() {
		TermGlobals.clearRepeatTimer();
	}

}

//eof