Skip to content

Instantly share code, notes, and snippets.

@vincasmiliunas
Created March 30, 2011 20:12
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save vincasmiliunas/895204 to your computer and use it in GitHub Desktop.
Save vincasmiliunas/895204 to your computer and use it in GitHub Desktop.
diff --git a/dlls/user32/Makefile.in b/dlls/user32/Makefile.in
index d2cdc92..7fd804e 100644
--- a/dlls/user32/Makefile.in
+++ b/dlls/user32/Makefile.in
@@ -1,7 +1,7 @@
EXTRADEFS = -D_USER32_ -D_WINABLE_
MODULE = user32.dll
IMPORTLIB = user32
-IMPORTS = gdi32 version advapi32
+IMPORTS = gdi32 version advapi32 dinput8 dinput dxguid
DELAYIMPORTS = imm32
C_SRCS = \
diff --git a/dlls/user32/input.c b/dlls/user32/input.c
index 06553a4..a8ed77e 100644
--- a/dlls/user32/input.c
+++ b/dlls/user32/input.c
@@ -22,6 +22,15 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
+/*
+ * Updated by Vincas Miliūnas 2011
+ * Modififed by Reco 2009
+ * patch is based on
+ * http://win2kgaming.site90.com/phpBB2/viewtopic.php?f=6&t=7
+ * OldCigarettes Windows 2000 XP API Wrapper Pack
+ * Released under LGPL
+ */
+
#include "config.h"
#include "wine/port.h"
@@ -48,6 +57,383 @@
#include "wine/server.h"
#include "wine/debug.h"
#include "wine/unicode.h"
+#include "dinput.h"
+
+
+static HANDLE hHeap = NULL;
+
+typedef struct _myNode
+{
+ DWORD data;
+ struct _myNode * next;
+} myNode;
+
+typedef struct
+{
+ myNode * head;
+ myNode * tail;
+ long length;
+ HANDLE lockMutex;
+} myList;
+
+
+__inline void GetLock(myList * l)
+{
+ WaitForSingleObject(l->lockMutex, INFINITE);
+}
+
+__inline void ReleaseLock(myList * l)
+{
+ ReleaseMutex(l->lockMutex);
+}
+
+
+__inline void InitializeList(myList ** l)
+{
+ *l = HeapAlloc(hHeap, 0, sizeof(myList));
+ (*l)->head = NULL;
+ (*l)->tail = NULL;
+ (*l)->length = 0;
+ (*l)->lockMutex = CreateMutexA(NULL, FALSE, NULL);
+}
+
+
+__inline void PushFrontByAddr(myList * l, myNode * nouv)
+{
+ if(!l->head)
+ l->tail = nouv;
+
+ nouv->next = l->head;
+ l->head = nouv;
+ l->length++;
+}
+
+__inline void PushBackByAddr(myList * l, myNode * nouv)
+{
+ if(!l->head)
+ {
+ nouv->next = NULL;
+ l->tail = nouv;
+ l->head = nouv;
+ }
+ else
+ {
+ nouv->next = NULL;
+ l->tail->next = nouv;
+ l->tail = nouv;
+ }
+ l->length++;
+}
+
+__inline void PushFrontByVal(myList * l, DWORD data)
+{
+ myNode * nouv = NULL;
+ nouv = HeapAlloc(hHeap, 0, sizeof(myNode));
+ nouv->next = l->head;
+ nouv->data = data;
+
+ if(!l->head)
+ l->tail = nouv;
+
+ l->head = nouv;
+ l->length++;
+}
+
+__inline void PushBackByVal(myList * l, DWORD data)
+{
+ myNode * nouv = NULL;
+ nouv = HeapAlloc(hHeap, 0, sizeof(myNode));
+ nouv->data = data;
+
+ if(!l->head)
+ {
+ nouv->next = NULL;
+ l->tail = nouv;
+ l->head = nouv;
+ }
+ else
+ {
+ nouv->next = NULL;
+ l->tail->next = nouv;
+ l->tail = nouv;
+ }
+ l->length++;
+}
+
+__inline void RemoveNodeByVal(myList * l, DWORD data)
+{
+ myNode * temp = NULL;
+ myNode * cour = NULL;
+ myNode ** prec = NULL;
+
+ cour = l->head;
+ prec = &l->head;
+
+ while(cour)
+ {
+ if(cour->data == data)
+ {
+ temp = cour->next;
+
+ HeapFree(hHeap, 0, cour);
+
+ *prec = temp;
+ cour = temp;
+ l->length--;
+ }
+ else
+ {
+ prec = &(cour->next);
+ cour = cour->next;
+ }
+ }
+}
+
+__inline void RemoveNodeByAddr(myList * l, myNode * node)
+{
+ myNode * temp = NULL;
+ myNode * cour = NULL;
+ myNode ** prec = NULL;
+
+ cour = l->head;
+ prec = &l->head;
+
+ while(cour)
+ {
+ if(cour == node)
+ {
+ temp = cour->next;
+
+ HeapFree(hHeap, 0, cour);
+
+ *prec = temp;
+ cour = temp;
+ l->length--;
+ }
+ else
+ {
+ prec = &(cour->next);
+ cour = cour->next;
+ }
+ }
+}
+
+
+__inline DWORD PopFrontAndFree(myList * l)
+{
+ myNode * res = NULL;
+ DWORD data = 0;
+
+ if(l->head && l->head == l->tail)
+ {
+ res = l->head;
+ l->head = NULL;
+ l->tail = NULL;
+ l->length = 0;
+ }
+ else if(l->head)
+ {
+ res = l->head;
+ l->head = res->next;
+ l->length--;
+ }
+
+ //win2000 finds bug here!!!!
+
+ if(res) {
+ data = res->data;
+ HeapFree(hHeap, 0, res);
+ }
+
+ return data;
+}
+
+
+__inline void PopBackAndFree(myList * l)
+{
+ myNode *res = NULL, *cour = NULL, *prec = NULL;
+
+ if(l->head && l->head == l->tail)
+ {
+ res = l->head;
+ l->head = NULL;
+ l->tail = NULL;
+ l->length = 0;
+ }
+ else if(l->tail)
+ {
+ cour = l->head;
+ prec = l->head;
+ while(cour->next)
+ {
+ prec = cour;
+ cour = cour->next;
+ }
+
+ res = l->tail;
+ l->tail = prec;
+ l->length--;
+ }
+
+ if(res)
+ HeapFree(hHeap, 0, res);
+}
+
+
+
+__inline myNode * PopFront(myList * l)
+{
+ myNode * res = NULL;
+
+ if(l->head && l->head == l->tail)
+ {
+ res = l->head;
+ l->head = NULL;
+ l->tail = NULL;
+ l->length = 0;
+ }
+ else if(l->head)
+ {
+ res = l->head;
+ l->head = res->next;
+ l->length--;
+ }
+
+ return res;
+}
+
+
+__inline myNode * PopBack(myList * l)
+{
+ myNode *res = NULL, *cour = NULL, *prec = NULL;
+
+ if(l->head && l->head == l->tail)
+ {
+ res = l->head;
+ l->head = NULL;
+ l->tail = NULL;
+ l->length = 0;
+ }
+ else if(l->tail)
+ {
+ cour = l->head;
+ prec = l->head;
+ while(cour->next)
+ {
+ prec = cour;
+ cour = cour->next;
+ }
+
+ res = l->tail;
+ prec->next = NULL;
+ l->tail = prec;
+ l->length--;
+ }
+
+ return res;
+}
+
+
+__inline BOOL IsInListByVal(myList * l, DWORD data)
+{
+ myNode * cour = NULL;
+ BOOL found = FALSE;
+
+ cour = l->head;
+ while(cour && !found)
+ {
+ found = (cour->data == data);
+ cour = cour->next;
+ }
+
+ return found;
+}
+
+
+__inline BOOL IsInListByAddr(myList * l, myNode * node)
+{
+ myNode * cour = NULL;
+ BOOL found = FALSE;
+
+ cour = l->head;
+ while(cour && !found)
+ {
+ found = (cour == node);
+ cour = cour->next;
+ }
+
+ return found;
+}
+
+
+__inline void FreeList(myList ** l)
+{
+ while((*l)->length)
+ PopFrontAndFree(*l);
+
+ CloseHandle((*l)->lockMutex);
+ HeapFree(hHeap, 0, *l);
+ *l = NULL;
+}
+
+/*Mode select*/
+BOOL UseDirectInput = TRUE;
+
+/*List of raw input data for each window*/
+static myList * rawMouseInputWindowList = NULL;
+static myList * rawKeyboardInputWindowList = NULL;
+static myList * rawInputHandleList = NULL;
+
+/*HOOK HANDLES*/
+static HHOOK rawInputMouseHook = NULL;
+static HHOOK rawInputKeyboardHook = NULL;
+static BOOL mouseFirstRun = TRUE;
+
+//X,Y coords to create relative movement of mouse from low level hook
+static LONG mouseHookLastX = 0, mouseHookLastY = 0;
+
+/*DirectInput data*/
+LPDIRECTINPUT8A lpdi = NULL;
+LPDIRECTINPUTDEVICE8A m_mouse = NULL;
+LPDIRECTINPUTDEVICE8A m_keyboard = NULL;
+HANDLE mouseInputEvent = NULL;
+
+BOOL b_registered_mouse;
+BOOL b_registered_keyboard;
+RAWINPUTDEVICE rid_mouse;
+RAWINPUTDEVICE rid_keyboard;
+
+//Only keep so many rawinput structures
+#define RAWINPUTHANDLETABLESIZE 32
+
+#define RIM_TYPEMOUSE 0
+#define RIM_INPUT 0x00000000
+#define MOUSE_MOVE_RELATIVE 0x00000000
+#define MOUSE_MOVE_ABSOLUTE 0x00000001
+#define MOUSE_VIRTUAL_DESKTOP 0x00000002
+#define RI_MOUSE_LEFT_BUTTON_DOWN 0x0001
+#define RI_MOUSE_LEFT_BUTTON_UP 0x0002
+#define RI_MOUSE_RIGHT_BUTTON_DOWN 0x0004
+#define RI_MOUSE_RIGHT_BUTTON_UP 0x0008
+#define RI_MOUSE_MIDDLE_BUTTON_DOWN 0x0010
+#define RI_MOUSE_MIDDLE_BUTTON_UP 0x0020
+#define RI_MOUSE_BUTTON_1_DOWN RI_MOUSE_LEFT_BUTTON_DOWN
+#define RI_MOUSE_BUTTON_1_UP RI_MOUSE_LEFT_BUTTON_UP
+#define RI_MOUSE_BUTTON_2_DOWN RI_MOUSE_RIGHT_BUTTON_DOWN
+#define RI_MOUSE_BUTTON_2_UP RI_MOUSE_RIGHT_BUTTON_UP
+#define RI_MOUSE_BUTTON_3_DOWN RI_MOUSE_MIDDLE_BUTTON_DOWN
+#define RI_MOUSE_BUTTON_3_UP RI_MOUSE_MIDDLE_BUTTON_UP
+#define RI_MOUSE_BUTTON_4_DOWN 0x0040
+#define RI_MOUSE_BUTTON_4_UP 0x0080
+#define RI_MOUSE_BUTTON_5_DOWN 0x0100
+#define RI_MOUSE_BUTTON_5_UP 0x0200
+#define RI_MOUSE_WHEEL 0x0400
+#define RIDEV_INPUTSINK 0x00000100
+#define MOUSE_DEVICE_HANDLE 0x1337
+#define RID_INPUT 0x10000003
+#define RID_HEADER 0x10000005
+#define RIDEV_REMOVE 0x00000001
+#define RIDEV_CAPTUREMOUSE 0x00000200
WINE_DEFAULT_DEBUG_CHANNEL(win);
WINE_DECLARE_DEBUG_CHANNEL(keyboard);
@@ -490,30 +876,439 @@ UINT WINAPI GetRawInputDeviceList(PRAWINPUTDEVICELIST pRawInputDeviceList, PUINT
return 0;
}
+void SetRawInputMouseHeader(RAWINPUT *ri) {
+ ri->header.dwType = RIM_TYPEMOUSE;
+ ri->header.dwSize = sizeof(RAWINPUT);
+ ri->header.hDevice = MOUSE_DEVICE_HANDLE;
+ ri->header.wParam = RIM_INPUT;
+ return;
+}
+
+RAWINPUT *GetDirectInputMouseData() {
+ static DIMOUSESTATE2 mouse_state;
+ static DIMOUSESTATE2 mouse_state_prev;
+ RAWINPUT *raw;
+ HRESULT hr;
+ int i;
+
+ raw = (RAWINPUT*)HeapAlloc(hHeap, 0, sizeof(RAWINPUT));
+ SetRawInputMouseHeader(raw);
+
+ //Try to get input, and maybe reaquire input
+ hr = m_mouse->lpVtbl->GetDeviceState(m_mouse, sizeof(DIMOUSESTATE2), (LPVOID)&mouse_state);
+ if(FAILED(hr)) {
+ m_mouse->lpVtbl->Acquire(m_mouse);
+ while(hr == DIERR_INPUTLOST) {
+ hr = m_mouse->lpVtbl->Acquire(m_mouse);
+ }
+ if(FAILED(hr)) {
+ HeapFree(hHeap, 0, raw);
+ return NULL;
+ }
+ m_mouse->lpVtbl->GetDeviceState(m_mouse, sizeof(DIMOUSESTATE2), (LPVOID)&mouse_state);
+ }
+
+ raw->data.mouse.usFlags = MOUSE_MOVE_RELATIVE;
+ raw->data.mouse.lLastX = mouse_state.lX;
+ raw->data.mouse.lLastY = mouse_state.lY;
+ raw->data.mouse.usButtonData = mouse_state.lZ & 0xFFFF;
+ raw->data.mouse.usButtonFlags = 0;
+ raw->data.mouse.ulRawButtons = 0;
+
+ if(raw->data.mouse.usButtonData != 0) raw->data.mouse.usButtonFlags |= RI_MOUSE_WHEEL;
+
+ for(i = 0; i < 8; i++) {
+ if(mouse_state.rgbButtons[i] & 0x80) {
+ raw->data.mouse.ulRawButtons |= 1<<i;
+ }
+ }
+
+ if(mouse_state.rgbButtons[0] & 0x80 && !(mouse_state_prev.rgbButtons[0] & 0x80))
+ raw->data.mouse.usButtonFlags |= RI_MOUSE_LEFT_BUTTON_DOWN;
+
+ if(!(mouse_state.rgbButtons[0] & 0x80) && mouse_state_prev.rgbButtons[0] & 0x80)
+ raw->data.mouse.usButtonFlags |= RI_MOUSE_LEFT_BUTTON_UP;
+
+ if(mouse_state.rgbButtons[1] & 0x80 && !(mouse_state_prev.rgbButtons[1] & 0x80))
+ raw->data.mouse.usButtonFlags |= RI_MOUSE_RIGHT_BUTTON_DOWN;
+
+ if(!(mouse_state.rgbButtons[1] & 0x80) && mouse_state_prev.rgbButtons[1] & 0x80)
+ raw->data.mouse.usButtonFlags |= RI_MOUSE_RIGHT_BUTTON_UP;
+
+ if(mouse_state.rgbButtons[2] & 0x80 && !(mouse_state_prev.rgbButtons[2] & 0x80))
+ raw->data.mouse.usButtonFlags |= RI_MOUSE_MIDDLE_BUTTON_DOWN;
+
+ if(!(mouse_state.rgbButtons[2] & 0x80) && mouse_state_prev.rgbButtons[2] & 0x80)
+ raw->data.mouse.usButtonFlags |= RI_MOUSE_MIDDLE_BUTTON_UP;
+
+ if(mouse_state.rgbButtons[3] & 0x80 && !(mouse_state_prev.rgbButtons[3] & 0x80))
+ raw->data.mouse.usButtonFlags |= RI_MOUSE_BUTTON_4_DOWN;
+
+ if(!(mouse_state.rgbButtons[3] & 0x80) && mouse_state_prev.rgbButtons[3] & 0x80)
+ raw->data.mouse.usButtonFlags |= RI_MOUSE_BUTTON_4_UP;
+
+ if(mouse_state.rgbButtons[4] & 0x80 && !(mouse_state_prev.rgbButtons[4] & 0x80))
+ raw->data.mouse.usButtonFlags |= RI_MOUSE_BUTTON_5_DOWN;
+
+ if(!(mouse_state.rgbButtons[4] & 0x80) && mouse_state_prev.rgbButtons[4] & 0x80)
+ raw->data.mouse.usButtonFlags |= RI_MOUSE_BUTTON_5_UP;
+
+ memcpy(&mouse_state_prev, &mouse_state, sizeof(DIMOUSESTATE2));
+
+ return raw;
+}
+
+VOID AddRawInputToWindowList(RAWINPUT *ri, myList *windowList) {
+ myNode * cour = NULL;
+ GetLock(rawInputHandleList);
+
+ //Remove old rawinputs
+ if(rawInputHandleList && rawInputHandleList->length > RAWINPUTHANDLETABLESIZE)
+ HeapFree(hHeap, 0, (RAWINPUT *)PopFrontAndFree(rawInputHandleList));
+
+ //Add this new RAWINPUT
+ PushBackByVal(rawInputHandleList, (DWORD)ri);
+
+ GetLock(windowList);
+ for(cour = windowList->head; cour; cour = cour->next) {
+ PostMessageA((HWND)cour->data, WM_INPUT, RIM_INPUT, (LPARAM)ri);
+ }
+ ReleaseLock(windowList);
+ ReleaseLock(rawInputHandleList);
+ return;
+}
+
+//Mouse and Keyboard seperate just to simplify things a bit
+DWORD WINAPI PollDirectInputMouse(PVOID data) {
+ RAWINPUT *raw;
+ for(;;) {
+ if(WaitForSingleObject(mouseInputEvent, 1000*2) != WAIT_ABANDONED) {
+ raw = GetDirectInputMouseData();
+ if(raw) AddRawInputToWindowList(raw, rawMouseInputWindowList);
+ }
+ }
+ return 0;
+}
+
+BOOL RegisterDirectInputMouse(PRAWINPUTDEVICE pRawInputDevices, HWND hWnd) {
+ HRESULT hr;
+ DWORD flags;
+
+ //Try to map these flags to DirectX
+ flags = 0;
+ if(pRawInputDevices->dwFlags & RIDEV_INPUTSINK) flags |= DISCL_BACKGROUND;
+ else flags |= DISCL_FOREGROUND;
+ flags |= DISCL_NONEXCLUSIVE;
+
+ //Init DirectInput if nessecary
+ if (lpdi == NULL && FAILED(DirectInput8Create(GetModuleHandleA(NULL), DIRECTINPUT_VERSION, &IID_IDirectInput8A, (void**)&lpdi, NULL))) {
+ ERR("user32: Failed to create DirectInput interface\n");
+ return FALSE;
+ }
+
+ //Init MouseDevice if nessecary
+ if (m_mouse == NULL && FAILED(lpdi->lpVtbl->CreateDevice(lpdi, &GUID_SysMouse, &m_mouse, NULL))) {
+ ERR("user32: Failed to create DirectInput mouse device\n");
+ return FALSE;
+ }
+
+ //Make friendly with this hWnd
+ if (FAILED(m_mouse->lpVtbl->SetCooperativeLevel(m_mouse, hWnd, flags))) {
+ ERR("user32: Failed to set cooperative level on DirectInput mouse device\n");
+ return FALSE;
+ }
+
+ if (FAILED(m_mouse->lpVtbl->SetDataFormat(m_mouse, &c_dfDIMouse2))) {
+ ERR("user32: Failed to set data format on DirectInput mouse device\n");
+ return FALSE;
+ }
+
+ if(!mouseInputEvent) {
+ HANDLE handle;
+
+ mouseInputEvent = CreateEventA(NULL, FALSE, FALSE, NULL);
+ if(!mouseInputEvent) {
+ ERR("user32: Failed to create event for DirectInput mouse\n");
+ return FALSE;
+ }
+
+ handle = CreateThread(NULL, 0, PollDirectInputMouse, NULL, 0, NULL);
+ if(!handle) {
+ ERR("user32: Failed to create polling thread for DirectInput mouse\n");
+ return FALSE;
+ }
+
+ if(!SetThreadAffinityMask(handle, 1)) {
+ ERR("user32: Failed to set thread affinity mask for the DirectInput mouse polling thread\n");
+ return FALSE;
+ }
+
+ }
+
+ //Must be NOT be acquired to SetEventNotification
+ m_mouse->lpVtbl->Unacquire(m_mouse);
+ if(FAILED(m_mouse->lpVtbl->SetEventNotification(m_mouse, mouseInputEvent))) {
+ ERR("user32: Failed to SetEventNotification for DirectInput mouse\n");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+//SetWindowsHookEx WH_MOUSE_LL handler
+LRESULT CALLBACK myLowLevelMouseProc(int nCode, WPARAM wParam, LPARAM lParam) {
+ static ULONG ulRawButtons = 0;
+ RAWMOUSE *rm = NULL;
+ RAWINPUT *ri = NULL;
+ MSLLHOOKSTRUCT * hs = (MSLLHOOKSTRUCT*)lParam;
+
+ if(nCode == HC_ACTION) { //Should always be true
+ ri = (RAWINPUT*)HeapAlloc(hHeap, 0, sizeof(RAWINPUT));
+ if(ri) {
+ SetRawInputMouseHeader(ri);
+
+ rm = &ri->data.mouse;
+ if(mouseFirstRun) { //first time around give the absolute position
+ rm->usFlags = MOUSE_MOVE_ABSOLUTE;
+ rm->lLastX = hs->pt.x;
+ rm->lLastY = hs->pt.y;
+ } else {
+ rm->usFlags = MOUSE_MOVE_RELATIVE;
+ if(hs->flags & LLMHF_INJECTED) {
+ rm->lLastX = 0;
+ rm->lLastY = 0;
+ } else {
+ rm->lLastX = (LONG)hs->pt.x - mouseHookLastX;
+ rm->lLastY = (LONG)hs->pt.y - mouseHookLastY;
+ }
+ }
+
+ mouseHookLastX = hs->pt.x;
+ mouseHookLastY = hs->pt.y;
+
+ rm->ulButtons = 0;
+ rm->usButtonData = 0;
+ rm->usButtonFlags = 0;
+ rm->ulExtraInformation = 0;
+
+ //note ulRawButtons is static and we keep track of the state of the buttons this way
+ switch(wParam)
+ {
+ case WM_LBUTTONDOWN:
+ rm->usButtonFlags |= RI_MOUSE_LEFT_BUTTON_DOWN;
+ ulRawButtons |= 0x00000001;
+ break;
+
+ case WM_LBUTTONUP:
+ rm->usButtonFlags |= RI_MOUSE_LEFT_BUTTON_UP;
+ ulRawButtons &= ~0x00000001;
+ break;
+
+ case WM_RBUTTONDOWN:
+ rm->usButtonFlags |= RI_MOUSE_RIGHT_BUTTON_DOWN;
+ ulRawButtons |= 0x00000002;
+ break;
+
+ case WM_RBUTTONUP:
+ rm->usButtonFlags |= RI_MOUSE_RIGHT_BUTTON_UP;
+ ulRawButtons &= ~0x00000002;
+ break;
+
+ case WM_MBUTTONDOWN:
+ rm->usButtonFlags |= RI_MOUSE_MIDDLE_BUTTON_DOWN;
+ ulRawButtons |= 0x00000004;
+ break;
+
+ case WM_MBUTTONUP:
+ rm->usButtonFlags |= RI_MOUSE_MIDDLE_BUTTON_UP;
+ ulRawButtons &= ~0x00000004;
+ break;
+
+ case WM_MOUSEWHEEL:
+ rm->usButtonFlags |= RI_MOUSE_WHEEL;
+ rm->usButtonData = HIWORD(hs->mouseData);
+ break;
+
+ case WM_XBUTTONDOWN:
+ if(HIWORD(hs->mouseData) == XBUTTON1) rm->usButtonFlags |= RI_MOUSE_BUTTON_4_DOWN;
+ else if(HIWORD(hs->mouseData) == XBUTTON2) rm->usButtonFlags |= RI_MOUSE_BUTTON_5_DOWN;
+ ulRawButtons |= (1 << (HIWORD(hs->mouseData) + 2));
+ break;
+
+ case WM_XBUTTONUP:
+ if(HIWORD(hs->mouseData) == XBUTTON1) rm->usButtonFlags |= RI_MOUSE_BUTTON_4_UP;
+ else if(HIWORD(hs->mouseData) == XBUTTON2) rm->usButtonFlags |= RI_MOUSE_BUTTON_5_UP;
+ ulRawButtons &= ~(1 << (HIWORD(hs->mouseData) + 2));
+ break;
+ }
+ rm->ulRawButtons = ulRawButtons;
+
+ if(!mouseFirstRun) {
+ AddRawInputToWindowList(ri, rawMouseInputWindowList);
+ } else {
+ mouseFirstRun = FALSE;
+ }
+ }
+ }
+
+ return CallNextHookEx(rawInputMouseHook, nCode, wParam, lParam);
+}
+
+VOID DeRegisterDirectInputMouse() {
+ m_mouse->lpVtbl->Unacquire(m_mouse);
+ m_mouse->lpVtbl->SetEventNotification(m_mouse, NULL);
+}
/******************************************************************
* RegisterRawInputDevices (USER32.@)
*/
-BOOL WINAPI DECLSPEC_HOTPATCH RegisterRawInputDevices(PRAWINPUTDEVICE pRawInputDevices, UINT uiNumDevices, UINT cbSize)
-{
- FIXME("(pRawInputDevices=%p, uiNumDevices=%d, cbSize=%d) stub!\n", pRawInputDevices, uiNumDevices, cbSize);
+BOOL WINAPI RegisterRawInputDevices(PRAWINPUTDEVICE pRawInputDevices, UINT uiNumDevices, UINT cbSize) {
+ int i;
+ HWND hWnd;
+
+ hHeap = GetProcessHeap();
+ if(!rawMouseInputWindowList) InitializeList(&rawMouseInputWindowList);
+ if(!rawKeyboardInputWindowList) InitializeList(&rawKeyboardInputWindowList);
+ if(!rawInputHandleList) InitializeList(&rawInputHandleList);
+
+ if(!pRawInputDevices || !uiNumDevices || !cbSize) {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+
+ for(i=0; i<uiNumDevices; i++) {
+ //Get the window handle if we need to
+ hWnd = pRawInputDevices[i].hwndTarget;
+ if(!hWnd) hWnd = GetFocus();
+ if(!hWnd) hWnd = GetForegroundWindow(); //try this too
+ if(!hWnd) {
+ ERR("user32: couldn't get HWND for RegisterRawInputDevices\n");
+ return FALSE;
+ }
+
+ // Mouse input
+ if(pRawInputDevices[i].usUsagePage==1 && pRawInputDevices[i].usUsage==2) { //Mouse should match this
+ GetLock(rawMouseInputWindowList);
+ if(!(pRawInputDevices[i].dwFlags & RIDEV_REMOVE)) {
+ //Add
+ TRACE("user32: Adding a RAWINPUT mouse\n");
+
+ if(pRawInputDevices[i].dwFlags & RIDEV_CAPTUREMOUSE)
+ SetCapture(hWnd);
+ //Add the hWnd to the list
+ if(!IsInListByVal(rawMouseInputWindowList, (DWORD)hWnd))
+ PushFrontByVal(rawMouseInputWindowList, (DWORD)hWnd);
+
+ //If not getting low level data yet activate
+ if(UseDirectInput) {
+ if(!RegisterDirectInputMouse(&pRawInputDevices[i], hWnd))
+ ERR("user32: Could not register DirectInput mouse\n");
+ } else if(!rawInputMouseHook) {
+ rawInputMouseHook = SetWindowsHookExA(WH_MOUSE_LL, myLowLevelMouseProc, GetModuleHandleA("user32.dll"), 0);
+ if(!rawInputMouseHook)
+ ERR("user32: Could not SetWindowsHookEx WH_MOUSE_LL LastError=0x%X\n", GetLastError());
+ }
+ //Save this structure to return with GetRegisteredRawInputDevices
+ b_registered_mouse = TRUE;
+ memcpy(&rid_mouse, &pRawInputDevices[i], sizeof(RAWINPUTDEVICE));
+ } else {
+ //Remove
+ TRACE("user32: Removing a RAWINPUT mouse\n");
+
+ if(pRawInputDevices[i].hwndTarget) {
+ //This actually is not allowed
+ RemoveNodeByVal(rawMouseInputWindowList, (DWORD)pRawInputDevices[i].hwndTarget);
+ } else {
+ //Remove dem all!
+ while(rawMouseInputWindowList->length)
+ PopFrontAndFree(rawMouseInputWindowList);
+ }
+
+ ReleaseCapture();
+
+ if(rawMouseInputWindowList->length==0) {
+ if(UseDirectInput) {
+ DeRegisterDirectInputMouse();
+ } else if(rawInputMouseHook) {
+ UnhookWindowsHookEx(rawInputMouseHook);
+ rawInputMouseHook = NULL;
+ }
+ }
+
+ b_registered_mouse = FALSE;
+ }
+ ReleaseLock(rawMouseInputWindowList);
+ }
+
+ }
return TRUE;
}
-
/******************************************************************
* GetRawInputData (USER32.@)
*/
-UINT WINAPI GetRawInputData(HRAWINPUT hRawInput, UINT uiCommand, LPVOID pData, PUINT pcbSize, UINT cbSizeHeader)
-{
- FIXME("(hRawInput=%p, uiCommand=%d, pData=%p, pcbSize=%p, cbSizeHeader=%d) stub!\n",
- hRawInput, uiCommand, pData, pcbSize, cbSizeHeader);
+UINT WINAPI GetRawInputData(HRAWINPUT hRawInput, UINT uiCommand, LPVOID pData, PUINT pcbSize, UINT cbSizeHeader) {
+ UINT res = 0;
+ RAWINPUT *ri = (RAWINPUT*)hRawInput;
+
+ if(cbSizeHeader != sizeof(RAWINPUTHEADER)) {
+ ERR("user32: sizeof(RAWINPUTHEADER) does not match expected\n");
+ }
+
+ GetLock(rawInputHandleList);
+
+ //Ain't in the list no more
+ if(!hRawInput || !IsInListByVal(rawInputHandleList, (DWORD)hRawInput)) {
+ ReleaseLock(rawInputHandleList);
+ return ((UINT)-1);
+ }
+
+ if(!pData) {
+ switch(uiCommand) {
+ case RID_INPUT:
+ *pcbSize = sizeof(RAWINPUT);
+ res = 0;
+ break;
+
+ case RID_HEADER:
+ *pcbSize = sizeof(RAWINPUTHEADER);
+ res = 0;
+ break;
+
+ default:
+ *pcbSize = 0;
+ res = (UINT)-1;
+ }
+ } else {
+ switch(uiCommand) {
+ case RID_INPUT:
+ if(*pcbSize >= sizeof(RAWINPUT)) {
+ res = *pcbSize;
+ RtlCopyMemory(pData, ri, sizeof(RAWINPUT));
+ } else {
+ res = (UINT)-1;
+ }
+ break;
+
+ case RID_HEADER:
+ if(*pcbSize >= sizeof(RAWINPUTHEADER)) {
+ res = *pcbSize;
+ RtlCopyMemory(pData, &ri->header, sizeof(RAWINPUTHEADER));
+ } else {
+ res = (UINT)-1;
+ }
+ break;
+
+ default:
+ res = (UINT)-1;
+ }
+ }
- return 0;
+ ReleaseLock(rawInputHandleList);
+ return res;
}
-
/******************************************************************
* GetRawInputBuffer (USER32.@)
*/
@@ -550,11 +1345,36 @@ UINT WINAPI GetRawInputDeviceInfoW(HANDLE hDevice, UINT uiCommand, LPVOID pData,
/******************************************************************
* GetRegisteredRawInputDevices (USER32.@)
*/
-UINT WINAPI GetRegisteredRawInputDevices(PRAWINPUTDEVICE pRawInputDevices, PUINT puiNumDevices, UINT cbSize)
-{
- FIXME("(pRawInputDevices=%p, puiNumDevices=%p, cbSize=%d) stub!\n", pRawInputDevices, puiNumDevices, cbSize);
-
- return 0;
+UINT WINAPI GetRegisteredRawInputDevices(
+ PRAWINPUTDEVICE pRawInputDevices, PUINT puiNumDevices, UINT cbSize) {
+ UINT nd;
+ if(cbSize != sizeof(RAWINPUTDEVICE)) {
+ ERR("user32: GetRegisteredRawInputDevices expected structure size %d got %d\n",
+ sizeof(RAWINPUTDEVICE), cbSize);
+ }
+
+ //Since we only can the keyboard and mouse there should only ever be two
+ //devices. This will just return whatever structure they were registered
+ //with in this application. If you register more than once, you get the last.
+ nd = (b_registered_mouse?1:0) + (b_registered_keyboard?1:0);
+
+ if(nd > *puiNumDevices || !pRawInputDevices) {
+ SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ *puiNumDevices = nd;
+ return -1;
+ }
+
+ if(b_registered_mouse) {
+ memcpy(pRawInputDevices, &rid_mouse, sizeof(RAWINPUTDEVICE));
+ pRawInputDevices = (PRAWINPUTDEVICE)((PBYTE)pRawInputDevices + cbSize);
+ }
+
+ if(b_registered_keyboard) {
+ memcpy(pRawInputDevices, &rid_keyboard, sizeof(RAWINPUTDEVICE));
+ }
+
+ *puiNumDevices = nd;
+ return nd;
}
diff --git a/include/winuser.h b/include/winuser.h
index a8b2c93..393939d 100644
--- a/include/winuser.h
+++ b/include/winuser.h
@@ -491,8 +491,8 @@ typedef struct tagRAWMOUSE {
struct {
USHORT usButtonFlags;
USHORT usButtonData;
- } DUMMYSTRUCTNAME;
- } DUMMYUNIONNAME;
+ };
+ };
ULONG ulRawButtons;
LONG lLastX;
LONG lLastY;
@pencilcheck
Copy link

your patch fixed the mouse problem in World of tanks but it doesn't work in wineskin as it will make the audio not work. Have to disable coreaudio for the game to run.

@vincasmiliunas
Copy link
Author

I am in a process of developing a proper raw input patch for WINE, you could try it - http://dl.dropbox.com/u/6901628/raw.patch , after applying you will also need to run ./tools/make_requests script for it to compile. It's also explained here - http://bugs.winehq.org/show_bug.cgi?id=20395

@pencilcheck
Copy link

In the latest wine changelog, I saw there was some directinput improvements, do I still need your patch for that?

@pencilcheck
Copy link

also, the game I was running doesn't work with other version of wine, and I can't compile your new patch with 1.3.22.

@vincasmiliunas
Copy link
Author

This gist patch is adopted Windows 2000 XP API Wrapper Pack, which by default uses DirectInput to read mouse input, otherwise Raw Input has nothing to do with DirectInput.

My patch I linked above will compile with 1.3.23+, but it's best to use the latest master tree anyways.

By saying the game doesn't work, you likely mean the graphical glitches (there was also one regression, where the game hanged, but it's fixed), so pull the latest WINE git and run: git revert --no-edit 68b15bc5ffe6ddf5d08cbc13479eaf718ad5e39f

@pencilcheck
Copy link

It might still be the sound problem.
Using specific versions tested by other users in the winehq page, I can play with sound without the mouse, but if I apply this patch, the sound will not work and the mouse works.

@vincasmiliunas
Copy link
Author

By "this patch" I hope you mean the one I linked above - http://dl.dropbox.com/u/6901628/raw.patch , it does not change anything DirectInput or sound related. I have not used WINE on MacOS, so no idea what's the cause.

Be sure that the version you compile and run with has sound, only after applying the patch and compiling the problem appears.

@pencilcheck
Copy link

that is exactly what I did. I recompile the kernel with sound and then sound doesn't work anymore.

@vincasmiliunas
Copy link
Author

Compiled the kernel? I hope you ment WINE. You can also try a bare minimum hack (which should work also for WoT) - http://bugs.winehq.org/attachment.cgi?id=35291 from http://bugs.winehq.org/show_bug.cgi?id=27551

@pencilcheck
Copy link

oops, I mean wine you are right. :P

@pencilcheck
Copy link

well, the author of the patch said it is targeted specifically for 1.3.23 but the latest compatible version is 1.3.22 for WoT as reported from the users on winehq page.

@vincasmiliunas
Copy link
Author

Yeah, the guy's patch doesn't work in WoT, also WoT uses RawInput for wheel input, which it lacks as well; so I wrote a better hack, which works. The master tree and 1.3.24 is playable by applying these patches - http://dl.dropbox.com/u/6901628/rawinput-hack.patch http://dl.dropbox.com/u/6901628/remove-GL_ARB_map_buffer_range.patch

@vincasmiliunas
Copy link
Author

Since somebody emailed me about this patch, I'll make an update.

Do not use this patch, as stated above, there is a better alternative version - http://dl.dropbox.com/u/6901628/raw3.patch . You can find instructions how to apply it in the "How to get the latest WINE's git working" comment - http://appdb.winehq.org/objectManager.php?sClass=version&iId=22521 .

@vincasmiliunas
Copy link
Author

vincasmiliunas commented Jan 19, 2012 via email

@stankz
Copy link

stankz commented Mar 18, 2012

This patch works for version 0.7.1.1 WoT?

@vincasmiliunas
Copy link
Author

@stankz The patch is for WINE, not for WoT. Also read the comment above - https://gist.github.com/895204#gistcomment-71400 or use WoTFLIX.

@pomozoff
Copy link

[SOLVED]
It needs to start this command before compile:
$ ./tools/make_requests

Do not use this patch, as stated above, there is a better alternative version - http://dl.dropbox.com/u/6901628/raw3.patch.

Current wine from git.
I have these errors with raw3.patch:

gcc-4.2 -m32 -c -I. -I. -I../include -I../include -D__WINESRC__ -Wall -pipe -fno-strict-aliasing -Wdeclaration-after-statement -Wempty-body -Wstrict-prototypes -Wwrite-strings -fno-omit-frame-pointer -Wpointer-arith -I/tmp/Wineskin/include/freetype2 -I/tmp/Wineskin/include -I/tmp/Wineskin/include -arch i386 -m32 -O2 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.7.sdk -mmacosx-version-min=10.7 -I/tmp/Wineskin/include -o raw_input.o raw_input.c
raw_input.c:137: warning: ‘struct raw_input_device_registration’ declared inside parameter list
raw_input.c:137: warning: its scope is only this definition or declaration, which is probably not what you want
raw_input.c: In function ‘register_raw_input_device’:
raw_input.c:146: error: dereferencing pointer to incomplete type
raw_input.c:147: error: ‘RAW_INPUT_DEVICE_FLAG_PAGEONLY’ undeclared (first use in this function)
raw_input.c:147: error: (Each undeclared identifier is reported only once
raw_input.c:147: error: for each function it appears in.)
raw_input.c:148: error: dereferencing pointer to incomplete type
raw_input.c:150: error: dereferencing pointer to incomplete type
raw_input.c:151: error: dereferencing pointer to incomplete type
raw_input.c:154: error: dereferencing pointer to incomplete type
raw_input.c:154: error: ‘RAW_INPUT_DEVICE_FLAG_REMOVE’ undeclared (first use in this function)
raw_input.c:162: error: dereferencing pointer to incomplete type
raw_input.c:163: error: dereferencing pointer to incomplete type
raw_input.c:167: error: dereferencing pointer to incomplete type
raw_input.c:171: error: dereferencing pointer to incomplete type
raw_input.c:172: error: dereferencing pointer to incomplete type
raw_input.c:173: error: dereferencing pointer to incomplete type
raw_input.c:174: error: dereferencing pointer to incomplete type
raw_input.c: In function ‘find_registered_usage’:
raw_input.c:254: error: ‘RAW_INPUT_DEVICE_FLAG_EXCLUDE’ undeclared (first use in this function)
raw_input.c:257: error: ‘RAW_INPUT_DEVICE_FLAG_PAGEONLY’ undeclared (first use in this function)
raw_input.c: In function ‘is_nolegacy_set_for_raw_input_mouse’:
raw_input.c:451: error: ‘RAW_INPUT_DEVICE_FLAG_NOLEGACY’ undeclared (first use in this function)
raw_input.c: In function ‘is_nolegacy_set_for_raw_input_keyboard’:
raw_input.c:458: error: ‘RAW_INPUT_DEVICE_FLAG_NOLEGACY’ undeclared (first use in this function)
raw_input.c: At top level:
raw_input.c:477: warning: ‘struct get_raw_input_device_list_reply’ declared inside parameter list
raw_input.c:477: warning: ‘struct get_raw_input_device_list_request’ declared inside parameter list
raw_input.c: In function ‘req_get_raw_input_device_list’:
raw_input.c:482: error: dereferencing pointer to incomplete type
raw_input.c:483: error: dereferencing pointer to incomplete type
raw_input.c:483: error: dereferencing pointer to incomplete type
raw_input.c:486: error: dereferencing pointer to incomplete type
raw_input.c:500: error: dereferencing pointer to incomplete type
raw_input.c: At top level:
raw_input.c:511: warning: ‘struct get_raw_input_device_info_reply’ declared inside parameter list
raw_input.c:511: warning: ‘struct get_raw_input_device_info_request’ declared inside parameter list
raw_input.c: In function ‘req_get_raw_input_device_info’:
raw_input.c:519: error: dereferencing pointer to incomplete type
raw_input.c:523: error: dereferencing pointer to incomplete type
raw_input.c:527: error: dereferencing pointer to incomplete type
raw_input.c:531: error: dereferencing pointer to incomplete type
raw_input.c:536: error: dereferencing pointer to incomplete type
raw_input.c:542: error: dereferencing pointer to incomplete type
raw_input.c:545: error: dereferencing pointer to incomplete type
raw_input.c:546: error: dereferencing pointer to incomplete type
raw_input.c:546: error: dereferencing pointer to incomplete type
raw_input.c: At top level:
raw_input.c:569: warning: ‘struct get_registered_raw_input_devices_reply’ declared inside parameter list
raw_input.c:569: warning: ‘struct get_registered_raw_input_devices_request’ declared inside parameter list
raw_input.c: In function ‘req_get_registered_raw_input_devices’:
raw_input.c:575: error: dereferencing pointer to incomplete type
raw_input.c:576: error: dereferencing pointer to incomplete type
raw_input.c:576: error: dereferencing pointer to incomplete type
raw_input.c:579: error: dereferencing pointer to incomplete type
raw_input.c: At top level:
raw_input.c:605: warning: ‘struct register_raw_input_devices_reply’ declared inside parameter list
raw_input.c:605: warning: ‘struct register_raw_input_devices_request’ declared inside parameter list
raw_input.c: In function ‘req_register_raw_input_devices’:
raw_input.c:610: error: dereferencing pointer to incomplete type
raw_input.c:611: error: invalid use of undefined type ‘struct raw_input_device_registration’
raw_input.c:611: error: dereferencing pointer to incomplete type
raw_input.c: At top level:
raw_input.c:615: warning: ‘struct get_raw_input_data_reply’ declared inside parameter list
raw_input.c:615: warning: ‘struct get_raw_input_data_request’ declared inside parameter list
raw_input.c: In function ‘req_get_raw_input_data’:
raw_input.c:618: error: dereferencing pointer to incomplete type
raw_input.c:620: error: dereferencing pointer to incomplete type
raw_input.c:629: error: dereferencing pointer to incomplete type
raw_input.c:630: error: dereferencing pointer to incomplete type
raw_input.c:631: error: dereferencing pointer to incomplete type
raw_input.c:632: error: dereferencing pointer to incomplete type
raw_input.c:633: error: dereferencing pointer to incomplete type
raw_input.c:634: error: dereferencing pointer to incomplete type
raw_input.c:635: error: dereferencing pointer to incomplete type
raw_input.c:636: error: dereferencing pointer to incomplete type
raw_input.c:643: error: dereferencing pointer to incomplete type
raw_input.c:646: error: dereferencing pointer to incomplete type
raw_input.c:652: error: dereferencing pointer to incomplete type
raw_input.c:660: error: dereferencing pointer to incomplete type
raw_input.c:662: error: dereferencing pointer to incomplete type
raw_input.c:662: error: dereferencing pointer to incomplete type
raw_input.c:664: error: dereferencing pointer to incomplete type
raw_input.c: At top level:
raw_input.c:669: warning: ‘struct get_raw_input_buffer_reply’ declared inside parameter list
raw_input.c:669: warning: ‘struct get_raw_input_buffer_request’ declared inside parameter list
raw_input.c: In function ‘req_get_raw_input_buffer’:
raw_input.c:676: error: dereferencing pointer to incomplete type
raw_input.c:679: error: dereferencing pointer to incomplete type
raw_input.c:680: error: dereferencing pointer to incomplete type
raw_input.c:690: error: dereferencing pointer to incomplete type
raw_input.c:713: error: dereferencing pointer to incomplete type
raw_input.c:714: error: dereferencing pointer to incomplete type
raw_input.c:716: error: dereferencing pointer to incomplete type
raw_input.c:733: error: dereferencing pointer to incomplete type
raw_input.c:738: error: dereferencing pointer to incomplete type
raw_input.c:744: error: dereferencing pointer to incomplete type
make[1]: *** [raw_input.o] Error 1
make[1]: *** Waiting for unfinished jobs....

@vincasmiliunas
Copy link
Author

@pomozoff Yes, you DO need to read the linked instructions in the second sentence.

@blakekl
Copy link

blakekl commented Jul 6, 2012

@vincasmiliunas - Do you have a version of this that would work with a more recent version of wine, like 1.5.x?

@vincasmiliunas
Copy link
Author

vincasmiliunas commented Jul 7, 2012 via email

@blackwingcat
Copy link

761				//Remove
762				TRACE("user32: Removing a RAWINPUT mouse\n");

+				if (UseDirectInput && m_mouse == NULL) {
+					RegisterDirectInputMouse(&pRawInputDevices[i], hWnd);
+				}
                if(pRawInputDevices[i].hwndTarget) {
					//This actually is not allowed
                    RemoveNodeByVal(rawMouseInputWindowList, (DWORD)pRawInputDevices[i].hwndTarget);
                } else {


It will be crash on DeRegisterDirectInputMouse().

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment