#include #include "keyboard.h" #include //#include // CUT !!! #include #include #ifdef WASABI_COMPILE_SCRIPT #include #endif #if !defined(WIN32) && !defined(LINUX) #error port me #endif Keyboard::vkEntry Keyboard::vkEntries[]={ #ifdef WIN32 //1, "lbutton", // fg> we don't want mouse messages in keyboard events, no. //2, "rbutton", 3, L"cancel", //4, L"mbutton", 8, L"backspace", 9, L"tab", 0xc, L"clear", 0xd, L"return", 0x10, L"shift", 0x11, L"ctrl", 0x12, L"alt", 0x13, L"pause", 0x14, L"capslock", 0x1b, L"esc", 0x20, L"space", 0x21, L"pgup", 0x22, L"pgdn", 0x23, L"end", 0x24, L"home", 0x25, L"left", 0x26, L"up", 0x27, L"right", 0x28, L"down", 0x29, L"select", 0x2b, L"execute", 0x2c, L"prtscr", 0x2d, L"insert", 0x2e, L"del", 0x2f, L"help", 0x5b, L"lwin", 0x5c, L"rwin", 0x5d, L"mwin", 0x60, L"n0", 0x61, L"n1", 0x62, L"n2", 0x63, L"n3", 0x64, L"n4", 0x65, L"n5", 0x66, L"n6", 0x67, L"n7", 0x68, L"n8", 0x69, L"n9", 0x6a, L"numpad_multiply", 0x6b, L"numpad_add", 0x6c, L"separator", 0x6d, L"numpad_substract", 0x6e, L"numpad_point", 0x6f, L"numpad_divide", 0x70, L"f1", 0x71, L"f2", 0x72, L"f3", 0x73, L"f4", 0x74, L"f5", 0x75, L"f6", 0x76, L"f7", 0x77, L"f8", 0x78, L"f9", 0x79, L"f10", 0x7a, L"f11", 0x7b, L"f12", 0x90, L"numlock", 0x91, L"scroll", 0xbb, L"equal", 0xbd, L"minus", 0xbf, L"slash", // 0xdb, L"minus", // seems to be the french code? --BU 0xf6, L"attn", 0xfe, L"clear", #endif #ifdef LINUX {XK_space, L"space"}, {XK_Cancel, L"cancel"}, {XK_BackSpace, L"backspace"}, {XK_Tab, L"tab"}, {XK_Clear, L"clear"}, {XK_Return, L"return"}, {XK_Shift_L, L"shift"}, {XK_Shift_R, L"shift"}, {XK_Control_L, L"ctrl"}, {XK_Control_R, L"ctrl"}, {XK_Alt_L, L"alt"}, {XK_Alt_R, L"alt"}, {XK_Pause, L"pause"}, {XK_Caps_Lock, L"capslock"}, {XK_Escape, L"esc"}, {XK_Page_Up, L"pgup"}, {XK_KP_Page_Up, L"pgup"}, {XK_Page_Down, L"pgdn"}, {XK_KP_Page_Down, L"pgdn"}, {XK_End, L"end"}, {XK_KP_End, L"end"}, {XK_Home, L"home"}, {XK_KP_Home, L"home"}, {XK_Left, L"left"}, {XK_KP_Left, L"left"}, {XK_Up, L"up"}, {XK_KP_Up, L"up"}, {XK_Right, L"right"}, {XK_KP_Right, L"right"}, {XK_Down, L"down"}, {XK_KP_Down, L"down"}, {XK_Select, L"select"}, {XK_Execute, L"execute"}, {XK_Print, L"prtscr"}, {XK_Insert, L"insert"}, {XK_KP_Insert, L"insert"}, {XK_Delete, L"del"}, {XK_KP_Delete, L"del"}, {XK_Help, L"help"}, {XK_KP_0, L"n0"}, {XK_KP_1, L"n1"}, {XK_KP_2, L"n2"}, {XK_KP_3, L"n3"}, {XK_KP_4, L"n4"}, {XK_KP_5, L"n5"}, {XK_KP_6, L"n6"}, {XK_KP_7, L"n7"}, {XK_KP_8, L"n8"}, {XK_KP_9, L"n9"}, {XK_KP_Multiply, L"numpad_multiply"}, {XK_KP_Add, L"numpad_add"}, {XK_KP_Separator, L"separator"}, {XK_KP_Subtract, L"numpad_substract"}, {XK_KP_Decimal, L"numpad_point"}, {XK_KP_Divide, L"numpad_divide"}, {XK_F1, L"f1"}, {XK_F2, L"f2"}, {XK_F3, L"f3"}, {XK_F4, L"f4"}, {XK_F5, L"f5"}, {XK_F6, L"f6"}, {XK_F7, L"f7"}, {XK_F8, L"f8"}, {XK_F9, L"f9"}, {XK_F10, L"f10"}, {XK_F11, L"f11"}, {XK_F12, L"f12"}, {XK_Scroll_Lock, L"scroll"}, #ifdef XK_3270 {XK_3270_Attn, L"attn"}, // I don't know what this is... #endif {XK_Clear, L"clear"}, #endif }; //PORTME wchar_t *Keyboard::getVkName(int vkey) { if(vkey>=0x41 && vkey<=0x5A) { // letters static wchar_t key[2]; key[0]=vkey+0x20; key[1]=0; return key; } if(vkey>=0x30 && vkey<=0x39) { // numbers static wchar_t key[2]; key[0]=vkey; key[1]=0; return key; } for(int i=0;i<(sizeof(vkEntries)/sizeof(vkEntry));i++) { if(vkEntries[i].vk==vkey) return vkEntries[i].trans; } #ifdef _DEBUG //DebugString("undefined vk key pressed! (0x%x) :(\n",vkey); #endif return NULL; } int Keyboard::forwardKbdMessage(ifc_window *from, int msg, int wp, int lp) { OSWINDOWHANDLE wnd_to = WASABI_API_WND->main_getRootWnd()->gethWnd(); // note to self: // this is necessary for winamp2's TranslateAccelerator call to work, it seems that this function will // use the mouse capture wnd to determine the keyboard focus, oh thank you microsoft, because of you // a script has to use "complete;" to be able to detect shift+ctrl+alt + click on a toggle button, // otherwise pressing a key will throw the capture away, and the button will think the mouse is gone. // this means that we can't be stealth doing that, we have to prevent anybody else getting shift+ctrl+alt // isn't that nice ? // we still avoid doing that if a mouse button is down, this will allow key+drags with capture #ifdef WIN32 if (!(GetAsyncKeyState(VK_LBUTTON)&(1 << 31)) && !(GetAsyncKeyState(VK_RBUTTON)&(1 << 31)) && !(GetAsyncKeyState(VK_MBUTTON)&(1 << 31))) { SetCapture(NULL); } #endif #ifdef GET_KBDFORWARD_WND ifc_window *dp = from->getDesktopParent(); if (dp) { Layout *l = static_cast(dp->getInterface(layoutGuid)); if (l) { Container *c = l->getParentContainer(); if (c) { GUID g = c->getDefaultContent(); GET_KBDFORWARD_WND(g, wnd_to); } } } #endif if (infw) return 0; // if (from && from->gethWnd() == wnd_to) return 1; infw = 1; /* MSG winmsg; winmsg.message = msg; winmsg.hwnd = from->gethWnd(); winmsg.wParam = wp; winmsg.lParam = lp;*/ int r = 0; // int r = WASABI_API_APP->app_translateAccelerators(&winmsg); infw = 0; return r; } int Keyboard::onForwardOnChar(ifc_window *from, unsigned int c, int kd) { if (WASABI_API_WND->isKeyboardLocked()) return 1; return forwardKbdMessage(from, WM_CHAR, (WPARAM)c, (LPARAM)kd); } int MEMCMPC(void *m, char c, int size) { char *p = (char*)m; for (int i=0;iisKeyboardLocked()) return 1; if (infw) return 0; if (k >= MAX_KEY) return 0; lastwasreset = 0; pressedKeys[k]=1; syncKeyTable(); wchar_t s[64]={0,}; int first=1; #ifdef LINUX for (int i=MAX_KEY-1; i >= 0; i--) { #else for (int i=0;iglobal || ase->wnd==wnd) { #ifdef WASABI_COMPILE_LOCALES if (action=LocalesManager::translateAccelerator(ase->name, s)) { if(ase->wnd==wnd) found = 1; wnd->onAcceleratorEvent(action); #ifdef _DEBUG DebugString("keyboard: accelerator found\n"); #endif continue; } #else wnd->onAcceleratorEvent(s); #endif } } wnd=wnd->getParent(); } if (found) return 1; if (NULL != from) { const wchar_t *accelSec = from->getId(); if (accelSec && *accelSec) { #ifdef WASABI_COMPILE_LOCALES if(action=LocalesManager::translateAccelerator(accelSec, s)) { int r = 0; #ifdef WASABI_COMPILE_SCRIPT r = SystemObject::onAccelerator(action, accelSec, s); #endif #ifdef WASABI_COMPILE_ACTIONS if (r == 0) { int act=SkinParser::getAction(action); if(act) Main::doAction(act); } #endif #ifdef _DEBUG DebugString("keyboard: accelerator found\n"); #endif return 1; } #endif } } #ifdef WASABI_COMPILE_LOCALES if(action=LocalesManager::translateAccelerator(L"general", s)) { int r = 0; #ifdef WASABI_COMPILE_SCRIPT r = SystemObject::onAccelerator(action, L"general", s); #endif #ifdef WASABI_COMPILE_ACTIONS if (r == 0) { int act=SkinParser::getAction(action); if(act) Main::doAction(act); } #endif #ifdef _DEBUG DebugString("keyboard: accelerator found\n"); #endif return 1; } #endif #ifdef _DEBUG DebugString("keyboard: accelerator not found\n"); #endif #ifdef WASABI_COMPILE_SCRIPT DebugStringW(L"keyboard: sending \"%s\" to script\n", s); SystemObject::onKeyDown(s); if (VCPU::getComplete()) { DebugStringW(L"keyboard: %s trapped by script\n", s); return 1; } #endif if (pressedKeys[VK_CONTROL] && pressedKeys[VK_TAB]) { int next = pressedKeys[VK_SHIFT] ? -1 : 1; HWND w = GetForegroundWindow(); if (w == NULL) { WASABI_API_WND->main_getRootWnd()->setFocus(); return 1; } ifc_window *cur = windowTracker->rootWndFromHwnd(w); // TODO: API_WNDMGR-> if (cur != NULL) { ifc_window *nextwnd = windowTracker->getNextDesktopWindow(cur, next); if (nextwnd) nextwnd->setFocus(); return 1; } WASABI_API_WND->main_getRootWnd()->setFocus(); return 1; } if (from && pressedKeys[VK_CONTROL] && pressedKeys[VK_F4]) { ifc_window *dp = from->getDesktopParent(); if (dp) { Layout *l = static_cast(dp->getInterface(layoutGuid)); if (l) { Container *c = l->getParentContainer(); if (c) { if (c->isMainContainer()) c->setVisible(!c->isVisible()); else c->close(); return 1; } } } } if (pressedKeys[0x5D]) { #if defined(WA3COMPATIBILITY) Main::appContextMenu(from, TRUE, 0); #elif defined(WASABI_CUSTOM_CONTEXTMENUS) extern void appContextMenu(ifc_window *wnd); appContextMenu(windowTracker->rootWndFromHwnd(GetForegroundWindow())); #endif } if (s[0] && from) return forwardKbdMessage(from, WM_KEYDOWN, (WPARAM)k, (LPARAM)kd); } return 0; } void Keyboard::syncKeyTable() { for (int i=0;iisKeyboardLocked()) return 1; if (infw) return 0; if (k >= MAX_KEY) return 0; /*int hadkey = */MEMCMPC(pressedKeys, 0, sizeof(pressedKeys)); pressedKeys[k]=0; syncKeyTable(); wchar_t s[64]={0,}; int first=1; #ifdef LINUX for (int i=MAX_KEY-1; i >= 0; i--) { #else for (int i=0;iisKeyboardLocked()) return 1; if (infw) return 0; if(kd&(1<<29)) pressedKeys[0x12]=1; int r = onForwardOnKeyDown(from, k, 1); if (r == 0) { if (from && forwardKbdMessage(from, WM_SYSKEYDOWN, (WPARAM)k, (LPARAM)kd)) return 1; } return r; } int Keyboard::onForwardOnSysKeyUp(ifc_window *from, int k, int kd) { if (WASABI_API_WND->isKeyboardLocked()) return 1; if (infw) return 0; if(kd&(1<<29)) pressedKeys[0x12]=0; pressedKeys[k]=0; int r = onForwardOnKeyUp(from, k, 1); if (r == 0) { if (forwardKbdMessage(from, WM_SYSKEYUP, (WPARAM)k, (WPARAM)kd)) return 1; } return r; } int Keyboard::onForwardOnKillFocus() { // FG> I don't think this is necessary anymore because onkeydown always resyncs the pressedKeys table // and supressing this allows scripts to trap ctrl/alt/shit + clicks (otherwise the click would reset // the modifiers by way of an automatic focus) //MEMSET(pressedKeys,0,sizeof(pressedKeys)); return 0; } void Keyboard::registerAcceleratorSection(const wchar_t *name, ifc_window *wnd, int global) { accSecEntries.addItem(new AccSec(name,wnd,global)); viewer.viewItem(wnd); } int Keyboard::interceptOnChar(unsigned int c) { if (hookers.getNumItems() > 0) { return hookers.getLast()->onChar(c); } return 0; } int Keyboard::interceptOnKeyDown(int k){ if (hookers.getNumItems() > 0) { return hookers.getLast()->onKeyDown(k); } return 0; } int Keyboard::interceptOnKeyUp(int k){ if (hookers.getNumItems() > 0) { return hookers.getLast()->onKeyUp(k); } return 0; } int Keyboard::interceptOnSysKeyDown(int k, int kd){ if (hookers.getNumItems() > 0) { return hookers.getLast()->onSysKeyDown(k, kd); } return 0; } int Keyboard::interceptOnSysKeyUp(int k, int kd){ if (hookers.getNumItems() > 0) { return hookers.getLast()->onSysKeyUp(k, kd); } return 0; } void Keyboard::hookKeyboard(ifc_window *hooker) { hookers.addItem(hooker); DebugString("hookKeyboard = %d\n", hookers.getNumItems()); } void Keyboard::unhookKeyboard(ifc_window *hooker) { hookers.removeItem(hooker); DebugString("unhookKeyboard = %d\n", hookers.getNumItems()); } void Keyboard::reset() { if (lastwasreset) return; DebugString("keyboard reset\n"); MEMZERO(pressedKeys, sizeof(pressedKeys)); if (!lastwasreset) { lastwasreset = 1; #ifdef WASABI_COMPILE_SCRIPT DebugString("keyboard: sending \"\" to script\n"); SystemObject::onKeyDown(L""); #endif } } int AccSecViewer::viewer_onItemDeleted(ifc_window *item) { for(int i=0;iwnd==item) { Keyboard::accSecEntries.removeByPos(i); i--; } return 1; } wchar_t Keyboard::pressedKeys[MAX_KEY]={0,}; PtrList Keyboard::accSecEntries; AccSecViewer Keyboard::viewer; PtrList Keyboard::hookers; int Keyboard::infw = 0; int Keyboard::lastwasreset = 0;