| 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; |
|
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
commented
Jul 10, 2011
|
In the latest wine changelog, I saw there was some directinput improvements, do I still need your patch for that? |
pencilcheck
commented
Jul 10, 2011
|
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. |
|
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
commented
Jul 10, 2011
|
It might still be the sound problem. |
|
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
commented
Jul 15, 2011
|
that is exactly what I did. I recompile the kernel with sound and then sound doesn't work anymore. |
|
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
commented
Jul 15, 2011
|
oops, I mean wine you are right. :P |
pencilcheck
commented
Jul 19, 2011
|
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. |
|
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 |
|
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 . |
|
On 01/19/2012 03:11 AM, sl1pkn07 wrote:
raw3.patch make me error
http://paste.kde.org/188762
greetings
---
Reply to this email directly or view it on GitHub:
https://gist.github.com/895204
Hi,
read the linked instructions, they're not redundant ;) You'll learn that
after applying the patch you also need to run ./tool/make_requests script.
|
stankz
commented
Mar 18, 2012
|
This patch works for version 0.7.1.1 WoT? |
|
@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
commented
Apr 22, 2012
|
[SOLVED]
Current wine from git. 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 |
|
@pomozoff Yes, you DO need to read the linked instructions in the second sentence. |
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? |
|
On 07/06/2012 03:39 AM, blakekl wrote:
@vincasmiliunas - Do you have a version of this that would work with a more recent version of wine, like 1.5.x?
---
Reply to this email directly or view it on GitHub:
https://gist.github.com/895204
Read the information provided in the comments above...
|
pencilcheck commentedJul 9, 2011
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.