neo-layout/windows/keybuddy2/src/main.cpp

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();
}