keyboard.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570
  1. #include <precomp.h>
  2. #include "keyboard.h"
  3. #include <api/locales/localesmgr.h>
  4. //#include <api/wac/main.h> // CUT !!!
  5. #include <api/script/objects/systemobj.h>
  6. #include <api/wnd/wndtrack.h>
  7. #ifdef WASABI_COMPILE_SCRIPT
  8. #include <api/script/vcpu.h>
  9. #endif
  10. #if !defined(WIN32) && !defined(LINUX)
  11. #error port me
  12. #endif
  13. Keyboard::vkEntry Keyboard::vkEntries[]={
  14. #ifdef WIN32
  15. //1, "lbutton", // fg> we don't want mouse messages in keyboard events, no.
  16. //2, "rbutton",
  17. 3, L"cancel",
  18. //4, L"mbutton",
  19. 8, L"backspace",
  20. 9, L"tab",
  21. 0xc, L"clear",
  22. 0xd, L"return",
  23. 0x10, L"shift",
  24. 0x11, L"ctrl",
  25. 0x12, L"alt",
  26. 0x13, L"pause",
  27. 0x14, L"capslock",
  28. 0x1b, L"esc",
  29. 0x20, L"space",
  30. 0x21, L"pgup",
  31. 0x22, L"pgdn",
  32. 0x23, L"end",
  33. 0x24, L"home",
  34. 0x25, L"left",
  35. 0x26, L"up",
  36. 0x27, L"right",
  37. 0x28, L"down",
  38. 0x29, L"select",
  39. 0x2b, L"execute",
  40. 0x2c, L"prtscr",
  41. 0x2d, L"insert",
  42. 0x2e, L"del",
  43. 0x2f, L"help",
  44. 0x5b, L"lwin",
  45. 0x5c, L"rwin",
  46. 0x5d, L"mwin",
  47. 0x60, L"n0",
  48. 0x61, L"n1",
  49. 0x62, L"n2",
  50. 0x63, L"n3",
  51. 0x64, L"n4",
  52. 0x65, L"n5",
  53. 0x66, L"n6",
  54. 0x67, L"n7",
  55. 0x68, L"n8",
  56. 0x69, L"n9",
  57. 0x6a, L"numpad_multiply",
  58. 0x6b, L"numpad_add",
  59. 0x6c, L"separator",
  60. 0x6d, L"numpad_substract",
  61. 0x6e, L"numpad_point",
  62. 0x6f, L"numpad_divide",
  63. 0x70, L"f1",
  64. 0x71, L"f2",
  65. 0x72, L"f3",
  66. 0x73, L"f4",
  67. 0x74, L"f5",
  68. 0x75, L"f6",
  69. 0x76, L"f7",
  70. 0x77, L"f8",
  71. 0x78, L"f9",
  72. 0x79, L"f10",
  73. 0x7a, L"f11",
  74. 0x7b, L"f12",
  75. 0x90, L"numlock",
  76. 0x91, L"scroll",
  77. 0xbb, L"equal",
  78. 0xbd, L"minus",
  79. 0xbf, L"slash",
  80. // 0xdb, L"minus", // seems to be the french code? --BU
  81. 0xf6, L"attn",
  82. 0xfe, L"clear",
  83. #endif
  84. #ifdef LINUX
  85. {XK_space, L"space"},
  86. {XK_Cancel, L"cancel"},
  87. {XK_BackSpace, L"backspace"},
  88. {XK_Tab, L"tab"},
  89. {XK_Clear, L"clear"},
  90. {XK_Return, L"return"},
  91. {XK_Shift_L, L"shift"},
  92. {XK_Shift_R, L"shift"},
  93. {XK_Control_L, L"ctrl"},
  94. {XK_Control_R, L"ctrl"},
  95. {XK_Alt_L, L"alt"},
  96. {XK_Alt_R, L"alt"},
  97. {XK_Pause, L"pause"},
  98. {XK_Caps_Lock, L"capslock"},
  99. {XK_Escape, L"esc"},
  100. {XK_Page_Up, L"pgup"},
  101. {XK_KP_Page_Up, L"pgup"},
  102. {XK_Page_Down, L"pgdn"},
  103. {XK_KP_Page_Down, L"pgdn"},
  104. {XK_End, L"end"},
  105. {XK_KP_End, L"end"},
  106. {XK_Home, L"home"},
  107. {XK_KP_Home, L"home"},
  108. {XK_Left, L"left"},
  109. {XK_KP_Left, L"left"},
  110. {XK_Up, L"up"},
  111. {XK_KP_Up, L"up"},
  112. {XK_Right, L"right"},
  113. {XK_KP_Right, L"right"},
  114. {XK_Down, L"down"},
  115. {XK_KP_Down, L"down"},
  116. {XK_Select, L"select"},
  117. {XK_Execute, L"execute"},
  118. {XK_Print, L"prtscr"},
  119. {XK_Insert, L"insert"},
  120. {XK_KP_Insert, L"insert"},
  121. {XK_Delete, L"del"},
  122. {XK_KP_Delete, L"del"},
  123. {XK_Help, L"help"},
  124. {XK_KP_0, L"n0"},
  125. {XK_KP_1, L"n1"},
  126. {XK_KP_2, L"n2"},
  127. {XK_KP_3, L"n3"},
  128. {XK_KP_4, L"n4"},
  129. {XK_KP_5, L"n5"},
  130. {XK_KP_6, L"n6"},
  131. {XK_KP_7, L"n7"},
  132. {XK_KP_8, L"n8"},
  133. {XK_KP_9, L"n9"},
  134. {XK_KP_Multiply, L"numpad_multiply"},
  135. {XK_KP_Add, L"numpad_add"},
  136. {XK_KP_Separator, L"separator"},
  137. {XK_KP_Subtract, L"numpad_substract"},
  138. {XK_KP_Decimal, L"numpad_point"},
  139. {XK_KP_Divide, L"numpad_divide"},
  140. {XK_F1, L"f1"},
  141. {XK_F2, L"f2"},
  142. {XK_F3, L"f3"},
  143. {XK_F4, L"f4"},
  144. {XK_F5, L"f5"},
  145. {XK_F6, L"f6"},
  146. {XK_F7, L"f7"},
  147. {XK_F8, L"f8"},
  148. {XK_F9, L"f9"},
  149. {XK_F10, L"f10"},
  150. {XK_F11, L"f11"},
  151. {XK_F12, L"f12"},
  152. {XK_Scroll_Lock, L"scroll"},
  153. #ifdef XK_3270
  154. {XK_3270_Attn, L"attn"}, // I don't know what this is...
  155. #endif
  156. {XK_Clear, L"clear"},
  157. #endif
  158. };
  159. //PORTME
  160. wchar_t *Keyboard::getVkName(int vkey)
  161. {
  162. if(vkey>=0x41 && vkey<=0x5A) { // letters
  163. static wchar_t key[2];
  164. key[0]=vkey+0x20;
  165. key[1]=0;
  166. return key;
  167. }
  168. if(vkey>=0x30 && vkey<=0x39) { // numbers
  169. static wchar_t key[2];
  170. key[0]=vkey;
  171. key[1]=0;
  172. return key;
  173. }
  174. for(int i=0;i<(sizeof(vkEntries)/sizeof(vkEntry));i++) {
  175. if(vkEntries[i].vk==vkey) return vkEntries[i].trans;
  176. }
  177. #ifdef _DEBUG
  178. //DebugString("undefined vk key pressed! (0x%x) :(\n",vkey);
  179. #endif
  180. return NULL;
  181. }
  182. int Keyboard::forwardKbdMessage(ifc_window *from, int msg, int wp, int lp)
  183. {
  184. OSWINDOWHANDLE wnd_to = WASABI_API_WND->main_getRootWnd()->gethWnd();
  185. // note to self:
  186. // this is necessary for winamp2's TranslateAccelerator call to work, it seems that this function will
  187. // use the mouse capture wnd to determine the keyboard focus, oh thank you microsoft, because of you
  188. // a script has to use "complete;" to be able to detect shift+ctrl+alt + click on a toggle button,
  189. // otherwise pressing a key will throw the capture away, and the button will think the mouse is gone.
  190. // this means that we can't be stealth doing that, we have to prevent anybody else getting shift+ctrl+alt
  191. // isn't that nice ?
  192. // we still avoid doing that if a mouse button is down, this will allow key+drags with capture
  193. #ifdef WIN32
  194. if (!(GetAsyncKeyState(VK_LBUTTON)&(1 << 31)) && !(GetAsyncKeyState(VK_RBUTTON)&(1 << 31)) && !(GetAsyncKeyState(VK_MBUTTON)&(1 << 31))) {
  195. SetCapture(NULL);
  196. }
  197. #endif
  198. #ifdef GET_KBDFORWARD_WND
  199. ifc_window *dp = from->getDesktopParent();
  200. if (dp) {
  201. Layout *l = static_cast<Layout *>(dp->getInterface(layoutGuid));
  202. if (l) {
  203. Container *c = l->getParentContainer();
  204. if (c) {
  205. GUID g = c->getDefaultContent();
  206. GET_KBDFORWARD_WND(g, wnd_to);
  207. }
  208. }
  209. }
  210. #endif
  211. if (infw) return 0;
  212. // if (from && from->gethWnd() == wnd_to) return 1;
  213. infw = 1;
  214. /* MSG winmsg;
  215. winmsg.message = msg;
  216. winmsg.hwnd = from->gethWnd();
  217. winmsg.wParam = wp;
  218. winmsg.lParam = lp;*/
  219. int r = 0;
  220. // int r = WASABI_API_APP->app_translateAccelerators(&winmsg);
  221. infw = 0;
  222. return r;
  223. }
  224. int Keyboard::onForwardOnChar(ifc_window *from, unsigned int c, int kd)
  225. {
  226. if (WASABI_API_WND->isKeyboardLocked()) return 1;
  227. return forwardKbdMessage(from, WM_CHAR, (WPARAM)c, (LPARAM)kd);
  228. }
  229. int MEMCMPC(void *m, char c, int size) {
  230. char *p = (char*)m;
  231. for (int i=0;i<size;i++) {
  232. if (*p != c) return 1;
  233. }
  234. return 0;
  235. }
  236. int Keyboard::onForwardOnKeyDown(ifc_window *from, int k, int kd, int nomsg)
  237. {
  238. if (WASABI_API_WND->isKeyboardLocked()) return 1;
  239. if (infw) return 0;
  240. if (k >= MAX_KEY) return 0;
  241. lastwasreset = 0;
  242. pressedKeys[k]=1;
  243. syncKeyTable();
  244. wchar_t s[64]={0,};
  245. int first=1;
  246. #ifdef LINUX
  247. for (int i=MAX_KEY-1; i >= 0; i--) {
  248. #else
  249. for (int i=0;i<MAX_KEY;i++) {
  250. #endif
  251. if (pressedKeys[i]) {
  252. wchar_t *n = getVkName(i);
  253. if (n) {
  254. if (!first) wcscat(s, L"+");
  255. else first=0;
  256. wcscat(s,n);
  257. }
  258. }
  259. }
  260. ifc_window *wnd = from;
  261. if(s[0]) {
  262. #ifdef _DEBUG
  263. DebugString("keyboard: key pressed: %s\n",s);
  264. #endif
  265. #ifdef WASABI_COMPILE_LOCALES
  266. const wchar_t *action;
  267. #endif
  268. int found=0;
  269. while(wnd!=NULL) {
  270. for(int i=0;i<accSecEntries.getNumItems();i++) {
  271. AccSec *ase = accSecEntries[i];
  272. if(ase->global || ase->wnd==wnd) {
  273. #ifdef WASABI_COMPILE_LOCALES
  274. if (action=LocalesManager::translateAccelerator(ase->name, s))
  275. {
  276. if(ase->wnd==wnd) found = 1;
  277. wnd->onAcceleratorEvent(action);
  278. #ifdef _DEBUG
  279. DebugString("keyboard: accelerator found\n");
  280. #endif
  281. continue;
  282. }
  283. #else
  284. wnd->onAcceleratorEvent(s);
  285. #endif
  286. }
  287. }
  288. wnd=wnd->getParent();
  289. }
  290. if (found) return 1;
  291. if (NULL != from)
  292. {
  293. const wchar_t *accelSec = from->getId();
  294. if (accelSec && *accelSec)
  295. {
  296. #ifdef WASABI_COMPILE_LOCALES
  297. if(action=LocalesManager::translateAccelerator(accelSec, s))
  298. {
  299. int r = 0;
  300. #ifdef WASABI_COMPILE_SCRIPT
  301. r = SystemObject::onAccelerator(action, accelSec, s);
  302. #endif
  303. #ifdef WASABI_COMPILE_ACTIONS
  304. if (r == 0)
  305. {
  306. int act=SkinParser::getAction(action);
  307. if(act) Main::doAction(act);
  308. }
  309. #endif
  310. #ifdef _DEBUG
  311. DebugString("keyboard: accelerator found\n");
  312. #endif
  313. return 1;
  314. }
  315. #endif
  316. }
  317. }
  318. #ifdef WASABI_COMPILE_LOCALES
  319. if(action=LocalesManager::translateAccelerator(L"general", s))
  320. {
  321. int r = 0;
  322. #ifdef WASABI_COMPILE_SCRIPT
  323. r = SystemObject::onAccelerator(action, L"general", s);
  324. #endif
  325. #ifdef WASABI_COMPILE_ACTIONS
  326. if (r == 0) {
  327. int act=SkinParser::getAction(action);
  328. if(act) Main::doAction(act);
  329. }
  330. #endif
  331. #ifdef _DEBUG
  332. DebugString("keyboard: accelerator found\n");
  333. #endif
  334. return 1;
  335. }
  336. #endif
  337. #ifdef _DEBUG
  338. DebugString("keyboard: accelerator not found\n");
  339. #endif
  340. #ifdef WASABI_COMPILE_SCRIPT
  341. DebugStringW(L"keyboard: sending \"%s\" to script\n", s);
  342. SystemObject::onKeyDown(s);
  343. if (VCPU::getComplete()) {
  344. DebugStringW(L"keyboard: %s trapped by script\n", s);
  345. return 1;
  346. }
  347. #endif
  348. if (pressedKeys[VK_CONTROL] && pressedKeys[VK_TAB])
  349. {
  350. int next = pressedKeys[VK_SHIFT] ? -1 : 1;
  351. HWND w = GetForegroundWindow();
  352. if (w == NULL) {
  353. WASABI_API_WND->main_getRootWnd()->setFocus();
  354. return 1;
  355. }
  356. ifc_window *cur = windowTracker->rootWndFromHwnd(w); // TODO: API_WNDMGR->
  357. if (cur != NULL) {
  358. ifc_window *nextwnd = windowTracker->getNextDesktopWindow(cur, next);
  359. if (nextwnd) nextwnd->setFocus();
  360. return 1;
  361. }
  362. WASABI_API_WND->main_getRootWnd()->setFocus();
  363. return 1;
  364. }
  365. if (from && pressedKeys[VK_CONTROL] && pressedKeys[VK_F4]) {
  366. ifc_window *dp = from->getDesktopParent();
  367. if (dp) {
  368. Layout *l = static_cast<Layout *>(dp->getInterface(layoutGuid));
  369. if (l) {
  370. Container *c = l->getParentContainer();
  371. if (c) {
  372. if (c->isMainContainer())
  373. c->setVisible(!c->isVisible());
  374. else
  375. c->close();
  376. return 1;
  377. }
  378. }
  379. }
  380. }
  381. if (pressedKeys[0x5D]) {
  382. #if defined(WA3COMPATIBILITY)
  383. Main::appContextMenu(from, TRUE, 0);
  384. #elif defined(WASABI_CUSTOM_CONTEXTMENUS)
  385. extern void appContextMenu(ifc_window *wnd);
  386. appContextMenu(windowTracker->rootWndFromHwnd(GetForegroundWindow()));
  387. #endif
  388. }
  389. if (s[0] && from) return forwardKbdMessage(from, WM_KEYDOWN, (WPARAM)k, (LPARAM)kd);
  390. }
  391. return 0;
  392. }
  393. void Keyboard::syncKeyTable() {
  394. for (int i=0;i<MAX_KEY;i++) {
  395. //if (pressedKeys[i] && !(GetAsyncKeyState(i) & (1 << 31))) pressedKeys[i] = 0;
  396. if (pressedKeys[i] && !Std::keyDown(i)) pressedKeys[i] = 0;
  397. }
  398. }
  399. int Keyboard::onForwardOnKeyUp(ifc_window *from, int k, int kd) {
  400. if (WASABI_API_WND->isKeyboardLocked()) return 1;
  401. if (infw) return 0;
  402. if (k >= MAX_KEY) return 0;
  403. /*int hadkey = */MEMCMPC(pressedKeys, 0, sizeof(pressedKeys));
  404. pressedKeys[k]=0;
  405. syncKeyTable();
  406. wchar_t s[64]={0,};
  407. int first=1;
  408. #ifdef LINUX
  409. for (int i=MAX_KEY-1; i >= 0; i--) {
  410. #else
  411. for (int i=0;i<MAX_KEY;i++) {
  412. #endif
  413. if (pressedKeys[i]) {
  414. wchar_t *n = getVkName(i);
  415. if (n) {
  416. if (!first) wcscat(s, L"+");
  417. else first=0;
  418. wcscat(s,n);
  419. }
  420. }
  421. }
  422. if (!*s) {
  423. if (!lastwasreset)
  424. {
  425. lastwasreset = 1;
  426. #ifdef WASABI_COMPILE_SCRIPT
  427. DebugStringW(L"keyboard: sending \"%s\" to script\n", s);
  428. SystemObject::onKeyDown(s);
  429. if (VCPU::getComplete()) {
  430. DebugStringW(L"keyboard: %s trapped by script\n", s);
  431. return 1;
  432. }
  433. #endif
  434. }
  435. }
  436. return forwardKbdMessage(from, WM_KEYUP, (WPARAM)k, (LPARAM)kd);
  437. }
  438. int Keyboard::onForwardOnSysKeyDown(ifc_window *from, int k, int kd) {
  439. if (WASABI_API_WND->isKeyboardLocked()) return 1;
  440. if (infw) return 0;
  441. if(kd&(1<<29)) pressedKeys[0x12]=1;
  442. int r = onForwardOnKeyDown(from, k, 1);
  443. if (r == 0) {
  444. if (from && forwardKbdMessage(from, WM_SYSKEYDOWN, (WPARAM)k, (LPARAM)kd)) return 1;
  445. }
  446. return r;
  447. }
  448. int Keyboard::onForwardOnSysKeyUp(ifc_window *from, int k, int kd)
  449. {
  450. if (WASABI_API_WND->isKeyboardLocked()) return 1;
  451. if (infw) return 0;
  452. if(kd&(1<<29)) pressedKeys[0x12]=0;
  453. pressedKeys[k]=0;
  454. int r = onForwardOnKeyUp(from, k, 1);
  455. if (r == 0) {
  456. if (forwardKbdMessage(from, WM_SYSKEYUP, (WPARAM)k, (WPARAM)kd)) return 1;
  457. }
  458. return r;
  459. }
  460. int Keyboard::onForwardOnKillFocus() {
  461. // FG> I don't think this is necessary anymore because onkeydown always resyncs the pressedKeys table
  462. // and supressing this allows scripts to trap ctrl/alt/shit + clicks (otherwise the click would reset
  463. // the modifiers by way of an automatic focus)
  464. //MEMSET(pressedKeys,0,sizeof(pressedKeys));
  465. return 0;
  466. }
  467. void Keyboard::registerAcceleratorSection(const wchar_t *name, ifc_window *wnd, int global)
  468. {
  469. accSecEntries.addItem(new AccSec(name,wnd,global));
  470. viewer.viewItem(wnd);
  471. }
  472. int Keyboard::interceptOnChar(unsigned int c) {
  473. if (hookers.getNumItems() > 0) {
  474. return hookers.getLast()->onChar(c);
  475. }
  476. return 0;
  477. }
  478. int Keyboard::interceptOnKeyDown(int k){
  479. if (hookers.getNumItems() > 0) {
  480. return hookers.getLast()->onKeyDown(k);
  481. }
  482. return 0;
  483. }
  484. int Keyboard::interceptOnKeyUp(int k){
  485. if (hookers.getNumItems() > 0) {
  486. return hookers.getLast()->onKeyUp(k);
  487. }
  488. return 0;
  489. }
  490. int Keyboard::interceptOnSysKeyDown(int k, int kd){
  491. if (hookers.getNumItems() > 0) {
  492. return hookers.getLast()->onSysKeyDown(k, kd);
  493. }
  494. return 0;
  495. }
  496. int Keyboard::interceptOnSysKeyUp(int k, int kd){
  497. if (hookers.getNumItems() > 0) {
  498. return hookers.getLast()->onSysKeyUp(k, kd);
  499. }
  500. return 0;
  501. }
  502. void Keyboard::hookKeyboard(ifc_window *hooker) {
  503. hookers.addItem(hooker);
  504. DebugString("hookKeyboard = %d\n", hookers.getNumItems());
  505. }
  506. void Keyboard::unhookKeyboard(ifc_window *hooker) {
  507. hookers.removeItem(hooker);
  508. DebugString("unhookKeyboard = %d\n", hookers.getNumItems());
  509. }
  510. void Keyboard::reset() {
  511. if (lastwasreset) return;
  512. DebugString("keyboard reset\n");
  513. MEMZERO(pressedKeys, sizeof(pressedKeys));
  514. if (!lastwasreset) {
  515. lastwasreset = 1;
  516. #ifdef WASABI_COMPILE_SCRIPT
  517. DebugString("keyboard: sending \"\" to script\n");
  518. SystemObject::onKeyDown(L"");
  519. #endif
  520. }
  521. }
  522. int AccSecViewer::viewer_onItemDeleted(ifc_window *item) {
  523. for(int i=0;i<Keyboard::accSecEntries.getNumItems();i++)
  524. if(Keyboard::accSecEntries[i]->wnd==item) {
  525. Keyboard::accSecEntries.removeByPos(i);
  526. i--;
  527. }
  528. return 1;
  529. }
  530. wchar_t Keyboard::pressedKeys[MAX_KEY]={0,};
  531. PtrList<AccSec> Keyboard::accSecEntries;
  532. AccSecViewer Keyboard::viewer;
  533. PtrList<ifc_window> Keyboard::hookers;
  534. int Keyboard::infw = 0;
  535. int Keyboard::lastwasreset = 0;