diff options
| author | qwertfisch <qwertfisch@b9310e46-f624-0410-8ea1-cfbb3a30dc96> | 2012-11-19 21:25:24 +0000 | 
|---|---|---|
| committer | qwertfisch <qwertfisch@b9310e46-f624-0410-8ea1-cfbb3a30dc96> | 2012-11-19 21:25:24 +0000 | 
| commit | 4cf9a3b8fe91cc0b43d0cbab51cf02c7b1f8d60d (patch) | |
| tree | 6f6ea79393d093d6fb1627bc6279f2dfae20b155 /windows/keybuddy2/src/main.cpp | |
| parent | 2d7fc76824f63c6e72193e0a4c48ce55cbb53aee (diff) | |
| download | neo-layout-4cf9a3b8fe91cc0b43d0cbab51cf02c7b1f8d60d.tar.gz neo-layout-4cf9a3b8fe91cc0b43d0cbab51cf02c7b1f8d60d.tar.bz2 neo-layout-4cf9a3b8fe91cc0b43d0cbab51cf02c7b1f8d60d.zip  | |
KeyBuddy2: ein neuer Ansatz eines Layouttools, ähnlich zu NeoVars, aber in C++ geschrieben
git-svn-id: https://svn.neo-layout.org@2431 b9310e46-f624-0410-8ea1-cfbb3a30dc96
Diffstat (limited to 'windows/keybuddy2/src/main.cpp')
| -rw-r--r-- | windows/keybuddy2/src/main.cpp | 819 | 
1 files changed, 819 insertions, 0 deletions
diff --git a/windows/keybuddy2/src/main.cpp b/windows/keybuddy2/src/main.cpp new file mode 100644 index 0000000..fa8418f --- /dev/null +++ b/windows/keybuddy2/src/main.cpp @@ -0,0 +1,819 @@ +
 +#include "includes.h"
 +
 +#define IMAGECLASS KB2Images
 +#define IMAGEFILE <KeyBuddy2/kb2images.iml>
 +
 +#include <Draw/iml.h>
 +
 +KeyBuddy2* KeyBuddy2::pKB2=NULL;
 +LineEdit* KeyBuddy2::pdisplay=NULL; // pointer to the display
 +keyButton* KeyBuddy2::pKeyButton[256]={0}; // pointers to gui key buttons
 +BYTE KeyBuddy2::keyFinger[256]={0}; // which finger is associated to this key (=style index)
 +bool KeyBuddy2::neoLevelsActive=true; // whether the additional layers of neo are active
 +bool KeyBuddy2::neoRemapActive=false; // false=qwertz layout, true=neo layout
 +bool KeyBuddy2::cyrillicActive=false; // if roman letters are translated into cyrillic
 +bool KeyBuddy2::capslockActive=false; // if capital letters shall be sent
 +bool KeyBuddy2::lockLayer4Active=false; // if neo layer 4 is locked
 +bool KeyBuddy2::mouseControlActive=false; // if mouse control via keyboard is active
 +bool KeyBuddy2::dummySwitch=false; // that is switched by badly assigned switch pointers to prevent memory access violation
 +bool KeyBuddy2::keyPressed[256]={0}; // key states
 +wchar KeyBuddy2::lastDeadKey; // buffer that stores which dead key was pressed	
 +wchar KeyBuddy2::ruDeadChar[2]; // the dead characters for the russian keyboard (small and capital)
 +wchar KeyBuddy2::map[256][7]={0}; // character to send = map[vkCode][mod]
 +wchar KeyBuddy2::symbolMap[256][7]={0}; // character to draw on keyboard = symbolMap[vkCode][mod]
 +BYTE KeyBuddy2::neoRemap[256]={0}; // vkNeoKey = neoRemap[vkQWERTZKey]
 +wchar KeyBuddy2::rumap[256][2]={0}; // cyrillic character = rumap[ansi of latin character][ruDeadKey toggled]
 +bool* KeyBuddy2::pSwitch[256]={0}; // pointer to the switches
 +WString KeyBuddy2::keyNames[256]; // names of unmodified keys
 +wchar KeyBuddy2::upperCaseMap[1023][2]={0}; // mapping lowercase unicode characters to uppercase
 +
 +KeyBuddy2::KeyBuddy2()
 +{
 +	pKB2 = this;
 +	#ifdef DEBUG
 +		pdisplay = &display;
 +	#endif
 +	
 +	STARTLOG(SRCPATH "log.html");
 +	loadMaps();
 +	hotString::loadHotStrings();
 +	
 +	int i;
 +	for(i=0;i<=255;i++){
 +		pSwitch[i]=&dummySwitch;
 +	}
 +	pSwitch[1]=&neoLevelsActive;
 +	pSwitch[2]=&neoRemapActive;
 +	pSwitch[3]=&cyrillicActive;
 +	pSwitch[4]=&capslockActive;
 +	pSwitch[5]=&lockLayer4Active;
 +	pSwitch[6]=&mouseControlActive;
 +
 +	KeyBuddy2::Zoomable();
 +	
 +	Icon(KB2Images::tray(),KB2Images::tray());
 +	trayicon.Icon(KB2Images::tray());
 +	trayicon.WhenBar=THISBACK(traymenu);
 +	trayicon.WhenLeftDown=THISBACK(trayclick);
 +	trayicon.Tip("KeyBuddy2 (verändert Tastatur)");
 +	
 +	CtrlLayout(*this, "KeyBuddy2");
 +	releaseAllKeys();
 +	SetHook();
 +	initKeyButtons();
 +
 +	NoAccessKeysDistribution();
 +	
 +	#ifndef DEBUG
 +		WhenClose=THISBACK(Hide);
 +	#endif
 +	
 +	ToolWindow();
 +	TopMost();
 +}
 +
 +KeyBuddy2::~KeyBuddy2()
 +{
 +	releaseAllKeys();
 +	RemoveHook();
 +	ENDLOG;
 +}
 +
 +bool KeyBuddy2::ProcessKbdEvent(
 +		WPARAM upDownInfo,
 +		DWORD vkCode,
 +		DWORD scanCode,
 +		bool isExtended,
 +		bool isInjected,
 +		bool isAltDown,
 +		bool isReleased,
 +		ULONG_PTR dwExtraInfo)
 +{
 +
 +	if(scanCode==0x21d){ // AltGr also presses left Strg but with scancode 0x21d, filter that out, it sucks
 +		return false;
 +	}
 +	if(!isInjected){ // memorize physical key states
 +		keyPressed[vkCode]=!isReleased;
 +		if(isReleased){pKeyButton[vkCode]->simUp();}
 +		else{pKeyButton[vkCode]->simDown();}
 +	}
 +
 +	// log information about captured event:
 +	
 +	char udi[14]; // up down info string
 +	char buffer[512];
 +	//bool forceRedraw=false; // force keyboard redraw
 +	
 +	switch(upDownInfo){
 +		case WM_KEYDOWN:
 +			sprintf(udi,"WM_KEYDOWN");
 +			break;
 +		case WM_KEYUP:
 +			sprintf(udi,"WM_KEYUP");
 +			break;
 +		case WM_SYSKEYDOWN:
 +			sprintf(udi,"WM_SYSKEYDOWN");
 +			break;
 +		case WM_SYSKEYUP:
 +			sprintf(udi,"WM_SYSKEYUP");
 +			break;			
 +		default:
 +			sprintf(udi,"UNKNOWN");
 +	}
 +	
 +	sprintf(buffer,"upDownInfo: %s\tvkCode: %d (0x%X)\tscanCode: %d (0x%X)\textended: %d\tinjected: %d\taltdown: %d\tup: %d\tdwExtraInfo: %d",
 +	        udi,vkCode,vkCode,scanCode,scanCode,(int)isExtended,(int)isInjected,(int)isAltDown,(int)isReleased,dwExtraInfo);
 +	
 +	LOGG(buffer);
 +	LOGGNL;
 +
 +	if(dwExtraInfo==HOTSTRING){ // a hotstring is being sent, dont do anything
 +		return true;
 +	}
 +
 +	// flush the hotstring buffer if certain navi or special keys are pressed (even if they are injected)
 +	if(vkCode==VK_UP || vkCode==VK_LEFT || vkCode==VK_RIGHT || vkCode==VK_DOWN
 +		|| vkCode==VK_PRIOR || vkCode==VK_NEXT || vkCode==VK_END || vkCode==VK_HOME
 +		|| keyPressed[VK_LCONTROL] || keyPressed[VK_RCONTROL]
 +		|| keyPressed[VK_LWIN] || keyPressed[VK_RWIN] || keyPressed[VK_LMENU]){
 +			
 +		hotString::clearBuffer();		
 +	}
 +	
 +	// delete one key from hotstring buffer if backspace is pushed
 +	if(vkCode==VK_BACK && !isReleased){
 +		int i;
 +		for(i=hotString::bufferLen-1;i>0;i--){
 +			hotString::hsBuffer.Set(i,(int)hotString::hsBuffer[i-1]);
 +		}
 +		hotString::hsBuffer.Set(0,(int)0);
 +	}
 +
 +	if(isInjected){ // dont stop or change generated key events
 +		return true;
 +	}
 +
 +	// check if the key combination would activate the neo levels
 +	if(!neoLevelsActive && !isReleased){
 +
 +		neoLevelsActive=true; // only simulative to fool getNeoMod
 +		int mod=getNeoMod();
 +		WORD vkCode_neo;
 +		
 +		if(neoRemapActive && (mod==1 || mod==2 || mod==5 || mod==6) || mod==3 || mod==4 || mod==7){
 +			vkCode_neo=neoRemap[vkCode];
 +		}
 +		else{
 +			vkCode_neo=vkCode;
 +		}		
 +		if(map[vkCode_neo][mod-1]!=0xF801){ // keystroke would not activate layers, leave true otherwise
 +			neoLevelsActive=false; // deactivate again
 +		}
 +		else{ // leave activated
 +			pKB2->drawKeyButtons();
 +			return false;
 +		}
 +	}
 +	
 +	// check if the key combination turns off mouse control
 +	if(mouseControlActive && !isReleased){
 +		int mod=getNeoMod();
 +		WORD vkCode_neo;
 +		
 +		if(neoRemapActive && (mod==1 || mod==2 || mod==5 || mod==6) || mod==3 || mod==4 || mod==7){
 +			vkCode_neo=neoRemap[vkCode];
 +		}
 +		else{
 +			vkCode_neo=vkCode;
 +		}		
 +		if(map[vkCode_neo][mod-1]==0xF806){ // keystroke deactivates mouse control
 +			mouseControlActive=false; // deactivate again
 +			pKB2->drawKeyButtons();
 +			return false;
 +		}
 +	}
 +	
 +	// dont do substitutions if neolevels are off or
 +	// certain functional keys are being pressed or held (getNeoMod returns 0)
 +	// this means that ctrl+a/x/c/v/z... remain on their standard position
 +	// also clear hotstring buffer then
 +	if(getNeoMod()==0 
 +		|| vkCode==VK_LCONTROL || vkCode==VK_RCONTROL
 +		|| vkCode==VK_LWIN || vkCode==VK_RWIN
 +		|| vkCode==VK_LMENU){
 +			
 +		// redraw keyboard
 +		pKB2->drawKeyButtons();	
 +
 +		return true;
 +	}
 +
 +	// capslock
 +	if(keyPressed[VK_LSHIFT] && keyPressed[VK_RSHIFT]
 +		&& (vkCode==VK_LSHIFT || vkCode==VK_RSHIFT)
 +		&& !isReleased){
 +			capslockActive=!capslockActive;
 +			pKB2->drawKeyButtons();
 +	}
 +	
 +	// lock 4th layer
 +	if(keyPressed[VK_MOD_41] && keyPressed[VK_MOD_42]
 +		&& (vkCode==VK_MOD_41 || vkCode==VK_MOD_42)
 +		&& !isReleased){
 +			lockLayer4Active=!lockLayer4Active;
 +			pKB2->drawKeyButtons();
 +	}
 +
 +	// number keys, letter keys, ",", "-", ".", dead keys, space
 +	if((vkCode>=VK_A && vkCode<=VK_Z) || (vkCode>=VK_0 && vkCode<=VK_9)
 +		|| vkCode==VK_AE || vkCode==VK_OE || vkCode==VK_UE || vkCode==VK_SZ
 +		|| vkCode==VK_COMMA || vkCode==VK_DASH || vkCode==VK_DOT
 +		|| vkCode==VK_CIRCUMFLEX || vkCode==VK_ACUT || vkCode==VK_PLUS
 +		|| vkCode==VK_SPACE || vkCode==VK_TAB){
 +
 +		if(mouseControlActive){	
 +			mouseController::mouseEvent(vkCode,isReleased);
 +			return false;
 +		}
 +
 +		WORD vkCode_neo;
 +		int mod=getNeoMod();
 +		
 +		if(neoRemapActive && (mod==1 || mod==2 || mod==5 || mod==6) || mod==3 || mod==4 || mod==7){
 +			vkCode_neo=neoRemap[vkCode];
 +		}
 +		else{
 +			vkCode_neo=vkCode;
 +		}
 +		
 +		LOGG("vkCode: ");
 +		LOGG((int)vkCode);
 +		LOGG("   vkCode_neo: ");
 +		LOGG((int)vkCode_neo);
 +		LOGG("   mod: ");
 +		LOGG(mod);
 +				
 +		if(mod>=1 && mod<=7){
 +			wchar charToSend=map[vkCode_neo][mod-1];
 +			
 +			if(cyrillicActive){
 +				if(charToSend==ruDeadChar[0] || charToSend==ruDeadChar[1]){
 +					lastDeadKey=charToSend;
 +					pKB2->drawKeyButtons();
 +					return false;
 +				}
 +				if(charToSend>0 && charToSend<256){
 +					if(lastDeadKey==ruDeadChar[0] || lastDeadKey==ruDeadChar[1]){
 +						charToSend=rumap[charToSend][1];
 +						lastDeadKey=0;	
 +						pKB2->drawKeyButtons();
 +					}
 +					else{
 +						charToSend=rumap[charToSend][0];
 +						lastDeadKey=0;
 +					}
 +				}
 +			}
 +
 +			if(capslockActive){
 +				charToSend=upperCase(charToSend);
 +			}
 +
 +			LOGG("   sending: ");
 +			LOGG(charToSend);
 +			LOGG(" (U+");
 +			LOGG((int)charToSend);
 +			LOGG(")");
 +			LOGGNL;
 +			
 +			SendUNIKey(charToSend,isReleased);
 +			if(!isReleased){
 +				long focusPtr=hotString::getFocusWindowPtr();
 +				
 +				if(focusPtr!=hotString::lastFocusPtr){ // if a new window has the focus, clear the buffer
 +					hotString::clearBuffer();
 +					hotString::lastFocusPtr=focusPtr;
 +				}
 +				
 +				hotString::appendBuffer(charToSend);
 +				hotString::checkHotStrings();
 +			}
 +		}
 +		
 +		return false;
 +	}
 +	
 +	if(!neoLevelsActive){
 +		return true;
 +	}
 +
 +	// redraw keyboard
 +	if(vkCode==VK_LSHIFT || vkCode==VK_RSHIFT
 +		|| vkCode==VK_MOD_31 || vkCode==VK_MOD_32
 +		|| vkCode==VK_MOD_41 || vkCode==VK_MOD_42
 +		|| vkCode==VK_LCONTROL || vkCode==VK_RCONTROL){
 +		pKB2->drawKeyButtons();
 +	}
 +	
 +	// block mod keys that have symbols
 +	if(vkCode==VK_MOD_32 || vkCode==VK_MOD_41){
 +		return false;
 +	}
 +	
 +	return true;
 +}
 +
 +WString KeyBuddy2::buttonLabel(DWORD vkCode){
 +	
 +	wchar res=0;
 +
 +	if(getNeoMod()==0){
 +		return keyNames[vkCode];
 +	}
 +
 +	// number keys, letter keys, ",", "-", ".", dead keys, tab, space
 +	if((vkCode>=VK_A && vkCode<=VK_Z) || (vkCode>=VK_0 && vkCode<=VK_9)
 +		|| vkCode==VK_AE || vkCode==VK_OE || vkCode==VK_UE || vkCode==VK_SZ
 +		|| vkCode==VK_COMMA || vkCode==VK_DASH || vkCode==VK_DOT
 +		|| vkCode==VK_CIRCUMFLEX || vkCode==VK_ACUT || vkCode==VK_PLUS
 +		|| vkCode==VK_TAB || vkCode==VK_SPACE){
 +		
 +		WORD vkCode_neo;
 +		int mod=getNeoMod();
 +		
 +		if(mouseControlActive){
 +			int i;
 +			for(i=0;i<9;i++){
 +				if(vkCode==mouseController::mouseKeys[i]){
 +					res=mouseController::mouseSymbols[i];
 +					return WString((int)res,1);
 +				}
 +			}
 +			return "";
 +		}
 +		
 +		if(neoRemapActive && (mod==1 || mod==2 || mod==5 || mod==6) || mod==3 || mod==4 || mod==7){
 +			vkCode_neo=neoRemap[vkCode];
 +		}
 +		else{
 +			vkCode_neo=vkCode;
 +		}
 +	
 +		if(mod>=1 && mod<=7){
 +			res=symbolMap[vkCode_neo][mod-1];
 +			
 +			if(cyrillicActive){
 +				if(res==ruDeadChar[0] || res==ruDeadChar[1]){
 +					return WString((int)res,1);
 +				}
 +				if(res>0 && res<256){
 +					if(lastDeadKey==ruDeadChar[0] || lastDeadKey==ruDeadChar[1]){
 +						res=rumap[res][1];
 +					}
 +					else{
 +						res=rumap[res][0];
 +					}
 +				}
 +			}
 +			
 +			if(capslockActive){
 +				res=upperCase(res);
 +			}
 +			
 +			return WString((int)res,1);
 +		}
 +		
 +	}
 +	
 +	switch(vkCode){ // layer-independent keys
 +		case VK_LSHIFT: case VK_RSHIFT: return WString(0x21e7,1); break;
 +		case VK_MOD_31: case VK_MOD_32: return WString("Mod3"); break;
 +		case VK_MOD_41: case VK_MOD_42: return WString("Mod4"); break;
 +		case VK_RETURN: return WString(0x21b5,1); break;
 +		case VK_BACK: return WString(0x232b,1); break;
 +		case VK_LCONTROL: case VK_RCONTROL: return WString("Strg"); break;
 +		case VK_LMENU: return WString("Alt"); break;
 +		case VK_LWIN: case VK_RWIN: return WString(0x229e,1)+WString(0x224b,1); break;
 +		case VK_APPS: return WString(0x2338,1)+WString(0x21d6,1); break;
 +	}
 +
 +	return WString("");	
 +	
 +}
 +
 +int KeyBuddy2::getNeoMod(){
 +	
 +	if(keyPressed[VK_LCONTROL] || keyPressed[VK_RCONTROL] // functional keys, disable neo stuff
 +		|| keyPressed[VK_LWIN] || keyPressed[VK_RWIN]
 +		|| keyPressed[VK_LMENU] || !neoLevelsActive){
 +			
 +			return 0;
 +	}
 +	
 +	bool kp2=keyPressed[VK_MOD_21] || keyPressed[VK_MOD_22];
 +	bool kp3=keyPressed[VK_MOD_31] || keyPressed[VK_MOD_32];
 +	bool kp4=keyPressed[VK_MOD_41] || keyPressed[VK_MOD_42] || lockLayer4Active;
 +
 +	if(!kp2 && !kp3 && !kp4){return 1;} // small letters
 +	
 +	if( kp2 && !kp3 && !kp4){return 2;} // capital letters
 +	
 +	if(!kp2 &&  kp3 && !kp4){return 3;} // special characters
 +	
 +	if(!kp2 && !kp3 &&  kp4){return 4;} // numbers/navi
 +	
 +	if( kp2 &&  kp3 && !kp4){return 5;} // small greek
 +	
 +	if(!kp2 &&  kp3 &&  kp4){return 6;} // capital greek/math
 +	
 +	if( kp2 && !kp3 &&  kp4){return 7;} // pseudo layer
 +	
 +	return 0;
 +		
 +}
 +
 +void KeyBuddy2::loadMaps(){
 +	FILE* pFile;
 +	int i;
 +	BYTE buffer;
 +	wchar unibuffer;
 +	
 +	#define FGETUC(pbuf,pfile) fread(pbuf,sizeof(wchar),1,pfile)
 +	
 +	// QWERTZ keycode -> neo keycode
 +	
 +	pFile = fopen(SRCPATH "neomap.txt", "rb");
 +	if (pFile==NULL) {PromptOK("Can't read neomap.txt"); exit(1);}	
 +	
 +	neoRemap[0]=0;
 +	
 +	for(i=1;i<=255;i++){ // assuming that no key has keycode 0. Otherwise the linenumber in map.txt does not match the keycode
 +		buffer=fgetc(pFile);
 +		if(buffer==13){ // line break, no mapping
 +			neoRemap[i]=i;
 +			fgetc(pFile); // skip second line break character
 +		}
 +		else{
 +			neoRemap[i]=buffer;
 +			fgetc(pFile); // skip line break characters
 +			fgetc(pFile);
 +		}
 +		LOGG("neoRemap ");LOGG(i);LOGG("->");LOGG(neoRemap[i]);LOGGNL;
 +	}
 +	fclose(pFile);
 +		
 +	
 +	// keycode -> unicode character to send
 +	
 +	pFile = fopen(SRCPATH "sendmap.txt", "rb");
 +	if (pFile==NULL) {PromptOK("Can't read sendmap.txt"); exit(1);}
 +	
 +	fgetc(pFile); // skip BOM
 +	fgetc(pFile);
 +	
 +	memset(map[0],0,7);
 +	
 +	for(i=1;i<=255;i++){ // assuming that no key has keycode 0. Otherwise the linenumber in sendmap.txt does not match the keycode
 +		fread(map[i],sizeof(wchar),7,pFile); // read from file
 +		fgetc(pFile); // skip line break (make sure to have a line break at the end of the file)
 +		fgetc(pFile);
 +		fgetc(pFile);
 +		fgetc(pFile);
 +		
 +		LOGG("key ");LOGG(i);LOGG(": ");LOGG(map[i][0]);LOGG(map[i][1]);LOGG(map[i][2]);LOGG(map[i][3]);LOGG(map[i][4]);LOGG(map[i][5]);LOGG(map[i][6]);LOGGNL;
 +	}
 +	fclose(pFile);
 +
 +
 +	// keycode -> unicode character to draw on keyboard
 +	
 +	pFile = fopen(SRCPATH "symbolmap.txt", "rb");
 +	if (pFile==NULL) {PromptOK("Can't read symbolmap.txt"); exit(1);}
 +	
 +	fgetc(pFile); // skip BOM
 +	fgetc(pFile);
 +	
 +	memset(symbolMap[0],0,7);
 +	
 +	for(i=1;i<=255;i++){ // assuming that no key has keycode 0. Otherwise the linenumber in symbolmap.txt does not match the keycode
 +		fread(symbolMap[i],sizeof(wchar),7,pFile); // read from file
 +		fgetc(pFile); // skip line break (make sure to have a line break at the end of the file)
 +		fgetc(pFile);
 +		fgetc(pFile);
 +		fgetc(pFile);
 +		
 +		LOGG("key ");LOGG(i);LOGG(": ");LOGG(map[i][0]);LOGG(map[i][1]);LOGG(map[i][2]);LOGG(map[i][3]);LOGG(map[i][4]);LOGG(map[i][5]);LOGG(map[i][6]);LOGGNL;
 +	}
 +	fclose(pFile);
 +
 +
 +	// latin character -> cyrillic character
 +	pFile = fopen(SRCPATH "rumap.txt", "rb");
 +	if (pFile==NULL) {PromptOK("Can't read rumap.txt"); exit(1);}
 +	
 +	fgetc(pFile); // skip BOM
 +	fgetc(pFile);
 +
 +	rumap[0][0]=0;
 +	rumap[0][1]=0;
 +
 +	int idead=0;
 +
 +	for(i=1;i<=255;i++){
 +		FGETUC(&unibuffer,pFile);
 +		if(unibuffer==13){ // line break, no mapping
 +			rumap[i][0]=i;
 +			rumap[i][1]=i;
 +			FGETUC(&unibuffer,pFile); // skip second line break character
 +		}
 +		else{
 +			if(unibuffer==0x2020){ // dagger, symbol for the dead character
 +				rumap[i][0]=0;
 +				rumap[i][1]=0;
 +				ruDeadChar[idead]=i;
 +				idead++;
 +				FGETUC(&unibuffer,pFile); // skip line break characters
 +				FGETUC(&unibuffer,pFile);									
 +			}
 +			else{
 +				rumap[i][0]=unibuffer;
 +				rumap[i][1]=unibuffer;
 +				FGETUC(&unibuffer,pFile);
 +				if(unibuffer==13){ // line break, no special character if dead key is toggled
 +					FGETUC(&unibuffer,pFile); // skip second line break character
 +				}
 +				else{ // special character if cyrillic dead key is toggled
 +					rumap[i][1]=unibuffer;
 +					FGETUC(&unibuffer,pFile); // skip line break characters
 +					FGETUC(&unibuffer,pFile);				
 +				}
 +			}
 +		}
 +		LOGG("russianRemap ");LOGG(i);LOGG("->");LOGG(rumap[i][0]);LOGG("/");LOGG(rumap[i][1]);LOGGNL;
 +	}
 +	fclose(pFile);
 +
 +	// keycode -> keyname
 +	
 +	pFile = fopen(SRCPATH "keynames.txt", "rb");
 +	if (pFile==NULL) {PromptOK("Can't read keynames.txt"); exit(1);}
 +	
 +	fgetc(pFile); // skip BOM
 +	fgetc(pFile);
 +
 +	keyNames[0]="";
 +	for(i=1;i<=255;i++){
 +		keyNames[i]="";
 +		
 +		FGETUC(&unibuffer,pFile);
 +		while(unibuffer!=13){ // line break
 +			keyNames[i]=keyNames[i]+unibuffer;
 +			FGETUC(&unibuffer,pFile);
 +		}
 +
 +		FGETUC(&unibuffer,pFile); // skip second line break character
 +	}
 +	fclose(pFile);
 +	
 +	// lowercase -> uppercase
 +	
 +	pFile = fopen(SRCPATH "uppercase.txt", "rb");
 +	if (pFile==NULL) {PromptOK("Can't read uppercase.txt"); exit(1);}
 +	
 +	fgetc(pFile); // skip BOM
 +	fgetc(pFile);
 +
 +	i=0;
 +	while(!feof(pFile) && i<1023){
 +		FGETUC(&(upperCaseMap[i][0]),pFile);
 +		FGETUC(&(upperCaseMap[i][1]),pFile);
 +		i++;
 +	}
 +	fclose(pFile);
 +	
 +	while(i<1023){
 +		upperCaseMap[i][0]=0xFFFF;
 +		upperCaseMap[i][1]=0xFFFF;
 +		i++;
 +	}
 +	   
 +	// keycode -> mouseevent
 +	
 +	pFile = fopen(SRCPATH "mousemap.txt", "rb");
 +	if (pFile==NULL) {PromptOK("Can't read mousemap.txt"); exit(1);}
 +	
 +	fread(mouseController::mouseKeys,sizeof(byte),9,pFile);
 +	fclose(pFile);
 +}
 +
 +void KeyBuddy2::SendUNIKey(wchar key, bool release, ULONG_PTR extraInfo){
 +
 +	// use unicodes Personal Usage Area (E000-F8FF) specially
 +	if(key/256>=0xE0 && key/256<=0xF8){ // send keystroke instead of unicode
 +		byte flags=key/256;
 +		bool onlyDown=flags<=0xE7;
 +		bool onlyUp=flags>=0xE8 && flags<=0xEF;
 +		bool swtch=(flags==0xF8);
 +		bool shift=(flags & 1)!=0;
 +		bool ctrl=(flags & 2)!=0;
 +		bool alt=(flags & 4)!=0;
 +				
 +		// E0-E7: only down event gets sent
 +		// E8-EF: only up event gets sent (but if key is pushed down)
 +		// F0-F7: down and up according to release parameter
 +		// F8: switch
 +		// unicode AND 0x0100 = shift also pressed
 +		// unicode AND 0x0200 = ctrl also pressed
 +		// unicode AND 0x0400 = alt also pressed
 +
 +		if(swtch && !release){
 +			if(key % 256==0){ // end program
 +				KeyBuddy2::pKB2->Break();
 +			}
 +			if(key % 256==7){ // show / hide GUI
 +				KeyBuddy2::pKB2->Show(!KeyBuddy2::pKB2->IsShown());
 +				return;
 +			}			
 +			*(KeyBuddy2::pSwitch[key % 256])=!*(KeyBuddy2::pSwitch[key % 256]);
 +			return;
 +		}
 +		
 +		if((onlyDown || onlyUp) && release){return;}
 +		
 +		// first release all other keys
 +		byte keyboardStateBuffer[256];
 +		byte allUp[256];
 +		DWORD unused;
 +		
 +		memset(keyboardStateBuffer,0,256);
 +		memset(allUp,0,256);
 +
 +		long myThread=GetWindowThreadProcessId(KeyBuddy2::pKB2->GetHWND(),&unused);
 +		long otherThread=GetWindowThreadProcessId(GetForegroundWindow(),&unused);
 +		
 +		if(myThread!=otherThread){
 +			AttachThreadInput(otherThread,myThread,true);
 +		}
 +		
 +		GetKeyboardState(keyboardStateBuffer);
 +		SetKeyboardState(allUp);		
 +		
 +		// then send the key
 +		
 +		INPUT in[4];
 +		int iIn=0;
 +		
 +		for(iIn=0;iIn<4;iIn++){
 +			in[iIn].type=INPUT_KEYBOARD;
 +			in[iIn].ki.dwExtraInfo=extraInfo;
 +			in[iIn].ki.time=0;
 +			in[iIn].ki.wScan=0;
 +			in[iIn].ki.dwFlags=0;
 +			if(release){in[iIn].ki.dwFlags=KEYEVENTF_KEYUP;}
 +		}
 +		
 +		iIn=0;
 +		
 +		if(release){ // if we release the buttons, release the key of interest first, then ctrl, alt or shift
 +			in[iIn].ki.wVk=key % 256;
 +			iIn++;
 +		}
 +		if(ctrl){
 +			in[iIn].ki.wVk=VK_LCONTROL;
 +			iIn++;
 +		}
 +		if(shift){
 +			in[iIn].ki.wVk=VK_LSHIFT;
 +			iIn++;
 +		}
 +		if(alt){
 +			in[iIn].ki.wVk=VK_LMENU;
 +			iIn++;
 +		}
 +		if(!release){ // if we push the buttons, push ctrl alt shift first, then the key of interest
 +			in[iIn].ki.wVk=key % 256;
 +			iIn++;
 +		}			
 +		
 +		SendInput(iIn,in,sizeof(INPUT));
 +		
 +		Sleep(1); // otherwise the other thread does not see the changed keyboard state
 +		
 +		// revert keyboard to its original state
 +		SetKeyboardState(keyboardStateBuffer);
 +		
 +		if(myThread!=otherThread){
 +			AttachThreadInput(otherThread,myThread,false);
 +		}
 +	}
 +	else{ // only send unicode character
 +		INPUT in[1];
 +		in[0].type=INPUT_KEYBOARD;
 +		in[0].ki.dwExtraInfo=extraInfo;		
 +		in[0].ki.wVk=0;
 +		in[0].ki.wScan=key;
 +		in[0].ki.dwFlags=KEYEVENTF_UNICODE;
 +		if(release){in[0].ki.dwFlags=in[0].ki.dwFlags | KEYEVENTF_KEYUP;}
 +		SendInput(1,in,sizeof(INPUT));
 +	}
 +}
 +
 +void KeyBuddy2::releaseAllKeys(){
 +	BYTE zeros[256]={0};
 +	SetKeyboardState(zeros);
 +	for(int i=0;i<256;i++){
 +		keyPressed[i]=false;
 +	}
 +}
 +
 +void KeyBuddy2::initKeyButtons(){
 +	int i,j;
 +	
 +	for(i=0; i<7; i++){
 +		buttonStyle[i] = Button::StyleNormal();
 +		for(j=0;j<4;j++){
 +			buttonStyle[i].look[j] = KB2Images::Get(i);
 +		}
 +		buttonStyle[i].look[2] = KB2Images::Get(1);
 +		buttonStyle[i].pressoffset = Point(0,0);
 +	}
 +	
 +	for(i=0;i<256;i++){
 +		pKeyButton[i]=&but_invis;
 +		keyFinger[i]=0;
 +	}
 +	
 +	but_invis.Hide();
 +
 +	#include "keybuttons.inc"
 +	
 +	int bfid=buttonFont.FindFaceNameIndex("unifont");
 +	buttonFont.Face(bfid);
 +	buttonFontU.Face(bfid);
 +	buttonFontU.Underline();
 +	smallButtonFont.Face(bfid);
 +	buttonFont.Height(32);
 +	buttonFontU.Height(32);
 +	smallButtonFont.Height(16);
 +	
 +	for(i=0;i<256;i++){
 +		pKeyButton[i]->SetStyle(buttonStyle[keyFinger[i]]);
 +		if(i==VK_MOD_31 || i==VK_MOD_32 || i==VK_MOD_41 || i==VK_MOD_42
 +			|| i==VK_LMENU || i==VK_LCONTROL || i==VK_RCONTROL){
 +			pKeyButton[i]->SetFont(smallButtonFont);
 +		}
 +		else{
 +			if(i==VK_A || i==VK_S || i==VK_D || i==VK_F
 +				|| i==VK_J || i==VK_K || i==VK_L || i==VK_OE){
 +				pKeyButton[i]->SetFont(buttonFontU);
 +			}
 +			else{
 +				pKeyButton[i]->SetFont(buttonFont);
 +			}
 +		}
 +		
 +		pKeyButton[i]->SetLabel(ToUtf8(buttonLabel(i)));
 +		//pKeyButton[i]->Disable();
 +	}
 +}
 +
 +void KeyBuddy2::drawKeyButtons(){
 +	int i;
 +	String newLabel,oldLabel;
 +
 +	for(i=0;i<256;i++){
 +		newLabel=ToUtf8(buttonLabel(i));
 +		oldLabel=pKeyButton[i]->GetLabel();
 +		if(!newLabel.IsEqual(oldLabel)){
 +			if(!pKeyButton[i]->isPushed()){
 +				pKeyButton[i]->SetLabel(newLabel);
 +			}
 +			else{
 +				pKeyButton[i]->simUp();
 +				pKeyButton[i]->SetLabel(newLabel);
 +				pKeyButton[i]->simDown();
 +			}
 +		}
 +	}
 +}
 +
 +wchar KeyBuddy2::upperCase(wchar letter){
 +	int a=0,b=1022,c;
 +	
 +	while(a<=b){
 +		c=(a+b)/2;
 +		if( letter< upperCaseMap[c][0] ){b=c-1; continue;}
 +		if( letter> upperCaseMap[c][0] ){a=c+1; continue;}
 +		if( letter==upperCaseMap[c][0] ){return upperCaseMap[c][1];}
 +	}
 +	
 +	return letter;
 +}
 +
 +GUI_APP_MAIN
 +{
 +	KeyBuddy2().Run();	
 +}
 +
  | 
