No longer directly accessing debuggee memory.
[wine] / windows / dinput.c
1 /*              DirectInput
2  *
3  * Copyright 1998 Marcus Meissner
4  * Copyright 1998,1999 Lionel Ulmer
5  *
6  */
7 /* Status:
8  *
9  * - Tomb Raider 2 Demo:
10  *   Playable using keyboard only.
11  * - WingCommander Prophecy Demo:
12  *   Doesn't get Input Focus.
13  * 
14  * - Fallout : works great in X and DGA mode
15  *
16  * FIXME: The keyboard handling needs to (and will) be merged into keyboard.c
17  *        (The current implementation is currently only a proof of concept and
18  *         an utter mess.)
19  */
20
21 #include "config.h"
22 #include <stdio.h>
23 #include <string.h>
24 #include <time.h>
25 #include <unistd.h>
26 #include <assert.h>
27 #ifdef HAVE_SYS_SIGNAL_H
28 # include <sys/signal.h>
29 #endif
30 #include <sys/time.h>
31 #include <sys/fcntl.h>
32 #include <sys/ioctl.h>
33 #include <errno.h>
34 #ifdef HAVE_SYS_ERRNO_H
35 # include <sys/errno.h>
36 #endif
37 #ifdef HAVE_LINUX_JOYSTICK_H
38 # include <linux/joystick.h>
39 # define JOYDEV "/dev/js0"
40 #endif
41 #include "wine/obj_base.h"
42 #include "debugtools.h"
43 #include "dinput.h"
44 #include "display.h"
45 #include "input.h"
46 #include "keyboard.h"
47 #include "message.h"
48 #include "mouse.h"
49 #include "sysmetrics.h"
50 #include "winbase.h"
51 #include "winerror.h"
52 #include "windef.h"
53 #include "wingdi.h"
54 #include "winuser.h"
55
56 DEFAULT_DEBUG_CHANNEL(dinput)
57
58 /* Wine mouse driver object instances */
59 #define WINE_MOUSE_X_AXIS_INSTANCE 0x0001
60 #define WINE_MOUSE_Y_AXIS_INSTANCE 0x0002
61 #define WINE_MOUSE_L_BUTTON_INSTANCE 0x0004
62 #define WINE_MOUSE_R_BUTTON_INSTANCE 0x0008
63 #define WINE_MOUSE_M_BUTTON_INSTANCE 0x0010
64
65 /* Wine joystick driver object instances */
66 #define WINE_JOYSTICK_AXIS_BASE   0
67 #define WINE_JOYSTICK_BUTTON_BASE 8
68
69 extern BYTE InputKeyStateTable[256];
70 extern int min_keycode, max_keycode;
71 extern WORD keyc2vkey[256];
72
73 /* Routines to do DataFormat / WineFormat conversions */
74 typedef struct {
75   int size;
76   int offset_in;
77   int offset_out;
78   int value;
79 } DataTransform;
80
81 typedef struct {
82   int size;
83   int internal_format_size;
84   DataTransform *dt;
85 } DataFormat;
86
87 /* ------------------------------- */
88 /* Wine mouse internal data format */
89 /* ------------------------------- */
90
91 /* Constants used to access the offset array */
92 #define WINE_MOUSE_X_POSITION 0
93 #define WINE_MOUSE_Y_POSITION 1
94 #define WINE_MOUSE_L_POSITION 2
95 #define WINE_MOUSE_R_POSITION 3
96 #define WINE_MOUSE_M_POSITION 4
97
98 typedef struct {
99   LONG lX;
100   LONG lY;
101   BYTE rgbButtons[4];
102 } Wine_InternalMouseData;
103
104 #define WINE_INTERNALMOUSE_NUM_OBJS 5
105
106 static DIOBJECTDATAFORMAT Wine_InternalMouseObjectFormat[WINE_INTERNALMOUSE_NUM_OBJS] = {
107   { &GUID_XAxis,   FIELD_OFFSET(Wine_InternalMouseData, lX),
108       DIDFT_MAKEINSTANCE(WINE_MOUSE_X_AXIS_INSTANCE) | DIDFT_RELAXIS, 0 },
109   { &GUID_YAxis,   FIELD_OFFSET(Wine_InternalMouseData, lY),
110       DIDFT_MAKEINSTANCE(WINE_MOUSE_Y_AXIS_INSTANCE) | DIDFT_RELAXIS, 0 },
111   { &GUID_Button, (FIELD_OFFSET(Wine_InternalMouseData, rgbButtons)) + 0,
112       DIDFT_MAKEINSTANCE(WINE_MOUSE_L_BUTTON_INSTANCE) | DIDFT_PSHBUTTON, 0 },
113   { &GUID_Button, (FIELD_OFFSET(Wine_InternalMouseData, rgbButtons)) + 1,
114       DIDFT_MAKEINSTANCE(WINE_MOUSE_R_BUTTON_INSTANCE) | DIDFT_PSHBUTTON, 0 },
115   { &GUID_Button, (FIELD_OFFSET(Wine_InternalMouseData, rgbButtons)) + 2,
116       DIDFT_MAKEINSTANCE(WINE_MOUSE_M_BUTTON_INSTANCE) | DIDFT_PSHBUTTON, 0 }
117 };
118
119 static DIDATAFORMAT Wine_InternalMouseFormat = {
120   0, /* dwSize - unused */
121   0, /* dwObjsize - unused */
122   0, /* dwFlags - unused */
123   sizeof(Wine_InternalMouseData),
124   WINE_INTERNALMOUSE_NUM_OBJS, /* dwNumObjs */
125   Wine_InternalMouseObjectFormat
126 };
127
128 static ICOM_VTABLE(IDirectInputA) ddiavt;
129 static ICOM_VTABLE(IDirectInputDevice2A) SysKeyboardAvt;
130 static ICOM_VTABLE(IDirectInputDevice2A) SysMouseAvt;
131
132 typedef struct IDirectInputAImpl IDirectInputAImpl;
133 typedef struct IDirectInputDevice2AImpl IDirectInputDevice2AImpl;
134 typedef struct SysKeyboardAImpl SysKeyboardAImpl;
135 typedef struct SysMouseAImpl SysMouseAImpl;
136
137 struct IDirectInputDevice2AImpl
138 {
139         ICOM_VFIELD(IDirectInputDevice2A);
140         DWORD                           ref;
141         GUID                            guid;
142 };
143
144 struct SysKeyboardAImpl
145 {
146         /* IDirectInputDevice2AImpl */
147         ICOM_VFIELD(IDirectInputDevice2A);
148         DWORD                           ref;
149         GUID                            guid;
150         /* SysKeyboardAImpl */
151         BYTE                            keystate[256];
152         KEYBOARD_CONFIG                 initial_config;
153         int                             acquired;
154 };
155
156 #ifdef HAVE_LINUX_22_JOYSTICK_API
157 typedef struct JoystickAImpl JoystickAImpl;
158 static ICOM_VTABLE(IDirectInputDevice2A) JoystickAvt;
159 struct JoystickAImpl
160 {
161         /* IDirectInputDevice2AImpl */
162         ICOM_VFIELD(IDirectInputDevice2A);
163         DWORD                           ref;
164         GUID                            guid;
165
166         /* joystick private */
167         int                             joyfd;
168         LPDIDATAFORMAT                  df;
169         HANDLE                          hEvent;
170         LONG                            lMin,lMax,deadzone;
171         LPDIDEVICEOBJECTDATA            data_queue;
172         int                             queue_pos, queue_len;
173         DIJOYSTATE                      js;
174 };
175 #endif
176
177 struct SysMouseAImpl
178 {
179         /* IDirectInputDevice2AImpl */
180         ICOM_VFIELD(IDirectInputDevice2A);
181         DWORD                           ref;
182         GUID                            guid;
183
184         /* The current data format and the conversion between internal
185            and external data formats */
186         LPDIDATAFORMAT                  df;
187         DataFormat                     *wine_df;
188         int                             offset_array[5];
189         
190         /* SysMouseAImpl */
191         BYTE                            absolute;
192         /* Previous position for relative moves */
193         LONG                            prevX, prevY;
194         LPMOUSE_EVENT_PROC              prev_handler;
195         HWND                            win;
196         DWORD                           win_centerX, win_centerY;
197         LPDIDEVICEOBJECTDATA            data_queue;
198         int                             queue_pos, queue_len;
199         int                             need_warp;
200         int                             acquired;
201         HANDLE                          hEvent;
202         CRITICAL_SECTION                crit;
203
204         /* This is for mouse reporting. */
205         Wine_InternalMouseData          m_state;
206 };
207
208 static int evsequence=0;
209
210
211 /* UIDs for Wine "drivers".
212    When enumerating each device supporting DInput, they have two UIDs :
213     - the 'windows' UID
214     - a vendor UID */
215 #ifdef HAVE_LINUX_22_JOYSTICK_API
216 static GUID DInput_Wine_Joystick_GUID = { /* 9e573ed9-7734-11d2-8d4a-23903fb6bdf7 */
217   0x9e573ed9,
218   0x7734,
219   0x11d2,
220   {0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf7}
221 };
222 #endif
223 static GUID DInput_Wine_Mouse_GUID = { /* 9e573ed8-7734-11d2-8d4a-23903fb6bdf7 */
224   0x9e573ed8,
225   0x7734,
226   0x11d2,
227   {0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf7}
228 };
229 static GUID DInput_Wine_Keyboard_GUID = { /* 0ab8648a-7735-11d2-8c73-71df54a96441 */
230   0x0ab8648a,
231   0x7735,
232   0x11d2,
233   {0x8c, 0x73, 0x71, 0xdf, 0x54, 0xa9, 0x64, 0x41}
234 };
235
236 /* FIXME: This is ugly and not thread safe :/ */
237 static IDirectInputDevice2A* current_lock = NULL;
238
239 /******************************************************************************
240  *      Various debugging tools
241  */
242 static void _dump_cooperativelevel(DWORD dwFlags) {
243   int   i;
244   const struct {
245     DWORD       mask;
246     char        *name;
247   } flags[] = {
248 #define FE(x) { x, #x},
249     FE(DISCL_BACKGROUND)
250     FE(DISCL_EXCLUSIVE)
251     FE(DISCL_FOREGROUND)
252     FE(DISCL_NONEXCLUSIVE)
253 #undef FE
254   };
255   for (i=0;i<sizeof(flags)/sizeof(flags[0]);i++)
256     if (flags[i].mask & dwFlags)
257       DPRINTF("%s ",flags[i].name);
258   DPRINTF("\n");
259 }
260
261 static void _dump_EnumObjects_flags(DWORD dwFlags) {
262   int   i;
263   const struct {
264     DWORD       mask;
265     char        *name;
266   } flags[] = {
267 #define FE(x) { x, #x},
268     FE(DIDFT_ABSAXIS)
269     FE(DIDFT_ALL)
270     FE(DIDFT_AXIS)
271     FE(DIDFT_BUTTON)
272     FE(DIDFT_COLLECTION)
273     FE(DIDFT_FFACTUATOR)
274     FE(DIDFT_FFEFFECTTRIGGER)
275     FE(DIDFT_NOCOLLECTION)
276     FE(DIDFT_NODATA)
277     FE(DIDFT_OUTPUT)
278     FE(DIDFT_POV)
279     FE(DIDFT_PSHBUTTON)
280     FE(DIDFT_RELAXIS)
281     FE(DIDFT_TGLBUTTON)
282 #undef FE
283   };
284   if (dwFlags == DIDFT_ALL) {
285     DPRINTF("DIDFT_ALL");
286     return;
287   }
288   for (i=0;i<sizeof(flags)/sizeof(flags[0]);i++)
289     if (flags[i].mask & dwFlags)
290       DPRINTF("%s ",flags[i].name);
291   if (dwFlags & DIDFT_INSTANCEMASK)
292     DPRINTF("Instance(%04lx) ", dwFlags >> 8);
293 }
294
295 static void _dump_DIPROPHEADER(DIPROPHEADER *diph) {
296   DPRINTF("  - dwObj = 0x%08lx\n", diph->dwObj);
297   DPRINTF("  - dwHow = %s\n",
298           ((diph->dwHow == DIPH_DEVICE) ? "DIPH_DEVICE" :
299            ((diph->dwHow == DIPH_BYOFFSET) ? "DIPH_BYOFFSET" :
300             ((diph->dwHow == DIPH_BYID)) ? "DIPH_BYID" : "unknown")));
301 }
302
303 static void _dump_OBJECTINSTANCE(DIDEVICEOBJECTINSTANCE *ddoi) {
304   if (TRACE_ON(dinput)) {
305     DPRINTF("    - enumerating : 0x%08lx - %2ld - 0x%08lx - %s\n",
306             ddoi->guidType.Data1, ddoi->dwOfs, ddoi->dwType, ddoi->tszName);
307   }
308 }
309
310 struct IDirectInputAImpl
311 {
312         ICOM_VFIELD(IDirectInputA);
313         DWORD                   ref;
314 };
315
316 /* Conversion between internal data buffer and external data buffer */
317 static void fill_DataFormat(void *out, void *in, DataFormat *df) {
318   int i;
319   char *in_c = (char *) in;
320   char *out_c = (char *) out;
321
322   if (df->dt == NULL) {
323     /* This means that the app uses Wine's internal data format */
324     memcpy(out, in, df->internal_format_size);
325   } else {
326     for (i = 0; i < df->size; i++) {
327       if (df->dt[i].offset_in >= 0) {
328         switch (df->dt[i].size) {
329         case 1:
330           TRACE("Copying (c) to %d from %d (value %d)\n",
331                 df->dt[i].offset_out, df->dt[i].offset_in, *((char *) (in_c + df->dt[i].offset_in)));
332           *((char *) (out_c + df->dt[i].offset_out)) = *((char *) (in_c + df->dt[i].offset_in));
333           break;
334         
335         case 2:
336           TRACE("Copying (s) to %d from %d (value %d)\n",
337                 df->dt[i].offset_out, df->dt[i].offset_in, *((short *) (in_c + df->dt[i].offset_in)));
338           *((short *) (out_c + df->dt[i].offset_out)) = *((short *) (in_c + df->dt[i].offset_in));
339           break;
340         
341         case 4:
342           TRACE("Copying (i) to %d from %d (value %d)\n",
343                 df->dt[i].offset_out, df->dt[i].offset_in, *((int *) (in_c + df->dt[i].offset_in)));
344           *((int *) (out_c + df->dt[i].offset_out)) = *((int *) (in_c + df->dt[i].offset_in));
345           break;
346         
347         default:
348           memcpy((out_c + df->dt[i].offset_out), (in_c + df->dt[i].offset_in), df->dt[i].size);
349         }
350       } else {
351         switch (df->dt[i].size) {
352         case 1:
353           TRACE("Copying (c) to %d default value %d\n",
354                 df->dt[i].offset_out, df->dt[i].value);
355           *((char *) (out_c + df->dt[i].offset_out)) = (char) df->dt[i].value;
356           break;
357         
358         case 2:
359           TRACE("Copying (s) to %d default value %d\n",
360                 df->dt[i].offset_out, df->dt[i].value);
361           *((short *) (out_c + df->dt[i].offset_out)) = (short) df->dt[i].value;
362           break;
363         
364         case 4:
365           TRACE("Copying (i) to %d default value %d\n",
366                 df->dt[i].offset_out, df->dt[i].value);
367           *((int *) (out_c + df->dt[i].offset_out)) = (int) df->dt[i].value;
368           break;
369         
370         default:
371           memset((out_c + df->dt[i].offset_out), df->dt[i].size, 0);
372         }
373       }
374     }
375   }
376 }
377
378 static DataFormat *create_DataFormat(DIDATAFORMAT *wine_format, DIDATAFORMAT *asked_format, int *offset) {
379   DataFormat *ret;
380   DataTransform *dt;
381   int i, j;
382   int same = 1;
383   int *done;
384   int index = 0;
385   
386   ret = (DataFormat *) HeapAlloc(GetProcessHeap(), 0, sizeof(DataFormat));
387   
388   done = (int *) HeapAlloc(GetProcessHeap(), 0, sizeof(int) * asked_format->dwNumObjs);
389   memset(done, 0, sizeof(int) * asked_format->dwNumObjs);
390
391   dt = (DataTransform *) HeapAlloc(GetProcessHeap(), 0, asked_format->dwNumObjs * sizeof(DataTransform));
392
393   TRACE("Creating DataTransorm : \n");
394   
395   for (i = 0; i < wine_format->dwNumObjs; i++) {
396     offset[i] = -1;
397     
398     for (j = 0; j < asked_format->dwNumObjs; j++) {
399       if (done[j] == 1)
400         continue;
401       
402       if (((asked_format->rgodf[j].pguid == NULL) || (IsEqualGUID(wine_format->rgodf[i].pguid, asked_format->rgodf[j].pguid)))
403           &&
404           (wine_format->rgodf[i].dwType & asked_format->rgodf[j].dwType)) {
405
406         done[j] = 1;
407
408         TRACE("Matching : \n"); 
409         TRACE("   - Asked (%d) : %s - Ofs = %3ld - (Type = 0x%02x | Instance = %04x)\n",
410               j, debugstr_guid(asked_format->rgodf[j].pguid), 
411               asked_format->rgodf[j].dwOfs,
412               DIDFT_GETTYPE(asked_format->rgodf[j].dwType), DIDFT_GETINSTANCE(asked_format->rgodf[j].dwType));
413         
414         TRACE("   - Wine  (%d) : %s - Ofs = %3ld - (Type = 0x%02x | Instance = %04x)\n",
415               j, debugstr_guid(wine_format->rgodf[i].pguid), 
416               wine_format->rgodf[i].dwOfs,
417               DIDFT_GETTYPE(wine_format->rgodf[i].dwType), DIDFT_GETINSTANCE(wine_format->rgodf[i].dwType));
418         
419         if (wine_format->rgodf[i].dwType & DIDFT_BUTTON)
420           dt[index].size = sizeof(BYTE);
421         else
422           dt[index].size = sizeof(DWORD);
423         dt[index].offset_in  = wine_format ->rgodf[i].dwOfs;
424         dt[index].offset_out = asked_format->rgodf[j].dwOfs;
425         dt[index].value = 0;
426         index++;
427         
428         if (wine_format->rgodf[i].dwOfs != asked_format->rgodf[j].dwOfs)
429           same = 0;
430
431         offset[i] = asked_format->rgodf[j].dwOfs;
432         break;
433       }
434     }
435
436     if (j == asked_format->dwNumObjs)
437       same = 0;
438   }
439
440   TRACE("Setting to default value :\n");
441   for (j = 0; j < asked_format->dwNumObjs; j++) {
442     if (done[j] == 0) {
443       TRACE(" - Asked (%d) : %s - Ofs = %3ld - (Type = 0x%02x | Instance = %04x)\n",
444             j, debugstr_guid(asked_format->rgodf[j].pguid), 
445             asked_format->rgodf[j].dwOfs,
446             DIDFT_GETTYPE(asked_format->rgodf[j].dwType), DIDFT_GETINSTANCE(asked_format->rgodf[j].dwType));
447
448       
449       if (asked_format->rgodf[j].dwType & DIDFT_BUTTON)
450         dt[index].size = sizeof(BYTE);
451       else
452         dt[index].size = sizeof(DWORD);
453       dt[index].offset_in  = -1;
454       dt[index].offset_out = asked_format->rgodf[j].dwOfs;
455       dt[index].value = 0;
456       index++;
457
458       same = 0;
459     }
460   }
461
462   ret->internal_format_size = wine_format->dwDataSize;
463   ret->size = index;
464   if (same) {
465     ret->dt = NULL;
466     HeapFree(GetProcessHeap(), 0, dt);
467   } else {
468     ret->dt = dt;
469   }
470   
471   HeapFree(GetProcessHeap(), 0, done);
472
473   return ret;
474 }
475
476 /******************************************************************************
477  *      DirectInputCreate32A
478  */
479 HRESULT WINAPI DirectInputCreateA(HINSTANCE hinst, DWORD dwVersion, LPDIRECTINPUTA *ppDI, LPUNKNOWN punkOuter)
480 {
481         IDirectInputAImpl* This;
482         TRACE("(0x%08lx,%04lx,%p,%p)\n",
483                 (DWORD)hinst,dwVersion,ppDI,punkOuter
484         );
485         This = (IDirectInputAImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(IDirectInputAImpl));
486         This->ref = 1;
487         ICOM_VTBL(This) = &ddiavt;
488         *ppDI=(IDirectInputA*)This;
489         return 0;
490 }
491 /******************************************************************************
492  *      IDirectInputA_EnumDevices
493  */
494 static HRESULT WINAPI IDirectInputAImpl_EnumDevices(
495         LPDIRECTINPUTA iface, DWORD dwDevType, LPDIENUMDEVICESCALLBACKA lpCallback,
496         LPVOID pvRef, DWORD dwFlags
497 )
498 {
499         ICOM_THIS(IDirectInputAImpl,iface);
500         DIDEVICEINSTANCEA devInstance;
501         int ret;
502
503         TRACE("(this=%p,0x%04lx,%p,%p,%04lx)\n", This, dwDevType, lpCallback, pvRef, dwFlags);
504
505         devInstance.dwSize = sizeof(DIDEVICEINSTANCEA);
506         if ((dwDevType == 0) || (dwDevType == DIDEVTYPE_KEYBOARD)) {
507                 /* Return keyboard */
508                 devInstance.guidInstance = GUID_SysKeyboard;/* DInput's GUID */
509                 devInstance.guidProduct = DInput_Wine_Keyboard_GUID; /* Vendor's GUID */
510                 devInstance.dwDevType = DIDEVTYPE_KEYBOARD | (DIDEVTYPEKEYBOARD_UNKNOWN << 8);
511                 strcpy(devInstance.tszInstanceName, "Keyboard");
512                 strcpy(devInstance.tszProductName, "Wine Keyboard");
513
514                 ret = lpCallback(&devInstance, pvRef);
515                 TRACE("Keyboard registered\n");
516                 if (ret == DIENUM_STOP)
517                         return 0;
518         }
519   
520         if ((dwDevType == 0) || (dwDevType == DIDEVTYPE_MOUSE)) {
521                 /* Return mouse */
522                 devInstance.guidInstance = GUID_SysMouse;/* DInput's GUID */
523                 devInstance.guidProduct = DInput_Wine_Mouse_GUID; /* Vendor's GUID */
524                 devInstance.dwDevType = DIDEVTYPE_MOUSE | (DIDEVTYPEMOUSE_UNKNOWN << 8);
525                 strcpy(devInstance.tszInstanceName, "Mouse");
526                 strcpy(devInstance.tszProductName, "Wine Mouse");
527
528                 ret = lpCallback(&devInstance, pvRef);
529                 TRACE("Mouse registered\n");
530                 if (ret == DIENUM_STOP)
531                         return 0;
532         }
533         if ((dwDevType == 0) || (dwDevType == DIDEVTYPE_JOYSTICK)) {
534                 /* check whether we have a joystick */
535 #ifdef HAVE_LINUX_22_JOYSTICK_API
536                 if (    (access(JOYDEV,O_RDONLY)!=-1)           ||
537                         (errno!=ENODEV && errno!=ENOENT)
538                 ) {
539                     /* Return joystick */
540                     devInstance.guidInstance    = GUID_Joystick;
541                     devInstance.guidProduct     = DInput_Wine_Joystick_GUID;
542                     /* we only support traditional joysticks for now */
543                     devInstance.dwDevType       = DIDEVTYPE_JOYSTICK | DIDEVTYPEJOYSTICK_TRADITIONAL;
544                     strcpy(devInstance.tszInstanceName, "Joystick");
545                     /* ioctl JSIOCGNAME(len) */
546                     strcpy(devInstance.tszProductName,  "Wine Joystick");
547
548                     ret = lpCallback(&devInstance,pvRef);
549                     TRACE("Joystick registered\n");
550                     if (ret == DIENUM_STOP)
551                             return 0;
552                 }
553 #endif
554         }
555         return 0;
556 }
557
558 static ULONG WINAPI IDirectInputAImpl_AddRef(LPDIRECTINPUTA iface)
559 {
560         ICOM_THIS(IDirectInputAImpl,iface);
561         return ++(This->ref);
562 }
563
564 static ULONG WINAPI IDirectInputAImpl_Release(LPDIRECTINPUTA iface)
565 {
566         ICOM_THIS(IDirectInputAImpl,iface);
567         if (!(--This->ref)) {
568                 HeapFree(GetProcessHeap(),0,This);
569                 return 0;
570         }
571         return This->ref;
572 }
573
574 static HRESULT WINAPI IDirectInputAImpl_CreateDevice(
575         LPDIRECTINPUTA iface,REFGUID rguid,LPDIRECTINPUTDEVICEA* pdev,
576         LPUNKNOWN punk
577 ) {
578         ICOM_THIS(IDirectInputAImpl,iface);
579         
580         TRACE("(this=%p,%s,%p,%p)\n",This,debugstr_guid(rguid),pdev,punk);
581         if ((IsEqualGUID(&GUID_SysKeyboard,rguid)) ||          /* Generic Keyboard */
582             (IsEqualGUID(&DInput_Wine_Keyboard_GUID,rguid))) { /* Wine Keyboard */
583                 SysKeyboardAImpl* newDevice;
584                 newDevice = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(SysKeyboardAImpl));
585                 newDevice->ref = 1;
586                 ICOM_VTBL(newDevice) = &SysKeyboardAvt;
587                 memcpy(&(newDevice->guid),rguid,sizeof(*rguid));
588                 memset(newDevice->keystate,0,256);
589                 *pdev=(IDirectInputDeviceA*)newDevice;
590
591                 TRACE("Creating a Keyboard device (%p)\n", newDevice);
592                 return DI_OK;
593         }
594         if ((IsEqualGUID(&GUID_SysMouse,rguid)) ||             /* Generic Mouse */
595             (IsEqualGUID(&DInput_Wine_Mouse_GUID,rguid))) { /* Wine Mouse */
596                 SysMouseAImpl* newDevice;
597                 int offset_array[5] = {
598                   FIELD_OFFSET(Wine_InternalMouseData, lX),
599                   FIELD_OFFSET(Wine_InternalMouseData, lY),
600                   FIELD_OFFSET(Wine_InternalMouseData, rgbButtons) + 0,
601                   FIELD_OFFSET(Wine_InternalMouseData, rgbButtons) + 1,
602                   FIELD_OFFSET(Wine_InternalMouseData, rgbButtons) + 2
603                 };
604                 
605                 newDevice = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(SysMouseAImpl));
606                 newDevice->ref = 1;
607                 ICOM_VTBL(newDevice) = &SysMouseAvt;
608                 InitializeCriticalSection(&(newDevice->crit));
609                 MakeCriticalSectionGlobal(&(newDevice->crit));
610                 memcpy(&(newDevice->guid),rguid,sizeof(*rguid));
611                 *pdev=(IDirectInputDeviceA*)newDevice;
612
613                 /* Per default, Wine uses its internal data format */
614                 newDevice->df = &Wine_InternalMouseFormat;
615                 memcpy(newDevice->offset_array, offset_array, 5 * sizeof(int));
616                 newDevice->wine_df = (DataFormat *) HeapAlloc(GetProcessHeap(), 0, sizeof(DataFormat));
617                 newDevice->wine_df->size = 0;
618                 newDevice->wine_df->internal_format_size = Wine_InternalMouseFormat.dwDataSize;
619                 newDevice->wine_df->dt = NULL;
620                 
621                 TRACE("Creating a Mouse device (%p)\n", newDevice);
622                 return DI_OK;
623         }
624 #ifdef HAVE_LINUX_22_JOYSTICK_API
625         if ((IsEqualGUID(&GUID_Joystick,rguid)) ||
626             (IsEqualGUID(&DInput_Wine_Joystick_GUID,rguid))) {
627                 JoystickAImpl* newDevice;
628                 newDevice = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(JoystickAImpl));
629                 newDevice->ref          = 1;
630                 ICOM_VTBL(newDevice)    = &JoystickAvt;
631                 newDevice->joyfd        = -1;
632                 newDevice->lMin = -32768;
633                 newDevice->lMax = +32767;
634                 memcpy(&(newDevice->guid),rguid,sizeof(*rguid));
635                 *pdev=(IDirectInputDeviceA*)newDevice;
636
637                 TRACE("Creating a Joystick device (%p)\n", newDevice);
638                 return DI_OK;
639         }
640 #endif
641         return E_FAIL;
642 }
643
644 static HRESULT WINAPI IDirectInputAImpl_QueryInterface(
645         LPDIRECTINPUTA iface,REFIID riid,LPVOID *ppobj
646 ) {
647         ICOM_THIS(IDirectInputAImpl,iface);
648
649         TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
650         if (IsEqualGUID(&IID_IUnknown,riid)) {
651                 IDirectInputA_AddRef(iface);
652                 *ppobj = This;
653                 return 0;
654         }
655         if (IsEqualGUID(&IID_IDirectInputA,riid)) {
656                 IDirectInputA_AddRef(iface);
657                 *ppobj = This;
658                 return 0;
659         }
660         TRACE("Unsupported interface !\n");
661         return E_FAIL;
662 }
663
664 static HRESULT WINAPI IDirectInputAImpl_Initialize(
665         LPDIRECTINPUTA iface,HINSTANCE hinst,DWORD x
666 ) {
667         return DIERR_ALREADYINITIALIZED;
668 }
669
670 static HRESULT WINAPI IDirectInputAImpl_GetDeviceStatus(LPDIRECTINPUTA iface,
671                                                         REFGUID rguid) {
672   ICOM_THIS(IDirectInputAImpl,iface);
673   
674   FIXME("(%p)->(%s): stub\n",This,debugstr_guid(rguid));
675   
676   return DI_OK;
677 }
678
679 static HRESULT WINAPI IDirectInputAImpl_RunControlPanel(LPDIRECTINPUTA iface,
680                                                         HWND hwndOwner,
681                                                         DWORD dwFlags) {
682   ICOM_THIS(IDirectInputAImpl,iface);
683   FIXME("(%p)->(%08lx,%08lx): stub\n",This, (DWORD) hwndOwner, dwFlags);
684   
685   return DI_OK;
686 }
687
688 static ICOM_VTABLE(IDirectInputA) ddiavt = 
689 {
690         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
691         IDirectInputAImpl_QueryInterface,
692         IDirectInputAImpl_AddRef,
693         IDirectInputAImpl_Release,
694         IDirectInputAImpl_CreateDevice,
695         IDirectInputAImpl_EnumDevices,
696         IDirectInputAImpl_GetDeviceStatus,
697         IDirectInputAImpl_RunControlPanel,
698         IDirectInputAImpl_Initialize
699 };
700
701 /******************************************************************************
702  *      IDirectInputDeviceA
703  */
704
705 static HRESULT WINAPI IDirectInputDevice2AImpl_SetDataFormat(
706         LPDIRECTINPUTDEVICE2A iface,LPCDIDATAFORMAT df
707 ) {
708         /*
709         int i;
710         TRACE(dinput,"(this=%p,%p)\n",This,df);
711
712         TRACE(dinput,"df.dwSize=%ld\n",df->dwSize);
713         TRACE(dinput,"(df.dwObjsize=%ld)\n",df->dwObjSize);
714         TRACE(dinput,"(df.dwFlags=0x%08lx)\n",df->dwFlags);
715         TRACE(dinput,"(df.dwDataSize=%ld)\n",df->dwDataSize);
716         TRACE(dinput,"(df.dwNumObjs=%ld)\n",df->dwNumObjs);
717
718         for (i=0;i<df->dwNumObjs;i++) {
719                 TRACE(dinput,"df.rgodf[%d].guid %s\n",i,debugstr_guid(df->rgodf[i].pguid));
720                 TRACE(dinput,"df.rgodf[%d].dwOfs %ld\n",i,df->rgodf[i].dwOfs);
721                 TRACE(dinput,"dwType 0x%02lx,dwInstance %ld\n",DIDFT_GETTYPE(df->rgodf[i].dwType),DIDFT_GETINSTANCE(df->rgodf[i].dwType));
722                 TRACE(dinput,"df.rgodf[%d].dwFlags 0x%08lx\n",i,df->rgodf[i].dwFlags);
723         }
724         */
725         return 0;
726 }
727
728 static HRESULT WINAPI IDirectInputDevice2AImpl_SetCooperativeLevel(
729         LPDIRECTINPUTDEVICE2A iface,HWND hwnd,DWORD dwflags
730 ) {
731         ICOM_THIS(IDirectInputDevice2AImpl,iface);
732         TRACE("(this=%p,0x%08lx,0x%08lx)\n",This,(DWORD)hwnd,dwflags);
733         if (TRACE_ON(dinput))
734           _dump_cooperativelevel(dwflags);
735         return 0;
736 }
737
738 static HRESULT WINAPI IDirectInputDevice2AImpl_SetEventNotification(
739         LPDIRECTINPUTDEVICE2A iface,HANDLE hnd
740 ) {
741         ICOM_THIS(IDirectInputDevice2AImpl,iface);
742         FIXME("(this=%p,0x%08lx): stub\n",This,(DWORD)hnd);
743         return 0;
744 }
745
746 static ULONG WINAPI IDirectInputDevice2AImpl_Release(LPDIRECTINPUTDEVICE2A iface)
747 {
748         ICOM_THIS(IDirectInputDevice2AImpl,iface);
749         This->ref--;
750         if (This->ref)
751                 return This->ref;
752         HeapFree(GetProcessHeap(),0,This);
753         return 0;
754 }
755
756 static HRESULT WINAPI SysKeyboardAImpl_SetProperty(
757         LPDIRECTINPUTDEVICE2A iface,REFGUID rguid,LPCDIPROPHEADER ph
758 )
759 {
760         ICOM_THIS(SysKeyboardAImpl,iface);
761
762         TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(rguid),ph);
763         TRACE("(size=%ld,headersize=%ld,obj=%ld,how=%ld\n",
764             ph->dwSize,ph->dwHeaderSize,ph->dwObj,ph->dwHow);
765         if (!HIWORD(rguid)) {
766                 switch ((DWORD)rguid) {
767                 case (DWORD) DIPROP_BUFFERSIZE: {
768                         LPCDIPROPDWORD  pd = (LPCDIPROPDWORD)ph;
769
770                         TRACE("(buffersize=%ld)\n",pd->dwData);
771                         break;
772                 }
773                 default:
774                         WARN("Unknown type %ld\n",(DWORD)rguid);
775                         break;
776                 }
777         }
778         return 0;
779 }
780
781 static HRESULT WINAPI SysKeyboardAImpl_GetDeviceState(
782         LPDIRECTINPUTDEVICE2A iface,DWORD len,LPVOID ptr
783 )
784 {
785         return KEYBOARD_Driver->pGetDIState(len, ptr)?DI_OK:E_FAIL;
786 }
787
788 static HRESULT WINAPI SysKeyboardAImpl_GetDeviceData(
789         LPDIRECTINPUTDEVICE2A iface,DWORD dodsize,LPDIDEVICEOBJECTDATA dod,
790         LPDWORD entries,DWORD flags
791 )
792 {
793         ICOM_THIS(SysKeyboardAImpl,iface);
794         HRESULT ret;
795         int     i;
796
797         TRACE("(this=%p,%ld,%p,%p(%ld)),0x%08lx)\n",
798               This,dodsize,dod,entries,entries?*entries:0,flags);
799
800         ret=KEYBOARD_Driver->pGetDIData(
801                 This->keystate, dodsize, dod, entries, flags)?DI_OK:E_FAIL;
802         for (i=0;i<*entries;i++) {
803                 dod[i].dwTimeStamp = GetTickCount();
804                 dod[i].dwSequence = evsequence++;
805         }
806         return ret;
807 }
808
809 static HRESULT WINAPI SysKeyboardAImpl_Acquire(LPDIRECTINPUTDEVICE2A iface)
810 {
811         ICOM_THIS(SysKeyboardAImpl,iface);
812         
813         TRACE("(this=%p)\n",This);
814         
815         if (This->acquired == 0) {
816           KEYBOARD_CONFIG no_auto;
817           
818           /* Save the original config */
819           KEYBOARD_Driver->pGetKeyboardConfig(&(This->initial_config));
820           
821           /* Now, remove auto-repeat */
822           no_auto.auto_repeat = FALSE;
823           KEYBOARD_Driver->pSetKeyboardConfig(&no_auto, WINE_KEYBOARD_CONFIG_AUTO_REPEAT);
824
825           This->acquired = 1;
826         }
827         
828         return DI_OK;
829 }
830
831 static HRESULT WINAPI SysKeyboardAImpl_Unacquire(LPDIRECTINPUTDEVICE2A iface)
832 {
833         ICOM_THIS(SysKeyboardAImpl,iface);
834         TRACE("(this=%p)\n",This);
835
836         if (This->acquired == 1) {
837           /* Restore the original configuration */
838           KEYBOARD_Driver->pSetKeyboardConfig(&(This->initial_config), 0xFFFFFFFF);
839           This->acquired = 0;
840         } else {
841           ERR("Unacquiring a not-acquired device !!!\n");
842         }
843
844         return DI_OK;
845 }
846
847 /******************************************************************************
848   *     GetCapabilities : get the device capablitites
849   */
850 static HRESULT WINAPI SysKeyboardAImpl_GetCapabilities(
851         LPDIRECTINPUTDEVICE2A iface,
852         LPDIDEVCAPS lpDIDevCaps)
853 {
854   ICOM_THIS(SysMouseAImpl,iface);
855
856   TRACE("(this=%p,%p)\n",This,lpDIDevCaps);
857
858   if (lpDIDevCaps->dwSize == sizeof(DIDEVCAPS)) {
859     lpDIDevCaps->dwFlags = DIDC_ATTACHED;
860     lpDIDevCaps->dwDevType = DIDEVTYPE_KEYBOARD;
861     lpDIDevCaps->dwAxes = 0;
862     lpDIDevCaps->dwButtons = 0;
863     lpDIDevCaps->dwPOVs = 0;
864     lpDIDevCaps->dwFFSamplePeriod = 0;
865     lpDIDevCaps->dwFFMinTimeResolution = 0;
866     lpDIDevCaps->dwFirmwareRevision = 100;
867     lpDIDevCaps->dwHardwareRevision = 100;
868     lpDIDevCaps->dwFFDriverVersion = 0;
869   } else {
870     /* DirectX 3.0 */
871     FIXME("DirectX 3.0 not supported....\n");
872   }
873   
874   return DI_OK;
875 }
876
877 static HRESULT WINAPI IDirectInputDevice2AImpl_QueryInterface(
878         LPDIRECTINPUTDEVICE2A iface,REFIID riid,LPVOID *ppobj
879 )
880 {
881         ICOM_THIS(IDirectInputDevice2AImpl,iface);
882
883         TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(riid),ppobj);
884         if (IsEqualGUID(&IID_IUnknown,riid)) {
885                 IDirectInputDevice2_AddRef(iface);
886                 *ppobj = This;
887                 return 0;
888         }
889         if (IsEqualGUID(&IID_IDirectInputDeviceA,riid)) {
890                 IDirectInputDevice2_AddRef(iface);
891                 *ppobj = This;
892                 return 0;
893         }
894         if (IsEqualGUID(&IID_IDirectInputDevice2A,riid)) {
895                 IDirectInputDevice2_AddRef(iface);
896                 *ppobj = This;
897                 return 0;
898         }
899         TRACE("Unsupported interface !\n");
900         return E_FAIL;
901 }
902
903 static ULONG WINAPI IDirectInputDevice2AImpl_AddRef(
904         LPDIRECTINPUTDEVICE2A iface)
905 {
906         ICOM_THIS(IDirectInputDevice2AImpl,iface);
907         return ++This->ref;
908 }
909
910 static HRESULT WINAPI IDirectInputDevice2AImpl_EnumObjects(
911         LPDIRECTINPUTDEVICE2A iface,
912         LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback,
913         LPVOID lpvRef,
914         DWORD dwFlags)
915 {
916         FIXME("(this=%p,%p,%p,%08lx): stub!\n", iface, lpCallback, lpvRef, dwFlags);
917         if (TRACE_ON(dinput)) {
918           DPRINTF("  - flags = ");
919           _dump_EnumObjects_flags(dwFlags);
920           DPRINTF("\n");
921         }
922         
923         return DI_OK;
924 }
925         
926 static HRESULT WINAPI IDirectInputDevice2AImpl_GetProperty(
927         LPDIRECTINPUTDEVICE2A iface,
928         REFGUID rguid,
929         LPDIPROPHEADER pdiph)
930 {
931         FIXME("(this=%p,%s,%p): stub!\n",
932               iface, debugstr_guid(rguid), pdiph);
933         
934         if (TRACE_ON(dinput))
935           _dump_DIPROPHEADER(pdiph);
936         
937         return DI_OK;
938 }
939
940 static HRESULT WINAPI IDirectInputDevice2AImpl_GetObjectInfo(
941         LPDIRECTINPUTDEVICE2A iface,
942         LPDIDEVICEOBJECTINSTANCEA pdidoi,
943         DWORD dwObj,
944         DWORD dwHow)
945 {
946         FIXME("(this=%p,%p,%ld,0x%08lx): stub!\n",
947               iface, pdidoi, dwObj, dwHow);
948         
949         return DI_OK;
950 }
951         
952 static HRESULT WINAPI IDirectInputDevice2AImpl_GetDeviceInfo(
953         LPDIRECTINPUTDEVICE2A iface,
954         LPDIDEVICEINSTANCEA pdidi)
955 {
956         FIXME("(this=%p,%p): stub!\n",
957               iface, pdidi);
958         
959         return DI_OK;
960 }
961         
962 static HRESULT WINAPI IDirectInputDevice2AImpl_RunControlPanel(
963         LPDIRECTINPUTDEVICE2A iface,
964         HWND hwndOwner,
965         DWORD dwFlags)
966 {
967   FIXME("(this=%p,0x%08x,0x%08lx): stub!\n",
968         iface, hwndOwner, dwFlags);
969         
970         return DI_OK;
971 }
972         
973 static HRESULT WINAPI IDirectInputDevice2AImpl_Initialize(
974         LPDIRECTINPUTDEVICE2A iface,
975         HINSTANCE hinst,
976         DWORD dwVersion,
977         REFGUID rguid)
978 {
979         FIXME("(this=%p,%d,%ld,%s): stub!\n",
980               iface, hinst, dwVersion, debugstr_guid(rguid));
981         return DI_OK;
982 }
983         
984 /******************************************************************************
985  *      IDirectInputDevice2A
986  */
987
988 static HRESULT WINAPI IDirectInputDevice2AImpl_CreateEffect(
989         LPDIRECTINPUTDEVICE2A iface,
990         REFGUID rguid,
991         LPCDIEFFECT lpeff,
992         LPDIRECTINPUTEFFECT *ppdef,
993         LPUNKNOWN pUnkOuter)
994 {
995         FIXME("(this=%p,%s,%p,%p,%p): stub!\n",
996               iface, debugstr_guid(rguid), lpeff, ppdef, pUnkOuter);
997         return DI_OK;
998 }
999
1000 static HRESULT WINAPI IDirectInputDevice2AImpl_EnumEffects(
1001         LPDIRECTINPUTDEVICE2A iface,
1002         LPDIENUMEFFECTSCALLBACKA lpCallback,
1003         LPVOID lpvRef,
1004         DWORD dwFlags)
1005 {
1006         FIXME("(this=%p,%p,%p,0x%08lx): stub!\n",
1007               iface, lpCallback, lpvRef, dwFlags);
1008         
1009         if (lpCallback)
1010                 lpCallback(NULL, lpvRef);
1011         return DI_OK;
1012 }
1013
1014 static HRESULT WINAPI IDirectInputDevice2AImpl_GetEffectInfo(
1015         LPDIRECTINPUTDEVICE2A iface,
1016         LPDIEFFECTINFOA lpdei,
1017         REFGUID rguid)
1018 {
1019         FIXME("(this=%p,%p,%s): stub!\n",
1020               iface, lpdei, debugstr_guid(rguid));
1021         return DI_OK;
1022 }
1023
1024 static HRESULT WINAPI IDirectInputDevice2AImpl_GetForceFeedbackState(
1025         LPDIRECTINPUTDEVICE2A iface,
1026         LPDWORD pdwOut)
1027 {
1028         FIXME("(this=%p,%p): stub!\n",
1029               iface, pdwOut);
1030         return DI_OK;
1031 }
1032
1033 static HRESULT WINAPI IDirectInputDevice2AImpl_SendForceFeedbackCommand(
1034         LPDIRECTINPUTDEVICE2A iface,
1035         DWORD dwFlags)
1036 {
1037         FIXME("(this=%p,0x%08lx): stub!\n",
1038               iface, dwFlags);
1039         return DI_OK;
1040 }
1041
1042 static HRESULT WINAPI IDirectInputDevice2AImpl_EnumCreatedEffectObjects(
1043         LPDIRECTINPUTDEVICE2A iface,
1044         LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback,
1045         LPVOID lpvRef,
1046         DWORD dwFlags)
1047 {
1048         FIXME("(this=%p,%p,%p,0x%08lx): stub!\n",
1049               iface, lpCallback, lpvRef, dwFlags);
1050         if (lpCallback)
1051                 lpCallback(NULL, lpvRef);
1052         return DI_OK;
1053 }
1054
1055 static HRESULT WINAPI IDirectInputDevice2AImpl_Escape(
1056         LPDIRECTINPUTDEVICE2A iface,
1057         LPDIEFFESCAPE lpDIEEsc)
1058 {
1059         FIXME("(this=%p,%p): stub!\n",
1060               iface, lpDIEEsc);
1061         return DI_OK;
1062 }
1063
1064 static HRESULT WINAPI IDirectInputDevice2AImpl_Poll(
1065         LPDIRECTINPUTDEVICE2A iface)
1066 {
1067         FIXME("(this=%p): stub!\n",
1068               iface);
1069         return DI_OK;
1070 }
1071
1072 static HRESULT WINAPI IDirectInputDevice2AImpl_SendDeviceData(
1073         LPDIRECTINPUTDEVICE2A iface,
1074         DWORD cbObjectData,
1075         LPDIDEVICEOBJECTDATA rgdod,
1076         LPDWORD pdwInOut,
1077         DWORD dwFlags)
1078 {
1079         FIXME("(this=%p,0x%08lx,%p,%p,0x%08lx): stub!\n",
1080               iface, cbObjectData, rgdod, pdwInOut, dwFlags);
1081         
1082         return DI_OK;
1083 }
1084
1085 /******************************************************************************
1086  *      SysMouseA (DInput Mouse support)
1087  */
1088
1089 /******************************************************************************
1090   *     Release : release the mouse buffer.
1091   */
1092 static ULONG WINAPI SysMouseAImpl_Release(LPDIRECTINPUTDEVICE2A iface)
1093 {
1094         ICOM_THIS(SysMouseAImpl,iface);
1095
1096         This->ref--;
1097         if (This->ref)
1098                 return This->ref;
1099
1100         /* Free the data queue */
1101         if (This->data_queue != NULL)
1102           HeapFree(GetProcessHeap(),0,This->data_queue);
1103
1104         /* Install the previous event handler (in case of releasing an aquired
1105            mouse device) */
1106         if (This->prev_handler != NULL)
1107           MOUSE_Enable(This->prev_handler);
1108         DeleteCriticalSection(&(This->crit));
1109
1110         /* Free the DataFormat */
1111         if (This->df != &(Wine_InternalMouseFormat)) {
1112           HeapFree(GetProcessHeap(), 0, This->df->rgodf);
1113           HeapFree(GetProcessHeap(), 0, This->df);
1114         }
1115         
1116         HeapFree(GetProcessHeap(),0,This);
1117         return 0;
1118 }
1119
1120
1121 /******************************************************************************
1122   *     SetCooperativeLevel : store the window in which we will do our
1123   *   grabbing.
1124   */
1125 static HRESULT WINAPI SysMouseAImpl_SetCooperativeLevel(
1126         LPDIRECTINPUTDEVICE2A iface,HWND hwnd,DWORD dwflags
1127 )
1128 {
1129   ICOM_THIS(SysMouseAImpl,iface);
1130
1131   TRACE("(this=%p,0x%08lx,0x%08lx)\n",This,(DWORD)hwnd,dwflags);
1132
1133   if (TRACE_ON(dinput))
1134     _dump_cooperativelevel(dwflags);
1135
1136   /* Store the window which asks for the mouse */
1137   This->win = hwnd;
1138   
1139   return 0;
1140 }
1141
1142
1143 /******************************************************************************
1144   *     SetDataFormat : the application can choose the format of the data
1145   *   the device driver sends back with GetDeviceState.
1146   *
1147   *   For the moment, only the "standard" configuration (c_dfDIMouse) is supported
1148   *   in absolute and relative mode.
1149   */
1150 static HRESULT WINAPI SysMouseAImpl_SetDataFormat(
1151         LPDIRECTINPUTDEVICE2A iface,LPCDIDATAFORMAT df
1152 )
1153 {
1154   ICOM_THIS(SysMouseAImpl,iface);
1155   int i;
1156   
1157   TRACE("(this=%p,%p)\n",This,df);
1158
1159   TRACE("(df.dwSize=%ld)\n",df->dwSize);
1160   TRACE("(df.dwObjsize=%ld)\n",df->dwObjSize);
1161   TRACE("(df.dwFlags=0x%08lx)\n",df->dwFlags);
1162   TRACE("(df.dwDataSize=%ld)\n",df->dwDataSize);
1163   TRACE("(df.dwNumObjs=%ld)\n",df->dwNumObjs);
1164
1165   for (i=0;i<df->dwNumObjs;i++) {
1166
1167     TRACE("df.rgodf[%d].guid %s (%p)\n",i, debugstr_guid(df->rgodf[i].pguid), df->rgodf[i].pguid);
1168     TRACE("df.rgodf[%d].dwOfs %ld\n",i,df->rgodf[i].dwOfs);
1169     TRACE("dwType 0x%02x,dwInstance %d\n",DIDFT_GETTYPE(df->rgodf[i].dwType),DIDFT_GETINSTANCE(df->rgodf[i].dwType));
1170     TRACE("df.rgodf[%d].dwFlags 0x%08lx\n",i,df->rgodf[i].dwFlags);
1171   }
1172
1173   /* Check if the mouse is in absolute or relative mode */
1174   if (df->dwFlags == DIDF_ABSAXIS)
1175     This->absolute = 1;
1176   else if (df->dwFlags == DIDF_RELAXIS)
1177     This->absolute = 0;
1178   else
1179     ERR("Neither absolute nor relative flag set.");
1180   
1181   /* Store the new data format */
1182   This->df = HeapAlloc(GetProcessHeap(),0,df->dwSize);
1183   memcpy(This->df, df, df->dwSize);
1184   This->df->rgodf = HeapAlloc(GetProcessHeap(),0,df->dwNumObjs*df->dwObjSize);
1185   memcpy(This->df->rgodf,df->rgodf,df->dwNumObjs*df->dwObjSize);
1186
1187   /* Prepare all the data-conversion filters */
1188   This->wine_df = create_DataFormat(&(Wine_InternalMouseFormat), df, This->offset_array);
1189   
1190   return 0;
1191 }
1192
1193 #define GEN_EVENT(offset,data,xtime,seq)                                                \
1194 {                                                                                       \
1195   if ((offset >= 0) && (This->queue_pos < This->queue_len)) {                           \
1196     This->data_queue[This->queue_pos].dwOfs = offset;                                   \
1197     This->data_queue[This->queue_pos].dwData = data;                                    \
1198     This->data_queue[This->queue_pos].dwTimeStamp = xtime;                              \
1199     This->data_queue[This->queue_pos].dwSequence = seq;                                 \
1200     This->queue_pos++;                                                                  \
1201   }                                                                                     \
1202 }
1203
1204   
1205 /* Our private mouse event handler */
1206 static void WINAPI dinput_mouse_event( DWORD dwFlags, DWORD dx, DWORD dy,
1207                                       DWORD cButtons, DWORD dwExtraInfo )
1208 {
1209   DWORD posX, posY, keyState, xtime, extra;
1210   SysMouseAImpl* This = (SysMouseAImpl*) current_lock;
1211   
1212   EnterCriticalSection(&(This->crit));
1213   /* Mouse moved -> send event if asked */
1214   if (This->hEvent)
1215     SetEvent(This->hEvent);
1216   
1217   if (   !IsBadReadPtr( (LPVOID)dwExtraInfo, sizeof(WINE_MOUSEEVENT) )
1218       && ((WINE_MOUSEEVENT *)dwExtraInfo)->magic == WINE_MOUSEEVENT_MAGIC ) {
1219     WINE_MOUSEEVENT *wme = (WINE_MOUSEEVENT *)dwExtraInfo;
1220     keyState = wme->keyState;
1221     xtime = wme->time;
1222     extra = (DWORD)wme->hWnd;
1223     
1224     if ((dwFlags & MOUSEEVENTF_MOVE) &&
1225         (dwFlags & MOUSEEVENTF_ABSOLUTE)) {
1226       posX = (dx * GetSystemMetrics(SM_CXSCREEN)) >> 16;
1227       posY = (dy * GetSystemMetrics(SM_CYSCREEN)) >> 16;
1228     } else {
1229       posX = This->prevX;
1230       posY = This->prevY;
1231     }
1232   } else {
1233     ERR("Mouse event not supported...\n");
1234     LeaveCriticalSection(&(This->crit));
1235     return ;
1236   }
1237
1238   TRACE(" %ld %ld ", posX, posY);
1239
1240   if ( dwFlags & MOUSEEVENTF_MOVE ) {
1241     if (This->absolute) {
1242       if (posX != This->prevX)
1243         GEN_EVENT(This->offset_array[WINE_MOUSE_X_POSITION], posX, xtime, 0);
1244       if (posY != This->prevY)
1245         GEN_EVENT(This->offset_array[WINE_MOUSE_Y_POSITION], posY, xtime, 0);
1246     } else {
1247       /* Relative mouse input : the real fun starts here... */
1248       if (This->need_warp) {
1249         if (posX != This->prevX)
1250           GEN_EVENT(This->offset_array[WINE_MOUSE_X_POSITION], posX - This->prevX, xtime, evsequence++);
1251         if (posY != This->prevY)
1252           GEN_EVENT(This->offset_array[WINE_MOUSE_Y_POSITION], posY - This->prevY, xtime, evsequence++);
1253       } else {
1254         /* This is the first time the event handler has been called after a
1255            GetData of GetState. */
1256         if (posX != This->win_centerX) {
1257           GEN_EVENT(This->offset_array[WINE_MOUSE_X_POSITION], posX - This->win_centerX, xtime, evsequence++);
1258           This->need_warp = 1;
1259         }
1260           
1261         if (posY != This->win_centerY) {
1262           GEN_EVENT(This->offset_array[WINE_MOUSE_Y_POSITION], posY - This->win_centerY, xtime, evsequence++);
1263           This->need_warp = 1;
1264         }
1265       }
1266     }
1267   }
1268   if ( dwFlags & MOUSEEVENTF_LEFTDOWN ) {
1269     if (TRACE_ON(dinput))
1270       DPRINTF(" LD ");
1271
1272     GEN_EVENT(This->offset_array[WINE_MOUSE_L_POSITION], 0xFF, xtime, evsequence++);
1273     This->m_state.rgbButtons[0] = 0xFF;
1274   }
1275   if ( dwFlags & MOUSEEVENTF_LEFTUP ) {
1276     if (TRACE_ON(dinput))
1277       DPRINTF(" LU ");
1278
1279     GEN_EVENT(This->offset_array[WINE_MOUSE_L_POSITION], 0x00, xtime, evsequence++);
1280     This->m_state.rgbButtons[0] = 0x00;
1281   }
1282   if ( dwFlags & MOUSEEVENTF_RIGHTDOWN ) {
1283     if (TRACE_ON(dinput))
1284       DPRINTF(" RD ");
1285
1286     GEN_EVENT(This->offset_array[WINE_MOUSE_R_POSITION], 0xFF, xtime, evsequence++);
1287     This->m_state.rgbButtons[1] = 0xFF;
1288   }
1289   if ( dwFlags & MOUSEEVENTF_RIGHTUP ) {
1290     if (TRACE_ON(dinput))
1291       DPRINTF(" RU ");
1292
1293     GEN_EVENT(This->offset_array[WINE_MOUSE_R_POSITION], 0x00, xtime, evsequence++);
1294     This->m_state.rgbButtons[1] = 0x00;
1295   }
1296   if ( dwFlags & MOUSEEVENTF_MIDDLEDOWN ) {
1297     if (TRACE_ON(dinput))
1298       DPRINTF(" MD ");
1299
1300     GEN_EVENT(This->offset_array[WINE_MOUSE_M_POSITION], 0xFF, xtime, evsequence++);
1301     This->m_state.rgbButtons[2] = 0xFF;
1302   }
1303   if ( dwFlags & MOUSEEVENTF_MIDDLEUP ) {
1304     if (TRACE_ON(dinput))
1305       DPRINTF(" MU ");
1306
1307     GEN_EVENT(This->offset_array[WINE_MOUSE_M_POSITION], 0x00, xtime, evsequence++);
1308     This->m_state.rgbButtons[2] = 0x00;
1309   }
1310   if (TRACE_ON(dinput))
1311     DPRINTF("\n");
1312   
1313   This->prevX = posX;
1314   This->prevY = posY;
1315
1316   if (This->absolute) {
1317     This->m_state.lX = posX;
1318     This->m_state.lY = posY;
1319   } else {
1320     This->m_state.lX = posX - This->win_centerX;
1321     This->m_state.lY = posY - This->win_centerY;
1322   }
1323   
1324   LeaveCriticalSection(&(This->crit));
1325
1326 }
1327
1328
1329 /******************************************************************************
1330   *     Acquire : gets exclusive control of the mouse
1331   */
1332 static HRESULT WINAPI SysMouseAImpl_Acquire(LPDIRECTINPUTDEVICE2A iface)
1333 {
1334   ICOM_THIS(SysMouseAImpl,iface);
1335   RECT  rect;
1336   
1337   TRACE("(this=%p)\n",This);
1338
1339   if (This->acquired == 0) {
1340     POINT       point;
1341     
1342     /* This stores the current mouse handler. */
1343     This->prev_handler = mouse_event;
1344     
1345     /* Store (in a global variable) the current lock */
1346     current_lock = (IDirectInputDevice2A*)This;
1347
1348     /* Init the mouse state */
1349     This->m_state.lX = PosX;
1350     This->m_state.lY = PosY;
1351     This->m_state.rgbButtons[0] = (MouseButtonsStates[0] ? 0xFF : 0x00);
1352     This->m_state.rgbButtons[1] = (MouseButtonsStates[1] ? 0xFF : 0x00);
1353     This->m_state.rgbButtons[2] = (MouseButtonsStates[2] ? 0xFF : 0x00);
1354
1355     /* Install our own mouse event handler */
1356     MOUSE_Enable(dinput_mouse_event);
1357     
1358     /* Get the window dimension and find the center */
1359     GetWindowRect(This->win, &rect);
1360     This->win_centerX = (rect.right  - rect.left) / 2;
1361     This->win_centerY = (rect.bottom - rect.top ) / 2;
1362
1363     /* Warp the mouse to the center of the window */
1364     TRACE("Warping mouse to %ld - %ld\n", This->win_centerX, This->win_centerY);
1365     point.x = This->win_centerX;
1366     point.y = This->win_centerY;
1367     MapWindowPoints(This->win, HWND_DESKTOP, &point, 1);
1368     DISPLAY_MoveCursor(point.x, point.y);
1369
1370     This->acquired = 1;
1371   }
1372   return 0;
1373 }
1374
1375 /******************************************************************************
1376   *     Unacquire : frees the mouse
1377   */
1378 static HRESULT WINAPI SysMouseAImpl_Unacquire(LPDIRECTINPUTDEVICE2A iface)
1379 {
1380   ICOM_THIS(SysMouseAImpl,iface);
1381
1382   TRACE("(this=%p)\n",This);
1383
1384   /* Reinstall previous mouse event handler */
1385   MOUSE_Enable(This->prev_handler);
1386   This->prev_handler = NULL;
1387   
1388   /* No more locks */
1389   current_lock = NULL;
1390
1391   /* Unacquire device */
1392   This->acquired = 0;
1393   
1394   return 0;
1395 }
1396
1397 /******************************************************************************
1398   *     GetDeviceState : returns the "state" of the mouse.
1399   *
1400   *   For the moment, only the "standard" return structure (DIMOUSESTATE) is
1401   *   supported.
1402   */
1403 static HRESULT WINAPI SysMouseAImpl_GetDeviceState(
1404         LPDIRECTINPUTDEVICE2A iface,DWORD len,LPVOID ptr
1405 ) {
1406   ICOM_THIS(SysMouseAImpl,iface);
1407   
1408   EnterCriticalSection(&(This->crit));
1409   TRACE("(this=%p,0x%08lx,%p): \n",This,len,ptr);
1410   
1411   /* Copy the current mouse state */
1412   fill_DataFormat(ptr, &(This->m_state), This->wine_df);
1413   
1414   /* Check if we need to do a mouse warping */
1415   if (This->need_warp) {
1416     POINT point;
1417
1418     TRACE("Warping mouse to %ld - %ld\n", This->win_centerX, This->win_centerY);
1419     point.x = This->win_centerX;
1420     point.y = This->win_centerY;
1421     MapWindowPoints(This->win, HWND_DESKTOP, &point, 1);
1422     DISPLAY_MoveCursor(point.x, point.y);
1423
1424     This->need_warp = 0;
1425   }
1426
1427   LeaveCriticalSection(&(This->crit));
1428   
1429   TRACE("(X: %ld - Y: %ld   L: %02x M: %02x R: %02x)\n",
1430         This->m_state.lX, This->m_state.lY,
1431         This->m_state.rgbButtons[0], This->m_state.rgbButtons[2], This->m_state.rgbButtons[1]);
1432   
1433   return 0;
1434 }
1435
1436 /******************************************************************************
1437   *     GetDeviceState : gets buffered input data.
1438   */
1439 static HRESULT WINAPI SysMouseAImpl_GetDeviceData(LPDIRECTINPUTDEVICE2A iface,
1440                                               DWORD dodsize,
1441                                               LPDIDEVICEOBJECTDATA dod,
1442                                               LPDWORD entries,
1443                                               DWORD flags
1444 ) {
1445   ICOM_THIS(SysMouseAImpl,iface);
1446   
1447   EnterCriticalSection(&(This->crit));
1448   TRACE("(%p)->(dods=%ld,entries=%ld,fl=0x%08lx)\n",This,dodsize,*entries,flags);
1449
1450   if (flags & DIGDD_PEEK)
1451     FIXME("DIGDD_PEEK\n");
1452
1453   if (dod == NULL) {
1454     *entries = This->queue_pos;
1455     This->queue_pos = 0;
1456   } else {
1457     /* Check for buffer overflow */
1458     if (This->queue_pos > *entries) {
1459       WARN("Buffer overflow not handled properly yet...\n");
1460       This->queue_pos = *entries;
1461     }
1462     if (dodsize != sizeof(DIDEVICEOBJECTDATA)) {
1463       ERR("Wrong structure size !\n");
1464       LeaveCriticalSection(&(This->crit));
1465       return DIERR_INVALIDPARAM;
1466     }
1467
1468     if (This->queue_pos)
1469         TRACE("Application retrieving %d event(s).\n", This->queue_pos); 
1470     
1471     /* Copy the buffered data into the application queue */
1472     memcpy(dod, This->data_queue, This->queue_pos * dodsize);
1473     *entries = This->queue_pos;
1474
1475     /* Reset the event queue */
1476     This->queue_pos = 0;
1477   }
1478   LeaveCriticalSection(&(This->crit));
1479   
1480 #if 0 /* FIXME: seems to create motion events, which fire back at us. */
1481   /* Check if we need to do a mouse warping */
1482   if (This->need_warp) {
1483     POINT point;
1484
1485     TRACE("Warping mouse to %ld - %ld\n", This->win_centerX, This->win_centerY);
1486     point.x = This->win_centerX;
1487     point.y = This->win_centerY;
1488     MapWindowPoints(This->win, HWND_DESKTOP, &point, 1);
1489
1490     DISPLAY_MoveCursor(point.x, point.y);
1491
1492     This->need_warp = 0;
1493   }
1494 #endif
1495   return 0;
1496 }
1497
1498 /******************************************************************************
1499   *     SetProperty : change input device properties
1500   */
1501 static HRESULT WINAPI SysMouseAImpl_SetProperty(LPDIRECTINPUTDEVICE2A iface,
1502                                             REFGUID rguid,
1503                                             LPCDIPROPHEADER ph)
1504 {
1505   ICOM_THIS(SysMouseAImpl,iface);
1506
1507   TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(rguid),ph);
1508   
1509   if (!HIWORD(rguid)) {
1510     switch ((DWORD)rguid) {
1511     case (DWORD) DIPROP_BUFFERSIZE: {
1512       LPCDIPROPDWORD    pd = (LPCDIPROPDWORD)ph;
1513       
1514       TRACE("buffersize = %ld\n",pd->dwData);
1515
1516       This->data_queue = (LPDIDEVICEOBJECTDATA)HeapAlloc(GetProcessHeap(),0,
1517                                                           pd->dwData * sizeof(DIDEVICEOBJECTDATA));
1518       This->queue_pos  = 0;
1519       This->queue_len  = pd->dwData;
1520       break;
1521     }
1522     default:
1523       FIXME("Unknown type %ld (%s)\n",(DWORD)rguid,debugstr_guid(rguid));
1524       break;
1525     }
1526   }
1527   
1528   return 0;
1529 }
1530
1531 /******************************************************************************
1532   *     GetProperty : get input device properties
1533   */
1534 static HRESULT WINAPI SysMouseAImpl_GetProperty(LPDIRECTINPUTDEVICE2A iface,
1535                                                 REFGUID rguid,
1536                                                 LPDIPROPHEADER pdiph)
1537 {
1538   ICOM_THIS(SysMouseAImpl,iface);
1539
1540   TRACE("(this=%p,%s,%p): stub!\n",
1541         iface, debugstr_guid(rguid), pdiph);
1542
1543   if (TRACE_ON(dinput))
1544     _dump_DIPROPHEADER(pdiph);
1545   
1546   if (!HIWORD(rguid)) {
1547     switch ((DWORD)rguid) {
1548     case (DWORD) DIPROP_BUFFERSIZE: {
1549       LPDIPROPDWORD     pd = (LPDIPROPDWORD)pdiph;
1550       
1551       TRACE(" return buffersize = %d\n",This->queue_len);
1552       pd->dwData = This->queue_len;
1553       break;
1554     }
1555
1556     case (DWORD) DIPROP_RANGE: {
1557       LPDIPROPRANGE pr = (LPDIPROPRANGE) pdiph;
1558
1559       if ((pdiph->dwHow == DIPH_BYID) &&
1560           ((pdiph->dwObj == (DIDFT_MAKEINSTANCE(WINE_MOUSE_X_AXIS_INSTANCE) | DIDFT_RELAXIS)) ||
1561            (pdiph->dwObj == (DIDFT_MAKEINSTANCE(WINE_MOUSE_Y_AXIS_INSTANCE) | DIDFT_RELAXIS)))) {
1562         /* Querying the range of either the X or the Y axis.  As I do
1563            not know the range, do as if the range where
1564            unrestricted...*/
1565         pr->lMin = DIPROPRANGE_NOMIN;
1566         pr->lMax = DIPROPRANGE_NOMAX;
1567       }
1568       
1569       break;
1570     }
1571       
1572     default:
1573       FIXME("Unknown type %ld (%s)\n",(DWORD)rguid,debugstr_guid(rguid));
1574       break;
1575     }
1576   }
1577   
1578   
1579   return DI_OK;
1580 }
1581
1582
1583
1584 /******************************************************************************
1585   *     SetEventNotification : specifies event to be sent on state change
1586   */
1587 static HRESULT WINAPI SysMouseAImpl_SetEventNotification(LPDIRECTINPUTDEVICE2A iface,
1588                                                          HANDLE hnd) {
1589   ICOM_THIS(SysMouseAImpl,iface);
1590
1591   TRACE("(this=%p,0x%08lx)\n",This,(DWORD)hnd);
1592
1593   This->hEvent = hnd;
1594
1595   return DI_OK;
1596 }
1597
1598 /******************************************************************************
1599   *     GetCapabilities : get the device capablitites
1600   */
1601 static HRESULT WINAPI SysMouseAImpl_GetCapabilities(
1602         LPDIRECTINPUTDEVICE2A iface,
1603         LPDIDEVCAPS lpDIDevCaps)
1604 {
1605   ICOM_THIS(SysMouseAImpl,iface);
1606
1607   TRACE("(this=%p,%p)\n",This,lpDIDevCaps);
1608
1609   if (lpDIDevCaps->dwSize == sizeof(DIDEVCAPS)) {
1610     lpDIDevCaps->dwFlags = DIDC_ATTACHED;
1611     lpDIDevCaps->dwDevType = DIDEVTYPE_MOUSE;
1612     lpDIDevCaps->dwAxes = 2;
1613     lpDIDevCaps->dwButtons = 3;
1614     lpDIDevCaps->dwPOVs = 0;
1615     lpDIDevCaps->dwFFSamplePeriod = 0;
1616     lpDIDevCaps->dwFFMinTimeResolution = 0;
1617     lpDIDevCaps->dwFirmwareRevision = 100;
1618     lpDIDevCaps->dwHardwareRevision = 100;
1619     lpDIDevCaps->dwFFDriverVersion = 0;
1620   } else {
1621     /* DirectX 3.0 */
1622     FIXME("DirectX 3.0 not supported....\n");
1623   }
1624   
1625   return DI_OK;
1626 }
1627
1628
1629 /******************************************************************************
1630   *     EnumObjects : enumerate the different buttons and axis...
1631   */
1632 static HRESULT WINAPI SysMouseAImpl_EnumObjects(
1633         LPDIRECTINPUTDEVICE2A iface,
1634         LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback,
1635         LPVOID lpvRef,
1636         DWORD dwFlags)
1637 {
1638   ICOM_THIS(SysMouseAImpl,iface);
1639   DIDEVICEOBJECTINSTANCE ddoi;
1640   
1641   TRACE("(this=%p,%p,%p,%08lx)\n", This, lpCallback, lpvRef, dwFlags);
1642   if (TRACE_ON(dinput)) {
1643     DPRINTF("  - flags = ");
1644     _dump_EnumObjects_flags(dwFlags);
1645     DPRINTF("\n");
1646   }
1647
1648   /* Only the fields till dwFFMaxForce are relevant */
1649   ddoi.dwSize = FIELD_OFFSET(DIDEVICEOBJECTINSTANCE, dwFFMaxForce);
1650     
1651   /* In a mouse, we have : two relative axis and three buttons */
1652   if ((dwFlags == DIDFT_ALL) ||
1653       (dwFlags & DIDFT_AXIS)) {
1654     /* X axis */
1655     ddoi.guidType = GUID_XAxis;
1656     ddoi.dwOfs = This->offset_array[WINE_MOUSE_X_POSITION];
1657     ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_X_AXIS_INSTANCE) | DIDFT_RELAXIS;
1658     strcpy(ddoi.tszName, "X-Axis");
1659     _dump_OBJECTINSTANCE(&ddoi);
1660     if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
1661     
1662     /* Y axis */
1663     ddoi.guidType = GUID_YAxis;
1664     ddoi.dwOfs = This->offset_array[WINE_MOUSE_Y_POSITION];
1665     ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_Y_AXIS_INSTANCE) | DIDFT_RELAXIS;
1666     strcpy(ddoi.tszName, "Y-Axis");
1667     _dump_OBJECTINSTANCE(&ddoi);
1668     if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
1669   }
1670
1671   if ((dwFlags == DIDFT_ALL) ||
1672       (dwFlags & DIDFT_BUTTON)) {
1673     ddoi.guidType = GUID_Button;
1674
1675     /* Left button */
1676     ddoi.dwOfs = This->offset_array[WINE_MOUSE_L_POSITION];
1677     ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_L_BUTTON_INSTANCE) | DIDFT_PSHBUTTON;
1678     strcpy(ddoi.tszName, "Left-Button");
1679     _dump_OBJECTINSTANCE(&ddoi);
1680     if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
1681
1682     /* Right button */
1683     ddoi.dwOfs = This->offset_array[WINE_MOUSE_R_POSITION];
1684     ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_R_BUTTON_INSTANCE) | DIDFT_PSHBUTTON;
1685     strcpy(ddoi.tszName, "Right-Button");
1686     _dump_OBJECTINSTANCE(&ddoi);
1687     if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
1688
1689     /* Middle button */
1690     ddoi.dwOfs = This->offset_array[WINE_MOUSE_M_POSITION];
1691     ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_M_BUTTON_INSTANCE) | DIDFT_PSHBUTTON;
1692     strcpy(ddoi.tszName, "Middle-Button");
1693     _dump_OBJECTINSTANCE(&ddoi);
1694     if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
1695   }
1696
1697   return DI_OK;
1698 }
1699         
1700
1701
1702 #ifdef HAVE_LINUX_22_JOYSTICK_API
1703 /******************************************************************************
1704  *      Joystick
1705  */
1706 static ULONG WINAPI JoystickAImpl_Release(LPDIRECTINPUTDEVICE2A iface)
1707 {
1708         ICOM_THIS(JoystickAImpl,iface);
1709
1710         This->ref--;
1711         if (This->ref)
1712                 return This->ref;
1713
1714         /* Free the data queue */
1715         if (This->data_queue != NULL)
1716           HeapFree(GetProcessHeap(),0,This->data_queue);
1717         
1718         /* Free the DataFormat */
1719         HeapFree(GetProcessHeap(), 0, This->df);
1720         
1721         HeapFree(GetProcessHeap(),0,This);
1722         return 0;
1723 }
1724
1725 /******************************************************************************
1726   *   SetDataFormat : the application can choose the format of the data
1727   *   the device driver sends back with GetDeviceState.
1728   */
1729 static HRESULT WINAPI JoystickAImpl_SetDataFormat(
1730         LPDIRECTINPUTDEVICE2A iface,LPCDIDATAFORMAT df
1731 )
1732 {
1733   ICOM_THIS(JoystickAImpl,iface);
1734   int i;
1735   
1736   TRACE("(this=%p,%p)\n",This,df);
1737
1738   TRACE("(df.dwSize=%ld)\n",df->dwSize);
1739   TRACE("(df.dwObjsize=%ld)\n",df->dwObjSize);
1740   TRACE("(df.dwFlags=0x%08lx)\n",df->dwFlags);
1741   TRACE("(df.dwDataSize=%ld)\n",df->dwDataSize);
1742   TRACE("(df.dwNumObjs=%ld)\n",df->dwNumObjs);
1743
1744   for (i=0;i<df->dwNumObjs;i++) {
1745     TRACE("df.rgodf[%d].guid %s (%p)\n",i,debugstr_guid(df->rgodf[i].pguid), df->rgodf[i].pguid);
1746     TRACE("df.rgodf[%d].dwOfs %ld\n",i,df->rgodf[i].dwOfs);
1747     TRACE("dwType 0x%02x,dwInstance %d\n",DIDFT_GETTYPE(df->rgodf[i].dwType),DIDFT_GETINSTANCE(df->rgodf[i].dwType));
1748     TRACE("df.rgodf[%d].dwFlags 0x%08lx\n",i,df->rgodf[i].dwFlags);
1749   }
1750   
1751   /* Store the new data format */
1752   This->df = HeapAlloc(GetProcessHeap(),0,df->dwSize);
1753   memcpy(This->df, df, df->dwSize);
1754   This->df->rgodf = HeapAlloc(GetProcessHeap(),0,df->dwNumObjs*df->dwObjSize);
1755   memcpy(This->df->rgodf,df->rgodf,df->dwNumObjs*df->dwObjSize);
1756   
1757   return 0;
1758 }
1759
1760 /******************************************************************************
1761   *     Acquire : gets exclusive control of the joystick
1762   */
1763 static HRESULT WINAPI JoystickAImpl_Acquire(LPDIRECTINPUTDEVICE2A iface)
1764 {
1765     ICOM_THIS(JoystickAImpl,iface);
1766   
1767     TRACE("(this=%p)\n",This);
1768     if (This->joyfd!=-1)
1769         return 0;
1770     This->joyfd=open(JOYDEV,O_RDONLY);
1771     if (This->joyfd==-1)
1772         return DIERR_NOTFOUND;
1773     return 0;
1774 }
1775
1776 /******************************************************************************
1777   *     Unacquire : frees the joystick
1778   */
1779 static HRESULT WINAPI JoystickAImpl_Unacquire(LPDIRECTINPUTDEVICE2A iface)
1780 {
1781     ICOM_THIS(JoystickAImpl,iface);
1782
1783     TRACE("(this=%p)\n",This);
1784     if (This->joyfd!=-1) {
1785         close(This->joyfd);
1786         This->joyfd = -1;
1787     }
1788     return 0;
1789 }
1790
1791 #define map_axis(val) ((val+32768)*(This->lMax-This->lMin)/65536+This->lMin)
1792
1793 static void joy_polldev(JoystickAImpl *This) {
1794     struct timeval tv;
1795     fd_set      readfds;
1796     struct      js_event jse;
1797
1798     if (This->joyfd==-1)
1799         return;
1800     while (1) {
1801         memset(&tv,0,sizeof(tv));
1802         FD_ZERO(&readfds);FD_SET(This->joyfd,&readfds);
1803         if (1>select(This->joyfd+1,&readfds,NULL,NULL,&tv))
1804             return;
1805         /* we have one event, so we can read */
1806         if (sizeof(jse)!=read(This->joyfd,&jse,sizeof(jse))) {
1807             return;
1808         }
1809         TRACE("js_event: type 0x%x, number %d, value %d\n",jse.type,jse.number,jse.value);
1810         if (jse.type & JS_EVENT_BUTTON) {
1811             GEN_EVENT(DIJOFS_BUTTON(jse.number),jse.value?0x80:0x00,jse.time,evsequence++);
1812             This->js.rgbButtons[jse.number] = jse.value?0x80:0x00;
1813         }
1814         if (jse.type & JS_EVENT_AXIS) {
1815             switch (jse.number) {
1816             case 0:
1817                 GEN_EVENT(jse.number*4,jse.value,jse.time,evsequence++);
1818                 This->js.lX = map_axis(jse.value);
1819                 break;
1820             case 1:
1821                 GEN_EVENT(jse.number*4,jse.value,jse.time,evsequence++);
1822                 This->js.lY = map_axis(jse.value);
1823                 break;
1824             case 2:
1825                 GEN_EVENT(jse.number*4,jse.value,jse.time,evsequence++);
1826                 This->js.lZ = map_axis(jse.value);
1827                 break;
1828             default:
1829                 FIXME("more then 3 axes (%d) not handled!\n",jse.number);
1830                 break;
1831             }
1832         }
1833     }
1834 }
1835
1836 /******************************************************************************
1837   *     GetDeviceState : returns the "state" of the joystick.
1838   *
1839   */
1840 static HRESULT WINAPI JoystickAImpl_GetDeviceState(
1841         LPDIRECTINPUTDEVICE2A iface,DWORD len,LPVOID ptr
1842 ) {
1843     ICOM_THIS(JoystickAImpl,iface);
1844   
1845     joy_polldev(This);
1846     TRACE("(this=%p,0x%08lx,%p)\n",This,len,ptr);
1847     if (len != sizeof(DIJOYSTATE)) {
1848         FIXME("len %ld is not sizeof(DIJOYSTATE), unsupported format.\n",len);
1849     }
1850     memcpy(ptr,&(This->js),len);
1851     This->queue_pos = 0;
1852     return 0;
1853 }
1854
1855 /******************************************************************************
1856   *     GetDeviceState : gets buffered input data.
1857   */
1858 static HRESULT WINAPI JoystickAImpl_GetDeviceData(LPDIRECTINPUTDEVICE2A iface,
1859                                               DWORD dodsize,
1860                                               LPDIDEVICEOBJECTDATA dod,
1861                                               LPDWORD entries,
1862                                               DWORD flags
1863 ) {
1864   ICOM_THIS(JoystickAImpl,iface);
1865   
1866   FIXME("(%p)->(dods=%ld,entries=%ld,fl=0x%08lx),STUB!\n",This,dodsize,*entries,flags);
1867
1868   joy_polldev(This);
1869   if (flags & DIGDD_PEEK)
1870     FIXME("DIGDD_PEEK\n");
1871
1872   if (dod == NULL) {
1873   } else {
1874   }
1875   return 0;
1876 }
1877
1878 /******************************************************************************
1879   *     SetProperty : change input device properties
1880   */
1881 static HRESULT WINAPI JoystickAImpl_SetProperty(LPDIRECTINPUTDEVICE2A iface,
1882                                             REFGUID rguid,
1883                                             LPCDIPROPHEADER ph)
1884 {
1885   ICOM_THIS(JoystickAImpl,iface);
1886
1887   FIXME("(this=%p,%s,%p)\n",This,debugstr_guid(rguid),ph);
1888   FIXME("ph.dwSize = %ld, ph.dwHeaderSize =%ld, ph.dwObj = %ld, ph.dwHow= %ld\n",ph->dwSize, ph->dwHeaderSize,ph->dwObj,ph->dwHow);
1889   
1890   if (!HIWORD(rguid)) {
1891     switch ((DWORD)rguid) {
1892     case (DWORD) DIPROP_BUFFERSIZE: {
1893       LPCDIPROPDWORD    pd = (LPCDIPROPDWORD)ph;
1894
1895       FIXME("buffersize = %ld\n",pd->dwData);
1896       break;
1897     }
1898     case (DWORD)DIPROP_RANGE: {
1899       LPCDIPROPRANGE    pr = (LPCDIPROPRANGE)ph;
1900
1901       FIXME("proprange(%ld,%ld)\n",pr->lMin,pr->lMax);
1902       This->lMin = pr->lMin;
1903       This->lMax = pr->lMax;
1904       break;
1905     }
1906     case (DWORD)DIPROP_DEADZONE: {
1907       LPCDIPROPDWORD    pd = (LPCDIPROPDWORD)ph;
1908
1909       FIXME("deadzone(%ld)\n",pd->dwData);
1910       This->deadzone = pd->dwData;
1911       break;
1912     }
1913     default:
1914       FIXME("Unknown type %ld (%s)\n",(DWORD)rguid,debugstr_guid(rguid));
1915       break;
1916     }
1917   }
1918   return 0;
1919 }
1920
1921 /******************************************************************************
1922   *     SetEventNotification : specifies event to be sent on state change
1923   */
1924 static HRESULT WINAPI JoystickAImpl_SetEventNotification(
1925         LPDIRECTINPUTDEVICE2A iface, HANDLE hnd
1926 ) {
1927     ICOM_THIS(JoystickAImpl,iface);
1928
1929     TRACE("(this=%p,0x%08lx)\n",This,(DWORD)hnd);
1930     This->hEvent = hnd;
1931     return DI_OK;
1932 }
1933
1934 static HRESULT WINAPI JoystickAImpl_GetCapabilities(
1935         LPDIRECTINPUTDEVICE2A iface,
1936         LPDIDEVCAPS lpDIDevCaps)
1937 {
1938     ICOM_THIS(JoystickAImpl,iface);
1939     BYTE        axes,buttons;
1940     int         xfd = This->joyfd;
1941
1942     TRACE("%p->(%p)\n",iface,lpDIDevCaps);
1943     if (xfd==-1)
1944         xfd = open(JOYDEV,O_RDONLY);
1945     lpDIDevCaps->dwFlags        = DIDC_ATTACHED;
1946     lpDIDevCaps->dwDevType      = DIDEVTYPE_JOYSTICK;
1947 #ifdef JSIOCGAXES
1948     if (-1==ioctl(xfd,JSIOCGAXES,&axes))
1949         axes = 2;
1950     lpDIDevCaps->dwAxes = axes;
1951 #endif
1952 #ifdef JSIOCGBUTTONS
1953     if (-1==ioctl(xfd,JSIOCGAXES,&buttons))
1954         buttons = 2;
1955     lpDIDevCaps->dwButtons = buttons;
1956 #endif
1957     if (xfd!=This->joyfd)
1958         close(xfd);
1959     return DI_OK;
1960 }
1961 static HRESULT WINAPI JoystickAImpl_Poll(LPDIRECTINPUTDEVICE2A iface) {
1962     ICOM_THIS(JoystickAImpl,iface);
1963     TRACE("(),stub!\n");
1964
1965     joy_polldev(This);
1966     return DI_OK;
1967 }
1968
1969 /******************************************************************************
1970   *     EnumObjects : enumerate the different buttons and axis...
1971   */
1972 static HRESULT WINAPI JoystickAImpl_EnumObjects(
1973         LPDIRECTINPUTDEVICE2A iface,
1974         LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback,
1975         LPVOID lpvRef,
1976         DWORD dwFlags)
1977 {
1978   ICOM_THIS(JoystickAImpl,iface);
1979   DIDEVICEOBJECTINSTANCE ddoi;
1980   int xfd = This->joyfd;
1981
1982   TRACE("(this=%p,%p,%p,%08lx)\n", This, lpCallback, lpvRef, dwFlags);
1983   if (TRACE_ON(dinput)) {
1984     DPRINTF("  - flags = ");
1985     _dump_EnumObjects_flags(dwFlags);
1986     DPRINTF("\n");
1987   }
1988
1989   /* Only the fields till dwFFMaxForce are relevant */
1990   ddoi.dwSize = FIELD_OFFSET(DIDEVICEOBJECTINSTANCE, dwFFMaxForce);
1991     
1992   /* For the joystick, do as is done in the GetCapabilities function */
1993   if ((dwFlags == DIDFT_ALL) ||
1994       (dwFlags & DIDFT_AXIS)) {
1995     BYTE axes, i;
1996     
1997 #ifdef JSIOCGAXES
1998     if (-1==ioctl(xfd,JSIOCGAXES,&axes))
1999       axes = 2;
2000 #endif
2001
2002     for (i = 0; i < axes; i++) {
2003       switch (i) {
2004       case 0:
2005         ddoi.guidType = GUID_XAxis;
2006         ddoi.dwOfs = DIJOFS_X;
2007         break;
2008       case 1:
2009         ddoi.guidType = GUID_YAxis;
2010         ddoi.dwOfs = DIJOFS_Y;
2011         break;
2012       case 2:
2013         ddoi.guidType = GUID_ZAxis;
2014         ddoi.dwOfs = DIJOFS_Z;
2015         break;
2016       default:
2017         ddoi.guidType = GUID_Unknown;
2018         ddoi.dwOfs = DIJOFS_Z + (i - 2) * sizeof(LONG);
2019       }
2020       ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << i) << WINE_JOYSTICK_AXIS_BASE) | DIDFT_ABSAXIS;
2021       sprintf(ddoi.tszName, "%d-Axis", i);
2022       _dump_OBJECTINSTANCE(&ddoi);
2023       if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
2024     }
2025   }
2026
2027   if ((dwFlags == DIDFT_ALL) ||
2028       (dwFlags & DIDFT_BUTTON)) {
2029     BYTE buttons, i;
2030     
2031 #ifdef JSIOCGBUTTONS
2032     if (-1==ioctl(xfd,JSIOCGAXES,&buttons))
2033       buttons = 2;
2034 #endif
2035   
2036     /* The DInput SDK says that GUID_Button is only for mouse buttons but well... */
2037     ddoi.guidType = GUID_Button;
2038     
2039     for (i = 0; i < buttons; i++) {
2040       ddoi.dwOfs = DIJOFS_BUTTON(i);
2041       ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << i) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON;
2042       sprintf(ddoi.tszName, "%d-Button", i);
2043       _dump_OBJECTINSTANCE(&ddoi);
2044       if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
2045     }
2046   }
2047
2048   if (xfd!=This->joyfd)
2049     close(xfd);
2050
2051   return DI_OK;
2052 }
2053
2054 /******************************************************************************
2055   *     GetProperty : get input device properties
2056   */
2057 static HRESULT WINAPI JoystickAImpl_GetProperty(LPDIRECTINPUTDEVICE2A iface,
2058                                                 REFGUID rguid,
2059                                                 LPDIPROPHEADER pdiph)
2060 {
2061   ICOM_THIS(JoystickAImpl,iface);
2062
2063   TRACE("(this=%p,%s,%p): stub!\n",
2064         iface, debugstr_guid(rguid), pdiph);
2065
2066   if (TRACE_ON(dinput))
2067     _dump_DIPROPHEADER(pdiph);
2068   
2069   if (!HIWORD(rguid)) {
2070     switch ((DWORD)rguid) {
2071     case (DWORD) DIPROP_BUFFERSIZE: {
2072       LPDIPROPDWORD     pd = (LPDIPROPDWORD)pdiph;
2073       
2074       TRACE(" return buffersize = %d\n",This->queue_len);
2075       pd->dwData = This->queue_len;
2076       break;
2077     }
2078
2079     case (DWORD) DIPROP_RANGE: {
2080       LPDIPROPRANGE pr = (LPDIPROPRANGE) pdiph;
2081
2082       if ((pdiph->dwHow == DIPH_BYID) &&
2083           (pdiph->dwObj & DIDFT_ABSAXIS)) {
2084         /* The app is querying the current range of the axis : return the lMin and lMax values */
2085         pr->lMin = This->lMin;
2086         pr->lMax = This->lMax;
2087       }
2088       
2089       break;
2090     }
2091       
2092     default:
2093       FIXME("Unknown type %ld (%s)\n",(DWORD)rguid,debugstr_guid(rguid));
2094       break;
2095     }
2096   }
2097   
2098   
2099   return DI_OK;
2100 }
2101
2102 #endif
2103
2104 /****************************************************************************/
2105 /****************************************************************************/
2106
2107 static ICOM_VTABLE(IDirectInputDevice2A) SysKeyboardAvt = 
2108 {
2109         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
2110         IDirectInputDevice2AImpl_QueryInterface,
2111         IDirectInputDevice2AImpl_AddRef,
2112         IDirectInputDevice2AImpl_Release,
2113         SysKeyboardAImpl_GetCapabilities,
2114         IDirectInputDevice2AImpl_EnumObjects,
2115         IDirectInputDevice2AImpl_GetProperty,
2116         SysKeyboardAImpl_SetProperty,
2117         SysKeyboardAImpl_Acquire,
2118         SysKeyboardAImpl_Unacquire,
2119         SysKeyboardAImpl_GetDeviceState,
2120         SysKeyboardAImpl_GetDeviceData,
2121         IDirectInputDevice2AImpl_SetDataFormat,
2122         IDirectInputDevice2AImpl_SetEventNotification,
2123         IDirectInputDevice2AImpl_SetCooperativeLevel,
2124         IDirectInputDevice2AImpl_GetObjectInfo,
2125         IDirectInputDevice2AImpl_GetDeviceInfo,
2126         IDirectInputDevice2AImpl_RunControlPanel,
2127         IDirectInputDevice2AImpl_Initialize,
2128         IDirectInputDevice2AImpl_CreateEffect,
2129         IDirectInputDevice2AImpl_EnumEffects,
2130         IDirectInputDevice2AImpl_GetEffectInfo,
2131         IDirectInputDevice2AImpl_GetForceFeedbackState,
2132         IDirectInputDevice2AImpl_SendForceFeedbackCommand,
2133         IDirectInputDevice2AImpl_EnumCreatedEffectObjects,
2134         IDirectInputDevice2AImpl_Escape,
2135         IDirectInputDevice2AImpl_Poll,
2136         IDirectInputDevice2AImpl_SendDeviceData,
2137 };
2138
2139 static ICOM_VTABLE(IDirectInputDevice2A) SysMouseAvt = 
2140 {
2141         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
2142         IDirectInputDevice2AImpl_QueryInterface,
2143         IDirectInputDevice2AImpl_AddRef,
2144         SysMouseAImpl_Release,
2145         SysMouseAImpl_GetCapabilities,
2146         SysMouseAImpl_EnumObjects,
2147         SysMouseAImpl_GetProperty,
2148         SysMouseAImpl_SetProperty,
2149         SysMouseAImpl_Acquire,
2150         SysMouseAImpl_Unacquire,
2151         SysMouseAImpl_GetDeviceState,
2152         SysMouseAImpl_GetDeviceData,
2153         SysMouseAImpl_SetDataFormat,
2154         SysMouseAImpl_SetEventNotification,
2155         SysMouseAImpl_SetCooperativeLevel,
2156         IDirectInputDevice2AImpl_GetObjectInfo,
2157         IDirectInputDevice2AImpl_GetDeviceInfo,
2158         IDirectInputDevice2AImpl_RunControlPanel,
2159         IDirectInputDevice2AImpl_Initialize,
2160         IDirectInputDevice2AImpl_CreateEffect,
2161         IDirectInputDevice2AImpl_EnumEffects,
2162         IDirectInputDevice2AImpl_GetEffectInfo,
2163         IDirectInputDevice2AImpl_GetForceFeedbackState,
2164         IDirectInputDevice2AImpl_SendForceFeedbackCommand,
2165         IDirectInputDevice2AImpl_EnumCreatedEffectObjects,
2166         IDirectInputDevice2AImpl_Escape,
2167         IDirectInputDevice2AImpl_Poll,
2168         IDirectInputDevice2AImpl_SendDeviceData,
2169 };
2170
2171 #ifdef HAVE_LINUX_22_JOYSTICK_API
2172 static ICOM_VTABLE(IDirectInputDevice2A) JoystickAvt = 
2173 {
2174         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
2175         IDirectInputDevice2AImpl_QueryInterface,
2176         IDirectInputDevice2AImpl_AddRef,
2177         JoystickAImpl_Release,
2178         JoystickAImpl_GetCapabilities,
2179         JoystickAImpl_EnumObjects,
2180         JoystickAImpl_GetProperty,
2181         JoystickAImpl_SetProperty,
2182         JoystickAImpl_Acquire,
2183         JoystickAImpl_Unacquire,
2184         JoystickAImpl_GetDeviceState,
2185         JoystickAImpl_GetDeviceData,
2186         JoystickAImpl_SetDataFormat,
2187         JoystickAImpl_SetEventNotification,
2188         IDirectInputDevice2AImpl_SetCooperativeLevel,
2189         IDirectInputDevice2AImpl_GetObjectInfo,
2190         IDirectInputDevice2AImpl_GetDeviceInfo,
2191         IDirectInputDevice2AImpl_RunControlPanel,
2192         IDirectInputDevice2AImpl_Initialize,
2193         IDirectInputDevice2AImpl_CreateEffect,
2194         IDirectInputDevice2AImpl_EnumEffects,
2195         IDirectInputDevice2AImpl_GetEffectInfo,
2196         IDirectInputDevice2AImpl_GetForceFeedbackState,
2197         IDirectInputDevice2AImpl_SendForceFeedbackCommand,
2198         IDirectInputDevice2AImpl_EnumCreatedEffectObjects,
2199         IDirectInputDevice2AImpl_Escape,
2200         JoystickAImpl_Poll,
2201         IDirectInputDevice2AImpl_SendDeviceData,
2202 };
2203 #endif