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

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

check initial cursor position in relative mode when acquiring the mouse

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