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