ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

joystick_linuxinput.c
Go to the documentation of this file.
00001 /*      DirectInput Joystick device
00002  *
00003  * Copyright 1998,2000 Marcus Meissner
00004  * Copyright 1998,1999 Lionel Ulmer
00005  * Copyright 2000-2001 TransGaming Technologies Inc.
00006  * Copyright 2005 Daniel Remenak
00007  *
00008  * This library is free software; you can redistribute it and/or
00009  * modify it under the terms of the GNU Lesser General Public
00010  * License as published by the Free Software Foundation; either
00011  * version 2.1 of the License, or (at your option) any later version.
00012  *
00013  * This library is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016  * Lesser General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU Lesser General Public
00019  * License along with this library; if not, write to the Free Software
00020  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00021  */
00022 
00023 #include "config.h"
00024 #include "wine/port.h"
00025 
00026 #include <assert.h>
00027 #include <stdarg.h>
00028 #include <stdio.h>
00029 #include <string.h>
00030 #include <time.h>
00031 #ifdef HAVE_UNISTD_H
00032 # include <unistd.h>
00033 #endif
00034 #ifdef HAVE_SYS_TIME_H
00035 # include <sys/time.h>
00036 #endif
00037 #include <fcntl.h>
00038 #ifdef HAVE_SYS_IOCTL_H
00039 # include <sys/ioctl.h>
00040 #endif
00041 #include <errno.h>
00042 #ifdef HAVE_SYS_ERRNO_H
00043 # include <sys/errno.h>
00044 #endif
00045 #ifdef HAVE_LINUX_INPUT_H
00046 # include <linux/input.h>
00047 # undef SW_MAX
00048 # if defined(EVIOCGBIT) && defined(EV_ABS) && defined(BTN_PINKIE)
00049 #  define HAVE_CORRECT_LINUXINPUT_H
00050 # endif
00051 #endif
00052 #ifdef HAVE_SYS_POLL_H
00053 # include <sys/poll.h>
00054 #endif
00055 
00056 #include "wine/debug.h"
00057 #include "wine/unicode.h"
00058 #include "wine/list.h"
00059 #include "windef.h"
00060 #include "winbase.h"
00061 #include "winerror.h"
00062 #include "winreg.h"
00063 #include "dinput.h"
00064 
00065 #include "dinput_private.h"
00066 #include "device_private.h"
00067 
00068 WINE_DEFAULT_DEBUG_CHANNEL(dinput);
00069 
00070 
00071 /*
00072  * Maps POV x & y event values to a DX "clock" position:
00073  *         0
00074  *   31500    4500
00075  * 27000  -1    9000
00076  *   22500   13500
00077  *       18000
00078  */
00079 DWORD joystick_map_pov(POINTL *p)
00080 {
00081     if (p->x > 0)
00082         return p->y < 0 ?  4500 : !p->y ?  9000 : 13500;
00083     else if (p->x < 0)
00084         return p->y < 0 ? 31500 : !p->y ? 27000 : 22500;
00085     else
00086         return p->y < 0 ?     0 : !p->y ?    -1 : 18000;
00087 }
00088 
00089 /*
00090  * This maps the read value (from the input event) to a value in the
00091  * 'wanted' range.
00092  * Notes:
00093  *   Dead zone is in % multiplied by a 100 (range 0..10000)
00094  */
00095 LONG joystick_map_axis(ObjProps *props, int val)
00096 {
00097     LONG ret;
00098     LONG dead_zone = MulDiv( props->lDeadZone, props->lDevMax - props->lDevMin, 10000 );
00099     LONG dev_range = props->lDevMax - props->lDevMin - dead_zone;
00100 
00101     /* Center input */
00102     val -= (props->lDevMin + props->lDevMax) / 2;
00103 
00104     /* Remove dead zone */
00105     if (abs( val ) <= dead_zone / 2)
00106         val = 0;
00107     else
00108         val = val < 0 ? val + dead_zone / 2 : val - dead_zone / 2;
00109 
00110     /* Scale and map the value from the device range into the required range */
00111     ret = MulDiv( val, props->lMax - props->lMin, dev_range ) +
00112           (props->lMin + props->lMax) / 2;
00113 
00114     /* Clamp in case or rounding errors */
00115     if      (ret > props->lMax) ret = props->lMax;
00116     else if (ret < props->lMin) ret = props->lMin;
00117 
00118     TRACE( "(%d <%d> %d) -> (%d <%d> %d): val=%d ret=%d\n",
00119            props->lDevMin, dead_zone, props->lDevMax,
00120            props->lMin, props->lDeadZone, props->lMax,
00121            val, ret );
00122 
00123     return ret;
00124 }
00125 
00126 #ifdef HAVE_CORRECT_LINUXINPUT_H
00127 
00128 #define EVDEVPREFIX "/dev/input/event"
00129 
00130 /* Wine joystick driver object instances */
00131 #define WINE_JOYSTICK_MAX_AXES    8
00132 #define WINE_JOYSTICK_MAX_POVS    4
00133 #define WINE_JOYSTICK_MAX_BUTTONS 128
00134 
00135 struct wine_input_absinfo {
00136     LONG value;
00137     LONG minimum;
00138     LONG maximum;
00139     LONG fuzz;
00140     LONG flat;
00141 };
00142 
00143 /* implemented in effect_linuxinput.c */
00144 HRESULT linuxinput_create_effect(int* fd, REFGUID rguid, struct list *parent_list_entry, LPDIRECTINPUTEFFECT* peff);
00145 HRESULT linuxinput_get_info_A(int fd, REFGUID rguid, LPDIEFFECTINFOA info);
00146 HRESULT linuxinput_get_info_W(int fd, REFGUID rguid, LPDIEFFECTINFOW info);
00147 
00148 typedef struct JoystickImpl JoystickImpl;
00149 static const IDirectInputDevice8AVtbl JoystickAvt;
00150 static const IDirectInputDevice8WVtbl JoystickWvt;
00151 
00152 struct JoyDev {
00153     char *device;
00154     char *name;
00155     GUID guid;
00156 
00157     int has_ff;
00158         int num_effects;
00159 
00160     /* data returned by EVIOCGBIT for caps, EV_ABS, EV_KEY, and EV_FF */
00161     BYTE                evbits[(EV_MAX+7)/8];
00162     BYTE                absbits[(ABS_MAX+7)/8];
00163     BYTE                keybits[(KEY_MAX+7)/8];
00164     BYTE                ffbits[(FF_MAX+7)/8];   
00165 
00166     /* data returned by the EVIOCGABS() ioctl */
00167         struct wine_input_absinfo       axes[ABS_MAX];
00168 };
00169 
00170 struct JoystickImpl
00171 {
00172         struct IDirectInputDevice2AImpl base;
00173 
00174         struct JoyDev                  *joydev;
00175 
00176     /* joystick private */
00177     int             joyfd;
00178 
00179     DIJOYSTATE2         js;
00180 
00181     ObjProps                        props[ABS_MAX];
00182 
00183     int                             axes[ABS_MAX];
00184         POINTL                          povs[4];
00185 
00186     /* LUT for KEY_ to offset in rgbButtons */
00187     BYTE                buttons[KEY_MAX];
00188 
00189     DWORD                           numAxes;
00190     DWORD                           numPOVs;
00191     DWORD                           numButtons;
00192 
00193     /* Force feedback variables */
00194         struct list                     ff_effects;
00195     int             ff_state;
00196     int             ff_autocenter;
00197     int             ff_gain;
00198 };
00199 
00200 static void fake_current_js_state(JoystickImpl *ji);
00201 static void find_joydevs(void);
00202 
00203 /* This GUID is slightly different from the linux joystick one. Take note. */
00204 static const GUID DInput_Wine_Joystick_Base_GUID = { /* 9e573eda-7734-11d2-8d4a-23903fb6bdf7 */
00205   0x9e573eda,
00206   0x7734,
00207   0x11d2,
00208   {0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf7}
00209 };
00210 
00211 #define test_bit(arr,bit) (((BYTE*)(arr))[(bit)>>3]&(1<<((bit)&7)))
00212 
00213 #define MAX_JOYDEV 64
00214 
00215 static int have_joydevs = -1;
00216 static struct JoyDev *joydevs = NULL;
00217 
00218 static void find_joydevs(void)
00219 {
00220     int i;
00221 
00222     if (InterlockedCompareExchange(&have_joydevs, 0, -1) != -1)
00223         /* Someone beat us to it */
00224         return;
00225 
00226     for (i = 0; i < MAX_JOYDEV; i++)
00227     {
00228         char buf[MAX_PATH];
00229         struct JoyDev joydev = {0};
00230         int fd;
00231         int no_ff_check = 0;
00232         int j;
00233         struct JoyDev *new_joydevs;
00234 
00235         snprintf(buf, sizeof(buf), EVDEVPREFIX"%d", i);
00236 
00237         if ((fd = open(buf, O_RDWR)) == -1)
00238         {
00239             fd = open(buf, O_RDONLY);
00240             no_ff_check = 1;
00241         }
00242 
00243         if (fd == -1)
00244         {
00245             WARN("Failed to open \"%s\": %d %s\n", buf, errno, strerror(errno));
00246             continue;
00247         }
00248 
00249         if (ioctl(fd, EVIOCGBIT(0, sizeof(joydev.evbits)), joydev.evbits) == -1)
00250         {
00251             WARN("ioct(EVIOCGBIT, 0) failed: %d %s\n", errno, strerror(errno));
00252             close(fd);
00253             continue;
00254         }
00255         if (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(joydev.absbits)), joydev.absbits) == -1)
00256         {
00257             WARN("ioct(EVIOCGBIT, EV_ABS) failed: %d %s\n", errno, strerror(errno));
00258             close(fd);
00259             continue;
00260         }
00261         if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(joydev.keybits)), joydev.keybits) == -1)
00262         {
00263             WARN("ioct(EVIOCGBIT, EV_KEY) failed: %d %s\n", errno, strerror(errno));
00264             close(fd);
00265             continue;
00266         }
00267 
00268         /* A true joystick has at least axis X and Y, and at least 1
00269          * button. copied from linux/drivers/input/joydev.c */
00270         if (!test_bit(joydev.absbits, ABS_X) || !test_bit(joydev.absbits, ABS_Y) ||
00271             !(test_bit(joydev.keybits, BTN_TRIGGER) ||
00272               test_bit(joydev.keybits, BTN_A) ||
00273               test_bit(joydev.keybits, BTN_1)))
00274         {
00275             close(fd);
00276             continue;
00277         }
00278 
00279         if (!(joydev.device = HeapAlloc(GetProcessHeap(), 0, strlen(buf) + 1)))
00280         {
00281             close(fd);
00282             continue;
00283         }
00284         strcpy(joydev.device, buf);
00285 
00286         buf[MAX_PATH - 1] = 0;
00287         if (ioctl(fd, EVIOCGNAME(MAX_PATH - 1), buf) != -1 &&
00288             (joydev.name = HeapAlloc(GetProcessHeap(), 0, strlen(buf) + 1)))
00289             strcpy(joydev.name, buf);
00290         else
00291             joydev.name = joydev.device;
00292 
00293     joydev.guid = DInput_Wine_Joystick_Base_GUID;
00294     joydev.guid.Data3 += have_joydevs;
00295 
00296         TRACE("Found a joystick on %s: %s (%s)\n", 
00297             joydev.device, joydev.name, 
00298             debugstr_guid(&joydev.guid)
00299             );
00300 
00301 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
00302         if (!no_ff_check &&
00303             test_bit(joydev.evbits, EV_FF) &&
00304             ioctl(fd, EVIOCGBIT(EV_FF, sizeof(joydev.ffbits)), joydev.ffbits) != -1 &&
00305             ioctl(fd, EVIOCGEFFECTS, &joydev.num_effects) != -1 &&
00306             joydev.num_effects > 0)
00307         {
00308         TRACE(" ... with force feedback\n");
00309         joydev.has_ff = 1;
00310         }
00311 #endif
00312 
00313         for (j = 0; j < ABS_MAX;j ++)
00314         {
00315             if (!test_bit(joydev.absbits, j)) continue;
00316             if (ioctl(fd, EVIOCGABS(j), &(joydev.axes[j])) != -1)
00317             {
00318           TRACE(" ... with axis %d: cur=%d, min=%d, max=%d, fuzz=%d, flat=%d\n",
00319           j,
00320           joydev.axes[j].value,
00321           joydev.axes[j].minimum,
00322           joydev.axes[j].maximum,
00323           joydev.axes[j].fuzz,
00324           joydev.axes[j].flat
00325           );
00326         }
00327     }
00328 
00329         if (!have_joydevs)
00330             new_joydevs = HeapAlloc(GetProcessHeap(), 0, sizeof(struct JoyDev));
00331         else
00332             new_joydevs = HeapReAlloc(GetProcessHeap(), 0, joydevs, (1 + have_joydevs) * sizeof(struct JoyDev));
00333 
00334         if (!new_joydevs)
00335         {
00336             close(fd);
00337             continue;
00338         }
00339         joydevs = new_joydevs;
00340         memcpy(joydevs + have_joydevs, &joydev, sizeof(joydev));
00341         have_joydevs++;
00342 
00343         close(fd);
00344     }
00345 }
00346 
00347 static void fill_joystick_dideviceinstanceA(LPDIDEVICEINSTANCEA lpddi, DWORD version, int id)
00348 {
00349     DWORD dwSize = lpddi->dwSize;
00350 
00351     TRACE("%d %p\n", dwSize, lpddi);
00352     memset(lpddi, 0, dwSize);
00353 
00354     lpddi->dwSize       = dwSize;
00355     lpddi->guidInstance = joydevs[id].guid;
00356     lpddi->guidProduct  = DInput_Wine_Joystick_Base_GUID;
00357     lpddi->guidFFDriver = GUID_NULL;
00358 
00359     if (version >= 0x0800)
00360         lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
00361     else
00362         lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
00363 
00364     strcpy(lpddi->tszInstanceName, joydevs[id].name);
00365     strcpy(lpddi->tszProductName, joydevs[id].device);
00366 }
00367 
00368 static void fill_joystick_dideviceinstanceW(LPDIDEVICEINSTANCEW lpddi, DWORD version, int id)
00369 {
00370     DWORD dwSize = lpddi->dwSize;
00371 
00372     TRACE("%d %p\n", dwSize, lpddi);
00373     memset(lpddi, 0, dwSize);
00374 
00375     lpddi->dwSize       = dwSize;
00376     lpddi->guidInstance = joydevs[id].guid;
00377     lpddi->guidProduct  = DInput_Wine_Joystick_Base_GUID;
00378     lpddi->guidFFDriver = GUID_NULL;
00379 
00380     if (version >= 0x0800)
00381         lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
00382     else
00383         lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
00384 
00385     MultiByteToWideChar(CP_ACP, 0, joydevs[id].name, -1, lpddi->tszInstanceName, MAX_PATH);
00386     MultiByteToWideChar(CP_ACP, 0, joydevs[id].device, -1, lpddi->tszProductName, MAX_PATH);
00387 }
00388 
00389 static BOOL joydev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, DWORD version, int id)
00390 {
00391   find_joydevs();
00392 
00393   if (id >= have_joydevs) {
00394     return FALSE;
00395   }
00396 
00397   if (!((dwDevType == 0) ||
00398         ((dwDevType == DIDEVTYPE_JOYSTICK) && (version > 0x0300 && version < 0x0800)) ||
00399         (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800))))
00400     return FALSE;
00401 
00402 #ifndef HAVE_STRUCT_FF_EFFECT_DIRECTION
00403   if (dwFlags & DIEDFL_FORCEFEEDBACK)
00404     return FALSE;
00405 #endif
00406 
00407   if (!(dwFlags & DIEDFL_FORCEFEEDBACK) || joydevs[id].has_ff) {
00408     fill_joystick_dideviceinstanceA(lpddi, version, id);
00409     return TRUE;
00410   }
00411   return FALSE;
00412 }
00413 
00414 static BOOL joydev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEW lpddi, DWORD version, int id)
00415 {
00416   find_joydevs();
00417 
00418   if (id >= have_joydevs) {
00419     return FALSE;
00420   }
00421 
00422   if (!((dwDevType == 0) ||
00423         ((dwDevType == DIDEVTYPE_JOYSTICK) && (version > 0x0300 && version < 0x0800)) ||
00424         (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800))))
00425     return FALSE;
00426 
00427 #ifndef HAVE_STRUCT_FF_EFFECT_DIRECTION
00428   if (dwFlags & DIEDFL_FORCEFEEDBACK)
00429     return FALSE;
00430 #endif
00431 
00432   if (!(dwFlags & DIEDFL_FORCEFEEDBACK) || joydevs[id].has_ff) {
00433     fill_joystick_dideviceinstanceW(lpddi, version, id);
00434     return TRUE;
00435   }
00436   return FALSE;
00437 }
00438 
00439 static JoystickImpl *alloc_device(REFGUID rguid, const void *jvt, IDirectInputImpl *dinput, unsigned short index)
00440 {
00441     JoystickImpl* newDevice;
00442     LPDIDATAFORMAT df = NULL;
00443     int i, idx = 0;
00444     char buffer[MAX_PATH+16];
00445     HKEY hkey, appkey;
00446     LONG def_deadzone = 0;
00447 
00448     newDevice = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(JoystickImpl));
00449     if (!newDevice) return NULL;
00450 
00451     newDevice->base.lpVtbl = jvt;
00452     newDevice->base.ref    = 1;
00453     newDevice->base.guid   = *rguid;
00454     newDevice->base.dinput = dinput;
00455     newDevice->joyfd       = -1;
00456     newDevice->joydev      = &joydevs[index];
00457     list_init(&newDevice->ff_effects);
00458 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
00459     newDevice->ff_state    = FF_STATUS_STOPPED;
00460 #endif
00461     /* There is no way in linux to query force feedback autocenter status.
00462        Instead, track it with ff_autocenter, and assume it's initialy
00463        enabled. */
00464     newDevice->ff_autocenter = 1;
00465     newDevice->ff_gain = 0xFFFF;
00466     InitializeCriticalSection(&newDevice->base.crit);
00467     newDevice->base.crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": JoystickImpl*->base.crit");
00468 
00469     /* get options */
00470     get_app_key(&hkey, &appkey);
00471 
00472     if (!get_config_key(hkey, appkey, "DefaultDeadZone", buffer, MAX_PATH))
00473     {
00474         def_deadzone = atoi(buffer);
00475         TRACE("setting default deadzone to: %d\n", def_deadzone);
00476     }
00477     if (appkey) RegCloseKey(appkey);
00478     if (hkey) RegCloseKey(hkey);
00479 
00480     /* Create copy of default data format */
00481     if (!(df = HeapAlloc(GetProcessHeap(), 0, c_dfDIJoystick2.dwSize))) goto failed;
00482     memcpy(df, &c_dfDIJoystick2, c_dfDIJoystick2.dwSize);
00483     if (!(df->rgodf = HeapAlloc(GetProcessHeap(), 0, df->dwNumObjs * df->dwObjSize))) goto failed;
00484 
00485     /* Supported Axis & POVs should map 1-to-1 */
00486     for (i = 0; i < WINE_JOYSTICK_MAX_AXES; i++)
00487     {
00488         if (!test_bit(newDevice->joydev->absbits, i)) {
00489             newDevice->axes[i] = -1;
00490             continue;
00491         }
00492 
00493         memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[i], df->dwObjSize);
00494         newDevice->axes[i] = idx;
00495         newDevice->props[idx].lDevMin = newDevice->joydev->axes[i].minimum;
00496         newDevice->props[idx].lDevMax = newDevice->joydev->axes[i].maximum;
00497         newDevice->props[idx].lMin    = 0;
00498         newDevice->props[idx].lMax    = 0xffff;
00499         newDevice->props[idx].lSaturation = 0;
00500         newDevice->props[idx].lDeadZone = def_deadzone;
00501 
00502         /* Linux supports force-feedback on X & Y axes only */
00503         if (newDevice->joydev->has_ff && (i == 0 || i == 1))
00504             df->rgodf[idx].dwFlags |= DIDOI_FFACTUATOR;
00505 
00506         df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(newDevice->numAxes++) | DIDFT_ABSAXIS;
00507     }
00508 
00509     for (i = 0; i < WINE_JOYSTICK_MAX_POVS; i++)
00510     {
00511         if (!test_bit(newDevice->joydev->absbits, ABS_HAT0X + i * 2) ||
00512             !test_bit(newDevice->joydev->absbits, ABS_HAT0Y + i * 2)) {
00513             newDevice->axes[ABS_HAT0X + i * 2] = newDevice->axes[ABS_HAT0Y + i * 2] = -1;
00514             continue;
00515         }
00516 
00517         memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[i + WINE_JOYSTICK_MAX_AXES], df->dwObjSize);
00518         newDevice->axes[ABS_HAT0X + i * 2] = newDevice->axes[ABS_HAT0Y + i * 2] = i;
00519         df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(newDevice->numPOVs++) | DIDFT_POV;
00520     }
00521 
00522     /* Buttons can be anywhere, so check all */
00523     for (i = 0; i < KEY_MAX && newDevice->numButtons < WINE_JOYSTICK_MAX_BUTTONS; i++)
00524     {
00525         if (!test_bit(newDevice->joydev->keybits, i)) continue;
00526 
00527         memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[newDevice->numButtons + WINE_JOYSTICK_MAX_AXES + WINE_JOYSTICK_MAX_POVS], df->dwObjSize);
00528     newDevice->buttons[i] = 0x80 | newDevice->numButtons;
00529         df->rgodf[idx  ].pguid = &GUID_Button;
00530         df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(newDevice->numButtons++) | DIDFT_PSHBUTTON;
00531     }
00532     df->dwNumObjs = idx;
00533 
00534     fake_current_js_state(newDevice);
00535 
00536     newDevice->base.data_format.wine_df = df;
00537     IDirectInput_AddRef((LPDIRECTINPUTDEVICE8A)newDevice->base.dinput);
00538     return newDevice;
00539 
00540 failed:
00541     if (df) HeapFree(GetProcessHeap(), 0, df->rgodf);
00542     HeapFree(GetProcessHeap(), 0, df);
00543     HeapFree(GetProcessHeap(), 0, newDevice);
00544     return NULL;
00545 }
00546 
00547 /******************************************************************************
00548   *     get_joystick_index : Get the joystick index from a given GUID
00549   */
00550 static unsigned short get_joystick_index(REFGUID guid)
00551 {
00552     GUID wine_joystick = DInput_Wine_Joystick_Base_GUID;
00553     GUID dev_guid = *guid;
00554 
00555     wine_joystick.Data3 = 0;
00556     dev_guid.Data3 = 0;
00557 
00558     /* for the standard joystick GUID use index 0 */
00559     if(IsEqualGUID(&GUID_Joystick,guid)) return 0;
00560 
00561     /* for the wine joystick GUIDs use the index stored in Data3 */
00562     if(IsEqualGUID(&wine_joystick, &dev_guid)) return guid->Data3 - DInput_Wine_Joystick_Base_GUID.Data3;
00563 
00564     return MAX_JOYDEV;
00565 }
00566 
00567 static HRESULT joydev_create_deviceA(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEA* pdev)
00568 {
00569     unsigned short index;
00570 
00571     find_joydevs();
00572 
00573     if ((index = get_joystick_index(rguid)) < MAX_JOYDEV &&
00574         have_joydevs && index < have_joydevs)
00575     {
00576         if ((riid == NULL) ||
00577             IsEqualGUID(&IID_IDirectInputDeviceA,  riid) ||
00578             IsEqualGUID(&IID_IDirectInputDevice2A, riid) ||
00579             IsEqualGUID(&IID_IDirectInputDevice7A, riid) ||
00580             IsEqualGUID(&IID_IDirectInputDevice8A, riid))
00581         {
00582             *pdev = (IDirectInputDeviceA*) alloc_device(rguid, &JoystickAvt, dinput, index);
00583             TRACE("Created a Joystick device (%p)\n", *pdev);
00584 
00585             if (*pdev == NULL)
00586             {
00587                 ERR("out of memory\n");
00588                 return DIERR_OUTOFMEMORY;
00589             }
00590             return DI_OK;
00591         }
00592 
00593         WARN("no interface\n");
00594         return DIERR_NOINTERFACE;
00595     }
00596 
00597     return DIERR_DEVICENOTREG;
00598 }
00599 
00600 
00601 static HRESULT joydev_create_deviceW(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEW* pdev)
00602 {
00603     unsigned short index;
00604 
00605     find_joydevs();
00606 
00607     if ((index = get_joystick_index(rguid)) < MAX_JOYDEV &&
00608         have_joydevs && index < have_joydevs)
00609     {
00610         if ((riid == NULL) ||
00611             IsEqualGUID(&IID_IDirectInputDeviceW,  riid) ||
00612             IsEqualGUID(&IID_IDirectInputDevice2W, riid) ||
00613             IsEqualGUID(&IID_IDirectInputDevice7W, riid) ||
00614             IsEqualGUID(&IID_IDirectInputDevice8W, riid))
00615         {
00616             *pdev = (IDirectInputDeviceW*) alloc_device(rguid, &JoystickWvt, dinput, index);
00617             TRACE("Created a Joystick device (%p)\n", *pdev);
00618 
00619             if (*pdev == NULL)
00620             {
00621                 ERR("out of memory\n");
00622                 return DIERR_OUTOFMEMORY;
00623             }
00624             return DI_OK;
00625         }
00626         WARN("no interface\n");
00627         return DIERR_NOINTERFACE;
00628     }
00629 
00630     WARN("invalid device GUID\n");
00631     return DIERR_DEVICENOTREG;
00632 }
00633 
00634 const struct dinput_device joystick_linuxinput_device = {
00635   "Wine Linux-input joystick driver",
00636   joydev_enum_deviceA,
00637   joydev_enum_deviceW,
00638   joydev_create_deviceA,
00639   joydev_create_deviceW
00640 };
00641 
00642 /******************************************************************************
00643   *     Acquire : gets exclusive control of the joystick
00644   */
00645 static HRESULT WINAPI JoystickAImpl_Acquire(LPDIRECTINPUTDEVICE8A iface)
00646 {
00647     JoystickImpl *This = (JoystickImpl *)iface;
00648     HRESULT res;
00649 
00650     TRACE("(this=%p)\n",This);
00651 
00652     if ((res = IDirectInputDevice2AImpl_Acquire(iface)) != DI_OK)
00653     {
00654         WARN("Failed to acquire: %x\n", res);
00655         return res;
00656     }
00657 
00658     if ((This->joyfd = open(This->joydev->device, O_RDWR)) == -1)
00659     {
00660         if ((This->joyfd = open(This->joydev->device, O_RDONLY)) == -1)
00661         {
00662             /* Couldn't open the device at all */
00663             ERR("Failed to open device %s: %d %s\n", This->joydev->device, errno, strerror(errno));
00664             IDirectInputDevice2AImpl_Unacquire(iface);
00665             return DIERR_NOTFOUND;
00666         }
00667         else
00668         {
00669             /* Couldn't open in r/w but opened in read-only. */
00670             WARN("Could not open %s in read-write mode.  Force feedback will be disabled.\n", This->joydev->device);
00671         }
00672     }
00673     else
00674     {
00675         struct input_event event;
00676 
00677         event.type = EV_FF;
00678         event.code = FF_GAIN;
00679         event.value = This->ff_gain;
00680         if (write(This->joyfd, &event, sizeof(event)) == -1)
00681             ERR("Failed to set gain (%i): %d %s\n", This->ff_gain, errno, strerror(errno));
00682         if (!This->ff_autocenter)
00683         {
00684             /* Disable autocenter. */
00685             event.code = FF_AUTOCENTER;
00686             event.value = 0;
00687             if (write(This->joyfd, &event, sizeof(event)) == -1)
00688                 ERR("Failed disabling autocenter: %d %s\n", errno, strerror(errno));
00689         }
00690     }
00691 
00692     return DI_OK;
00693 }
00694 
00695 /******************************************************************************
00696   *     Unacquire : frees the joystick
00697   */
00698 static HRESULT WINAPI JoystickAImpl_Unacquire(LPDIRECTINPUTDEVICE8A iface)
00699 {
00700     JoystickImpl *This = (JoystickImpl *)iface;
00701     HRESULT res;
00702 
00703     TRACE("(this=%p)\n",This);
00704     res = IDirectInputDevice2AImpl_Unacquire(iface);
00705     if (res==DI_OK && This->joyfd!=-1) {
00706       effect_list_item *itr;
00707       struct input_event event;
00708 
00709       /* For each known effect:
00710        * - stop it
00711        * - unload it
00712        * But, unlike DISFFC_RESET, do not release the effect.
00713        */
00714       LIST_FOR_EACH_ENTRY(itr, &This->ff_effects, effect_list_item, entry) {
00715           IDirectInputEffect_Stop(itr->ref);
00716           IDirectInputEffect_Unload(itr->ref);
00717       }
00718 
00719       /* Enable autocenter. */
00720       event.type = EV_FF;
00721       event.code = FF_AUTOCENTER;
00722       /* TODO: Read autocenter strengh before disabling it, and use it here
00723        * instead of 0xFFFF (maximum strengh).
00724        */
00725       event.value = 0xFFFF;
00726       if (write(This->joyfd, &event, sizeof(event)) == -1)
00727         ERR("Failed to set autocenter to %04x: %d %s\n", event.value, errno, strerror(errno));
00728 
00729       close(This->joyfd);
00730       This->joyfd = -1;
00731     }
00732     return res;
00733 }
00734 
00735 /* 
00736  * set the current state of the js device as it would be with the middle
00737  * values on the axes
00738  */
00739 #define CENTER_AXIS(a) \
00740     (ji->axes[a] == -1 ? 0 : joystick_map_axis( &ji->props[ji->axes[a]], \
00741                                                 ji->joydev->axes[a].value ))
00742 static void fake_current_js_state(JoystickImpl *ji)
00743 {
00744     int i;
00745 
00746     /* center the axes */
00747     ji->js.lX           = CENTER_AXIS(ABS_X);
00748     ji->js.lY           = CENTER_AXIS(ABS_Y);
00749     ji->js.lZ           = CENTER_AXIS(ABS_Z);
00750     ji->js.lRx          = CENTER_AXIS(ABS_RX);
00751     ji->js.lRy          = CENTER_AXIS(ABS_RY);
00752     ji->js.lRz          = CENTER_AXIS(ABS_RZ);
00753     ji->js.rglSlider[0] = CENTER_AXIS(ABS_THROTTLE);
00754     ji->js.rglSlider[1] = CENTER_AXIS(ABS_RUDDER);
00755 
00756     /* POV center is -1 */
00757     for (i = 0; i < 4; i++)
00758         ji->js.rgdwPOV[i] = -1;
00759 }
00760 #undef CENTER_AXIS
00761 
00762 /* convert wine format offset to user format object index */
00763 static void joy_polldev(JoystickImpl *This)
00764 {
00765     struct pollfd plfd;
00766     struct input_event ie;
00767 
00768     if (This->joyfd==-1)
00769     return;
00770 
00771     while (1)
00772     {
00773         LONG value = 0;
00774         int inst_id = -1;
00775 
00776     plfd.fd = This->joyfd;
00777     plfd.events = POLLIN;
00778 
00779     if (poll(&plfd,1,0) != 1)
00780         return;
00781 
00782     /* we have one event, so we can read */
00783     if (sizeof(ie)!=read(This->joyfd,&ie,sizeof(ie)))
00784         return;
00785 
00786     TRACE("input_event: type %d, code %d, value %d\n",ie.type,ie.code,ie.value);
00787     switch (ie.type) {
00788     case EV_KEY:    /* button */
00789         {
00790             int btn = This->buttons[ie.code];
00791 
00792             TRACE("(%p) %d -> %d\n", This, ie.code, btn);
00793             if (btn & 0x80)
00794             {
00795                 btn &= 0x7F;
00796                 inst_id = DIDFT_MAKEINSTANCE(btn) | DIDFT_PSHBUTTON;
00797                 This->js.rgbButtons[btn] = value = ie.value ? 0x80 : 0x00;
00798             }
00799             break;
00800         }
00801     case EV_ABS:
00802         {
00803             int axis = This->axes[ie.code];
00804             if (axis==-1) {
00805                 break;
00806             }
00807             inst_id = DIDFT_MAKEINSTANCE(axis) | (ie.code < ABS_HAT0X ? DIDFT_ABSAXIS : DIDFT_POV);
00808             value = joystick_map_axis(&This->props[id_to_object(This->base.data_format.wine_df, inst_id)], ie.value);
00809 
00810         switch (ie.code) {
00811             case ABS_X:         This->js.lX  = value; break;
00812             case ABS_Y:         This->js.lY  = value; break;
00813             case ABS_Z:         This->js.lZ  = value; break;
00814             case ABS_RX:        This->js.lRx = value; break;
00815             case ABS_RY:        This->js.lRy = value; break;
00816             case ABS_RZ:        This->js.lRz = value; break;
00817             case ABS_THROTTLE:  This->js.rglSlider[0] = value; break;
00818             case ABS_RUDDER:    This->js.rglSlider[1] = value; break;
00819             case ABS_HAT0X: case ABS_HAT0Y: case ABS_HAT1X: case ABS_HAT1Y:
00820             case ABS_HAT2X: case ABS_HAT2Y: case ABS_HAT3X: case ABS_HAT3Y:
00821             {
00822                 int idx = (ie.code - ABS_HAT0X) / 2;
00823 
00824                 if (ie.code % 2)
00825                     This->povs[idx].y = ie.value;
00826                 else
00827                     This->povs[idx].x = ie.value;
00828 
00829                 This->js.rgdwPOV[idx] = value = joystick_map_pov(&This->povs[idx]);
00830                 break;
00831             }
00832         default:
00833         FIXME("unhandled joystick axis event (code %d, value %d)\n",ie.code,ie.value);
00834         }
00835         break;
00836         }
00837 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
00838     case EV_FF_STATUS:
00839         This->ff_state = ie.value;
00840         break;
00841 #endif
00842 #ifdef EV_SYN
00843     case EV_SYN:
00844         /* there is nothing to do */
00845         break;
00846 #endif
00847     default:
00848         FIXME("joystick cannot handle type %d event (code %d)\n",ie.type,ie.code);
00849         break;
00850     }
00851         if (inst_id >= 0)
00852             queue_event((LPDIRECTINPUTDEVICE8A)This,
00853                         id_to_offset(&This->base.data_format, inst_id),
00854                         value, ie.time.tv_usec, This->base.dinput->evsequence++);
00855     }
00856 }
00857 
00858 /******************************************************************************
00859   *     GetDeviceState : returns the "state" of the joystick.
00860   *
00861   */
00862 static HRESULT WINAPI JoystickAImpl_GetDeviceState(
00863     LPDIRECTINPUTDEVICE8A iface,DWORD len,LPVOID ptr
00864 ) {
00865     JoystickImpl *This = (JoystickImpl *)iface;
00866 
00867     TRACE("(this=%p,0x%08x,%p)\n", This, len, ptr);
00868 
00869     if (!This->base.acquired)
00870     {
00871         WARN("not acquired\n");
00872         return DIERR_NOTACQUIRED;
00873     }
00874 
00875     joy_polldev(This);
00876 
00877     /* convert and copy data to user supplied buffer */
00878     fill_DataFormat(ptr, len, &This->js, &This->base.data_format);
00879 
00880     return DI_OK;
00881 }
00882 
00883 /******************************************************************************
00884   *     SetProperty : change input device properties
00885   */
00886 static HRESULT WINAPI JoystickAImpl_SetProperty(LPDIRECTINPUTDEVICE8A iface,
00887                         REFGUID rguid,
00888                         LPCDIPROPHEADER ph)
00889 {
00890   JoystickImpl *This = (JoystickImpl *)iface;
00891 
00892   if (!ph) {
00893     WARN("invalid argument\n");
00894     return DIERR_INVALIDPARAM;
00895   }
00896 
00897   TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(rguid),ph);
00898   TRACE("ph.dwSize = %d, ph.dwHeaderSize =%d, ph.dwObj = %d, ph.dwHow= %d\n",
00899         ph->dwSize, ph->dwHeaderSize, ph->dwObj, ph->dwHow);
00900 
00901   if (!HIWORD(rguid)) {
00902     switch (LOWORD(rguid)) {
00903     case (DWORD_PTR)DIPROP_RANGE: {
00904       LPCDIPROPRANGE pr = (LPCDIPROPRANGE)ph;
00905 
00906       if (ph->dwHow == DIPH_DEVICE) {
00907         DWORD i;
00908         TRACE("proprange(%d,%d) all\n", pr->lMin, pr->lMax);
00909         for (i = 0; i < This->base.data_format.wine_df->dwNumObjs; i++) {
00910           /* Scale dead-zone */
00911           This->props[i].lDeadZone = MulDiv(This->props[i].lDeadZone, pr->lMax - pr->lMin,
00912                                             This->props[i].lMax - This->props[i].lMin);
00913           This->props[i].lMin = pr->lMin;
00914           This->props[i].lMax = pr->lMax;
00915         }
00916       } else {
00917         int obj = find_property(&This->base.data_format, ph);
00918 
00919         TRACE("proprange(%d,%d) obj=%d\n", pr->lMin, pr->lMax, obj);
00920         if (obj >= 0) {
00921           /* Scale dead-zone */
00922           This->props[obj].lDeadZone = MulDiv(This->props[obj].lDeadZone, pr->lMax - pr->lMin,
00923                                               This->props[obj].lMax - This->props[obj].lMin);
00924           This->props[obj].lMin = pr->lMin;
00925           This->props[obj].lMax = pr->lMax;
00926         }
00927       }
00928       fake_current_js_state(This);
00929       break;
00930     }
00931     case (DWORD_PTR)DIPROP_DEADZONE: {
00932       LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph;
00933       if (ph->dwHow == DIPH_DEVICE) {
00934         DWORD i;
00935         TRACE("deadzone(%d) all\n", pd->dwData);
00936         for (i = 0; i < This->base.data_format.wine_df->dwNumObjs; i++) {
00937           This->props[i].lDeadZone = pd->dwData;
00938         }
00939       } else {
00940         int obj = find_property(&This->base.data_format, ph);
00941 
00942         TRACE("deadzone(%d) obj=%d\n", pd->dwData, obj);
00943         if (obj >= 0) {
00944           This->props[obj].lDeadZone = pd->dwData;
00945         }
00946       }
00947       fake_current_js_state(This);
00948       break;
00949     }
00950     case (DWORD_PTR)DIPROP_CALIBRATIONMODE: {
00951       LPCDIPROPDWORD    pd = (LPCDIPROPDWORD)ph;
00952       FIXME("DIPROP_CALIBRATIONMODE(%d)\n", pd->dwData);
00953       break;
00954     }
00955     case (DWORD_PTR)DIPROP_AUTOCENTER: {
00956       LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph;
00957 
00958       TRACE("autocenter(%d)\n", pd->dwData);
00959       This->ff_autocenter = pd->dwData == DIPROPAUTOCENTER_ON;
00960 
00961       break;
00962     }
00963     case (DWORD_PTR)DIPROP_SATURATION: {
00964       LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph;
00965 
00966       if (ph->dwHow == DIPH_DEVICE) {
00967         DWORD i;
00968 
00969         TRACE("saturation(%d) all\n", pd->dwData);
00970         for (i = 0; i < This->base.data_format.wine_df->dwNumObjs; i++)
00971           This->props[i].lSaturation = pd->dwData;
00972       } else {
00973           int obj = find_property(&This->base.data_format, ph);
00974 
00975           if (obj < 0) return DIERR_OBJECTNOTFOUND;
00976 
00977           TRACE("saturation(%d) obj=%d\n", pd->dwData, obj);
00978           This->props[obj].lSaturation = pd->dwData;
00979       }
00980       fake_current_js_state(This);
00981       break;
00982     }
00983     case (DWORD_PTR)DIPROP_FFGAIN: {
00984       LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph;
00985 
00986       TRACE("DIPROP_FFGAIN(%d)\n", pd->dwData);
00987       This->ff_gain = MulDiv(pd->dwData, 0xFFFF, 10000);
00988       if (This->base.acquired) {
00989         /* Update immediately. */
00990         struct input_event event;
00991 
00992         event.type = EV_FF;
00993         event.code = FF_GAIN;
00994         event.value = This->ff_gain;
00995         if (write(This->joyfd, &event, sizeof(event)) == -1)
00996           ERR("Failed to set gain (%i): %d %s\n", This->ff_gain, errno, strerror(errno));
00997       }
00998       break;
00999     }
01000     default:
01001       return IDirectInputDevice2AImpl_SetProperty(iface, rguid, ph);
01002     }
01003   }
01004   return DI_OK;
01005 }
01006 
01007 static HRESULT WINAPI JoystickAImpl_GetCapabilities(
01008     LPDIRECTINPUTDEVICE8A iface,
01009     LPDIDEVCAPS lpDIDevCaps)
01010 {
01011     JoystickImpl *This = (JoystickImpl *)iface;
01012 
01013     TRACE("%p->(%p)\n",iface,lpDIDevCaps);
01014 
01015     if (!lpDIDevCaps) {
01016     WARN("invalid pointer\n");
01017     return E_POINTER;
01018     }
01019 
01020     if (lpDIDevCaps->dwSize != sizeof(DIDEVCAPS)) {
01021         WARN("invalid argument\n");
01022         return DIERR_INVALIDPARAM;
01023     }
01024 
01025     lpDIDevCaps->dwFlags    = DIDC_ATTACHED;
01026     if (This->base.dinput->dwVersion >= 0x0800)
01027         lpDIDevCaps->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
01028     else
01029         lpDIDevCaps->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
01030 
01031     if (This->joydev->has_ff) 
01032      lpDIDevCaps->dwFlags |= DIDC_FORCEFEEDBACK;
01033 
01034     lpDIDevCaps->dwAxes = This->numAxes;
01035     lpDIDevCaps->dwButtons = This->numButtons;
01036     lpDIDevCaps->dwPOVs = This->numPOVs;
01037 
01038     return DI_OK;
01039 }
01040 
01041 static HRESULT WINAPI JoystickAImpl_Poll(LPDIRECTINPUTDEVICE8A iface)
01042 {
01043     JoystickImpl *This = (JoystickImpl *)iface;
01044 
01045     TRACE("(%p)\n",This);
01046 
01047     if (!This->base.acquired)
01048         return DIERR_NOTACQUIRED;
01049 
01050     joy_polldev(This);
01051     return DI_OK;
01052 }
01053 
01054 /******************************************************************************
01055   *     GetProperty : get input device properties
01056   */
01057 static HRESULT WINAPI JoystickAImpl_GetProperty(LPDIRECTINPUTDEVICE8A iface,
01058                         REFGUID rguid,
01059                         LPDIPROPHEADER pdiph)
01060 {
01061     JoystickImpl *This = (JoystickImpl *)iface;
01062 
01063     TRACE("(this=%p,%s,%p)\n", iface, debugstr_guid(rguid), pdiph);
01064     _dump_DIPROPHEADER(pdiph);
01065 
01066     if (HIWORD(rguid)) return DI_OK;
01067 
01068     switch (LOWORD(rguid)) {
01069     case (DWORD_PTR) DIPROP_RANGE:
01070     {
01071         LPDIPROPRANGE pr = (LPDIPROPRANGE) pdiph;
01072         int obj = find_property(&This->base.data_format, pdiph);
01073 
01074         if (obj < 0) return DIERR_OBJECTNOTFOUND;
01075 
01076         pr->lMin = This->props[obj].lMin;
01077         pr->lMax = This->props[obj].lMax;
01078     TRACE("range(%d, %d) obj=%d\n", pr->lMin, pr->lMax, obj);
01079         break;
01080     }
01081     case (DWORD_PTR) DIPROP_DEADZONE:
01082     {
01083         LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph;
01084         int obj = find_property(&This->base.data_format, pdiph);
01085 
01086         if (obj < 0) return DIERR_OBJECTNOTFOUND;
01087 
01088         pd->dwData = This->props[obj].lDeadZone;
01089         TRACE("deadzone(%d) obj=%d\n", pd->dwData, obj);
01090         break;
01091     }
01092     case (DWORD_PTR) DIPROP_SATURATION:
01093     {
01094         LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph;
01095         int obj = find_property(&This->base.data_format, pdiph);
01096 
01097         if (obj < 0) return DIERR_OBJECTNOTFOUND;
01098 
01099         pd->dwData = This->props[obj].lSaturation;
01100         TRACE("saturation(%d) obj=%d\n", pd->dwData, obj);
01101         break;
01102     }
01103     case (DWORD_PTR) DIPROP_AUTOCENTER:
01104     {
01105         LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph;
01106 
01107         pd->dwData = This->ff_autocenter ? DIPROPAUTOCENTER_ON : DIPROPAUTOCENTER_OFF;
01108         TRACE("autocenter(%d)\n", pd->dwData);
01109         break;
01110     }
01111     case (DWORD_PTR) DIPROP_FFGAIN:
01112     {
01113         LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph;
01114 
01115         pd->dwData = MulDiv(This->ff_gain, 10000, 0xFFFF);
01116         TRACE("DIPROP_FFGAIN(%d)\n", pd->dwData);
01117         break;
01118     }
01119 
01120     default:
01121         return IDirectInputDevice2AImpl_GetProperty(iface, rguid, pdiph);
01122     }
01123 
01124     return DI_OK;
01125 }
01126 
01127 /******************************************************************************
01128   *     GetObjectInfo : get information about a device object such as a button
01129   *                     or axis
01130   */
01131 static HRESULT WINAPI JoystickWImpl_GetObjectInfo(LPDIRECTINPUTDEVICE8W iface,
01132         LPDIDEVICEOBJECTINSTANCEW pdidoi, DWORD dwObj, DWORD dwHow)
01133 {
01134     static const WCHAR axisW[] = {'A','x','i','s',' ','%','d',0};
01135     static const WCHAR povW[] = {'P','O','V',' ','%','d',0};
01136     static const WCHAR buttonW[] = {'B','u','t','t','o','n',' ','%','d',0};
01137     HRESULT res;
01138 
01139     res = IDirectInputDevice2WImpl_GetObjectInfo(iface, pdidoi, dwObj, dwHow);
01140     if (res != DI_OK) return res;
01141 
01142     if      (pdidoi->dwType & DIDFT_AXIS)
01143         sprintfW(pdidoi->tszName, axisW, DIDFT_GETINSTANCE(pdidoi->dwType));
01144     else if (pdidoi->dwType & DIDFT_POV)
01145         sprintfW(pdidoi->tszName, povW, DIDFT_GETINSTANCE(pdidoi->dwType));
01146     else if (pdidoi->dwType & DIDFT_BUTTON)
01147         sprintfW(pdidoi->tszName, buttonW, DIDFT_GETINSTANCE(pdidoi->dwType));
01148 
01149     _dump_OBJECTINSTANCEW(pdidoi);
01150     return res;
01151 }
01152 
01153 static HRESULT WINAPI JoystickAImpl_GetObjectInfo(LPDIRECTINPUTDEVICE8A iface,
01154         LPDIDEVICEOBJECTINSTANCEA pdidoi, DWORD dwObj, DWORD dwHow)
01155 {
01156     HRESULT res;
01157     DIDEVICEOBJECTINSTANCEW didoiW;
01158     DWORD dwSize = pdidoi->dwSize;
01159 
01160     didoiW.dwSize = sizeof(didoiW);
01161     res = JoystickWImpl_GetObjectInfo((LPDIRECTINPUTDEVICE8W)iface, &didoiW, dwObj, dwHow);
01162     if (res != DI_OK) return res;
01163 
01164     memset(pdidoi, 0, pdidoi->dwSize);
01165     memcpy(pdidoi, &didoiW, FIELD_OFFSET(DIDEVICEOBJECTINSTANCEW, tszName));
01166     pdidoi->dwSize = dwSize;
01167     WideCharToMultiByte(CP_ACP, 0, didoiW.tszName, -1, pdidoi->tszName,
01168                         sizeof(pdidoi->tszName), NULL, NULL);
01169 
01170     return res;
01171 }
01172 
01173 /****************************************************************************** 
01174   * CreateEffect - Create a new FF effect with the specified params
01175   */
01176 static HRESULT WINAPI JoystickAImpl_CreateEffect(LPDIRECTINPUTDEVICE8A iface,
01177                          REFGUID rguid,
01178                          LPCDIEFFECT lpeff,
01179                          LPDIRECTINPUTEFFECT *ppdef,
01180                          LPUNKNOWN pUnkOuter)
01181 {
01182 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
01183     effect_list_item* new_effect = NULL;
01184     HRESULT retval = DI_OK;
01185 #endif
01186 
01187     JoystickImpl* This = (JoystickImpl*)iface;
01188     TRACE("(this=%p,%p,%p,%p,%p)\n", This, rguid, lpeff, ppdef, pUnkOuter);
01189 
01190 #ifndef HAVE_STRUCT_FF_EFFECT_DIRECTION
01191     TRACE("not available (compiled w/o ff support)\n");
01192     *ppdef = NULL;
01193     return DI_OK;
01194 #else
01195 
01196     if (!(new_effect = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_effect))))
01197         return DIERR_OUTOFMEMORY;
01198 
01199     retval = linuxinput_create_effect(&This->joyfd, rguid, &new_effect->entry, &new_effect->ref);
01200     if (retval != DI_OK)
01201     {
01202         HeapFree(GetProcessHeap(), 0, new_effect);
01203         return retval;
01204     }
01205 
01206     if (lpeff != NULL)
01207     {
01208         retval = IDirectInputEffect_SetParameters(new_effect->ref, lpeff, 0);
01209 
01210         if (retval != DI_OK && retval != DI_DOWNLOADSKIPPED)
01211         {
01212             HeapFree(GetProcessHeap(), 0, new_effect);
01213             return retval;
01214         }
01215     }
01216 
01217     list_add_tail(&This->ff_effects, &new_effect->entry);
01218     *ppdef = new_effect->ref;
01219 
01220     if (pUnkOuter != NULL)
01221     FIXME("Interface aggregation not implemented.\n");
01222 
01223     return DI_OK;
01224 
01225 #endif /* HAVE_STRUCT_FF_EFFECT_DIRECTION */
01226 } 
01227 
01228 /*******************************************************************************
01229  *  EnumEffects - Enumerate available FF effects
01230  */
01231 static HRESULT WINAPI JoystickAImpl_EnumEffects(LPDIRECTINPUTDEVICE8A iface,
01232                         LPDIENUMEFFECTSCALLBACKA lpCallback,
01233                         LPVOID pvRef,
01234                         DWORD dwEffType)
01235 {
01236 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
01237     DIEFFECTINFOA dei; /* feif */
01238     DWORD type = DIEFT_GETTYPE(dwEffType);
01239     JoystickImpl* This = (JoystickImpl*)iface;
01240 
01241     TRACE("(this=%p,%p,%d) type=%d\n", This, pvRef, dwEffType, type);
01242 
01243     dei.dwSize = sizeof(DIEFFECTINFOA);          
01244 
01245     if ((type == DIEFT_ALL || type == DIEFT_CONSTANTFORCE)
01246     && test_bit(This->joydev->ffbits, FF_CONSTANT)) {
01247     IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_ConstantForce);
01248     (*lpCallback)(&dei, pvRef);
01249     }
01250 
01251     if ((type == DIEFT_ALL || type == DIEFT_PERIODIC)
01252     && test_bit(This->joydev->ffbits, FF_PERIODIC)) {
01253     if (test_bit(This->joydev->ffbits, FF_SQUARE)) {
01254         IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Square);
01255         (*lpCallback)(&dei, pvRef);
01256     }
01257     if (test_bit(This->joydev->ffbits, FF_SINE)) {
01258             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Sine);
01259         (*lpCallback)(&dei, pvRef);
01260     }
01261     if (test_bit(This->joydev->ffbits, FF_TRIANGLE)) {
01262         IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Triangle);
01263         (*lpCallback)(&dei, pvRef);
01264     }
01265     if (test_bit(This->joydev->ffbits, FF_SAW_UP)) {
01266         IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_SawtoothUp);
01267         (*lpCallback)(&dei, pvRef);
01268     }
01269     if (test_bit(This->joydev->ffbits, FF_SAW_DOWN)) {
01270         IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_SawtoothDown);
01271         (*lpCallback)(&dei, pvRef);
01272     }
01273     } 
01274 
01275     if ((type == DIEFT_ALL || type == DIEFT_RAMPFORCE)
01276     && test_bit(This->joydev->ffbits, FF_RAMP)) {
01277         IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_RampForce);
01278         (*lpCallback)(&dei, pvRef);
01279     }
01280 
01281     if (type == DIEFT_ALL || type == DIEFT_CONDITION) {
01282     if (test_bit(This->joydev->ffbits, FF_SPRING)) {
01283         IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Spring);
01284         (*lpCallback)(&dei, pvRef);
01285     }
01286     if (test_bit(This->joydev->ffbits, FF_DAMPER)) {
01287         IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Damper);
01288         (*lpCallback)(&dei, pvRef);
01289     }
01290     if (test_bit(This->joydev->ffbits, FF_INERTIA)) {
01291         IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Inertia);
01292         (*lpCallback)(&dei, pvRef);
01293     }
01294     if (test_bit(This->joydev->ffbits, FF_FRICTION)) {
01295         IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Friction);
01296         (*lpCallback)(&dei, pvRef);
01297     }
01298     }
01299 
01300 #endif
01301 
01302     return DI_OK;
01303 }
01304 
01305 static HRESULT WINAPI JoystickWImpl_EnumEffects(LPDIRECTINPUTDEVICE8W iface,
01306                                                 LPDIENUMEFFECTSCALLBACKW lpCallback,
01307                                                 LPVOID pvRef,
01308                                                 DWORD dwEffType)
01309 {
01310 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
01311     /* seems silly to duplicate all this code but all the structures and functions
01312      * are actually different (A/W) */
01313     DIEFFECTINFOW dei; /* feif */
01314     DWORD type = DIEFT_GETTYPE(dwEffType);
01315     JoystickImpl* This = (JoystickImpl*)iface;
01316     int xfd = This->joyfd;
01317 
01318     TRACE("(this=%p,%p,%d) type=%d fd=%d\n", This, pvRef, dwEffType, type, xfd);
01319 
01320     dei.dwSize = sizeof(DIEFFECTINFOW);          
01321 
01322     if ((type == DIEFT_ALL || type == DIEFT_CONSTANTFORCE)
01323     && test_bit(This->joydev->ffbits, FF_CONSTANT)) {
01324     IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_ConstantForce);
01325     (*lpCallback)(&dei, pvRef);
01326     }
01327 
01328     if ((type == DIEFT_ALL || type == DIEFT_PERIODIC)
01329     && test_bit(This->joydev->ffbits, FF_PERIODIC)) {
01330     if (test_bit(This->joydev->ffbits, FF_SQUARE)) {
01331         IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Square);
01332         (*lpCallback)(&dei, pvRef);
01333     }
01334     if (test_bit(This->joydev->ffbits, FF_SINE)) {
01335             IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Sine);
01336         (*lpCallback)(&dei, pvRef);
01337     }
01338     if (test_bit(This->joydev->ffbits, FF_TRIANGLE)) {
01339         IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Triangle);
01340         (*lpCallback)(&dei, pvRef);
01341     }
01342     if (test_bit(This->joydev->ffbits, FF_SAW_UP)) {
01343         IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_SawtoothUp);
01344         (*lpCallback)(&dei, pvRef);
01345     }
01346     if (test_bit(This->joydev->ffbits, FF_SAW_DOWN)) {
01347         IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_SawtoothDown);
01348         (*lpCallback)(&dei, pvRef);
01349     }
01350     } 
01351 
01352     if ((type == DIEFT_ALL || type == DIEFT_RAMPFORCE)
01353     && test_bit(This->joydev->ffbits, FF_RAMP)) {
01354         IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_RampForce);
01355         (*lpCallback)(&dei, pvRef);
01356     }
01357 
01358     if (type == DIEFT_ALL || type == DIEFT_CONDITION) {
01359     if (test_bit(This->joydev->ffbits, FF_SPRING)) {
01360         IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Spring);
01361         (*lpCallback)(&dei, pvRef);
01362     }
01363     if (test_bit(This->joydev->ffbits, FF_DAMPER)) {
01364         IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Damper);
01365         (*lpCallback)(&dei, pvRef);
01366     }
01367     if (test_bit(This->joydev->ffbits, FF_INERTIA)) {
01368         IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Inertia);
01369         (*lpCallback)(&dei, pvRef);
01370     }
01371     if (test_bit(This->joydev->ffbits, FF_FRICTION)) {
01372         IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Friction);
01373         (*lpCallback)(&dei, pvRef);
01374     }
01375     }
01376 
01377     /* return to unacquired state if that's where it was */
01378     if (xfd == -1)
01379     IDirectInputDevice8_Unacquire(iface);
01380 #endif
01381 
01382     return DI_OK;
01383 }
01384 
01385 /*******************************************************************************
01386  *      GetEffectInfo - Get information about a particular effect 
01387  */
01388 static HRESULT WINAPI JoystickAImpl_GetEffectInfo(LPDIRECTINPUTDEVICE8A iface,
01389                           LPDIEFFECTINFOA pdei,
01390                           REFGUID guid)
01391 {
01392     JoystickImpl* This = (JoystickImpl*)iface;
01393 
01394     TRACE("(this=%p,%p,%s)\n", This, pdei, _dump_dinput_GUID(guid));
01395 
01396 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
01397     return linuxinput_get_info_A(This->joyfd, guid, pdei); 
01398 #else
01399     return DI_OK;
01400 #endif
01401 }
01402 
01403 static HRESULT WINAPI JoystickWImpl_GetEffectInfo(LPDIRECTINPUTDEVICE8W iface,
01404                                                   LPDIEFFECTINFOW pdei,
01405                                                   REFGUID guid)
01406 {
01407     JoystickImpl* This = (JoystickImpl*)iface;
01408             
01409     TRACE("(this=%p,%p,%s)\n", This, pdei, _dump_dinput_GUID(guid));
01410         
01411 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
01412     return linuxinput_get_info_W(This->joyfd, guid, pdei);
01413 #else
01414     return DI_OK;
01415 #endif
01416 }
01417 
01418 /*******************************************************************************
01419  *      GetForceFeedbackState - Get information about the device's FF state 
01420  */
01421 static HRESULT WINAPI JoystickAImpl_GetForceFeedbackState(
01422     LPDIRECTINPUTDEVICE8A iface,
01423     LPDWORD pdwOut)
01424 {
01425     JoystickImpl* This = (JoystickImpl*)iface;
01426 
01427     TRACE("(this=%p,%p)\n", This, pdwOut);
01428 
01429     (*pdwOut) = 0;
01430 
01431 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
01432     /* DIGFFS_STOPPED is the only mandatory flag to report */
01433     if (This->ff_state == FF_STATUS_STOPPED)
01434     (*pdwOut) |= DIGFFS_STOPPED;
01435 #endif
01436 
01437     return DI_OK;
01438 }
01439 
01440 /*******************************************************************************
01441  *      SendForceFeedbackCommand - Send a command to the device's FF system
01442  */
01443 static HRESULT WINAPI JoystickAImpl_SendForceFeedbackCommand(
01444     LPDIRECTINPUTDEVICE8A iface,
01445     DWORD dwFlags)
01446 {
01447     JoystickImpl* This = (JoystickImpl*)iface;
01448     TRACE("(this=%p,%d)\n", This, dwFlags);
01449 
01450 #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION
01451     switch (dwFlags)
01452     {
01453     case DISFFC_STOPALL:
01454     {
01455     /* Stop all effects */
01456         effect_list_item *itr;
01457 
01458         LIST_FOR_EACH_ENTRY(itr, &This->ff_effects, effect_list_item, entry)
01459             IDirectInputEffect_Stop(itr->ref);
01460         break;
01461     }
01462 
01463     case DISFFC_RESET:
01464     {
01465         effect_list_item *itr, *ptr;
01466 
01467     /* Stop, unload, release and free all effects */
01468     /* This returns the device to its "bare" state */
01469         LIST_FOR_EACH_ENTRY_SAFE(itr, ptr, &This->ff_effects, effect_list_item, entry)
01470             IDirectInputEffect_Release(itr->ref);
01471         break;
01472     }
01473     case DISFFC_PAUSE:
01474     case DISFFC_CONTINUE:
01475     FIXME("No support for Pause or Continue in linux\n");
01476         break;
01477 
01478     case DISFFC_SETACTUATORSOFF:
01479     case DISFFC_SETACTUATORSON:
01480         FIXME("No direct actuator control in linux\n");
01481         break;
01482 
01483     default:
01484     FIXME("Unknown Force Feedback Command!\n");
01485     return DIERR_INVALIDPARAM;
01486     }
01487     return DI_OK;
01488 #else
01489     return DIERR_UNSUPPORTED;
01490 #endif
01491 }
01492 
01493 /*******************************************************************************
01494  *      EnumCreatedEffectObjects - Enumerate all the effects that have been
01495  *      created for this device.
01496  */
01497 static HRESULT WINAPI JoystickAImpl_EnumCreatedEffectObjects(
01498     LPDIRECTINPUTDEVICE8A iface,
01499     LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback,
01500     LPVOID pvRef,
01501     DWORD dwFlags)
01502 {
01503     /* this function is safe to call on non-ff-enabled builds */
01504     JoystickImpl* This = (JoystickImpl*)iface;
01505     effect_list_item *itr, *ptr;
01506 
01507     TRACE("(this=%p,%p,%p,%d)\n", This, lpCallback, pvRef, dwFlags);
01508 
01509     if (!lpCallback)
01510     return DIERR_INVALIDPARAM;
01511 
01512     if (dwFlags != 0)
01513     FIXME("Flags specified, but no flags exist yet (DX9)!\n");
01514 
01515     LIST_FOR_EACH_ENTRY_SAFE(itr, ptr, &This->ff_effects, effect_list_item, entry)
01516         (*lpCallback)(itr->ref, pvRef);
01517 
01518     return DI_OK;
01519 }
01520 
01521 /******************************************************************************
01522   *     GetDeviceInfo : get information about a device's identity
01523   */
01524 static HRESULT WINAPI JoystickAImpl_GetDeviceInfo(LPDIRECTINPUTDEVICE8A iface,
01525                                                   LPDIDEVICEINSTANCEA pdidi)
01526 {
01527     JoystickImpl *This = (JoystickImpl *)iface;
01528 
01529     TRACE("(%p) %p\n", This, pdidi);
01530 
01531     if (pdidi == NULL) return E_POINTER;
01532     if ((pdidi->dwSize != sizeof(DIDEVICEINSTANCE_DX3A)) &&
01533         (pdidi->dwSize != sizeof(DIDEVICEINSTANCEA)))
01534         return DIERR_INVALIDPARAM;
01535 
01536     fill_joystick_dideviceinstanceA(pdidi, This->base.dinput->dwVersion,
01537                                     get_joystick_index(&This->base.guid));
01538     return DI_OK;
01539 }
01540 
01541 static HRESULT WINAPI JoystickWImpl_GetDeviceInfo(LPDIRECTINPUTDEVICE8W iface,
01542                                                   LPDIDEVICEINSTANCEW pdidi)
01543 {
01544     JoystickImpl *This = (JoystickImpl *)iface;
01545 
01546     TRACE("(%p) %p\n", This, pdidi);
01547 
01548     if (pdidi == NULL) return E_POINTER;
01549     if ((pdidi->dwSize != sizeof(DIDEVICEINSTANCE_DX3W)) &&
01550         (pdidi->dwSize != sizeof(DIDEVICEINSTANCEW)))
01551         return DIERR_INVALIDPARAM;
01552 
01553     fill_joystick_dideviceinstanceW(pdidi, This->base.dinput->dwVersion,
01554                                     get_joystick_index(&This->base.guid));
01555     return DI_OK;
01556 }
01557 
01558 static const IDirectInputDevice8AVtbl JoystickAvt =
01559 {
01560     IDirectInputDevice2AImpl_QueryInterface,
01561     IDirectInputDevice2AImpl_AddRef,
01562         IDirectInputDevice2AImpl_Release,
01563     JoystickAImpl_GetCapabilities,
01564         IDirectInputDevice2AImpl_EnumObjects,
01565     JoystickAImpl_GetProperty,
01566     JoystickAImpl_SetProperty,
01567     JoystickAImpl_Acquire,
01568     JoystickAImpl_Unacquire,
01569     JoystickAImpl_GetDeviceState,
01570     IDirectInputDevice2AImpl_GetDeviceData,
01571         IDirectInputDevice2AImpl_SetDataFormat,
01572     IDirectInputDevice2AImpl_SetEventNotification,
01573     IDirectInputDevice2AImpl_SetCooperativeLevel,
01574         JoystickAImpl_GetObjectInfo,
01575     JoystickAImpl_GetDeviceInfo,
01576     IDirectInputDevice2AImpl_RunControlPanel,
01577     IDirectInputDevice2AImpl_Initialize,
01578     JoystickAImpl_CreateEffect,
01579     JoystickAImpl_EnumEffects,
01580     JoystickAImpl_GetEffectInfo,
01581     JoystickAImpl_GetForceFeedbackState,
01582     JoystickAImpl_SendForceFeedbackCommand,
01583     JoystickAImpl_EnumCreatedEffectObjects,
01584     IDirectInputDevice2AImpl_Escape,
01585     JoystickAImpl_Poll,
01586     IDirectInputDevice2AImpl_SendDeviceData,
01587     IDirectInputDevice7AImpl_EnumEffectsInFile,
01588         IDirectInputDevice7AImpl_WriteEffectToFile,
01589         IDirectInputDevice8AImpl_BuildActionMap,
01590         IDirectInputDevice8AImpl_SetActionMap,
01591         IDirectInputDevice8AImpl_GetImageInfo
01592 };
01593 
01594 #if !defined(__STRICT_ANSI__) && defined(__GNUC__)
01595 # define XCAST(fun) (typeof(JoystickWvt.fun))
01596 #else
01597 # define XCAST(fun) (void*)
01598 #endif
01599 
01600 static const IDirectInputDevice8WVtbl JoystickWvt =
01601 {
01602     IDirectInputDevice2WImpl_QueryInterface,
01603     XCAST(AddRef)IDirectInputDevice2AImpl_AddRef,
01604         XCAST(Release)IDirectInputDevice2AImpl_Release,
01605     XCAST(GetCapabilities)JoystickAImpl_GetCapabilities,
01606         IDirectInputDevice2WImpl_EnumObjects,
01607     XCAST(GetProperty)JoystickAImpl_GetProperty,
01608     XCAST(SetProperty)JoystickAImpl_SetProperty,
01609     XCAST(Acquire)JoystickAImpl_Acquire,
01610     XCAST(Unacquire)JoystickAImpl_Unacquire,
01611     XCAST(GetDeviceState)JoystickAImpl_GetDeviceState,
01612     XCAST(GetDeviceData)IDirectInputDevice2AImpl_GetDeviceData,
01613         XCAST(SetDataFormat)IDirectInputDevice2AImpl_SetDataFormat,
01614     XCAST(SetEventNotification)IDirectInputDevice2AImpl_SetEventNotification,
01615     XCAST(SetCooperativeLevel)IDirectInputDevice2AImpl_SetCooperativeLevel,
01616         JoystickWImpl_GetObjectInfo,
01617     JoystickWImpl_GetDeviceInfo,
01618     XCAST(RunControlPanel)IDirectInputDevice2AImpl_RunControlPanel,
01619     XCAST(Initialize)IDirectInputDevice2AImpl_Initialize,
01620     XCAST(CreateEffect)JoystickAImpl_CreateEffect,
01621     JoystickWImpl_EnumEffects,
01622     JoystickWImpl_GetEffectInfo,
01623     XCAST(GetForceFeedbackState)JoystickAImpl_GetForceFeedbackState,
01624     XCAST(SendForceFeedbackCommand)JoystickAImpl_SendForceFeedbackCommand,
01625     XCAST(EnumCreatedEffectObjects)JoystickAImpl_EnumCreatedEffectObjects,
01626     XCAST(Escape)IDirectInputDevice2AImpl_Escape,
01627     XCAST(Poll)JoystickAImpl_Poll,
01628     XCAST(SendDeviceData)IDirectInputDevice2AImpl_SendDeviceData,
01629         IDirectInputDevice7WImpl_EnumEffectsInFile,
01630         IDirectInputDevice7WImpl_WriteEffectToFile,
01631         IDirectInputDevice8WImpl_BuildActionMap,
01632         IDirectInputDevice8WImpl_SetActionMap,
01633         IDirectInputDevice8WImpl_GetImageInfo
01634 };
01635 #undef XCAST
01636 
01637 #else  /* HAVE_CORRECT_LINUXINPUT_H */
01638 
01639 const struct dinput_device joystick_linuxinput_device = {
01640   "Wine Linux-input joystick driver",
01641   NULL,
01642   NULL,
01643   NULL,
01644   NULL
01645 };
01646 
01647 #endif  /* HAVE_CORRECT_LINUXINPUT_H */

Generated on Sun May 27 2012 04:21:32 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.