source: trunk/src/dinput/mouse.c@ 8532

Last change on this file since 8532 was 8532, checked in by sandervl, 23 years ago

Ignore injected mouse messages (hook; LLMHF_INJECTED flag)

File size: 31.0 KB
Line 
1/* DirectInput Mouse device
2 *
3 * Copyright 1998 Marcus Meissner
4 * Copyright 1998,1999 Lionel Ulmer
5 *
6 */
7
8#include "config.h"
9#include <string.h>
10#ifdef HAVE_SYS_ERRNO_H
11# include <sys/errno.h>
12#endif
13
14#include "winbase.h"
15#include "wingdi.h"
16#include "winuser.h"
17#include "winerror.h"
18#include "dinput.h"
19
20#include "dinput_private.h"
21#include "device_private.h"
22#include "debugtools.h"
23
24#define MOUSE_HACK
25
26DEFAULT_DEBUG_CHANNEL(dinput);
27
28/* Wine mouse driver object instances */
29#define WINE_MOUSE_X_AXIS_INSTANCE 0x0001
30#define WINE_MOUSE_Y_AXIS_INSTANCE 0x0002
31#define WINE_MOUSE_L_BUTTON_INSTANCE 0x0004
32#define WINE_MOUSE_R_BUTTON_INSTANCE 0x0008
33#define WINE_MOUSE_M_BUTTON_INSTANCE 0x0010
34
35/* ------------------------------- */
36/* Wine mouse internal data format */
37/* ------------------------------- */
38
39/* Constants used to access the offset array */
40#define WINE_MOUSE_X_POSITION 0
41#define WINE_MOUSE_Y_POSITION 1
42#define WINE_MOUSE_L_POSITION 2
43#define WINE_MOUSE_R_POSITION 3
44#define WINE_MOUSE_M_POSITION 4
45
46typedef struct {
47 LONG lX;
48 LONG lY;
49 BYTE rgbButtons[4];
50} Wine_InternalMouseData;
51
52#define WINE_INTERNALMOUSE_NUM_OBJS 5
53
54static DIOBJECTDATAFORMAT Wine_InternalMouseObjectFormat[WINE_INTERNALMOUSE_NUM_OBJS] = {
55 { &GUID_XAxis, FIELD_OFFSET(Wine_InternalMouseData, lX),
56 DIDFT_MAKEINSTANCE(WINE_MOUSE_X_AXIS_INSTANCE) | DIDFT_RELAXIS, 0 },
57 { &GUID_YAxis, FIELD_OFFSET(Wine_InternalMouseData, lY),
58 DIDFT_MAKEINSTANCE(WINE_MOUSE_Y_AXIS_INSTANCE) | DIDFT_RELAXIS, 0 },
59 { &GUID_Button, (FIELD_OFFSET(Wine_InternalMouseData, rgbButtons)) + 0,
60 DIDFT_MAKEINSTANCE(WINE_MOUSE_L_BUTTON_INSTANCE) | DIDFT_PSHBUTTON, 0 },
61 { &GUID_Button, (FIELD_OFFSET(Wine_InternalMouseData, rgbButtons)) + 1,
62 DIDFT_MAKEINSTANCE(WINE_MOUSE_R_BUTTON_INSTANCE) | DIDFT_PSHBUTTON, 0 },
63 { &GUID_Button, (FIELD_OFFSET(Wine_InternalMouseData, rgbButtons)) + 2,
64 DIDFT_MAKEINSTANCE(WINE_MOUSE_M_BUTTON_INSTANCE) | DIDFT_PSHBUTTON, 0 }
65};
66
67static DIDATAFORMAT Wine_InternalMouseFormat = {
68 0, /* dwSize - unused */
69 0, /* dwObjsize - unused */
70 0, /* dwFlags - unused */
71 sizeof(Wine_InternalMouseData),
72 WINE_INTERNALMOUSE_NUM_OBJS, /* dwNumObjs */
73 Wine_InternalMouseObjectFormat
74};
75
76static ICOM_VTABLE(IDirectInputDevice2A) SysMouseAvt;
77static ICOM_VTABLE(IDirectInputDevice7A) SysMouse7Avt;
78typedef struct SysMouseAImpl SysMouseAImpl;
79
80typedef enum {
81 WARP_NEEDED, /* Warping is needed */
82 WARP_STARTED, /* Warping has been done, waiting for the warp event */
83 WARP_DONE /* Warping has been done */
84} WARP_STATUS;
85
86struct SysMouseAImpl
87{
88 /* IDirectInputDevice2AImpl */
89 ICOM_VFIELD(IDirectInputDevice2A);
90 DWORD ref;
91 GUID guid;
92
93 IDirectInputAImpl *dinput;
94
95 /* The current data format and the conversion between internal
96 and external data formats */
97 LPDIDATAFORMAT df;
98 DataFormat *wine_df;
99 int offset_array[5];
100
101 /* SysMouseAImpl */
102 BYTE absolute;
103 /* Previous position for relative moves */
104 LONG prevX, prevY;
105 HHOOK hook;
106 HWND win;
107 DWORD dwCoopLevel;
108 POINT mapped_center;
109 DWORD win_centerX, win_centerY;
110 LPDIDEVICEOBJECTDATA data_queue;
111 int queue_head, queue_tail, queue_len;
112 /* warping: whether we need to move mouse back to middle once we
113 * reach window borders (for e.g. shooters, "surface movement" games) */
114 WARP_STATUS need_warp;
115 int acquired;
116 HANDLE hEvent;
117 CRITICAL_SECTION crit;
118
119#ifdef __WIN32OS2__
120 char hookcode[32];
121#endif
122
123 /* This is for mouse reporting. */
124 Wine_InternalMouseData m_state;
125};
126
127static GUID DInput_Wine_Mouse_GUID = { /* 9e573ed8-7734-11d2-8d4a-23903fb6bdf7 */
128 0x9e573ed8,
129 0x7734,
130 0x11d2,
131 {0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf7}
132};
133
134/* FIXME: This is ugly and not thread safe :/ */
135static IDirectInputDevice2A* current_lock = NULL;
136
137
138static BOOL mousedev_enum_device(DWORD dwDevType, DWORD dwFlags, LPCDIDEVICEINSTANCEA lpddi)
139{
140 if ((dwDevType == 0) || (dwDevType == DIDEVTYPE_MOUSE)) {
141 TRACE("Enumerating the mouse device\n");
142
143 /* Return mouse */
144 lpddi->guidInstance = GUID_SysMouse;/* DInput's GUID */
145 lpddi->guidProduct = DInput_Wine_Mouse_GUID; /* Vendor's GUID */
146 lpddi->dwDevType = DIDEVTYPE_MOUSE | (DIDEVTYPEMOUSE_UNKNOWN << 8);
147 strcpy(lpddi->tszInstanceName, "Mouse");
148 strcpy(lpddi->tszProductName, "Wine Mouse");
149
150 return TRUE;
151 }
152
153 return FALSE;
154}
155
156static SysMouseAImpl *alloc_device(REFGUID rguid, ICOM_VTABLE(IDirectInputDevice2A) *mvt, IDirectInputAImpl *dinput)
157{
158 int offset_array[5] = {
159 FIELD_OFFSET(Wine_InternalMouseData, lX),
160 FIELD_OFFSET(Wine_InternalMouseData, lY),
161 FIELD_OFFSET(Wine_InternalMouseData, rgbButtons) + 0,
162 FIELD_OFFSET(Wine_InternalMouseData, rgbButtons) + 1,
163 FIELD_OFFSET(Wine_InternalMouseData, rgbButtons) + 2
164 };
165 SysMouseAImpl* newDevice;
166 newDevice = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(SysMouseAImpl));
167 newDevice->ref = 1;
168 ICOM_VTBL(newDevice) = mvt;
169 InitializeCriticalSection(&(newDevice->crit));
170 memcpy(&(newDevice->guid),rguid,sizeof(*rguid));
171
172 /* Per default, Wine uses its internal data format */
173 newDevice->df = &Wine_InternalMouseFormat;
174 memcpy(newDevice->offset_array, offset_array, 5 * sizeof(int));
175 newDevice->wine_df = (DataFormat *) HeapAlloc(GetProcessHeap(), 0, sizeof(DataFormat));
176 newDevice->wine_df->size = 0;
177 newDevice->wine_df->internal_format_size = Wine_InternalMouseFormat.dwDataSize;
178 newDevice->wine_df->dt = NULL;
179 newDevice->dinput = dinput;
180
181 return newDevice;
182}
183
184static HRESULT mousedev_create_device(IDirectInputAImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEA* pdev)
185{
186 if ((IsEqualGUID(&GUID_SysMouse,rguid)) || /* Generic Mouse */
187 (IsEqualGUID(&DInput_Wine_Mouse_GUID,rguid))) { /* Wine Mouse */
188 if ((riid == NULL) || (IsEqualGUID(&IID_IDirectInputDevice2A,riid)) || (IsEqualGUID(&IID_IDirectInputDevice2A,riid))) {
189 *pdev=(IDirectInputDeviceA*) alloc_device(rguid, &SysMouseAvt, dinput);
190
191 TRACE("Creating a Mouse device (%p)\n", *pdev);
192 return DI_OK;
193 }else if (IsEqualGUID(&IID_IDirectInputDevice7A,riid)) {
194 *pdev=(IDirectInputDeviceA*) alloc_device(rguid, (ICOM_VTABLE(IDirectInputDevice2A) *) &SysMouse7Avt, dinput);
195
196 TRACE("Creating a Mouse DInput7A device (%p)\n", *pdev);
197 return DI_OK;
198 } else
199 return DIERR_NOINTERFACE;
200 }
201
202 return DIERR_DEVICENOTREG;
203}
204
205static dinput_device mousedev = {
206 100,
207 mousedev_enum_device,
208 mousedev_create_device
209};
210
211DECL_GLOBAL_CONSTRUCTOR(mousedev_register) { dinput_register_device(&mousedev); }
212
213/******************************************************************************
214 * SysMouseA (DInput Mouse support)
215 */
216
217/******************************************************************************
218 * Release : release the mouse buffer.
219 */
220static ULONG WINAPI SysMouseAImpl_Release(LPDIRECTINPUTDEVICE2A iface)
221{
222 ICOM_THIS(SysMouseAImpl,iface);
223
224#ifdef __WIN32OS2__
225 dprintf(("SysMouseAImpl_Release %x", This));
226#endif
227
228 This->ref--;
229 if (This->ref)
230 return This->ref;
231
232 /* Free the data queue */
233 if (This->data_queue != NULL)
234 HeapFree(GetProcessHeap(),0,This->data_queue);
235
236 if (This->hook) UnhookWindowsHookEx( This->hook );
237 DeleteCriticalSection(&(This->crit));
238
239 /* Free the DataFormat */
240 if (This->df != &(Wine_InternalMouseFormat)) {
241 HeapFree(GetProcessHeap(), 0, This->df->rgodf);
242 HeapFree(GetProcessHeap(), 0, This->df);
243 }
244
245 HeapFree(GetProcessHeap(),0,This);
246 return 0;
247}
248
249
250/******************************************************************************
251 * SetCooperativeLevel : store the window in which we will do our
252 * grabbing.
253 */
254static HRESULT WINAPI SysMouseAImpl_SetCooperativeLevel(
255 LPDIRECTINPUTDEVICE2A iface,HWND hwnd,DWORD dwflags
256)
257{
258 ICOM_THIS(SysMouseAImpl,iface);
259
260 TRACE("(this=%p,0x%08lx,0x%08lx)\n",This,(DWORD)hwnd,dwflags);
261
262 if (TRACE_ON(dinput))
263 _dump_cooperativelevel_DI(dwflags);
264
265 /* Store the window which asks for the mouse */
266 if (!hwnd)
267 hwnd = GetDesktopWindow();
268 This->win = hwnd;
269 This->dwCoopLevel = dwflags;
270
271 return 0;
272}
273
274
275/******************************************************************************
276 * SetDataFormat : the application can choose the format of the data
277 * the device driver sends back with GetDeviceState.
278 *
279 * For the moment, only the "standard" configuration (c_dfDIMouse) is supported
280 * in absolute and relative mode.
281 */
282static HRESULT WINAPI SysMouseAImpl_SetDataFormat(
283 LPDIRECTINPUTDEVICE2A iface,LPCDIDATAFORMAT df
284)
285{
286 ICOM_THIS(SysMouseAImpl,iface);
287 int i;
288
289 TRACE("(this=%p,%p)\n",This,df);
290
291 TRACE("(df.dwSize=%ld)\n",df->dwSize);
292 TRACE("(df.dwObjsize=%ld)\n",df->dwObjSize);
293 TRACE("(df.dwFlags=0x%08lx)\n",df->dwFlags);
294 TRACE("(df.dwDataSize=%ld)\n",df->dwDataSize);
295 TRACE("(df.dwNumObjs=%ld)\n",df->dwNumObjs);
296
297 for (i=0;i<df->dwNumObjs;i++) {
298
299 TRACE("df.rgodf[%d].guid %s (%p)\n",i, debugstr_guid(df->rgodf[i].pguid), df->rgodf[i].pguid);
300 TRACE("df.rgodf[%d].dwOfs %ld\n",i,df->rgodf[i].dwOfs);
301 TRACE("dwType 0x%02x,dwInstance %d\n",DIDFT_GETTYPE(df->rgodf[i].dwType),DIDFT_GETINSTANCE(df->rgodf[i].dwType));
302 TRACE("df.rgodf[%d].dwFlags 0x%08lx\n",i,df->rgodf[i].dwFlags);
303 }
304
305 /* Check if the mouse is in absolute or relative mode */
306 if (df->dwFlags == DIDF_ABSAXIS)
307 This->absolute = 1;
308 else if (df->dwFlags == DIDF_RELAXIS)
309 This->absolute = 0;
310 else
311 ERR("Neither absolute nor relative flag set\n");
312
313 /* Store the new data format */
314 This->df = HeapAlloc(GetProcessHeap(),0,df->dwSize);
315 memcpy(This->df, df, df->dwSize);
316 This->df->rgodf = HeapAlloc(GetProcessHeap(),0,df->dwNumObjs*df->dwObjSize);
317 memcpy(This->df->rgodf,df->rgodf,df->dwNumObjs*df->dwObjSize);
318
319 /* Prepare all the data-conversion filters */
320 This->wine_df = create_DataFormat(&(Wine_InternalMouseFormat), df, This->offset_array);
321
322 return 0;
323}
324
325/* low-level mouse hook */
326#ifdef __WIN32OS2__
327static LRESULT CALLBACK dinput_mouse_hook(SysMouseAImpl* This, int code, WPARAM wparam, LPARAM lparam )
328#else
329static LRESULT CALLBACK dinput_mouse_hook( int code, WPARAM wparam, LPARAM lparam )
330#endif
331{
332 LRESULT ret;
333 MSLLHOOKSTRUCT *hook = (MSLLHOOKSTRUCT *)lparam;
334#ifndef __WIN32OS2__
335 SysMouseAImpl* This = (SysMouseAImpl*) current_lock;
336#endif
337
338//testestest
339 dprintf(("dinput_mouse_hook %d %x %x", code, wparam, lparam));
340
341 if (code != HC_ACTION) return CallNextHookEx( This->hook, code, wparam, lparam );
342
343 EnterCriticalSection(&(This->crit));
344 /* Mouse moved -> send event if asked */
345 if (This->hEvent)
346 SetEvent(This->hEvent);
347
348 if (wparam == WM_MOUSEMOVE) {
349#ifdef __WIN32OS2__
350 if(hook->flags != LLMHF_INJECTED)
351#endif
352 if(hook->dwExtraInfo != 666)
353 if (This->absolute) {
354 if (hook->pt.x != This->prevX)
355 GEN_EVENT(This->offset_array[WINE_MOUSE_X_POSITION], hook->pt.x, hook->time, 0);
356 if (hook->pt.y != This->prevY)
357 GEN_EVENT(This->offset_array[WINE_MOUSE_Y_POSITION], hook->pt.y, hook->time, 0);
358 } else {
359 /* Now, warp handling */
360 if ((This->need_warp == WARP_STARTED) &&
361 (hook->pt.x == This->mapped_center.x) && (hook->pt.y == This->mapped_center.y)) {
362 /* Warp has been done... */
363 This->need_warp = WARP_DONE;
364 goto end;
365 }
366
367 /* Relative mouse input with absolute mouse event : the real fun starts here... */
368 if ((This->need_warp == WARP_NEEDED) ||
369 (This->need_warp == WARP_STARTED)) {
370 if (hook->pt.x != This->prevX)
371 GEN_EVENT(This->offset_array[WINE_MOUSE_X_POSITION], hook->pt.x - This->prevX, hook->time, (This->dinput->evsequence)++);
372 if (hook->pt.y != This->prevY)
373 GEN_EVENT(This->offset_array[WINE_MOUSE_Y_POSITION], hook->pt.y - This->prevY, hook->time, (This->dinput->evsequence)++);
374 } else {
375 /* This is the first time the event handler has been called after a
376 GetDeviceData or GetDeviceState. */
377 if (hook->pt.x != This->mapped_center.x) {
378 GEN_EVENT(This->offset_array[WINE_MOUSE_X_POSITION], hook->pt.x - This->mapped_center.x, hook->time, (This->dinput->evsequence)++);
379 This->need_warp = WARP_NEEDED;
380 }
381
382 if (hook->pt.y != This->mapped_center.y) {
383 GEN_EVENT(This->offset_array[WINE_MOUSE_Y_POSITION], hook->pt.y - This->mapped_center.y, hook->time, (This->dinput->evsequence)++);
384 This->need_warp = WARP_NEEDED;
385 }
386 }
387 }
388
389 This->prevX = hook->pt.x;
390 This->prevY = hook->pt.y;
391
392 if (This->absolute) {
393 This->m_state.lX = hook->pt.x;
394 This->m_state.lY = hook->pt.y;
395 } else {
396 This->m_state.lX = hook->pt.x - This->mapped_center.x;
397 This->m_state.lY = hook->pt.y - This->mapped_center.y;
398 }
399 }
400
401 TRACE(" msg %x pt %ld %ld (W=%d)\n",
402 wparam, hook->pt.x, hook->pt.y, (!This->absolute) && This->need_warp );
403
404 switch(wparam)
405 {
406 case WM_LBUTTONDOWN:
407 GEN_EVENT(This->offset_array[WINE_MOUSE_L_POSITION], 0xFF,
408 hook->time, This->dinput->evsequence++);
409 This->m_state.rgbButtons[0] = 0xFF;
410 break;
411 case WM_LBUTTONUP:
412 GEN_EVENT(This->offset_array[WINE_MOUSE_L_POSITION], 0x00,
413 hook->time, This->dinput->evsequence++);
414 This->m_state.rgbButtons[0] = 0x00;
415 break;
416 case WM_RBUTTONDOWN:
417 GEN_EVENT(This->offset_array[WINE_MOUSE_R_POSITION], 0xFF,
418 hook->time, This->dinput->evsequence++);
419 This->m_state.rgbButtons[1] = 0xFF;
420 break;
421 case WM_RBUTTONUP:
422 GEN_EVENT(This->offset_array[WINE_MOUSE_R_POSITION], 0x00,
423 hook->time, This->dinput->evsequence++);
424 This->m_state.rgbButtons[1] = 0x00;
425 break;
426 case WM_MBUTTONDOWN:
427 GEN_EVENT(This->offset_array[WINE_MOUSE_M_POSITION], 0xFF,
428 hook->time, This->dinput->evsequence++);
429 This->m_state.rgbButtons[2] = 0xFF;
430 break;
431 case WM_MBUTTONUP:
432 GEN_EVENT(This->offset_array[WINE_MOUSE_M_POSITION], 0x00,
433 hook->time, This->dinput->evsequence++);
434 This->m_state.rgbButtons[2] = 0x00;
435 break;
436 }
437
438 TRACE("(X: %ld - Y: %ld L: %02x M: %02x R: %02x)\n",
439 This->m_state.lX, This->m_state.lY,
440 This->m_state.rgbButtons[0], This->m_state.rgbButtons[2], This->m_state.rgbButtons[1]);
441
442end:
443 if (This->dwCoopLevel & DISCL_NONEXCLUSIVE)
444 { /* pass the events down to previous handlers (e.g. win32 input) */
445 ret = CallNextHookEx( This->hook, code, wparam, lparam );
446 }
447 else ret = 1; /* ignore message */
448 LeaveCriticalSection(&(This->crit));
449 return ret;
450}
451
452
453/******************************************************************************
454 * Acquire : gets exclusive control of the mouse
455 */
456static HRESULT WINAPI SysMouseAImpl_Acquire(LPDIRECTINPUTDEVICE2A iface)
457{
458 ICOM_THIS(SysMouseAImpl,iface);
459 RECT rect;
460
461#ifdef __WIN32OS2__
462 dprintf(("SysMouseAImpl_Acquire %x", This));
463#else
464 TRACE("(this=%p)\n",This);
465#endif
466 if (This->acquired == 0) {
467 POINT point;
468
469 /* Store (in a global variable) the current lock */
470 current_lock = (IDirectInputDevice2A*)This;
471
472 /* Init the mouse state */
473 if (This->absolute) {
474 GetCursorPos( &point );
475 This->m_state.lX = point.x;
476 This->m_state.lY = point.y;
477 This->prevX = point.x;
478 This->prevY = point.y;
479 } else {
480 This->m_state.lX = 0;
481 This->m_state.lY = 0;
482 }
483 This->m_state.rgbButtons[0] = (GetKeyState(VK_LBUTTON) ? 0xFF : 0x00);
484 This->m_state.rgbButtons[1] = (GetKeyState(VK_MBUTTON) ? 0xFF : 0x00);
485 This->m_state.rgbButtons[2] = (GetKeyState(VK_RBUTTON) ? 0xFF : 0x00);
486
487 /* Install our mouse hook */
488#ifdef __WIN32OS2__
489 /* push ebp */
490 This->hookcode[0] = 0x55;
491 /* mov ebp, esp */
492 This->hookcode[1] = 0x8B; This->hookcode[2] = 0xEC;
493 /* push [ebp+16] */
494 This->hookcode[3] = 0xFF; This->hookcode[4] = 0x75; This->hookcode[5] = 0x10;
495 /* push [ebp+12] */
496 This->hookcode[6] = 0xFF; This->hookcode[7] = 0x75; This->hookcode[8] = 0x0C;
497 /* push [ebp+8] */
498 This->hookcode[9] = 0xFF; This->hookcode[10] = 0x75; This->hookcode[11] = 0x08;
499 /* push This */
500 This->hookcode[12] = 0x68; *(DWORD *)&This->hookcode[13] = (DWORD)This;
501 /* mov eax, dinput_mouse_hook */
502 This->hookcode[17] = 0xB8; *(DWORD *)&This->hookcode[18] = (DWORD)&dinput_mouse_hook;
503 /* call eax */
504 This->hookcode[22] = 0xFF; This->hookcode[23] = 0xD0;
505 /* pop ebp */
506 This->hookcode[24] = 0x5D;
507 /* ret 12 */
508 This->hookcode[25] = 0xC2; *(WORD *)&This->hookcode[26] = 0x000C;
509
510 This->hook = SetWindowsHookExW( WH_MOUSE_LL, (HOOKPROC)This->hookcode, 0, 0 );
511#else
512 This->hook = SetWindowsHookExW( WH_MOUSE_LL, dinput_mouse_hook, 0, 0 );
513#endif
514
515 /* Get the window dimension and find the center */
516 GetWindowRect(This->win, &rect);
517 This->win_centerX = (rect.right - rect.left) / 2;
518 This->win_centerY = (rect.bottom - rect.top ) / 2;
519
520#ifndef __WIN32OS2__
521 /* Warp the mouse to the center of the window */
522 if (This->absolute == 0) {
523 This->mapped_center.x = This->win_centerX;
524 This->mapped_center.y = This->win_centerY;
525 MapWindowPoints(This->win, HWND_DESKTOP, &This->mapped_center, 1);
526 TRACE("Warping mouse to %ld - %ld\n", This->mapped_center.x, This->mapped_center.y);
527 SetCursorPos( This->mapped_center.x, This->mapped_center.y );
528#ifdef MOUSE_HACK
529 This->need_warp = WARP_DONE;
530#else
531 This->need_warp = WARP_STARTED;
532#endif
533 }
534#endif
535 This->acquired = 1;
536 }
537 return DI_OK;
538}
539
540/******************************************************************************
541 * Unacquire : frees the mouse
542 */
543static HRESULT WINAPI SysMouseAImpl_Unacquire(LPDIRECTINPUTDEVICE2A iface)
544{
545 ICOM_THIS(SysMouseAImpl,iface);
546
547#ifdef __WIN32OS2__
548 dprintf(("SysMouseAImpl_Unacquire %x", This));
549#else
550 TRACE("(this=%p)\n",This);
551#endif
552
553 if (This->acquired)
554 {
555 /* Reinstall previous mouse event handler */
556 if (This->hook) UnhookWindowsHookEx( This->hook );
557 This->hook = 0;
558
559 /* No more locks */
560 current_lock = NULL;
561
562 /* Unacquire device */
563 This->acquired = 0;
564 }
565 else
566 ERR("Unacquiring a not-acquired device !!!\n");
567
568 return DI_OK;
569}
570
571/******************************************************************************
572 * GetDeviceState : returns the "state" of the mouse.
573 *
574 * For the moment, only the "standard" return structure (DIMOUSESTATE) is
575 * supported.
576 */
577static HRESULT WINAPI SysMouseAImpl_GetDeviceState(
578 LPDIRECTINPUTDEVICE2A iface,DWORD len,LPVOID ptr
579) {
580 ICOM_THIS(SysMouseAImpl,iface);
581
582 EnterCriticalSection(&(This->crit));
583 TRACE("(this=%p,0x%08lx,%p): \n",This,len,ptr);
584
585 /* Copy the current mouse state */
586 fill_DataFormat(ptr, &(This->m_state), This->wine_df);
587
588 /* Initialize the buffer when in relative mode */
589 if (This->absolute == 0) {
590 This->m_state.lX = 0;
591 This->m_state.lY = 0;
592 }
593
594#ifndef __WIN32OS2__
595 //SvL: Completely breaks some apps
596 /* Check if we need to do a mouse warping */
597 if (This->need_warp == WARP_NEEDED) {
598 This->mapped_center.x = This->win_centerX;
599 This->mapped_center.y = This->win_centerY;
600 MapWindowPoints(This->win, HWND_DESKTOP, &This->mapped_center, 1);
601 TRACE("Warping mouse to %ld - %ld\n", This->mapped_center.x, This->mapped_center.y);
602 SetCursorPos( This->mapped_center.x, This->mapped_center.y );
603
604#ifdef MOUSE_HACK
605 This->need_warp = WARP_DONE;
606#else
607 This->need_warp = WARP_STARTED;
608#endif
609 }
610#endif
611
612 LeaveCriticalSection(&(This->crit));
613
614 TRACE("(X: %ld - Y: %ld L: %02x M: %02x R: %02x)\n",
615 This->m_state.lX, This->m_state.lY,
616 This->m_state.rgbButtons[0], This->m_state.rgbButtons[2], This->m_state.rgbButtons[1]);
617
618 return 0;
619}
620
621/******************************************************************************
622 * GetDeviceState : gets buffered input data.
623 */
624static HRESULT WINAPI SysMouseAImpl_GetDeviceData(LPDIRECTINPUTDEVICE2A iface,
625 DWORD dodsize,
626 LPDIDEVICEOBJECTDATA dod,
627 LPDWORD entries,
628 DWORD flags
629) {
630 ICOM_THIS(SysMouseAImpl,iface);
631 DWORD len, nqtail;
632
633 EnterCriticalSection(&(This->crit));
634 TRACE("(%p)->(dods=%ld,entries=%ld,fl=0x%08lx)\n",This,dodsize,*entries,flags);
635
636 len = ((This->queue_head < This->queue_tail) ? This->queue_len : 0)
637 + (This->queue_head - This->queue_tail);
638 if (len > *entries) len = *entries;
639
640 if (dod == NULL) {
641 *entries = len;
642 nqtail = This->queue_tail + len;
643 while (nqtail >= This->queue_len) nqtail -= This->queue_len;
644 } else {
645 if (dodsize != sizeof(DIDEVICEOBJECTDATA)) {
646 ERR("Wrong structure size !\n");
647 LeaveCriticalSection(&(This->crit));
648 return DIERR_INVALIDPARAM;
649 }
650
651 if (len)
652 TRACE("Application retrieving %ld event(s).\n", len);
653
654 *entries = 0;
655 nqtail = This->queue_tail;
656 while (len) {
657 DWORD span = ((This->queue_head < nqtail) ? This->queue_len : This->queue_head)
658 - nqtail;
659 if (span > len) span = len;
660 /* Copy the buffered data into the application queue */
661 memcpy(dod + *entries, This->data_queue + nqtail, span * dodsize);
662 /* Advance position */
663 nqtail += span;
664 if (nqtail >= This->queue_len) nqtail -= This->queue_len;
665 *entries += span;
666 len -= span;
667 }
668 }
669 if (!(flags & DIGDD_PEEK))
670 This->queue_tail = nqtail;
671
672 LeaveCriticalSection(&(This->crit));
673
674#ifndef __WIN32OS2__
675 //SvL: Completely breaks some apps
676 /* Check if we need to do a mouse warping */
677 if (This->need_warp == WARP_NEEDED) {
678 This->mapped_center.x = This->win_centerX;
679 This->mapped_center.y = This->win_centerY;
680 MapWindowPoints(This->win, HWND_DESKTOP, &This->mapped_center, 1);
681 TRACE("Warping mouse to %ld - %ld\n", This->mapped_center.x, This->mapped_center.y);
682 SetCursorPos( This->mapped_center.x, This->mapped_center.y );
683
684#ifdef MOUSE_HACK
685 This->need_warp = WARP_DONE;
686#else
687 This->need_warp = WARP_STARTED;
688#endif
689 }
690#endif
691 return 0;
692}
693
694/******************************************************************************
695 * SetProperty : change input device properties
696 */
697static HRESULT WINAPI SysMouseAImpl_SetProperty(LPDIRECTINPUTDEVICE2A iface,
698 REFGUID rguid,
699 LPCDIPROPHEADER ph)
700{
701 ICOM_THIS(SysMouseAImpl,iface);
702
703 TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(rguid),ph);
704
705 if (!HIWORD(rguid)) {
706 switch ((DWORD)rguid) {
707 case (DWORD) DIPROP_BUFFERSIZE: {
708 LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph;
709
710 TRACE("buffersize = %ld\n",pd->dwData);
711
712 This->data_queue = (LPDIDEVICEOBJECTDATA)HeapAlloc(GetProcessHeap(),0,
713 pd->dwData * sizeof(DIDEVICEOBJECTDATA));
714 This->queue_head = 0;
715 This->queue_tail = 0;
716 This->queue_len = pd->dwData;
717 break;
718 }
719 case (DWORD) DIPROP_AXISMODE: {
720 LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph;
721 This->absolute = !(pd->dwData);
722 TRACE("Using %s coordinates mode now\n", This->absolute ? "absolute" : "relative");
723 break;
724 }
725 default:
726 FIXME("Unknown type %ld (%s)\n",(DWORD)rguid,debugstr_guid(rguid));
727 break;
728 }
729 }
730
731 return 0;
732}
733
734/******************************************************************************
735 * GetProperty : get input device properties
736 */
737static HRESULT WINAPI SysMouseAImpl_GetProperty(LPDIRECTINPUTDEVICE2A iface,
738 REFGUID rguid,
739 LPDIPROPHEADER pdiph)
740{
741 ICOM_THIS(SysMouseAImpl,iface);
742
743 TRACE("(this=%p,%s,%p): stub!\n",
744 iface, debugstr_guid(rguid), pdiph);
745
746 if (TRACE_ON(dinput))
747 _dump_DIPROPHEADER(pdiph);
748
749 if (!HIWORD(rguid)) {
750 switch ((DWORD)rguid) {
751 case (DWORD) DIPROP_BUFFERSIZE: {
752 LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph;
753
754 TRACE(" return buffersize = %d\n",This->queue_len);
755 pd->dwData = This->queue_len;
756 break;
757 }
758
759 case (DWORD) DIPROP_RANGE: {
760 LPDIPROPRANGE pr = (LPDIPROPRANGE) pdiph;
761
762 if ((pdiph->dwHow == DIPH_BYID) &&
763 ((pdiph->dwObj == (DIDFT_MAKEINSTANCE(WINE_MOUSE_X_AXIS_INSTANCE) | DIDFT_RELAXIS)) ||
764 (pdiph->dwObj == (DIDFT_MAKEINSTANCE(WINE_MOUSE_Y_AXIS_INSTANCE) | DIDFT_RELAXIS)))) {
765 /* Querying the range of either the X or the Y axis. As I do
766 not know the range, do as if the range were
767 unrestricted...*/
768 pr->lMin = DIPROPRANGE_NOMIN;
769 pr->lMax = DIPROPRANGE_NOMAX;
770 }
771
772 break;
773 }
774
775 default:
776 FIXME("Unknown type %ld (%s)\n",(DWORD)rguid,debugstr_guid(rguid));
777 break;
778 }
779 }
780
781
782 return DI_OK;
783}
784
785
786
787/******************************************************************************
788 * SetEventNotification : specifies event to be sent on state change
789 */
790static HRESULT WINAPI SysMouseAImpl_SetEventNotification(LPDIRECTINPUTDEVICE2A iface,
791 HANDLE hnd) {
792 ICOM_THIS(SysMouseAImpl,iface);
793
794 TRACE("(this=%p,0x%08lx)\n",This,(DWORD)hnd);
795
796 This->hEvent = hnd;
797
798 return DI_OK;
799}
800
801/******************************************************************************
802 * GetCapabilities : get the device capablitites
803 */
804static HRESULT WINAPI SysMouseAImpl_GetCapabilities(
805 LPDIRECTINPUTDEVICE2A iface,
806 LPDIDEVCAPS lpDIDevCaps)
807{
808 ICOM_THIS(SysMouseAImpl,iface);
809
810 TRACE("(this=%p,%p)\n",This,lpDIDevCaps);
811
812 if (lpDIDevCaps->dwSize == sizeof(DIDEVCAPS)) {
813 lpDIDevCaps->dwFlags = DIDC_ATTACHED;
814 lpDIDevCaps->dwDevType = DIDEVTYPE_MOUSE;
815 lpDIDevCaps->dwAxes = 2;
816 lpDIDevCaps->dwButtons = 3;
817 lpDIDevCaps->dwPOVs = 0;
818 lpDIDevCaps->dwFFSamplePeriod = 0;
819 lpDIDevCaps->dwFFMinTimeResolution = 0;
820 lpDIDevCaps->dwFirmwareRevision = 100;
821 lpDIDevCaps->dwHardwareRevision = 100;
822 lpDIDevCaps->dwFFDriverVersion = 0;
823 } else {
824 /* DirectX 3.0 */
825 FIXME("DirectX 3.0 not supported....\n");
826 }
827
828 return DI_OK;
829}
830
831
832/******************************************************************************
833 * EnumObjects : enumerate the different buttons and axis...
834 */
835static HRESULT WINAPI SysMouseAImpl_EnumObjects(
836 LPDIRECTINPUTDEVICE2A iface,
837 LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback,
838 LPVOID lpvRef,
839 DWORD dwFlags)
840{
841 ICOM_THIS(SysMouseAImpl,iface);
842 DIDEVICEOBJECTINSTANCEA ddoi;
843
844 TRACE("(this=%p,%p,%p,%08lx)\n", This, lpCallback, lpvRef, dwFlags);
845 if (TRACE_ON(dinput)) {
846 DPRINTF(" - flags = ");
847 _dump_EnumObjects_flags(dwFlags);
848 DPRINTF("\n");
849 }
850
851 /* Only the fields till dwFFMaxForce are relevant */
852 ddoi.dwSize = FIELD_OFFSET(DIDEVICEOBJECTINSTANCEA, dwFFMaxForce);
853
854 /* In a mouse, we have : two relative axis and three buttons */
855 if ((dwFlags == DIDFT_ALL) ||
856 (dwFlags & DIDFT_AXIS)) {
857 /* X axis */
858 ddoi.guidType = GUID_XAxis;
859 ddoi.dwOfs = This->offset_array[WINE_MOUSE_X_POSITION];
860 ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_X_AXIS_INSTANCE) | DIDFT_RELAXIS;
861 strcpy(ddoi.tszName, "X-Axis");
862 _dump_OBJECTINSTANCEA(&ddoi);
863 if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
864
865 /* Y axis */
866 ddoi.guidType = GUID_YAxis;
867 ddoi.dwOfs = This->offset_array[WINE_MOUSE_Y_POSITION];
868 ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_Y_AXIS_INSTANCE) | DIDFT_RELAXIS;
869 strcpy(ddoi.tszName, "Y-Axis");
870 _dump_OBJECTINSTANCEA(&ddoi);
871 if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
872 }
873
874 if ((dwFlags == DIDFT_ALL) ||
875 (dwFlags & DIDFT_BUTTON)) {
876 ddoi.guidType = GUID_Button;
877
878 /* Left button */
879 ddoi.dwOfs = This->offset_array[WINE_MOUSE_L_POSITION];
880 ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_L_BUTTON_INSTANCE) | DIDFT_PSHBUTTON;
881 strcpy(ddoi.tszName, "Left-Button");
882 _dump_OBJECTINSTANCEA(&ddoi);
883 if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
884
885 /* Right button */
886 ddoi.dwOfs = This->offset_array[WINE_MOUSE_R_POSITION];
887 ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_R_BUTTON_INSTANCE) | DIDFT_PSHBUTTON;
888 strcpy(ddoi.tszName, "Right-Button");
889 _dump_OBJECTINSTANCEA(&ddoi);
890 if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
891
892 /* Middle button */
893 ddoi.dwOfs = This->offset_array[WINE_MOUSE_M_POSITION];
894 ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_M_BUTTON_INSTANCE) | DIDFT_PSHBUTTON;
895 strcpy(ddoi.tszName, "Middle-Button");
896 _dump_OBJECTINSTANCEA(&ddoi);
897 if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
898 }
899
900 return DI_OK;
901}
902
903
904static ICOM_VTABLE(IDirectInputDevice2A) SysMouseAvt =
905{
906 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
907 IDirectInputDevice2AImpl_QueryInterface,
908 IDirectInputDevice2AImpl_AddRef,
909 SysMouseAImpl_Release,
910 SysMouseAImpl_GetCapabilities,
911 SysMouseAImpl_EnumObjects,
912 SysMouseAImpl_GetProperty,
913 SysMouseAImpl_SetProperty,
914 SysMouseAImpl_Acquire,
915 SysMouseAImpl_Unacquire,
916 SysMouseAImpl_GetDeviceState,
917 SysMouseAImpl_GetDeviceData,
918 SysMouseAImpl_SetDataFormat,
919 SysMouseAImpl_SetEventNotification,
920 SysMouseAImpl_SetCooperativeLevel,
921 IDirectInputDevice2AImpl_GetObjectInfo,
922 IDirectInputDevice2AImpl_GetDeviceInfo,
923 IDirectInputDevice2AImpl_RunControlPanel,
924 IDirectInputDevice2AImpl_Initialize,
925 IDirectInputDevice2AImpl_CreateEffect,
926 IDirectInputDevice2AImpl_EnumEffects,
927 IDirectInputDevice2AImpl_GetEffectInfo,
928 IDirectInputDevice2AImpl_GetForceFeedbackState,
929 IDirectInputDevice2AImpl_SendForceFeedbackCommand,
930 IDirectInputDevice2AImpl_EnumCreatedEffectObjects,
931 IDirectInputDevice2AImpl_Escape,
932 IDirectInputDevice2AImpl_Poll,
933 IDirectInputDevice2AImpl_SendDeviceData,
934};
935
936#if !defined(__STRICT_ANSI__) && defined(__GNUC__)
937# define XCAST(fun) (typeof(SysMouse7Avt.fun))
938#else
939# define XCAST(fun) (void*)
940#endif
941
942static ICOM_VTABLE(IDirectInputDevice7A) SysMouse7Avt =
943{
944 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
945 XCAST(QueryInterface)IDirectInputDevice2AImpl_QueryInterface,
946 XCAST(AddRef)IDirectInputDevice2AImpl_AddRef,
947 XCAST(Release)SysMouseAImpl_Release,
948 XCAST(GetCapabilities)SysMouseAImpl_GetCapabilities,
949 XCAST(EnumObjects)SysMouseAImpl_EnumObjects,
950 XCAST(GetProperty)SysMouseAImpl_GetProperty,
951 XCAST(SetProperty)SysMouseAImpl_SetProperty,
952 XCAST(Acquire)SysMouseAImpl_Acquire,
953 XCAST(Unacquire)SysMouseAImpl_Unacquire,
954 XCAST(GetDeviceState)SysMouseAImpl_GetDeviceState,
955 XCAST(GetDeviceData)SysMouseAImpl_GetDeviceData,
956 XCAST(SetDataFormat)SysMouseAImpl_SetDataFormat,
957 XCAST(SetEventNotification)SysMouseAImpl_SetEventNotification,
958 XCAST(SetCooperativeLevel)SysMouseAImpl_SetCooperativeLevel,
959 XCAST(GetObjectInfo)IDirectInputDevice2AImpl_GetObjectInfo,
960 XCAST(GetDeviceInfo)IDirectInputDevice2AImpl_GetDeviceInfo,
961 XCAST(RunControlPanel)IDirectInputDevice2AImpl_RunControlPanel,
962 XCAST(Initialize)IDirectInputDevice2AImpl_Initialize,
963 XCAST(CreateEffect)IDirectInputDevice2AImpl_CreateEffect,
964 XCAST(EnumEffects)IDirectInputDevice2AImpl_EnumEffects,
965 XCAST(GetEffectInfo)IDirectInputDevice2AImpl_GetEffectInfo,
966 XCAST(GetForceFeedbackState)IDirectInputDevice2AImpl_GetForceFeedbackState,
967 XCAST(SendForceFeedbackCommand)IDirectInputDevice2AImpl_SendForceFeedbackCommand,
968 XCAST(EnumCreatedEffectObjects)IDirectInputDevice2AImpl_EnumCreatedEffectObjects,
969 XCAST(Escape)IDirectInputDevice2AImpl_Escape,
970 XCAST(Poll)IDirectInputDevice2AImpl_Poll,
971 XCAST(SendDeviceData)IDirectInputDevice2AImpl_SendDeviceData,
972 IDirectInputDevice7AImpl_EnumEffectsInFile,
973 IDirectInputDevice7AImpl_WriteEffectToFile
974};
975
976#undef XCAST
Note: See TracBrowser for help on using the repository browser.