POSIX threads emulation, tricks glibc into being threadsafe.
[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  *      DirectInputCreate32A
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             return;
1255           }
1256                   
1257           /* Relative mouse input with absolute mouse event : the real fun starts here... */
1258           if ((This->need_warp == WARP_NEEDED) ||
1259               (This->need_warp == WARP_STARTED)) {
1260             if (posX != This->prevX)
1261               GEN_EVENT(This->offset_array[WINE_MOUSE_X_POSITION], posX - This->prevX, xtime, evsequence++);
1262             if (posY != This->prevY)
1263               GEN_EVENT(This->offset_array[WINE_MOUSE_Y_POSITION], posY - This->prevY, xtime, evsequence++);
1264           } else {
1265             /* This is the first time the event handler has been called after a
1266                GetData of GetState. */
1267             if (posX != This->win_centerX) {
1268               GEN_EVENT(This->offset_array[WINE_MOUSE_X_POSITION], posX - This->win_centerX, xtime, evsequence++);
1269               This->need_warp = WARP_NEEDED;
1270             }
1271             
1272             if (posY != This->win_centerY) {
1273               GEN_EVENT(This->offset_array[WINE_MOUSE_Y_POSITION], posY - This->win_centerY, xtime, evsequence++);
1274               This->need_warp = WARP_NEEDED;
1275             }
1276           }
1277         }
1278
1279         This->prevX = posX;
1280         This->prevY = posY;
1281         
1282         if (This->absolute) {
1283           This->m_state.lX = posX;
1284           This->m_state.lY = posY;
1285         } else {
1286           This->m_state.lX = posX - This->win_centerX;
1287           This->m_state.lY = posY - This->win_centerY;
1288         }
1289       } else {
1290         /* Mouse reporting is in relative mode */
1291         posX = (long) dx;
1292         posY = (long) dy;
1293
1294         if (This->absolute) {
1295           long aposX, aposY;
1296           
1297           aposX = This->m_state.lX + posX;
1298           if (aposX < 0)
1299             aposX = 0;
1300           if (aposX >= GetSystemMetrics(SM_CXSCREEN))
1301             aposX = GetSystemMetrics(SM_CXSCREEN);
1302           
1303           aposY = This->m_state.lY + posY;
1304           if (aposY < 0)
1305             aposY = 0;
1306           if (aposY >= GetSystemMetrics(SM_CYSCREEN))
1307             aposY = GetSystemMetrics(SM_CYSCREEN);
1308           
1309           if (posX != 0)
1310             GEN_EVENT(This->offset_array[WINE_MOUSE_X_POSITION], aposX, xtime, evsequence++);
1311           if (posY != 0)
1312             GEN_EVENT(This->offset_array[WINE_MOUSE_Y_POSITION], aposY, xtime, evsequence++);
1313
1314           This->m_state.lX = aposX;
1315           This->m_state.lY = aposY;
1316         } else {
1317           if (posX != 0)
1318             GEN_EVENT(This->offset_array[WINE_MOUSE_X_POSITION], posX, xtime, evsequence++);
1319           if (posY != 0)
1320             GEN_EVENT(This->offset_array[WINE_MOUSE_Y_POSITION], posY, xtime, evsequence++);
1321
1322           This->m_state.lX = posX;
1323           This->m_state.lY = posY;
1324         }
1325       }
1326     }
1327   } else {
1328     ERR("Mouse event not supported...\n");
1329     LeaveCriticalSection(&(This->crit));
1330     return ;
1331   }
1332
1333   if (TRACE_ON(dinput)) {
1334     if (dwFlags & MOUSEEVENTF_MOVE)
1335       TRACE(" %ld %ld (%s)", posX, posY,
1336             (dwFlags & MOUSEEVENTF_ABSOLUTE ? "abs" : "rel"));
1337     
1338     if ( dwFlags & MOUSEEVENTF_LEFTDOWN ) DPRINTF(" LD ");
1339     if ( dwFlags & MOUSEEVENTF_LEFTUP )   DPRINTF(" LU ");
1340
1341     if ( dwFlags & MOUSEEVENTF_RIGHTDOWN ) DPRINTF(" RD ");
1342     if ( dwFlags & MOUSEEVENTF_RIGHTUP )   DPRINTF(" RU ");
1343
1344     if ( dwFlags & MOUSEEVENTF_MIDDLEDOWN ) DPRINTF(" MD ");
1345     if ( dwFlags & MOUSEEVENTF_MIDDLEUP )   DPRINTF(" MU ");
1346
1347     if (!(This->absolute)) DPRINTF(" W=%d ", This->need_warp);
1348     
1349     DPRINTF("\n");
1350   }
1351
1352   
1353   if ( dwFlags & MOUSEEVENTF_LEFTDOWN ) {
1354     GEN_EVENT(This->offset_array[WINE_MOUSE_L_POSITION], 0xFF, xtime, evsequence++);
1355     This->m_state.rgbButtons[0] = 0xFF;
1356   }
1357   if ( dwFlags & MOUSEEVENTF_LEFTUP ) {
1358     GEN_EVENT(This->offset_array[WINE_MOUSE_L_POSITION], 0x00, xtime, evsequence++);
1359     This->m_state.rgbButtons[0] = 0x00;
1360   }
1361   if ( dwFlags & MOUSEEVENTF_RIGHTDOWN ) {
1362     GEN_EVENT(This->offset_array[WINE_MOUSE_R_POSITION], 0xFF, xtime, evsequence++);
1363     This->m_state.rgbButtons[1] = 0xFF;
1364   }
1365   if ( dwFlags & MOUSEEVENTF_RIGHTUP ) {
1366     GEN_EVENT(This->offset_array[WINE_MOUSE_R_POSITION], 0x00, xtime, evsequence++);
1367     This->m_state.rgbButtons[1] = 0x00;
1368   }
1369   if ( dwFlags & MOUSEEVENTF_MIDDLEDOWN ) {
1370     GEN_EVENT(This->offset_array[WINE_MOUSE_M_POSITION], 0xFF, xtime, evsequence++);
1371     This->m_state.rgbButtons[2] = 0xFF;
1372   }
1373   if ( dwFlags & MOUSEEVENTF_MIDDLEUP ) {
1374     GEN_EVENT(This->offset_array[WINE_MOUSE_M_POSITION], 0x00, xtime, evsequence++);
1375     This->m_state.rgbButtons[2] = 0x00;
1376   }
1377
1378   TRACE("(X: %ld - Y: %ld   L: %02x M: %02x R: %02x)\n",
1379         This->m_state.lX, This->m_state.lY,
1380         This->m_state.rgbButtons[0], This->m_state.rgbButtons[2], This->m_state.rgbButtons[1]);
1381   
1382   LeaveCriticalSection(&(This->crit));
1383 }
1384
1385
1386 /******************************************************************************
1387   *     Acquire : gets exclusive control of the mouse
1388   */
1389 static HRESULT WINAPI SysMouseAImpl_Acquire(LPDIRECTINPUTDEVICE2A iface)
1390 {
1391   ICOM_THIS(SysMouseAImpl,iface);
1392   RECT  rect;
1393   
1394   TRACE("(this=%p)\n",This);
1395
1396   if (This->acquired == 0) {
1397     POINT       point;
1398     
1399     /* This stores the current mouse handler. */
1400     This->prev_handler = mouse_event;
1401     
1402     /* Store (in a global variable) the current lock */
1403     current_lock = (IDirectInputDevice2A*)This;
1404
1405     /* Init the mouse state */
1406     if (This->absolute) {
1407       This->m_state.lX = PosX;
1408       This->m_state.lY = PosY;
1409
1410       This->prevX = PosX;
1411       This->prevY = PosY;
1412     } else {
1413       This->m_state.lX = 0;
1414       This->m_state.lY = 0;
1415     }
1416     This->m_state.rgbButtons[0] = (MouseButtonsStates[0] ? 0xFF : 0x00);
1417     This->m_state.rgbButtons[1] = (MouseButtonsStates[1] ? 0xFF : 0x00);
1418     This->m_state.rgbButtons[2] = (MouseButtonsStates[2] ? 0xFF : 0x00);
1419
1420     /* Install our own mouse event handler */
1421     MOUSE_Enable(dinput_mouse_event);
1422     
1423     /* Get the window dimension and find the center */
1424     GetWindowRect(This->win, &rect);
1425     This->win_centerX = (rect.right  - rect.left) / 2;
1426     This->win_centerY = (rect.bottom - rect.top ) / 2;
1427
1428     /* Warp the mouse to the center of the window */
1429     if (This->absolute == 0) {
1430       TRACE("Warping mouse to %ld - %ld\n", This->win_centerX, This->win_centerY);
1431       point.x = This->win_centerX;
1432       point.y = This->win_centerY;
1433       MapWindowPoints(This->win, HWND_DESKTOP, &point, 1);
1434       DISPLAY_MoveCursor(point.x, point.y);
1435       This->need_warp = WARP_STARTED;
1436     }
1437
1438     This->acquired = 1;
1439   }
1440   return 0;
1441 }
1442
1443 /******************************************************************************
1444   *     Unacquire : frees the mouse
1445   */
1446 static HRESULT WINAPI SysMouseAImpl_Unacquire(LPDIRECTINPUTDEVICE2A iface)
1447 {
1448   ICOM_THIS(SysMouseAImpl,iface);
1449
1450   TRACE("(this=%p)\n",This);
1451
1452   /* Reinstall previous mouse event handler */
1453   MOUSE_Enable(This->prev_handler);
1454   This->prev_handler = NULL;
1455   
1456   /* No more locks */
1457   current_lock = NULL;
1458
1459   /* Unacquire device */
1460   This->acquired = 0;
1461   
1462   return 0;
1463 }
1464
1465 /******************************************************************************
1466   *     GetDeviceState : returns the "state" of the mouse.
1467   *
1468   *   For the moment, only the "standard" return structure (DIMOUSESTATE) is
1469   *   supported.
1470   */
1471 static HRESULT WINAPI SysMouseAImpl_GetDeviceState(
1472         LPDIRECTINPUTDEVICE2A iface,DWORD len,LPVOID ptr
1473 ) {
1474   ICOM_THIS(SysMouseAImpl,iface);
1475   
1476   EnterCriticalSection(&(This->crit));
1477   TRACE("(this=%p,0x%08lx,%p): \n",This,len,ptr);
1478   
1479   /* Copy the current mouse state */
1480   fill_DataFormat(ptr, &(This->m_state), This->wine_df);
1481   
1482   /* Initialize the buffer when in relative mode */
1483   if (This->absolute == 0) {
1484     This->m_state.lX = 0;
1485     This->m_state.lY = 0;
1486   }
1487   
1488   /* Check if we need to do a mouse warping */
1489   if (This->need_warp == WARP_NEEDED) {
1490     POINT point;
1491
1492     TRACE("Warping mouse to %ld - %ld\n", This->win_centerX, This->win_centerY);
1493     point.x = This->win_centerX;
1494     point.y = This->win_centerY;
1495     MapWindowPoints(This->win, HWND_DESKTOP, &point, 1);
1496     DISPLAY_MoveCursor(point.x, point.y);
1497
1498     This->need_warp = WARP_STARTED;
1499   }
1500
1501   LeaveCriticalSection(&(This->crit));
1502   
1503   TRACE("(X: %ld - Y: %ld   L: %02x M: %02x R: %02x)\n",
1504         This->m_state.lX, This->m_state.lY,
1505         This->m_state.rgbButtons[0], This->m_state.rgbButtons[2], This->m_state.rgbButtons[1]);
1506   
1507   return 0;
1508 }
1509
1510 /******************************************************************************
1511   *     GetDeviceState : gets buffered input data.
1512   */
1513 static HRESULT WINAPI SysMouseAImpl_GetDeviceData(LPDIRECTINPUTDEVICE2A iface,
1514                                               DWORD dodsize,
1515                                               LPDIDEVICEOBJECTDATA dod,
1516                                               LPDWORD entries,
1517                                               DWORD flags
1518 ) {
1519   ICOM_THIS(SysMouseAImpl,iface);
1520   
1521   EnterCriticalSection(&(This->crit));
1522   TRACE("(%p)->(dods=%ld,entries=%ld,fl=0x%08lx)\n",This,dodsize,*entries,flags);
1523
1524   if (flags & DIGDD_PEEK)
1525     FIXME("DIGDD_PEEK\n");
1526
1527   if (dod == NULL) {
1528     *entries = This->queue_pos;
1529     This->queue_pos = 0;
1530   } else {
1531     /* Check for buffer overflow */
1532     if (This->queue_pos > *entries) {
1533       WARN("Buffer overflow not handled properly yet...\n");
1534       This->queue_pos = *entries;
1535     }
1536     if (dodsize != sizeof(DIDEVICEOBJECTDATA)) {
1537       ERR("Wrong structure size !\n");
1538       LeaveCriticalSection(&(This->crit));
1539       return DIERR_INVALIDPARAM;
1540     }
1541
1542     if (This->queue_pos)
1543         TRACE("Application retrieving %d event(s).\n", This->queue_pos); 
1544     
1545     /* Copy the buffered data into the application queue */
1546     memcpy(dod, This->data_queue, This->queue_pos * dodsize);
1547     *entries = This->queue_pos;
1548
1549     /* Reset the event queue */
1550     This->queue_pos = 0;
1551   }
1552   LeaveCriticalSection(&(This->crit));
1553   
1554   /* Check if we need to do a mouse warping */
1555   if (This->need_warp == WARP_NEEDED) {
1556     POINT point;
1557
1558     TRACE("Warping mouse to %ld - %ld\n", This->win_centerX, This->win_centerY);
1559     point.x = This->win_centerX;
1560     point.y = This->win_centerY;
1561     MapWindowPoints(This->win, HWND_DESKTOP, &point, 1);
1562
1563     DISPLAY_MoveCursor(point.x, point.y);
1564
1565     This->need_warp = WARP_STARTED;
1566   }
1567   return 0;
1568 }
1569
1570 /******************************************************************************
1571   *     SetProperty : change input device properties
1572   */
1573 static HRESULT WINAPI SysMouseAImpl_SetProperty(LPDIRECTINPUTDEVICE2A iface,
1574                                             REFGUID rguid,
1575                                             LPCDIPROPHEADER ph)
1576 {
1577   ICOM_THIS(SysMouseAImpl,iface);
1578
1579   TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(rguid),ph);
1580   
1581   if (!HIWORD(rguid)) {
1582     switch ((DWORD)rguid) {
1583     case (DWORD) DIPROP_BUFFERSIZE: {
1584       LPCDIPROPDWORD    pd = (LPCDIPROPDWORD)ph;
1585       
1586       TRACE("buffersize = %ld\n",pd->dwData);
1587
1588       This->data_queue = (LPDIDEVICEOBJECTDATA)HeapAlloc(GetProcessHeap(),0,
1589                                                           pd->dwData * sizeof(DIDEVICEOBJECTDATA));
1590       This->queue_pos  = 0;
1591       This->queue_len  = pd->dwData;
1592       break;
1593     }
1594     default:
1595       FIXME("Unknown type %ld (%s)\n",(DWORD)rguid,debugstr_guid(rguid));
1596       break;
1597     }
1598   }
1599   
1600   return 0;
1601 }
1602
1603 /******************************************************************************
1604   *     GetProperty : get input device properties
1605   */
1606 static HRESULT WINAPI SysMouseAImpl_GetProperty(LPDIRECTINPUTDEVICE2A iface,
1607                                                 REFGUID rguid,
1608                                                 LPDIPROPHEADER pdiph)
1609 {
1610   ICOM_THIS(SysMouseAImpl,iface);
1611
1612   TRACE("(this=%p,%s,%p): stub!\n",
1613         iface, debugstr_guid(rguid), pdiph);
1614
1615   if (TRACE_ON(dinput))
1616     _dump_DIPROPHEADER(pdiph);
1617   
1618   if (!HIWORD(rguid)) {
1619     switch ((DWORD)rguid) {
1620     case (DWORD) DIPROP_BUFFERSIZE: {
1621       LPDIPROPDWORD     pd = (LPDIPROPDWORD)pdiph;
1622       
1623       TRACE(" return buffersize = %d\n",This->queue_len);
1624       pd->dwData = This->queue_len;
1625       break;
1626     }
1627
1628     case (DWORD) DIPROP_RANGE: {
1629       LPDIPROPRANGE pr = (LPDIPROPRANGE) pdiph;
1630
1631       if ((pdiph->dwHow == DIPH_BYID) &&
1632           ((pdiph->dwObj == (DIDFT_MAKEINSTANCE(WINE_MOUSE_X_AXIS_INSTANCE) | DIDFT_RELAXIS)) ||
1633            (pdiph->dwObj == (DIDFT_MAKEINSTANCE(WINE_MOUSE_Y_AXIS_INSTANCE) | DIDFT_RELAXIS)))) {
1634         /* Querying the range of either the X or the Y axis.  As I do
1635            not know the range, do as if the range where
1636            unrestricted...*/
1637         pr->lMin = DIPROPRANGE_NOMIN;
1638         pr->lMax = DIPROPRANGE_NOMAX;
1639       }
1640       
1641       break;
1642     }
1643       
1644     default:
1645       FIXME("Unknown type %ld (%s)\n",(DWORD)rguid,debugstr_guid(rguid));
1646       break;
1647     }
1648   }
1649   
1650   
1651   return DI_OK;
1652 }
1653
1654
1655
1656 /******************************************************************************
1657   *     SetEventNotification : specifies event to be sent on state change
1658   */
1659 static HRESULT WINAPI SysMouseAImpl_SetEventNotification(LPDIRECTINPUTDEVICE2A iface,
1660                                                          HANDLE hnd) {
1661   ICOM_THIS(SysMouseAImpl,iface);
1662
1663   TRACE("(this=%p,0x%08lx)\n",This,(DWORD)hnd);
1664
1665   This->hEvent = hnd;
1666
1667   return DI_OK;
1668 }
1669
1670 /******************************************************************************
1671   *     GetCapabilities : get the device capablitites
1672   */
1673 static HRESULT WINAPI SysMouseAImpl_GetCapabilities(
1674         LPDIRECTINPUTDEVICE2A iface,
1675         LPDIDEVCAPS lpDIDevCaps)
1676 {
1677   ICOM_THIS(SysMouseAImpl,iface);
1678
1679   TRACE("(this=%p,%p)\n",This,lpDIDevCaps);
1680
1681   if (lpDIDevCaps->dwSize == sizeof(DIDEVCAPS)) {
1682     lpDIDevCaps->dwFlags = DIDC_ATTACHED;
1683     lpDIDevCaps->dwDevType = DIDEVTYPE_MOUSE;
1684     lpDIDevCaps->dwAxes = 2;
1685     lpDIDevCaps->dwButtons = 3;
1686     lpDIDevCaps->dwPOVs = 0;
1687     lpDIDevCaps->dwFFSamplePeriod = 0;
1688     lpDIDevCaps->dwFFMinTimeResolution = 0;
1689     lpDIDevCaps->dwFirmwareRevision = 100;
1690     lpDIDevCaps->dwHardwareRevision = 100;
1691     lpDIDevCaps->dwFFDriverVersion = 0;
1692   } else {
1693     /* DirectX 3.0 */
1694     FIXME("DirectX 3.0 not supported....\n");
1695   }
1696   
1697   return DI_OK;
1698 }
1699
1700
1701 /******************************************************************************
1702   *     EnumObjects : enumerate the different buttons and axis...
1703   */
1704 static HRESULT WINAPI SysMouseAImpl_EnumObjects(
1705         LPDIRECTINPUTDEVICE2A iface,
1706         LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback,
1707         LPVOID lpvRef,
1708         DWORD dwFlags)
1709 {
1710   ICOM_THIS(SysMouseAImpl,iface);
1711   DIDEVICEOBJECTINSTANCEA ddoi;
1712   
1713   TRACE("(this=%p,%p,%p,%08lx)\n", This, lpCallback, lpvRef, dwFlags);
1714   if (TRACE_ON(dinput)) {
1715     DPRINTF("  - flags = ");
1716     _dump_EnumObjects_flags(dwFlags);
1717     DPRINTF("\n");
1718   }
1719
1720   /* Only the fields till dwFFMaxForce are relevant */
1721   ddoi.dwSize = FIELD_OFFSET(DIDEVICEOBJECTINSTANCEA, dwFFMaxForce);
1722     
1723   /* In a mouse, we have : two relative axis and three buttons */
1724   if ((dwFlags == DIDFT_ALL) ||
1725       (dwFlags & DIDFT_AXIS)) {
1726     /* X axis */
1727     ddoi.guidType = GUID_XAxis;
1728     ddoi.dwOfs = This->offset_array[WINE_MOUSE_X_POSITION];
1729     ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_X_AXIS_INSTANCE) | DIDFT_RELAXIS;
1730     strcpy(ddoi.tszName, "X-Axis");
1731     _dump_OBJECTINSTANCEA(&ddoi);
1732     if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
1733     
1734     /* Y axis */
1735     ddoi.guidType = GUID_YAxis;
1736     ddoi.dwOfs = This->offset_array[WINE_MOUSE_Y_POSITION];
1737     ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_Y_AXIS_INSTANCE) | DIDFT_RELAXIS;
1738     strcpy(ddoi.tszName, "Y-Axis");
1739     _dump_OBJECTINSTANCEA(&ddoi);
1740     if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
1741   }
1742
1743   if ((dwFlags == DIDFT_ALL) ||
1744       (dwFlags & DIDFT_BUTTON)) {
1745     ddoi.guidType = GUID_Button;
1746
1747     /* Left button */
1748     ddoi.dwOfs = This->offset_array[WINE_MOUSE_L_POSITION];
1749     ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_L_BUTTON_INSTANCE) | DIDFT_PSHBUTTON;
1750     strcpy(ddoi.tszName, "Left-Button");
1751     _dump_OBJECTINSTANCEA(&ddoi);
1752     if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
1753
1754     /* Right button */
1755     ddoi.dwOfs = This->offset_array[WINE_MOUSE_R_POSITION];
1756     ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_R_BUTTON_INSTANCE) | DIDFT_PSHBUTTON;
1757     strcpy(ddoi.tszName, "Right-Button");
1758     _dump_OBJECTINSTANCEA(&ddoi);
1759     if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
1760
1761     /* Middle button */
1762     ddoi.dwOfs = This->offset_array[WINE_MOUSE_M_POSITION];
1763     ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_M_BUTTON_INSTANCE) | DIDFT_PSHBUTTON;
1764     strcpy(ddoi.tszName, "Middle-Button");
1765     _dump_OBJECTINSTANCEA(&ddoi);
1766     if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
1767   }
1768
1769   return DI_OK;
1770 }
1771         
1772
1773
1774 #ifdef HAVE_LINUX_22_JOYSTICK_API
1775 /******************************************************************************
1776  *      Joystick
1777  */
1778 static ULONG WINAPI JoystickAImpl_Release(LPDIRECTINPUTDEVICE2A iface)
1779 {
1780         ICOM_THIS(JoystickAImpl,iface);
1781
1782         This->ref--;
1783         if (This->ref)
1784                 return This->ref;
1785
1786         /* Free the data queue */
1787         if (This->data_queue != NULL)
1788           HeapFree(GetProcessHeap(),0,This->data_queue);
1789         
1790         /* Free the DataFormat */
1791         HeapFree(GetProcessHeap(), 0, This->df);
1792         
1793         HeapFree(GetProcessHeap(),0,This);
1794         return 0;
1795 }
1796
1797 /******************************************************************************
1798   *   SetDataFormat : the application can choose the format of the data
1799   *   the device driver sends back with GetDeviceState.
1800   */
1801 static HRESULT WINAPI JoystickAImpl_SetDataFormat(
1802         LPDIRECTINPUTDEVICE2A iface,LPCDIDATAFORMAT df
1803 )
1804 {
1805   ICOM_THIS(JoystickAImpl,iface);
1806   int i;
1807   
1808   TRACE("(this=%p,%p)\n",This,df);
1809
1810   TRACE("(df.dwSize=%ld)\n",df->dwSize);
1811   TRACE("(df.dwObjsize=%ld)\n",df->dwObjSize);
1812   TRACE("(df.dwFlags=0x%08lx)\n",df->dwFlags);
1813   TRACE("(df.dwDataSize=%ld)\n",df->dwDataSize);
1814   TRACE("(df.dwNumObjs=%ld)\n",df->dwNumObjs);
1815
1816   for (i=0;i<df->dwNumObjs;i++) {
1817     TRACE("df.rgodf[%d].guid %s (%p)\n",i,debugstr_guid(df->rgodf[i].pguid), df->rgodf[i].pguid);
1818     TRACE("df.rgodf[%d].dwOfs %ld\n",i,df->rgodf[i].dwOfs);
1819     TRACE("dwType 0x%02x,dwInstance %d\n",DIDFT_GETTYPE(df->rgodf[i].dwType),DIDFT_GETINSTANCE(df->rgodf[i].dwType));
1820     TRACE("df.rgodf[%d].dwFlags 0x%08lx\n",i,df->rgodf[i].dwFlags);
1821   }
1822   
1823   /* Store the new data format */
1824   This->df = HeapAlloc(GetProcessHeap(),0,df->dwSize);
1825   memcpy(This->df, df, df->dwSize);
1826   This->df->rgodf = HeapAlloc(GetProcessHeap(),0,df->dwNumObjs*df->dwObjSize);
1827   memcpy(This->df->rgodf,df->rgodf,df->dwNumObjs*df->dwObjSize);
1828   
1829   return 0;
1830 }
1831
1832 /******************************************************************************
1833   *     Acquire : gets exclusive control of the joystick
1834   */
1835 static HRESULT WINAPI JoystickAImpl_Acquire(LPDIRECTINPUTDEVICE2A iface)
1836 {
1837     ICOM_THIS(JoystickAImpl,iface);
1838   
1839     TRACE("(this=%p)\n",This);
1840     if (This->joyfd!=-1)
1841         return 0;
1842     This->joyfd=open(JOYDEV,O_RDONLY);
1843     if (This->joyfd==-1)
1844         return DIERR_NOTFOUND;
1845     return 0;
1846 }
1847
1848 /******************************************************************************
1849   *     Unacquire : frees the joystick
1850   */
1851 static HRESULT WINAPI JoystickAImpl_Unacquire(LPDIRECTINPUTDEVICE2A iface)
1852 {
1853     ICOM_THIS(JoystickAImpl,iface);
1854
1855     TRACE("(this=%p)\n",This);
1856     if (This->joyfd!=-1) {
1857         close(This->joyfd);
1858         This->joyfd = -1;
1859     }
1860     return 0;
1861 }
1862
1863 #define map_axis(val) ((val+32768)*(This->lMax-This->lMin)/65536+This->lMin)
1864
1865 static void joy_polldev(JoystickAImpl *This) {
1866     struct timeval tv;
1867     fd_set      readfds;
1868     struct      js_event jse;
1869
1870     if (This->joyfd==-1)
1871         return;
1872     while (1) {
1873         memset(&tv,0,sizeof(tv));
1874         FD_ZERO(&readfds);FD_SET(This->joyfd,&readfds);
1875         if (1>select(This->joyfd+1,&readfds,NULL,NULL,&tv))
1876             return;
1877         /* we have one event, so we can read */
1878         if (sizeof(jse)!=read(This->joyfd,&jse,sizeof(jse))) {
1879             return;
1880         }
1881         TRACE("js_event: type 0x%x, number %d, value %d\n",jse.type,jse.number,jse.value);
1882         if (jse.type & JS_EVENT_BUTTON) {
1883             GEN_EVENT(DIJOFS_BUTTON(jse.number),jse.value?0x80:0x00,jse.time,evsequence++);
1884             This->js.rgbButtons[jse.number] = jse.value?0x80:0x00;
1885         }
1886         if (jse.type & JS_EVENT_AXIS) {
1887             switch (jse.number) {
1888             case 0:
1889                 GEN_EVENT(jse.number*4,jse.value,jse.time,evsequence++);
1890                 This->js.lX = map_axis(jse.value);
1891                 break;
1892             case 1:
1893                 GEN_EVENT(jse.number*4,jse.value,jse.time,evsequence++);
1894                 This->js.lY = map_axis(jse.value);
1895                 break;
1896             case 2:
1897                 GEN_EVENT(jse.number*4,jse.value,jse.time,evsequence++);
1898                 This->js.lZ = map_axis(jse.value);
1899                 break;
1900             default:
1901                 FIXME("more then 3 axes (%d) not handled!\n",jse.number);
1902                 break;
1903             }
1904         }
1905     }
1906 }
1907
1908 /******************************************************************************
1909   *     GetDeviceState : returns the "state" of the joystick.
1910   *
1911   */
1912 static HRESULT WINAPI JoystickAImpl_GetDeviceState(
1913         LPDIRECTINPUTDEVICE2A iface,DWORD len,LPVOID ptr
1914 ) {
1915     ICOM_THIS(JoystickAImpl,iface);
1916   
1917     joy_polldev(This);
1918     TRACE("(this=%p,0x%08lx,%p)\n",This,len,ptr);
1919     if (len != sizeof(DIJOYSTATE)) {
1920         FIXME("len %ld is not sizeof(DIJOYSTATE), unsupported format.\n",len);
1921     }
1922     memcpy(ptr,&(This->js),len);
1923     This->queue_pos = 0;
1924     return 0;
1925 }
1926
1927 /******************************************************************************
1928   *     GetDeviceState : gets buffered input data.
1929   */
1930 static HRESULT WINAPI JoystickAImpl_GetDeviceData(LPDIRECTINPUTDEVICE2A iface,
1931                                               DWORD dodsize,
1932                                               LPDIDEVICEOBJECTDATA dod,
1933                                               LPDWORD entries,
1934                                               DWORD flags
1935 ) {
1936   ICOM_THIS(JoystickAImpl,iface);
1937   
1938   FIXME("(%p)->(dods=%ld,entries=%ld,fl=0x%08lx),STUB!\n",This,dodsize,*entries,flags);
1939
1940   joy_polldev(This);
1941   if (flags & DIGDD_PEEK)
1942     FIXME("DIGDD_PEEK\n");
1943
1944   if (dod == NULL) {
1945   } else {
1946   }
1947   return 0;
1948 }
1949
1950 /******************************************************************************
1951   *     SetProperty : change input device properties
1952   */
1953 static HRESULT WINAPI JoystickAImpl_SetProperty(LPDIRECTINPUTDEVICE2A iface,
1954                                             REFGUID rguid,
1955                                             LPCDIPROPHEADER ph)
1956 {
1957   ICOM_THIS(JoystickAImpl,iface);
1958
1959   FIXME("(this=%p,%s,%p)\n",This,debugstr_guid(rguid),ph);
1960   FIXME("ph.dwSize = %ld, ph.dwHeaderSize =%ld, ph.dwObj = %ld, ph.dwHow= %ld\n",ph->dwSize, ph->dwHeaderSize,ph->dwObj,ph->dwHow);
1961   
1962   if (!HIWORD(rguid)) {
1963     switch ((DWORD)rguid) {
1964     case (DWORD) DIPROP_BUFFERSIZE: {
1965       LPCDIPROPDWORD    pd = (LPCDIPROPDWORD)ph;
1966
1967       FIXME("buffersize = %ld\n",pd->dwData);
1968       break;
1969     }
1970     case (DWORD)DIPROP_RANGE: {
1971       LPCDIPROPRANGE    pr = (LPCDIPROPRANGE)ph;
1972
1973       FIXME("proprange(%ld,%ld)\n",pr->lMin,pr->lMax);
1974       This->lMin = pr->lMin;
1975       This->lMax = pr->lMax;
1976       break;
1977     }
1978     case (DWORD)DIPROP_DEADZONE: {
1979       LPCDIPROPDWORD    pd = (LPCDIPROPDWORD)ph;
1980
1981       FIXME("deadzone(%ld)\n",pd->dwData);
1982       This->deadzone = pd->dwData;
1983       break;
1984     }
1985     default:
1986       FIXME("Unknown type %ld (%s)\n",(DWORD)rguid,debugstr_guid(rguid));
1987       break;
1988     }
1989   }
1990   return 0;
1991 }
1992
1993 /******************************************************************************
1994   *     SetEventNotification : specifies event to be sent on state change
1995   */
1996 static HRESULT WINAPI JoystickAImpl_SetEventNotification(
1997         LPDIRECTINPUTDEVICE2A iface, HANDLE hnd
1998 ) {
1999     ICOM_THIS(JoystickAImpl,iface);
2000
2001     TRACE("(this=%p,0x%08lx)\n",This,(DWORD)hnd);
2002     This->hEvent = hnd;
2003     return DI_OK;
2004 }
2005
2006 static HRESULT WINAPI JoystickAImpl_GetCapabilities(
2007         LPDIRECTINPUTDEVICE2A iface,
2008         LPDIDEVCAPS lpDIDevCaps)
2009 {
2010     ICOM_THIS(JoystickAImpl,iface);
2011     BYTE        axes,buttons;
2012     int         xfd = This->joyfd;
2013
2014     TRACE("%p->(%p)\n",iface,lpDIDevCaps);
2015     if (xfd==-1)
2016         xfd = open(JOYDEV,O_RDONLY);
2017     lpDIDevCaps->dwFlags        = DIDC_ATTACHED;
2018     lpDIDevCaps->dwDevType      = DIDEVTYPE_JOYSTICK;
2019 #ifdef JSIOCGAXES
2020     if (-1==ioctl(xfd,JSIOCGAXES,&axes))
2021         axes = 2;
2022     lpDIDevCaps->dwAxes = axes;
2023 #endif
2024 #ifdef JSIOCGBUTTONS
2025     if (-1==ioctl(xfd,JSIOCGAXES,&buttons))
2026         buttons = 2;
2027     lpDIDevCaps->dwButtons = buttons;
2028 #endif
2029     if (xfd!=This->joyfd)
2030         close(xfd);
2031     return DI_OK;
2032 }
2033 static HRESULT WINAPI JoystickAImpl_Poll(LPDIRECTINPUTDEVICE2A iface) {
2034     ICOM_THIS(JoystickAImpl,iface);
2035     TRACE("(),stub!\n");
2036
2037     joy_polldev(This);
2038     return DI_OK;
2039 }
2040
2041 /******************************************************************************
2042   *     EnumObjects : enumerate the different buttons and axis...
2043   */
2044 static HRESULT WINAPI JoystickAImpl_EnumObjects(
2045         LPDIRECTINPUTDEVICE2A iface,
2046         LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback,
2047         LPVOID lpvRef,
2048         DWORD dwFlags)
2049 {
2050   ICOM_THIS(JoystickAImpl,iface);
2051   DIDEVICEOBJECTINSTANCEA ddoi;
2052   int xfd = This->joyfd;
2053
2054   TRACE("(this=%p,%p,%p,%08lx)\n", This, lpCallback, lpvRef, dwFlags);
2055   if (TRACE_ON(dinput)) {
2056     DPRINTF("  - flags = ");
2057     _dump_EnumObjects_flags(dwFlags);
2058     DPRINTF("\n");
2059   }
2060
2061   /* Only the fields till dwFFMaxForce are relevant */
2062   ddoi.dwSize = FIELD_OFFSET(DIDEVICEOBJECTINSTANCEA, dwFFMaxForce);
2063     
2064   /* For the joystick, do as is done in the GetCapabilities function */
2065   if ((dwFlags == DIDFT_ALL) ||
2066       (dwFlags & DIDFT_AXIS)) {
2067     BYTE axes, i;
2068     
2069 #ifdef JSIOCGAXES
2070     if (-1==ioctl(xfd,JSIOCGAXES,&axes))
2071       axes = 2;
2072 #endif
2073
2074     for (i = 0; i < axes; i++) {
2075       switch (i) {
2076       case 0:
2077         ddoi.guidType = GUID_XAxis;
2078         ddoi.dwOfs = DIJOFS_X;
2079         break;
2080       case 1:
2081         ddoi.guidType = GUID_YAxis;
2082         ddoi.dwOfs = DIJOFS_Y;
2083         break;
2084       case 2:
2085         ddoi.guidType = GUID_ZAxis;
2086         ddoi.dwOfs = DIJOFS_Z;
2087         break;
2088       default:
2089         ddoi.guidType = GUID_Unknown;
2090         ddoi.dwOfs = DIJOFS_Z + (i - 2) * sizeof(LONG);
2091       }
2092       ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << i) << WINE_JOYSTICK_AXIS_BASE) | DIDFT_ABSAXIS;
2093       sprintf(ddoi.tszName, "%d-Axis", i);
2094       _dump_OBJECTINSTANCEA(&ddoi);
2095       if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
2096     }
2097   }
2098
2099   if ((dwFlags == DIDFT_ALL) ||
2100       (dwFlags & DIDFT_BUTTON)) {
2101     BYTE buttons, i;
2102     
2103 #ifdef JSIOCGBUTTONS
2104     if (-1==ioctl(xfd,JSIOCGAXES,&buttons))
2105       buttons = 2;
2106 #endif
2107   
2108     /* The DInput SDK says that GUID_Button is only for mouse buttons but well... */
2109     ddoi.guidType = GUID_Button;
2110     
2111     for (i = 0; i < buttons; i++) {
2112       ddoi.dwOfs = DIJOFS_BUTTON(i);
2113       ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << i) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON;
2114       sprintf(ddoi.tszName, "%d-Button", i);
2115       _dump_OBJECTINSTANCEA(&ddoi);
2116       if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK;
2117     }
2118   }
2119
2120   if (xfd!=This->joyfd)
2121     close(xfd);
2122
2123   return DI_OK;
2124 }
2125
2126 /******************************************************************************
2127   *     GetProperty : get input device properties
2128   */
2129 static HRESULT WINAPI JoystickAImpl_GetProperty(LPDIRECTINPUTDEVICE2A iface,
2130                                                 REFGUID rguid,
2131                                                 LPDIPROPHEADER pdiph)
2132 {
2133   ICOM_THIS(JoystickAImpl,iface);
2134
2135   TRACE("(this=%p,%s,%p): stub!\n",
2136         iface, debugstr_guid(rguid), pdiph);
2137
2138   if (TRACE_ON(dinput))
2139     _dump_DIPROPHEADER(pdiph);
2140   
2141   if (!HIWORD(rguid)) {
2142     switch ((DWORD)rguid) {
2143     case (DWORD) DIPROP_BUFFERSIZE: {
2144       LPDIPROPDWORD     pd = (LPDIPROPDWORD)pdiph;
2145       
2146       TRACE(" return buffersize = %d\n",This->queue_len);
2147       pd->dwData = This->queue_len;
2148       break;
2149     }
2150
2151     case (DWORD) DIPROP_RANGE: {
2152       LPDIPROPRANGE pr = (LPDIPROPRANGE) pdiph;
2153
2154       if ((pdiph->dwHow == DIPH_BYID) &&
2155           (pdiph->dwObj & DIDFT_ABSAXIS)) {
2156         /* The app is querying the current range of the axis : return the lMin and lMax values */
2157         pr->lMin = This->lMin;
2158         pr->lMax = This->lMax;
2159       }
2160       
2161       break;
2162     }
2163       
2164     default:
2165       FIXME("Unknown type %ld (%s)\n",(DWORD)rguid,debugstr_guid(rguid));
2166       break;
2167     }
2168   }
2169   
2170   
2171   return DI_OK;
2172 }
2173
2174 #endif
2175
2176 /****************************************************************************/
2177 /****************************************************************************/
2178
2179 static ICOM_VTABLE(IDirectInputDevice2A) SysKeyboardAvt = 
2180 {
2181         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
2182         IDirectInputDevice2AImpl_QueryInterface,
2183         IDirectInputDevice2AImpl_AddRef,
2184         IDirectInputDevice2AImpl_Release,
2185         SysKeyboardAImpl_GetCapabilities,
2186         IDirectInputDevice2AImpl_EnumObjects,
2187         IDirectInputDevice2AImpl_GetProperty,
2188         SysKeyboardAImpl_SetProperty,
2189         SysKeyboardAImpl_Acquire,
2190         SysKeyboardAImpl_Unacquire,
2191         SysKeyboardAImpl_GetDeviceState,
2192         SysKeyboardAImpl_GetDeviceData,
2193         IDirectInputDevice2AImpl_SetDataFormat,
2194         IDirectInputDevice2AImpl_SetEventNotification,
2195         IDirectInputDevice2AImpl_SetCooperativeLevel,
2196         IDirectInputDevice2AImpl_GetObjectInfo,
2197         IDirectInputDevice2AImpl_GetDeviceInfo,
2198         IDirectInputDevice2AImpl_RunControlPanel,
2199         IDirectInputDevice2AImpl_Initialize,
2200         IDirectInputDevice2AImpl_CreateEffect,
2201         IDirectInputDevice2AImpl_EnumEffects,
2202         IDirectInputDevice2AImpl_GetEffectInfo,
2203         IDirectInputDevice2AImpl_GetForceFeedbackState,
2204         IDirectInputDevice2AImpl_SendForceFeedbackCommand,
2205         IDirectInputDevice2AImpl_EnumCreatedEffectObjects,
2206         IDirectInputDevice2AImpl_Escape,
2207         IDirectInputDevice2AImpl_Poll,
2208         IDirectInputDevice2AImpl_SendDeviceData,
2209 };
2210
2211 static ICOM_VTABLE(IDirectInputDevice2A) SysMouseAvt = 
2212 {
2213         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
2214         IDirectInputDevice2AImpl_QueryInterface,
2215         IDirectInputDevice2AImpl_AddRef,
2216         SysMouseAImpl_Release,
2217         SysMouseAImpl_GetCapabilities,
2218         SysMouseAImpl_EnumObjects,
2219         SysMouseAImpl_GetProperty,
2220         SysMouseAImpl_SetProperty,
2221         SysMouseAImpl_Acquire,
2222         SysMouseAImpl_Unacquire,
2223         SysMouseAImpl_GetDeviceState,
2224         SysMouseAImpl_GetDeviceData,
2225         SysMouseAImpl_SetDataFormat,
2226         SysMouseAImpl_SetEventNotification,
2227         SysMouseAImpl_SetCooperativeLevel,
2228         IDirectInputDevice2AImpl_GetObjectInfo,
2229         IDirectInputDevice2AImpl_GetDeviceInfo,
2230         IDirectInputDevice2AImpl_RunControlPanel,
2231         IDirectInputDevice2AImpl_Initialize,
2232         IDirectInputDevice2AImpl_CreateEffect,
2233         IDirectInputDevice2AImpl_EnumEffects,
2234         IDirectInputDevice2AImpl_GetEffectInfo,
2235         IDirectInputDevice2AImpl_GetForceFeedbackState,
2236         IDirectInputDevice2AImpl_SendForceFeedbackCommand,
2237         IDirectInputDevice2AImpl_EnumCreatedEffectObjects,
2238         IDirectInputDevice2AImpl_Escape,
2239         IDirectInputDevice2AImpl_Poll,
2240         IDirectInputDevice2AImpl_SendDeviceData,
2241 };
2242
2243 #ifdef HAVE_LINUX_22_JOYSTICK_API
2244 static ICOM_VTABLE(IDirectInputDevice2A) JoystickAvt = 
2245 {
2246         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
2247         IDirectInputDevice2AImpl_QueryInterface,
2248         IDirectInputDevice2AImpl_AddRef,
2249         JoystickAImpl_Release,
2250         JoystickAImpl_GetCapabilities,
2251         JoystickAImpl_EnumObjects,
2252         JoystickAImpl_GetProperty,
2253         JoystickAImpl_SetProperty,
2254         JoystickAImpl_Acquire,
2255         JoystickAImpl_Unacquire,
2256         JoystickAImpl_GetDeviceState,
2257         JoystickAImpl_GetDeviceData,
2258         JoystickAImpl_SetDataFormat,
2259         JoystickAImpl_SetEventNotification,
2260         IDirectInputDevice2AImpl_SetCooperativeLevel,
2261         IDirectInputDevice2AImpl_GetObjectInfo,
2262         IDirectInputDevice2AImpl_GetDeviceInfo,
2263         IDirectInputDevice2AImpl_RunControlPanel,
2264         IDirectInputDevice2AImpl_Initialize,
2265         IDirectInputDevice2AImpl_CreateEffect,
2266         IDirectInputDevice2AImpl_EnumEffects,
2267         IDirectInputDevice2AImpl_GetEffectInfo,
2268         IDirectInputDevice2AImpl_GetForceFeedbackState,
2269         IDirectInputDevice2AImpl_SendForceFeedbackCommand,
2270         IDirectInputDevice2AImpl_EnumCreatedEffectObjects,
2271         IDirectInputDevice2AImpl_Escape,
2272         JoystickAImpl_Poll,
2273         IDirectInputDevice2AImpl_SendDeviceData,
2274 };
2275 #endif