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
24 #ifdef HAVE_SYS_ERRNO_H
25 # include <sys/errno.h>
34 #include "dinput_private.h"
35 #include "device_private.h"
36 #include "wine/debug.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(dinput);
42 /* Wine mouse driver object instances */
43 #define WINE_MOUSE_X_AXIS_INSTANCE 0x0001
44 #define WINE_MOUSE_Y_AXIS_INSTANCE 0x0002
45 #define WINE_MOUSE_Z_AXIS_INSTANCE 0x0004
46 #define WINE_MOUSE_L_BUTTON_INSTANCE 0x0008
47 #define WINE_MOUSE_R_BUTTON_INSTANCE 0x0010
48 #define WINE_MOUSE_M_BUTTON_INSTANCE 0x0020
50 /* ------------------------------- */
51 /* Wine mouse internal data format */
52 /* ------------------------------- */
54 /* Constants used to access the offset array */
55 #define WINE_MOUSE_X_POSITION 0
56 #define WINE_MOUSE_Y_POSITION 1
57 #define WINE_MOUSE_Z_POSITION 2
58 #define WINE_MOUSE_L_POSITION 3
59 #define WINE_MOUSE_R_POSITION 4
60 #define WINE_MOUSE_M_POSITION 5
67 } Wine_InternalMouseData;
69 #define WINE_INTERNALMOUSE_NUM_OBJS 6
71 static DIOBJECTDATAFORMAT Wine_InternalMouseObjectFormat[WINE_INTERNALMOUSE_NUM_OBJS] = {
72 { &GUID_XAxis, FIELD_OFFSET(Wine_InternalMouseData, lX),
73 DIDFT_MAKEINSTANCE(WINE_MOUSE_X_AXIS_INSTANCE) | DIDFT_RELAXIS, 0 },
74 { &GUID_YAxis, FIELD_OFFSET(Wine_InternalMouseData, lY),
75 DIDFT_MAKEINSTANCE(WINE_MOUSE_Y_AXIS_INSTANCE) | DIDFT_RELAXIS, 0 },
76 { &GUID_ZAxis, FIELD_OFFSET(Wine_InternalMouseData, lZ),
77 DIDFT_MAKEINSTANCE(WINE_MOUSE_Z_AXIS_INSTANCE) | DIDFT_RELAXIS, 0 },
78 { &GUID_Button, (FIELD_OFFSET(Wine_InternalMouseData, rgbButtons)) + 0,
79 DIDFT_MAKEINSTANCE(WINE_MOUSE_L_BUTTON_INSTANCE) | DIDFT_PSHBUTTON, 0 },
80 { &GUID_Button, (FIELD_OFFSET(Wine_InternalMouseData, rgbButtons)) + 1,
81 DIDFT_MAKEINSTANCE(WINE_MOUSE_R_BUTTON_INSTANCE) | DIDFT_PSHBUTTON, 0 },
82 { &GUID_Button, (FIELD_OFFSET(Wine_InternalMouseData, rgbButtons)) + 2,
83 DIDFT_MAKEINSTANCE(WINE_MOUSE_M_BUTTON_INSTANCE) | DIDFT_PSHBUTTON, 0 }
86 static DIDATAFORMAT Wine_InternalMouseFormat = {
87 0, /* dwSize - unused */
88 0, /* dwObjsize - unused */
89 0, /* dwFlags - unused */
90 sizeof(Wine_InternalMouseData),
91 WINE_INTERNALMOUSE_NUM_OBJS, /* dwNumObjs */
92 Wine_InternalMouseObjectFormat
95 static ICOM_VTABLE(IDirectInputDevice8A) SysMouseAvt;
96 typedef struct SysMouseAImpl SysMouseAImpl;
99 WARP_NEEDED, /* Warping is needed */
100 WARP_STARTED, /* Warping has been done, waiting for the warp event */
101 WARP_DONE /* Warping has been done */
110 IDirectInputAImpl *dinput;
112 /* The current data format and the conversion between internal
113 and external data formats */
116 int offset_array[WINE_INTERNALMOUSE_NUM_OBJS];
120 /* Previous position for relative moves */
126 DWORD win_centerX, win_centerY;
127 LPDIDEVICEOBJECTDATA data_queue;
128 int queue_head, queue_tail, queue_len;
129 /* warping: whether we need to move mouse back to middle once we
130 * reach window borders (for e.g. shooters, "surface movement" games) */
131 WARP_STATUS need_warp;
134 CRITICAL_SECTION crit;
136 /* This is for mouse reporting. */
137 Wine_InternalMouseData m_state;
140 static GUID DInput_Wine_Mouse_GUID = { /* 9e573ed8-7734-11d2-8d4a-23903fb6bdf7 */
144 {0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf7}
147 /* FIXME: This is ugly and not thread safe :/ */
148 static IDirectInputDevice8A* current_lock = NULL;
151 static BOOL mousedev_enum_device(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi)
153 if ((dwDevType == 0) || (dwDevType == DIDEVTYPE_MOUSE)) {
154 TRACE("Enumerating the mouse device\n");
157 lpddi->guidInstance = GUID_SysMouse;/* DInput's GUID */
158 lpddi->guidProduct = DInput_Wine_Mouse_GUID; /* Vendor's GUID */
159 lpddi->dwDevType = DIDEVTYPE_MOUSE | (DIDEVTYPEMOUSE_UNKNOWN << 8);
160 strcpy(lpddi->tszInstanceName, "Mouse");
161 strcpy(lpddi->tszProductName, "Wine Mouse");
169 static SysMouseAImpl *alloc_device(REFGUID rguid, LPVOID mvt, IDirectInputAImpl *dinput)
171 int offset_array[WINE_INTERNALMOUSE_NUM_OBJS] = {
172 FIELD_OFFSET(Wine_InternalMouseData, lX),
173 FIELD_OFFSET(Wine_InternalMouseData, lY),
174 FIELD_OFFSET(Wine_InternalMouseData, lZ),
175 FIELD_OFFSET(Wine_InternalMouseData, rgbButtons) + 0,
176 FIELD_OFFSET(Wine_InternalMouseData, rgbButtons) + 1,
177 FIELD_OFFSET(Wine_InternalMouseData, rgbButtons) + 2
179 SysMouseAImpl* newDevice;
180 newDevice = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(SysMouseAImpl));
182 newDevice->lpVtbl = mvt;
183 InitializeCriticalSection(&(newDevice->crit));
184 memcpy(&(newDevice->guid),rguid,sizeof(*rguid));
186 /* Per default, Wine uses its internal data format */
187 newDevice->df = &Wine_InternalMouseFormat;
188 memcpy(newDevice->offset_array, offset_array, WINE_INTERNALMOUSE_NUM_OBJS * sizeof(int));
189 newDevice->wine_df = (DataFormat *) HeapAlloc(GetProcessHeap(), 0, sizeof(DataFormat));
190 newDevice->wine_df->size = 0;
191 newDevice->wine_df->internal_format_size = Wine_InternalMouseFormat.dwDataSize;
192 newDevice->wine_df->dt = NULL;
193 newDevice->dinput = dinput;
198 static HRESULT mousedev_create_device(IDirectInputAImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEA* pdev)
200 if ((IsEqualGUID(&GUID_SysMouse,rguid)) || /* Generic Mouse */
201 (IsEqualGUID(&DInput_Wine_Mouse_GUID,rguid))) { /* Wine Mouse */
202 if ((riid == NULL) ||
203 IsEqualGUID(&IID_IDirectInputDeviceA,riid) ||
204 IsEqualGUID(&IID_IDirectInputDevice2A,riid) ||
205 IsEqualGUID(&IID_IDirectInputDevice7A,riid) ||
206 IsEqualGUID(&IID_IDirectInputDevice8A,riid)) {
207 *pdev=(IDirectInputDeviceA*) alloc_device(rguid, &SysMouseAvt, dinput);
208 TRACE("Creating a Mouse device (%p)\n", *pdev);
211 return DIERR_NOINTERFACE;
214 return DIERR_DEVICENOTREG;
217 static dinput_device mousedev = {
219 mousedev_enum_device,
220 mousedev_create_device
223 DECL_GLOBAL_CONSTRUCTOR(mousedev_register) { dinput_register_device(&mousedev); }
225 /******************************************************************************
226 * SysMouseA (DInput Mouse support)
229 /******************************************************************************
230 * Release : release the mouse buffer.
232 static ULONG WINAPI SysMouseAImpl_Release(LPDIRECTINPUTDEVICE8A iface)
234 ICOM_THIS(SysMouseAImpl,iface);
240 /* Free the data queue */
241 if (This->data_queue != NULL)
242 HeapFree(GetProcessHeap(),0,This->data_queue);
245 UnhookWindowsHookEx( This->hook );
246 if (This->dwCoopLevel & DISCL_EXCLUSIVE)
247 ShowCursor(TRUE); /* show cursor */
249 DeleteCriticalSection(&(This->crit));
251 /* Free the DataFormat */
252 if (This->df != &(Wine_InternalMouseFormat)) {
253 HeapFree(GetProcessHeap(), 0, This->df->rgodf);
254 HeapFree(GetProcessHeap(), 0, This->df);
257 HeapFree(GetProcessHeap(),0,This);
262 /******************************************************************************
263 * SetCooperativeLevel : store the window in which we will do our
266 static HRESULT WINAPI SysMouseAImpl_SetCooperativeLevel(
267 LPDIRECTINPUTDEVICE8A iface,HWND hwnd,DWORD dwflags
270 ICOM_THIS(SysMouseAImpl,iface);
272 TRACE("(this=%p,0x%08lx,0x%08lx)\n",This,(DWORD)hwnd,dwflags);
274 if (TRACE_ON(dinput))
275 _dump_cooperativelevel_DI(dwflags);
277 /* Store the window which asks for the mouse */
279 hwnd = GetDesktopWindow();
281 This->dwCoopLevel = dwflags;
287 /******************************************************************************
288 * SetDataFormat : the application can choose the format of the data
289 * the device driver sends back with GetDeviceState.
291 * For the moment, only the "standard" configuration (c_dfDIMouse) is supported
292 * in absolute and relative mode.
294 static HRESULT WINAPI SysMouseAImpl_SetDataFormat(
295 LPDIRECTINPUTDEVICE8A iface,LPCDIDATAFORMAT df
298 ICOM_THIS(SysMouseAImpl,iface);
301 TRACE("(this=%p,%p)\n",This,df);
303 TRACE("(df.dwSize=%ld)\n",df->dwSize);
304 TRACE("(df.dwObjsize=%ld)\n",df->dwObjSize);
305 TRACE("(df.dwFlags=0x%08lx)\n",df->dwFlags);
306 TRACE("(df.dwDataSize=%ld)\n",df->dwDataSize);
307 TRACE("(df.dwNumObjs=%ld)\n",df->dwNumObjs);
309 for (i=0;i<df->dwNumObjs;i++) {
311 TRACE("df.rgodf[%d].guid %s (%p)\n",i, debugstr_guid(df->rgodf[i].pguid), df->rgodf[i].pguid);
312 TRACE("df.rgodf[%d].dwOfs %ld\n",i,df->rgodf[i].dwOfs);
313 TRACE("dwType 0x%02x,dwInstance %d\n",DIDFT_GETTYPE(df->rgodf[i].dwType),DIDFT_GETINSTANCE(df->rgodf[i].dwType));
314 TRACE("df.rgodf[%d].dwFlags 0x%08lx\n",i,df->rgodf[i].dwFlags);
317 /* Check if the mouse is in absolute or relative mode */
318 if (df->dwFlags == DIDF_ABSAXIS)
320 else if (df->dwFlags == DIDF_RELAXIS)
323 ERR("Neither absolute nor relative flag set\n");
325 /* Store the new data format */
326 This->df = HeapAlloc(GetProcessHeap(),0,df->dwSize);
327 memcpy(This->df, df, df->dwSize);
328 This->df->rgodf = HeapAlloc(GetProcessHeap(),0,df->dwNumObjs*df->dwObjSize);
329 memcpy(This->df->rgodf,df->rgodf,df->dwNumObjs*df->dwObjSize);
331 /* Prepare all the data-conversion filters */
332 This->wine_df = create_DataFormat(&(Wine_InternalMouseFormat), df, This->offset_array);
337 /* low-level mouse hook */
338 static LRESULT CALLBACK dinput_mouse_hook( int code, WPARAM wparam, LPARAM lparam )
341 MSLLHOOKSTRUCT *hook = (MSLLHOOKSTRUCT *)lparam;
342 SysMouseAImpl* This = (SysMouseAImpl*) current_lock;
344 static long last_event = 0;
347 if (code != HC_ACTION) return CallNextHookEx( This->hook, code, wparam, lparam );
349 EnterCriticalSection(&(This->crit));
350 dwCoop = This->dwCoopLevel;
352 /* Only allow mouse events every 10 ms.
353 * This is to allow the cursor to start acceleration before
354 * the warps happen. But if it involves a mouse button event we
355 * allow it since we dont want to loose the clicks.
357 if (((GetCurrentTime() - last_event) < 10)
358 && wparam == WM_MOUSEMOVE)
360 else last_event = GetCurrentTime();
362 /* Mouse moved -> send event if asked */
364 SetEvent(This->hEvent);
366 if (wparam == WM_MOUSEMOVE) {
367 if (This->absolute) {
368 if (hook->pt.x != This->prevX)
369 GEN_EVENT(This->offset_array[WINE_MOUSE_X_POSITION], hook->pt.x, hook->time, 0);
370 if (hook->pt.y != This->prevY)
371 GEN_EVENT(This->offset_array[WINE_MOUSE_Y_POSITION], hook->pt.y, hook->time, 0);
373 /* Now, warp handling */
374 if ((This->need_warp == WARP_STARTED) &&
375 (hook->pt.x == This->mapped_center.x) && (hook->pt.y == This->mapped_center.y)) {
376 /* Warp has been done... */
377 This->need_warp = WARP_DONE;
381 /* Relative mouse input with absolute mouse event : the real fun starts here... */
382 if ((This->need_warp == WARP_NEEDED) ||
383 (This->need_warp == WARP_STARTED)) {
384 if (hook->pt.x != This->prevX)
385 GEN_EVENT(This->offset_array[WINE_MOUSE_X_POSITION], hook->pt.x - This->prevX, hook->time, (This->dinput->evsequence)++);
386 if (hook->pt.y != This->prevY)
387 GEN_EVENT(This->offset_array[WINE_MOUSE_Y_POSITION], hook->pt.y - This->prevY, hook->time, (This->dinput->evsequence)++);
389 /* This is the first time the event handler has been called after a
390 GetDeviceData or GetDeviceState. */
391 if (hook->pt.x != This->mapped_center.x) {
392 GEN_EVENT(This->offset_array[WINE_MOUSE_X_POSITION], hook->pt.x - This->mapped_center.x, hook->time, (This->dinput->evsequence)++);
393 This->need_warp = WARP_NEEDED;
396 if (hook->pt.y != This->mapped_center.y) {
397 GEN_EVENT(This->offset_array[WINE_MOUSE_Y_POSITION], hook->pt.y - This->mapped_center.y, hook->time, (This->dinput->evsequence)++);
398 This->need_warp = WARP_NEEDED;
403 This->prevX = hook->pt.x;
404 This->prevY = hook->pt.y;
406 if (This->absolute) {
407 This->m_state.lX = hook->pt.x;
408 This->m_state.lY = hook->pt.y;
410 This->m_state.lX = hook->pt.x - This->mapped_center.x;
411 This->m_state.lY = hook->pt.y - This->mapped_center.y;
415 TRACE(" msg %x pt %ld %ld (W=%d)\n",
416 wparam, hook->pt.x, hook->pt.y, (!This->absolute) && This->need_warp );
421 GEN_EVENT(This->offset_array[WINE_MOUSE_L_POSITION], 0xFF,
422 hook->time, This->dinput->evsequence++);
423 This->m_state.rgbButtons[0] = 0xFF;
426 GEN_EVENT(This->offset_array[WINE_MOUSE_L_POSITION], 0x00,
427 hook->time, This->dinput->evsequence++);
428 This->m_state.rgbButtons[0] = 0x00;
431 GEN_EVENT(This->offset_array[WINE_MOUSE_R_POSITION], 0xFF,
432 hook->time, This->dinput->evsequence++);
433 This->m_state.rgbButtons[1] = 0xFF;
436 GEN_EVENT(This->offset_array[WINE_MOUSE_R_POSITION], 0x00,
437 hook->time, This->dinput->evsequence++);
438 This->m_state.rgbButtons[1] = 0x00;
441 GEN_EVENT(This->offset_array[WINE_MOUSE_M_POSITION], 0xFF,
442 hook->time, This->dinput->evsequence++);
443 This->m_state.rgbButtons[2] = 0xFF;
446 GEN_EVENT(This->offset_array[WINE_MOUSE_M_POSITION], 0x00,
447 hook->time, This->dinput->evsequence++);
448 This->m_state.rgbButtons[2] = 0x00;
451 wdata = (short)HIWORD(hook->mouseData);
452 GEN_EVENT(This->offset_array[WINE_MOUSE_Z_POSITION], wdata,
453 hook->time, This->dinput->evsequence++);
454 This->m_state.lZ += wdata;
458 TRACE("(X: %ld - Y: %ld L: %02x M: %02x R: %02x)\n",
459 This->m_state.lX, This->m_state.lY,
460 This->m_state.rgbButtons[0], This->m_state.rgbButtons[2], This->m_state.rgbButtons[1]);
463 LeaveCriticalSection(&(This->crit));
465 if (dwCoop & DISCL_NONEXCLUSIVE)
466 { /* pass the events down to previous handlers (e.g. win32 input) */
467 ret = CallNextHookEx( This->hook, code, wparam, lparam );
469 else ret = 1; /* ignore message */
474 static void dinput_window_check(SysMouseAImpl* This)
477 DWORD centerX, centerY;
479 /* make sure the window hasn't moved */
480 GetWindowRect(This->win, &rect);
481 centerX = (rect.right - rect.left) / 2;
482 centerY = (rect.bottom - rect.top ) / 2;
483 if (This->win_centerX != centerX || This->win_centerY != centerY) {
484 This->win_centerX = centerX;
485 This->win_centerY = centerY;
487 This->mapped_center.x = This->win_centerX;
488 This->mapped_center.y = This->win_centerY;
489 MapWindowPoints(This->win, HWND_DESKTOP, &This->mapped_center, 1);
493 /******************************************************************************
494 * Acquire : gets exclusive control of the mouse
496 static HRESULT WINAPI SysMouseAImpl_Acquire(LPDIRECTINPUTDEVICE8A iface)
498 ICOM_THIS(SysMouseAImpl,iface);
501 TRACE("(this=%p)\n",This);
503 if (This->acquired == 0) {
506 /* Store (in a global variable) the current lock */
507 current_lock = (IDirectInputDevice8A*)This;
509 /* Init the mouse state */
510 if (This->absolute) {
511 GetCursorPos( &point );
512 This->m_state.lX = point.x;
513 This->m_state.lY = point.y;
514 This->prevX = point.x;
515 This->prevY = point.y;
517 This->m_state.lX = 0;
518 This->m_state.lY = 0;
520 This->m_state.lZ = 0;
521 This->m_state.rgbButtons[0] = (GetKeyState(VK_LBUTTON) ? 0xFF : 0x00);
522 This->m_state.rgbButtons[1] = (GetKeyState(VK_MBUTTON) ? 0xFF : 0x00);
523 This->m_state.rgbButtons[2] = (GetKeyState(VK_RBUTTON) ? 0xFF : 0x00);
525 /* Install our mouse hook */
526 if (This->dwCoopLevel & DISCL_EXCLUSIVE)
527 ShowCursor(FALSE); /* hide cursor */
528 This->hook = SetWindowsHookExW( WH_MOUSE_LL, dinput_mouse_hook, 0, 0 );
530 /* Get the window dimension and find the center */
531 GetWindowRect(This->win, &rect);
532 This->win_centerX = (rect.right - rect.left) / 2;
533 This->win_centerY = (rect.bottom - rect.top ) / 2;
535 /* Warp the mouse to the center of the window */
536 if (This->absolute == 0) {
537 This->mapped_center.x = This->win_centerX;
538 This->mapped_center.y = This->win_centerY;
539 MapWindowPoints(This->win, HWND_DESKTOP, &This->mapped_center, 1);
540 TRACE("Warping mouse to %ld - %ld\n", This->mapped_center.x, This->mapped_center.y);
541 SetCursorPos( This->mapped_center.x, This->mapped_center.y );
543 This->need_warp = WARP_DONE;
545 This->need_warp = WARP_STARTED;
555 /******************************************************************************
556 * Unacquire : frees the mouse
558 static HRESULT WINAPI SysMouseAImpl_Unacquire(LPDIRECTINPUTDEVICE8A iface)
560 ICOM_THIS(SysMouseAImpl,iface);
562 TRACE("(this=%p)\n",This);
566 /* Reinstall previous mouse event handler */
568 UnhookWindowsHookEx( This->hook );
570 if (This->dwCoopLevel & DISCL_EXCLUSIVE)
571 ShowCursor(TRUE); /* show cursor */
577 /* Unacquire device */
581 ERR("Unacquiring a not-acquired device !!!\n");
586 /******************************************************************************
587 * GetDeviceState : returns the "state" of the mouse.
589 * For the moment, only the "standard" return structure (DIMOUSESTATE) is
592 static HRESULT WINAPI SysMouseAImpl_GetDeviceState(
593 LPDIRECTINPUTDEVICE8A iface,DWORD len,LPVOID ptr
595 ICOM_THIS(SysMouseAImpl,iface);
597 EnterCriticalSection(&(This->crit));
598 TRACE("(this=%p,0x%08lx,%p): \n",This,len,ptr);
600 /* Copy the current mouse state */
601 fill_DataFormat(ptr, &(This->m_state), This->wine_df);
603 /* Initialize the buffer when in relative mode */
604 if (This->absolute == 0) {
605 This->m_state.lX = 0;
606 This->m_state.lY = 0;
607 This->m_state.lZ = 0;
610 /* Check if we need to do a mouse warping */
611 if (This->need_warp == WARP_NEEDED) {
612 dinput_window_check(This);
613 TRACE("Warping mouse to %ld - %ld\n", This->mapped_center.x, This->mapped_center.y);
614 SetCursorPos( This->mapped_center.x, This->mapped_center.y );
617 This->need_warp = WARP_DONE;
619 This->need_warp = WARP_STARTED;
623 LeaveCriticalSection(&(This->crit));
625 TRACE("(X: %ld - Y: %ld L: %02x M: %02x R: %02x)\n",
626 This->m_state.lX, This->m_state.lY,
627 This->m_state.rgbButtons[0], This->m_state.rgbButtons[2], This->m_state.rgbButtons[1]);
632 /******************************************************************************
633 * GetDeviceState : gets buffered input data.
635 static HRESULT WINAPI SysMouseAImpl_GetDeviceData(LPDIRECTINPUTDEVICE8A iface,
637 LPDIDEVICEOBJECTDATA dod,
641 ICOM_THIS(SysMouseAImpl,iface);
644 EnterCriticalSection(&(This->crit));
645 TRACE("(%p)->(dods=%ld,entries=%ld,fl=0x%08lx)\n",This,dodsize,*entries,flags);
647 len = ((This->queue_head < This->queue_tail) ? This->queue_len : 0)
648 + (This->queue_head - This->queue_tail);
649 if (len > *entries) len = *entries;
653 TRACE("Application discarding %ld event(s).\n", len);
656 nqtail = This->queue_tail + len;
657 while (nqtail >= This->queue_len) nqtail -= This->queue_len;
659 if (dodsize < sizeof(DIDEVICEOBJECTDATA)) {
660 ERR("Wrong structure size !\n");
661 LeaveCriticalSection(&(This->crit));
662 return DIERR_INVALIDPARAM;
666 TRACE("Application retrieving %ld event(s).\n", len);
669 nqtail = This->queue_tail;
671 DWORD span = ((This->queue_head < nqtail) ? This->queue_len : This->queue_head)
673 if (span > len) span = len;
674 /* Copy the buffered data into the application queue */
675 memcpy(dod + *entries, This->data_queue + nqtail, span * dodsize);
676 /* Advance position */
678 if (nqtail >= This->queue_len) nqtail -= This->queue_len;
683 if (!(flags & DIGDD_PEEK))
684 This->queue_tail = nqtail;
686 LeaveCriticalSection(&(This->crit));
688 /* Check if we need to do a mouse warping */
689 if (This->need_warp == WARP_NEEDED) {
690 dinput_window_check(This);
691 TRACE("Warping mouse to %ld - %ld\n", This->mapped_center.x, This->mapped_center.y);
692 SetCursorPos( This->mapped_center.x, This->mapped_center.y );
695 This->need_warp = WARP_DONE;
697 This->need_warp = WARP_STARTED;
703 /******************************************************************************
704 * SetProperty : change input device properties
706 static HRESULT WINAPI SysMouseAImpl_SetProperty(LPDIRECTINPUTDEVICE8A iface,
710 ICOM_THIS(SysMouseAImpl,iface);
712 TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(rguid),ph);
714 if (!HIWORD(rguid)) {
715 switch ((DWORD)rguid) {
716 case (DWORD) DIPROP_BUFFERSIZE: {
717 LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph;
719 TRACE("buffersize = %ld\n",pd->dwData);
721 This->data_queue = (LPDIDEVICEOBJECTDATA)HeapAlloc(GetProcessHeap(),0,
722 pd->dwData * sizeof(DIDEVICEOBJECTDATA));
723 This->queue_head = 0;
724 This->queue_tail = 0;
725 This->queue_len = pd->dwData;
728 case (DWORD) DIPROP_AXISMODE: {
729 LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph;
730 This->absolute = !(pd->dwData);
731 TRACE("Using %s coordinates mode now\n", This->absolute ? "absolute" : "relative");
735 FIXME("Unknown type %ld (%s)\n",(DWORD)rguid,debugstr_guid(rguid));
743 /******************************************************************************
744 * GetProperty : get input device properties
746 static HRESULT WINAPI SysMouseAImpl_GetProperty(LPDIRECTINPUTDEVICE8A iface,
748 LPDIPROPHEADER pdiph)
750 ICOM_THIS(SysMouseAImpl,iface);
752 TRACE("(this=%p,%s,%p): stub!\n",
753 iface, debugstr_guid(rguid), pdiph);
755 if (TRACE_ON(dinput))
756 _dump_DIPROPHEADER(pdiph);
758 if (!HIWORD(rguid)) {
759 switch ((DWORD)rguid) {
760 case (DWORD) DIPROP_BUFFERSIZE: {
761 LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph;
763 TRACE(" return buffersize = %d\n",This->queue_len);
764 pd->dwData = This->queue_len;
768 case (DWORD) DIPROP_GRANULARITY: {
769 LPDIPROPDWORD pr = (LPDIPROPDWORD) pdiph;
771 /* We'll just assume that the app asks about the Z axis */
772 pr->dwData = WHEEL_DELTA;
777 case (DWORD) DIPROP_RANGE: {
778 LPDIPROPRANGE pr = (LPDIPROPRANGE) pdiph;
780 if ((pdiph->dwHow == DIPH_BYID) &&
781 ((pdiph->dwObj == (DIDFT_MAKEINSTANCE(WINE_MOUSE_X_AXIS_INSTANCE) | DIDFT_RELAXIS)) ||
782 (pdiph->dwObj == (DIDFT_MAKEINSTANCE(WINE_MOUSE_Y_AXIS_INSTANCE) | DIDFT_RELAXIS)))) {
783 /* Querying the range of either the X or the Y axis. As I do
784 not know the range, do as if the range were
786 pr->lMin = DIPROPRANGE_NOMIN;
787 pr->lMax = DIPROPRANGE_NOMAX;
794 FIXME("Unknown type %ld (%s)\n",(DWORD)rguid,debugstr_guid(rguid));
805 /******************************************************************************
806 * SetEventNotification : specifies event to be sent on state change
808 static HRESULT WINAPI SysMouseAImpl_SetEventNotification(LPDIRECTINPUTDEVICE8A iface,
810 ICOM_THIS(SysMouseAImpl,iface);
812 TRACE("(this=%p,0x%08lx)\n",This,(DWORD)hnd);
819 /******************************************************************************
820 * GetCapabilities : get the device capablitites
822 static HRESULT WINAPI SysMouseAImpl_GetCapabilities(
823 LPDIRECTINPUTDEVICE8A iface,
824 LPDIDEVCAPS lpDIDevCaps)
826 ICOM_THIS(SysMouseAImpl,iface);
828 TRACE("(this=%p,%p)\n",This,lpDIDevCaps);
830 if (lpDIDevCaps->dwSize == sizeof(DIDEVCAPS)) {
831 lpDIDevCaps->dwFlags = DIDC_ATTACHED;
832 lpDIDevCaps->dwDevType = DIDEVTYPE_MOUSE;
833 lpDIDevCaps->dwAxes = 3;
834 lpDIDevCaps->dwButtons = 3;
835 lpDIDevCaps->dwPOVs = 0;
836 lpDIDevCaps->dwFFSamplePeriod = 0;
837 lpDIDevCaps->dwFFMinTimeResolution = 0;
838 lpDIDevCaps->dwFirmwareRevision = 100;
839 lpDIDevCaps->dwHardwareRevision = 100;
840 lpDIDevCaps->dwFFDriverVersion = 0;
843 FIXME("DirectX 3.0 not supported....\n");
850 /******************************************************************************
851 * EnumObjects : enumerate the different buttons and axis...
853 static HRESULT WINAPI SysMouseAImpl_EnumObjects(
854 LPDIRECTINPUTDEVICE8A iface,
855 LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback,
859 ICOM_THIS(SysMouseAImpl,iface);
860 DIDEVICEOBJECTINSTANCEA ddoi;
862 TRACE("(this=%p,%p,%p,%08lx)\n", This, lpCallback, lpvRef, dwFlags);
863 if (TRACE_ON(dinput)) {
864 DPRINTF(" - flags = ");
865 _dump_EnumObjects_flags(dwFlags);
869 /* Only the fields till dwFFMaxForce are relevant */
870 ddoi.dwSize = FIELD_OFFSET(DIDEVICEOBJECTINSTANCEA, dwFFMaxForce);
872 /* In a mouse, we have : two relative axis and three buttons */
873 if ((dwFlags == DIDFT_ALL) ||
874 (dwFlags & DIDFT_AXIS)) {
876 ddoi.guidType = GUID_XAxis;
877 ddoi.dwOfs = This->offset_array[WINE_MOUSE_X_POSITION];
878 ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_X_AXIS_INSTANCE) | DIDFT_RELAXIS;
879 strcpy(ddoi.tszName, "X-Axis");
880 _dump_OBJECTINSTANCEA(&ddoi);
881 if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
884 ddoi.guidType = GUID_YAxis;
885 ddoi.dwOfs = This->offset_array[WINE_MOUSE_Y_POSITION];
886 ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_Y_AXIS_INSTANCE) | DIDFT_RELAXIS;
887 strcpy(ddoi.tszName, "Y-Axis");
888 _dump_OBJECTINSTANCEA(&ddoi);
889 if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
892 ddoi.guidType = GUID_ZAxis;
893 ddoi.dwOfs = This->offset_array[WINE_MOUSE_Z_POSITION];
894 ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_Z_AXIS_INSTANCE) | DIDFT_RELAXIS;
895 strcpy(ddoi.tszName, "Z-Axis");
896 _dump_OBJECTINSTANCEA(&ddoi);
897 if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
900 if ((dwFlags == DIDFT_ALL) ||
901 (dwFlags & DIDFT_BUTTON)) {
902 ddoi.guidType = GUID_Button;
905 ddoi.dwOfs = This->offset_array[WINE_MOUSE_L_POSITION];
906 ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_L_BUTTON_INSTANCE) | DIDFT_PSHBUTTON;
907 strcpy(ddoi.tszName, "Left-Button");
908 _dump_OBJECTINSTANCEA(&ddoi);
909 if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
912 ddoi.dwOfs = This->offset_array[WINE_MOUSE_R_POSITION];
913 ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_R_BUTTON_INSTANCE) | DIDFT_PSHBUTTON;
914 strcpy(ddoi.tszName, "Right-Button");
915 _dump_OBJECTINSTANCEA(&ddoi);
916 if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
919 ddoi.dwOfs = This->offset_array[WINE_MOUSE_M_POSITION];
920 ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_M_BUTTON_INSTANCE) | DIDFT_PSHBUTTON;
921 strcpy(ddoi.tszName, "Middle-Button");
922 _dump_OBJECTINSTANCEA(&ddoi);
923 if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
930 static ICOM_VTABLE(IDirectInputDevice8A) SysMouseAvt =
932 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
933 IDirectInputDevice2AImpl_QueryInterface,
934 IDirectInputDevice2AImpl_AddRef,
935 SysMouseAImpl_Release,
936 SysMouseAImpl_GetCapabilities,
937 SysMouseAImpl_EnumObjects,
938 SysMouseAImpl_GetProperty,
939 SysMouseAImpl_SetProperty,
940 SysMouseAImpl_Acquire,
941 SysMouseAImpl_Unacquire,
942 SysMouseAImpl_GetDeviceState,
943 SysMouseAImpl_GetDeviceData,
944 SysMouseAImpl_SetDataFormat,
945 SysMouseAImpl_SetEventNotification,
946 SysMouseAImpl_SetCooperativeLevel,
947 IDirectInputDevice2AImpl_GetObjectInfo,
948 IDirectInputDevice2AImpl_GetDeviceInfo,
949 IDirectInputDevice2AImpl_RunControlPanel,
950 IDirectInputDevice2AImpl_Initialize,
951 IDirectInputDevice2AImpl_CreateEffect,
952 IDirectInputDevice2AImpl_EnumEffects,
953 IDirectInputDevice2AImpl_GetEffectInfo,
954 IDirectInputDevice2AImpl_GetForceFeedbackState,
955 IDirectInputDevice2AImpl_SendForceFeedbackCommand,
956 IDirectInputDevice2AImpl_EnumCreatedEffectObjects,
957 IDirectInputDevice2AImpl_Escape,
958 IDirectInputDevice2AImpl_Poll,
959 IDirectInputDevice2AImpl_SendDeviceData,
960 IDirectInputDevice7AImpl_EnumEffectsInFile,
961 IDirectInputDevice7AImpl_WriteEffectToFile,
962 IDirectInputDevice8AImpl_BuildActionMap,
963 IDirectInputDevice8AImpl_SetActionMap,
964 IDirectInputDevice8AImpl_GetImageInfo