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

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

Wine resync; added missing bugfix

File size: 32.7 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 This->m_state.lX = 0;
547 This->m_state.lY = 0;
548 }
549 This->m_state.lZ = 0;
550 This->m_state.rgbButtons[0] = (GetKeyState(VK_LBUTTON) ? 0xFF : 0x00);
551 This->m_state.rgbButtons[1] = (GetKeyState(VK_MBUTTON) ? 0xFF : 0x00);
552 This->m_state.rgbButtons[2] = (GetKeyState(VK_RBUTTON) ? 0xFF : 0x00);
553
554 /* Install our mouse hook */
555 if (This->dwCoopLevel & DISCL_EXCLUSIVE)
556 ShowCursor(FALSE); /* hide cursor */
557
558#ifdef __WIN32OS2__
559 /* push ebp */
560 This->hookcode[0] = 0x55;
561 /* mov ebp, esp */
562 This->hookcode[1] = 0x8B; This->hookcode[2] = 0xEC;
563 /* push [ebp+16] */
564 This->hookcode[3] = 0xFF; This->hookcode[4] = 0x75; This->hookcode[5] = 0x10;
565 /* push [ebp+12] */
566 This->hookcode[6] = 0xFF; This->hookcode[7] = 0x75; This->hookcode[8] = 0x0C;
567 /* push [ebp+8] */
568 This->hookcode[9] = 0xFF; This->hookcode[10] = 0x75; This->hookcode[11] = 0x08;
569 /* push This */
570 This->hookcode[12] = 0x68; *(DWORD *)&This->hookcode[13] = (DWORD)This;
571 /* mov eax, dinput_mouse_hook */
572 This->hookcode[17] = 0xB8; *(DWORD *)&This->hookcode[18] = (DWORD)&dinput_mouse_hook;
573 /* call eax */
574 This->hookcode[22] = 0xFF; This->hookcode[23] = 0xD0;
575 /* pop ebp */
576 This->hookcode[24] = 0x5D;
577 /* ret 12 */
578 This->hookcode[25] = 0xC2; *(WORD *)&This->hookcode[26] = 0x000C;
579
580 This->hook = SetWindowsHookExW( WH_MOUSE_LL, (HOOKPROC)This->hookcode, 0, 0 );
581#else
582 This->hook = SetWindowsHookExW( WH_MOUSE_LL, dinput_mouse_hook, 0, 0 );
583#endif
584
585 /* Get the window dimension and find the center */
586 GetWindowRect(This->win, &rect);
587 This->win_centerX = (rect.right - rect.left) / 2;
588 This->win_centerY = (rect.bottom - rect.top ) / 2;
589
590#ifndef __WIN32OS2__
591 /* Warp the mouse to the center of the window */
592 if (This->absolute == 0) {
593 This->mapped_center.x = This->win_centerX;
594 This->mapped_center.y = This->win_centerY;
595 MapWindowPoints(This->win, HWND_DESKTOP, &This->mapped_center, 1);
596 TRACE("Warping mouse to %ld - %ld\n", This->mapped_center.x, This->mapped_center.y);
597 SetCursorPos( This->mapped_center.x, This->mapped_center.y );
598#ifdef MOUSE_HACK
599 This->need_warp = WARP_DONE;
600#else
601 This->need_warp = WARP_STARTED;
602#endif
603 }
604#endif
605
606 This->acquired = 1;
607 return DI_OK;
608 }
609 return S_FALSE;
610}
611
612/******************************************************************************
613 * Unacquire : frees the mouse
614 */
615static HRESULT WINAPI SysMouseAImpl_Unacquire(LPDIRECTINPUTDEVICE8A iface)
616{
617 ICOM_THIS(SysMouseAImpl,iface);
618
619#ifdef __WIN32OS2__
620 dprintf(("SysMouseAImpl_Unacquire %x", This));
621#else
622 TRACE("(this=%p)\n",This);
623#endif
624 if (This->acquired)
625 {
626 /* Reinstall previous mouse event handler */
627 if (This->hook) {
628 UnhookWindowsHookEx( This->hook );
629 This->hook = 0;
630 if (This->dwCoopLevel & DISCL_EXCLUSIVE)
631 ShowCursor(TRUE); /* show cursor */
632 }
633
634 /* No more locks */
635 current_lock = NULL;
636
637 /* Unacquire device */
638 This->acquired = 0;
639 }
640 else
641 ERR("Unacquiring a not-acquired device !!!\n");
642
643 return DI_OK;
644}
645
646/******************************************************************************
647 * GetDeviceState : returns the "state" of the mouse.
648 *
649 * For the moment, only the "standard" return structure (DIMOUSESTATE) is
650 * supported.
651 */
652static HRESULT WINAPI SysMouseAImpl_GetDeviceState(
653 LPDIRECTINPUTDEVICE8A iface,DWORD len,LPVOID ptr
654) {
655 ICOM_THIS(SysMouseAImpl,iface);
656
657#ifdef __WIN32OS2__
658 /* mouse state may have changed since last hook call; update it first */
659 POINT point;
660 GetCursorPos(&point);
661
662 if(point.x != This->prevX || point.y != This->prevY) {
663 MSLLHOOKSTRUCT hook;
664
665 //Note: this is not entirely correct (should use HOOK_CallHooksW)
666 hook.pt.x = point.x;
667 hook.pt.y = point.y;
668 hook.mouseData = 0;
669 hook.flags = 0;
670 hook.time = GetCurrentTime();
671 hook.dwExtraInfo = 0;
672
673 dinput_mouse_hook(This, HC_ACTION, WM_MOUSEMOVE, (LPARAM)&hook );
674 }
675#endif
676
677 EnterCriticalSection(&(This->crit));
678 TRACE("(this=%p,0x%08lx,%p): \n",This,len,ptr);
679
680 /* Copy the current mouse state */
681 fill_DataFormat(ptr, &(This->m_state), This->wine_df);
682
683 /* Initialize the buffer when in relative mode */
684 if (This->absolute == 0) {
685 This->m_state.lX = 0;
686 This->m_state.lY = 0;
687 This->m_state.lZ = 0;
688 }
689
690#ifndef __WIN32OS2__
691 //SvL: Completely breaks some apps
692 /* Check if we need to do a mouse warping */
693 if (This->need_warp == WARP_NEEDED) {
694 dinput_window_check(This);
695 TRACE("Warping mouse to %ld - %ld\n", This->mapped_center.x, This->mapped_center.y);
696 SetCursorPos( This->mapped_center.x, This->mapped_center.y );
697
698#ifdef MOUSE_HACK
699 This->need_warp = WARP_DONE;
700#else
701 This->need_warp = WARP_STARTED;
702#endif
703 }
704#endif
705 LeaveCriticalSection(&(This->crit));
706
707 TRACE("(X: %ld - Y: %ld L: %02x M: %02x R: %02x)\n",
708 This->m_state.lX, This->m_state.lY,
709 This->m_state.rgbButtons[0], This->m_state.rgbButtons[2], This->m_state.rgbButtons[1]);
710
711 return 0;
712}
713
714/******************************************************************************
715 * GetDeviceState : gets buffered input data.
716 */
717static HRESULT WINAPI SysMouseAImpl_GetDeviceData(LPDIRECTINPUTDEVICE8A iface,
718 DWORD dodsize,
719 LPDIDEVICEOBJECTDATA dod,
720 LPDWORD entries,
721 DWORD flags
722) {
723 ICOM_THIS(SysMouseAImpl,iface);
724 DWORD len, nqtail;
725
726 EnterCriticalSection(&(This->crit));
727 TRACE("(%p)->(dods=%ld,entries=%ld,fl=0x%08lx)\n",This,dodsize,*entries,flags);
728
729 len = ((This->queue_head < This->queue_tail) ? This->queue_len : 0)
730 + (This->queue_head - This->queue_tail);
731 if (len > *entries) len = *entries;
732
733 if (dod == NULL) {
734 if (len)
735 TRACE("Application discarding %ld event(s).\n", len);
736
737 *entries = len;
738 nqtail = This->queue_tail + len;
739 while (nqtail >= This->queue_len) nqtail -= This->queue_len;
740 } else {
741 if (dodsize < sizeof(DIDEVICEOBJECTDATA)) {
742 ERR("Wrong structure size !\n");
743 LeaveCriticalSection(&(This->crit));
744 return DIERR_INVALIDPARAM;
745 }
746
747 if (len)
748 TRACE("Application retrieving %ld event(s).\n", len);
749
750 *entries = 0;
751 nqtail = This->queue_tail;
752 while (len) {
753 DWORD span = ((This->queue_head < nqtail) ? This->queue_len : This->queue_head)
754 - nqtail;
755 if (span > len) span = len;
756 /* Copy the buffered data into the application queue */
757 memcpy(dod + *entries, This->data_queue + nqtail, span * dodsize);
758 /* Advance position */
759 nqtail += span;
760 if (nqtail >= This->queue_len) nqtail -= This->queue_len;
761 *entries += span;
762 len -= span;
763 }
764 }
765 if (!(flags & DIGDD_PEEK))
766 This->queue_tail = nqtail;
767
768 LeaveCriticalSection(&(This->crit));
769
770#ifndef __WIN32OS2__
771 //SvL: Completely breaks some apps
772 /* Check if we need to do a mouse warping */
773 if (This->need_warp == WARP_NEEDED) {
774 dinput_window_check(This);
775 TRACE("Warping mouse to %ld - %ld\n", This->mapped_center.x, This->mapped_center.y);
776 SetCursorPos( This->mapped_center.x, This->mapped_center.y );
777
778#ifdef MOUSE_HACK
779 This->need_warp = WARP_DONE;
780#else
781 This->need_warp = WARP_STARTED;
782#endif
783 }
784#endif
785 return 0;
786}
787
788/******************************************************************************
789 * SetProperty : change input device properties
790 */
791static HRESULT WINAPI SysMouseAImpl_SetProperty(LPDIRECTINPUTDEVICE8A iface,
792 REFGUID rguid,
793 LPCDIPROPHEADER ph)
794{
795 ICOM_THIS(SysMouseAImpl,iface);
796
797 TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(rguid),ph);
798
799 if (!HIWORD(rguid)) {
800 switch ((DWORD)rguid) {
801 case (DWORD) DIPROP_BUFFERSIZE: {
802 LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph;
803
804 TRACE("buffersize = %ld\n",pd->dwData);
805
806 This->data_queue = (LPDIDEVICEOBJECTDATA)HeapAlloc(GetProcessHeap(),0,
807 pd->dwData * sizeof(DIDEVICEOBJECTDATA));
808 This->queue_head = 0;
809 This->queue_tail = 0;
810 This->queue_len = pd->dwData;
811 break;
812 }
813 case (DWORD) DIPROP_AXISMODE: {
814 LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph;
815 This->absolute = !(pd->dwData);
816 TRACE("Using %s coordinates mode now\n", This->absolute ? "absolute" : "relative");
817 break;
818 }
819 default:
820 FIXME("Unknown type %ld (%s)\n",(DWORD)rguid,debugstr_guid(rguid));
821 break;
822 }
823 }
824
825 return 0;
826}
827
828/******************************************************************************
829 * GetProperty : get input device properties
830 */
831static HRESULT WINAPI SysMouseAImpl_GetProperty(LPDIRECTINPUTDEVICE8A iface,
832 REFGUID rguid,
833 LPDIPROPHEADER pdiph)
834{
835 ICOM_THIS(SysMouseAImpl,iface);
836
837 TRACE("(this=%p,%s,%p): stub!\n",
838 iface, debugstr_guid(rguid), pdiph);
839
840 if (TRACE_ON(dinput))
841 _dump_DIPROPHEADER(pdiph);
842
843 if (!HIWORD(rguid)) {
844 switch ((DWORD)rguid) {
845 case (DWORD) DIPROP_BUFFERSIZE: {
846 LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph;
847
848 TRACE(" return buffersize = %d\n",This->queue_len);
849 pd->dwData = This->queue_len;
850 break;
851 }
852
853 case (DWORD) DIPROP_GRANULARITY: {
854 LPDIPROPDWORD pr = (LPDIPROPDWORD) pdiph;
855
856 /* We'll just assume that the app asks about the Z axis */
857 pr->dwData = WHEEL_DELTA;
858
859 break;
860 }
861
862 case (DWORD) DIPROP_RANGE: {
863 LPDIPROPRANGE pr = (LPDIPROPRANGE) pdiph;
864
865 if ((pdiph->dwHow == DIPH_BYID) &&
866 ((pdiph->dwObj == (DIDFT_MAKEINSTANCE(WINE_MOUSE_X_AXIS_INSTANCE) | DIDFT_RELAXIS)) ||
867 (pdiph->dwObj == (DIDFT_MAKEINSTANCE(WINE_MOUSE_Y_AXIS_INSTANCE) | DIDFT_RELAXIS)))) {
868 /* Querying the range of either the X or the Y axis. As I do
869 not know the range, do as if the range were
870 unrestricted...*/
871 pr->lMin = DIPROPRANGE_NOMIN;
872 pr->lMax = DIPROPRANGE_NOMAX;
873 }
874
875 break;
876 }
877
878 default:
879 FIXME("Unknown type %ld (%s)\n",(DWORD)rguid,debugstr_guid(rguid));
880 break;
881 }
882 }
883
884
885 return DI_OK;
886}
887
888
889
890/******************************************************************************
891 * SetEventNotification : specifies event to be sent on state change
892 */
893static HRESULT WINAPI SysMouseAImpl_SetEventNotification(LPDIRECTINPUTDEVICE8A iface,
894 HANDLE hnd) {
895 ICOM_THIS(SysMouseAImpl,iface);
896
897 TRACE("(this=%p,0x%08lx)\n",This,(DWORD)hnd);
898
899 This->hEvent = hnd;
900
901 return DI_OK;
902}
903
904/******************************************************************************
905 * GetCapabilities : get the device capablitites
906 */
907static HRESULT WINAPI SysMouseAImpl_GetCapabilities(
908 LPDIRECTINPUTDEVICE8A iface,
909 LPDIDEVCAPS lpDIDevCaps)
910{
911 ICOM_THIS(SysMouseAImpl,iface);
912
913 TRACE("(this=%p,%p)\n",This,lpDIDevCaps);
914
915 if (lpDIDevCaps->dwSize == sizeof(DIDEVCAPS)) {
916 lpDIDevCaps->dwFlags = DIDC_ATTACHED;
917 lpDIDevCaps->dwDevType = DIDEVTYPE_MOUSE;
918 lpDIDevCaps->dwAxes = 3;
919 lpDIDevCaps->dwButtons = 3;
920 lpDIDevCaps->dwPOVs = 0;
921 lpDIDevCaps->dwFFSamplePeriod = 0;
922 lpDIDevCaps->dwFFMinTimeResolution = 0;
923 lpDIDevCaps->dwFirmwareRevision = 100;
924 lpDIDevCaps->dwHardwareRevision = 100;
925 lpDIDevCaps->dwFFDriverVersion = 0;
926 } else {
927 /* DirectX 3.0 */
928 FIXME("DirectX 3.0 not supported....\n");
929 }
930
931 return DI_OK;
932}
933
934
935/******************************************************************************
936 * EnumObjects : enumerate the different buttons and axis...
937 */
938static HRESULT WINAPI SysMouseAImpl_EnumObjects(
939 LPDIRECTINPUTDEVICE8A iface,
940 LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback,
941 LPVOID lpvRef,
942 DWORD dwFlags)
943{
944 ICOM_THIS(SysMouseAImpl,iface);
945 DIDEVICEOBJECTINSTANCEA ddoi;
946
947 TRACE("(this=%p,%p,%p,%08lx)\n", This, lpCallback, lpvRef, dwFlags);
948 if (TRACE_ON(dinput)) {
949 DPRINTF(" - flags = ");
950 _dump_EnumObjects_flags(dwFlags);
951 DPRINTF("\n");
952 }
953
954 /* Only the fields till dwFFMaxForce are relevant */
955 ddoi.dwSize = FIELD_OFFSET(DIDEVICEOBJECTINSTANCEA, dwFFMaxForce);
956
957 /* In a mouse, we have : two relative axis and three buttons */
958 if ((dwFlags == DIDFT_ALL) ||
959 (dwFlags & DIDFT_AXIS)) {
960 /* X axis */
961 ddoi.guidType = GUID_XAxis;
962 ddoi.dwOfs = This->offset_array[WINE_MOUSE_X_POSITION];
963 ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_X_AXIS_INSTANCE) | DIDFT_RELAXIS;
964 strcpy(ddoi.tszName, "X-Axis");
965 _dump_OBJECTINSTANCEA(&ddoi);
966 if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
967
968 /* Y axis */
969 ddoi.guidType = GUID_YAxis;
970 ddoi.dwOfs = This->offset_array[WINE_MOUSE_Y_POSITION];
971 ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_Y_AXIS_INSTANCE) | DIDFT_RELAXIS;
972 strcpy(ddoi.tszName, "Y-Axis");
973 _dump_OBJECTINSTANCEA(&ddoi);
974 if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
975
976 /* Z axis */
977 ddoi.guidType = GUID_ZAxis;
978 ddoi.dwOfs = This->offset_array[WINE_MOUSE_Z_POSITION];
979 ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_Z_AXIS_INSTANCE) | DIDFT_RELAXIS;
980 strcpy(ddoi.tszName, "Z-Axis");
981 _dump_OBJECTINSTANCEA(&ddoi);
982 if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
983 }
984
985 if ((dwFlags == DIDFT_ALL) ||
986 (dwFlags & DIDFT_BUTTON)) {
987 ddoi.guidType = GUID_Button;
988
989 /* Left button */
990 ddoi.dwOfs = This->offset_array[WINE_MOUSE_L_POSITION];
991 ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_L_BUTTON_INSTANCE) | DIDFT_PSHBUTTON;
992 strcpy(ddoi.tszName, "Left-Button");
993 _dump_OBJECTINSTANCEA(&ddoi);
994 if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
995
996 /* Right button */
997 ddoi.dwOfs = This->offset_array[WINE_MOUSE_R_POSITION];
998 ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_R_BUTTON_INSTANCE) | DIDFT_PSHBUTTON;
999 strcpy(ddoi.tszName, "Right-Button");
1000 _dump_OBJECTINSTANCEA(&ddoi);
1001 if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
1002
1003 /* Middle button */
1004 ddoi.dwOfs = This->offset_array[WINE_MOUSE_M_POSITION];
1005 ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_M_BUTTON_INSTANCE) | DIDFT_PSHBUTTON;
1006 strcpy(ddoi.tszName, "Middle-Button");
1007 _dump_OBJECTINSTANCEA(&ddoi);
1008 if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
1009 }
1010
1011 return DI_OK;
1012}
1013
1014
1015static ICOM_VTABLE(IDirectInputDevice8A) SysMouseAvt =
1016{
1017 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1018 IDirectInputDevice2AImpl_QueryInterface,
1019 IDirectInputDevice2AImpl_AddRef,
1020 SysMouseAImpl_Release,
1021 SysMouseAImpl_GetCapabilities,
1022 SysMouseAImpl_EnumObjects,
1023 SysMouseAImpl_GetProperty,
1024 SysMouseAImpl_SetProperty,
1025 SysMouseAImpl_Acquire,
1026 SysMouseAImpl_Unacquire,
1027 SysMouseAImpl_GetDeviceState,
1028 SysMouseAImpl_GetDeviceData,
1029 SysMouseAImpl_SetDataFormat,
1030 SysMouseAImpl_SetEventNotification,
1031 SysMouseAImpl_SetCooperativeLevel,
1032 IDirectInputDevice2AImpl_GetObjectInfo,
1033 IDirectInputDevice2AImpl_GetDeviceInfo,
1034 IDirectInputDevice2AImpl_RunControlPanel,
1035 IDirectInputDevice2AImpl_Initialize,
1036 IDirectInputDevice2AImpl_CreateEffect,
1037 IDirectInputDevice2AImpl_EnumEffects,
1038 IDirectInputDevice2AImpl_GetEffectInfo,
1039 IDirectInputDevice2AImpl_GetForceFeedbackState,
1040 IDirectInputDevice2AImpl_SendForceFeedbackCommand,
1041 IDirectInputDevice2AImpl_EnumCreatedEffectObjects,
1042 IDirectInputDevice2AImpl_Escape,
1043 IDirectInputDevice2AImpl_Poll,
1044 IDirectInputDevice2AImpl_SendDeviceData,
1045 IDirectInputDevice7AImpl_EnumEffectsInFile,
1046 IDirectInputDevice7AImpl_WriteEffectToFile,
1047 IDirectInputDevice8AImpl_BuildActionMap,
1048 IDirectInputDevice8AImpl_SetActionMap,
1049 IDirectInputDevice8AImpl_GetImageInfo
1050};
Note: See TracBrowser for help on using the repository browser.