function InitKB(textInputId, areaId, defKBStatusControlValue, oName){
	oName = oName || 'qwerty';
	var tc = typeof textInputId == 'string' ?
            document.getElementById(textInputId) : textInputId;
	this.shiftKey = false;
	this.capsLock = false;
	this.holdShiftKey = false;

	var KBData=[
"~!@#$%^&*()_+QWERTYUIOP{}|ASDFGHJKL:\"ZXCVBNM<>?`1234567890-=qwertyuiop[]|asdfghjkl;'zxcvbnm,./",
"Ё!\"№;%:?*()_+ЙЦУКЕНГШЩЗХЪ/ФЫВАПРОЛДЖЭЯЧСМИТЬБЮ,ё1234567890-=йцукенгшщзхъ\\фывапролджэячсмитьбю.",
"~!@#$%^&*()_+АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ?`1234567890-=абвгдеёжзийклмнопрстуфхцчшщъыьэюя/",
"Ґ!»№;%:?*()_+ЙЦУКЕНГШЩЗХЇ/ФІВАПРОЛДЖЄЯЧСМИТЬБЮ,ґ1234567890-=йцукенгшщзхї\\фівапролджєячсмитьбю."];

    var KBStatusControlValue = defKBStatusControlValue ? defKBStatusControlValue : 0;

	function saveCaret(elem){
        if (elem.isTextEdit){
            elem.caretPos = document.selection.createRange();
        }
	}

	function getCaretPosAlph(tc, CurrentKey){
		tc.focus();

		if (typeof tc.setSelectionRange != 'undefined'){
			var oldSelectionStart = tc.selectionStart;
			var oldSelectionEnd = tc.selectionEnd;
			tc.value = tc.value.substring(0, oldSelectionStart) + CurrentKey + tc.value.substring(oldSelectionEnd);
			tc.setSelectionRange(oldSelectionStart + CurrentKey.length, oldSelectionStart + CurrentKey.length);
		}else{
			if(typeof(tc.createTextRange) != "undefined" && tc.caretPos){
				var caretPos = tc.caretPos;
				caretPos.text = caretPos.text.charAt(caretPos.text.length - 1) == ' ' ? CurrentKey + ' ' : CurrentKey;
				caretPos.select();
			}else{
				tc.value += CurrentKey;
			}
		}

		tc.focus();
	}

	this.dell = function(){
		tc.focus();

		if (typeof tc.setSelectionRange != 'undefined'){
			var oldSelectionStart = tc.selectionStart;
			var oldSelectionEnd = tc.selectionEnd;
			tc.value = tc.value.substring(0, oldSelectionStart - 1) + tc.value.substring(oldSelectionEnd);
			tc.setSelectionRange(oldSelectionStart - 1, oldSelectionStart - 1);
		}else{
			if(typeof(tc.createTextRange) != "undefined" && tc.caretPos){
				var caretPos = tc.caretPos;
				if (!caretPos.text) {
					caretPos.moveStart("character", -1);
				}
				caretPos.text = '';
					
				caretPos.select();
			}else{
				tc.value = tc.value.substring(0, tc.value.length);
			}
		}

		tc.focus();
	};

	function PB(v, text, onclick, id, x, y, w){
		return '<div style="left:' + (x * 40) + 'px;top:' + (y * 39)+ 'px;width:' + (w * 35) + 'px;" ' + ( id ? 'id="' + id + '"' : '') +
				(v ? ' onclick="window.' + oName + '.PutNEv(' + window.n + ', event);">' +
						'<font id="e' + window.n + '"  class="b">&nbsp;</font>&nbsp;' +
						'<font id="k' + (window.n++) + '" class="r">&nbsp;</font>' :
							(text ? (onclick ? ' onclick="window.' + oName + '.' + onclick + '"' : '') + '>' + text : '>'))
				+ '</div>';
	}

	function show(){
		var i = 0;
		window.n = 0;
		var html = '<div class="kb">';
							
	
		for(i = 0; i < 13; i++){
			html += PB(1, null, null, null, i ? i - 0.5 : 0, 0, i ? 1 : 0.4);
		}
	
		html += PB(0, ' ', 'dell();', null, 12.5, 0, 1.5);
		html += PB(0, '<table><tr><td>Tab</td></tr></table>', "PutNEv('	', event);", null, 0, 1, 1);
		for( i = 0; i < 13; i++){
			html += PB(1, null, null, null, i + 1, 1, 1);
		}
		html += PB(0, '<table><tr><td>Caps L</td></tr></table>', 'invertCapsLock();', 'keyCapsLock', 0, 2, 1.5);

		for( i = 0; i < 11; i++){
			html += PB(1, null, null, null, 1.5 + i, 2, 1);			
		}
	
		var isSText = 'event.shiftKey || window.' + oName + '.capsLock || (window.' + oName + '.holdShiftKey && window.' + oName + '.shiftKey)';
		html += PB(0, '<table><tr><td>Enter</td></tr></table>', "PutNEv('\\n', event);", null, 12.5, 2, 1.5);
		html += PB(0, '<table><tr><td>Shift</td></tr></table>', 'invertShiftKey()', 'keyShift', 12, 3, 2);
		html += PB(0, '<table><tr><td>Вкл.</td></tr></table>', 'kbOnOf()', 'kbOnOf', 0, 3, 2.1);
		html += PB(0, '<table><tr><td>"алфавит"</td></tr></table>', 'changeSort()', 'changeSort', 0, 4, 2.7);
		html += PB(0, '<font class="b">&lt;</font><font class="r" style="color:#000">&gt;</font>', "PutNEv(" + isSText + " ? '<' : '>', event);", null, 2.5, 4, 1);
		html += PB(0, '<font class="b">\'</font><font class="r" style="color:#000">"</font>', "PutNEv(" + isSText + " ? '\\\'' : '&qout;', event);", null, 3.5, 4, 1);
		html += PB(0, '<font class="b">[</font><font class="r" style="color:#000">]</font>', "PutNEv(" + isSText + " ? '[' : ']', event);", null, 4.5, 4, 1);
		html += PB(0, '<font class="b">/</font><font class="r" style="color:#000">?</font>', "PutNEv(" + isSText + " ? '/' : '?', event);", null, 9.5, 4, 1);
		html += PB(0, '<font class="b">\\</font><font class="r" style="color:#000">|</font>', "PutNEv(" + isSText + " ? '\\\\\' : '|', event);", null, 10.5, 4, 1);
		html += PB(0, '<table><tr><td>Выделить все</td></tr></table>', 'select()', null, 11.5, 4, 2.6);
		
	
		for( i = 0; i < 10; i++){
			html += PB(1, null, null, null, i + 2, 3, 1);
		}
	
		html += PB(0, ' ', "PutNEv(' ', event);", null, 5.5, 4, 4.4);
		html += "</div>";
		
		document.getElementById(areaId).innerHTML = html;
	}

	show();
	
	function setShiftKey(newShiftKey){
		if(this.shiftKey != newShiftKey){
			this.shiftKey = newShiftKey;
			window[oName].CTyle();
		}		
	}

	this.invertShiftKey = function(){
		this.shiftKey = !this.shiftKey;
		this.holdShiftKey = true;
		this.CTyle();
	}

	this.invertCapsLock = function(){
		this.capsLock = !this.capsLock;
		this.CTyle();
	}
	
	this.PutN = function(n){
		getCaretPosAlph(tc, n);
	}

	this.PutNEv = function(N, ev){
		if(typeof(N) != 'number'){			
			this.PutN(N == '&qout;' ? '"' : N);
			if(N == '\n' && tc.tagName == 'INPUT' && tc.form){
				tc.form.submit();
			}
		}else if (ev.shiftKey || (this.holdShiftKey && this.shiftKey) || this.capsLock){
			this.PutN(KBData[KBStatusControlValue].charAt(N));
		}else{
			this.PutN(KBData[KBStatusControlValue].charAt(N + 47));
		}

		this.holdShiftKey = false;

		setShiftKey(ev.shiftKey);
	}

	function changeKey(tc, evt){
		setShiftKey(evt.shiftKey);

		if(KBStatusControlValue < 1){
			return true;
		}
		
		if(evt.ctrlKey){
			return true;
		}
		
		var keyCode = evt.keyCode ? evt.keyCode : evt.charCode ? evt.charCode : evt.which ? evt.which : void 0;
		
		if (evt.which == 0){
			return true;
		}
		
		var CurrentKey = String.fromCharCode(keyCode);
		
		if(KBData[0].indexOf(CurrentKey) == -1){
			return true;
		}
		
		saveCaret(tc);
		getCaretPosAlph(tc, KBData[KBStatusControlValue].charAt(KBData[0].indexOf(CurrentKey)));

		return false;
	}

	function escapeHTML(text) {
	    return text.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;');
	}

	this.CTyle = function(){
		document.getElementById('keyShift').getElementsByTagName('td')[0].style.color = (this.holdShiftKey && this.shiftKey) ? '#f00' : '#000';
		document.getElementById('keyCapsLock').getElementsByTagName('td')[0].style.color = this.capsLock ? '#f00' : '#000';
		document.getElementById('kbOnOf').innerHTML = KBStatusControlValue == 0 ? '<table><tr><td style="color:#000">Включить</td></tr></table>' : '<table><tr><td style="color:#f00">Выключить</td></tr></table>';
		var changeSortHTML = '<table><tr><td>';
		changeSortHTML += KBStatusControlValue == 1 ? '<font color="#ff0000">ру</font>' : 'ру';
		changeSortHTML += '/';
		changeSortHTML += KBStatusControlValue == 2 ? '<font color="#ff0000">абв</font>' : 'абв';
		changeSortHTML += '/';
		changeSortHTML += KBStatusControlValue == 3 ? '<font color="#ff0000">ук</font>' : 'ук';
		changeSortHTML += '</td></tr></table>';
		document.getElementById('changeSort').innerHTML = changeSortHTML;

		var charCodeAdd = (this.holdShiftKey && this.shiftKey) || this.capsLock ? 0 : 47;

		for( var i = 0; i < 47; i ++ ){
			document.getElementById("k" + i).innerHTML = escapeHTML(KBData[KBStatusControlValue].charAt(i + charCodeAdd));
			document.getElementById("e" + i).innerHTML = escapeHTML(KBData[0].charAt(i + charCodeAdd));
		}		
	}

	this.kbOnOf = function(){
		KBStatusControlValue = 	KBStatusControlValue > 0 ? 0 : 1;
		this.CTyle();
	}

	this.changeSort = function(){
		KBStatusControlValue++;

		if(KBStatusControlValue == 4){
			KBStatusControlValue = 1;
		}
		
		this.CTyle();
	}		
	
	this.select = function(){
		tc.select();
		if(window.clipboardData){
			window.clipboardData.setData('Text', tc.value);	
		}
		saveCaret(tc);
	}
	
	this.CTyle();

	tc.onkeypress = function(ev){return changeKey(tc, ev || event);};
	tc.onkeydown = function(ev){setShiftKey((ev || event).shiftKey)};
	tc.onkeyup = function(ev){setShiftKey((ev || event).shiftKey)};
	tc.onchange = function(){saveCaret(tc)};
	tc.focus();
	saveCaret(tc);
	window[oName] = this;
}