820 lines
22 KiB
C++
820 lines
22 KiB
C++
|
|
#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(0x23cE,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();
|
|
}
|
|
|