Sync to Wine-20050930: Jakob Eriksson jakov@vmlinux.org - Get rid of HeapAlloc casts. Robert Reif reif@earthlink.net - Added keyboard data format. - Fix joystick crash when a button guid is specified in the data format. Add some parameter checking. - Pass around real version and do correct thing based on it. Change cooperative level to pass on windows. - Fix SetProperty error returned. Add EnumDevice joystick version check. Test multiple versions. - Added dinput tests. - Effect objects are not supported yet so don't crash when trying to enumerate them. Raphael Junqueira fenix@club-internet.fr - use WINE_DINPUT_KEYBOARD_MAX_KEYS instead hard-coded 256 value - better use of critical section - some cleanup to better understand code paths - logic correction on SetWindowsHookExA/UnhookWindowsHookEx on keyboard. Alexandre Julliard julliard@winehq.org - Build a static list of devices instead of relying on ELF constructors. Gerald Pfeifer gerald@pfeifer.com - Fix compilation of the case without proper Linux joystick support. James Dean Anderson petr@pantek.org - Report an error if trying to get data from an unacquired mouse. Lionel Ulmer lionel.ulmer@free.fr - more pretty print for the types flag - more Windows-aligned check for object instances - Windows reports 0x80 on pressed buttons not 0xFF - trace the events reported to the application - do not flush the buffer when the application only wants to peek the number of elements in the queue - trace the GetDeviceState values before they are reset Alexandre Julliard julliard@winehq.org - Added rules for building import libraries in the individual dll makefiles, and added support for building a .def.a static import library too. - Added rules to build import libraries in the individual dll makefiles. Generate import libraries with the right name right away instead of using an intermediate .spec.def file. - Moved config parameters to HKCU\Software\Wine\DirectInput. - Added magic comments to all Wine-specific registry accesses to make them easier to grep. - Sort entry points alphabetically. - Removed some unused or redundant configure checks. A few cleanups in configure.ac. - Don't prefix the functions DllCanUnloadNow, DllGetClassObject and Dll(Un)RegisterServer with the dll name so that the compiler can check the prototypes. - Fixed some traces to use the right printf format and avoid typecasts. - Use a more portable scheme for storing the name of a critical section. - Use the COM macros instead of accessing lpVtbl directly. - We are no longer generating .dbg.c files. Marcus Meissner marcus@jet.franken.de - The last argument to MultiByteToWideChar is wide character count and not the buffer size in bytes. Fixed all places where it was wrong. - Fixed 3 memset()s which used the wrong size (too large). Dmitry Timoshkov dmitry@codeweavers.com - Make more of the OLE interface vtables const. Daniel Remenak dtremenak@gmail.com - Added a linux input system force feedback effect implementation. - Allow the creation of an FF effect while the joystick is not acquired. - Failing to download an effect after setting parameters is not a fatal error. - Allow enumeration of objects when the device is not yet acquired. - Flag FF-capable axes during enumeration. - Protect FF_STATUS usage to avoid compile errors on machines with old linux/input.h. - Implement EnumEffects, CreateEffect, EnumCreatedEffects, SendForceFeedbackCommand, and GetForceFeedbackStatus for linux input joysticks. - Correct dinput handling of sliders and non-zero-based axes through the linux input system. - Correctly enumerate evdev joysticks when enumeration is restricted with DIEDFL_FORCEFEEDBACK. - Detect force-feedback-capable linux event device joysticks and return DIDC_FORCEFEEDBACK when queried for capabilities. Mike McCormack mike@codeweavers.com - Interlocked LONG* gcc warning fixes. - gcc 4.0 warning fixes. - gcc 4.0 warning fixes for Interlocked* functions. - Fix warnings for no force feedback case. Stefan Huehner stefan@huehner.org - Fix some more -Wmissing-declarations warnings. Vincent Béron vberon@mecano.gme.usherb.ca - Use proper ifdefs around unistd.h. Modified: trunk/reactos/lib/dinput/device.c Modified: trunk/reactos/lib/dinput/device_private.h Modified: trunk/reactos/lib/dinput/dinput.spec Modified: trunk/reactos/lib/dinput/dinput.xml Modified: trunk/reactos/lib/dinput/dinput_main.c Modified: trunk/reactos/lib/dinput/dinput_private.h Added: trunk/reactos/lib/dinput/effect_linuxinput.c Modified: trunk/reactos/lib/dinput/joystick_linux.c Modified: trunk/reactos/lib/dinput/joystick_linuxinput.c Modified: trunk/reactos/lib/dinput/keyboard.c Modified: trunk/reactos/lib/dinput/mouse.c Modified: trunk/reactos/lib/dinput/regsvr.c Modified: trunk/reactos/lib/dinput/version.rc _____
Modified: trunk/reactos/lib/dinput/device.c --- trunk/reactos/lib/dinput/device.c 2005-10-08 19:59:09 UTC (rev 18360) +++ trunk/reactos/lib/dinput/device.c 2005-10-08 20:11:27 UTC (rev 18361) @@ -464,7 +464,7 @@
LPDIRECTINPUTDEVICE8A iface,HWND hwnd,DWORD dwflags ) { IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface; - TRACE("(this=%p,0x%08lx,0x%08lx)\n",This,(DWORD)hwnd,dwflags); + TRACE("(this=%p,%p,0x%08lx)\n",This,hwnd,dwflags); if (TRACE_ON(dinput)) { TRACE(" cooperative level : "); _dump_cooperativelevel_DI(dwflags); @@ -476,7 +476,7 @@ LPDIRECTINPUTDEVICE8A iface,HANDLE hnd ) { IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface; - FIXME("(this=%p,0x%08lx): stub\n",This,(DWORD)hnd); + FIXME("(this=%p,%p): stub\n",This,hnd); return DI_OK; }
_____
Modified: trunk/reactos/lib/dinput/device_private.h --- trunk/reactos/lib/dinput/device_private.h 2005-10-08 19:59:09 UTC (rev 18360) +++ trunk/reactos/lib/dinput/device_private.h 2005-10-08 20:11:27 UTC (rev 18361) @@ -30,8 +30,8 @@
typedef struct IDirectInputDevice2AImpl IDirectInputDevice2AImpl; struct IDirectInputDevice2AImpl { - IDirectInputDevice2AVtbl *lpVtbl; - DWORD ref; + const IDirectInputDevice2AVtbl *lpVtbl; + LONG ref; GUID guid; };
_____
Modified: trunk/reactos/lib/dinput/dinput.spec --- trunk/reactos/lib/dinput/dinput.spec 2005-10-08 19:59:09 UTC (rev 18360) +++ trunk/reactos/lib/dinput/dinput.spec 2005-10-08 20:11:27 UTC (rev 18361) @@ -1,7 +1,7 @@
-@ stdcall DirectInputCreateA(long long ptr ptr) -@ stdcall DirectInputCreateW(long long ptr ptr) -@ stdcall DirectInputCreateEx(long long ptr ptr ptr) -@ stdcall -private DllCanUnloadNow() DINPUT_DllCanUnloadNow -@ stdcall -private DllGetClassObject(ptr ptr ptr) DINPUT_DllGetClassObject -@ stdcall -private DllRegisterServer() DINPUT_DllRegisterServer -@ stdcall -private DllUnregisterServer() DINPUT_DllUnregisterServer +@ stdcall DirectInputCreateA(long long ptr ptr) +@ stdcall DirectInputCreateEx(long long ptr ptr ptr) +@ stdcall DirectInputCreateW(long long ptr ptr) +@ stdcall -private DllCanUnloadNow() +@ stdcall -private DllGetClassObject(ptr ptr ptr) +@ stdcall -private DllRegisterServer() +@ stdcall -private DllUnregisterServer() Property changes on: trunk/reactos/lib/dinput/dinput.spec ___________________________________________________________________ Name: svn:eol-style + native _____
Modified: trunk/reactos/lib/dinput/dinput.xml --- trunk/reactos/lib/dinput/dinput.xml 2005-10-08 19:59:09 UTC (rev 18360) +++ trunk/reactos/lib/dinput/dinput.xml 2005-10-08 20:11:27 UTC (rev 18361) @@ -21,6 +21,7 @@
<file>data_formats.c</file> <file>device.c</file> <file>dinput_main.c</file> + <file>effect_linuxinput.c</file> <file>joystick_linux.c</file> <file>joystick_linuxinput.c</file> <file>keyboard.c</file> _____
Modified: trunk/reactos/lib/dinput/dinput_main.c --- trunk/reactos/lib/dinput/dinput_main.c 2005-10-08 19:59:09 UTC (rev 18360) +++ trunk/reactos/lib/dinput/dinput_main.c 2005-10-08 20:11:27 UTC (rev 18361) @@ -46,10 +46,10 @@
WINE_DEFAULT_DEBUG_CHANNEL(dinput);
-static IDirectInput7AVtbl ddi7avt; -static IDirectInput7WVtbl ddi7wvt; -static IDirectInput8AVtbl ddi8avt; -static IDirectInput8WVtbl ddi8wvt; +static const IDirectInput7AVtbl ddi7avt; +static const IDirectInput7WVtbl ddi7wvt; +static const IDirectInput8AVtbl ddi8avt; +static const IDirectInput8WVtbl ddi8wvt;
static const struct dinput_device *dinput_devices[] = { @@ -86,7 +86,7 @@ { IDirectInputImpl* This;
- TRACE("(0x%08lx,%04lx,%s,%p,%p)\n", (DWORD)hinst,dwVersion,debugstr_guid(riid),ppDI,punkOuter); + TRACE("(%p,%04lx,%s,%p,%p)\n", hinst,dwVersion,debugstr_guid(riid),ppDI,punkOuter);
if (IsEqualGUID(&IID_IDirectInputA,riid) || IsEqualGUID(&IID_IDirectInput2A,riid) || @@ -384,7 +384,7 @@ HWND hwndOwner, DWORD dwFlags) { IDirectInputImpl *This = (IDirectInputImpl *)iface; - FIXME("(%p)->(%08lx,%08lx): stub\n",This, (DWORD) hwndOwner, dwFlags); + FIXME("(%p)->(%p,%08lx): stub\n",This, hwndOwner, dwFlags);
return DI_OK; } @@ -535,7 +535,7 @@ # define XCAST(fun) (void*) #endif
-static IDirectInput7AVtbl ddi7avt = { +static const IDirectInput7AVtbl ddi7avt = { XCAST(QueryInterface)IDirectInputAImpl_QueryInterface, XCAST(AddRef)IDirectInputAImpl_AddRef, XCAST(Release)IDirectInputAImpl_Release, @@ -555,7 +555,7 @@ # define XCAST(fun) (void*) #endif
-static IDirectInput7WVtbl ddi7wvt = { +static const IDirectInput7WVtbl ddi7wvt = { XCAST(QueryInterface)IDirectInputWImpl_QueryInterface, XCAST(AddRef)IDirectInputAImpl_AddRef, XCAST(Release)IDirectInputAImpl_Release, @@ -575,7 +575,7 @@ # define XCAST(fun) (void*) #endif
-static IDirectInput8AVtbl ddi8avt = { +static const IDirectInput8AVtbl ddi8avt = { XCAST(QueryInterface)IDirectInput8AImpl_QueryInterface, XCAST(AddRef)IDirectInputAImpl_AddRef, XCAST(Release)IDirectInputAImpl_Release, @@ -595,7 +595,7 @@ #else # define XCAST(fun) (void*) #endif -static IDirectInput8WVtbl ddi8wvt = { +static const IDirectInput8WVtbl ddi8wvt = { XCAST(QueryInterface)IDirectInput8WImpl_QueryInterface, XCAST(AddRef)IDirectInputAImpl_AddRef, XCAST(Release)IDirectInputAImpl_Release, @@ -616,8 +616,8 @@ typedef struct { /* IUnknown fields */ - IClassFactoryVtbl *lpVtbl; - DWORD ref; + const IClassFactoryVtbl *lpVtbl; + LONG ref; } IClassFactoryImpl;
static HRESULT WINAPI DICF_QueryInterface(LPCLASSFACTORY iface,REFIID riid,LPVOID *ppobj) { @@ -666,7 +666,7 @@ return S_OK; }
-static IClassFactoryVtbl DICF_Vtbl = { +static const IClassFactoryVtbl DICF_Vtbl = { DICF_QueryInterface, DICF_AddRef, DICF_Release, @@ -678,7 +678,7 @@
/*********************************************************************** * DllCanUnloadNow (DINPUT.@) */ -HRESULT WINAPI DINPUT_DllCanUnloadNow(void) +HRESULT WINAPI DllCanUnloadNow(void) { FIXME("(void): stub\n");
@@ -688,8 +688,7 @@
/*********************************************************************** * DllGetClassObject (DINPUT.@) */ -HRESULT WINAPI DINPUT_DllGetClassObject(REFCLSID rclsid, REFIID riid, - LPVOID *ppv) +HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) { TRACE("(%s,%s,%p)\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv); if ( IsEqualCLSID( &IID_IClassFactory, riid ) ) { _____
Modified: trunk/reactos/lib/dinput/dinput_private.h --- trunk/reactos/lib/dinput/dinput_private.h 2005-10-08 19:59:09 UTC (rev 18360) +++ trunk/reactos/lib/dinput/dinput_private.h 2005-10-08 20:11:27 UTC (rev 18361) @@ -29,8 +29,8 @@
typedef struct IDirectInputImpl IDirectInputImpl; struct IDirectInputImpl { - LPVOID lpVtbl; - DWORD ref; + const void *lpVtbl; + LONG ref;
/* Used to have an unique sequence number for all the events */ DWORD evsequence; _____
Copied: trunk/reactos/lib/dinput/effect_linuxinput.c (from rev 18360, vendor/wine/dlls/dinput/current/effect_linuxinput.c) Property changes on: trunk/reactos/lib/dinput/effect_linuxinput.c ___________________________________________________________________ Name: svn:keywords + Author Date Id Revision Name: svn:eol-style + native _____
Modified: trunk/reactos/lib/dinput/joystick_linux.c --- trunk/reactos/lib/dinput/joystick_linux.c 2005-10-08 19:59:09 UTC (rev 18360) +++ trunk/reactos/lib/dinput/joystick_linux.c 2005-10-08 20:11:27 UTC (rev 18361) @@ -84,12 +84,12 @@
} POV;
typedef struct JoystickImpl JoystickImpl; -static IDirectInputDevice8AVtbl JoystickAvt; -static IDirectInputDevice8WVtbl JoystickWvt; +static const IDirectInputDevice8AVtbl JoystickAvt; +static const IDirectInputDevice8WVtbl JoystickWvt; struct JoystickImpl { - LPVOID lpVtbl; - DWORD ref; + const void *lpVtbl; + LONG ref; GUID guid; char dev[32];
@@ -254,10 +254,10 @@ inline static DWORD get_config_key( HKEY defkey, HKEY appkey, const char *name, char *buffer, DWORD size ) { - if (appkey && !RegQueryValueExA( appkey, name, 0, NULL, buffer, &size )) + if (appkey && !RegQueryValueExA( appkey, name, 0, NULL, (LPBYTE)buffer, &size )) return 0;
- if (defkey && !RegQueryValueExA( defkey, name, 0, NULL, buffer, &size )) + if (defkey && !RegQueryValueExA( defkey, name, 0, NULL, (LPBYTE)buffer, &size )) return 0;
return ERROR_FILE_NOT_FOUND; @@ -269,28 +269,27 @@
static HRESULT setup_dinput_options(JoystickImpl * device) { - char buffer[MAX_PATH+1]; + char buffer[MAX_PATH+16]; HKEY hkey, appkey = 0; DWORD len;
buffer[MAX_PATH]='\0';
- if (RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\Wine\dinput", &hkey)) hkey = 0; + /* @@ Wine registry key: HKCU\Software\Wine\DirectInput */ + if (RegOpenKeyA( HKEY_CURRENT_USER, "Software\Wine\DirectInput", &hkey)) hkey = 0;
len = GetModuleFileNameA( 0, buffer, MAX_PATH ); if (len && len < MAX_PATH) { HKEY tmpkey; - - if (!RegOpenKeyA( HKEY_LOCAL_MACHINE, "Software\Wine\AppDefaults", &tmpkey )) { - char appname[MAX_PATH+16]; - char *p = strrchr( buffer, '\' ); - if (p!=NULL) { - strcpy(appname,p+1); - strcat(appname,"\dinput"); - TRACE("appname = [%s] \n",appname); - if (RegOpenKeyA( tmpkey, appname, &appkey )) appkey = 0; - } - RegCloseKey( tmpkey ); + /* @@ Wine registry key: HKCU\Software\Wine\AppDefaults\app.exe\DirectInput */ + if (!RegOpenKeyA( HKEY_CURRENT_USER, "Software\Wine\AppDefaults", &tmpkey )) + { + char *p, *appname = buffer; + if ((p = strrchr( appname, '/' ))) appname = p + 1; + if ((p = strrchr( appname, '\' ))) appname = p + 1; + strcat( appname, "\DirectInput" ); + if (RegOpenKeyA( tmpkey, appname, &appkey )) appkey = 0; + RegCloseKey( tmpkey ); } }
@@ -386,7 +385,7 @@ return DI_OK; }
-void calculate_ids(JoystickImpl* device) +static void calculate_ids(JoystickImpl* device) { int i; int axis = 0; @@ -437,7 +436,7 @@ } }
-static HRESULT alloc_device(REFGUID rguid, LPVOID jvt, IDirectInputImpl *dinput, LPDIRECTINPUTDEVICEA* pdev) +static HRESULT alloc_device(REFGUID rguid, const void *jvt, IDirectInputImpl *dinput, LPDIRECTINPUTDEVICEA* pdev) { DWORD i; JoystickImpl* newDevice; @@ -553,7 +552,7 @@
IDirectInputDevice_AddRef((LPDIRECTINPUTDEVICE8A)newDevice->dinput); InitializeCriticalSection(&(newDevice->crit)); - newDevice->crit.DebugInfo->Spare[1] = (DWORD)"DINPUT_Mouse"; + newDevice->crit.DebugInfo->Spare[0] = (DWORD_PTR)"DINPUT_Mouse";
newDevice->devcaps.dwSize = sizeof(newDevice->devcaps); newDevice->devcaps.dwFlags = DIDC_ATTACHED; @@ -689,7 +688,7 @@ /* release the data transform filter */ release_DataFormat(This->transform);
- This->crit.DebugInfo->Spare[1] = 0; + This->crit.DebugInfo->Spare[0] = 0; DeleteCriticalSection(&(This->crit)); IDirectInputDevice_Release((LPDIRECTINPUTDEVICE8A)This->dinput);
@@ -831,7 +830,7 @@ return DI_NOEFFECT; }
-LONG map_axis(JoystickImpl * This, short val, short index) +static LONG map_axis(JoystickImpl * This, short val, short index) { double fval = val; double fmin = This->props[index].lMin; @@ -849,7 +848,7 @@ }
/* convert wine format offset to user format object index */ -int offset_to_object(JoystickImpl *This, int offset) +static int offset_to_object(JoystickImpl *This, int offset) { int i;
@@ -1094,7 +1093,7 @@ return hr; }
-int find_property(JoystickImpl * This, LPCDIPROPHEADER ph) +static int find_property(JoystickImpl * This, LPCDIPROPHEADER ph) { int i; if (ph->dwHow == DIPH_BYOFFSET) { @@ -1132,7 +1131,7 @@ _dump_DIPROPHEADER(ph);
if (!HIWORD(rguid)) { - switch ((DWORD)rguid) { + switch (LOWORD(rguid)) { case (DWORD) DIPROP_BUFFERSIZE: { LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph; TRACE("buffersize = %ld\n",pd->dwData); @@ -1197,7 +1196,7 @@ break; } default: - FIXME("Unknown type %ld (%s)\n",(DWORD)rguid,debugstr_guid(rguid)); + FIXME("Unknown type %p (%s)\n",rguid,debugstr_guid(rguid)); break; } } @@ -1213,7 +1212,7 @@ ) { JoystickImpl *This = (JoystickImpl *)iface;
- TRACE("(this=%p,0x%08lx)\n",This,(DWORD)hnd); + TRACE("(this=%p,%p)\n",This,hnd); This->hEvent = hnd; return DI_OK; } @@ -1428,7 +1427,7 @@ _dump_DIPROPHEADER(pdiph);
if (!HIWORD(rguid)) { - switch ((DWORD)rguid) { + switch (LOWORD(rguid)) { case (DWORD) DIPROP_BUFFERSIZE: { LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph; TRACE(" return buffersize = %d\n",This->queue_len); @@ -1469,7 +1468,7 @@ break; } default: - FIXME("Unknown type %ld (%s)\n",(DWORD)rguid,debugstr_guid(rguid)); + FIXME("Unknown type %p (%s)\n",rguid,debugstr_guid(rguid)); break; } } @@ -1640,7 +1639,7 @@ return DI_OK; }
-static IDirectInputDevice8AVtbl JoystickAvt = +static const IDirectInputDevice8AVtbl JoystickAvt = { IDirectInputDevice2AImpl_QueryInterface, IDirectInputDevice2AImpl_AddRef, @@ -1682,7 +1681,7 @@ # define XCAST(fun) (void*) #endif
-static IDirectInputDevice8WVtbl SysJoystickWvt = +static const IDirectInputDevice8WVtbl SysJoystickWvt = { IDirectInputDevice2WImpl_QueryInterface, XCAST(AddRef)IDirectInputDevice2AImpl_AddRef, _____
Modified: trunk/reactos/lib/dinput/joystick_linuxinput.c --- trunk/reactos/lib/dinput/joystick_linuxinput.c 2005-10-08 19:59:09 UTC (rev 18360) +++ trunk/reactos/lib/dinput/joystick_linuxinput.c 2005-10-08 20:11:27 UTC (rev 18361) @@ -3,6 +3,7 @@
* Copyright 1998,2000 Marcus Meissner * Copyright 1998,1999 Lionel Ulmer * Copyright 2000-2001 TransGaming Technologies Inc. + * Copyright 2005 Daniel Remenak * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -43,6 +44,9 @@ #endif #ifdef HAVE_LINUX_INPUT_H # include <linux/input.h> +# if defined(EVIOCGBIT) && defined(EV_ABS) && defined(BTN_PINKIE) +# define HAVE_CORRECT_LINUXINPUT_H +# endif #endif
#include "wine/debug.h" @@ -65,13 +69,25 @@ #define WINE_JOYSTICK_AXIS_BASE 0 #define WINE_JOYSTICK_BUTTON_BASE 8
+typedef struct EffectListItem EffectListItem; +struct EffectListItem +{ + LPDIRECTINPUTEFFECT ref; + struct EffectListItem* next; +}; + +/* implemented in effect_linuxinput.c */ +HRESULT linuxinput_create_effect(int* fd, REFGUID rguid, LPDIRECTINPUTEFFECT* peff); +HRESULT linuxinput_get_info_A(int fd, REFGUID rguid, LPDIEFFECTINFOA info); +HRESULT linuxinput_get_info_W(int fd, REFGUID rguid, LPDIEFFECTINFOW info); + typedef struct JoystickImpl JoystickImpl; -static IDirectInputDevice8AVtbl JoystickAvt; -static IDirectInputDevice8WVtbl JoystickWvt; +static const IDirectInputDevice8AVtbl JoystickAvt; +static const IDirectInputDevice8WVtbl JoystickWvt; struct JoystickImpl { - LPVOID lpVtbl; - DWORD ref; + const void *lpVtbl; + LONG ref; GUID guid;
@@ -97,6 +113,12 @@ BOOL overflow; DIJOYSTATE2 js;
+ /* Force feedback variables */ + BOOL has_ff; + int num_effects; + EffectListItem* top_effect; + int ff_state; + /* data returned by the EVIOCGABS() ioctl */ int axes[ABS_MAX+1][5];
@@ -107,9 +129,11 @@ #define AXE_ABSFLAT 4
- /* data returned by EVIOCGBIT for EV_ABS and EV_KEY */ + /* data returned by EVIOCGBIT for caps, EV_ABS, EV_KEY, and EV_FF */ + BYTE evbits[(EV_MAX+7)/8]; BYTE absbits[(ABS_MAX+7)/8]; BYTE keybits[(KEY_MAX+7)/8]; + BYTE ffbits[(FF_MAX+7)/8]; };
/* This GUID is slightly different from the linux joystick one. Take note. */ @@ -124,17 +148,24 @@
#define test_bit(arr,bit) (((BYTE*)arr)[bit>>3]&(1<<(bit&7)))
-static int joydev_have(void) +static int joydev_have(BOOL require_ff) { - int i, fd; + int i, fd, flags, num_effects; int havejoy = 0;
for (i=0;i<64;i++) { char buf[200]; BYTE absbits[(ABS_MAX+7)/8],keybits[(KEY_MAX+7)/8]; + BYTE evbits[(EV_MAX+7)/8],ffbits[(FF_MAX+7)/8];
sprintf(buf,EVDEVPREFIX"%d",i); - if (-1!=(fd=open(buf,O_RDONLY))) { + + if (require_ff) + flags = O_RDWR; + else + flags = O_RDONLY; + + if (-1!=(fd=open(buf,flags))) { if (-1==ioctl(fd,EVIOCGBIT(EV_ABS,sizeof(absbits)),absbits)) { perror("EVIOCGBIT EV_ABS"); close(fd); @@ -145,6 +176,23 @@ close(fd); continue; } + + /* test for force feedback if it's required */ + if (require_ff) { + if ((-1==ioctl(fd,EVIOCGBIT(0,sizeof(evbits)),evbits))) { + perror("EVIOCGBIT 0"); + close(fd); + continue; + } + if ( (!test_bit(evbits,EV_FF)) + || (-1==ioctl(fd,EVIOCGBIT(EV_FF,sizeof(ffbits)),ffbits)) + || (-1==ioctl(fd,EVIOCGEFFECTS,&num_effects)) + || (num_effects <= 0)) { + close(fd); + continue; + } + } + /* A true joystick has at least axis X and Y, and at least 1 * button. copied from linux/drivers/input/joydev.c */ if (test_bit(absbits,ABS_X) && test_bit(absbits,ABS_Y) && @@ -176,10 +224,12 @@ (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800)))) return FALSE;
+#ifndef HAVE_STRUCT_FF_EFFECT_DIRECTION if (dwFlags & DIEDFL_FORCEFEEDBACK) return FALSE; +#endif
- havejoy = joydev_have(); + havejoy = joydev_have(dwFlags & DIEDFL_FORCEFEEDBACK);
if (!havejoy) return FALSE; @@ -214,10 +264,12 @@ (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800)))) return FALSE;
+#ifndef HAVE_STRUCT_FF_EFFECT_DIRECTION if (dwFlags & DIEDFL_FORCEFEEDBACK) return FALSE; +#endif
- havejoy = joydev_have(); + havejoy = joydev_have(dwFlags & DIEDFL_FORCEFEEDBACK);
if (!havejoy) return FALSE; @@ -240,7 +292,7 @@ return TRUE; }
-static JoystickImpl *alloc_device(REFGUID rguid, LPVOID jvt, IDirectInputImpl *dinput) +static JoystickImpl *alloc_device(REFGUID rguid, const void *jvt, IDirectInputImpl *dinput) { JoystickImpl* newDevice; int i; @@ -250,6 +302,9 @@ newDevice->ref = 1; newDevice->joyfd = -1; newDevice->dinput = dinput; +#ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION + newDevice->ff_state = FF_STATUS_STOPPED; +#endif memcpy(&(newDevice->guid),rguid,sizeof(*rguid)); for (i=0;i<ABS_MAX;i++) { newDevice->wantmin[i] = -32768; @@ -269,7 +324,7 @@ { int havejoy = 0;
- havejoy = joydev_have(); + havejoy = joydev_have(FALSE);
if (!havejoy) return DIERR_DEVICENOTREG; @@ -296,7 +351,7 @@ { int havejoy = 0;
- havejoy = joydev_have(); + havejoy = joydev_have(FALSE);
if (!havejoy) return DIERR_DEVICENOTREG; @@ -338,6 +393,9 @@ if (ref) return ref;
+ /* Reset the FF state, free all effects, etc */ + IDirectInputDevice8_SendForceFeedbackCommand(iface, DISFFC_RESET); + /* Free the data queue */ HeapFree(GetProcessHeap(),0,This->data_queue);
@@ -379,19 +437,32 @@ int i; JoystickImpl *This = (JoystickImpl *)iface; char buf[200]; + BOOL readonly = TRUE;
TRACE("(this=%p)\n",This); if (This->joyfd!=-1) return 0; for (i=0;i<64;i++) { sprintf(buf,EVDEVPREFIX"%d",i); - if (-1==(This->joyfd=open(buf,O_RDONLY))) { - if (errno==ENODEV) - return DIERR_NOTFOUND; - perror(buf); - continue; + if (-1==(This->joyfd=open(buf,O_RDWR))) { + if (-1==(This->joyfd=open(buf,O_RDONLY))) { + /* Couldn't open the device at all */ + if (errno==ENODEV) + return DIERR_NOTFOUND; + perror(buf); + continue; + } + else { + /* Couldn't open in r/w but opened in read-only. */ + WARN("Could not open %s in read-write mode. Force feedback will be disabled.\n",buf); + } } - if ((-1!=ioctl(This->joyfd,EVIOCGBIT(EV_ABS,sizeof(This->absbits)),This->ab sbits)) && + else { + /* Opened device in read-write */ + readonly = FALSE; + } + if ((-1!=ioctl(This->joyfd,EVIOCGBIT(0,sizeof(This->evbits)),This->evbits)) && + (-1!=ioctl(This->joyfd,EVIOCGBIT(EV_ABS,sizeof(This->absbits)),This->abs bits)) &&
(-1!=ioctl(This->joyfd,EVIOCGBIT(EV_KEY,sizeof(This->keybits)),This->key bits)) && (test_bit(This->absbits,ABS_X) && test_bit(This->absbits,ABS_Y) && (test_bit(This->keybits,BTN_TRIGGER)|| @@ -407,6 +478,30 @@ if (This->joyfd==-1) return DIERR_NOTFOUND;
+ This->has_ff = FALSE; + This->num_effects = 0; + +#ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION + if (!readonly && test_bit(This->evbits, EV_FF)) { + if (-1!=ioctl(This->joyfd,EVIOCGBIT(EV_FF,sizeof(This->ffbits)),This->ffbit s)) { + if (-1!=ioctl(This->joyfd,EVIOCGEFFECTS,&This->num_effects) + && This->num_effects > 0) { + This->has_ff = TRUE; + TRACE("Joystick seems to be capable of force feedback.\n"); + } + else { + TRACE("Joystick does not support any effects, disabling force feedback.\n"); + } + } + else { + TRACE("Could not get EV_FF bits; disabling force feedback.\n"); + } + } + else { + TRACE("Force feedback disabled (device is readonly or joystick incapable).\n"); + } +#endif + for (i=0;i<ABS_MAX;i++) { if (test_bit(This->absbits,i)) { if (-1==ioctl(This->joyfd,EVIOCGABS(i),&(This->axes[i]))) @@ -468,8 +563,10 @@ if (xmin == xmax) return val;
/* map the value from the hmin-hmax range into the wmin-wmax range */ - ret = (val * (wmax-wmin)) / (hmax-hmin) + wmin; + ret = ((val-hmin) * (wmax-wmin)) / (hmax-hmin) + wmin;
+ TRACE("xmin=%d xmax=%d hmin=%d hmax=%d wmin=%d wmax=%d val=%d ret=%d\n", xmin, xmax, hmin, hmax, wmin, wmax, val, ret); + #if 0 /* deadzone doesn't work comfortably enough right now. needs more testing*/ if ((ret > -deadz/2 ) && (ret < deadz/2)) { @@ -492,6 +589,8 @@ ji->js.lRx = map_axis(ji, ABS_RX, ji->axes[ABS_RX][AXE_ABS]); ji->js.lRy = map_axis(ji, ABS_RY, ji->axes[ABS_RY][AXE_ABS]); ji->js.lRz = map_axis(ji, ABS_RZ, ji->axes[ABS_RZ][AXE_ABS]); + ji->js.rglSlider[0] = map_axis(ji, ABS_THROTTLE, ji->axes[ABS_THROTTLE][AXE_ABS]); + ji->js.rglSlider[1] = map_axis(ji, ABS_RUDDER, ji->axes[ABS_RUDDER ][AXE_ABS]); }
static void joy_polldev(JoystickImpl *This) { @@ -613,11 +712,24 @@ This->js.lRz = map_axis(This,ABS_RZ,ie.value);
GEN_EVENT(DIJOFS_RZ,This->js.lRz,ie.time.tv_usec,(This->dinput->evsequen ce)++); break; + case ABS_THROTTLE: + This->js.rglSlider[0] = map_axis(This,ABS_THROTTLE,ie.value); + GEN_EVENT(DIJOFS_SLIDER(0),This->js.rglSlider[0],ie.time.tv_usec,(This-> dinput->evsequence)++); + break; + case ABS_RUDDER: + This->js.rglSlider[1] = map_axis(This,ABS_RUDDER,ie.value); + GEN_EVENT(DIJOFS_SLIDER(1),This->js.rglSlider[1],ie.time.tv_usec,(This-> dinput->evsequence)++); + break; default: FIXME("unhandled joystick axe event (code %d, value %d)\n",ie.code,ie.value); break; } break; +#ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION + case EV_FF_STATUS: + This->ff_state = ie.value; + break; +#endif default: FIXME("joystick cannot handle type %d event (code %d)\n",ie.type,ie.code); break; @@ -683,7 +795,7 @@ FIXME("ph.dwSize = %ld, ph.dwHeaderSize =%ld, ph.dwObj = %ld, ph.dwHow= %ld\n",ph->dwSize, ph->dwHeaderSize,ph->dwObj,ph->dwHow);
if (!HIWORD(rguid)) { - switch ((DWORD)rguid) { + switch (LOWORD(rguid)) { case (DWORD) DIPROP_BUFFERSIZE: { LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph;
@@ -701,6 +813,8 @@ case 12: /* Rx */ case 16: /* Ry */ case 20: /* Rz */ + case 24: /* Slider 0 -> Throttle */ + case 28: /* Slider 1 -> Rudder */ This->wantmin[ph->dwObj/4] = pr->lMin; This->wantmax[ph->dwObj/4] = pr->lMax; break; @@ -717,7 +831,7 @@ break; } default: - FIXME("Unknown type %ld (%s)\n",(DWORD)rguid,debugstr_guid(rguid)); + FIXME("Unknown type %p (%s)\n",rguid,debugstr_guid(rguid)); break; } } @@ -733,7 +847,7 @@ ) { JoystickImpl *This = (JoystickImpl *)iface;
- TRACE("(this=%p,0x%08lx)\n",This,(DWORD)hnd); + TRACE("(this=%p,%p)\n",This,hnd); This->hEvent = hnd; return DI_OK; } @@ -765,6 +879,9 @@ buttons=0; for (i=0;i<KEY_MAX;i++) if (test_bit(This->keybits,i)) buttons++;
+ if (This->has_ff) + lpDIDevCaps->dwFlags |= DIDC_FORCEFEEDBACK; + lpDIDevCaps->dwAxes = axes; lpDIDevCaps->dwButtons = buttons;
@@ -795,7 +912,6 @@ DIDEVICEOBJECTINSTANCEA ddoi; int xfd = This->joyfd;
- TRACE("(this=%p,%p,%p,%08lx)\n", This, lpCallback, lpvRef, dwFlags); if (TRACE_ON(dinput)) { TRACE(" - flags = "); @@ -803,7 +919,9 @@ TRACE("\n"); }
- if (xfd == -1) return DIERR_NOTACQUIRED; + /* We need to work even if we're not yet acquired */ + if (xfd == -1) + IDirectInputDevice8_Acquire(iface);
/* Only the fields till dwFFMaxForce are relevant */ ddoi.dwSize = FIELD_OFFSET(DIDEVICEOBJECTINSTANCEA, dwFFMaxForce); @@ -846,14 +964,27 @@ ddoi.guidType = GUID_Slider; ddoi.dwOfs = DIJOFS_SLIDER(0); break; + case ABS_RUDDER: + ddoi.guidType = GUID_Slider; + ddoi.dwOfs = DIJOFS_SLIDER(1); + break; default: FIXME("unhandled abs axis %d, ignoring!\n",i); } ddoi.dwType = DIDFT_MAKEINSTANCE((1<<i) << WINE_JOYSTICK_AXIS_BASE) | DIDFT_ABSAXIS; + /* Linux event force feedback supports only (and always) x and y axes */ + if (i == ABS_X || i == ABS_Y) { + if (This->has_ff) + ddoi.dwFlags |= DIDOI_FFACTUATOR; + } sprintf(ddoi.tszName, "%d-Axis", i); _dump_OBJECTINSTANCEA(&ddoi); - if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) - return DI_OK; + if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) { + /* return to unaquired state if that's where we were */ + if (xfd == -1) + IDirectInputDevice8_Unacquire(iface); + return DI_OK; + } } }
@@ -936,13 +1067,18 @@ } sprintf(ddoi.tszName, "%d-Button", i); _dump_OBJECTINSTANCEA(&ddoi); - if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) - return DI_OK; + if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) { + /* return to unaquired state if that's where we were */ + if (xfd == -1) + IDirectInputDevice8_Unacquire(iface); + return DI_OK; + } } }
- if (xfd!=This->joyfd) - close(xfd); + /* return to unaquired state if that's where we were */ + if (xfd == -1) + IDirectInputDevice8_Unacquire(iface);
return DI_OK; } @@ -978,7 +1114,7 @@ _dump_DIPROPHEADER(pdiph);
if (!HIWORD(rguid)) { - switch ((DWORD)rguid) { + switch (LOWORD(rguid)) { case (DWORD) DIPROP_BUFFERSIZE: { LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph;
@@ -999,7 +1135,7 @@ }
default: - FIXME("Unknown type %ld (%s)\n",(DWORD)rguid,debugstr_guid(rguid)); + FIXME("Unknown type %p (%s)\n",rguid,debugstr_guid(rguid)); break; } } @@ -1008,8 +1144,352 @@ return DI_OK; }
-static IDirectInputDevice8AVtbl JoystickAvt = +/********************************************************************** ******** + * CreateEffect - Create a new FF effect with the specified params + */ +static HRESULT WINAPI JoystickAImpl_CreateEffect(LPDIRECTINPUTDEVICE8A iface, + REFGUID rguid, + LPCDIEFFECT lpeff, + LPDIRECTINPUTEFFECT *ppdef, + LPUNKNOWN pUnkOuter) { +#ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION + EffectListItem* new = NULL; + HRESULT retval = DI_OK; +#endif + + JoystickImpl* This = (JoystickImpl*)iface; + TRACE("(this=%p,%p,%p,%p,%p)\n", This, rguid, lpeff, ppdef, pUnkOuter); + +#ifndef HAVE_STRUCT_FF_EFFECT_DIRECTION + TRACE("not available (compiled w/o ff support)\n"); + *ppdef = NULL; + return DI_OK; +#else + + new = malloc(sizeof(EffectListItem)); + new->next = This->top_effect; + This->top_effect = new; + + retval = linuxinput_create_effect(&(This->joyfd), rguid, &(new->ref)); + if (retval != DI_OK) + return retval; + + if (lpeff != NULL) + retval = IDirectInputEffect_SetParameters(new->ref, lpeff, 0); + if (retval != DI_OK && retval != DI_DOWNLOADSKIPPED) + return retval; + + *ppdef = new->ref; + + if (pUnkOuter != NULL) + FIXME("Interface aggregation not implemented.\n"); + + return DI_OK; + +#endif /* HAVE_STRUCT_FF_EFFECT_DIRECTION */ +} + +/********************************************************************** ********* + * EnumEffects - Enumerate available FF effects + */ +static HRESULT WINAPI JoystickAImpl_EnumEffects(LPDIRECTINPUTDEVICE8A iface, + LPDIENUMEFFECTSCALLBACKA lpCallback, + LPVOID pvRef, + DWORD dwEffType) +{ +#ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION + DIEFFECTINFOA dei; /* feif */ + DWORD type = DIEFT_GETTYPE(dwEffType); + JoystickImpl* This = (JoystickImpl*)iface; + int xfd = This->joyfd; + + TRACE("(this=%p,%p,%ld) type=%ld fd=%d\n", This, pvRef, dwEffType, type, xfd); + + dei.dwSize = sizeof(DIEFFECTINFOA); + + /* We need to return something even if we're not yet acquired */ + if (xfd == -1) + IDirectInputDevice8_Acquire(iface); + + if ((type == DIEFT_ALL || type == DIEFT_CONSTANTFORCE) + && test_bit(This->ffbits, FF_CONSTANT)) { + IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_ConstantForce); + (*lpCallback)(&dei, pvRef); + } + + if ((type == DIEFT_ALL || type == DIEFT_PERIODIC) + && test_bit(This->ffbits, FF_PERIODIC)) { + if (test_bit(This->ffbits, FF_SQUARE)) { + IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Square); + (*lpCallback)(&dei, pvRef); + } + if (test_bit(This->ffbits, FF_SINE)) { + IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Sine); + (*lpCallback)(&dei, pvRef); + } + if (test_bit(This->ffbits, FF_TRIANGLE)) { + IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Triangle); + (*lpCallback)(&dei, pvRef); + } + if (test_bit(This->ffbits, FF_SAW_UP)) { + IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_SawtoothUp); + (*lpCallback)(&dei, pvRef); + } + if (test_bit(This->ffbits, FF_SAW_DOWN)) { + IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_SawtoothDown); + (*lpCallback)(&dei, pvRef); + } + } + + if ((type == DIEFT_ALL || type == DIEFT_RAMPFORCE) + && test_bit(This->ffbits, FF_RAMP)) { + IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_RampForce); + (*lpCallback)(&dei, pvRef); + } + + if (type == DIEFT_ALL || type == DIEFT_CONDITION) { + if (test_bit(This->ffbits, FF_SPRING)) { + IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Spring); + (*lpCallback)(&dei, pvRef); + } + if (test_bit(This->ffbits, FF_DAMPER)) { + IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Damper); + (*lpCallback)(&dei, pvRef); + } + if (test_bit(This->ffbits, FF_INERTIA)) { + IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Inertia); + (*lpCallback)(&dei, pvRef); + } + if (test_bit(This->ffbits, FF_FRICTION)) { + IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Friction); + (*lpCallback)(&dei, pvRef); + } + } + + /* return to unaquired state if that's where it was */ + if (xfd == -1) + IDirectInputDevice8_Unacquire(iface); +#endif + + return DI_OK; +} + [truncated at 1000 lines; 564 more skipped]