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