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

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

Made mouse code reentrant

File size: 30.9 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 if (This->absolute) {
350 if (hook->pt.x != This->prevX)
351 GEN_EVENT(This->offset_array[WINE_MOUSE_X_POSITION], hook->pt.x, hook->time, 0);
352 if (hook->pt.y != This->prevY)
353 GEN_EVENT(This->offset_array[WINE_MOUSE_Y_POSITION], hook->pt.y, hook->time, 0);
354 } else {
355 /* Now, warp handling */
356 if ((This->need_warp == WARP_STARTED) &&
357 (hook->pt.x == This->mapped_center.x) && (hook->pt.y == This->mapped_center.y)) {
358 /* Warp has been done... */
359 This->need_warp = WARP_DONE;
360 goto end;
361 }
362
363 /* Relative mouse input with absolute mouse event : the real fun starts here... */
364 if ((This->need_warp == WARP_NEEDED) ||
365 (This->need_warp == WARP_STARTED)) {
366 if (hook->pt.x != This->prevX)
367 GEN_EVENT(This->offset_array[WINE_MOUSE_X_POSITION], hook->pt.x - This->prevX, hook->time, (This->dinput->evsequence)++);
368 if (hook->pt.y != This->prevY)
369 GEN_EVENT(This->offset_array[WINE_MOUSE_Y_POSITION], hook->pt.y - This->prevY, hook->time, (This->dinput->evsequence)++);
370 } else {
371 /* This is the first time the event handler has been called after a
372 GetDeviceData or GetDeviceState. */
373 if (hook->pt.x != This->mapped_center.x) {
374 GEN_EVENT(This->offset_array[WINE_MOUSE_X_POSITION], hook->pt.x - This->mapped_center.x, hook->time, (This->dinput->evsequence)++);
375 This->need_warp = WARP_NEEDED;
376 }
377
378 if (hook->pt.y != This->mapped_center.y) {
379 GEN_EVENT(This->offset_array[WINE_MOUSE_Y_POSITION], hook->pt.y - This->mapped_center.y, hook->time, (This->dinput->evsequence)++);
380 This->need_warp = WARP_NEEDED;
381 }
382 }
383 }
384
385 This->prevX = hook->pt.x;
386 This->prevY = hook->pt.y;
387
388 if (This->absolute) {
389 This->m_state.lX = hook->pt.x;
390 This->m_state.lY = hook->pt.y;
391 } else {
392 This->m_state.lX = hook->pt.x - This->mapped_center.x;
393 This->m_state.lY = hook->pt.y - This->mapped_center.y;
394 }
395 }
396
397 TRACE(" msg %x pt %ld %ld (W=%d)\n",
398 wparam, hook->pt.x, hook->pt.y, (!This->absolute) && This->need_warp );
399
400 switch(wparam)
401 {
402 case WM_LBUTTONDOWN:
403 GEN_EVENT(This->offset_array[WINE_MOUSE_L_POSITION], 0xFF,
404 hook->time, This->dinput->evsequence++);
405 This->m_state.rgbButtons[0] = 0xFF;
406 break;
407 case WM_LBUTTONUP:
408 GEN_EVENT(This->offset_array[WINE_MOUSE_L_POSITION], 0x00,
409 hook->time, This->dinput->evsequence++);
410 This->m_state.rgbButtons[0] = 0x00;
411 break;
412 case WM_RBUTTONDOWN:
413 GEN_EVENT(This->offset_array[WINE_MOUSE_R_POSITION], 0xFF,
414 hook->time, This->dinput->evsequence++);
415 This->m_state.rgbButtons[1] = 0xFF;
416 break;
417 case WM_RBUTTONUP:
418 GEN_EVENT(This->offset_array[WINE_MOUSE_R_POSITION], 0x00,
419 hook->time, This->dinput->evsequence++);
420 This->m_state.rgbButtons[1] = 0x00;
421 break;
422 case WM_MBUTTONDOWN:
423 GEN_EVENT(This->offset_array[WINE_MOUSE_M_POSITION], 0xFF,
424 hook->time, This->dinput->evsequence++);
425 This->m_state.rgbButtons[2] = 0xFF;
426 break;
427 case WM_MBUTTONUP:
428 GEN_EVENT(This->offset_array[WINE_MOUSE_M_POSITION], 0x00,
429 hook->time, This->dinput->evsequence++);
430 This->m_state.rgbButtons[2] = 0x00;
431 break;
432 }
433
434 TRACE("(X: %ld - Y: %ld L: %02x M: %02x R: %02x)\n",
435 This->m_state.lX, This->m_state.lY,
436 This->m_state.rgbButtons[0], This->m_state.rgbButtons[2], This->m_state.rgbButtons[1]);
437
438end:
439 if (This->dwCoopLevel & DISCL_NONEXCLUSIVE)
440 { /* pass the events down to previous handlers (e.g. win32 input) */
441 ret = CallNextHookEx( This->hook, code, wparam, lparam );
442 }
443 else ret = 1; /* ignore message */
444 LeaveCriticalSection(&(This->crit));
445 return ret;
446}
447
448
449/******************************************************************************
450 * Acquire : gets exclusive control of the mouse
451 */
452static HRESULT WINAPI SysMouseAImpl_Acquire(LPDIRECTINPUTDEVICE2A iface)
453{
454 ICOM_THIS(SysMouseAImpl,iface);
455 RECT rect;
456
457#ifdef __WIN32OS2__
458 dprintf(("SysMouseAImpl_Acquire %x", This));
459#else
460 TRACE("(this=%p)\n",This);
461#endif
462 if (This->acquired == 0) {
463 POINT point;
464
465 /* Store (in a global variable) the current lock */
466 current_lock = (IDirectInputDevice2A*)This;
467
468 /* Init the mouse state */
469 if (This->absolute) {
470 GetCursorPos( &point );
471 This->m_state.lX = point.x;
472 This->m_state.lY = point.y;
473 This->prevX = point.x;
474 This->prevY = point.y;
475 } else {
476 This->m_state.lX = 0;
477 This->m_state.lY = 0;
478 }
479 This->m_state.rgbButtons[0] = (GetKeyState(VK_LBUTTON) ? 0xFF : 0x00);
480 This->m_state.rgbButtons[1] = (GetKeyState(VK_MBUTTON) ? 0xFF : 0x00);
481 This->m_state.rgbButtons[2] = (GetKeyState(VK_RBUTTON) ? 0xFF : 0x00);
482
483 /* Install our mouse hook */
484#ifdef __WIN32OS2__
485 //push ebp
486 This->hookcode[0] = 0x55;
487 //mov ebp, esp
488 This->hookcode[1] = 0x8B; This->hookcode[2] = 0xEC;
489 //push [ebp+16]
490 This->hookcode[3] = 0xFF; This->hookcode[4] = 0x75; This->hookcode[5] = 0x10;
491 //push [ebp+12]
492 This->hookcode[6] = 0xFF; This->hookcode[7] = 0x75; This->hookcode[8] = 0x0C;
493 //push [ebp+8]
494 This->hookcode[9] = 0xFF; This->hookcode[10] = 0x75; This->hookcode[11] = 0x08;
495 //push This
496 This->hookcode[12] = 0x68; *(DWORD *)&This->hookcode[13] = (DWORD)This;
497 //mov eax, dinput_mouse_hook
498 This->hookcode[17] = 0xB8; *(DWORD *)&This->hookcode[18] = (DWORD)&dinput_mouse_hook;
499 //call eax
500 This->hookcode[22] = 0xFF; This->hookcode[23] = 0xD0;
501 //pop ebp
502 This->hookcode[24] = 0x5D;
503 //ret 12
504 This->hookcode[25] = 0xC2; *(WORD *)&This->hookcode[26] = 0x000C;
505
506 This->hook = SetWindowsHookExW( WH_MOUSE_LL, (HOOKPROC)This->hookcode, 0, 0 );
507#else
508 This->hook = SetWindowsHookExW( WH_MOUSE_LL, dinput_mouse_hook, 0, 0 );
509#endif
510
511 /* Get the window dimension and find the center */
512 GetWindowRect(This->win, &rect);
513 This->win_centerX = (rect.right - rect.left) / 2;
514 This->win_centerY = (rect.bottom - rect.top ) / 2;
515
516#ifndef __WIN32OS2__
517 /* Warp the mouse to the center of the window */
518 if (This->absolute == 0) {
519 This->mapped_center.x = This->win_centerX;
520 This->mapped_center.y = This->win_centerY;
521 MapWindowPoints(This->win, HWND_DESKTOP, &This->mapped_center, 1);
522 TRACE("Warping mouse to %ld - %ld\n", This->mapped_center.x, This->mapped_center.y);
523 SetCursorPos( This->mapped_center.x, This->mapped_center.y );
524#ifdef MOUSE_HACK
525 This->need_warp = WARP_DONE;
526#else
527 This->need_warp = WARP_STARTED;
528#endif
529 }
530#endif
531 This->acquired = 1;
532 }
533 return DI_OK;
534}
535
536/******************************************************************************
537 * Unacquire : frees the mouse
538 */
539static HRESULT WINAPI SysMouseAImpl_Unacquire(LPDIRECTINPUTDEVICE2A iface)
540{
541 ICOM_THIS(SysMouseAImpl,iface);
542
543#ifdef __WIN32OS2__
544 dprintf(("SysMouseAImpl_Unacquire %x", This));
545#else
546 TRACE("(this=%p)\n",This);
547#endif
548
549 if (This->acquired)
550 {
551 /* Reinstall previous mouse event handler */
552 if (This->hook) UnhookWindowsHookEx( This->hook );
553 This->hook = 0;
554
555 /* No more locks */
556 current_lock = NULL;
557
558 /* Unacquire device */
559 This->acquired = 0;
560 }
561 else
562 ERR("Unacquiring a not-acquired device !!!\n");
563
564 return DI_OK;
565}
566
567/******************************************************************************
568 * GetDeviceState : returns the "state" of the mouse.
569 *
570 * For the moment, only the "standard" return structure (DIMOUSESTATE) is
571 * supported.
572 */
573static HRESULT WINAPI SysMouseAImpl_GetDeviceState(
574 LPDIRECTINPUTDEVICE2A iface,DWORD len,LPVOID ptr
575) {
576 ICOM_THIS(SysMouseAImpl,iface);
577
578 EnterCriticalSection(&(This->crit));
579 TRACE("(this=%p,0x%08lx,%p): \n",This,len,ptr);
580
581 /* Copy the current mouse state */
582 fill_DataFormat(ptr, &(This->m_state), This->wine_df);
583
584 /* Initialize the buffer when in relative mode */
585 if (This->absolute == 0) {
586 This->m_state.lX = 0;
587 This->m_state.lY = 0;
588 }
589
590#ifndef __WIN32OS2__
591 //SvL: Completely breaks some apps
592 /* Check if we need to do a mouse warping */
593 if (This->need_warp == WARP_NEEDED) {
594 This->mapped_center.x = This->win_centerX;
595 This->mapped_center.y = This->win_centerY;
596 MapWindowPoints(This->win, HWND_DESKTOP, &This->mapped_center, 1);
597 TRACE("Warping mouse to %ld - %ld\n", This->mapped_center.x, This->mapped_center.y);
598 SetCursorPos( This->mapped_center.x, This->mapped_center.y );
599
600#ifdef MOUSE_HACK
601 This->need_warp = WARP_DONE;
602#else
603 This->need_warp = WARP_STARTED;
604#endif
605 }
606#endif
607
608 LeaveCriticalSection(&(This->crit));
609
610 TRACE("(X: %ld - Y: %ld L: %02x M: %02x R: %02x)\n",
611 This->m_state.lX, This->m_state.lY,
612 This->m_state.rgbButtons[0], This->m_state.rgbButtons[2], This->m_state.rgbButtons[1]);
613
614 return 0;
615}
616
617/******************************************************************************
618 * GetDeviceState : gets buffered input data.
619 */
620static HRESULT WINAPI SysMouseAImpl_GetDeviceData(LPDIRECTINPUTDEVICE2A iface,
621 DWORD dodsize,
622 LPDIDEVICEOBJECTDATA dod,
623 LPDWORD entries,
624 DWORD flags
625) {
626 ICOM_THIS(SysMouseAImpl,iface);
627 DWORD len, nqtail;
628
629 EnterCriticalSection(&(This->crit));
630 TRACE("(%p)->(dods=%ld,entries=%ld,fl=0x%08lx)\n",This,dodsize,*entries,flags);
631
632 len = ((This->queue_head < This->queue_tail) ? This->queue_len : 0)
633 + (This->queue_head - This->queue_tail);
634 if (len > *entries) len = *entries;
635
636 if (dod == NULL) {
637 *entries = len;
638 nqtail = This->queue_tail + len;
639 while (nqtail >= This->queue_len) nqtail -= This->queue_len;
640 } else {
641 if (dodsize != sizeof(DIDEVICEOBJECTDATA)) {
642 ERR("Wrong structure size !\n");
643 LeaveCriticalSection(&(This->crit));
644 return DIERR_INVALIDPARAM;
645 }
646
647 if (len)
648 TRACE("Application retrieving %ld event(s).\n", len);
649
650 *entries = 0;
651 nqtail = This->queue_tail;
652 while (len) {
653 DWORD span = ((This->queue_head < nqtail) ? This->queue_len : This->queue_head)
654 - nqtail;
655 if (span > len) span = len;
656 /* Copy the buffered data into the application queue */
657 memcpy(dod + *entries, This->data_queue + nqtail, span * dodsize);
658 /* Advance position */
659 nqtail += span;
660 if (nqtail >= This->queue_len) nqtail -= This->queue_len;
661 *entries += span;
662 len -= span;
663 }
664 }
665 if (!(flags & DIGDD_PEEK))
666 This->queue_tail = nqtail;
667
668 LeaveCriticalSection(&(This->crit));
669
670#ifndef __WIN32OS2__
671 //SvL: Completely breaks some apps
672 /* Check if we need to do a mouse warping */
673 if (This->need_warp == WARP_NEEDED) {
674 This->mapped_center.x = This->win_centerX;
675 This->mapped_center.y = This->win_centerY;
676 MapWindowPoints(This->win, HWND_DESKTOP, &This->mapped_center, 1);
677 TRACE("Warping mouse to %ld - %ld\n", This->mapped_center.x, This->mapped_center.y);
678 SetCursorPos( This->mapped_center.x, This->mapped_center.y );
679
680#ifdef MOUSE_HACK
681 This->need_warp = WARP_DONE;
682#else
683 This->need_warp = WARP_STARTED;
684#endif
685 }
686#endif
687 return 0;
688}
689
690/******************************************************************************
691 * SetProperty : change input device properties
692 */
693static HRESULT WINAPI SysMouseAImpl_SetProperty(LPDIRECTINPUTDEVICE2A iface,
694 REFGUID rguid,
695 LPCDIPROPHEADER ph)
696{
697 ICOM_THIS(SysMouseAImpl,iface);
698
699 TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(rguid),ph);
700
701 if (!HIWORD(rguid)) {
702 switch ((DWORD)rguid) {
703 case (DWORD) DIPROP_BUFFERSIZE: {
704 LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph;
705
706 TRACE("buffersize = %ld\n",pd->dwData);
707
708 This->data_queue = (LPDIDEVICEOBJECTDATA)HeapAlloc(GetProcessHeap(),0,
709 pd->dwData * sizeof(DIDEVICEOBJECTDATA));
710 This->queue_head = 0;
711 This->queue_tail = 0;
712 This->queue_len = pd->dwData;
713 break;
714 }
715 case (DWORD) DIPROP_AXISMODE: {
716 LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph;
717 This->absolute = !(pd->dwData);
718 TRACE("Using %s coordinates mode now\n", This->absolute ? "absolute" : "relative");
719 break;
720 }
721 default:
722 FIXME("Unknown type %ld (%s)\n",(DWORD)rguid,debugstr_guid(rguid));
723 break;
724 }
725 }
726
727 return 0;
728}
729
730/******************************************************************************
731 * GetProperty : get input device properties
732 */
733static HRESULT WINAPI SysMouseAImpl_GetProperty(LPDIRECTINPUTDEVICE2A iface,
734 REFGUID rguid,
735 LPDIPROPHEADER pdiph)
736{
737 ICOM_THIS(SysMouseAImpl,iface);
738
739 TRACE("(this=%p,%s,%p): stub!\n",
740 iface, debugstr_guid(rguid), pdiph);
741
742 if (TRACE_ON(dinput))
743 _dump_DIPROPHEADER(pdiph);
744
745 if (!HIWORD(rguid)) {
746 switch ((DWORD)rguid) {
747 case (DWORD) DIPROP_BUFFERSIZE: {
748 LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph;
749
750 TRACE(" return buffersize = %d\n",This->queue_len);
751 pd->dwData = This->queue_len;
752 break;
753 }
754
755 case (DWORD) DIPROP_RANGE: {
756 LPDIPROPRANGE pr = (LPDIPROPRANGE) pdiph;
757
758 if ((pdiph->dwHow == DIPH_BYID) &&
759 ((pdiph->dwObj == (DIDFT_MAKEINSTANCE(WINE_MOUSE_X_AXIS_INSTANCE) | DIDFT_RELAXIS)) ||
760 (pdiph->dwObj == (DIDFT_MAKEINSTANCE(WINE_MOUSE_Y_AXIS_INSTANCE) | DIDFT_RELAXIS)))) {
761 /* Querying the range of either the X or the Y axis. As I do
762 not know the range, do as if the range were
763 unrestricted...*/
764 pr->lMin = DIPROPRANGE_NOMIN;
765 pr->lMax = DIPROPRANGE_NOMAX;
766 }
767
768 break;
769 }
770
771 default:
772 FIXME("Unknown type %ld (%s)\n",(DWORD)rguid,debugstr_guid(rguid));
773 break;
774 }
775 }
776
777
778 return DI_OK;
779}
780
781
782
783/******************************************************************************
784 * SetEventNotification : specifies event to be sent on state change
785 */
786static HRESULT WINAPI SysMouseAImpl_SetEventNotification(LPDIRECTINPUTDEVICE2A iface,
787 HANDLE hnd) {
788 ICOM_THIS(SysMouseAImpl,iface);
789
790 TRACE("(this=%p,0x%08lx)\n",This,(DWORD)hnd);
791
792 This->hEvent = hnd;
793
794 return DI_OK;
795}
796
797/******************************************************************************
798 * GetCapabilities : get the device capablitites
799 */
800static HRESULT WINAPI SysMouseAImpl_GetCapabilities(
801 LPDIRECTINPUTDEVICE2A iface,
802 LPDIDEVCAPS lpDIDevCaps)
803{
804 ICOM_THIS(SysMouseAImpl,iface);
805
806 TRACE("(this=%p,%p)\n",This,lpDIDevCaps);
807
808 if (lpDIDevCaps->dwSize == sizeof(DIDEVCAPS)) {
809 lpDIDevCaps->dwFlags = DIDC_ATTACHED;
810 lpDIDevCaps->dwDevType = DIDEVTYPE_MOUSE;
811 lpDIDevCaps->dwAxes = 2;
812 lpDIDevCaps->dwButtons = 3;
813 lpDIDevCaps->dwPOVs = 0;
814 lpDIDevCaps->dwFFSamplePeriod = 0;
815 lpDIDevCaps->dwFFMinTimeResolution = 0;
816 lpDIDevCaps->dwFirmwareRevision = 100;
817 lpDIDevCaps->dwHardwareRevision = 100;
818 lpDIDevCaps->dwFFDriverVersion = 0;
819 } else {
820 /* DirectX 3.0 */
821 FIXME("DirectX 3.0 not supported....\n");
822 }
823
824 return DI_OK;
825}
826
827
828/******************************************************************************
829 * EnumObjects : enumerate the different buttons and axis...
830 */
831static HRESULT WINAPI SysMouseAImpl_EnumObjects(
832 LPDIRECTINPUTDEVICE2A iface,
833 LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback,
834 LPVOID lpvRef,
835 DWORD dwFlags)
836{
837 ICOM_THIS(SysMouseAImpl,iface);
838 DIDEVICEOBJECTINSTANCEA ddoi;
839
840 TRACE("(this=%p,%p,%p,%08lx)\n", This, lpCallback, lpvRef, dwFlags);
841 if (TRACE_ON(dinput)) {
842 DPRINTF(" - flags = ");
843 _dump_EnumObjects_flags(dwFlags);
844 DPRINTF("\n");
845 }
846
847 /* Only the fields till dwFFMaxForce are relevant */
848 ddoi.dwSize = FIELD_OFFSET(DIDEVICEOBJECTINSTANCEA, dwFFMaxForce);
849
850 /* In a mouse, we have : two relative axis and three buttons */
851 if ((dwFlags == DIDFT_ALL) ||
852 (dwFlags & DIDFT_AXIS)) {
853 /* X axis */
854 ddoi.guidType = GUID_XAxis;
855 ddoi.dwOfs = This->offset_array[WINE_MOUSE_X_POSITION];
856 ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_X_AXIS_INSTANCE) | DIDFT_RELAXIS;
857 strcpy(ddoi.tszName, "X-Axis");
858 _dump_OBJECTINSTANCEA(&ddoi);
859 if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
860
861 /* Y axis */
862 ddoi.guidType = GUID_YAxis;
863 ddoi.dwOfs = This->offset_array[WINE_MOUSE_Y_POSITION];
864 ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_Y_AXIS_INSTANCE) | DIDFT_RELAXIS;
865 strcpy(ddoi.tszName, "Y-Axis");
866 _dump_OBJECTINSTANCEA(&ddoi);
867 if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
868 }
869
870 if ((dwFlags == DIDFT_ALL) ||
871 (dwFlags & DIDFT_BUTTON)) {
872 ddoi.guidType = GUID_Button;
873
874 /* Left button */
875 ddoi.dwOfs = This->offset_array[WINE_MOUSE_L_POSITION];
876 ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_L_BUTTON_INSTANCE) | DIDFT_PSHBUTTON;
877 strcpy(ddoi.tszName, "Left-Button");
878 _dump_OBJECTINSTANCEA(&ddoi);
879 if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
880
881 /* Right button */
882 ddoi.dwOfs = This->offset_array[WINE_MOUSE_R_POSITION];
883 ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_R_BUTTON_INSTANCE) | DIDFT_PSHBUTTON;
884 strcpy(ddoi.tszName, "Right-Button");
885 _dump_OBJECTINSTANCEA(&ddoi);
886 if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
887
888 /* Middle button */
889 ddoi.dwOfs = This->offset_array[WINE_MOUSE_M_POSITION];
890 ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_M_BUTTON_INSTANCE) | DIDFT_PSHBUTTON;
891 strcpy(ddoi.tszName, "Middle-Button");
892 _dump_OBJECTINSTANCEA(&ddoi);
893 if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
894 }
895
896 return DI_OK;
897}
898
899
900static ICOM_VTABLE(IDirectInputDevice2A) SysMouseAvt =
901{
902 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
903 IDirectInputDevice2AImpl_QueryInterface,
904 IDirectInputDevice2AImpl_AddRef,
905 SysMouseAImpl_Release,
906 SysMouseAImpl_GetCapabilities,
907 SysMouseAImpl_EnumObjects,
908 SysMouseAImpl_GetProperty,
909 SysMouseAImpl_SetProperty,
910 SysMouseAImpl_Acquire,
911 SysMouseAImpl_Unacquire,
912 SysMouseAImpl_GetDeviceState,
913 SysMouseAImpl_GetDeviceData,
914 SysMouseAImpl_SetDataFormat,
915 SysMouseAImpl_SetEventNotification,
916 SysMouseAImpl_SetCooperativeLevel,
917 IDirectInputDevice2AImpl_GetObjectInfo,
918 IDirectInputDevice2AImpl_GetDeviceInfo,
919 IDirectInputDevice2AImpl_RunControlPanel,
920 IDirectInputDevice2AImpl_Initialize,
921 IDirectInputDevice2AImpl_CreateEffect,
922 IDirectInputDevice2AImpl_EnumEffects,
923 IDirectInputDevice2AImpl_GetEffectInfo,
924 IDirectInputDevice2AImpl_GetForceFeedbackState,
925 IDirectInputDevice2AImpl_SendForceFeedbackCommand,
926 IDirectInputDevice2AImpl_EnumCreatedEffectObjects,
927 IDirectInputDevice2AImpl_Escape,
928 IDirectInputDevice2AImpl_Poll,
929 IDirectInputDevice2AImpl_SendDeviceData,
930};
931
932#if !defined(__STRICT_ANSI__) && defined(__GNUC__)
933# define XCAST(fun) (typeof(SysMouse7Avt.fun))
934#else
935# define XCAST(fun) (void*)
936#endif
937
938static ICOM_VTABLE(IDirectInputDevice7A) SysMouse7Avt =
939{
940 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
941 XCAST(QueryInterface)IDirectInputDevice2AImpl_QueryInterface,
942 XCAST(AddRef)IDirectInputDevice2AImpl_AddRef,
943 XCAST(Release)SysMouseAImpl_Release,
944 XCAST(GetCapabilities)SysMouseAImpl_GetCapabilities,
945 XCAST(EnumObjects)SysMouseAImpl_EnumObjects,
946 XCAST(GetProperty)SysMouseAImpl_GetProperty,
947 XCAST(SetProperty)SysMouseAImpl_SetProperty,
948 XCAST(Acquire)SysMouseAImpl_Acquire,
949 XCAST(Unacquire)SysMouseAImpl_Unacquire,
950 XCAST(GetDeviceState)SysMouseAImpl_GetDeviceState,
951 XCAST(GetDeviceData)SysMouseAImpl_GetDeviceData,
952 XCAST(SetDataFormat)SysMouseAImpl_SetDataFormat,
953 XCAST(SetEventNotification)SysMouseAImpl_SetEventNotification,
954 XCAST(SetCooperativeLevel)SysMouseAImpl_SetCooperativeLevel,
955 XCAST(GetObjectInfo)IDirectInputDevice2AImpl_GetObjectInfo,
956 XCAST(GetDeviceInfo)IDirectInputDevice2AImpl_GetDeviceInfo,
957 XCAST(RunControlPanel)IDirectInputDevice2AImpl_RunControlPanel,
958 XCAST(Initialize)IDirectInputDevice2AImpl_Initialize,
959 XCAST(CreateEffect)IDirectInputDevice2AImpl_CreateEffect,
960 XCAST(EnumEffects)IDirectInputDevice2AImpl_EnumEffects,
961 XCAST(GetEffectInfo)IDirectInputDevice2AImpl_GetEffectInfo,
962 XCAST(GetForceFeedbackState)IDirectInputDevice2AImpl_GetForceFeedbackState,
963 XCAST(SendForceFeedbackCommand)IDirectInputDevice2AImpl_SendForceFeedbackCommand,
964 XCAST(EnumCreatedEffectObjects)IDirectInputDevice2AImpl_EnumCreatedEffectObjects,
965 XCAST(Escape)IDirectInputDevice2AImpl_Escape,
966 XCAST(Poll)IDirectInputDevice2AImpl_Poll,
967 XCAST(SendDeviceData)IDirectInputDevice2AImpl_SendDeviceData,
968 IDirectInputDevice7AImpl_EnumEffectsInFile,
969 IDirectInputDevice7AImpl_WriteEffectToFile
970};
971
972#undef XCAST
Note: See TracBrowser for help on using the repository browser.