Release 20030408.
[wine/gsoc-2012-control.git] / dlls / dinput / mouse / main.c
blob2450cba1f8190d3d57136885bd57bde6b9c520d4
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
22 #include "config.h"
23 #include "wine/port.h"
25 #include <string.h>
27 #include "winbase.h"
28 #include "wingdi.h"
29 #include "winuser.h"
30 #include "winerror.h"
31 #include "dinput.h"
33 #include "dinput_private.h"
34 #include "device_private.h"
35 #include "wine/debug.h"
37 #define MOUSE_HACK
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
61 typedef struct {
62 LONG lX;
63 LONG lY;
64 LONG lZ;
65 BYTE rgbButtons[4];
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;
97 typedef enum {
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 */
101 } WARP_STATUS;
103 struct SysMouseAImpl
105 LPVOID lpVtbl;
106 DWORD ref;
107 GUID guid;
109 IDirectInputAImpl *dinput;
111 /* The current data format and the conversion between internal
112 and external data formats */
113 LPDIDATAFORMAT df;
114 DataFormat *wine_df;
115 int offset_array[WINE_INTERNALMOUSE_NUM_OBJS];
117 /* SysMouseAImpl */
118 BYTE absolute;
119 /* Previous position for relative moves */
120 LONG prevX, prevY;
121 HHOOK hook;
122 HWND win;
123 DWORD dwCoopLevel;
124 POINT mapped_center;
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;
131 int acquired;
132 HANDLE hEvent;
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 */
140 0x9e573ed8,
141 0x7734,
142 0x11d2,
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");
155 /* Return mouse */
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");
162 return TRUE;
165 return FALSE;
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));
180 newDevice->ref = 1;
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;
194 return newDevice;
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);
208 return DI_OK;
209 } else
210 return DIERR_NOINTERFACE;
213 return DIERR_DEVICENOTREG;
216 static dinput_device mousedev = {
217 100,
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);
235 This->ref--;
236 if (This->ref)
237 return This->ref;
239 /* Free the data queue */
240 if (This->data_queue != NULL)
241 HeapFree(GetProcessHeap(),0,This->data_queue);
243 if (This->hook) {
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);
257 return 0;
261 /******************************************************************************
262 * SetCooperativeLevel : store the window in which we will do our
263 * grabbing.
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 */
279 if (!hwnd)
280 hwnd = GetDesktopWindow();
281 This->win = hwnd;
282 This->dwCoopLevel = dwflags;
284 return 0;
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);
300 int i;
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)
320 This->absolute = 1;
321 else if (df->dwFlags == DIDF_RELAXIS)
322 This->absolute = 0;
323 else
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);
335 return 0;
338 /* low-level mouse hook */
339 static LRESULT CALLBACK dinput_mouse_hook( int code, WPARAM wparam, LPARAM lparam )
341 LRESULT ret;
342 MSLLHOOKSTRUCT *hook = (MSLLHOOKSTRUCT *)lparam;
343 SysMouseAImpl* This = (SysMouseAImpl*) current_lock;
344 DWORD dwCoop;
345 static long last_event = 0;
346 int wdata;
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)
360 goto end;
361 else last_event = GetCurrentTime();
363 /* Mouse moved -> send event if asked */
364 if (This->hEvent)
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);
373 } else {
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;
379 goto end;
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)++);
389 } else {
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;
410 } else {
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 );
419 switch(wparam)
421 case WM_LBUTTONDOWN:
422 GEN_EVENT(This->offset_array[WINE_MOUSE_L_POSITION], 0xFF,
423 hook->time, This->dinput->evsequence++);
424 This->m_state.rgbButtons[0] = 0xFF;
425 break;
426 case WM_LBUTTONUP:
427 GEN_EVENT(This->offset_array[WINE_MOUSE_L_POSITION], 0x00,
428 hook->time, This->dinput->evsequence++);
429 This->m_state.rgbButtons[0] = 0x00;
430 break;
431 case WM_RBUTTONDOWN:
432 GEN_EVENT(This->offset_array[WINE_MOUSE_R_POSITION], 0xFF,
433 hook->time, This->dinput->evsequence++);
434 This->m_state.rgbButtons[1] = 0xFF;
435 break;
436 case WM_RBUTTONUP:
437 GEN_EVENT(This->offset_array[WINE_MOUSE_R_POSITION], 0x00,
438 hook->time, This->dinput->evsequence++);
439 This->m_state.rgbButtons[1] = 0x00;
440 break;
441 case WM_MBUTTONDOWN:
442 GEN_EVENT(This->offset_array[WINE_MOUSE_M_POSITION], 0xFF,
443 hook->time, This->dinput->evsequence++);
444 This->m_state.rgbButtons[2] = 0xFF;
445 break;
446 case WM_MBUTTONUP:
447 GEN_EVENT(This->offset_array[WINE_MOUSE_M_POSITION], 0x00,
448 hook->time, This->dinput->evsequence++);
449 This->m_state.rgbButtons[2] = 0x00;
450 break;
451 case WM_MOUSEWHEEL:
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;
456 break;
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]);
463 end:
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 */
471 return ret;
475 static void dinput_window_check(SysMouseAImpl* This)
477 RECT rect;
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);
500 RECT rect;
502 TRACE("(this=%p)\n",This);
504 if (This->acquired == 0) {
505 POINT point;
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;
517 } else {
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 );
543 #ifdef MOUSE_HACK
544 This->need_warp = WARP_DONE;
545 #else
546 This->need_warp = WARP_STARTED;
547 #endif
550 This->acquired = 1;
551 return DI_OK;
553 return S_FALSE;
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);
565 if (This->acquired)
567 /* Reinstall previous mouse event handler */
568 if (This->hook) {
569 UnhookWindowsHookEx( This->hook );
570 This->hook = 0;
571 if (This->dwCoopLevel & DISCL_EXCLUSIVE)
572 ShowCursor(TRUE); /* show cursor */
575 /* No more locks */
576 current_lock = NULL;
578 /* Unacquire device */
579 This->acquired = 0;
581 else
582 ERR("Unacquiring a not-acquired device !!!\n");
584 return DI_OK;
587 /******************************************************************************
588 * GetDeviceState : returns the "state" of the mouse.
590 * For the moment, only the "standard" return structure (DIMOUSESTATE) is
591 * supported.
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 );
617 #ifdef MOUSE_HACK
618 This->need_warp = WARP_DONE;
619 #else
620 This->need_warp = WARP_STARTED;
621 #endif
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]);
630 return 0;
633 /******************************************************************************
634 * GetDeviceState : gets buffered input data.
636 static HRESULT WINAPI SysMouseAImpl_GetDeviceData(LPDIRECTINPUTDEVICE8A iface,
637 DWORD dodsize,
638 LPDIDEVICEOBJECTDATA dod,
639 LPDWORD entries,
640 DWORD flags
642 ICOM_THIS(SysMouseAImpl,iface);
643 DWORD len, nqtail;
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;
658 if (dod == NULL) {
659 if (len)
660 TRACE("Application discarding %ld event(s).\n", len);
662 *entries = len;
663 nqtail = This->queue_tail + len;
664 while (nqtail >= This->queue_len) nqtail -= This->queue_len;
665 } else {
666 if (dodsize < sizeof(DIDEVICEOBJECTDATA)) {
667 ERR("Wrong structure size !\n");
668 LeaveCriticalSection(&(This->crit));
669 return DIERR_INVALIDPARAM;
672 if (len)
673 TRACE("Application retrieving %ld event(s).\n", len);
675 *entries = 0;
676 nqtail = This->queue_tail;
677 while (len) {
678 DWORD span = ((This->queue_head < nqtail) ? This->queue_len : This->queue_head)
679 - nqtail;
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 */
684 nqtail += span;
685 if (nqtail >= This->queue_len) nqtail -= This->queue_len;
686 *entries += span;
687 len -= span;
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 );
701 #ifdef MOUSE_HACK
702 This->need_warp = WARP_DONE;
703 #else
704 This->need_warp = WARP_STARTED;
705 #endif
707 return 0;
710 /******************************************************************************
711 * SetProperty : change input device properties
713 static HRESULT WINAPI SysMouseAImpl_SetProperty(LPDIRECTINPUTDEVICE8A iface,
714 REFGUID rguid,
715 LPCDIPROPHEADER ph)
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;
733 break;
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");
739 break;
741 default:
742 FIXME("Unknown type %ld (%s)\n",(DWORD)rguid,debugstr_guid(rguid));
743 break;
747 return 0;
750 /******************************************************************************
751 * GetProperty : get input device properties
753 static HRESULT WINAPI SysMouseAImpl_GetProperty(LPDIRECTINPUTDEVICE8A iface,
754 REFGUID rguid,
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;
772 break;
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;
781 break;
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
792 unrestricted...*/
793 pr->lMin = DIPROPRANGE_NOMIN;
794 pr->lMax = DIPROPRANGE_NOMAX;
797 break;
800 default:
801 FIXME("Unknown type %ld (%s)\n",(DWORD)rguid,debugstr_guid(rguid));
802 break;
807 return DI_OK;
812 /******************************************************************************
813 * SetEventNotification : specifies event to be sent on state change
815 static HRESULT WINAPI SysMouseAImpl_SetEventNotification(LPDIRECTINPUTDEVICE8A iface,
816 HANDLE hnd) {
817 ICOM_THIS(SysMouseAImpl,iface);
819 TRACE("(this=%p,0x%08lx)\n",This,(DWORD)hnd);
821 This->hEvent = hnd;
823 return DI_OK;
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;
848 } else {
849 /* DirectX 3.0 */
850 FIXME("DirectX 3.0 not supported....\n");
853 return DI_OK;
857 /******************************************************************************
858 * EnumObjects : enumerate the different buttons and axis...
860 static HRESULT WINAPI SysMouseAImpl_EnumObjects(
861 LPDIRECTINPUTDEVICE8A iface,
862 LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback,
863 LPVOID lpvRef,
864 DWORD dwFlags)
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);
873 TRACE("\n");
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)) {
883 /* X 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;
891 /* Y axis */
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;
899 /* Z axis */
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;
912 /* Left 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;
919 /* Right button */
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;
926 /* Middle button */
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;
934 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