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"
26 #ifdef HAVE_SYS_ERRNO_H
27 # include <sys/errno.h>
36 #include "dinput_private.h"
37 #include "device_private.h"
38 #include "wine/debug.h"
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
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
;
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 */
112 IDirectInputAImpl
*dinput
;
114 /* The current data format and the conversion between internal
115 and external data formats */
118 int offset_array
[WINE_INTERNALMOUSE_NUM_OBJS
];
122 /* Previous position for relative moves */
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
;
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 */
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");
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");
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
));
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
;
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
);
213 return DIERR_NOINTERFACE
;
216 return DIERR_DEVICENOTREG
;
219 static dinput_device mousedev
= {
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
);
242 /* Free the data queue */
243 if (This
->data_queue
!= NULL
)
244 HeapFree(GetProcessHeap(),0,This
->data_queue
);
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
);
264 /******************************************************************************
265 * SetCooperativeLevel : store the window in which we will do our
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 */
281 hwnd
= GetDesktopWindow();
283 This
->dwCoopLevel
= dwflags
;
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
);
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
)
322 else if (df
->dwFlags
== DIDF_RELAXIS
)
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
);
339 /* low-level mouse hook */
340 static LRESULT CALLBACK
dinput_mouse_hook( int code
, WPARAM wparam
, LPARAM lparam
)
343 MSLLHOOKSTRUCT
*hook
= (MSLLHOOKSTRUCT
*)lparam
;
344 SysMouseAImpl
* This
= (SysMouseAImpl
*) current_lock
;
346 static long last_event
= 0;
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
)
362 else last_event
= GetCurrentTime();
364 /* Mouse moved -> send event if asked */
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);
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
;
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
)++);
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
;
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
);
423 GEN_EVENT(This
->offset_array
[WINE_MOUSE_L_POSITION
], 0xFF,
424 hook
->time
, This
->dinput
->evsequence
++);
425 This
->m_state
.rgbButtons
[0] = 0xFF;
428 GEN_EVENT(This
->offset_array
[WINE_MOUSE_L_POSITION
], 0x00,
429 hook
->time
, This
->dinput
->evsequence
++);
430 This
->m_state
.rgbButtons
[0] = 0x00;
433 GEN_EVENT(This
->offset_array
[WINE_MOUSE_R_POSITION
], 0xFF,
434 hook
->time
, This
->dinput
->evsequence
++);
435 This
->m_state
.rgbButtons
[1] = 0xFF;
438 GEN_EVENT(This
->offset_array
[WINE_MOUSE_R_POSITION
], 0x00,
439 hook
->time
, This
->dinput
->evsequence
++);
440 This
->m_state
.rgbButtons
[1] = 0x00;
443 GEN_EVENT(This
->offset_array
[WINE_MOUSE_M_POSITION
], 0xFF,
444 hook
->time
, This
->dinput
->evsequence
++);
445 This
->m_state
.rgbButtons
[2] = 0xFF;
448 GEN_EVENT(This
->offset_array
[WINE_MOUSE_M_POSITION
], 0x00,
449 hook
->time
, This
->dinput
->evsequence
++);
450 This
->m_state
.rgbButtons
[2] = 0x00;
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
;
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]);
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 */
476 static void dinput_window_check(SysMouseAImpl
* This
)
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
);
503 TRACE("(this=%p)\n",This
);
505 if (This
->acquired
== 0) {
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
;
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
);
545 This
->need_warp
= WARP_DONE
;
547 This
->need_warp
= WARP_STARTED
;
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
);
568 /* Reinstall previous mouse event handler */
570 UnhookWindowsHookEx( This
->hook
);
572 if (This
->dwCoopLevel
& DISCL_EXCLUSIVE
)
573 ShowCursor(TRUE
); /* show cursor */
579 /* Unacquire device */
583 ERR("Unacquiring a not-acquired device !!!\n");
588 /******************************************************************************
589 * GetDeviceState : returns the "state" of the mouse.
591 * For the moment, only the "standard" return structure (DIMOUSESTATE) is
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
);
619 This
->need_warp
= WARP_DONE
;
621 This
->need_warp
= WARP_STARTED
;
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]);
634 /******************************************************************************
635 * GetDeviceState : gets buffered input data.
637 static HRESULT WINAPI
SysMouseAImpl_GetDeviceData(LPDIRECTINPUTDEVICE8A iface
,
639 LPDIDEVICEOBJECTDATA dod
,
643 ICOM_THIS(SysMouseAImpl
,iface
);
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
;
655 TRACE("Application discarding %ld event(s).\n", len
);
658 nqtail
= This
->queue_tail
+ len
;
659 while (nqtail
>= This
->queue_len
) nqtail
-= This
->queue_len
;
661 if (dodsize
< sizeof(DIDEVICEOBJECTDATA
)) {
662 ERR("Wrong structure size !\n");
663 LeaveCriticalSection(&(This
->crit
));
664 return DIERR_INVALIDPARAM
;
668 TRACE("Application retrieving %ld event(s).\n", len
);
671 nqtail
= This
->queue_tail
;
673 DWORD span
= ((This
->queue_head
< nqtail
) ? This
->queue_len
: This
->queue_head
)
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 */
680 if (nqtail
>= This
->queue_len
) nqtail
-= This
->queue_len
;
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
);
697 This
->need_warp
= WARP_DONE
;
699 This
->need_warp
= WARP_STARTED
;
705 /******************************************************************************
706 * SetProperty : change input device properties
708 static HRESULT WINAPI
SysMouseAImpl_SetProperty(LPDIRECTINPUTDEVICE8A iface
,
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
;
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");
737 FIXME("Unknown type %ld (%s)\n",(DWORD
)rguid
,debugstr_guid(rguid
));
745 /******************************************************************************
746 * GetProperty : get input device properties
748 static HRESULT WINAPI
SysMouseAImpl_GetProperty(LPDIRECTINPUTDEVICE8A iface
,
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
;
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
;
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
788 pr
->lMin
= DIPROPRANGE_NOMIN
;
789 pr
->lMax
= DIPROPRANGE_NOMAX
;
796 FIXME("Unknown type %ld (%s)\n",(DWORD
)rguid
,debugstr_guid(rguid
));
807 /******************************************************************************
808 * SetEventNotification : specifies event to be sent on state change
810 static HRESULT WINAPI
SysMouseAImpl_SetEventNotification(LPDIRECTINPUTDEVICE8A iface
,
812 ICOM_THIS(SysMouseAImpl
,iface
);
814 TRACE("(this=%p,0x%08lx)\n",This
,(DWORD
)hnd
);
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;
845 FIXME("DirectX 3.0 not supported....\n");
852 /******************************************************************************
853 * EnumObjects : enumerate the different buttons and axis...
855 static HRESULT WINAPI
SysMouseAImpl_EnumObjects(
856 LPDIRECTINPUTDEVICE8A iface
,
857 LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback
,
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
);
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
)) {
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
;
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
;
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
;
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
;
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
;
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
;
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