* Sync with trunk r64401.
[reactos.git] / dll / directx / wine / dinput / mouse.c
1 /* DirectInput Mouse device
2 *
3 * Copyright 1998 Marcus Meissner
4 * Copyright 1998,1999 Lionel Ulmer
5 * Copyright 2000-2001 TransGaming Technologies Inc.
6 *
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.
11 *
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.
16 *
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 */
21
22 #include "dinput_private.h"
23
24 /* Wine mouse driver object instances */
25 #define WINE_MOUSE_X_AXIS_INSTANCE 0
26 #define WINE_MOUSE_Y_AXIS_INSTANCE 1
27 #define WINE_MOUSE_Z_AXIS_INSTANCE 2
28 #define WINE_MOUSE_BUTTONS_INSTANCE 3
29
30 static const IDirectInputDevice8AVtbl SysMouseAvt;
31 static const IDirectInputDevice8WVtbl SysMouseWvt;
32
33 typedef struct SysMouseImpl SysMouseImpl;
34
35 typedef enum
36 {
37 WARP_DEFAULT,
38 WARP_DISABLE,
39 WARP_FORCE_ON
40 } WARP_MOUSE;
41
42 struct SysMouseImpl
43 {
44 struct IDirectInputDeviceImpl base;
45
46 /* SysMouseAImpl */
47 /* These are used in case of relative -> absolute transitions */
48 POINT org_coords;
49 BOOL clipped;
50 /* warping: whether we need to move mouse back to middle once we
51 * reach window borders (for e.g. shooters, "surface movement" games) */
52 BOOL need_warp;
53 DWORD last_warped;
54
55 /* This is for mouse reporting. */
56 DIMOUSESTATE2 m_state;
57
58 WARP_MOUSE warp_override;
59 };
60
61 static inline SysMouseImpl *impl_from_IDirectInputDevice8A(IDirectInputDevice8A *iface)
62 {
63 return CONTAINING_RECORD(CONTAINING_RECORD(iface, IDirectInputDeviceImpl, IDirectInputDevice8A_iface), SysMouseImpl, base);
64 }
65 static inline SysMouseImpl *impl_from_IDirectInputDevice8W(IDirectInputDevice8W *iface)
66 {
67 return CONTAINING_RECORD(CONTAINING_RECORD(iface, IDirectInputDeviceImpl, IDirectInputDevice8W_iface), SysMouseImpl, base);
68 }
69 static inline IDirectInputDevice8A *IDirectInputDevice8A_from_impl(SysMouseImpl *This)
70 {
71 return &This->base.IDirectInputDevice8A_iface;
72 }
73 static inline IDirectInputDevice8W *IDirectInputDevice8W_from_impl(SysMouseImpl *This)
74 {
75 return &This->base.IDirectInputDevice8W_iface;
76 }
77
78 static int dinput_mouse_hook( LPDIRECTINPUTDEVICE8A iface, WPARAM wparam, LPARAM lparam );
79
80 const GUID DInput_Wine_Mouse_GUID = { /* 9e573ed8-7734-11d2-8d4a-23903fb6bdf7 */
81 0x9e573ed8, 0x7734, 0x11d2, {0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf7}
82 };
83
84 static void _dump_mouse_state(const DIMOUSESTATE2 *m_state)
85 {
86 int i;
87
88 if (!TRACE_ON(dinput)) return;
89
90 TRACE("(X: %d Y: %d Z: %d", m_state->lX, m_state->lY, m_state->lZ);
91 for (i = 0; i < 5; i++) TRACE(" B%d: %02x", i, m_state->rgbButtons[i]);
92 TRACE(")\n");
93 }
94
95 static void fill_mouse_dideviceinstanceA(LPDIDEVICEINSTANCEA lpddi, DWORD version) {
96 DWORD dwSize;
97 DIDEVICEINSTANCEA ddi;
98
99 dwSize = lpddi->dwSize;
100
101 TRACE("%d %p\n", dwSize, lpddi);
102
103 memset(lpddi, 0, dwSize);
104 memset(&ddi, 0, sizeof(ddi));
105
106 ddi.dwSize = dwSize;
107 ddi.guidInstance = GUID_SysMouse;/* DInput's GUID */
108 ddi.guidProduct = DInput_Wine_Mouse_GUID; /* Vendor's GUID */
109 if (version >= 0x0800)
110 ddi.dwDevType = DI8DEVTYPE_MOUSE | (DI8DEVTYPEMOUSE_TRADITIONAL << 8);
111 else
112 ddi.dwDevType = DIDEVTYPE_MOUSE | (DIDEVTYPEMOUSE_TRADITIONAL << 8);
113 strcpy(ddi.tszInstanceName, "Mouse");
114 strcpy(ddi.tszProductName, "Wine Mouse");
115
116 memcpy(lpddi, &ddi, (dwSize < sizeof(ddi) ? dwSize : sizeof(ddi)));
117 }
118
119 static void fill_mouse_dideviceinstanceW(LPDIDEVICEINSTANCEW lpddi, DWORD version) {
120 DWORD dwSize;
121 DIDEVICEINSTANCEW ddi;
122
123 dwSize = lpddi->dwSize;
124
125 TRACE("%d %p\n", dwSize, lpddi);
126
127 memset(lpddi, 0, dwSize);
128 memset(&ddi, 0, sizeof(ddi));
129
130 ddi.dwSize = dwSize;
131 ddi.guidInstance = GUID_SysMouse;/* DInput's GUID */
132 ddi.guidProduct = DInput_Wine_Mouse_GUID; /* Vendor's GUID */
133 if (version >= 0x0800)
134 ddi.dwDevType = DI8DEVTYPE_MOUSE | (DI8DEVTYPEMOUSE_TRADITIONAL << 8);
135 else
136 ddi.dwDevType = DIDEVTYPE_MOUSE | (DIDEVTYPEMOUSE_TRADITIONAL << 8);
137 MultiByteToWideChar(CP_ACP, 0, "Mouse", -1, ddi.tszInstanceName, MAX_PATH);
138 MultiByteToWideChar(CP_ACP, 0, "Wine Mouse", -1, ddi.tszProductName, MAX_PATH);
139
140 memcpy(lpddi, &ddi, (dwSize < sizeof(ddi) ? dwSize : sizeof(ddi)));
141 }
142
143 static HRESULT mousedev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, DWORD version, int id)
144 {
145 if (id != 0)
146 return E_FAIL;
147
148 if ((dwDevType == 0) ||
149 ((dwDevType == DIDEVTYPE_MOUSE) && (version < 0x0800)) ||
150 (((dwDevType == DI8DEVCLASS_POINTER) || (dwDevType == DI8DEVTYPE_MOUSE)) && (version >= 0x0800))) {
151 TRACE("Enumerating the mouse device\n");
152
153 fill_mouse_dideviceinstanceA(lpddi, version);
154
155 return S_OK;
156 }
157
158 return S_FALSE;
159 }
160
161 static HRESULT mousedev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEW lpddi, DWORD version, int id)
162 {
163 if (id != 0)
164 return E_FAIL;
165
166 if ((dwDevType == 0) ||
167 ((dwDevType == DIDEVTYPE_MOUSE) && (version < 0x0800)) ||
168 (((dwDevType == DI8DEVCLASS_POINTER) || (dwDevType == DI8DEVTYPE_MOUSE)) && (version >= 0x0800))) {
169 TRACE("Enumerating the mouse device\n");
170
171 fill_mouse_dideviceinstanceW(lpddi, version);
172
173 return S_OK;
174 }
175
176 return S_FALSE;
177 }
178
179 static SysMouseImpl *alloc_device(REFGUID rguid, IDirectInputImpl *dinput)
180 {
181 SysMouseImpl* newDevice;
182 LPDIDATAFORMAT df = NULL;
183 unsigned i;
184 char buffer[20];
185 HKEY hkey, appkey;
186
187 newDevice = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(SysMouseImpl));
188 if (!newDevice) return NULL;
189 newDevice->base.IDirectInputDevice8A_iface.lpVtbl = &SysMouseAvt;
190 newDevice->base.IDirectInputDevice8W_iface.lpVtbl = &SysMouseWvt;
191 newDevice->base.ref = 1;
192 newDevice->base.dwCoopLevel = DISCL_NONEXCLUSIVE | DISCL_BACKGROUND;
193 newDevice->base.guid = *rguid;
194 InitializeCriticalSection(&newDevice->base.crit);
195 newDevice->base.crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": SysMouseImpl*->base.crit");
196 newDevice->base.dinput = dinput;
197 newDevice->base.event_proc = dinput_mouse_hook;
198
199 get_app_key(&hkey, &appkey);
200 if (!get_config_key(hkey, appkey, "MouseWarpOverride", buffer, sizeof(buffer)))
201 {
202 if (!strcasecmp(buffer, "disable"))
203 newDevice->warp_override = WARP_DISABLE;
204 else if (!strcasecmp(buffer, "force"))
205 newDevice->warp_override = WARP_FORCE_ON;
206 }
207 if (appkey) RegCloseKey(appkey);
208 if (hkey) RegCloseKey(hkey);
209
210 /* Create copy of default data format */
211 if (!(df = HeapAlloc(GetProcessHeap(), 0, c_dfDIMouse2.dwSize))) goto failed;
212 memcpy(df, &c_dfDIMouse2, c_dfDIMouse2.dwSize);
213 if (!(df->rgodf = HeapAlloc(GetProcessHeap(), 0, df->dwNumObjs * df->dwObjSize))) goto failed;
214 memcpy(df->rgodf, c_dfDIMouse2.rgodf, df->dwNumObjs * df->dwObjSize);
215
216 /* Because we don't do any detection yet just modify instance and type */
217 for (i = 0; i < df->dwNumObjs; i++)
218 if (DIDFT_GETTYPE(df->rgodf[i].dwType) & DIDFT_AXIS)
219 df->rgodf[i].dwType = DIDFT_MAKEINSTANCE(i) | DIDFT_RELAXIS;
220 else
221 df->rgodf[i].dwType = DIDFT_MAKEINSTANCE(i) | DIDFT_PSHBUTTON;
222
223 newDevice->base.data_format.wine_df = df;
224 IDirectInput_AddRef(&newDevice->base.dinput->IDirectInput7A_iface);
225
226 EnterCriticalSection(&dinput->crit);
227 list_add_tail(&dinput->devices_list, &newDevice->base.entry);
228 LeaveCriticalSection(&dinput->crit);
229
230 return newDevice;
231
232 failed:
233 if (df) HeapFree(GetProcessHeap(), 0, df->rgodf);
234 HeapFree(GetProcessHeap(), 0, df);
235 HeapFree(GetProcessHeap(), 0, newDevice);
236 return NULL;
237 }
238
239 static HRESULT mousedev_create_device(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPVOID *pdev, int unicode)
240 {
241 TRACE("%p %s %s %p %i\n", dinput, debugstr_guid(rguid), debugstr_guid(riid), pdev, unicode);
242 *pdev = NULL;
243
244 if (IsEqualGUID(&GUID_SysMouse, rguid) || /* Generic Mouse */
245 IsEqualGUID(&DInput_Wine_Mouse_GUID, rguid)) /* Wine Mouse */
246 {
247 SysMouseImpl *This;
248
249 if (riid == NULL)
250 ;/* nothing */
251 else if (IsEqualGUID(&IID_IDirectInputDeviceA, riid) ||
252 IsEqualGUID(&IID_IDirectInputDevice2A, riid) ||
253 IsEqualGUID(&IID_IDirectInputDevice7A, riid) ||
254 IsEqualGUID(&IID_IDirectInputDevice8A, riid))
255 {
256 unicode = 0;
257 }
258 else if (IsEqualGUID(&IID_IDirectInputDeviceW, riid) ||
259 IsEqualGUID(&IID_IDirectInputDevice2W, riid) ||
260 IsEqualGUID(&IID_IDirectInputDevice7W, riid) ||
261 IsEqualGUID(&IID_IDirectInputDevice8W, riid))
262 {
263 unicode = 1;
264 }
265 else
266 {
267 WARN("no interface\n");
268 return DIERR_NOINTERFACE;
269 }
270
271 This = alloc_device(rguid, dinput);
272 TRACE("Created a Mouse device (%p)\n", This);
273
274 if (!This) return DIERR_OUTOFMEMORY;
275
276 if (unicode)
277 *pdev = &This->base.IDirectInputDevice8W_iface;
278 else
279 *pdev = &This->base.IDirectInputDevice8A_iface;
280
281 return DI_OK;
282 }
283
284 return DIERR_DEVICENOTREG;
285 }
286
287 const struct dinput_device mouse_device = {
288 "Wine mouse driver",
289 mousedev_enum_deviceA,
290 mousedev_enum_deviceW,
291 mousedev_create_device
292 };
293
294 /******************************************************************************
295 * SysMouseA (DInput Mouse support)
296 */
297
298 /* low-level mouse hook */
299 static int dinput_mouse_hook( LPDIRECTINPUTDEVICE8A iface, WPARAM wparam, LPARAM lparam )
300 {
301 MSLLHOOKSTRUCT *hook = (MSLLHOOKSTRUCT *)lparam;
302 SysMouseImpl* This = impl_from_IDirectInputDevice8A(iface);
303 int wdata = 0, inst_id = -1, ret = 0;
304
305 TRACE("msg %lx @ (%d %d)\n", wparam, hook->pt.x, hook->pt.y);
306
307 EnterCriticalSection(&This->base.crit);
308
309 switch(wparam) {
310 case WM_MOUSEMOVE:
311 {
312 POINT pt, pt1;
313
314 GetCursorPos(&pt);
315 This->m_state.lX += pt.x = hook->pt.x - pt.x;
316 This->m_state.lY += pt.y = hook->pt.y - pt.y;
317
318 if (This->base.data_format.user_df->dwFlags & DIDF_ABSAXIS)
319 {
320 pt1.x = This->m_state.lX;
321 pt1.y = This->m_state.lY;
322 } else
323 pt1 = pt;
324
325 if (pt.x)
326 {
327 inst_id = DIDFT_MAKEINSTANCE(WINE_MOUSE_X_AXIS_INSTANCE) | DIDFT_RELAXIS;
328 wdata = pt1.x;
329 }
330 if (pt.y)
331 {
332 /* Already have X, need to queue it */
333 if (inst_id != -1)
334 queue_event(iface, inst_id,
335 wdata, GetCurrentTime(), This->base.dinput->evsequence);
336 inst_id = DIDFT_MAKEINSTANCE(WINE_MOUSE_Y_AXIS_INSTANCE) | DIDFT_RELAXIS;
337 wdata = pt1.y;
338 }
339
340 if (pt.x || pt.y)
341 {
342 if ((This->warp_override == WARP_FORCE_ON) ||
343 (This->warp_override != WARP_DISABLE && (This->base.dwCoopLevel & DISCL_EXCLUSIVE)))
344 This->need_warp = TRUE;
345 }
346 break;
347 }
348 case WM_MOUSEWHEEL:
349 inst_id = DIDFT_MAKEINSTANCE(WINE_MOUSE_Z_AXIS_INSTANCE) | DIDFT_RELAXIS;
350 This->m_state.lZ += wdata = (short)HIWORD(hook->mouseData);
351 /* FarCry crashes if it gets a mouse wheel message */
352 /* FIXME: should probably filter out other messages too */
353 ret = This->clipped;
354 break;
355 case WM_LBUTTONDOWN:
356 inst_id = DIDFT_MAKEINSTANCE(WINE_MOUSE_BUTTONS_INSTANCE + 0) | DIDFT_PSHBUTTON;
357 This->m_state.rgbButtons[0] = wdata = 0x80;
358 break;
359 case WM_LBUTTONUP:
360 inst_id = DIDFT_MAKEINSTANCE(WINE_MOUSE_BUTTONS_INSTANCE + 0) | DIDFT_PSHBUTTON;
361 This->m_state.rgbButtons[0] = wdata = 0x00;
362 break;
363 case WM_RBUTTONDOWN:
364 inst_id = DIDFT_MAKEINSTANCE(WINE_MOUSE_BUTTONS_INSTANCE + 1) | DIDFT_PSHBUTTON;
365 This->m_state.rgbButtons[1] = wdata = 0x80;
366 break;
367 case WM_RBUTTONUP:
368 inst_id = DIDFT_MAKEINSTANCE(WINE_MOUSE_BUTTONS_INSTANCE + 1) | DIDFT_PSHBUTTON;
369 This->m_state.rgbButtons[1] = wdata = 0x00;
370 break;
371 case WM_MBUTTONDOWN:
372 inst_id = DIDFT_MAKEINSTANCE(WINE_MOUSE_BUTTONS_INSTANCE + 2) | DIDFT_PSHBUTTON;
373 This->m_state.rgbButtons[2] = wdata = 0x80;
374 break;
375 case WM_MBUTTONUP:
376 inst_id = DIDFT_MAKEINSTANCE(WINE_MOUSE_BUTTONS_INSTANCE + 2) | DIDFT_PSHBUTTON;
377 This->m_state.rgbButtons[2] = wdata = 0x00;
378 break;
379 case WM_XBUTTONDOWN:
380 inst_id = DIDFT_MAKEINSTANCE(WINE_MOUSE_BUTTONS_INSTANCE + 2 + HIWORD(hook->mouseData)) | DIDFT_PSHBUTTON;
381 This->m_state.rgbButtons[2 + HIWORD(hook->mouseData)] = wdata = 0x80;
382 break;
383 case WM_XBUTTONUP:
384 inst_id = DIDFT_MAKEINSTANCE(WINE_MOUSE_BUTTONS_INSTANCE + 2 + HIWORD(hook->mouseData)) | DIDFT_PSHBUTTON;
385 This->m_state.rgbButtons[2 + HIWORD(hook->mouseData)] = wdata = 0x00;
386 break;
387 }
388
389
390 if (inst_id != -1)
391 {
392 _dump_mouse_state(&This->m_state);
393 queue_event(iface, inst_id,
394 wdata, GetCurrentTime(), This->base.dinput->evsequence++);
395 }
396
397 LeaveCriticalSection(&This->base.crit);
398 return ret;
399 }
400
401 static void warp_check( SysMouseImpl* This, BOOL force )
402 {
403 DWORD now = GetCurrentTime();
404 const DWORD interval = This->clipped ? 500 : 10;
405
406 if (force || (This->need_warp && (now - This->last_warped > interval)))
407 {
408 RECT rect, new_rect;
409 POINT mapped_center;
410
411 This->last_warped = now;
412 This->need_warp = FALSE;
413 if (!GetClientRect(This->base.win, &rect)) return;
414 MapWindowPoints( This->base.win, 0, (POINT *)&rect, 2 );
415 if (!This->clipped)
416 {
417 mapped_center.x = (rect.left + rect.right) / 2;
418 mapped_center.y = (rect.top + rect.bottom) / 2;
419 TRACE("Warping mouse to %d - %d\n", mapped_center.x, mapped_center.y);
420 SetCursorPos( mapped_center.x, mapped_center.y );
421 }
422 if (This->base.dwCoopLevel & DISCL_EXCLUSIVE)
423 {
424 /* make sure we clip even if the window covers the whole screen */
425 rect.left = max( rect.left, GetSystemMetrics( SM_XVIRTUALSCREEN ) + 1 );
426 rect.top = max( rect.top, GetSystemMetrics( SM_YVIRTUALSCREEN ) + 1 );
427 rect.right = min( rect.right, rect.left + GetSystemMetrics( SM_CXVIRTUALSCREEN ) - 2 );
428 rect.bottom = min( rect.bottom, rect.top + GetSystemMetrics( SM_CYVIRTUALSCREEN ) - 2 );
429 TRACE("Clipping mouse to %s\n", wine_dbgstr_rect( &rect ));
430 ClipCursor( &rect );
431 This->clipped = GetClipCursor( &new_rect ) && EqualRect( &rect, &new_rect );
432 }
433 }
434 }
435
436
437 /******************************************************************************
438 * Acquire : gets exclusive control of the mouse
439 */
440 static HRESULT WINAPI SysMouseWImpl_Acquire(LPDIRECTINPUTDEVICE8W iface)
441 {
442 SysMouseImpl *This = impl_from_IDirectInputDevice8W(iface);
443 POINT point;
444 HRESULT res;
445
446 TRACE("(this=%p)\n",This);
447
448 if ((res = IDirectInputDevice2WImpl_Acquire(iface)) != DI_OK) return res;
449
450 /* Init the mouse state */
451 GetCursorPos( &point );
452 if (This->base.data_format.user_df->dwFlags & DIDF_ABSAXIS)
453 {
454 This->m_state.lX = point.x;
455 This->m_state.lY = point.y;
456 } else {
457 This->m_state.lX = 0;
458 This->m_state.lY = 0;
459 This->org_coords = point;
460 }
461 This->m_state.lZ = 0;
462 This->m_state.rgbButtons[0] = GetKeyState(VK_LBUTTON) & 0x80;
463 This->m_state.rgbButtons[1] = GetKeyState(VK_RBUTTON) & 0x80;
464 This->m_state.rgbButtons[2] = GetKeyState(VK_MBUTTON) & 0x80;
465
466 if (This->base.dwCoopLevel & DISCL_EXCLUSIVE)
467 {
468 ShowCursor(FALSE); /* hide cursor */
469 warp_check( This, TRUE );
470 }
471 else if (This->warp_override == WARP_FORCE_ON)
472 {
473 /* Need a window to warp mouse in. */
474 if (!This->base.win) This->base.win = GetDesktopWindow();
475 warp_check( This, TRUE );
476 }
477 else if (This->clipped)
478 {
479 ClipCursor( NULL );
480 This->clipped = FALSE;
481 }
482
483 return DI_OK;
484 }
485
486 static HRESULT WINAPI SysMouseAImpl_Acquire(LPDIRECTINPUTDEVICE8A iface)
487 {
488 SysMouseImpl *This = impl_from_IDirectInputDevice8A(iface);
489 return SysMouseWImpl_Acquire(IDirectInputDevice8W_from_impl(This));
490 }
491
492 /******************************************************************************
493 * Unacquire : frees the mouse
494 */
495 static HRESULT WINAPI SysMouseWImpl_Unacquire(LPDIRECTINPUTDEVICE8W iface)
496 {
497 SysMouseImpl *This = impl_from_IDirectInputDevice8W(iface);
498 HRESULT res;
499
500 TRACE("(this=%p)\n",This);
501
502 if ((res = IDirectInputDevice2WImpl_Unacquire(iface)) != DI_OK) return res;
503
504 if (This->base.dwCoopLevel & DISCL_EXCLUSIVE)
505 {
506 ClipCursor(NULL);
507 ShowCursor(TRUE); /* show cursor */
508 This->clipped = FALSE;
509 }
510
511 /* And put the mouse cursor back where it was at acquire time */
512 if (This->base.dwCoopLevel & DISCL_EXCLUSIVE || This->warp_override == WARP_FORCE_ON)
513 {
514 TRACE("warping mouse back to %s\n", wine_dbgstr_point(&This->org_coords));
515 SetCursorPos(This->org_coords.x, This->org_coords.y);
516 }
517
518 return DI_OK;
519 }
520
521 static HRESULT WINAPI SysMouseAImpl_Unacquire(LPDIRECTINPUTDEVICE8A iface)
522 {
523 SysMouseImpl *This = impl_from_IDirectInputDevice8A(iface);
524 return SysMouseWImpl_Unacquire(IDirectInputDevice8W_from_impl(This));
525 }
526
527 /******************************************************************************
528 * GetDeviceState : returns the "state" of the mouse.
529 *
530 * For the moment, only the "standard" return structure (DIMOUSESTATE) is
531 * supported.
532 */
533 static HRESULT WINAPI SysMouseWImpl_GetDeviceState(LPDIRECTINPUTDEVICE8W iface, DWORD len, LPVOID ptr)
534 {
535 SysMouseImpl *This = impl_from_IDirectInputDevice8W(iface);
536
537 if(This->base.acquired == 0) return DIERR_NOTACQUIRED;
538
539 TRACE("(this=%p,0x%08x,%p):\n", This, len, ptr);
540 _dump_mouse_state(&This->m_state);
541
542 EnterCriticalSection(&This->base.crit);
543 /* Copy the current mouse state */
544 fill_DataFormat(ptr, len, &This->m_state, &This->base.data_format);
545
546 /* Initialize the buffer when in relative mode */
547 if (!(This->base.data_format.user_df->dwFlags & DIDF_ABSAXIS))
548 {
549 This->m_state.lX = 0;
550 This->m_state.lY = 0;
551 This->m_state.lZ = 0;
552 }
553 LeaveCriticalSection(&This->base.crit);
554
555 warp_check( This, FALSE );
556 return DI_OK;
557 }
558
559 static HRESULT WINAPI SysMouseAImpl_GetDeviceState(LPDIRECTINPUTDEVICE8A iface, DWORD len, LPVOID ptr)
560 {
561 SysMouseImpl *This = impl_from_IDirectInputDevice8A(iface);
562 return SysMouseWImpl_GetDeviceState(IDirectInputDevice8W_from_impl(This), len, ptr);
563 }
564
565 /******************************************************************************
566 * GetDeviceData : gets buffered input data.
567 */
568 static HRESULT WINAPI SysMouseWImpl_GetDeviceData(LPDIRECTINPUTDEVICE8W iface,
569 DWORD dodsize, LPDIDEVICEOBJECTDATA dod, LPDWORD entries, DWORD flags)
570 {
571 SysMouseImpl *This = impl_from_IDirectInputDevice8W(iface);
572 HRESULT res;
573
574 res = IDirectInputDevice2WImpl_GetDeviceData(iface, dodsize, dod, entries, flags);
575 if (SUCCEEDED(res)) warp_check( This, FALSE );
576 return res;
577 }
578
579 static HRESULT WINAPI SysMouseAImpl_GetDeviceData(LPDIRECTINPUTDEVICE8A iface,
580 DWORD dodsize, LPDIDEVICEOBJECTDATA dod, LPDWORD entries, DWORD flags)
581 {
582 SysMouseImpl *This = impl_from_IDirectInputDevice8A(iface);
583 return SysMouseWImpl_GetDeviceData(IDirectInputDevice8W_from_impl(This), dodsize, dod, entries, flags);
584 }
585
586 /******************************************************************************
587 * GetProperty : get input device properties
588 */
589 static HRESULT WINAPI SysMouseWImpl_GetProperty(LPDIRECTINPUTDEVICE8W iface, REFGUID rguid, LPDIPROPHEADER pdiph)
590 {
591 SysMouseImpl *This = impl_from_IDirectInputDevice8W(iface);
592
593 TRACE("(%p) %s,%p\n", This, debugstr_guid(rguid), pdiph);
594 _dump_DIPROPHEADER(pdiph);
595
596 if (IS_DIPROP(rguid)) {
597 switch (LOWORD(rguid)) {
598 case (DWORD_PTR) DIPROP_GRANULARITY: {
599 LPDIPROPDWORD pr = (LPDIPROPDWORD) pdiph;
600
601 /* We'll just assume that the app asks about the Z axis */
602 pr->dwData = WHEEL_DELTA;
603
604 break;
605 }
606
607 case (DWORD_PTR) DIPROP_RANGE: {
608 LPDIPROPRANGE pr = (LPDIPROPRANGE) pdiph;
609
610 if ((pdiph->dwHow == DIPH_BYID) &&
611 ((pdiph->dwObj == (DIDFT_MAKEINSTANCE(WINE_MOUSE_X_AXIS_INSTANCE) | DIDFT_RELAXIS)) ||
612 (pdiph->dwObj == (DIDFT_MAKEINSTANCE(WINE_MOUSE_Y_AXIS_INSTANCE) | DIDFT_RELAXIS)))) {
613 /* Querying the range of either the X or the Y axis. As I do
614 not know the range, do as if the range were
615 unrestricted...*/
616 pr->lMin = DIPROPRANGE_NOMIN;
617 pr->lMax = DIPROPRANGE_NOMAX;
618 }
619
620 break;
621 }
622
623 default:
624 return IDirectInputDevice2WImpl_GetProperty(iface, rguid, pdiph);
625 }
626 }
627
628 return DI_OK;
629 }
630
631 static HRESULT WINAPI SysMouseAImpl_GetProperty(LPDIRECTINPUTDEVICE8A iface, REFGUID rguid, LPDIPROPHEADER pdiph)
632 {
633 SysMouseImpl *This = impl_from_IDirectInputDevice8A(iface);
634 return SysMouseWImpl_GetProperty(IDirectInputDevice8W_from_impl(This), rguid, pdiph);
635 }
636
637 /******************************************************************************
638 * GetCapabilities : get the device capabilities
639 */
640 static HRESULT WINAPI SysMouseWImpl_GetCapabilities(LPDIRECTINPUTDEVICE8W iface, LPDIDEVCAPS lpDIDevCaps)
641 {
642 SysMouseImpl *This = impl_from_IDirectInputDevice8W(iface);
643 DIDEVCAPS devcaps;
644
645 TRACE("(this=%p,%p)\n",This,lpDIDevCaps);
646
647 if ((lpDIDevCaps->dwSize != sizeof(DIDEVCAPS)) && (lpDIDevCaps->dwSize != sizeof(DIDEVCAPS_DX3))) {
648 WARN("invalid parameter\n");
649 return DIERR_INVALIDPARAM;
650 }
651
652 devcaps.dwSize = lpDIDevCaps->dwSize;
653 devcaps.dwFlags = DIDC_ATTACHED | DIDC_EMULATED;
654 if (This->base.dinput->dwVersion >= 0x0800)
655 devcaps.dwDevType = DI8DEVTYPE_MOUSE | (DI8DEVTYPEMOUSE_TRADITIONAL << 8);
656 else
657 devcaps.dwDevType = DIDEVTYPE_MOUSE | (DIDEVTYPEMOUSE_TRADITIONAL << 8);
658 devcaps.dwAxes = 3;
659 devcaps.dwButtons = 8;
660 devcaps.dwPOVs = 0;
661 devcaps.dwFFSamplePeriod = 0;
662 devcaps.dwFFMinTimeResolution = 0;
663 devcaps.dwFirmwareRevision = 100;
664 devcaps.dwHardwareRevision = 100;
665 devcaps.dwFFDriverVersion = 0;
666
667 memcpy(lpDIDevCaps, &devcaps, lpDIDevCaps->dwSize);
668
669 return DI_OK;
670 }
671
672 static HRESULT WINAPI SysMouseAImpl_GetCapabilities(LPDIRECTINPUTDEVICE8A iface, LPDIDEVCAPS lpDIDevCaps)
673 {
674 SysMouseImpl *This = impl_from_IDirectInputDevice8A(iface);
675 return SysMouseWImpl_GetCapabilities(IDirectInputDevice8W_from_impl(This), lpDIDevCaps);
676 }
677
678 /******************************************************************************
679 * GetObjectInfo : get information about a device object such as a button
680 * or axis
681 */
682 static HRESULT WINAPI SysMouseWImpl_GetObjectInfo(LPDIRECTINPUTDEVICE8W iface,
683 LPDIDEVICEOBJECTINSTANCEW pdidoi, DWORD dwObj, DWORD dwHow)
684 {
685 static const WCHAR x_axisW[] = {'X','-','A','x','i','s',0};
686 static const WCHAR y_axisW[] = {'Y','-','A','x','i','s',0};
687 static const WCHAR wheelW[] = {'W','h','e','e','l',0};
688 static const WCHAR buttonW[] = {'B','u','t','t','o','n',' ','%','d',0};
689 HRESULT res;
690
691 res = IDirectInputDevice2WImpl_GetObjectInfo(iface, pdidoi, dwObj, dwHow);
692 if (res != DI_OK) return res;
693
694 if (IsEqualGUID(&pdidoi->guidType, &GUID_XAxis)) strcpyW(pdidoi->tszName, x_axisW);
695 else if (IsEqualGUID(&pdidoi->guidType, &GUID_YAxis)) strcpyW(pdidoi->tszName, y_axisW);
696 else if (IsEqualGUID(&pdidoi->guidType, &GUID_ZAxis)) strcpyW(pdidoi->tszName, wheelW);
697 else if (pdidoi->dwType & DIDFT_BUTTON)
698 wsprintfW(pdidoi->tszName, buttonW, DIDFT_GETINSTANCE(pdidoi->dwType) - 3);
699
700 _dump_OBJECTINSTANCEW(pdidoi);
701 return res;
702 }
703
704 static HRESULT WINAPI SysMouseAImpl_GetObjectInfo(LPDIRECTINPUTDEVICE8A iface,
705 LPDIDEVICEOBJECTINSTANCEA pdidoi, DWORD dwObj, DWORD dwHow)
706 {
707 SysMouseImpl *This = impl_from_IDirectInputDevice8A(iface);
708 HRESULT res;
709 DIDEVICEOBJECTINSTANCEW didoiW;
710 DWORD dwSize = pdidoi->dwSize;
711
712 didoiW.dwSize = sizeof(didoiW);
713 res = SysMouseWImpl_GetObjectInfo(IDirectInputDevice8W_from_impl(This), &didoiW, dwObj, dwHow);
714 if (res != DI_OK) return res;
715
716 memset(pdidoi, 0, pdidoi->dwSize);
717 memcpy(pdidoi, &didoiW, FIELD_OFFSET(DIDEVICEOBJECTINSTANCEW, tszName));
718 pdidoi->dwSize = dwSize;
719 WideCharToMultiByte(CP_ACP, 0, didoiW.tszName, -1, pdidoi->tszName,
720 sizeof(pdidoi->tszName), NULL, NULL);
721
722 return res;
723 }
724
725 /******************************************************************************
726 * GetDeviceInfo : get information about a device's identity
727 */
728 static HRESULT WINAPI SysMouseAImpl_GetDeviceInfo(
729 LPDIRECTINPUTDEVICE8A iface,
730 LPDIDEVICEINSTANCEA pdidi)
731 {
732 SysMouseImpl *This = impl_from_IDirectInputDevice8A(iface);
733 TRACE("(this=%p,%p)\n", This, pdidi);
734
735 if (pdidi->dwSize != sizeof(DIDEVICEINSTANCEA)) {
736 WARN(" dinput3 not supported yet...\n");
737 return DI_OK;
738 }
739
740 fill_mouse_dideviceinstanceA(pdidi, This->base.dinput->dwVersion);
741
742 return DI_OK;
743 }
744
745 static HRESULT WINAPI SysMouseWImpl_GetDeviceInfo(LPDIRECTINPUTDEVICE8W iface, LPDIDEVICEINSTANCEW pdidi)
746 {
747 SysMouseImpl *This = impl_from_IDirectInputDevice8W(iface);
748 TRACE("(this=%p,%p)\n", This, pdidi);
749
750 if (pdidi->dwSize != sizeof(DIDEVICEINSTANCEW)) {
751 WARN(" dinput3 not supported yet...\n");
752 return DI_OK;
753 }
754
755 fill_mouse_dideviceinstanceW(pdidi, This->base.dinput->dwVersion);
756
757 return DI_OK;
758 }
759
760 static HRESULT WINAPI SysMouseWImpl_BuildActionMap(LPDIRECTINPUTDEVICE8W iface,
761 LPDIACTIONFORMATW lpdiaf,
762 LPCWSTR lpszUserName,
763 DWORD dwFlags)
764 {
765 FIXME("(%p)->(%p,%s,%08x): semi-stub !\n", iface, lpdiaf, debugstr_w(lpszUserName), dwFlags);
766
767 return _build_action_map(iface, lpdiaf, lpszUserName, dwFlags, DIMOUSE_MASK, &c_dfDIMouse2);
768 }
769
770 static HRESULT WINAPI SysMouseAImpl_BuildActionMap(LPDIRECTINPUTDEVICE8A iface,
771 LPDIACTIONFORMATA lpdiaf,
772 LPCSTR lpszUserName,
773 DWORD dwFlags)
774 {
775 SysMouseImpl *This = impl_from_IDirectInputDevice8A(iface);
776 DIACTIONFORMATW diafW;
777 HRESULT hr;
778 WCHAR *lpszUserNameW = NULL;
779 int username_size;
780
781 diafW.rgoAction = HeapAlloc(GetProcessHeap(), 0, sizeof(DIACTIONW)*lpdiaf->dwNumActions);
782 _copy_diactionformatAtoW(&diafW, lpdiaf);
783
784 if (lpszUserName != NULL)
785 {
786 username_size = MultiByteToWideChar(CP_ACP, 0, lpszUserName, -1, NULL, 0);
787 lpszUserNameW = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*username_size);
788 MultiByteToWideChar(CP_ACP, 0, lpszUserName, -1, lpszUserNameW, username_size);
789 }
790
791 hr = SysMouseWImpl_BuildActionMap(&This->base.IDirectInputDevice8W_iface, &diafW, lpszUserNameW, dwFlags);
792
793 _copy_diactionformatWtoA(lpdiaf, &diafW);
794 HeapFree(GetProcessHeap(), 0, diafW.rgoAction);
795 HeapFree(GetProcessHeap(), 0, lpszUserNameW);
796
797 return hr;
798 }
799
800 static HRESULT WINAPI SysMouseWImpl_SetActionMap(LPDIRECTINPUTDEVICE8W iface,
801 LPDIACTIONFORMATW lpdiaf,
802 LPCWSTR lpszUserName,
803 DWORD dwFlags)
804 {
805 FIXME("(%p)->(%p,%s,%08x): semi-stub !\n", iface, lpdiaf, debugstr_w(lpszUserName), dwFlags);
806
807 return _set_action_map(iface, lpdiaf, lpszUserName, dwFlags, &c_dfDIMouse2);
808 }
809
810 static HRESULT WINAPI SysMouseAImpl_SetActionMap(LPDIRECTINPUTDEVICE8A iface,
811 LPDIACTIONFORMATA lpdiaf,
812 LPCSTR lpszUserName,
813 DWORD dwFlags)
814 {
815 SysMouseImpl *This = impl_from_IDirectInputDevice8A(iface);
816 DIACTIONFORMATW diafW;
817 HRESULT hr;
818 WCHAR *lpszUserNameW = NULL;
819 int username_size;
820
821 diafW.rgoAction = HeapAlloc(GetProcessHeap(), 0, sizeof(DIACTIONW)*lpdiaf->dwNumActions);
822 _copy_diactionformatAtoW(&diafW, lpdiaf);
823
824 if (lpszUserName != NULL)
825 {
826 username_size = MultiByteToWideChar(CP_ACP, 0, lpszUserName, -1, NULL, 0);
827 lpszUserNameW = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*username_size);
828 MultiByteToWideChar(CP_ACP, 0, lpszUserName, -1, lpszUserNameW, username_size);
829 }
830
831 hr = SysMouseWImpl_SetActionMap(&This->base.IDirectInputDevice8W_iface, &diafW, lpszUserNameW, dwFlags);
832
833 HeapFree(GetProcessHeap(), 0, diafW.rgoAction);
834 HeapFree(GetProcessHeap(), 0, lpszUserNameW);
835
836 return hr;
837 }
838
839 static const IDirectInputDevice8AVtbl SysMouseAvt =
840 {
841 IDirectInputDevice2AImpl_QueryInterface,
842 IDirectInputDevice2AImpl_AddRef,
843 IDirectInputDevice2AImpl_Release,
844 SysMouseAImpl_GetCapabilities,
845 IDirectInputDevice2AImpl_EnumObjects,
846 SysMouseAImpl_GetProperty,
847 IDirectInputDevice2AImpl_SetProperty,
848 SysMouseAImpl_Acquire,
849 SysMouseAImpl_Unacquire,
850 SysMouseAImpl_GetDeviceState,
851 SysMouseAImpl_GetDeviceData,
852 IDirectInputDevice2AImpl_SetDataFormat,
853 IDirectInputDevice2AImpl_SetEventNotification,
854 IDirectInputDevice2AImpl_SetCooperativeLevel,
855 SysMouseAImpl_GetObjectInfo,
856 SysMouseAImpl_GetDeviceInfo,
857 IDirectInputDevice2AImpl_RunControlPanel,
858 IDirectInputDevice2AImpl_Initialize,
859 IDirectInputDevice2AImpl_CreateEffect,
860 IDirectInputDevice2AImpl_EnumEffects,
861 IDirectInputDevice2AImpl_GetEffectInfo,
862 IDirectInputDevice2AImpl_GetForceFeedbackState,
863 IDirectInputDevice2AImpl_SendForceFeedbackCommand,
864 IDirectInputDevice2AImpl_EnumCreatedEffectObjects,
865 IDirectInputDevice2AImpl_Escape,
866 IDirectInputDevice2AImpl_Poll,
867 IDirectInputDevice2AImpl_SendDeviceData,
868 IDirectInputDevice7AImpl_EnumEffectsInFile,
869 IDirectInputDevice7AImpl_WriteEffectToFile,
870 SysMouseAImpl_BuildActionMap,
871 SysMouseAImpl_SetActionMap,
872 IDirectInputDevice8AImpl_GetImageInfo
873 };
874
875 static const IDirectInputDevice8WVtbl SysMouseWvt =
876 {
877 IDirectInputDevice2WImpl_QueryInterface,
878 IDirectInputDevice2WImpl_AddRef,
879 IDirectInputDevice2WImpl_Release,
880 SysMouseWImpl_GetCapabilities,
881 IDirectInputDevice2WImpl_EnumObjects,
882 SysMouseWImpl_GetProperty,
883 IDirectInputDevice2WImpl_SetProperty,
884 SysMouseWImpl_Acquire,
885 SysMouseWImpl_Unacquire,
886 SysMouseWImpl_GetDeviceState,
887 SysMouseWImpl_GetDeviceData,
888 IDirectInputDevice2WImpl_SetDataFormat,
889 IDirectInputDevice2WImpl_SetEventNotification,
890 IDirectInputDevice2WImpl_SetCooperativeLevel,
891 SysMouseWImpl_GetObjectInfo,
892 SysMouseWImpl_GetDeviceInfo,
893 IDirectInputDevice2WImpl_RunControlPanel,
894 IDirectInputDevice2WImpl_Initialize,
895 IDirectInputDevice2WImpl_CreateEffect,
896 IDirectInputDevice2WImpl_EnumEffects,
897 IDirectInputDevice2WImpl_GetEffectInfo,
898 IDirectInputDevice2WImpl_GetForceFeedbackState,
899 IDirectInputDevice2WImpl_SendForceFeedbackCommand,
900 IDirectInputDevice2WImpl_EnumCreatedEffectObjects,
901 IDirectInputDevice2WImpl_Escape,
902 IDirectInputDevice2WImpl_Poll,
903 IDirectInputDevice2WImpl_SendDeviceData,
904 IDirectInputDevice7WImpl_EnumEffectsInFile,
905 IDirectInputDevice7WImpl_WriteEffectToFile,
906 SysMouseWImpl_BuildActionMap,
907 SysMouseWImpl_SetActionMap,
908 IDirectInputDevice8WImpl_GetImageInfo
909 };