Pass the correct instance when installing the mouse hook (spotted by
[wine/multimedia.git] / dlls / dinput / mouse / main.c
blobf8b91ba158d5a1345af5748fa36898c535c0352f
1 /* DirectInput Mouse device
3 * Copyright 1998 Marcus Meissner
4 * Copyright 1998,1999 Lionel Ulmer
5 * Copyright 2000-2001 TransGaming Technologies Inc.
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "config.h"
23 #include "wine/port.h"
25 #include <string.h>
26 #ifdef HAVE_SYS_ERRNO_H
27 # include <sys/errno.h>
28 #endif
30 #include "winbase.h"
31 #include "wingdi.h"
32 #include "winuser.h"
33 #include "winerror.h"
34 #include "dinput.h"
36 #include "dinput_private.h"
37 #include "device_private.h"
38 #include "wine/debug.h"
40 #define MOUSE_HACK
42 WINE_DEFAULT_DEBUG_CHANNEL(dinput);
44 /* Wine mouse driver object instances */
45 #define WINE_MOUSE_X_AXIS_INSTANCE 0x0001
46 #define WINE_MOUSE_Y_AXIS_INSTANCE 0x0002
47 #define WINE_MOUSE_Z_AXIS_INSTANCE 0x0004
48 #define WINE_MOUSE_L_BUTTON_INSTANCE 0x0008
49 #define WINE_MOUSE_R_BUTTON_INSTANCE 0x0010
50 #define WINE_MOUSE_M_BUTTON_INSTANCE 0x0020
52 /* ------------------------------- */
53 /* Wine mouse internal data format */
54 /* ------------------------------- */
56 /* Constants used to access the offset array */
57 #define WINE_MOUSE_X_POSITION 0
58 #define WINE_MOUSE_Y_POSITION 1
59 #define WINE_MOUSE_Z_POSITION 2
60 #define WINE_MOUSE_L_POSITION 3
61 #define WINE_MOUSE_R_POSITION 4
62 #define WINE_MOUSE_M_POSITION 5
64 typedef struct {
65 LONG lX;
66 LONG lY;
67 LONG lZ;
68 BYTE rgbButtons[4];
69 } Wine_InternalMouseData;
71 #define WINE_INTERNALMOUSE_NUM_OBJS 6
73 static DIOBJECTDATAFORMAT Wine_InternalMouseObjectFormat[WINE_INTERNALMOUSE_NUM_OBJS] = {
74 { &GUID_XAxis, FIELD_OFFSET(Wine_InternalMouseData, lX),
75 DIDFT_MAKEINSTANCE(WINE_MOUSE_X_AXIS_INSTANCE) | DIDFT_RELAXIS, 0 },
76 { &GUID_YAxis, FIELD_OFFSET(Wine_InternalMouseData, lY),
77 DIDFT_MAKEINSTANCE(WINE_MOUSE_Y_AXIS_INSTANCE) | DIDFT_RELAXIS, 0 },
78 { &GUID_ZAxis, FIELD_OFFSET(Wine_InternalMouseData, lZ),
79 DIDFT_MAKEINSTANCE(WINE_MOUSE_Z_AXIS_INSTANCE) | DIDFT_RELAXIS, 0 },
80 { &GUID_Button, (FIELD_OFFSET(Wine_InternalMouseData, rgbButtons)) + 0,
81 DIDFT_MAKEINSTANCE(WINE_MOUSE_L_BUTTON_INSTANCE) | DIDFT_PSHBUTTON, 0 },
82 { &GUID_Button, (FIELD_OFFSET(Wine_InternalMouseData, rgbButtons)) + 1,
83 DIDFT_MAKEINSTANCE(WINE_MOUSE_R_BUTTON_INSTANCE) | DIDFT_PSHBUTTON, 0 },
84 { &GUID_Button, (FIELD_OFFSET(Wine_InternalMouseData, rgbButtons)) + 2,
85 DIDFT_MAKEINSTANCE(WINE_MOUSE_M_BUTTON_INSTANCE) | DIDFT_PSHBUTTON, 0 }
88 static DIDATAFORMAT Wine_InternalMouseFormat = {
89 0, /* dwSize - unused */
90 0, /* dwObjsize - unused */
91 0, /* dwFlags - unused */
92 sizeof(Wine_InternalMouseData),
93 WINE_INTERNALMOUSE_NUM_OBJS, /* dwNumObjs */
94 Wine_InternalMouseObjectFormat
97 static ICOM_VTABLE(IDirectInputDevice8A) SysMouseAvt;
98 typedef struct SysMouseAImpl SysMouseAImpl;
100 typedef enum {
101 WARP_NEEDED, /* Warping is needed */
102 WARP_STARTED, /* Warping has been done, waiting for the warp event */
103 WARP_DONE /* Warping has been done */
104 } WARP_STATUS;
106 struct SysMouseAImpl
108 LPVOID lpVtbl;
109 DWORD ref;
110 GUID guid;
112 IDirectInputAImpl *dinput;
114 /* The current data format and the conversion between internal
115 and external data formats */
116 LPDIDATAFORMAT df;
117 DataFormat *wine_df;
118 int offset_array[WINE_INTERNALMOUSE_NUM_OBJS];
120 /* SysMouseAImpl */
121 BYTE absolute;
122 /* Previous position for relative moves */
123 LONG prevX, prevY;
124 HHOOK hook;
125 HWND win;
126 DWORD dwCoopLevel;
127 POINT mapped_center;
128 DWORD win_centerX, win_centerY;
129 LPDIDEVICEOBJECTDATA data_queue;
130 int queue_head, queue_tail, queue_len;
131 /* warping: whether we need to move mouse back to middle once we
132 * reach window borders (for e.g. shooters, "surface movement" games) */
133 WARP_STATUS need_warp;
134 int acquired;
135 HANDLE hEvent;
136 CRITICAL_SECTION crit;
138 /* This is for mouse reporting. */
139 Wine_InternalMouseData m_state;
142 static GUID DInput_Wine_Mouse_GUID = { /* 9e573ed8-7734-11d2-8d4a-23903fb6bdf7 */
143 0x9e573ed8,
144 0x7734,
145 0x11d2,
146 {0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf7}
149 /* FIXME: This is ugly and not thread safe :/ */
150 static IDirectInputDevice8A* current_lock = NULL;
153 static BOOL mousedev_enum_device(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi)
155 if ((dwDevType == 0) || (dwDevType == DIDEVTYPE_MOUSE)) {
156 TRACE("Enumerating the mouse device\n");
158 /* Return mouse */
159 lpddi->guidInstance = GUID_SysMouse;/* DInput's GUID */
160 lpddi->guidProduct = DInput_Wine_Mouse_GUID; /* Vendor's GUID */
161 lpddi->dwDevType = DIDEVTYPE_MOUSE | (DIDEVTYPEMOUSE_UNKNOWN << 8);
162 strcpy(lpddi->tszInstanceName, "Mouse");
163 strcpy(lpddi->tszProductName, "Wine Mouse");
165 return TRUE;
168 return FALSE;
171 static SysMouseAImpl *alloc_device(REFGUID rguid, LPVOID mvt, IDirectInputAImpl *dinput)
173 int offset_array[WINE_INTERNALMOUSE_NUM_OBJS] = {
174 FIELD_OFFSET(Wine_InternalMouseData, lX),
175 FIELD_OFFSET(Wine_InternalMouseData, lY),
176 FIELD_OFFSET(Wine_InternalMouseData, lZ),
177 FIELD_OFFSET(Wine_InternalMouseData, rgbButtons) + 0,
178 FIELD_OFFSET(Wine_InternalMouseData, rgbButtons) + 1,
179 FIELD_OFFSET(Wine_InternalMouseData, rgbButtons) + 2
181 SysMouseAImpl* newDevice;
182 newDevice = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(SysMouseAImpl));
183 newDevice->ref = 1;
184 newDevice->lpVtbl = mvt;
185 InitializeCriticalSection(&(newDevice->crit));
186 memcpy(&(newDevice->guid),rguid,sizeof(*rguid));
188 /* Per default, Wine uses its internal data format */
189 newDevice->df = &Wine_InternalMouseFormat;
190 memcpy(newDevice->offset_array, offset_array, WINE_INTERNALMOUSE_NUM_OBJS * sizeof(int));
191 newDevice->wine_df = (DataFormat *) HeapAlloc(GetProcessHeap(), 0, sizeof(DataFormat));
192 newDevice->wine_df->size = 0;
193 newDevice->wine_df->internal_format_size = Wine_InternalMouseFormat.dwDataSize;
194 newDevice->wine_df->dt = NULL;
195 newDevice->dinput = dinput;
197 return newDevice;
200 static HRESULT mousedev_create_device(IDirectInputAImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEA* pdev)
202 if ((IsEqualGUID(&GUID_SysMouse,rguid)) || /* Generic Mouse */
203 (IsEqualGUID(&DInput_Wine_Mouse_GUID,rguid))) { /* Wine Mouse */
204 if ((riid == NULL) ||
205 IsEqualGUID(&IID_IDirectInputDeviceA,riid) ||
206 IsEqualGUID(&IID_IDirectInputDevice2A,riid) ||
207 IsEqualGUID(&IID_IDirectInputDevice7A,riid) ||
208 IsEqualGUID(&IID_IDirectInputDevice8A,riid)) {
209 *pdev=(IDirectInputDeviceA*) alloc_device(rguid, &SysMouseAvt, dinput);
210 TRACE("Creating a Mouse device (%p)\n", *pdev);
211 return DI_OK;
212 } else
213 return DIERR_NOINTERFACE;
216 return DIERR_DEVICENOTREG;
219 static dinput_device mousedev = {
220 100,
221 mousedev_enum_device,
222 mousedev_create_device
225 DECL_GLOBAL_CONSTRUCTOR(mousedev_register) { dinput_register_device(&mousedev); }
227 /******************************************************************************
228 * SysMouseA (DInput Mouse support)
231 /******************************************************************************
232 * Release : release the mouse buffer.
234 static ULONG WINAPI SysMouseAImpl_Release(LPDIRECTINPUTDEVICE8A iface)
236 ICOM_THIS(SysMouseAImpl,iface);
238 This->ref--;
239 if (This->ref)
240 return This->ref;
242 /* Free the data queue */
243 if (This->data_queue != NULL)
244 HeapFree(GetProcessHeap(),0,This->data_queue);
246 if (This->hook) {
247 UnhookWindowsHookEx( This->hook );
248 if (This->dwCoopLevel & DISCL_EXCLUSIVE)
249 ShowCursor(TRUE); /* show cursor */
251 DeleteCriticalSection(&(This->crit));
253 /* Free the DataFormat */
254 if (This->df != &(Wine_InternalMouseFormat)) {
255 HeapFree(GetProcessHeap(), 0, This->df->rgodf);
256 HeapFree(GetProcessHeap(), 0, This->df);
259 HeapFree(GetProcessHeap(),0,This);
260 return 0;
264 /******************************************************************************
265 * SetCooperativeLevel : store the window in which we will do our
266 * grabbing.
268 static HRESULT WINAPI SysMouseAImpl_SetCooperativeLevel(
269 LPDIRECTINPUTDEVICE8A iface,HWND hwnd,DWORD dwflags
272 ICOM_THIS(SysMouseAImpl,iface);
274 TRACE("(this=%p,0x%08lx,0x%08lx)\n",This,(DWORD)hwnd,dwflags);
276 if (TRACE_ON(dinput))
277 _dump_cooperativelevel_DI(dwflags);
279 /* Store the window which asks for the mouse */
280 if (!hwnd)
281 hwnd = GetDesktopWindow();
282 This->win = hwnd;
283 This->dwCoopLevel = dwflags;
285 return 0;
289 /******************************************************************************
290 * SetDataFormat : the application can choose the format of the data
291 * the device driver sends back with GetDeviceState.
293 * For the moment, only the "standard" configuration (c_dfDIMouse) is supported
294 * in absolute and relative mode.
296 static HRESULT WINAPI SysMouseAImpl_SetDataFormat(
297 LPDIRECTINPUTDEVICE8A iface,LPCDIDATAFORMAT df
300 ICOM_THIS(SysMouseAImpl,iface);
301 int i;
303 TRACE("(this=%p,%p)\n",This,df);
305 TRACE("(df.dwSize=%ld)\n",df->dwSize);
306 TRACE("(df.dwObjsize=%ld)\n",df->dwObjSize);
307 TRACE("(df.dwFlags=0x%08lx)\n",df->dwFlags);
308 TRACE("(df.dwDataSize=%ld)\n",df->dwDataSize);
309 TRACE("(df.dwNumObjs=%ld)\n",df->dwNumObjs);
311 for (i=0;i<df->dwNumObjs;i++) {
313 TRACE("df.rgodf[%d].guid %s (%p)\n",i, debugstr_guid(df->rgodf[i].pguid), df->rgodf[i].pguid);
314 TRACE("df.rgodf[%d].dwOfs %ld\n",i,df->rgodf[i].dwOfs);
315 TRACE("dwType 0x%02x,dwInstance %d\n",DIDFT_GETTYPE(df->rgodf[i].dwType),DIDFT_GETINSTANCE(df->rgodf[i].dwType));
316 TRACE("df.rgodf[%d].dwFlags 0x%08lx\n",i,df->rgodf[i].dwFlags);
319 /* Check if the mouse is in absolute or relative mode */
320 if (df->dwFlags == DIDF_ABSAXIS)
321 This->absolute = 1;
322 else if (df->dwFlags == DIDF_RELAXIS)
323 This->absolute = 0;
324 else
325 ERR("Neither absolute nor relative flag set\n");
327 /* Store the new data format */
328 This->df = HeapAlloc(GetProcessHeap(),0,df->dwSize);
329 memcpy(This->df, df, df->dwSize);
330 This->df->rgodf = HeapAlloc(GetProcessHeap(),0,df->dwNumObjs*df->dwObjSize);
331 memcpy(This->df->rgodf,df->rgodf,df->dwNumObjs*df->dwObjSize);
333 /* Prepare all the data-conversion filters */
334 This->wine_df = create_DataFormat(&(Wine_InternalMouseFormat), df, This->offset_array);
336 return 0;
339 /* low-level mouse hook */
340 static LRESULT CALLBACK dinput_mouse_hook( int code, WPARAM wparam, LPARAM lparam )
342 LRESULT ret;
343 MSLLHOOKSTRUCT *hook = (MSLLHOOKSTRUCT *)lparam;
344 SysMouseAImpl* This = (SysMouseAImpl*) current_lock;
345 DWORD dwCoop;
346 static long last_event = 0;
347 int wdata;
349 if (code != HC_ACTION) return CallNextHookEx( This->hook, code, wparam, lparam );
351 EnterCriticalSection(&(This->crit));
352 dwCoop = This->dwCoopLevel;
354 /* Only allow mouse events every 10 ms.
355 * This is to allow the cursor to start acceleration before
356 * the warps happen. But if it involves a mouse button event we
357 * allow it since we dont want to loose the clicks.
359 if (((GetCurrentTime() - last_event) < 10)
360 && wparam == WM_MOUSEMOVE)
361 goto end;
362 else last_event = GetCurrentTime();
364 /* Mouse moved -> send event if asked */
365 if (This->hEvent)
366 SetEvent(This->hEvent);
368 if (wparam == WM_MOUSEMOVE) {
369 if (This->absolute) {
370 if (hook->pt.x != This->prevX)
371 GEN_EVENT(This->offset_array[WINE_MOUSE_X_POSITION], hook->pt.x, hook->time, 0);
372 if (hook->pt.y != This->prevY)
373 GEN_EVENT(This->offset_array[WINE_MOUSE_Y_POSITION], hook->pt.y, hook->time, 0);
374 } else {
375 /* Now, warp handling */
376 if ((This->need_warp == WARP_STARTED) &&
377 (hook->pt.x == This->mapped_center.x) && (hook->pt.y == This->mapped_center.y)) {
378 /* Warp has been done... */
379 This->need_warp = WARP_DONE;
380 goto end;
383 /* Relative mouse input with absolute mouse event : the real fun starts here... */
384 if ((This->need_warp == WARP_NEEDED) ||
385 (This->need_warp == WARP_STARTED)) {
386 if (hook->pt.x != This->prevX)
387 GEN_EVENT(This->offset_array[WINE_MOUSE_X_POSITION], hook->pt.x - This->prevX, hook->time, (This->dinput->evsequence)++);
388 if (hook->pt.y != This->prevY)
389 GEN_EVENT(This->offset_array[WINE_MOUSE_Y_POSITION], hook->pt.y - This->prevY, hook->time, (This->dinput->evsequence)++);
390 } else {
391 /* This is the first time the event handler has been called after a
392 GetDeviceData or GetDeviceState. */
393 if (hook->pt.x != This->mapped_center.x) {
394 GEN_EVENT(This->offset_array[WINE_MOUSE_X_POSITION], hook->pt.x - This->mapped_center.x, hook->time, (This->dinput->evsequence)++);
395 This->need_warp = WARP_NEEDED;
398 if (hook->pt.y != This->mapped_center.y) {
399 GEN_EVENT(This->offset_array[WINE_MOUSE_Y_POSITION], hook->pt.y - This->mapped_center.y, hook->time, (This->dinput->evsequence)++);
400 This->need_warp = WARP_NEEDED;
405 This->prevX = hook->pt.x;
406 This->prevY = hook->pt.y;
408 if (This->absolute) {
409 This->m_state.lX = hook->pt.x;
410 This->m_state.lY = hook->pt.y;
411 } else {
412 This->m_state.lX = hook->pt.x - This->mapped_center.x;
413 This->m_state.lY = hook->pt.y - This->mapped_center.y;
417 TRACE(" msg %x pt %ld %ld (W=%d)\n",
418 wparam, hook->pt.x, hook->pt.y, (!This->absolute) && This->need_warp );
420 switch(wparam)
422 case WM_LBUTTONDOWN:
423 GEN_EVENT(This->offset_array[WINE_MOUSE_L_POSITION], 0xFF,
424 hook->time, This->dinput->evsequence++);
425 This->m_state.rgbButtons[0] = 0xFF;
426 break;
427 case WM_LBUTTONUP:
428 GEN_EVENT(This->offset_array[WINE_MOUSE_L_POSITION], 0x00,
429 hook->time, This->dinput->evsequence++);
430 This->m_state.rgbButtons[0] = 0x00;
431 break;
432 case WM_RBUTTONDOWN:
433 GEN_EVENT(This->offset_array[WINE_MOUSE_R_POSITION], 0xFF,
434 hook->time, This->dinput->evsequence++);
435 This->m_state.rgbButtons[1] = 0xFF;
436 break;
437 case WM_RBUTTONUP:
438 GEN_EVENT(This->offset_array[WINE_MOUSE_R_POSITION], 0x00,
439 hook->time, This->dinput->evsequence++);
440 This->m_state.rgbButtons[1] = 0x00;
441 break;
442 case WM_MBUTTONDOWN:
443 GEN_EVENT(This->offset_array[WINE_MOUSE_M_POSITION], 0xFF,
444 hook->time, This->dinput->evsequence++);
445 This->m_state.rgbButtons[2] = 0xFF;
446 break;
447 case WM_MBUTTONUP:
448 GEN_EVENT(This->offset_array[WINE_MOUSE_M_POSITION], 0x00,
449 hook->time, This->dinput->evsequence++);
450 This->m_state.rgbButtons[2] = 0x00;
451 break;
452 case WM_MOUSEWHEEL:
453 wdata = (short)HIWORD(hook->mouseData);
454 GEN_EVENT(This->offset_array[WINE_MOUSE_Z_POSITION], wdata,
455 hook->time, This->dinput->evsequence++);
456 This->m_state.lZ += wdata;
457 break;
460 TRACE("(X: %ld - Y: %ld L: %02x M: %02x R: %02x)\n",
461 This->m_state.lX, This->m_state.lY,
462 This->m_state.rgbButtons[0], This->m_state.rgbButtons[2], This->m_state.rgbButtons[1]);
464 end:
465 LeaveCriticalSection(&(This->crit));
467 if (dwCoop & DISCL_NONEXCLUSIVE)
468 { /* pass the events down to previous handlers (e.g. win32 input) */
469 ret = CallNextHookEx( This->hook, code, wparam, lparam );
471 else ret = 1; /* ignore message */
472 return ret;
476 static void dinput_window_check(SysMouseAImpl* This)
478 RECT rect;
479 DWORD centerX, centerY;
481 /* make sure the window hasn't moved */
482 GetWindowRect(This->win, &rect);
483 centerX = (rect.right - rect.left) / 2;
484 centerY = (rect.bottom - rect.top ) / 2;
485 if (This->win_centerX != centerX || This->win_centerY != centerY) {
486 This->win_centerX = centerX;
487 This->win_centerY = centerY;
489 This->mapped_center.x = This->win_centerX;
490 This->mapped_center.y = This->win_centerY;
491 MapWindowPoints(This->win, HWND_DESKTOP, &This->mapped_center, 1);
495 /******************************************************************************
496 * Acquire : gets exclusive control of the mouse
498 static HRESULT WINAPI SysMouseAImpl_Acquire(LPDIRECTINPUTDEVICE8A iface)
500 ICOM_THIS(SysMouseAImpl,iface);
501 RECT rect;
503 TRACE("(this=%p)\n",This);
505 if (This->acquired == 0) {
506 POINT point;
508 /* Store (in a global variable) the current lock */
509 current_lock = (IDirectInputDevice8A*)This;
511 /* Init the mouse state */
512 if (This->absolute) {
513 GetCursorPos( &point );
514 This->m_state.lX = point.x;
515 This->m_state.lY = point.y;
516 This->prevX = point.x;
517 This->prevY = point.y;
518 } else {
519 This->m_state.lX = 0;
520 This->m_state.lY = 0;
522 This->m_state.lZ = 0;
523 This->m_state.rgbButtons[0] = (GetKeyState(VK_LBUTTON) ? 0xFF : 0x00);
524 This->m_state.rgbButtons[1] = (GetKeyState(VK_MBUTTON) ? 0xFF : 0x00);
525 This->m_state.rgbButtons[2] = (GetKeyState(VK_RBUTTON) ? 0xFF : 0x00);
527 /* Install our mouse hook */
528 if (This->dwCoopLevel & DISCL_EXCLUSIVE)
529 ShowCursor(FALSE); /* hide cursor */
530 This->hook = SetWindowsHookExA( WH_MOUSE_LL, dinput_mouse_hook, DINPUT_instance, 0 );
532 /* Get the window dimension and find the center */
533 GetWindowRect(This->win, &rect);
534 This->win_centerX = (rect.right - rect.left) / 2;
535 This->win_centerY = (rect.bottom - rect.top ) / 2;
537 /* Warp the mouse to the center of the window */
538 if (This->absolute == 0) {
539 This->mapped_center.x = This->win_centerX;
540 This->mapped_center.y = This->win_centerY;
541 MapWindowPoints(This->win, HWND_DESKTOP, &This->mapped_center, 1);
542 TRACE("Warping mouse to %ld - %ld\n", This->mapped_center.x, This->mapped_center.y);
543 SetCursorPos( This->mapped_center.x, This->mapped_center.y );
544 #ifdef MOUSE_HACK
545 This->need_warp = WARP_DONE;
546 #else
547 This->need_warp = WARP_STARTED;
548 #endif
551 This->acquired = 1;
552 return DI_OK;
554 return S_FALSE;
557 /******************************************************************************
558 * Unacquire : frees the mouse
560 static HRESULT WINAPI SysMouseAImpl_Unacquire(LPDIRECTINPUTDEVICE8A iface)
562 ICOM_THIS(SysMouseAImpl,iface);
564 TRACE("(this=%p)\n",This);
566 if (This->acquired)
568 /* Reinstall previous mouse event handler */
569 if (This->hook) {
570 UnhookWindowsHookEx( This->hook );
571 This->hook = 0;
572 if (This->dwCoopLevel & DISCL_EXCLUSIVE)
573 ShowCursor(TRUE); /* show cursor */
576 /* No more locks */
577 current_lock = NULL;
579 /* Unacquire device */
580 This->acquired = 0;
582 else
583 ERR("Unacquiring a not-acquired device !!!\n");
585 return DI_OK;
588 /******************************************************************************
589 * GetDeviceState : returns the "state" of the mouse.
591 * For the moment, only the "standard" return structure (DIMOUSESTATE) is
592 * supported.
594 static HRESULT WINAPI SysMouseAImpl_GetDeviceState(
595 LPDIRECTINPUTDEVICE8A iface,DWORD len,LPVOID ptr
597 ICOM_THIS(SysMouseAImpl,iface);
599 EnterCriticalSection(&(This->crit));
600 TRACE("(this=%p,0x%08lx,%p): \n",This,len,ptr);
602 /* Copy the current mouse state */
603 fill_DataFormat(ptr, &(This->m_state), This->wine_df);
605 /* Initialize the buffer when in relative mode */
606 if (This->absolute == 0) {
607 This->m_state.lX = 0;
608 This->m_state.lY = 0;
609 This->m_state.lZ = 0;
612 /* Check if we need to do a mouse warping */
613 if (This->need_warp == WARP_NEEDED) {
614 dinput_window_check(This);
615 TRACE("Warping mouse to %ld - %ld\n", This->mapped_center.x, This->mapped_center.y);
616 SetCursorPos( This->mapped_center.x, This->mapped_center.y );
618 #ifdef MOUSE_HACK
619 This->need_warp = WARP_DONE;
620 #else
621 This->need_warp = WARP_STARTED;
622 #endif
625 LeaveCriticalSection(&(This->crit));
627 TRACE("(X: %ld - Y: %ld L: %02x M: %02x R: %02x)\n",
628 This->m_state.lX, This->m_state.lY,
629 This->m_state.rgbButtons[0], This->m_state.rgbButtons[2], This->m_state.rgbButtons[1]);
631 return 0;
634 /******************************************************************************
635 * GetDeviceState : gets buffered input data.
637 static HRESULT WINAPI SysMouseAImpl_GetDeviceData(LPDIRECTINPUTDEVICE8A iface,
638 DWORD dodsize,
639 LPDIDEVICEOBJECTDATA dod,
640 LPDWORD entries,
641 DWORD flags
643 ICOM_THIS(SysMouseAImpl,iface);
644 DWORD len, nqtail;
646 EnterCriticalSection(&(This->crit));
647 TRACE("(%p)->(dods=%ld,entries=%ld,fl=0x%08lx)\n",This,dodsize,*entries,flags);
649 len = ((This->queue_head < This->queue_tail) ? This->queue_len : 0)
650 + (This->queue_head - This->queue_tail);
651 if (len > *entries) len = *entries;
653 if (dod == NULL) {
654 if (len)
655 TRACE("Application discarding %ld event(s).\n", len);
657 *entries = len;
658 nqtail = This->queue_tail + len;
659 while (nqtail >= This->queue_len) nqtail -= This->queue_len;
660 } else {
661 if (dodsize < sizeof(DIDEVICEOBJECTDATA)) {
662 ERR("Wrong structure size !\n");
663 LeaveCriticalSection(&(This->crit));
664 return DIERR_INVALIDPARAM;
667 if (len)
668 TRACE("Application retrieving %ld event(s).\n", len);
670 *entries = 0;
671 nqtail = This->queue_tail;
672 while (len) {
673 DWORD span = ((This->queue_head < nqtail) ? This->queue_len : This->queue_head)
674 - nqtail;
675 if (span > len) span = len;
676 /* Copy the buffered data into the application queue */
677 memcpy(dod + *entries, This->data_queue + nqtail, span * dodsize);
678 /* Advance position */
679 nqtail += span;
680 if (nqtail >= This->queue_len) nqtail -= This->queue_len;
681 *entries += span;
682 len -= span;
685 if (!(flags & DIGDD_PEEK))
686 This->queue_tail = nqtail;
688 LeaveCriticalSection(&(This->crit));
690 /* Check if we need to do a mouse warping */
691 if (This->need_warp == WARP_NEEDED) {
692 dinput_window_check(This);
693 TRACE("Warping mouse to %ld - %ld\n", This->mapped_center.x, This->mapped_center.y);
694 SetCursorPos( This->mapped_center.x, This->mapped_center.y );
696 #ifdef MOUSE_HACK
697 This->need_warp = WARP_DONE;
698 #else
699 This->need_warp = WARP_STARTED;
700 #endif
702 return 0;
705 /******************************************************************************
706 * SetProperty : change input device properties
708 static HRESULT WINAPI SysMouseAImpl_SetProperty(LPDIRECTINPUTDEVICE8A iface,
709 REFGUID rguid,
710 LPCDIPROPHEADER ph)
712 ICOM_THIS(SysMouseAImpl,iface);
714 TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(rguid),ph);
716 if (!HIWORD(rguid)) {
717 switch ((DWORD)rguid) {
718 case (DWORD) DIPROP_BUFFERSIZE: {
719 LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph;
721 TRACE("buffersize = %ld\n",pd->dwData);
723 This->data_queue = (LPDIDEVICEOBJECTDATA)HeapAlloc(GetProcessHeap(),0,
724 pd->dwData * sizeof(DIDEVICEOBJECTDATA));
725 This->queue_head = 0;
726 This->queue_tail = 0;
727 This->queue_len = pd->dwData;
728 break;
730 case (DWORD) DIPROP_AXISMODE: {
731 LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph;
732 This->absolute = !(pd->dwData);
733 TRACE("Using %s coordinates mode now\n", This->absolute ? "absolute" : "relative");
734 break;
736 default:
737 FIXME("Unknown type %ld (%s)\n",(DWORD)rguid,debugstr_guid(rguid));
738 break;
742 return 0;
745 /******************************************************************************
746 * GetProperty : get input device properties
748 static HRESULT WINAPI SysMouseAImpl_GetProperty(LPDIRECTINPUTDEVICE8A iface,
749 REFGUID rguid,
750 LPDIPROPHEADER pdiph)
752 ICOM_THIS(SysMouseAImpl,iface);
754 TRACE("(this=%p,%s,%p): stub!\n",
755 iface, debugstr_guid(rguid), pdiph);
757 if (TRACE_ON(dinput))
758 _dump_DIPROPHEADER(pdiph);
760 if (!HIWORD(rguid)) {
761 switch ((DWORD)rguid) {
762 case (DWORD) DIPROP_BUFFERSIZE: {
763 LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph;
765 TRACE(" return buffersize = %d\n",This->queue_len);
766 pd->dwData = This->queue_len;
767 break;
770 case (DWORD) DIPROP_GRANULARITY: {
771 LPDIPROPDWORD pr = (LPDIPROPDWORD) pdiph;
773 /* We'll just assume that the app asks about the Z axis */
774 pr->dwData = WHEEL_DELTA;
776 break;
779 case (DWORD) DIPROP_RANGE: {
780 LPDIPROPRANGE pr = (LPDIPROPRANGE) pdiph;
782 if ((pdiph->dwHow == DIPH_BYID) &&
783 ((pdiph->dwObj == (DIDFT_MAKEINSTANCE(WINE_MOUSE_X_AXIS_INSTANCE) | DIDFT_RELAXIS)) ||
784 (pdiph->dwObj == (DIDFT_MAKEINSTANCE(WINE_MOUSE_Y_AXIS_INSTANCE) | DIDFT_RELAXIS)))) {
785 /* Querying the range of either the X or the Y axis. As I do
786 not know the range, do as if the range were
787 unrestricted...*/
788 pr->lMin = DIPROPRANGE_NOMIN;
789 pr->lMax = DIPROPRANGE_NOMAX;
792 break;
795 default:
796 FIXME("Unknown type %ld (%s)\n",(DWORD)rguid,debugstr_guid(rguid));
797 break;
802 return DI_OK;
807 /******************************************************************************
808 * SetEventNotification : specifies event to be sent on state change
810 static HRESULT WINAPI SysMouseAImpl_SetEventNotification(LPDIRECTINPUTDEVICE8A iface,
811 HANDLE hnd) {
812 ICOM_THIS(SysMouseAImpl,iface);
814 TRACE("(this=%p,0x%08lx)\n",This,(DWORD)hnd);
816 This->hEvent = hnd;
818 return DI_OK;
821 /******************************************************************************
822 * GetCapabilities : get the device capablitites
824 static HRESULT WINAPI SysMouseAImpl_GetCapabilities(
825 LPDIRECTINPUTDEVICE8A iface,
826 LPDIDEVCAPS lpDIDevCaps)
828 ICOM_THIS(SysMouseAImpl,iface);
830 TRACE("(this=%p,%p)\n",This,lpDIDevCaps);
832 if (lpDIDevCaps->dwSize == sizeof(DIDEVCAPS)) {
833 lpDIDevCaps->dwFlags = DIDC_ATTACHED;
834 lpDIDevCaps->dwDevType = DIDEVTYPE_MOUSE;
835 lpDIDevCaps->dwAxes = 3;
836 lpDIDevCaps->dwButtons = 3;
837 lpDIDevCaps->dwPOVs = 0;
838 lpDIDevCaps->dwFFSamplePeriod = 0;
839 lpDIDevCaps->dwFFMinTimeResolution = 0;
840 lpDIDevCaps->dwFirmwareRevision = 100;
841 lpDIDevCaps->dwHardwareRevision = 100;
842 lpDIDevCaps->dwFFDriverVersion = 0;
843 } else {
844 /* DirectX 3.0 */
845 FIXME("DirectX 3.0 not supported....\n");
848 return DI_OK;
852 /******************************************************************************
853 * EnumObjects : enumerate the different buttons and axis...
855 static HRESULT WINAPI SysMouseAImpl_EnumObjects(
856 LPDIRECTINPUTDEVICE8A iface,
857 LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback,
858 LPVOID lpvRef,
859 DWORD dwFlags)
861 ICOM_THIS(SysMouseAImpl,iface);
862 DIDEVICEOBJECTINSTANCEA ddoi;
864 TRACE("(this=%p,%p,%p,%08lx)\n", This, lpCallback, lpvRef, dwFlags);
865 if (TRACE_ON(dinput)) {
866 DPRINTF(" - flags = ");
867 _dump_EnumObjects_flags(dwFlags);
868 DPRINTF("\n");
871 /* Only the fields till dwFFMaxForce are relevant */
872 ddoi.dwSize = FIELD_OFFSET(DIDEVICEOBJECTINSTANCEA, dwFFMaxForce);
874 /* In a mouse, we have : two relative axis and three buttons */
875 if ((dwFlags == DIDFT_ALL) ||
876 (dwFlags & DIDFT_AXIS)) {
877 /* X axis */
878 ddoi.guidType = GUID_XAxis;
879 ddoi.dwOfs = This->offset_array[WINE_MOUSE_X_POSITION];
880 ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_X_AXIS_INSTANCE) | DIDFT_RELAXIS;
881 strcpy(ddoi.tszName, "X-Axis");
882 _dump_OBJECTINSTANCEA(&ddoi);
883 if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
885 /* Y axis */
886 ddoi.guidType = GUID_YAxis;
887 ddoi.dwOfs = This->offset_array[WINE_MOUSE_Y_POSITION];
888 ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_Y_AXIS_INSTANCE) | DIDFT_RELAXIS;
889 strcpy(ddoi.tszName, "Y-Axis");
890 _dump_OBJECTINSTANCEA(&ddoi);
891 if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
893 /* Z axis */
894 ddoi.guidType = GUID_ZAxis;
895 ddoi.dwOfs = This->offset_array[WINE_MOUSE_Z_POSITION];
896 ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_Z_AXIS_INSTANCE) | DIDFT_RELAXIS;
897 strcpy(ddoi.tszName, "Z-Axis");
898 _dump_OBJECTINSTANCEA(&ddoi);
899 if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
902 if ((dwFlags == DIDFT_ALL) ||
903 (dwFlags & DIDFT_BUTTON)) {
904 ddoi.guidType = GUID_Button;
906 /* Left button */
907 ddoi.dwOfs = This->offset_array[WINE_MOUSE_L_POSITION];
908 ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_L_BUTTON_INSTANCE) | DIDFT_PSHBUTTON;
909 strcpy(ddoi.tszName, "Left-Button");
910 _dump_OBJECTINSTANCEA(&ddoi);
911 if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
913 /* Right button */
914 ddoi.dwOfs = This->offset_array[WINE_MOUSE_R_POSITION];
915 ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_R_BUTTON_INSTANCE) | DIDFT_PSHBUTTON;
916 strcpy(ddoi.tszName, "Right-Button");
917 _dump_OBJECTINSTANCEA(&ddoi);
918 if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
920 /* Middle button */
921 ddoi.dwOfs = This->offset_array[WINE_MOUSE_M_POSITION];
922 ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_M_BUTTON_INSTANCE) | DIDFT_PSHBUTTON;
923 strcpy(ddoi.tszName, "Middle-Button");
924 _dump_OBJECTINSTANCEA(&ddoi);
925 if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
928 return DI_OK;
932 static ICOM_VTABLE(IDirectInputDevice8A) SysMouseAvt =
934 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
935 IDirectInputDevice2AImpl_QueryInterface,
936 IDirectInputDevice2AImpl_AddRef,
937 SysMouseAImpl_Release,
938 SysMouseAImpl_GetCapabilities,
939 SysMouseAImpl_EnumObjects,
940 SysMouseAImpl_GetProperty,
941 SysMouseAImpl_SetProperty,
942 SysMouseAImpl_Acquire,
943 SysMouseAImpl_Unacquire,
944 SysMouseAImpl_GetDeviceState,
945 SysMouseAImpl_GetDeviceData,
946 SysMouseAImpl_SetDataFormat,
947 SysMouseAImpl_SetEventNotification,
948 SysMouseAImpl_SetCooperativeLevel,
949 IDirectInputDevice2AImpl_GetObjectInfo,
950 IDirectInputDevice2AImpl_GetDeviceInfo,
951 IDirectInputDevice2AImpl_RunControlPanel,
952 IDirectInputDevice2AImpl_Initialize,
953 IDirectInputDevice2AImpl_CreateEffect,
954 IDirectInputDevice2AImpl_EnumEffects,
955 IDirectInputDevice2AImpl_GetEffectInfo,
956 IDirectInputDevice2AImpl_GetForceFeedbackState,
957 IDirectInputDevice2AImpl_SendForceFeedbackCommand,
958 IDirectInputDevice2AImpl_EnumCreatedEffectObjects,
959 IDirectInputDevice2AImpl_Escape,
960 IDirectInputDevice2AImpl_Poll,
961 IDirectInputDevice2AImpl_SendDeviceData,
962 IDirectInputDevice7AImpl_EnumEffectsInFile,
963 IDirectInputDevice7AImpl_WriteEffectToFile,
964 IDirectInputDevice8AImpl_BuildActionMap,
965 IDirectInputDevice8AImpl_SetActionMap,
966 IDirectInputDevice8AImpl_GetImageInfo