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
23 #include "wine/port.h"
33 #include "dinput_private.h"
34 #include "device_private.h"
35 #include "wine/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(dinput);
41 /* Wine mouse driver object instances */
42 #define WINE_MOUSE_X_AXIS_INSTANCE 0x0001
43 #define WINE_MOUSE_Y_AXIS_INSTANCE 0x0002
44 #define WINE_MOUSE_Z_AXIS_INSTANCE 0x0004
45 #define WINE_MOUSE_L_BUTTON_INSTANCE 0x0008
46 #define WINE_MOUSE_R_BUTTON_INSTANCE 0x0010
47 #define WINE_MOUSE_M_BUTTON_INSTANCE 0x0020
49 /* ------------------------------- */
50 /* Wine mouse internal data format */
51 /* ------------------------------- */
53 /* Constants used to access the offset array */
54 #define WINE_MOUSE_X_POSITION 0
55 #define WINE_MOUSE_Y_POSITION 1
56 #define WINE_MOUSE_Z_POSITION 2
57 #define WINE_MOUSE_L_POSITION 3
58 #define WINE_MOUSE_R_POSITION 4
59 #define WINE_MOUSE_M_POSITION 5
66 } Wine_InternalMouseData;
68 #define WINE_INTERNALMOUSE_NUM_OBJS 6
70 static DIOBJECTDATAFORMAT Wine_InternalMouseObjectFormat[WINE_INTERNALMOUSE_NUM_OBJS] = {
71 { &GUID_XAxis, FIELD_OFFSET(Wine_InternalMouseData, lX),
72 DIDFT_MAKEINSTANCE(WINE_MOUSE_X_AXIS_INSTANCE) | DIDFT_RELAXIS, 0 },
73 { &GUID_YAxis, FIELD_OFFSET(Wine_InternalMouseData, lY),
74 DIDFT_MAKEINSTANCE(WINE_MOUSE_Y_AXIS_INSTANCE) | DIDFT_RELAXIS, 0 },
75 { &GUID_ZAxis, FIELD_OFFSET(Wine_InternalMouseData, lZ),
76 DIDFT_MAKEINSTANCE(WINE_MOUSE_Z_AXIS_INSTANCE) | DIDFT_RELAXIS, 0 },
77 { &GUID_Button, (FIELD_OFFSET(Wine_InternalMouseData, rgbButtons)) + 0,
78 DIDFT_MAKEINSTANCE(WINE_MOUSE_L_BUTTON_INSTANCE) | DIDFT_PSHBUTTON, 0 },
79 { &GUID_Button, (FIELD_OFFSET(Wine_InternalMouseData, rgbButtons)) + 1,
80 DIDFT_MAKEINSTANCE(WINE_MOUSE_R_BUTTON_INSTANCE) | DIDFT_PSHBUTTON, 0 },
81 { &GUID_Button, (FIELD_OFFSET(Wine_InternalMouseData, rgbButtons)) + 2,
82 DIDFT_MAKEINSTANCE(WINE_MOUSE_M_BUTTON_INSTANCE) | DIDFT_PSHBUTTON, 0 }
85 static DIDATAFORMAT Wine_InternalMouseFormat = {
86 0, /* dwSize - unused */
87 0, /* dwObjsize - unused */
88 0, /* dwFlags - unused */
89 sizeof(Wine_InternalMouseData),
90 WINE_INTERNALMOUSE_NUM_OBJS, /* dwNumObjs */
91 Wine_InternalMouseObjectFormat
94 static ICOM_VTABLE(IDirectInputDevice8A) SysMouseAvt;
95 typedef struct SysMouseAImpl SysMouseAImpl;
98 WARP_NEEDED, /* Warping is needed */
99 WARP_STARTED, /* Warping has been done, waiting for the warp event */
100 WARP_DONE /* Warping has been done */
109 IDirectInputAImpl *dinput;
111 /* The current data format and the conversion between internal
112 and external data formats */
115 int offset_array[WINE_INTERNALMOUSE_NUM_OBJS];
119 /* Previous position for relative moves */
125 DWORD win_centerX, win_centerY;
126 LPDIDEVICEOBJECTDATA data_queue;
127 int queue_head, queue_tail, queue_len;
128 /* warping: whether we need to move mouse back to middle once we
129 * reach window borders (for e.g. shooters, "surface movement" games) */
130 WARP_STATUS need_warp;
133 CRITICAL_SECTION crit;
135 /* This is for mouse reporting. */
136 Wine_InternalMouseData m_state;
139 static GUID DInput_Wine_Mouse_GUID = { /* 9e573ed8-7734-11d2-8d4a-23903fb6bdf7 */
143 {0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf7}
146 /* FIXME: This is ugly and not thread safe :/ */
147 static IDirectInputDevice8A* current_lock = NULL;
150 static BOOL mousedev_enum_device(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi)
152 if ((dwDevType == 0) || (dwDevType == DIDEVTYPE_MOUSE)) {
153 TRACE("Enumerating the mouse device\n");
156 lpddi->guidInstance = GUID_SysMouse;/* DInput's GUID */
157 lpddi->guidProduct = DInput_Wine_Mouse_GUID; /* Vendor's GUID */
158 lpddi->dwDevType = DIDEVTYPE_MOUSE | (DIDEVTYPEMOUSE_UNKNOWN << 8);
159 strcpy(lpddi->tszInstanceName, "Mouse");
160 strcpy(lpddi->tszProductName, "Wine Mouse");
168 static SysMouseAImpl *alloc_device(REFGUID rguid, LPVOID mvt, IDirectInputAImpl *dinput)
170 int offset_array[WINE_INTERNALMOUSE_NUM_OBJS] = {
171 FIELD_OFFSET(Wine_InternalMouseData, lX),
172 FIELD_OFFSET(Wine_InternalMouseData, lY),
173 FIELD_OFFSET(Wine_InternalMouseData, lZ),
174 FIELD_OFFSET(Wine_InternalMouseData, rgbButtons) + 0,
175 FIELD_OFFSET(Wine_InternalMouseData, rgbButtons) + 1,
176 FIELD_OFFSET(Wine_InternalMouseData, rgbButtons) + 2
178 SysMouseAImpl* newDevice;
179 newDevice = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(SysMouseAImpl));
181 newDevice->lpVtbl = mvt;
182 InitializeCriticalSection(&(newDevice->crit));
183 memcpy(&(newDevice->guid),rguid,sizeof(*rguid));
185 /* Per default, Wine uses its internal data format */
186 newDevice->df = &Wine_InternalMouseFormat;
187 memcpy(newDevice->offset_array, offset_array, WINE_INTERNALMOUSE_NUM_OBJS * sizeof(int));
188 newDevice->wine_df = (DataFormat *) HeapAlloc(GetProcessHeap(), 0, sizeof(DataFormat));
189 newDevice->wine_df->size = 0;
190 newDevice->wine_df->internal_format_size = Wine_InternalMouseFormat.dwDataSize;
191 newDevice->wine_df->dt = NULL;
192 newDevice->dinput = dinput;
197 static HRESULT mousedev_create_device(IDirectInputAImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEA* pdev)
199 if ((IsEqualGUID(&GUID_SysMouse,rguid)) || /* Generic Mouse */
200 (IsEqualGUID(&DInput_Wine_Mouse_GUID,rguid))) { /* Wine Mouse */
201 if ((riid == NULL) ||
202 IsEqualGUID(&IID_IDirectInputDeviceA,riid) ||
203 IsEqualGUID(&IID_IDirectInputDevice2A,riid) ||
204 IsEqualGUID(&IID_IDirectInputDevice7A,riid) ||
205 IsEqualGUID(&IID_IDirectInputDevice8A,riid)) {
206 *pdev=(IDirectInputDeviceA*) alloc_device(rguid, &SysMouseAvt, dinput);
207 TRACE("Creating a Mouse device (%p)\n", *pdev);
210 return DIERR_NOINTERFACE;
213 return DIERR_DEVICENOTREG;
216 static dinput_device mousedev = {
218 mousedev_enum_device,
219 mousedev_create_device
222 DECL_GLOBAL_CONSTRUCTOR(mousedev_register) { dinput_register_device(&mousedev); }
224 /******************************************************************************
225 * SysMouseA (DInput Mouse support)
228 /******************************************************************************
229 * Release : release the mouse buffer.
231 static ULONG WINAPI SysMouseAImpl_Release(LPDIRECTINPUTDEVICE8A iface)
233 ICOM_THIS(SysMouseAImpl,iface);
239 /* Free the data queue */
240 if (This->data_queue != NULL)
241 HeapFree(GetProcessHeap(),0,This->data_queue);
244 UnhookWindowsHookEx( This->hook );
245 if (This->dwCoopLevel & DISCL_EXCLUSIVE)
246 ShowCursor(TRUE); /* show cursor */
248 DeleteCriticalSection(&(This->crit));
250 /* Free the DataFormat */
251 if (This->df != &(Wine_InternalMouseFormat)) {
252 HeapFree(GetProcessHeap(), 0, This->df->rgodf);
253 HeapFree(GetProcessHeap(), 0, This->df);
256 HeapFree(GetProcessHeap(),0,This);
261 /******************************************************************************
262 * SetCooperativeLevel : store the window in which we will do our
265 static HRESULT WINAPI SysMouseAImpl_SetCooperativeLevel(
266 LPDIRECTINPUTDEVICE8A iface,HWND hwnd,DWORD dwflags
269 ICOM_THIS(SysMouseAImpl,iface);
271 TRACE("(this=%p,0x%08lx,0x%08lx)\n",This,(DWORD)hwnd,dwflags);
273 if (TRACE_ON(dinput)) {
274 TRACE(" cooperative level : ");
275 _dump_cooperativelevel_DI(dwflags);
278 /* Store the window which asks for the mouse */
280 hwnd = GetDesktopWindow();
282 This->dwCoopLevel = dwflags;
288 /******************************************************************************
289 * SetDataFormat : the application can choose the format of the data
290 * the device driver sends back with GetDeviceState.
292 * For the moment, only the "standard" configuration (c_dfDIMouse) is supported
293 * in absolute and relative mode.
295 static HRESULT WINAPI SysMouseAImpl_SetDataFormat(
296 LPDIRECTINPUTDEVICE8A iface,LPCDIDATAFORMAT df
299 ICOM_THIS(SysMouseAImpl,iface);
302 TRACE("(this=%p,%p)\n",This,df);
304 TRACE("(df.dwSize=%ld)\n",df->dwSize);
305 TRACE("(df.dwObjsize=%ld)\n",df->dwObjSize);
306 TRACE("(df.dwFlags=0x%08lx)\n",df->dwFlags);
307 TRACE("(df.dwDataSize=%ld)\n",df->dwDataSize);
308 TRACE("(df.dwNumObjs=%ld)\n",df->dwNumObjs);
310 for (i=0;i<df->dwNumObjs;i++) {
312 TRACE("df.rgodf[%d].guid %s (%p)\n",i, debugstr_guid(df->rgodf[i].pguid), df->rgodf[i].pguid);
313 TRACE("df.rgodf[%d].dwOfs %ld\n",i,df->rgodf[i].dwOfs);
314 TRACE("dwType 0x%02x,dwInstance %d\n",DIDFT_GETTYPE(df->rgodf[i].dwType),DIDFT_GETINSTANCE(df->rgodf[i].dwType));
315 TRACE("df.rgodf[%d].dwFlags 0x%08lx\n",i,df->rgodf[i].dwFlags);
318 /* Check if the mouse is in absolute or relative mode */
319 if (df->dwFlags == DIDF_ABSAXIS)
321 else if (df->dwFlags == DIDF_RELAXIS)
324 ERR("Neither absolute nor relative flag set\n");
326 /* Store the new data format */
327 This->df = HeapAlloc(GetProcessHeap(),0,df->dwSize);
328 memcpy(This->df, df, df->dwSize);
329 This->df->rgodf = HeapAlloc(GetProcessHeap(),0,df->dwNumObjs*df->dwObjSize);
330 memcpy(This->df->rgodf,df->rgodf,df->dwNumObjs*df->dwObjSize);
332 /* Prepare all the data-conversion filters */
333 This->wine_df = create_DataFormat(&(Wine_InternalMouseFormat), df, This->offset_array);
338 /* low-level mouse hook */
339 static LRESULT CALLBACK dinput_mouse_hook( int code, WPARAM wparam, LPARAM lparam )
342 MSLLHOOKSTRUCT *hook = (MSLLHOOKSTRUCT *)lparam;
343 SysMouseAImpl* This = (SysMouseAImpl*) current_lock;
345 static long last_event = 0;
348 if (code != HC_ACTION) return CallNextHookEx( This->hook, code, wparam, lparam );
350 EnterCriticalSection(&(This->crit));
351 dwCoop = This->dwCoopLevel;
353 /* Only allow mouse events every 10 ms.
354 * This is to allow the cursor to start acceleration before
355 * the warps happen. But if it involves a mouse button event we
356 * allow it since we dont want to loose the clicks.
358 if (((GetCurrentTime() - last_event) < 10)
359 && wparam == WM_MOUSEMOVE)
361 else last_event = GetCurrentTime();
363 /* Mouse moved -> send event if asked */
365 SetEvent(This->hEvent);
367 if (wparam == WM_MOUSEMOVE) {
368 if (This->absolute) {
369 if (hook->pt.x != This->prevX)
370 GEN_EVENT(This->offset_array[WINE_MOUSE_X_POSITION], hook->pt.x, hook->time, 0);
371 if (hook->pt.y != This->prevY)
372 GEN_EVENT(This->offset_array[WINE_MOUSE_Y_POSITION], hook->pt.y, hook->time, 0);
374 /* Now, warp handling */
375 if ((This->need_warp == WARP_STARTED) &&
376 (hook->pt.x == This->mapped_center.x) && (hook->pt.y == This->mapped_center.y)) {
377 /* Warp has been done... */
378 This->need_warp = WARP_DONE;
382 /* Relative mouse input with absolute mouse event : the real fun starts here... */
383 if ((This->need_warp == WARP_NEEDED) ||
384 (This->need_warp == WARP_STARTED)) {
385 if (hook->pt.x != This->prevX)
386 GEN_EVENT(This->offset_array[WINE_MOUSE_X_POSITION], hook->pt.x - This->prevX, hook->time, (This->dinput->evsequence)++);
387 if (hook->pt.y != This->prevY)
388 GEN_EVENT(This->offset_array[WINE_MOUSE_Y_POSITION], hook->pt.y - This->prevY, hook->time, (This->dinput->evsequence)++);
390 /* This is the first time the event handler has been called after a
391 GetDeviceData or GetDeviceState. */
392 if (hook->pt.x != This->mapped_center.x) {
393 GEN_EVENT(This->offset_array[WINE_MOUSE_X_POSITION], hook->pt.x - This->mapped_center.x, hook->time, (This->dinput->evsequence)++);
394 This->need_warp = WARP_NEEDED;
397 if (hook->pt.y != This->mapped_center.y) {
398 GEN_EVENT(This->offset_array[WINE_MOUSE_Y_POSITION], hook->pt.y - This->mapped_center.y, hook->time, (This->dinput->evsequence)++);
399 This->need_warp = WARP_NEEDED;
404 This->prevX = hook->pt.x;
405 This->prevY = hook->pt.y;
407 if (This->absolute) {
408 This->m_state.lX = hook->pt.x;
409 This->m_state.lY = hook->pt.y;
411 This->m_state.lX = hook->pt.x - This->mapped_center.x;
412 This->m_state.lY = hook->pt.y - This->mapped_center.y;
416 TRACE(" msg %x pt %ld %ld (W=%d)\n",
417 wparam, hook->pt.x, hook->pt.y, (!This->absolute) && This->need_warp );
422 GEN_EVENT(This->offset_array[WINE_MOUSE_L_POSITION], 0xFF,
423 hook->time, This->dinput->evsequence++);
424 This->m_state.rgbButtons[0] = 0xFF;
427 GEN_EVENT(This->offset_array[WINE_MOUSE_L_POSITION], 0x00,
428 hook->time, This->dinput->evsequence++);
429 This->m_state.rgbButtons[0] = 0x00;
432 GEN_EVENT(This->offset_array[WINE_MOUSE_R_POSITION], 0xFF,
433 hook->time, This->dinput->evsequence++);
434 This->m_state.rgbButtons[1] = 0xFF;
437 GEN_EVENT(This->offset_array[WINE_MOUSE_R_POSITION], 0x00,
438 hook->time, This->dinput->evsequence++);
439 This->m_state.rgbButtons[1] = 0x00;
442 GEN_EVENT(This->offset_array[WINE_MOUSE_M_POSITION], 0xFF,
443 hook->time, This->dinput->evsequence++);
444 This->m_state.rgbButtons[2] = 0xFF;
447 GEN_EVENT(This->offset_array[WINE_MOUSE_M_POSITION], 0x00,
448 hook->time, This->dinput->evsequence++);
449 This->m_state.rgbButtons[2] = 0x00;
452 wdata = (short)HIWORD(hook->mouseData);
453 GEN_EVENT(This->offset_array[WINE_MOUSE_Z_POSITION], wdata,
454 hook->time, This->dinput->evsequence++);
455 This->m_state.lZ += wdata;
459 TRACE("(X: %ld - Y: %ld L: %02x M: %02x R: %02x)\n",
460 This->m_state.lX, This->m_state.lY,
461 This->m_state.rgbButtons[0], This->m_state.rgbButtons[2], This->m_state.rgbButtons[1]);
464 LeaveCriticalSection(&(This->crit));
466 if (dwCoop & DISCL_NONEXCLUSIVE)
467 { /* pass the events down to previous handlers (e.g. win32 input) */
468 ret = CallNextHookEx( This->hook, code, wparam, lparam );
470 else ret = 1; /* ignore message */
475 static void dinput_window_check(SysMouseAImpl* This)
478 DWORD centerX, centerY;
480 /* make sure the window hasn't moved */
481 GetWindowRect(This->win, &rect);
482 centerX = (rect.right - rect.left) / 2;
483 centerY = (rect.bottom - rect.top ) / 2;
484 if (This->win_centerX != centerX || This->win_centerY != centerY) {
485 This->win_centerX = centerX;
486 This->win_centerY = centerY;
488 This->mapped_center.x = This->win_centerX;
489 This->mapped_center.y = This->win_centerY;
490 MapWindowPoints(This->win, HWND_DESKTOP, &This->mapped_center, 1);
494 /******************************************************************************
495 * Acquire : gets exclusive control of the mouse
497 static HRESULT WINAPI SysMouseAImpl_Acquire(LPDIRECTINPUTDEVICE8A iface)
499 ICOM_THIS(SysMouseAImpl,iface);
502 TRACE("(this=%p)\n",This);
504 if (This->acquired == 0) {
507 /* Store (in a global variable) the current lock */
508 current_lock = (IDirectInputDevice8A*)This;
510 /* Init the mouse state */
511 if (This->absolute) {
512 GetCursorPos( &point );
513 This->m_state.lX = point.x;
514 This->m_state.lY = point.y;
515 This->prevX = point.x;
516 This->prevY = point.y;
518 This->m_state.lX = 0;
519 This->m_state.lY = 0;
521 This->m_state.lZ = 0;
522 This->m_state.rgbButtons[0] = (GetKeyState(VK_LBUTTON) ? 0xFF : 0x00);
523 This->m_state.rgbButtons[1] = (GetKeyState(VK_MBUTTON) ? 0xFF : 0x00);
524 This->m_state.rgbButtons[2] = (GetKeyState(VK_RBUTTON) ? 0xFF : 0x00);
526 /* Install our mouse hook */
527 if (This->dwCoopLevel & DISCL_EXCLUSIVE)
528 ShowCursor(FALSE); /* hide cursor */
529 This->hook = SetWindowsHookExA( WH_MOUSE_LL, dinput_mouse_hook, DINPUT_instance, 0 );
531 /* Get the window dimension and find the center */
532 GetWindowRect(This->win, &rect);
533 This->win_centerX = (rect.right - rect.left) / 2;
534 This->win_centerY = (rect.bottom - rect.top ) / 2;
536 /* Warp the mouse to the center of the window */
537 if (This->absolute == 0) {
538 This->mapped_center.x = This->win_centerX;
539 This->mapped_center.y = This->win_centerY;
540 MapWindowPoints(This->win, HWND_DESKTOP, &This->mapped_center, 1);
541 TRACE("Warping mouse to %ld - %ld\n", This->mapped_center.x, This->mapped_center.y);
542 SetCursorPos( This->mapped_center.x, This->mapped_center.y );
544 This->need_warp = WARP_DONE;
546 This->need_warp = WARP_STARTED;
556 /******************************************************************************
557 * Unacquire : frees the mouse
559 static HRESULT WINAPI SysMouseAImpl_Unacquire(LPDIRECTINPUTDEVICE8A iface)
561 ICOM_THIS(SysMouseAImpl,iface);
563 TRACE("(this=%p)\n",This);
567 /* Reinstall previous mouse event handler */
569 UnhookWindowsHookEx( This->hook );
571 if (This->dwCoopLevel & DISCL_EXCLUSIVE)
572 ShowCursor(TRUE); /* show cursor */
578 /* Unacquire device */
582 ERR("Unacquiring a not-acquired device !!!\n");
587 /******************************************************************************
588 * GetDeviceState : returns the "state" of the mouse.
590 * For the moment, only the "standard" return structure (DIMOUSESTATE) is
593 static HRESULT WINAPI SysMouseAImpl_GetDeviceState(
594 LPDIRECTINPUTDEVICE8A iface,DWORD len,LPVOID ptr
596 ICOM_THIS(SysMouseAImpl,iface);
598 EnterCriticalSection(&(This->crit));
599 TRACE("(this=%p,0x%08lx,%p): \n",This,len,ptr);
601 /* Copy the current mouse state */
602 fill_DataFormat(ptr, &(This->m_state), This->wine_df);
604 /* Initialize the buffer when in relative mode */
605 if (This->absolute == 0) {
606 This->m_state.lX = 0;
607 This->m_state.lY = 0;
608 This->m_state.lZ = 0;
611 /* Check if we need to do a mouse warping */
612 if (This->need_warp == WARP_NEEDED) {
613 dinput_window_check(This);
614 TRACE("Warping mouse to %ld - %ld\n", This->mapped_center.x, This->mapped_center.y);
615 SetCursorPos( This->mapped_center.x, This->mapped_center.y );
618 This->need_warp = WARP_DONE;
620 This->need_warp = WARP_STARTED;
624 LeaveCriticalSection(&(This->crit));
626 TRACE("(X: %ld - Y: %ld L: %02x M: %02x R: %02x)\n",
627 This->m_state.lX, This->m_state.lY,
628 This->m_state.rgbButtons[0], This->m_state.rgbButtons[2], This->m_state.rgbButtons[1]);
633 /******************************************************************************
634 * GetDeviceState : gets buffered input data.
636 static HRESULT WINAPI SysMouseAImpl_GetDeviceData(LPDIRECTINPUTDEVICE8A iface,
638 LPDIDEVICEOBJECTDATA dod,
642 ICOM_THIS(SysMouseAImpl,iface);
645 TRACE("(%p)->(dods=%ld,entries=%ld,fl=0x%08lx)\n",This,dodsize,*entries,flags);
647 if (This->acquired == 0) {
648 WARN(" application tries to get data from an unacquired device !\n");
649 return DIERR_NOTACQUIRED;
652 EnterCriticalSection(&(This->crit));
654 len = ((This->queue_head < This->queue_tail) ? This->queue_len : 0)
655 + (This->queue_head - This->queue_tail);
656 if (len > *entries) len = *entries;
660 TRACE("Application discarding %ld event(s).\n", len);
663 nqtail = This->queue_tail + len;
664 while (nqtail >= This->queue_len) nqtail -= This->queue_len;
666 if (dodsize < sizeof(DIDEVICEOBJECTDATA)) {
667 ERR("Wrong structure size !\n");
668 LeaveCriticalSection(&(This->crit));
669 return DIERR_INVALIDPARAM;
673 TRACE("Application retrieving %ld event(s).\n", len);
676 nqtail = This->queue_tail;
678 DWORD span = ((This->queue_head < nqtail) ? This->queue_len : This->queue_head)
680 if (span > len) span = len;
681 /* Copy the buffered data into the application queue */
682 memcpy(dod + *entries, This->data_queue + nqtail, span * dodsize);
683 /* Advance position */
685 if (nqtail >= This->queue_len) nqtail -= This->queue_len;
690 if (!(flags & DIGDD_PEEK))
691 This->queue_tail = nqtail;
693 LeaveCriticalSection(&(This->crit));
695 /* Check if we need to do a mouse warping */
696 if (This->need_warp == WARP_NEEDED) {
697 dinput_window_check(This);
698 TRACE("Warping mouse to %ld - %ld\n", This->mapped_center.x, This->mapped_center.y);
699 SetCursorPos( This->mapped_center.x, This->mapped_center.y );
702 This->need_warp = WARP_DONE;
704 This->need_warp = WARP_STARTED;
710 /******************************************************************************
711 * SetProperty : change input device properties
713 static HRESULT WINAPI SysMouseAImpl_SetProperty(LPDIRECTINPUTDEVICE8A iface,
717 ICOM_THIS(SysMouseAImpl,iface);
719 TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(rguid),ph);
721 if (!HIWORD(rguid)) {
722 switch ((DWORD)rguid) {
723 case (DWORD) DIPROP_BUFFERSIZE: {
724 LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph;
726 TRACE("buffersize = %ld\n",pd->dwData);
728 This->data_queue = (LPDIDEVICEOBJECTDATA)HeapAlloc(GetProcessHeap(),0,
729 pd->dwData * sizeof(DIDEVICEOBJECTDATA));
730 This->queue_head = 0;
731 This->queue_tail = 0;
732 This->queue_len = pd->dwData;
735 case (DWORD) DIPROP_AXISMODE: {
736 LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph;
737 This->absolute = !(pd->dwData);
738 TRACE("Using %s coordinates mode now\n", This->absolute ? "absolute" : "relative");
742 FIXME("Unknown type %ld (%s)\n",(DWORD)rguid,debugstr_guid(rguid));
750 /******************************************************************************
751 * GetProperty : get input device properties
753 static HRESULT WINAPI SysMouseAImpl_GetProperty(LPDIRECTINPUTDEVICE8A iface,
755 LPDIPROPHEADER pdiph)
757 ICOM_THIS(SysMouseAImpl,iface);
759 TRACE("(this=%p,%s,%p): stub!\n",
760 iface, debugstr_guid(rguid), pdiph);
762 if (TRACE_ON(dinput))
763 _dump_DIPROPHEADER(pdiph);
765 if (!HIWORD(rguid)) {
766 switch ((DWORD)rguid) {
767 case (DWORD) DIPROP_BUFFERSIZE: {
768 LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph;
770 TRACE(" return buffersize = %d\n",This->queue_len);
771 pd->dwData = This->queue_len;
775 case (DWORD) DIPROP_GRANULARITY: {
776 LPDIPROPDWORD pr = (LPDIPROPDWORD) pdiph;
778 /* We'll just assume that the app asks about the Z axis */
779 pr->dwData = WHEEL_DELTA;
784 case (DWORD) DIPROP_RANGE: {
785 LPDIPROPRANGE pr = (LPDIPROPRANGE) pdiph;
787 if ((pdiph->dwHow == DIPH_BYID) &&
788 ((pdiph->dwObj == (DIDFT_MAKEINSTANCE(WINE_MOUSE_X_AXIS_INSTANCE) | DIDFT_RELAXIS)) ||
789 (pdiph->dwObj == (DIDFT_MAKEINSTANCE(WINE_MOUSE_Y_AXIS_INSTANCE) | DIDFT_RELAXIS)))) {
790 /* Querying the range of either the X or the Y axis. As I do
791 not know the range, do as if the range were
793 pr->lMin = DIPROPRANGE_NOMIN;
794 pr->lMax = DIPROPRANGE_NOMAX;
801 FIXME("Unknown type %ld (%s)\n",(DWORD)rguid,debugstr_guid(rguid));
812 /******************************************************************************
813 * SetEventNotification : specifies event to be sent on state change
815 static HRESULT WINAPI SysMouseAImpl_SetEventNotification(LPDIRECTINPUTDEVICE8A iface,
817 ICOM_THIS(SysMouseAImpl,iface);
819 TRACE("(this=%p,0x%08lx)\n",This,(DWORD)hnd);
826 /******************************************************************************
827 * GetCapabilities : get the device capablitites
829 static HRESULT WINAPI SysMouseAImpl_GetCapabilities(
830 LPDIRECTINPUTDEVICE8A iface,
831 LPDIDEVCAPS lpDIDevCaps)
833 ICOM_THIS(SysMouseAImpl,iface);
835 TRACE("(this=%p,%p)\n",This,lpDIDevCaps);
837 if (lpDIDevCaps->dwSize == sizeof(DIDEVCAPS)) {
838 lpDIDevCaps->dwFlags = DIDC_ATTACHED;
839 lpDIDevCaps->dwDevType = DIDEVTYPE_MOUSE;
840 lpDIDevCaps->dwAxes = 3;
841 lpDIDevCaps->dwButtons = 3;
842 lpDIDevCaps->dwPOVs = 0;
843 lpDIDevCaps->dwFFSamplePeriod = 0;
844 lpDIDevCaps->dwFFMinTimeResolution = 0;
845 lpDIDevCaps->dwFirmwareRevision = 100;
846 lpDIDevCaps->dwHardwareRevision = 100;
847 lpDIDevCaps->dwFFDriverVersion = 0;
850 FIXME("DirectX 3.0 not supported....\n");
857 /******************************************************************************
858 * EnumObjects : enumerate the different buttons and axis...
860 static HRESULT WINAPI SysMouseAImpl_EnumObjects(
861 LPDIRECTINPUTDEVICE8A iface,
862 LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback,
866 ICOM_THIS(SysMouseAImpl,iface);
867 DIDEVICEOBJECTINSTANCEA ddoi;
869 TRACE("(this=%p,%p,%p,%08lx)\n", This, lpCallback, lpvRef, dwFlags);
870 if (TRACE_ON(dinput)) {
871 TRACE(" - flags = ");
872 _dump_EnumObjects_flags(dwFlags);
876 /* Only the fields till dwFFMaxForce are relevant */
877 memset(&ddoi, 0, sizeof(ddoi));
878 ddoi.dwSize = FIELD_OFFSET(DIDEVICEOBJECTINSTANCEA, dwFFMaxForce);
880 /* In a mouse, we have : two relative axis and three buttons */
881 if ((dwFlags == DIDFT_ALL) ||
882 (dwFlags & DIDFT_AXIS)) {
884 ddoi.guidType = GUID_XAxis;
885 ddoi.dwOfs = This->offset_array[WINE_MOUSE_X_POSITION];
886 ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_X_AXIS_INSTANCE) | DIDFT_RELAXIS;
887 strcpy(ddoi.tszName, "X-Axis");
888 _dump_OBJECTINSTANCEA(&ddoi);
889 if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
892 ddoi.guidType = GUID_YAxis;
893 ddoi.dwOfs = This->offset_array[WINE_MOUSE_Y_POSITION];
894 ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_Y_AXIS_INSTANCE) | DIDFT_RELAXIS;
895 strcpy(ddoi.tszName, "Y-Axis");
896 _dump_OBJECTINSTANCEA(&ddoi);
897 if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
900 ddoi.guidType = GUID_ZAxis;
901 ddoi.dwOfs = This->offset_array[WINE_MOUSE_Z_POSITION];
902 ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_Z_AXIS_INSTANCE) | DIDFT_RELAXIS;
903 strcpy(ddoi.tszName, "Z-Axis");
904 _dump_OBJECTINSTANCEA(&ddoi);
905 if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
908 if ((dwFlags == DIDFT_ALL) ||
909 (dwFlags & DIDFT_BUTTON)) {
910 ddoi.guidType = GUID_Button;
913 ddoi.dwOfs = This->offset_array[WINE_MOUSE_L_POSITION];
914 ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_L_BUTTON_INSTANCE) | DIDFT_PSHBUTTON;
915 strcpy(ddoi.tszName, "Left-Button");
916 _dump_OBJECTINSTANCEA(&ddoi);
917 if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
920 ddoi.dwOfs = This->offset_array[WINE_MOUSE_R_POSITION];
921 ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_R_BUTTON_INSTANCE) | DIDFT_PSHBUTTON;
922 strcpy(ddoi.tszName, "Right-Button");
923 _dump_OBJECTINSTANCEA(&ddoi);
924 if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
927 ddoi.dwOfs = This->offset_array[WINE_MOUSE_M_POSITION];
928 ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_M_BUTTON_INSTANCE) | DIDFT_PSHBUTTON;
929 strcpy(ddoi.tszName, "Middle-Button");
930 _dump_OBJECTINSTANCEA(&ddoi);
931 if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
938 static ICOM_VTABLE(IDirectInputDevice8A) SysMouseAvt =
940 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
941 IDirectInputDevice2AImpl_QueryInterface,
942 IDirectInputDevice2AImpl_AddRef,
943 SysMouseAImpl_Release,
944 SysMouseAImpl_GetCapabilities,
945 SysMouseAImpl_EnumObjects,
946 SysMouseAImpl_GetProperty,
947 SysMouseAImpl_SetProperty,
948 SysMouseAImpl_Acquire,
949 SysMouseAImpl_Unacquire,
950 SysMouseAImpl_GetDeviceState,
951 SysMouseAImpl_GetDeviceData,
952 SysMouseAImpl_SetDataFormat,
953 SysMouseAImpl_SetEventNotification,
954 SysMouseAImpl_SetCooperativeLevel,
955 IDirectInputDevice2AImpl_GetObjectInfo,
956 IDirectInputDevice2AImpl_GetDeviceInfo,
957 IDirectInputDevice2AImpl_RunControlPanel,
958 IDirectInputDevice2AImpl_Initialize,
959 IDirectInputDevice2AImpl_CreateEffect,
960 IDirectInputDevice2AImpl_EnumEffects,
961 IDirectInputDevice2AImpl_GetEffectInfo,
962 IDirectInputDevice2AImpl_GetForceFeedbackState,
963 IDirectInputDevice2AImpl_SendForceFeedbackCommand,
964 IDirectInputDevice2AImpl_EnumCreatedEffectObjects,
965 IDirectInputDevice2AImpl_Escape,
966 IDirectInputDevice2AImpl_Poll,
967 IDirectInputDevice2AImpl_SendDeviceData,
968 IDirectInputDevice7AImpl_EnumEffectsInFile,
969 IDirectInputDevice7AImpl_WriteEffectToFile,
970 IDirectInputDevice8AImpl_BuildActionMap,
971 IDirectInputDevice8AImpl_SetActionMap,
972 IDirectInputDevice8AImpl_GetImageInfo