summaryrefslogtreecommitdiff
path: root/windows/keybuddy2/src/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'windows/keybuddy2/src/main.cpp')
-rw-r--r--windows/keybuddy2/src/main.cpp819
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();
+}
+