Neo ist eine ergonomische Tastaturbelegung, welche für die deutsche Sprache optimiert ist. https://neo-layout.org
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

820 lines
22KB

  1. #include "includes.h"
  2. #define IMAGECLASS KB2Images
  3. #define IMAGEFILE <KeyBuddy2/kb2images.iml>
  4. #include <Draw/iml.h>
  5. KeyBuddy2* KeyBuddy2::pKB2=NULL;
  6. LineEdit* KeyBuddy2::pdisplay=NULL; // pointer to the display
  7. keyButton* KeyBuddy2::pKeyButton[256]={0}; // pointers to gui key buttons
  8. BYTE KeyBuddy2::keyFinger[256]={0}; // which finger is associated to this key (=style index)
  9. bool KeyBuddy2::neoLevelsActive=true; // whether the additional layers of neo are active
  10. bool KeyBuddy2::neoRemapActive=false; // false=qwertz layout, true=neo layout
  11. bool KeyBuddy2::cyrillicActive=false; // if roman letters are translated into cyrillic
  12. bool KeyBuddy2::capslockActive=false; // if capital letters shall be sent
  13. bool KeyBuddy2::lockLayer4Active=false; // if neo layer 4 is locked
  14. bool KeyBuddy2::mouseControlActive=false; // if mouse control via keyboard is active
  15. bool KeyBuddy2::dummySwitch=false; // that is switched by badly assigned switch pointers to prevent memory access violation
  16. bool KeyBuddy2::keyPressed[256]={0}; // key states
  17. wchar KeyBuddy2::lastDeadKey; // buffer that stores which dead key was pressed
  18. wchar KeyBuddy2::ruDeadChar[2]; // the dead characters for the russian keyboard (small and capital)
  19. wchar KeyBuddy2::map[256][7]={0}; // character to send = map[vkCode][mod]
  20. wchar KeyBuddy2::symbolMap[256][7]={0}; // character to draw on keyboard = symbolMap[vkCode][mod]
  21. BYTE KeyBuddy2::neoRemap[256]={0}; // vkNeoKey = neoRemap[vkQWERTZKey]
  22. wchar KeyBuddy2::rumap[256][2]={0}; // cyrillic character = rumap[ansi of latin character][ruDeadKey toggled]
  23. bool* KeyBuddy2::pSwitch[256]={0}; // pointer to the switches
  24. WString KeyBuddy2::keyNames[256]; // names of unmodified keys
  25. wchar KeyBuddy2::upperCaseMap[1023][2]={0}; // mapping lowercase unicode characters to uppercase
  26. KeyBuddy2::KeyBuddy2()
  27. {
  28. pKB2 = this;
  29. #ifdef DEBUG
  30. pdisplay = &display;
  31. #endif
  32. STARTLOG(SRCPATH "log.html");
  33. loadMaps();
  34. hotString::loadHotStrings();
  35. int i;
  36. for(i=0;i<=255;i++){
  37. pSwitch[i]=&dummySwitch;
  38. }
  39. pSwitch[1]=&neoLevelsActive;
  40. pSwitch[2]=&neoRemapActive;
  41. pSwitch[3]=&cyrillicActive;
  42. pSwitch[4]=&capslockActive;
  43. pSwitch[5]=&lockLayer4Active;
  44. pSwitch[6]=&mouseControlActive;
  45. KeyBuddy2::Zoomable();
  46. Icon(KB2Images::tray(),KB2Images::tray());
  47. trayicon.Icon(KB2Images::tray());
  48. trayicon.WhenBar=THISBACK(traymenu);
  49. trayicon.WhenLeftDown=THISBACK(trayclick);
  50. trayicon.Tip("KeyBuddy2 (verändert Tastatur)");
  51. CtrlLayout(*this, "KeyBuddy2");
  52. releaseAllKeys();
  53. SetHook();
  54. initKeyButtons();
  55. NoAccessKeysDistribution();
  56. #ifndef DEBUG
  57. WhenClose=THISBACK(Hide);
  58. #endif
  59. ToolWindow();
  60. TopMost();
  61. }
  62. KeyBuddy2::~KeyBuddy2()
  63. {
  64. releaseAllKeys();
  65. RemoveHook();
  66. ENDLOG;
  67. }
  68. bool KeyBuddy2::ProcessKbdEvent(
  69. WPARAM upDownInfo,
  70. DWORD vkCode,
  71. DWORD scanCode,
  72. bool isExtended,
  73. bool isInjected,
  74. bool isAltDown,
  75. bool isReleased,
  76. ULONG_PTR dwExtraInfo)
  77. {
  78. if(scanCode==0x21d){ // AltGr also presses left Strg but with scancode 0x21d, filter that out, it sucks
  79. return false;
  80. }
  81. if(!isInjected){ // memorize physical key states
  82. keyPressed[vkCode]=!isReleased;
  83. if(isReleased){pKeyButton[vkCode]->simUp();}
  84. else{pKeyButton[vkCode]->simDown();}
  85. }
  86. // log information about captured event:
  87. char udi[14]; // up down info string
  88. char buffer[512];
  89. //bool forceRedraw=false; // force keyboard redraw
  90. switch(upDownInfo){
  91. case WM_KEYDOWN:
  92. sprintf(udi,"WM_KEYDOWN");
  93. break;
  94. case WM_KEYUP:
  95. sprintf(udi,"WM_KEYUP");
  96. break;
  97. case WM_SYSKEYDOWN:
  98. sprintf(udi,"WM_SYSKEYDOWN");
  99. break;
  100. case WM_SYSKEYUP:
  101. sprintf(udi,"WM_SYSKEYUP");
  102. break;
  103. default:
  104. sprintf(udi,"UNKNOWN");
  105. }
  106. sprintf(buffer,"upDownInfo: %s\tvkCode: %d (0x%X)\tscanCode: %d (0x%X)\textended: %d\tinjected: %d\taltdown: %d\tup: %d\tdwExtraInfo: %d",
  107. udi,vkCode,vkCode,scanCode,scanCode,(int)isExtended,(int)isInjected,(int)isAltDown,(int)isReleased,dwExtraInfo);
  108. LOGG(buffer);
  109. LOGGNL;
  110. if(dwExtraInfo==HOTSTRING){ // a hotstring is being sent, dont do anything
  111. return true;
  112. }
  113. // flush the hotstring buffer if certain navi or special keys are pressed (even if they are injected)
  114. if(vkCode==VK_UP || vkCode==VK_LEFT || vkCode==VK_RIGHT || vkCode==VK_DOWN
  115. || vkCode==VK_PRIOR || vkCode==VK_NEXT || vkCode==VK_END || vkCode==VK_HOME
  116. || keyPressed[VK_LCONTROL] || keyPressed[VK_RCONTROL]
  117. || keyPressed[VK_LWIN] || keyPressed[VK_RWIN] || keyPressed[VK_LMENU]){
  118. hotString::clearBuffer();
  119. }
  120. // delete one key from hotstring buffer if backspace is pushed
  121. if(vkCode==VK_BACK && !isReleased){
  122. int i;
  123. for(i=hotString::bufferLen-1;i>0;i--){
  124. hotString::hsBuffer.Set(i,(int)hotString::hsBuffer[i-1]);
  125. }
  126. hotString::hsBuffer.Set(0,(int)0);
  127. }
  128. if(isInjected){ // dont stop or change generated key events
  129. return true;
  130. }
  131. // check if the key combination would activate the neo levels
  132. if(!neoLevelsActive && !isReleased){
  133. neoLevelsActive=true; // only simulative to fool getNeoMod
  134. int mod=getNeoMod();
  135. WORD vkCode_neo;
  136. if(neoRemapActive && (mod==1 || mod==2 || mod==5 || mod==6) || mod==3 || mod==4 || mod==7){
  137. vkCode_neo=neoRemap[vkCode];
  138. }
  139. else{
  140. vkCode_neo=vkCode;
  141. }
  142. if(map[vkCode_neo][mod-1]!=0xF801){ // keystroke would not activate layers, leave true otherwise
  143. neoLevelsActive=false; // deactivate again
  144. }
  145. else{ // leave activated
  146. pKB2->drawKeyButtons();
  147. return false;
  148. }
  149. }
  150. // check if the key combination turns off mouse control
  151. if(mouseControlActive && !isReleased){
  152. int mod=getNeoMod();
  153. WORD vkCode_neo;
  154. if(neoRemapActive && (mod==1 || mod==2 || mod==5 || mod==6) || mod==3 || mod==4 || mod==7){
  155. vkCode_neo=neoRemap[vkCode];
  156. }
  157. else{
  158. vkCode_neo=vkCode;
  159. }
  160. if(map[vkCode_neo][mod-1]==0xF806){ // keystroke deactivates mouse control
  161. mouseControlActive=false; // deactivate again
  162. pKB2->drawKeyButtons();
  163. return false;
  164. }
  165. }
  166. // dont do substitutions if neolevels are off or
  167. // certain functional keys are being pressed or held (getNeoMod returns 0)
  168. // this means that ctrl+a/x/c/v/z... remain on their standard position
  169. // also clear hotstring buffer then
  170. if(getNeoMod()==0
  171. || vkCode==VK_LCONTROL || vkCode==VK_RCONTROL
  172. || vkCode==VK_LWIN || vkCode==VK_RWIN
  173. || vkCode==VK_LMENU){
  174. // redraw keyboard
  175. pKB2->drawKeyButtons();
  176. return true;
  177. }
  178. // capslock
  179. if(keyPressed[VK_LSHIFT] && keyPressed[VK_RSHIFT]
  180. && (vkCode==VK_LSHIFT || vkCode==VK_RSHIFT)
  181. && !isReleased){
  182. capslockActive=!capslockActive;
  183. pKB2->drawKeyButtons();
  184. }
  185. // lock 4th layer
  186. if(keyPressed[VK_MOD_41] && keyPressed[VK_MOD_42]
  187. && (vkCode==VK_MOD_41 || vkCode==VK_MOD_42)
  188. && !isReleased){
  189. lockLayer4Active=!lockLayer4Active;
  190. pKB2->drawKeyButtons();
  191. }
  192. // number keys, letter keys, ",", "-", ".", dead keys, space
  193. if((vkCode>=VK_A && vkCode<=VK_Z) || (vkCode>=VK_0 && vkCode<=VK_9)
  194. || vkCode==VK_AE || vkCode==VK_OE || vkCode==VK_UE || vkCode==VK_SZ
  195. || vkCode==VK_COMMA || vkCode==VK_DASH || vkCode==VK_DOT
  196. || vkCode==VK_CIRCUMFLEX || vkCode==VK_ACUT || vkCode==VK_PLUS
  197. || vkCode==VK_SPACE || vkCode==VK_TAB){
  198. if(mouseControlActive){
  199. mouseController::mouseEvent(vkCode,isReleased);
  200. return false;
  201. }
  202. WORD vkCode_neo;
  203. int mod=getNeoMod();
  204. if(neoRemapActive && (mod==1 || mod==2 || mod==5 || mod==6) || mod==3 || mod==4 || mod==7){
  205. vkCode_neo=neoRemap[vkCode];
  206. }
  207. else{
  208. vkCode_neo=vkCode;
  209. }
  210. LOGG("vkCode: ");
  211. LOGG((int)vkCode);
  212. LOGG(" vkCode_neo: ");
  213. LOGG((int)vkCode_neo);
  214. LOGG(" mod: ");
  215. LOGG(mod);
  216. if(mod>=1 && mod<=7){
  217. wchar charToSend=map[vkCode_neo][mod-1];
  218. if(cyrillicActive){
  219. if(charToSend==ruDeadChar[0] || charToSend==ruDeadChar[1]){
  220. lastDeadKey=charToSend;
  221. pKB2->drawKeyButtons();
  222. return false;
  223. }
  224. if(charToSend>0 && charToSend<256){
  225. if(lastDeadKey==ruDeadChar[0] || lastDeadKey==ruDeadChar[1]){
  226. charToSend=rumap[charToSend][1];
  227. lastDeadKey=0;
  228. pKB2->drawKeyButtons();
  229. }
  230. else{
  231. charToSend=rumap[charToSend][0];
  232. lastDeadKey=0;
  233. }
  234. }
  235. }
  236. if(capslockActive){
  237. charToSend=upperCase(charToSend);
  238. }
  239. LOGG(" sending: ");
  240. LOGG(charToSend);
  241. LOGG(" (U+");
  242. LOGG((int)charToSend);
  243. LOGG(")");
  244. LOGGNL;
  245. SendUNIKey(charToSend,isReleased);
  246. if(!isReleased){
  247. long focusPtr=hotString::getFocusWindowPtr();
  248. if(focusPtr!=hotString::lastFocusPtr){ // if a new window has the focus, clear the buffer
  249. hotString::clearBuffer();
  250. hotString::lastFocusPtr=focusPtr;
  251. }
  252. hotString::appendBuffer(charToSend);
  253. hotString::checkHotStrings();
  254. }
  255. }
  256. return false;
  257. }
  258. if(!neoLevelsActive){
  259. return true;
  260. }
  261. // redraw keyboard
  262. if(vkCode==VK_LSHIFT || vkCode==VK_RSHIFT
  263. || vkCode==VK_MOD_31 || vkCode==VK_MOD_32
  264. || vkCode==VK_MOD_41 || vkCode==VK_MOD_42
  265. || vkCode==VK_LCONTROL || vkCode==VK_RCONTROL){
  266. pKB2->drawKeyButtons();
  267. }
  268. // block mod keys that have symbols
  269. if(vkCode==VK_MOD_32 || vkCode==VK_MOD_41){
  270. return false;
  271. }
  272. return true;
  273. }
  274. WString KeyBuddy2::buttonLabel(DWORD vkCode){
  275. wchar res=0;
  276. if(getNeoMod()==0){
  277. return keyNames[vkCode];
  278. }
  279. // number keys, letter keys, ",", "-", ".", dead keys, tab, space
  280. if((vkCode>=VK_A && vkCode<=VK_Z) || (vkCode>=VK_0 && vkCode<=VK_9)
  281. || vkCode==VK_AE || vkCode==VK_OE || vkCode==VK_UE || vkCode==VK_SZ
  282. || vkCode==VK_COMMA || vkCode==VK_DASH || vkCode==VK_DOT
  283. || vkCode==VK_CIRCUMFLEX || vkCode==VK_ACUT || vkCode==VK_PLUS
  284. || vkCode==VK_TAB || vkCode==VK_SPACE){
  285. WORD vkCode_neo;
  286. int mod=getNeoMod();
  287. if(mouseControlActive){
  288. int i;
  289. for(i=0;i<9;i++){
  290. if(vkCode==mouseController::mouseKeys[i]){
  291. res=mouseController::mouseSymbols[i];
  292. return WString((int)res,1);
  293. }
  294. }
  295. return "";
  296. }
  297. if(neoRemapActive && (mod==1 || mod==2 || mod==5 || mod==6) || mod==3 || mod==4 || mod==7){
  298. vkCode_neo=neoRemap[vkCode];
  299. }
  300. else{
  301. vkCode_neo=vkCode;
  302. }
  303. if(mod>=1 && mod<=7){
  304. res=symbolMap[vkCode_neo][mod-1];
  305. if(cyrillicActive){
  306. if(res==ruDeadChar[0] || res==ruDeadChar[1]){
  307. return WString((int)res,1);
  308. }
  309. if(res>0 && res<256){
  310. if(lastDeadKey==ruDeadChar[0] || lastDeadKey==ruDeadChar[1]){
  311. res=rumap[res][1];
  312. }
  313. else{
  314. res=rumap[res][0];
  315. }
  316. }
  317. }
  318. if(capslockActive){
  319. res=upperCase(res);
  320. }
  321. return WString((int)res,1);
  322. }
  323. }
  324. switch(vkCode){ // layer-independent keys
  325. case VK_LSHIFT: case VK_RSHIFT: return WString(0x21e7,1); break;
  326. case VK_MOD_31: case VK_MOD_32: return WString("Mod3"); break;
  327. case VK_MOD_41: case VK_MOD_42: return WString("Mod4"); break;
  328. case VK_RETURN: return WString(0x23cE,1); break;
  329. case VK_BACK: return WString(0x232b,1); break;
  330. case VK_LCONTROL: case VK_RCONTROL: return WString("Strg"); break;
  331. case VK_LMENU: return WString("Alt"); break;
  332. case VK_LWIN: case VK_RWIN: return WString(0x229e,1)+WString(0x224b,1); break;
  333. case VK_APPS: return WString(0x2338,1)+WString(0x21d6,1); break;
  334. }
  335. return WString("");
  336. }
  337. int KeyBuddy2::getNeoMod(){
  338. if(keyPressed[VK_LCONTROL] || keyPressed[VK_RCONTROL] // functional keys, disable neo stuff
  339. || keyPressed[VK_LWIN] || keyPressed[VK_RWIN]
  340. || keyPressed[VK_LMENU] || !neoLevelsActive){
  341. return 0;
  342. }
  343. bool kp2=keyPressed[VK_MOD_21] || keyPressed[VK_MOD_22];
  344. bool kp3=keyPressed[VK_MOD_31] || keyPressed[VK_MOD_32];
  345. bool kp4=keyPressed[VK_MOD_41] || keyPressed[VK_MOD_42] || lockLayer4Active;
  346. if(!kp2 && !kp3 && !kp4){return 1;} // small letters
  347. if( kp2 && !kp3 && !kp4){return 2;} // capital letters
  348. if(!kp2 && kp3 && !kp4){return 3;} // special characters
  349. if(!kp2 && !kp3 && kp4){return 4;} // numbers/navi
  350. if( kp2 && kp3 && !kp4){return 5;} // small greek
  351. if(!kp2 && kp3 && kp4){return 6;} // capital greek/math
  352. if( kp2 && !kp3 && kp4){return 7;} // pseudo layer
  353. return 0;
  354. }
  355. void KeyBuddy2::loadMaps(){
  356. FILE* pFile;
  357. int i;
  358. BYTE buffer;
  359. wchar unibuffer;
  360. #define FGETUC(pbuf,pfile) fread(pbuf,sizeof(wchar),1,pfile)
  361. // QWERTZ keycode -> neo keycode
  362. pFile = fopen(SRCPATH "neomap.txt", "rb");
  363. if (pFile==NULL) {PromptOK("Can't read neomap.txt"); exit(1);}
  364. neoRemap[0]=0;
  365. for(i=1;i<=255;i++){ // assuming that no key has keycode 0. Otherwise the linenumber in map.txt does not match the keycode
  366. buffer=fgetc(pFile);
  367. if(buffer==13){ // line break, no mapping
  368. neoRemap[i]=i;
  369. fgetc(pFile); // skip second line break character
  370. }
  371. else{
  372. neoRemap[i]=buffer;
  373. fgetc(pFile); // skip line break characters
  374. fgetc(pFile);
  375. }
  376. LOGG("neoRemap ");LOGG(i);LOGG("->");LOGG(neoRemap[i]);LOGGNL;
  377. }
  378. fclose(pFile);
  379. // keycode -> unicode character to send
  380. pFile = fopen(SRCPATH "sendmap.txt", "rb");
  381. if (pFile==NULL) {PromptOK("Can't read sendmap.txt"); exit(1);}
  382. fgetc(pFile); // skip BOM
  383. fgetc(pFile);
  384. memset(map[0],0,7);
  385. for(i=1;i<=255;i++){ // assuming that no key has keycode 0. Otherwise the linenumber in sendmap.txt does not match the keycode
  386. fread(map[i],sizeof(wchar),7,pFile); // read from file
  387. fgetc(pFile); // skip line break (make sure to have a line break at the end of the file)
  388. fgetc(pFile);
  389. fgetc(pFile);
  390. fgetc(pFile);
  391. 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;
  392. }
  393. fclose(pFile);
  394. // keycode -> unicode character to draw on keyboard
  395. pFile = fopen(SRCPATH "symbolmap.txt", "rb");
  396. if (pFile==NULL) {PromptOK("Can't read symbolmap.txt"); exit(1);}
  397. fgetc(pFile); // skip BOM
  398. fgetc(pFile);
  399. memset(symbolMap[0],0,7);
  400. for(i=1;i<=255;i++){ // assuming that no key has keycode 0. Otherwise the linenumber in symbolmap.txt does not match the keycode
  401. fread(symbolMap[i],sizeof(wchar),7,pFile); // read from file
  402. fgetc(pFile); // skip line break (make sure to have a line break at the end of the file)
  403. fgetc(pFile);
  404. fgetc(pFile);
  405. fgetc(pFile);
  406. 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;
  407. }
  408. fclose(pFile);
  409. // latin character -> cyrillic character
  410. pFile = fopen(SRCPATH "rumap.txt", "rb");
  411. if (pFile==NULL) {PromptOK("Can't read rumap.txt"); exit(1);}
  412. fgetc(pFile); // skip BOM
  413. fgetc(pFile);
  414. rumap[0][0]=0;
  415. rumap[0][1]=0;
  416. int idead=0;
  417. for(i=1;i<=255;i++){
  418. FGETUC(&unibuffer,pFile);
  419. if(unibuffer==13){ // line break, no mapping
  420. rumap[i][0]=i;
  421. rumap[i][1]=i;
  422. FGETUC(&unibuffer,pFile); // skip second line break character
  423. }
  424. else{
  425. if(unibuffer==0x2020){ // dagger, symbol for the dead character
  426. rumap[i][0]=0;
  427. rumap[i][1]=0;
  428. ruDeadChar[idead]=i;
  429. idead++;
  430. FGETUC(&unibuffer,pFile); // skip line break characters
  431. FGETUC(&unibuffer,pFile);
  432. }
  433. else{
  434. rumap[i][0]=unibuffer;
  435. rumap[i][1]=unibuffer;
  436. FGETUC(&unibuffer,pFile);
  437. if(unibuffer==13){ // line break, no special character if dead key is toggled
  438. FGETUC(&unibuffer,pFile); // skip second line break character
  439. }
  440. else{ // special character if cyrillic dead key is toggled
  441. rumap[i][1]=unibuffer;
  442. FGETUC(&unibuffer,pFile); // skip line break characters
  443. FGETUC(&unibuffer,pFile);
  444. }
  445. }
  446. }
  447. LOGG("russianRemap ");LOGG(i);LOGG("->");LOGG(rumap[i][0]);LOGG("/");LOGG(rumap[i][1]);LOGGNL;
  448. }
  449. fclose(pFile);
  450. // keycode -> keyname
  451. pFile = fopen(SRCPATH "keynames.txt", "rb");
  452. if (pFile==NULL) {PromptOK("Can't read keynames.txt"); exit(1);}
  453. fgetc(pFile); // skip BOM
  454. fgetc(pFile);
  455. keyNames[0]="";
  456. for(i=1;i<=255;i++){
  457. keyNames[i]="";
  458. FGETUC(&unibuffer,pFile);
  459. while(unibuffer!=13){ // line break
  460. keyNames[i]=keyNames[i]+unibuffer;
  461. FGETUC(&unibuffer,pFile);
  462. }
  463. FGETUC(&unibuffer,pFile); // skip second line break character
  464. }
  465. fclose(pFile);
  466. // lowercase -> uppercase
  467. pFile = fopen(SRCPATH "uppercase.txt", "rb");
  468. if (pFile==NULL) {PromptOK("Can't read uppercase.txt"); exit(1);}
  469. fgetc(pFile); // skip BOM
  470. fgetc(pFile);
  471. i=0;
  472. while(!feof(pFile) && i<1023){
  473. FGETUC(&(upperCaseMap[i][0]),pFile);
  474. FGETUC(&(upperCaseMap[i][1]),pFile);
  475. i++;
  476. }
  477. fclose(pFile);
  478. while(i<1023){
  479. upperCaseMap[i][0]=0xFFFF;
  480. upperCaseMap[i][1]=0xFFFF;
  481. i++;
  482. }
  483. // keycode -> mouseevent
  484. pFile = fopen(SRCPATH "mousemap.txt", "rb");
  485. if (pFile==NULL) {PromptOK("Can't read mousemap.txt"); exit(1);}
  486. fread(mouseController::mouseKeys,sizeof(byte),9,pFile);
  487. fclose(pFile);
  488. }
  489. void KeyBuddy2::SendUNIKey(wchar key, bool release, ULONG_PTR extraInfo){
  490. // use unicodes Personal Usage Area (E000-F8FF) specially
  491. if(key/256>=0xE0 && key/256<=0xF8){ // send keystroke instead of unicode
  492. byte flags=key/256;
  493. bool onlyDown=flags<=0xE7;
  494. bool onlyUp=flags>=0xE8 && flags<=0xEF;
  495. bool swtch=(flags==0xF8);
  496. bool shift=(flags & 1)!=0;
  497. bool ctrl=(flags & 2)!=0;
  498. bool alt=(flags & 4)!=0;
  499. // E0-E7: only down event gets sent
  500. // E8-EF: only up event gets sent (but if key is pushed down)
  501. // F0-F7: down and up according to release parameter
  502. // F8: switch
  503. // unicode AND 0x0100 = shift also pressed
  504. // unicode AND 0x0200 = ctrl also pressed
  505. // unicode AND 0x0400 = alt also pressed
  506. if(swtch && !release){
  507. if(key % 256==0){ // end program
  508. KeyBuddy2::pKB2->Break();
  509. }
  510. if(key % 256==7){ // show / hide GUI
  511. KeyBuddy2::pKB2->Show(!KeyBuddy2::pKB2->IsShown());
  512. return;
  513. }
  514. *(KeyBuddy2::pSwitch[key % 256])=!*(KeyBuddy2::pSwitch[key % 256]);
  515. return;
  516. }
  517. if((onlyDown || onlyUp) && release){return;}
  518. // first release all other keys
  519. byte keyboardStateBuffer[256];
  520. byte allUp[256];
  521. DWORD unused;
  522. memset(keyboardStateBuffer,0,256);
  523. memset(allUp,0,256);
  524. long myThread=GetWindowThreadProcessId(KeyBuddy2::pKB2->GetHWND(),&unused);
  525. long otherThread=GetWindowThreadProcessId(GetForegroundWindow(),&unused);
  526. if(myThread!=otherThread){
  527. AttachThreadInput(otherThread,myThread,true);
  528. }
  529. GetKeyboardState(keyboardStateBuffer);
  530. SetKeyboardState(allUp);
  531. // then send the key
  532. INPUT in[4];
  533. int iIn=0;
  534. for(iIn=0;iIn<4;iIn++){
  535. in[iIn].type=INPUT_KEYBOARD;
  536. in[iIn].ki.dwExtraInfo=extraInfo;
  537. in[iIn].ki.time=0;
  538. in[iIn].ki.wScan=0;
  539. in[iIn].ki.dwFlags=0;
  540. if(release){in[iIn].ki.dwFlags=KEYEVENTF_KEYUP;}
  541. }
  542. iIn=0;
  543. if(release){ // if we release the buttons, release the key of interest first, then ctrl, alt or shift
  544. in[iIn].ki.wVk=key % 256;
  545. iIn++;
  546. }
  547. if(ctrl){
  548. in[iIn].ki.wVk=VK_LCONTROL;
  549. iIn++;
  550. }
  551. if(shift){
  552. in[iIn].ki.wVk=VK_LSHIFT;
  553. iIn++;
  554. }
  555. if(alt){
  556. in[iIn].ki.wVk=VK_LMENU;
  557. iIn++;
  558. }
  559. if(!release){ // if we push the buttons, push ctrl alt shift first, then the key of interest
  560. in[iIn].ki.wVk=key % 256;
  561. iIn++;
  562. }
  563. SendInput(iIn,in,sizeof(INPUT));
  564. Sleep(1); // otherwise the other thread does not see the changed keyboard state
  565. // revert keyboard to its original state
  566. SetKeyboardState(keyboardStateBuffer);
  567. if(myThread!=otherThread){
  568. AttachThreadInput(otherThread,myThread,false);
  569. }
  570. }
  571. else{ // only send unicode character
  572. INPUT in[1];
  573. in[0].type=INPUT_KEYBOARD;
  574. in[0].ki.dwExtraInfo=extraInfo;
  575. in[0].ki.wVk=0;
  576. in[0].ki.wScan=key;
  577. in[0].ki.dwFlags=KEYEVENTF_UNICODE;
  578. if(release){in[0].ki.dwFlags=in[0].ki.dwFlags | KEYEVENTF_KEYUP;}
  579. SendInput(1,in,sizeof(INPUT));
  580. }
  581. }
  582. void KeyBuddy2::releaseAllKeys(){
  583. BYTE zeros[256]={0};
  584. SetKeyboardState(zeros);
  585. for(int i=0;i<256;i++){
  586. keyPressed[i]=false;
  587. }
  588. }
  589. void KeyBuddy2::initKeyButtons(){
  590. int i,j;
  591. for(i=0; i<7; i++){
  592. buttonStyle[i] = Button::StyleNormal();
  593. for(j=0;j<4;j++){
  594. buttonStyle[i].look[j] = KB2Images::Get(i);
  595. }
  596. buttonStyle[i].look[2] = KB2Images::Get(1);
  597. buttonStyle[i].pressoffset = Point(0,0);
  598. }
  599. for(i=0;i<256;i++){
  600. pKeyButton[i]=&but_invis;
  601. keyFinger[i]=0;
  602. }
  603. but_invis.Hide();
  604. #include "keybuttons.inc"
  605. int bfid=buttonFont.FindFaceNameIndex("unifont");
  606. buttonFont.Face(bfid);
  607. buttonFontU.Face(bfid);
  608. buttonFontU.Underline();
  609. smallButtonFont.Face(bfid);
  610. buttonFont.Height(32);
  611. buttonFontU.Height(32);
  612. smallButtonFont.Height(16);
  613. for(i=0;i<256;i++){
  614. pKeyButton[i]->SetStyle(buttonStyle[keyFinger[i]]);
  615. if(i==VK_MOD_31 || i==VK_MOD_32 || i==VK_MOD_41 || i==VK_MOD_42
  616. || i==VK_LMENU || i==VK_LCONTROL || i==VK_RCONTROL){
  617. pKeyButton[i]->SetFont(smallButtonFont);
  618. }
  619. else{
  620. if(i==VK_A || i==VK_S || i==VK_D || i==VK_F
  621. || i==VK_J || i==VK_K || i==VK_L || i==VK_OE){
  622. pKeyButton[i]->SetFont(buttonFontU);
  623. }
  624. else{
  625. pKeyButton[i]->SetFont(buttonFont);
  626. }
  627. }
  628. pKeyButton[i]->SetLabel(ToUtf8(buttonLabel(i)));
  629. //pKeyButton[i]->Disable();
  630. }
  631. }
  632. void KeyBuddy2::drawKeyButtons(){
  633. int i;
  634. String newLabel,oldLabel;
  635. for(i=0;i<256;i++){
  636. newLabel=ToUtf8(buttonLabel(i));
  637. oldLabel=pKeyButton[i]->GetLabel();
  638. if(!newLabel.IsEqual(oldLabel)){
  639. if(!pKeyButton[i]->isPushed()){
  640. pKeyButton[i]->SetLabel(newLabel);
  641. }
  642. else{
  643. pKeyButton[i]->simUp();
  644. pKeyButton[i]->SetLabel(newLabel);
  645. pKeyButton[i]->simDown();
  646. }
  647. }
  648. }
  649. }
  650. wchar KeyBuddy2::upperCase(wchar letter){
  651. int a=0,b=1022,c;
  652. while(a<=b){
  653. c=(a+b)/2;
  654. if( letter< upperCaseMap[c][0] ){b=c-1; continue;}
  655. if( letter> upperCaseMap[c][0] ){a=c+1; continue;}
  656. if( letter==upperCaseMap[c][0] ){return upperCaseMap[c][1];}
  657. }
  658. return letter;
  659. }
  660. GUI_APP_MAIN
  661. {
  662. KeyBuddy2().Run();
  663. }