diff --git a/include/dinput.h b/include/dinput.h index 0bf86c33c90..2ee382e9882 100644 --- a/include/dinput.h +++ b/include/dinput.h @@ -2,6 +2,7 @@ #define _WINE_DINPUT_H #include "unknwn.h" +#include "mouse.h" #define STDMETHOD(xfn) HRESULT (CALLBACK *fn##xfn) #define STDMETHOD_(ret,xfn) ret (CALLBACK *fn##xfn) @@ -716,20 +717,36 @@ struct IDirectInputDevice32A { }; /* "Standard" Mouse report... */ -struct DIMOUSESTATE { +typedef struct DIMOUSESTATE { LONG lX; LONG lY; LONG lZ; BYTE rgbButtons[4]; -}; +} DIMOUSESTATE; + +#define DIMOFS_X FIELD_OFFSET(DIMOUSESTATE, lX) +#define DIMOFS_Y FIELD_OFFSET(DIMOUSESTATE, lY) +#define DIMOFS_Z FIELD_OFFSET(DIMOUSESTATE, lZ) +#define DIMOFS_BUTTON0 (FIELD_OFFSET(DIMOUSESTATE, rgbButtons) + 0) +#define DIMOFS_BUTTON1 (FIELD_OFFSET(DIMOUSESTATE, rgbButtons) + 1) +#define DIMOFS_BUTTON2 (FIELD_OFFSET(DIMOUSESTATE, rgbButtons) + 2) +#define DIMOFS_BUTTON3 (FIELD_OFFSET(DIMOUSESTATE, rgbButtons) + 3) + struct SysMouse32A { LPDIRECTINPUTDEVICEA_VTABLE lpvtbl; DWORD ref; GUID guid; BYTE absolute; /* Previous position for relative moves */ - LONG prevX; - LONG prevY; + LONG prevX, prevY; + LPMOUSE_EVENT_PROC prev_handler; + HWND32 win; + int xwin; + DWORD win_centerX, win_centerY; + LPDIDEVICEOBJECTDATA data_queue; + int queue_pos, queue_len; + int need_warp; + int acquired; }; struct SysKeyboard32A { diff --git a/windows/dinput.c b/windows/dinput.c index f00dcc545c1..52379bd3a3a 100644 --- a/windows/dinput.c +++ b/windows/dinput.c @@ -1,8 +1,8 @@ /* DirectInput * * Copyright 1998 Marcus Meissner + * Copyright 1998,1999 Lionel Ulmer * - * Additions (mouse support) Copyright 1998 Lionel Ulmer */ /* Status: * @@ -35,6 +35,11 @@ #include "debug.h" #include "message.h" +#include "mouse.h" +#include "ts_xlib.h" +#include "sysmetrics.h" +#include "x11drv.h" + extern BYTE InputKeyStateTable[256]; extern int min_keycode, max_keycode; extern WORD keyc2vkey[256]; @@ -60,6 +65,31 @@ static GUID DInput_Wine_Keyboard_GUID = { /* 0ab8648a-7735-11d2-8c73-71df54a9644 {0x8c, 0x73, 0x71, 0xdf, 0x54, 0xa9, 0x64, 0x41} }; +/* This is ugly and not thread safe :/ */ +static LPDIRECTINPUTDEVICE32A current_lock = NULL; + +/****************************************************************************** + * Various debugging tools + */ +static void _dump_cooperativelevel(DWORD dwFlags) { + int i; + const struct { + DWORD mask; + char *name; + } flags[] = { +#define FE(x) { x, #x}, + FE(DISCL_BACKGROUND) + FE(DISCL_EXCLUSIVE) + FE(DISCL_FOREGROUND) + FE(DISCL_NONEXCLUSIVE) + }; + for (i=0;iref = 1; (*pdev)->lpvtbl = &SysMouseAvt; @@ -231,32 +261,8 @@ static HRESULT WINAPI IDirectInputDeviceA_SetCooperativeLevel( LPDIRECTINPUTDEVICE32A this,HWND32 hwnd,DWORD dwflags ) { FIXME(dinput,"(this=%p,0x%08lx,0x%08lx): stub\n",this,(DWORD)hwnd,dwflags); - return 0; -} - -static HRESULT WINAPI IDirectInputDeviceA_SetProperty( - LPDIRECTINPUTDEVICE32A this,REFGUID rguid,LPCDIPROPHEADER ph -) { - char xbuf[50]; - - if (HIWORD(rguid)) - WINE_StringFromCLSID(rguid,xbuf); - else - sprintf(xbuf,"",(DWORD)rguid); - TRACE(dinput,"(this=%p,%s,%p)\n",this,xbuf,ph); - if (!HIWORD(rguid)) { - switch ((DWORD)rguid) { - case DIPROP_BUFFERSIZE: { - LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph; - - TRACE(dinput,"buffersize = %ld\n",pd->dwData); - break; - } - default: - WARN(dinput,"Unknown type %ld\n",(DWORD)rguid); - break; - } - } + if (TRACE_ON(dinput)) + _dump_cooperativelevel(dwflags); return 0; } @@ -267,26 +273,6 @@ static HRESULT WINAPI IDirectInputDeviceA_SetEventNotification( return 0; } -static HRESULT WINAPI IDirectInputDeviceA_GetDeviceData( - LPDIRECTINPUTDEVICE32A this,DWORD dodsize,LPDIDEVICEOBJECTDATA dod, - LPDWORD entries,DWORD flags -) { - TRACE(dinput,"IDirectInputDeviceA(%p)->GetDeviceData(%ld,%p,%p(0x%08lx),0x%08lx)\n", - this,dodsize,dod,entries,*entries,flags); - return 0; -} - - -static HRESULT WINAPI IDirectInputDeviceA_Acquire(LPDIRECTINPUTDEVICE32A this) { - TRACE(dinput,"(this=%p): stub\n",this); - return 0; -} - -static HRESULT WINAPI IDirectInputDeviceA_Unacquire(LPDIRECTINPUTDEVICE32A this) { - TRACE(dinput,"(this=%p): stub\n",this); - return 0; -} - static ULONG WINAPI IDirectInputDeviceA_Release(LPDIRECTINPUTDEVICE32A this) { this->ref--; if (this->ref) @@ -590,6 +576,51 @@ static HRESULT WINAPI IDirectInputDevice2A_SendDeviceData( * SysMouseA (DInput Mouse support) */ +/****************************************************************************** + * Release : release the mouse buffer. + */ +static ULONG WINAPI SysMouseA_Release(LPDIRECTINPUTDEVICE32A this) { + LPSYSMOUSE32A mthis = (LPSYSMOUSE32A) this; + + this->ref--; + if (this->ref) + return this->ref; + + /* Free the data queue */ + if (mthis->data_queue != NULL) + HeapFree(GetProcessHeap(),0,mthis->data_queue); + + /* Install the previous event handler (in case of releasing an aquired + mouse device) */ + if (mthis->prev_handler != NULL) + MOUSE_Enable(mthis->prev_handler); + + HeapFree(GetProcessHeap(),0,this); + return 0; +} + + +/****************************************************************************** + * SetCooperativeLevel : store the window in which we will do our + * grabbing. + */ +static HRESULT WINAPI SysMouseA_SetCooperativeLevel( + LPDIRECTINPUTDEVICE32A this,HWND32 hwnd,DWORD dwflags +) { + LPSYSMOUSE32A mthis = (LPSYSMOUSE32A) this; + + TRACE(dinput,"(this=%p,0x%08lx,0x%08lx): stub\n",this,(DWORD)hwnd,dwflags); + + if (TRACE_ON(dinput)) + _dump_cooperativelevel(dwflags); + + /* Store the window which asks for the mouse */ + mthis->win = hwnd; + + return 0; +} + + /****************************************************************************** * SetDataFormat : the application can choose the format of the data * the device driver sends back with GetDeviceState. @@ -633,23 +664,177 @@ static HRESULT WINAPI SysMouseA_SetDataFormat( /* For the moment, ignore these fields and return always as if c_dfDIMouse was passed as format... */ + + /* Check if the mouse is in absolute or relative mode */ if (df->dwFlags == DIDF_ABSAXIS) mthis->absolute = 1; - else { - DWORD rx, ry; - - /* We need to get the initial "previous" position to be able - to return deltas */ + else mthis->absolute = 0; - /* Get the mouse position */ - EVENT_QueryPointer(&rx, &ry, NULL); + return 0; +} - /* Fill the initial mouse state structure */ - mthis->prevX = rx; - mthis->prevY = ry; +#define GEN_EVENT(offset,data,time,seq) \ +{ \ + if (mthis->queue_pos < mthis->queue_len) { \ + mthis->data_queue[mthis->queue_pos].dwOfs = offset; \ + mthis->data_queue[mthis->queue_pos].dwData = data; \ + mthis->data_queue[mthis->queue_pos].dwTimeStamp = time; \ + mthis->data_queue[mthis->queue_pos].dwSequence = seq; \ + mthis->queue_pos++; \ + } \ } +/* Our private mouse event handler */ +static void WINAPI dinput_mouse_event( DWORD dwFlags, DWORD dx, DWORD dy, + DWORD cButtons, DWORD dwExtraInfo ) +{ + DWORD posX, posY, keyState, time, extra; + LPSYSMOUSE32A mthis = (LPSYSMOUSE32A) current_lock; + + if ( !IsBadReadPtr32( (LPVOID)dwExtraInfo, sizeof(WINE_MOUSEEVENT) ) + && ((WINE_MOUSEEVENT *)dwExtraInfo)->magic == WINE_MOUSEEVENT_MAGIC ) { + WINE_MOUSEEVENT *wme = (WINE_MOUSEEVENT *)dwExtraInfo; + keyState = wme->keyState; + time = wme->time; + extra = (DWORD)wme->hWnd; + + assert( dwFlags & MOUSEEVENTF_ABSOLUTE ); + posX = (dx * SYSMETRICS_CXSCREEN) >> 16; + posY = (dy * SYSMETRICS_CYSCREEN) >> 16; + } else { + ERR(dinput, "Mouse event not supported...\n"); + return ; + } + + TRACE(dinput, " %ld %ld ", posX, posY); + + if ( dwFlags & MOUSEEVENTF_MOVE ) { + if (mthis->absolute) { + if (posX != mthis->prevX) + GEN_EVENT(DIMOFS_X, posX, time, 0); + if (posY != mthis->prevY) + GEN_EVENT(DIMOFS_Y, posY, time, 0); + } else { + /* Relative mouse input : the real fun starts here... */ + if (mthis->need_warp) { + if (posX != mthis->prevX) + GEN_EVENT(DIMOFS_X, posX - mthis->prevX, time, 0); + if (posY != mthis->prevY) + GEN_EVENT(DIMOFS_Y, posY - mthis->prevY, time, 0); + } else { + /* This is the first time the event handler has been called after a + GetData of GetState. */ + if (posX != mthis->win_centerX) { + GEN_EVENT(DIMOFS_X, posX - mthis->win_centerX, time, 0); + mthis->need_warp = 1; + } + + if (posY != mthis->win_centerY) { + GEN_EVENT(DIMOFS_Y, posY - mthis->win_centerY, time, 0); + mthis->need_warp = 1; + } + } + } + } + if ( dwFlags & MOUSEEVENTF_LEFTDOWN ) { + if (TRACE_ON(dinput)) + DUMP(" LD "); + + GEN_EVENT(DIMOFS_BUTTON0, 0xFF, time, 0); + } + if ( dwFlags & MOUSEEVENTF_LEFTUP ) { + if (TRACE_ON(dinput)) + DUMP(" LU "); + + GEN_EVENT(DIMOFS_BUTTON0, 0x00, time, 0); + } + if ( dwFlags & MOUSEEVENTF_RIGHTDOWN ) { + if (TRACE_ON(dinput)) + DUMP(" RD "); + + GEN_EVENT(DIMOFS_BUTTON1, 0xFF, time, 0); + } + if ( dwFlags & MOUSEEVENTF_RIGHTUP ) { + if (TRACE_ON(dinput)) + DUMP(" RU "); + + GEN_EVENT(DIMOFS_BUTTON1, 0x00, time, 0); + } + if ( dwFlags & MOUSEEVENTF_MIDDLEDOWN ) { + if (TRACE_ON(dinput)) + DUMP(" MD "); + + GEN_EVENT(DIMOFS_BUTTON2, 0xFF, time, 0); + } + if ( dwFlags & MOUSEEVENTF_MIDDLEUP ) { + if (TRACE_ON(dinput)) + DUMP(" MU "); + + GEN_EVENT(DIMOFS_BUTTON2, 0x00, time, 0); + } + if (TRACE_ON(dinput)) + DUMP("\n"); + + mthis->prevX = posX; + mthis->prevY = posY; +} + + +/****************************************************************************** + * Acquire : gets exclusive control of the mouse + */ +static HRESULT WINAPI SysMouseA_Acquire(LPDIRECTINPUTDEVICE32A this) { + LPSYSMOUSE32A mthis = (LPSYSMOUSE32A) this; + RECT32 rect; + + TRACE(dinput,"(this=%p)\n",this); + + if (mthis->acquired == 0) { + /* This stores the current mouse handler. + FIXME : need to be fixed for native USER use */ + mthis->prev_handler = mouse_event; + + /* Store (in a global variable) the current lock */ + current_lock = this; + + /* Install our own mouse event handler */ + MOUSE_Enable(dinput_mouse_event); + + /* Get the window dimension and find the center */ + GetWindowRect32(mthis->win, &rect); + mthis->xwin = ((X11DRV_WND_DATA *) WIN_FindWndPtr(mthis->win)->pDriverData)->window; + mthis->win_centerX = (rect.right - rect.left) / 2; + mthis->win_centerY = (rect.bottom - rect.top ) / 2; + /* Warp the mouse to the center of the window */ + TRACE(dinput, "Warping mouse to %ld - %ld\n", mthis->win_centerX, mthis->win_centerY); + TSXWarpPointer(display, DefaultRootWindow(display), + mthis->xwin, 0, 0, 0, 0, + mthis->win_centerX, mthis->win_centerY); + + mthis->acquired = 1; + } + return 0; +} + +/****************************************************************************** + * Unacquire : frees the mouse + */ +static HRESULT WINAPI SysMouseA_Unacquire(LPDIRECTINPUTDEVICE32A this) { + LPSYSMOUSE32A mthis = (LPSYSMOUSE32A) this; + + TRACE(dinput,"(this=%p)\n",this); + + /* Reinstall previous mouse event handler */ + MOUSE_Enable(mthis->prev_handler); + mthis->prev_handler = NULL; + + /* No more locks */ + current_lock = NULL; + + /* Unacquire device */ + mthis->acquired = 0; + return 0; } @@ -683,11 +868,11 @@ static HRESULT WINAPI SysMouseA_GetDeviceState( mstate->lX = rx; mstate->lY = ry; } else { - mstate->lX = rx - mthis->prevX; - mstate->lY = ry - mthis->prevY; - /* Fill the previous positions */ - mthis->prevX = rx; - mthis->prevY = ry; + mstate->lX = rx - mthis->win_centerX; + mstate->lY = ry - mthis->win_centerY; + + if ((mstate->lX != 0) || (mstate->lY != 0)) + mthis->need_warp = 1; } mstate->lZ = 0; mstate->rgbButtons[0] = (state & MK_LBUTTON ? 0xFF : 0x00); @@ -695,9 +880,109 @@ static HRESULT WINAPI SysMouseA_GetDeviceState( mstate->rgbButtons[2] = (state & MK_MBUTTON ? 0xFF : 0x00); mstate->rgbButtons[3] = 0x00; + /* Check if we need to do a mouse warping */ + if (mthis->need_warp) { + TRACE(dinput, "Warping mouse to %ld - %ld\n", mthis->win_centerX, mthis->win_centerY); + TSXWarpPointer(display, DefaultRootWindow(display), + mthis->xwin, 0, 0, 0, 0, + mthis->win_centerX, mthis->win_centerY); + mthis->need_warp = 0; + } + + TRACE(dinput, "(X: %ld - Y: %ld L: %02x M: %02x R: %02x)\n", + mstate->lX, mstate->lY, + mstate->rgbButtons[0], mstate->rgbButtons[2], mstate->rgbButtons[1]); + return 0; } +/****************************************************************************** + * GetDeviceState : gets buffered input data. + */ +static HRESULT WINAPI SysMouseA_GetDeviceData(LPDIRECTINPUTDEVICE32A this, + DWORD dodsize, + LPDIDEVICEOBJECTDATA dod, + LPDWORD entries, + DWORD flags +) { + LPSYSMOUSE32A mthis = (LPSYSMOUSE32A) this; + + TRACE(dinput,"(%p)->(%ld,%p,%p(0x%08lx),0x%08lx)\n", + this,dodsize,dod,entries,*entries,flags); + + if (flags & DIGDD_PEEK) + TRACE(dinput, "DIGDD_PEEK\n"); + + if (dod == NULL) { + *entries = mthis->queue_pos; + mthis->queue_pos = 0; + } else { + /* Check for buffer overflow */ + if (mthis->queue_pos > *entries) { + WARN(dinput, "Buffer overflow not handled properly yet...\n"); + mthis->queue_pos = *entries; + } + if (dodsize != sizeof(DIDEVICEOBJECTDATA)) { + ERR(dinput, "Wrong structure size !\n"); + return DIERR_INVALIDPARAM; + } + + /* Copy the buffered data into the application queue */ + memcpy(dod, mthis->data_queue, mthis->queue_pos * dodsize); + + /* Reset the event queue */ + mthis->queue_pos = 0; + } + + /* Check if we need to do a mouse warping */ + if (mthis->need_warp) { + TRACE(dinput, "Warping mouse to %ld - %ld\n", mthis->win_centerX, mthis->win_centerY); + TSXWarpPointer(display, DefaultRootWindow(display), + mthis->xwin, 0, 0, 0, 0, + mthis->win_centerX, mthis->win_centerY); + mthis->need_warp = 0; + } + + return 0; +} + +/****************************************************************************** + * SetProperty : change input device properties + */ +static HRESULT WINAPI SysMouseA_SetProperty(LPDIRECTINPUTDEVICE32A this, + REFGUID rguid, + LPCDIPROPHEADER ph) { + char xbuf[50]; + LPSYSMOUSE32A mthis = (LPSYSMOUSE32A) this; + + if (HIWORD(rguid)) + WINE_StringFromCLSID(rguid,xbuf); + else + sprintf(xbuf,"",(DWORD)rguid); + + TRACE(dinput,"(this=%p,%s,%p)\n",this,xbuf,ph); + + if (!HIWORD(rguid)) { + switch ((DWORD)rguid) { + case DIPROP_BUFFERSIZE: { + LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph; + + TRACE(dinput,"buffersize = %ld\n",pd->dwData); + + mthis->data_queue = (LPDIDEVICEOBJECTDATA)HeapAlloc(GetProcessHeap(),0, + pd->dwData * sizeof(DIDEVICEOBJECTDATA)); + mthis->queue_pos = 0; + mthis->queue_len = pd->dwData; + break; + } + default: + WARN(dinput,"Unknown type %ld\n",(DWORD)rguid); + break; + } + } + + return 0; +} static IDirectInputDeviceA_VTable SysKeyboardAvt={ @@ -733,18 +1018,18 @@ static IDirectInputDeviceA_VTable SysKeyboardAvt={ static IDirectInputDeviceA_VTable SysMouseAvt={ IDirectInputDeviceA_QueryInterface, IDirectInputDeviceA_AddRef, - IDirectInputDeviceA_Release, + SysMouseA_Release, IDirectInputDeviceA_GetCapabilities, IDirectInputDeviceA_EnumObjects, IDirectInputDeviceA_GetProperty, - IDirectInputDeviceA_SetProperty, - IDirectInputDeviceA_Acquire, - IDirectInputDeviceA_Unacquire, + SysMouseA_SetProperty, + SysMouseA_Acquire, + SysMouseA_Unacquire, SysMouseA_GetDeviceState, - IDirectInputDeviceA_GetDeviceData, + SysMouseA_GetDeviceData, SysMouseA_SetDataFormat, IDirectInputDeviceA_SetEventNotification, - IDirectInputDeviceA_SetCooperativeLevel, + SysMouseA_SetCooperativeLevel, IDirectInputDeviceA_GetObjectInfo, IDirectInputDeviceA_GetDeviceInfo, IDirectInputDeviceA_RunControlPanel,