#include "Global.h" #include "WindowsMessaging.h" #include "VKey.h" #include "DeviceEnumerator.h" #include "WndProcEater.h" #include "WindowsKeyboard.h" #include "WindowsMouse.h" #include "Config.h" typedef BOOL (CALLBACK *_RegisterRawInputDevices)(PCRAWINPUTDEVICE pRawInputDevices, UINT uiNumDevices, UINT cbSize); typedef UINT (CALLBACK *_GetRawInputDeviceInfo)(HANDLE hDevice, UINT uiCommand, LPVOID pData, PUINT pcbSize); typedef UINT (CALLBACK *_GetRawInputData)(HRAWINPUT hRawInput, UINT uiCommand, LPVOID pData, PUINT pcbSize, UINT cbSizeHeader); typedef UINT (CALLBACK *_GetRawInputDeviceList)(PRAWINPUTDEVICELIST pRawInputDeviceList, PUINT puiNumDevices, UINT cbSize); _RegisterRawInputDevices pRegisterRawInputDevices = 0; _GetRawInputDeviceInfo pGetRawInputDeviceInfo = 0; _GetRawInputData pGetRawInputData = 0; _GetRawInputDeviceList pGetRawInputDeviceList = 0; ExtraWndProcResult RawInputWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *output); int GetRawKeyboards(HWND hWnd) { RAWINPUTDEVICE Rid; Rid.hwndTarget = hWnd; Rid.dwFlags = 0; Rid.usUsagePage = 0x01; Rid.usUsage = 0x06; return pRegisterRawInputDevices(&Rid, 1, sizeof(Rid)); } void ReleaseRawKeyboards() { RAWINPUTDEVICE Rid; Rid.hwndTarget = 0; Rid.dwFlags = RIDEV_REMOVE; Rid.usUsagePage = 0x01; Rid.usUsage = 0x06; pRegisterRawInputDevices(&Rid, 1, sizeof(Rid)); } int GetRawMice(HWND hWnd) { RAWINPUTDEVICE Rid; Rid.hwndTarget = hWnd; Rid.dwFlags = RIDEV_NOLEGACY | RIDEV_CAPTUREMOUSE; Rid.usUsagePage = 0x01; Rid.usUsage = 0x02; return pRegisterRawInputDevices(&Rid, 1, sizeof(Rid)); } void ReleaseRawMice() { RAWINPUTDEVICE Rid; Rid.hwndTarget = 0; Rid.dwFlags = RIDEV_REMOVE; Rid.usUsagePage = 0x01; Rid.usUsage = 0x02; pRegisterRawInputDevices(&Rid, 1, sizeof(Rid)); } // Count of active raw keyboard devices. // when it gets to 0, release them all. static int rawKeyboardActivatedCount = 0; // Same for mice. static int rawMouseActivatedCount = 0; class RawInputKeyboard : public WindowsKeyboard { public: HANDLE hDevice; RawInputKeyboard(HANDLE hDevice, wchar_t *name, wchar_t *instanceID=0) : WindowsKeyboard(RAW, name, instanceID) { this->hDevice = hDevice; } int Activate(void *d) { InitInfo *info = (InitInfo*)d; Deactivate(); HWND hWnd = info->hWnd; if (info->hWndButton) { hWnd = info->hWndButton; } active = 1; if (!rawKeyboardActivatedCount++) { if (!rawMouseActivatedCount && !EatWndProc(hWnd, RawInputWndProc)) { Deactivate(); return 0; } if (!GetRawKeyboards(hWnd)) { Deactivate(); return 0; } } InitState(); return 1; } void Deactivate() { FreeState(); if (active) { active = 0; rawKeyboardActivatedCount --; if (!rawKeyboardActivatedCount) { ReleaseRawKeyboards(); if (!rawMouseActivatedCount) ReleaseExtraProc(RawInputWndProc); } } } }; static POINT rawOrigCursorPos; static POINT rawCenter; class RawInputMouse : public WindowsMouse { public: HANDLE hDevice; RawInputMouse(HANDLE hDevice, wchar_t *name, wchar_t *instanceID=0, wchar_t *productID=0) : WindowsMouse(RAW, 0, name, instanceID, productID) { this->hDevice = hDevice; } int Activate(void *d) { InitInfo *info = (InitInfo*)d; Deactivate(); HWND hWnd = info->hWnd; if (info->hWndButton) { hWnd = info->hWndButton; } active = 1; // Have to be careful with order. At worst, one unmatched call to ReleaseRawMice on // EatWndProc fail. In all other cases, no unmatched initialization/cleanup // lines. if (!rawMouseActivatedCount++) { GetCursorPos(&rawOrigCursorPos); ShowCursor(0); if (!rawKeyboardActivatedCount && !EatWndProc(hWnd, RawInputWndProc)) { Deactivate(); return 0; } if (!GetRawMice(hWnd)) { Deactivate(); return 0; } RECT r; // No need to clip cursor, since I seem to have complete control of buttons. GetWindowRect(hWnd, &r); rawCenter.x = (r.left + r.right)/2; rawCenter.y = (r.top + r.bottom)/2; SetCursorPos(rawCenter.x, rawCenter.y); } AllocState(); return 1; } void Deactivate() { FreeState(); if (active) { active = 0; rawMouseActivatedCount --; if (!rawMouseActivatedCount) { ShowCursor(1); ReleaseRawMice(); SetCursorPos(rawOrigCursorPos.x, rawOrigCursorPos.y); if (!rawKeyboardActivatedCount) { ReleaseExtraProc(RawInputWndProc); } } } } }; ExtraWndProcResult RawInputWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *output) { if (uMsg == WM_INPUT) { if (GET_RAWINPUT_CODE_WPARAM (wParam) == RIM_INPUT && pGetRawInputData) { RAWINPUT in; unsigned int size = sizeof(RAWINPUT); if (0 < pGetRawInputData((HRAWINPUT)lParam, RID_INPUT, &in, &size, sizeof(RAWINPUTHEADER))) { for (int i=0; inumDevices; i++) { Device *dev = dm->devices[i]; if (dev->api != RAW || !dev->active) continue; if (in.header.dwType == RIM_TYPEKEYBOARD && dev->type == KEYBOARD) { RawInputKeyboard* rik = (RawInputKeyboard*)dev; if (rik->hDevice != in.header.hDevice) continue; u32 uMsg = in.data.keyboard.Message; if (!(in.data.keyboard.VKey>>8)) rik->UpdateKey((u8) in.data.keyboard.VKey, (uMsg == WM_KEYDOWN || uMsg == WM_SYSKEYDOWN)); } else if (in.header.dwType == RIM_TYPEMOUSE && dev->type == MOUSE) { RawInputMouse* rim = (RawInputMouse*)dev; if (rim->hDevice != in.header.hDevice) continue; if (in.data.mouse.usFlags) { // Never been set for me, and specs on what most of them // actually mean is sorely lacking. Also, specs erroneously // indicate MOUSE_MOVE_RELATIVE is a flag, when it's really // 0... continue; } unsigned short buttons = in.data.mouse.usButtonFlags & 0x3FF; int button = 0; while (buttons) { if (buttons & 3) { // 2 is up, 1 is down. Up takes precedence over down. rim->UpdateButton(button, !(buttons & 2)); } button++; buttons >>= 2; } if (in.data.mouse.usButtonFlags & 0x400) { rim->UpdateAxis(2, ((short)in.data.mouse.usButtonData)/WHEEL_DELTA); } if (in.data.mouse.lLastX || in.data.mouse.lLastY) { rim->UpdateAxis(0, in.data.mouse.lLastX); rim->UpdateAxis(1, in.data.mouse.lLastY); SetCursorPos(rawCenter.x, rawCenter.y); } } } } } } else if (uMsg == WM_ACTIVATE) { for (int i=0; inumDevices; i++) { Device *dev = dm->devices[i]; if (dev->api != RAW || dev->physicalControlState == 0) continue; memset(dev->physicalControlState, 0, sizeof(int) * dev->numPhysicalControls); } } return CONTINUE_BLISSFULLY; } int InitializeRawInput() { static int RawInputFailed = 0; if (RawInputFailed) return 0; if (!pGetRawInputDeviceList) { HMODULE user32 = LoadLibrary(L"user32.dll"); if (user32) { if (!(pRegisterRawInputDevices = (_RegisterRawInputDevices) GetProcAddress(user32, "RegisterRawInputDevices")) || !(pGetRawInputDeviceInfo = (_GetRawInputDeviceInfo) GetProcAddress(user32, "GetRawInputDeviceInfoW")) || !(pGetRawInputData = (_GetRawInputData) GetProcAddress(user32, "GetRawInputData")) || !(pGetRawInputDeviceList = (_GetRawInputDeviceList) GetProcAddress(user32, "GetRawInputDeviceList"))) { FreeLibrary(user32); RawInputFailed = 1; return 0; } } } return 1; } void EnumRawInputDevices() { UINT count = 0; if (InitializeRawInput() && pGetRawInputDeviceList(0, &count, sizeof(RAWINPUTDEVICELIST)) != (UINT)-1) { wchar_t *instanceID = (wchar_t *) malloc(41000*sizeof(wchar_t)); wchar_t *keyName = instanceID + 11000; wchar_t *displayName = keyName + 10000; wchar_t *productID = displayName + 10000; int keyboardCount = 1; int mouseCount = 1; if (count) { RAWINPUTDEVICELIST *list = (RAWINPUTDEVICELIST*) malloc(sizeof(RAWINPUTDEVICELIST) * count); if (list && pGetRawInputDeviceList(list, &count, sizeof(RAWINPUTDEVICELIST))) { for (UINT i=0; i= 3) { wcscpy(productID, instanceID); wchar_t *temp = 0; for (int j=0; j<3; j++) { wchar_t *s = wcschr(productID, '#'); if (!s) break; *s = '\\'; if (j==2) { *s = 0; } if (j==1) temp = s; } wsprintfW(keyName, L"SYSTEM\\CurrentControlSet\\Enum%s", productID+3); if (temp) *temp = 0; displayName[0] = 0; HKEY hKey; if (ERROR_SUCCESS == RegOpenKeyExW(HKEY_LOCAL_MACHINE, keyName, 0, KEY_QUERY_VALUE, &hKey)) { DWORD type; DWORD len = 10000 * sizeof(wchar_t); if (ERROR_SUCCESS == RegQueryValueExW(hKey, L"DeviceDesc", 0, &type, (BYTE*)displayName, &len) && len && type == REG_SZ) { wchar_t *temp2 = wcsrchr(displayName, ';'); if (!temp2) temp2 = displayName; else temp2++; // Could do without this, but more effort than it's worth. wcscpy(keyName, temp2); } RegCloseKey(hKey); } if (list[i].dwType == RIM_TYPEKEYBOARD) { if (!displayName[0]) wsprintfW(displayName, L"Raw Keyboard %i", keyboardCount++); else wsprintfW(displayName, L"Raw KB: %s", keyName); dm->AddDevice(new RawInputKeyboard(list[i].hDevice, displayName, instanceID)); } else if (list[i].dwType == RIM_TYPEMOUSE) { if (!displayName[0]) wsprintfW(displayName, L"Raw Mouse %i", mouseCount++); else wsprintfW(displayName, L"Raw MS: %s", keyName); dm->AddDevice(new RawInputMouse(list[i].hDevice, displayName, instanceID, productID)); } } } free(list); } } free(instanceID); dm->AddDevice(new RawInputKeyboard(0, L"Simulated Keyboard")); dm->AddDevice(new RawInputMouse(0, L"Simulated Mouse")); } }