From 2ffd7b7d5a4e00014f52838d5eacb5973399648a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9=20van=20Geldorp?= Date: Sat, 8 Oct 2005 20:11:27 +0000 Subject: [PATCH] =?UTF-8?q?Sync=20to=20Wine-20050930:=20Jakob=20Eriksson?= =?UTF-8?q?=20=20-=20Get=20rid=20of=20HeapAlloc=20casts?= =?UTF-8?q?.=20Robert=20Reif=20=20-=20Added=20keyboard?= =?UTF-8?q?=20data=20format.=20-=20Fix=20joystick=20crash=20when=20a=20but?= =?UTF-8?q?ton=20guid=20is=20specified=20in=20the=20data=20=20=20format.?= =?UTF-8?q?=20=20=20Add=20some=20parameter=20checking.=20-=20Pass=20around?= =?UTF-8?q?=20real=20version=20and=20do=20correct=20thing=20based=20on=20i?= =?UTF-8?q?t.=20=20=20Change=20cooperative=20level=20to=20pass=20on=20wind?= =?UTF-8?q?ows.=20-=20Fix=20SetProperty=20error=20returned.=20=20=20Add=20?= =?UTF-8?q?EnumDevice=20joystick=20version=20check.=20=20=20Test=20multipl?= =?UTF-8?q?e=20versions.=20-=20Added=20dinput=20tests.=20-=20Effect=20obje?= =?UTF-8?q?cts=20are=20not=20supported=20yet=20so=20don't=20crash=20when?= =?UTF-8?q?=20trying=20to=20=20=20enumerate=20them.=20Raphael=20Junqueira?= =?UTF-8?q?=20=20-=20use=20WINE=5FDINPUT=5FKEYBOAR?= =?UTF-8?q?D=5FMAX=5FKEYS=20instead=20hard-coded=20256=20value=20-=20bette?= =?UTF-8?q?r=20use=20of=20critical=20section=20-=20some=20cleanup=20to=20b?= =?UTF-8?q?etter=20understand=20code=20paths=20-=20logic=20correction=20on?= =?UTF-8?q?=20SetWindowsHookExA/UnhookWindowsHookEx=20on=20=20=20keyboard.?= =?UTF-8?q?=20Alexandre=20Julliard=20=20-=20Build=20a?= =?UTF-8?q?=20static=20list=20of=20devices=20instead=20of=20relying=20on?= =?UTF-8?q?=20ELF=20=20=20constructors.=20Gerald=20Pfeifer=20=20-=20Fix=20compilation=20of=20the=20case=20without=20p?= =?UTF-8?q?roper=20Linux=20joystick=20support.=20James=20Dean=20Anderson?= =?UTF-8?q?=20=20-=20Report=20an=20error=20if=20trying=20?= =?UTF-8?q?to=20get=20data=20from=20an=20unacquired=20mouse.=20Lionel=20Ul?= =?UTF-8?q?mer=20=20-=20more=20pretty=20print=20for?= =?UTF-8?q?=20the=20types=20flag=20-=20more=20Windows-aligned=20check=20fo?= =?UTF-8?q?r=20object=20instances=20-=20Windows=20reports=200x80=20on=20pr?= =?UTF-8?q?essed=20buttons=20not=200xFF=20-=20trace=20the=20events=20repor?= =?UTF-8?q?ted=20to=20the=20application=20-=20do=20not=20flush=20the=20buf?= =?UTF-8?q?fer=20when=20the=20application=20only=20wants=20to=20peek=20the?= =?UTF-8?q?=20=20=20number=20of=20elements=20in=20the=20queue=20-=20trace?= =?UTF-8?q?=20the=20GetDeviceState=20values=20before=20they=20are=20reset?= =?UTF-8?q?=20Alexandre=20Julliard=20=20-=20Added=20r?= =?UTF-8?q?ules=20for=20building=20import=20libraries=20in=20the=20individ?= =?UTF-8?q?ual=20dll=20=20=20makefiles,=20and=20added=20support=20for=20bu?= =?UTF-8?q?ilding=20a=20.def.a=20static=20import=20=20=20library=20too.=20?= =?UTF-8?q?-=20Added=20rules=20to=20build=20import=20libraries=20in=20the?= =?UTF-8?q?=20individual=20dll=20makefiles.=20=20=20Generate=20import=20li?= =?UTF-8?q?braries=20with=20the=20right=20name=20right=20away=20instead=20?= =?UTF-8?q?of=20=20=20using=20an=20intermediate=20.spec.def=20file.=20-=20?= =?UTF-8?q?Moved=20config=20parameters=20to=20HKCU\Software\Wine\DirectInp?= =?UTF-8?q?ut.=20-=20Added=20magic=20comments=20to=20all=20Wine-specific?= =?UTF-8?q?=20registry=20accesses=20to=20make=20=20=20them=20easier=20to?= =?UTF-8?q?=20grep.=20-=20Sort=20entry=20points=20alphabetically.=20-=20Re?= =?UTF-8?q?moved=20some=20unused=20or=20redundant=20configure=20checks.=20?= =?UTF-8?q?=20=20A=20few=20cleanups=20in=20configure.ac.=20-=20Don't=20pre?= =?UTF-8?q?fix=20the=20functions=20DllCanUnloadNow,=20DllGetClassObject=20?= =?UTF-8?q?and=20=20=20Dll(Un)RegisterServer=20with=20the=20dll=20name=20s?= =?UTF-8?q?o=20that=20the=20compiler=20can=20check=20=20=20the=20prototype?= =?UTF-8?q?s.=20-=20Fixed=20some=20traces=20to=20use=20the=20right=20print?= =?UTF-8?q?f=20format=20and=20avoid=20typecasts.=20-=20Use=20a=20more=20po?= =?UTF-8?q?rtable=20scheme=20for=20storing=20the=20name=20of=20a=20critica?= =?UTF-8?q?l=20=20=20section.=20-=20Use=20the=20COM=20macros=20instead=20o?= =?UTF-8?q?f=20accessing=20lpVtbl=20directly.=20-=20We=20are=20no=20longer?= =?UTF-8?q?=20generating=20.dbg.c=20files.=20Marcus=20Meissner=20=20-=20The=20last=20argument=20to=20MultiByteToWi?= =?UTF-8?q?deChar=20is=20wide=20character=20count=20and=20=20=20not=20the?= =?UTF-8?q?=20buffer=20size=20in=20bytes.=20Fixed=20all=20places=20where?= =?UTF-8?q?=20it=20was=20wrong.=20-=20Fixed=203=20memset()s=20which=20used?= =?UTF-8?q?=20the=20wrong=20size=20(too=20large).=20Dmitry=20Timoshkov=20=20-=20Make=20more=20of=20the=20OLE=20in?= =?UTF-8?q?terface=20vtables=20const.=20Daniel=20Remenak=20=20-=20Added=20a=20linux=20input=20system=20force=20feedb?= =?UTF-8?q?ack=20effect=20implementation.=20-=20Allow=20the=20creation=20o?= =?UTF-8?q?f=20an=20FF=20effect=20while=20the=20joystick=20is=20not=20=20?= =?UTF-8?q?=20acquired.=20-=20Failing=20to=20download=20an=20effect=20afte?= =?UTF-8?q?r=20setting=20parameters=20is=20not=20a=20=20=20fatal=20error.?= =?UTF-8?q?=20-=20Allow=20enumeration=20of=20objects=20when=20the=20device?= =?UTF-8?q?=20is=20not=20yet=20acquired.=20-=20Flag=20FF-capable=20axes=20?= =?UTF-8?q?during=20enumeration.=20-=20Protect=20FF=5FSTATUS=20usage=20to?= =?UTF-8?q?=20avoid=20compile=20errors=20on=20machines=20with=20old=20=20?= =?UTF-8?q?=20linux/input.h.=20-=20Implement=20EnumEffects,=20CreateEffect?= =?UTF-8?q?,=20EnumCreatedEffects,=20=20=20SendForceFeedbackCommand,=20and?= =?UTF-8?q?=20GetForceFeedbackStatus=20for=20linux=20input=20=20=20joystic?= =?UTF-8?q?ks.=20-=20Correct=20dinput=20handling=20of=20sliders=20and=20no?= =?UTF-8?q?n-zero-based=20axes=20through=20the=20=20=20linux=20input=20sys?= =?UTF-8?q?tem.=20-=20Correctly=20enumerate=20evdev=20joysticks=20when=20e?= =?UTF-8?q?numeration=20is=20restricted=20=20=20with=20DIEDFL=5FFORCEFEEDB?= =?UTF-8?q?ACK.=20-=20Detect=20force-feedback-capable=20linux=20event=20de?= =?UTF-8?q?vice=20joysticks=20and=20return=20=20=20DIDC=5FFORCEFEEDBACK=20?= =?UTF-8?q?when=20queried=20for=20capabilities.=20Mike=20McCormack=20=20-=20Interlocked=20LONG*=20gcc=20warning=20f?= =?UTF-8?q?ixes.=20-=20gcc=204.0=20warning=20fixes.=20-=20gcc=204.0=20warn?= =?UTF-8?q?ing=20fixes=20for=20Interlocked*=20functions.=20-=20Fix=20warni?= =?UTF-8?q?ngs=20for=20no=20force=20feedback=20case.=20Stefan=20Huehner=20?= =?UTF-8?q?=20-=20Fix=20some=20more=20-Wmissing-declar?= =?UTF-8?q?ations=20warnings.=20Vincent=20B=C3=A9ron=20=20-=20Use=20proper=20ifdefs=20around=20unistd.h.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit svn path=/trunk/; revision=18361 --- reactos/lib/dinput/device.c | 4 +- reactos/lib/dinput/device_private.h | 4 +- reactos/lib/dinput/dinput.spec | 14 +- reactos/lib/dinput/dinput.xml | 1 + reactos/lib/dinput/dinput_main.c | 31 +- reactos/lib/dinput/dinput_private.h | 4 +- reactos/lib/dinput/effect_linuxinput.c | 927 +++++++++++++++++++++++ reactos/lib/dinput/joystick_linux.c | 65 +- reactos/lib/dinput/joystick_linuxinput.c | 574 ++++++++++++-- reactos/lib/dinput/keyboard.c | 28 +- reactos/lib/dinput/mouse.c | 26 +- reactos/lib/dinput/regsvr.c | 4 +- reactos/lib/dinput/version.rc | 52 +- 13 files changed, 1570 insertions(+), 164 deletions(-) create mode 100644 reactos/lib/dinput/effect_linuxinput.c diff --git a/reactos/lib/dinput/device.c b/reactos/lib/dinput/device.c index 6139e53daed..a38dea64a5d 100644 --- a/reactos/lib/dinput/device.c +++ b/reactos/lib/dinput/device.c @@ -464,7 +464,7 @@ HRESULT WINAPI IDirectInputDevice2AImpl_SetCooperativeLevel( 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 @@ HRESULT WINAPI IDirectInputDevice2AImpl_SetEventNotification( 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; } diff --git a/reactos/lib/dinput/device_private.h b/reactos/lib/dinput/device_private.h index e7a32096efa..4f2347bcb6f 100644 --- a/reactos/lib/dinput/device_private.h +++ b/reactos/lib/dinput/device_private.h @@ -30,8 +30,8 @@ typedef struct IDirectInputDevice2AImpl IDirectInputDevice2AImpl; struct IDirectInputDevice2AImpl { - IDirectInputDevice2AVtbl *lpVtbl; - DWORD ref; + const IDirectInputDevice2AVtbl *lpVtbl; + LONG ref; GUID guid; }; diff --git a/reactos/lib/dinput/dinput.spec b/reactos/lib/dinput/dinput.spec index 9a5ec99fd43..619079526c6 100644 --- a/reactos/lib/dinput/dinput.spec +++ b/reactos/lib/dinput/dinput.spec @@ -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() diff --git a/reactos/lib/dinput/dinput.xml b/reactos/lib/dinput/dinput.xml index 9f96816e446..1cc8712c116 100644 --- a/reactos/lib/dinput/dinput.xml +++ b/reactos/lib/dinput/dinput.xml @@ -21,6 +21,7 @@ data_formats.c device.c dinput_main.c + effect_linuxinput.c joystick_linux.c joystick_linuxinput.c keyboard.c diff --git a/reactos/lib/dinput/dinput_main.c b/reactos/lib/dinput/dinput_main.c index 74f0ddf8877..cc12e7a22c2 100644 --- a/reactos/lib/dinput/dinput_main.c +++ b/reactos/lib/dinput/dinput_main.c @@ -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 @@ HRESULT WINAPI DirectInputCreateEx( { 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 @@ static HRESULT WINAPI IDirectInputAImpl_RunControlPanel(LPDIRECTINPUT7A iface, 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 @@ static HRESULT WINAPI IDirectInput8WImpl_ConfigureDevices( # 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 @@ static IDirectInput7AVtbl ddi7avt = { # 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 @@ static IDirectInput7WVtbl ddi7wvt = { # 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 @@ static IDirectInput8AVtbl ddi8avt = { #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 @@ static IDirectInput8WVtbl ddi8wvt = { 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 @@ static HRESULT WINAPI DICF_LockServer(LPCLASSFACTORY iface,BOOL dolock) { return S_OK; } -static IClassFactoryVtbl DICF_Vtbl = { +static const IClassFactoryVtbl DICF_Vtbl = { DICF_QueryInterface, DICF_AddRef, DICF_Release, @@ -678,7 +678,7 @@ static IClassFactoryImpl DINPUT_CF = {&DICF_Vtbl, 1 }; /*********************************************************************** * DllCanUnloadNow (DINPUT.@) */ -HRESULT WINAPI DINPUT_DllCanUnloadNow(void) +HRESULT WINAPI DllCanUnloadNow(void) { FIXME("(void): stub\n"); @@ -688,8 +688,7 @@ HRESULT WINAPI DINPUT_DllCanUnloadNow(void) /*********************************************************************** * 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 ) ) { diff --git a/reactos/lib/dinput/dinput_private.h b/reactos/lib/dinput/dinput_private.h index 6beb2f848ef..51385815e48 100644 --- a/reactos/lib/dinput/dinput_private.h +++ b/reactos/lib/dinput/dinput_private.h @@ -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; diff --git a/reactos/lib/dinput/effect_linuxinput.c b/reactos/lib/dinput/effect_linuxinput.c new file mode 100644 index 00000000000..d86b0aca4bf --- /dev/null +++ b/reactos/lib/dinput/effect_linuxinput.c @@ -0,0 +1,927 @@ +/* DirectInput Linux Event Device Effect + * + * Copyright 2005 Daniel Remenak + * + * Thanks to Google's Summer of Code Program (2005) + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "config.h" + +#ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION + +#include +#include +#ifdef HAVE_LINUX_INPUT_H +# include +#endif +#include +#ifdef HAVE_UNISTD_H +# include +#endif +#include +#include "wine/debug.h" +#include "wine/unicode.h" +#include "windef.h" +#include "winbase.h" +#include "winerror.h" +#include "dinput.h" + +#include "device_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(dinput); + +static const IDirectInputEffectVtbl LinuxInputEffectVtbl; +typedef struct LinuxInputEffectImpl LinuxInputEffectImpl; +struct LinuxInputEffectImpl +{ + const void *lpVtbl; + LONG ref; + GUID guid; + + /* Effect data */ + struct ff_effect effect; + + /* Parent device */ + int* fd; +}; + + +/****************************************************************************** + * DirectInputEffect Functional Helper + */ + +static DWORD _typeFromGUID(REFGUID guid) +{ + if (IsEqualGUID(guid, &GUID_ConstantForce)) { + return DIEFT_CONSTANTFORCE; + } else if (IsEqualGUID(guid, &GUID_Square) + || IsEqualGUID(guid, &GUID_Sine) + || IsEqualGUID(guid, &GUID_Triangle) + || IsEqualGUID(guid, &GUID_SawtoothUp) + || IsEqualGUID(guid, &GUID_SawtoothDown)) { + return DIEFT_PERIODIC; + } else if (IsEqualGUID(guid, &GUID_RampForce)) { + return DIEFT_RAMPFORCE; + } else if (IsEqualGUID(guid, &GUID_Spring) + || IsEqualGUID(guid, &GUID_Damper) + || IsEqualGUID(guid, &GUID_Inertia) + || IsEqualGUID(guid, &GUID_Friction)) { + return DIEFT_CONDITION; + } else if (IsEqualGUID(guid, &GUID_CustomForce)) { + return DIEFT_CUSTOMFORCE; + } else { + WARN("GUID (%s) is not a known force type\n", _dump_dinput_GUID(guid)); + return 0; + } +} + + +/****************************************************************************** + * DirectInputEffect debug helpers + */ + +static void _dump_DIEFFECT_flags(DWORD dwFlags) +{ + if (TRACE_ON(dinput)) { + unsigned int i; + static const struct { + DWORD mask; + const char *name; + } flags[] = { +#define FE(x) { x, #x} + FE(DIEFF_CARTESIAN), + FE(DIEFF_OBJECTIDS), + FE(DIEFF_OBJECTOFFSETS), + FE(DIEFF_POLAR), + FE(DIEFF_SPHERICAL) +#undef FE + }; + for (i = 0; i < (sizeof(flags) / sizeof(flags[0])); i++) + if (flags[i].mask & dwFlags) + DPRINTF("%s ", flags[i].name); + DPRINTF("\n"); + } +} + +static void _dump_DIENVELOPE(LPDIENVELOPE env) +{ + if (env->dwSize != sizeof(DIENVELOPE)) { + WARN("Non-standard DIENVELOPE structure size (%ld instead of %d).\n", + env->dwSize, sizeof(DIENVELOPE)); + } + TRACE("Envelope has attack (level: %ld time: %ld), fade (level: %ld time: %ld)\n", + env->dwAttackLevel, env->dwAttackTime, env->dwFadeLevel, env->dwFadeTime); +} + +static void _dump_DICONSTANTFORCE(LPDICONSTANTFORCE frc) +{ + TRACE("Constant force has magnitude %ld\n", frc->lMagnitude); +} + +static void _dump_DIPERIODIC(LPDIPERIODIC frc) +{ + TRACE("Periodic force has magnitude %ld, offset %ld, phase %ld, period %ld\n", + frc->dwMagnitude, frc->lOffset, frc->dwPhase, frc->dwPeriod); +} + +static void _dump_DIRAMPFORCE(LPDIRAMPFORCE frc) +{ + TRACE("Ramp force has start %ld, end %ld\n", + frc->lStart, frc->lEnd); +} + +static void _dump_DICONDITION(LPDICONDITION frc) +{ + TRACE("Condition has offset %ld, pos/neg coefficients %ld and %ld, pos/neg saturations %ld and %ld, deadband %ld\n", + frc->lOffset, frc->lPositiveCoefficient, frc->lNegativeCoefficient, + frc->dwPositiveSaturation, frc->dwNegativeSaturation, frc->lDeadBand); +} + +static void _dump_DICUSTOMFORCE(LPDICUSTOMFORCE frc) +{ + unsigned int i; + TRACE("Custom force uses %ld channels, sample period %ld. Has %ld samples at %p.\n", + frc->cChannels, frc->dwSamplePeriod, frc->cSamples, frc->rglForceData); + if (frc->cSamples % frc->cChannels != 0) + WARN("Custom force has a non-integral samples-per-channel count!\n"); + if (TRACE_ON(dinput)) { + DPRINTF("Custom force data (time aligned, axes in order):\n"); + for (i = 1; i <= frc->cSamples; ++i) { + DPRINTF("%ld ", frc->rglForceData[i]); + if (i % frc->cChannels == 0) + DPRINTF("\n"); + } + } +} + +static void _dump_DIEFFECT(LPCDIEFFECT eff, REFGUID guid) +{ + unsigned int i; + DWORD type = _typeFromGUID(guid); + + TRACE("Dumping DIEFFECT structure:\n"); + TRACE(" - dwSize: %ld\n", eff->dwSize); + if ((eff->dwSize != sizeof(DIEFFECT)) && (eff->dwSize != sizeof(DIEFFECT_DX5))) { + WARN("Non-standard DIEFFECT structure size (%ld instead of %d or %d).\n", + eff->dwSize, sizeof(DIEFFECT), sizeof(DIEFFECT_DX5)); + } + TRACE(" - dwFlags: %ld\n", eff->dwFlags); + TRACE(" "); + _dump_DIEFFECT_flags(eff->dwFlags); + TRACE(" - dwDuration: %ld\n", eff->dwDuration); + TRACE(" - dwGain: %ld\n", eff->dwGain); + if ((eff->dwGain > 10000) || (eff->dwGain < 0)) + WARN("dwGain is out of range (0 - 10,000)\n"); + TRACE(" - dwTriggerButton: %ld\n", eff->dwTriggerButton); + TRACE(" - dwTriggerRepeatInterval: %ld\n", eff->dwTriggerRepeatInterval); + TRACE(" - cAxes: %ld\n", eff->cAxes); + TRACE(" - rgdwAxes: %p\n", eff->rgdwAxes); + if (TRACE_ON(dinput)) { + TRACE(" "); + for (i = 0; i < eff->cAxes; ++i) + DPRINTF("%ld ", eff->rgdwAxes[i]); + DPRINTF("\n"); + } + TRACE(" - rglDirection: %p\n", eff->rglDirection); + TRACE(" - lpEnvelope: %p\n", eff->lpEnvelope); + TRACE(" - cbTypeSpecificParams: %ld\n", eff->cbTypeSpecificParams); + TRACE(" - lpvTypeSpecificParams: %p\n", eff->lpvTypeSpecificParams); + if (eff->dwSize > sizeof(DIEFFECT_DX5)) + TRACE(" - dwStartDelay: %ld\n", eff->dwStartDelay); + if (eff->lpEnvelope != NULL) + _dump_DIENVELOPE(eff->lpEnvelope); + if (type == DIEFT_CONSTANTFORCE) { + if (eff->cbTypeSpecificParams != sizeof(DICONSTANTFORCE)) { + WARN("Effect claims to be a constant force but the type-specific params are the wrong size!\n"); + } else { + _dump_DICONSTANTFORCE(eff->lpvTypeSpecificParams); + } + } else if (type == DIEFT_PERIODIC) { + if (eff->cbTypeSpecificParams != sizeof(DIPERIODIC)) { + WARN("Effect claims to be a periodic force but the type-specific params are the wrong size!\n"); + } else { + _dump_DIPERIODIC(eff->lpvTypeSpecificParams); + } + } else if (type == DIEFT_RAMPFORCE) { + if (eff->cbTypeSpecificParams != sizeof(DIRAMPFORCE)) { + WARN("Effect claims to be a ramp force but the type-specific params are the wrong size!\n"); + } else { + _dump_DIRAMPFORCE(eff->lpvTypeSpecificParams); + } + } else if (type == DIEFT_CONDITION) { + if (eff->cbTypeSpecificParams != sizeof(DICONDITION)) { + WARN("Effect claims to be a condition but the type-specific params are the wrong size!\n"); + } else { + _dump_DICONDITION(eff->lpvTypeSpecificParams); + } + } else if (type == DIEFT_CUSTOMFORCE) { + if (eff->cbTypeSpecificParams != sizeof(DICUSTOMFORCE)) { + WARN("Effect claims to be a custom force but the type-specific params are the wrong size!\n"); + } else { + _dump_DICUSTOMFORCE(eff->lpvTypeSpecificParams); + } + } +} + + +/****************************************************************************** + * LinuxInputEffectImpl + */ + +static ULONG WINAPI LinuxInputEffectImpl_AddRef( + LPDIRECTINPUTEFFECT iface) +{ + LinuxInputEffectImpl *This = (LinuxInputEffectImpl *)iface; + return InterlockedIncrement(&(This->ref)); +} + +static HRESULT WINAPI LinuxInputEffectImpl_Download( + LPDIRECTINPUTEFFECT iface) +{ + LinuxInputEffectImpl *This = (LinuxInputEffectImpl *)iface; + + TRACE("(this=%p)\n", This); + + if (ioctl(*(This->fd), EVIOCSFF, &This->effect) == -1) { + if (errno == ENOMEM) { + return DIERR_DEVICEFULL; + } else { + FIXME("Could not upload effect. Assuming a disconnected device.\n"); + return DIERR_INPUTLOST; + } + } + + return DI_OK; +} + +static HRESULT WINAPI LinuxInputEffectImpl_Escape( + LPDIRECTINPUTEFFECT iface, + LPDIEFFESCAPE pesc) +{ + WARN("(this=%p,%p): invalid: no hardware-specific escape codes in this" + " driver!\n", iface, pesc); + + return DI_OK; +} + +static HRESULT WINAPI LinuxInputEffectImpl_GetEffectGuid( + LPDIRECTINPUTEFFECT iface, + LPGUID pguid) +{ + LinuxInputEffectImpl *This = (LinuxInputEffectImpl*)iface; + + TRACE("(this=%p,%p)\n", This, pguid); + + pguid = &This->guid; + + return DI_OK; +} + +static HRESULT WINAPI LinuxInputEffectImpl_GetEffectStatus( + LPDIRECTINPUTEFFECT iface, + LPDWORD pdwFlags) +{ + TRACE("(this=%p,%p)\n", iface, pdwFlags); + + /* linux sends the effect status through an event. + * that event is trapped by our parent joystick driver + * and there is no clean way to pass it back to us. */ + FIXME("Not enough information to provide a status.\n"); + + (*pdwFlags) = 0; + + return DI_OK; +} + +static HRESULT WINAPI LinuxInputEffectImpl_GetParameters( + LPDIRECTINPUTEFFECT iface, + LPDIEFFECT peff, + DWORD dwFlags) +{ + HRESULT diErr = DI_OK; + LinuxInputEffectImpl *This = (LinuxInputEffectImpl *)iface; + TRACE("(this=%p,%p,%ld)\n", This, peff, dwFlags); + + /* Major conversion factors are: + * times: millisecond (linux) -> microsecond (windows) (x * 1000) + * forces: scale 0x7FFF (linux) -> scale 10000 (windows) approx ((x / 33) * 10) + * angles: scale 0x7FFF (linux) -> scale 35999 (windows) approx ((x / 33) * 36) + * angle bases: 0 -> -y (down) (linux) -> 0 -> +x (right) (windows) + */ + + if (dwFlags & DIEP_AXES) { + if (peff->cAxes < 2 /* linuxinput effects always use 2 axes, x and y */) + diErr = DIERR_MOREDATA; + peff->cAxes = 2; + if (diErr) + return diErr; + else { + peff->rgdwAxes[0] = DIJOFS_X; + peff->rgdwAxes[1] = DIJOFS_Y; + } + } + + if (dwFlags & DIEP_DIRECTION) { + if (peff->cAxes < 2) + diErr = DIERR_MOREDATA; + peff->cAxes = 2; + if (diErr) + return diErr; + else { + if (peff->dwFlags & DIEFF_CARTESIAN) { + peff->rglDirection[0] = (long)(sin(M_PI * 3 * This->effect.direction / 0x7FFF) * 1000); + peff->rglDirection[1] = (long)(cos(M_PI * 3 * This->effect.direction / 0x7FFF) * 1000); + } else { + /* Polar and spherical coordinates are the same for two or less + * axes. + * Note that we also use this case if NO flags are marked. + * According to MSDN, we should return the direction in the + * format that it was specified in, if no flags are marked. + */ + peff->rglDirection[0] = (This->effect.direction / 33) * 36 + 9000; + if (peff->rglDirection[0] > 35999) + peff->rglDirection[0] -= 35999; + } + } + } + + if (dwFlags & DIEP_DURATION) { + peff->dwDuration = (DWORD)This->effect.replay.length * 1000; + } + + if (dwFlags & DIEP_ENVELOPE) { + struct ff_envelope* env; + if (This->effect.type == FF_CONSTANT) env = &This->effect.u.constant.envelope; + else if (This->effect.type == FF_PERIODIC) env = &This->effect.u.periodic.envelope; + else if (This->effect.type == FF_RAMP) env = &This->effect.u.ramp.envelope; + else env = NULL; + if (env == NULL) { + peff->lpEnvelope = NULL; + } else if (peff->lpEnvelope == NULL) { + return DIERR_INVALIDPARAM; + } else { + peff->lpEnvelope->dwAttackLevel = (env->attack_level / 33) * 10; + peff->lpEnvelope->dwAttackTime = env->attack_length * 1000; + peff->lpEnvelope->dwFadeLevel = (env->fade_level / 33) * 10; + peff->lpEnvelope->dwFadeTime = env->fade_length * 1000; + } + } + + if (dwFlags & DIEP_GAIN) { + /* the linux input ff driver apparently has no support + * for setting the device's gain. */ + peff->dwGain = DI_FFNOMINALMAX; + } + + if (dwFlags & DIEP_SAMPLEPERIOD) { + /* the linux input ff driver has no support for setting + * the playback sample period. 0 means default. */ + peff->dwSamplePeriod = 0; + } + + if (dwFlags & DIEP_STARTDELAY) { + peff->dwStartDelay = This->effect.replay.delay * 1000; + } + + if (dwFlags & DIEP_TRIGGERBUTTON) { + FIXME("LinuxInput button mapping needs redoing; for now, assuming we're using an actual joystick.\n"); + peff->dwTriggerButton = DIJOFS_BUTTON(This->effect.trigger.button - BTN_JOYSTICK); + } + + if (dwFlags & DIEP_TRIGGERREPEATINTERVAL) { + peff->dwTriggerRepeatInterval = This->effect.trigger.interval * 1000; + } + + if (dwFlags & DIEP_TYPESPECIFICPARAMS) { + int expectedsize = 0; + if (This->effect.type == FF_PERIODIC) { + expectedsize = sizeof(DIPERIODIC); + } else if (This->effect.type == FF_CONSTANT) { + expectedsize = sizeof(DICONSTANTFORCE); + } else if (This->effect.type == FF_SPRING + || This->effect.type == FF_FRICTION + || This->effect.type == FF_INERTIA + || This->effect.type == FF_DAMPER) { + expectedsize = sizeof(DICONDITION) * 2; + } else if (This->effect.type == FF_RAMP) { + expectedsize = sizeof(DIRAMPFORCE); + } + if (expectedsize > peff->cbTypeSpecificParams) + diErr = DIERR_MOREDATA; + peff->cbTypeSpecificParams = expectedsize; + if (diErr) + return diErr; + else { + if (This->effect.type == FF_PERIODIC) { + LPDIPERIODIC tsp = (LPDIPERIODIC)(peff->lpvTypeSpecificParams); + tsp->dwMagnitude = (This->effect.u.periodic.magnitude / 33) * 10; + tsp->lOffset = (This->effect.u.periodic.offset / 33) * 10; + tsp->dwPhase = (This->effect.u.periodic.phase / 33) * 36; + tsp->dwPeriod = (This->effect.u.periodic.period * 1000); + } else if (This->effect.type == FF_CONSTANT) { + LPDICONSTANTFORCE tsp = (LPDICONSTANTFORCE)(peff->lpvTypeSpecificParams); + tsp->lMagnitude = (This->effect.u.constant.level / 33) * 10; + } else if (This->effect.type == FF_SPRING + || This->effect.type == FF_FRICTION + || This->effect.type == FF_INERTIA + || This->effect.type == FF_DAMPER) { + LPDICONDITION tsp = (LPDICONDITION)(peff->lpvTypeSpecificParams); + int i; + for (i = 0; i < 2; ++i) { + tsp[i].lOffset = (This->effect.u.condition[i].center / 33) * 10; + tsp[i].lPositiveCoefficient = (This->effect.u.condition[i].right_coeff / 33) * 10; + tsp[i].lNegativeCoefficient = (This->effect.u.condition[i].left_coeff / 33) * 10; + tsp[i].dwPositiveSaturation = (This->effect.u.condition[i].right_saturation / 33) * 10; + tsp[i].dwNegativeSaturation = (This->effect.u.condition[i].left_saturation / 33) * 10; + tsp[i].lDeadBand = (This->effect.u.condition[i].deadband / 33) * 10; + } + } else if (This->effect.type == FF_RAMP) { + LPDIRAMPFORCE tsp = (LPDIRAMPFORCE)(peff->lpvTypeSpecificParams); + tsp->lStart = (This->effect.u.ramp.start_level / 33) * 10; + tsp->lEnd = (This->effect.u.ramp.end_level / 33) * 10; + } + } + } + + return diErr; +} + +static HRESULT WINAPI LinuxInputEffectImpl_Initialize( + LPDIRECTINPUTEFFECT iface, + HINSTANCE hinst, + DWORD dwVersion, + REFGUID rguid) +{ + FIXME("(this=%p,%p,%ld,%s): stub!\n", + iface, hinst, dwVersion, debugstr_guid(rguid)); + + return DI_OK; +} + +static HRESULT WINAPI LinuxInputEffectImpl_QueryInterface( + LPDIRECTINPUTEFFECT iface, + REFIID riid, + void **ppvObject) +{ + LinuxInputEffectImpl* This = (LinuxInputEffectImpl*)iface; + + TRACE("(this=%p,%s,%p)\n", This, debugstr_guid(riid), ppvObject); + + if (IsEqualGUID(&IID_IUnknown, riid) || + IsEqualGUID(&IID_IDirectInputEffect, riid)) { + LinuxInputEffectImpl_AddRef(iface); + *ppvObject = This; + return 0; + } + + TRACE("Unsupported interface!\n"); + return E_FAIL; +} + +static HRESULT WINAPI LinuxInputEffectImpl_Start( + LPDIRECTINPUTEFFECT iface, + DWORD dwIterations, + DWORD dwFlags) +{ + struct input_event event; + LinuxInputEffectImpl* This = (LinuxInputEffectImpl*)iface; + + TRACE("(this=%p,%ld,%ld)\n", This, dwIterations, dwFlags); + + if (!(dwFlags & DIES_NODOWNLOAD)) { + /* Download the effect if necessary */ + if (This->effect.id == -1) { + HRESULT res = LinuxInputEffectImpl_Download(iface); + if (res != DI_OK) + return res; + } + } + + if (dwFlags & DIES_SOLO) { + FIXME("Solo mode requested: should be stopping all effects here!\n"); + } + + event.type = EV_FF; + event.code = This->effect.id; + event.value = dwIterations; + if (write(*(This->fd), &event, sizeof(event)) == -1) { + FIXME("Unable to write event. Assuming device disconnected.\n"); + return DIERR_INPUTLOST; + } + + return DI_OK; +} + +static HRESULT WINAPI LinuxInputEffectImpl_SetParameters( + LPDIRECTINPUTEFFECT iface, + LPCDIEFFECT peff, + DWORD dwFlags) +{ + LinuxInputEffectImpl* This = (LinuxInputEffectImpl*)iface; + DWORD type = _typeFromGUID(&This->guid); + HRESULT retval = DI_OK; + + TRACE("(this=%p,%p,%ld)\n", This, peff, dwFlags); + + _dump_DIEFFECT(peff, &This->guid); + + if ((dwFlags & !DIEP_NORESTART & !DIEP_NODOWNLOAD & !DIEP_START) == 0) { + /* set everything */ + dwFlags = DIEP_AXES | DIEP_DIRECTION | DIEP_DURATION | DIEP_ENVELOPE | + DIEP_GAIN | DIEP_SAMPLEPERIOD | DIEP_STARTDELAY | DIEP_TRIGGERBUTTON | + DIEP_TRIGGERREPEATINTERVAL | DIEP_TYPESPECIFICPARAMS; + } + + if (dwFlags & DIEP_AXES) { + /* the linux input effect system only supports one or two axes */ + if (peff->cAxes > 2) + return DIERR_INVALIDPARAM; + else if (peff->cAxes < 1) + return DIERR_INCOMPLETEEFFECT; + } + + /* some of this may look funky, but it's 'cause the linux driver and directx have + * different opinions about which way direction "0" is. directx has 0 along the x + * axis (left), linux has it along the y axis (down). */ + if (dwFlags & DIEP_DIRECTION) { + if (peff->cAxes == 1) { + if (peff->dwFlags & DIEFF_CARTESIAN) { + if (dwFlags & DIEP_AXES) { + if (peff->rgdwAxes[0] == DIJOFS_X && peff->rglDirection[0] >= 0) + This->effect.direction = 0x4000; + else if (peff->rgdwAxes[0] == DIJOFS_X && peff->rglDirection[0] < 0) + This->effect.direction = 0xC000; + else if (peff->rgdwAxes[0] == DIJOFS_Y && peff->rglDirection[0] >= 0) + This->effect.direction = 0; + else if (peff->rgdwAxes[0] == DIJOFS_Y && peff->rglDirection[0] < 0) + This->effect.direction = 0x8000; + } + } else { + /* one-axis effects must use cartesian coords */ + return DIERR_INVALIDPARAM; + } + } else { /* two axes */ + if (peff->dwFlags & DIEFF_CARTESIAN) { + /* avoid divide-by-zero */ + if (peff->rglDirection[1] == 0) { + if (peff->rglDirection[0] >= 0) + This->effect.direction = 0x4000; + else if (peff->rglDirection[0] < 0) + This->effect.direction = 0xC000; + } else { + This->effect.direction = (int)(atan(peff->rglDirection[0] / peff->rglDirection[1]) * 0x7FFF / (3 * M_PI)); + } + } else { + /* Polar and spherical are the same for 2 axes */ + /* Precision is important here, so we do double math with exact constants */ + This->effect.direction = (int)(((double)peff->rglDirection[0] - 90) / 35999) * 0x7FFF; + } + } + } + + if (dwFlags & DIEP_DURATION) + This->effect.replay.length = peff->dwDuration / 1000; + + if (dwFlags & DIEP_ENVELOPE) { + struct ff_envelope* env; + if (This->effect.type == FF_CONSTANT) env = &This->effect.u.constant.envelope; + else if (This->effect.type == FF_PERIODIC) env = &This->effect.u.periodic.envelope; + else if (This->effect.type == FF_RAMP) env = &This->effect.u.ramp.envelope; + else env = NULL; + + if (peff->lpEnvelope == NULL) { + /* if this type had an envelope, reset it + * note that length can never be zero, so we set it to something miniscule */ + if (env) { + env->attack_length = 0x10; + env->attack_level = 0x7FFF; + env->fade_length = 0x10; + env->fade_level = 0x7FFF; + } + } else { + /* did we get passed an envelope for a type that doesn't even have one? */ + if (!env) return DIERR_INVALIDPARAM; + /* copy the envelope */ + env->attack_length = peff->lpEnvelope->dwAttackTime / 1000; + env->attack_level = (peff->lpEnvelope->dwAttackLevel / 10) * 32; + env->fade_length = peff->lpEnvelope->dwFadeTime / 1000; + env->fade_level = (peff->lpEnvelope->dwFadeLevel / 10) * 32; + } + } + + /* Gain and Sample Period settings are not supported by the linux + * event system */ + if (dwFlags & DIEP_GAIN) + TRACE("Gain requested but no gain functionality present.\n"); + + if (dwFlags & DIEP_SAMPLEPERIOD) + TRACE("Sample period requested but no sample period functionality present.\n"); + + if (dwFlags & DIEP_STARTDELAY) + This->effect.replay.delay = peff->dwStartDelay / 1000; + + if (dwFlags & DIEP_TRIGGERBUTTON) { + if (peff->dwTriggerButton != -1) { + FIXME("Linuxinput button mapping needs redoing, assuming we're using a joystick.\n"); + FIXME("Trigger button translation not yet implemented!\n"); + } + This->effect.trigger.button = 0; + } + + if (dwFlags & DIEP_TRIGGERREPEATINTERVAL) + This->effect.trigger.interval = peff->dwTriggerRepeatInterval / 1000; + + if (dwFlags & DIEP_TYPESPECIFICPARAMS) { + if (!(peff->lpvTypeSpecificParams)) + return DIERR_INCOMPLETEEFFECT; + if (type == DIEFT_PERIODIC) { + LPCDIPERIODIC tsp; + if (peff->cbTypeSpecificParams != sizeof(DIPERIODIC)) + return DIERR_INVALIDPARAM; + tsp = (LPCDIPERIODIC)(peff->lpvTypeSpecificParams); + This->effect.u.periodic.magnitude = (tsp->dwMagnitude / 10) * 32; + This->effect.u.periodic.offset = (tsp->lOffset / 10) * 32; + This->effect.u.periodic.phase = (tsp->dwPhase / 9) * 8; /* == (/ 36 * 32) */ + This->effect.u.periodic.period = tsp->dwPeriod / 1000; + } else if (type == DIEFT_CONSTANTFORCE) { + LPCDICONSTANTFORCE tsp; + if (peff->cbTypeSpecificParams != sizeof(DICONSTANTFORCE)) + return DIERR_INVALIDPARAM; + tsp = (LPCDICONSTANTFORCE)(peff->lpvTypeSpecificParams); + This->effect.u.constant.level = (tsp->lMagnitude / 10) * 32; + } else if (type == DIEFT_RAMPFORCE) { + LPCDIRAMPFORCE tsp; + if (peff->cbTypeSpecificParams != sizeof(DIRAMPFORCE)) + return DIERR_INVALIDPARAM; + tsp = (LPCDIRAMPFORCE)(peff->lpvTypeSpecificParams); + This->effect.u.ramp.start_level = (tsp->lStart / 10) * 32; + This->effect.u.ramp.end_level = (tsp->lStart / 10) * 32; + } else if (type == DIEFT_CONDITION) { + LPCDICONDITION tsp = (LPCDICONDITION)(peff->lpvTypeSpecificParams); + if (peff->cbTypeSpecificParams == sizeof(DICONDITION)) { + /* One condition block. This needs to be rotated to direction, + * and expanded to separate x and y conditions. */ + int i; + double factor[2]; + factor[0] = asin((This->effect.direction * 3.0 * M_PI) / 0x7FFF); + factor[1] = acos((This->effect.direction * 3.0 * M_PI) / 0x7FFF); + for (i = 0; i < 2; ++i) { + This->effect.u.condition[i].center = (int)(factor[i] * (tsp->lOffset / 10) * 32); + This->effect.u.condition[i].right_coeff = (int)(factor[i] * (tsp->lPositiveCoefficient / 10) * 32); + This->effect.u.condition[i].left_coeff = (int)(factor[i] * (tsp->lNegativeCoefficient / 10) * 32); + This->effect.u.condition[i].right_saturation = (int)(factor[i] * (tsp->dwPositiveSaturation / 10) * 32); + This->effect.u.condition[i].left_saturation = (int)(factor[i] * (tsp->dwNegativeSaturation / 10) * 32); + This->effect.u.condition[i].deadband = (int)(factor[i] * (tsp->lDeadBand / 10) * 32); + } + } else if (peff->cbTypeSpecificParams == 2 * sizeof(DICONDITION)) { + /* Two condition blocks. Direct parameter copy. */ + int i; + for (i = 0; i < 2; ++i) { + This->effect.u.condition[i].center = (tsp[i].lOffset / 10) * 32; + This->effect.u.condition[i].right_coeff = (tsp[i].lPositiveCoefficient / 10) * 32; + This->effect.u.condition[i].left_coeff = (tsp[i].lNegativeCoefficient / 10) * 32; + This->effect.u.condition[i].right_saturation = (tsp[i].dwPositiveSaturation / 10) * 32; + This->effect.u.condition[i].left_saturation = (tsp[i].dwNegativeSaturation / 10) * 32; + This->effect.u.condition[i].deadband = (tsp[i].lDeadBand / 10) * 32; + } + } else { + return DIERR_INVALIDPARAM; + } + } else { + FIXME("Custom force types are not supported\n"); + return DIERR_INVALIDPARAM; + } + } + + if (!(dwFlags & DIEP_NODOWNLOAD)) + retval = LinuxInputEffectImpl_Download(iface); + if (retval != DI_OK) + return DI_DOWNLOADSKIPPED; + + if (dwFlags & DIEP_NORESTART) + TRACE("DIEP_NORESTART: not handled (we have no control of that).\n"); + + if (dwFlags & DIEP_START) + retval = LinuxInputEffectImpl_Start(iface, 1, 0); + if (retval != DI_OK) + return retval; + + return DI_OK; +} + +static ULONG WINAPI LinuxInputEffectImpl_Release( + LPDIRECTINPUTEFFECT iface) +{ + LinuxInputEffectImpl *This = (LinuxInputEffectImpl *)iface; + ULONG ref = InterlockedDecrement(&(This->ref)); + + if (ref == 0) + HeapFree(GetProcessHeap(), 0, This); + return ref; +} + +static HRESULT WINAPI LinuxInputEffectImpl_Stop( + LPDIRECTINPUTEFFECT iface) +{ + struct input_event event; + LinuxInputEffectImpl *This = (LinuxInputEffectImpl *)iface; + + TRACE("(this=%p)\n", This); + + event.type = EV_FF; + event.code = This->effect.id; + event.value = 0; + /* we don't care about the success or failure of this call */ + write(*(This->fd), &event, sizeof(event)); + + return DI_OK; +} + +static HRESULT WINAPI LinuxInputEffectImpl_Unload( + LPDIRECTINPUTEFFECT iface) +{ + LinuxInputEffectImpl *This = (LinuxInputEffectImpl *)iface; + TRACE("(this=%p)\n", This); + + /* Erase the downloaded effect */ + if (ioctl(*(This->fd), EVIOCRMFF, This->effect.id) == -1) + return DIERR_INVALIDPARAM; + + /* Mark the effect as deallocated */ + This->effect.id = -1; + + return DI_OK; +} + +/****************************************************************************** + * LinuxInputEffect + */ + +HRESULT linuxinput_create_effect( + int* fd, + REFGUID rguid, + LPDIRECTINPUTEFFECT* peff) +{ + LinuxInputEffectImpl* newEffect = HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, sizeof(LinuxInputEffectImpl)); + DWORD type = _typeFromGUID(rguid); + + newEffect->lpVtbl = &LinuxInputEffectVtbl; + newEffect->ref = 1; + memcpy(&(newEffect->guid), rguid, sizeof(*rguid)); + newEffect->fd = fd; + + /* set the type. this cannot be changed over the effect's life. */ + switch (type) { + case DIEFT_PERIODIC: + newEffect->effect.type = FF_PERIODIC; + if (IsEqualGUID(rguid, &GUID_Sine)) { + newEffect->effect.u.periodic.waveform = FF_SINE; + } else if (IsEqualGUID(rguid, &GUID_Triangle)) { + newEffect->effect.u.periodic.waveform = FF_TRIANGLE; + } else if (IsEqualGUID(rguid, &GUID_Square)) { + newEffect->effect.u.periodic.waveform = FF_SQUARE; + } else if (IsEqualGUID(rguid, &GUID_SawtoothUp)) { + newEffect->effect.u.periodic.waveform = FF_SAW_UP; + } else if (IsEqualGUID(rguid, &GUID_SawtoothDown)) { + newEffect->effect.u.periodic.waveform = FF_SAW_DOWN; + } + break; + case DIEFT_CONSTANTFORCE: + newEffect->effect.type = FF_CONSTANT; + break; + case DIEFT_RAMPFORCE: + newEffect->effect.type = FF_RAMP; + break; + case DIEFT_CONDITION: + if (IsEqualGUID(rguid, &GUID_Spring)) { + newEffect->effect.type = FF_SPRING; + } else if (IsEqualGUID(rguid, &GUID_Friction)) { + newEffect->effect.type = FF_FRICTION; + } else if (IsEqualGUID(rguid, &GUID_Inertia)) { + newEffect->effect.type = FF_INERTIA; + } else if (IsEqualGUID(rguid, &GUID_Damper)) { + newEffect->effect.type = FF_DAMPER; + } + break; + case DIEFT_CUSTOMFORCE: + FIXME("Custom forces are not supported.\n"); + HeapFree(GetProcessHeap(), 0, newEffect); + return DIERR_INVALIDPARAM; + default: + FIXME("Unkown force type.\n"); + HeapFree(GetProcessHeap(), 0, newEffect); + return DIERR_INVALIDPARAM; + } + + /* mark as non-uploaded */ + newEffect->effect.id = -1; + + *peff = (LPDIRECTINPUTEFFECT)newEffect; + + TRACE("Creating linux input system effect (%p) with guid %s\n", + *peff, _dump_dinput_GUID(rguid)); + + return DI_OK; +} + +HRESULT linuxinput_get_info_A( + int fd, + REFGUID rguid, + LPDIEFFECTINFOA info) +{ + DWORD type = _typeFromGUID(rguid); + + TRACE("(%d, %s, %p) type=%ld\n", fd, _dump_dinput_GUID(rguid), info, type); + + if (!info) return E_POINTER; + + if (info->dwSize != sizeof(DIEFFECTINFOA)) return DIERR_INVALIDPARAM; + + info->guid = *rguid; + + info->dwEffType = type; + /* the event device API does not support querying for all these things + * therefore we assume that we have support for them + * that's not as dangerous as it sounds, since drivers are allowed to + * ignore parameters they claim to support anyway */ + info->dwEffType |= DIEFT_DEADBAND | DIEFT_FFATTACK | DIEFT_FFFADE + | DIEFT_POSNEGCOEFFICIENTS | DIEFT_POSNEGSATURATION + | DIEFT_SATURATION | DIEFT_STARTDELAY; + + /* again, assume we have support for everything */ + info->dwStaticParams = DIEP_ALLPARAMS; + info->dwDynamicParams = info->dwStaticParams; + + /* yes, this is windows behavior (print the GUID_Name for name) */ + strcpy((char*)&(info->tszName), _dump_dinput_GUID(rguid)); + + return DI_OK; +} + +HRESULT linuxinput_get_info_W( + int fd, + REFGUID rguid, + LPDIEFFECTINFOW info) +{ + DWORD type = _typeFromGUID(rguid); + + TRACE("(%d, %s, %p) type=%ld\n", fd, _dump_dinput_GUID(rguid), info, type); + + if (!info) return E_POINTER; + + if (info->dwSize != sizeof(DIEFFECTINFOW)) return DIERR_INVALIDPARAM; + + info->guid = *rguid; + + info->dwEffType = type; + /* the event device API does not support querying for all these things + * therefore we assume that we have support for them + * that's not as dangerous as it sounds, since drivers are allowed to + * ignore parameters they claim to support anyway */ + info->dwEffType |= DIEFT_DEADBAND | DIEFT_FFATTACK | DIEFT_FFFADE + | DIEFT_POSNEGCOEFFICIENTS | DIEFT_POSNEGSATURATION + | DIEFT_SATURATION | DIEFT_STARTDELAY; + + /* again, assume we have support for everything */ + info->dwStaticParams = DIEP_ALLPARAMS; + info->dwDynamicParams = info->dwStaticParams; + + /* yes, this is windows behavior (print the GUID_Name for name) */ + MultiByteToWideChar(CP_ACP, 0, _dump_dinput_GUID(rguid), -1, + (WCHAR*)&(info->tszName), MAX_PATH); + + return DI_OK; +} + +static const IDirectInputEffectVtbl LinuxInputEffectVtbl = { + LinuxInputEffectImpl_QueryInterface, + LinuxInputEffectImpl_AddRef, + LinuxInputEffectImpl_Release, + LinuxInputEffectImpl_Initialize, + LinuxInputEffectImpl_GetEffectGuid, + LinuxInputEffectImpl_GetParameters, + LinuxInputEffectImpl_SetParameters, + LinuxInputEffectImpl_Start, + LinuxInputEffectImpl_Stop, + LinuxInputEffectImpl_GetEffectStatus, + LinuxInputEffectImpl_Download, + LinuxInputEffectImpl_Unload, + LinuxInputEffectImpl_Escape +}; + +#endif /* HAVE_STRUCT_FF_EFFECT_DIRECTION */ diff --git a/reactos/lib/dinput/joystick_linux.c b/reactos/lib/dinput/joystick_linux.c index 14ad4b0e254..6c494277861 100644 --- a/reactos/lib/dinput/joystick_linux.c +++ b/reactos/lib/dinput/joystick_linux.c @@ -84,12 +84,12 @@ typedef struct { } 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 @@ static BOOL joydev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTAN 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 @@ inline static DWORD get_config_key( HKEY defkey, HKEY appkey, const char *name, 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 @@ static HRESULT setup_dinput_options(JoystickImpl * device) return DI_OK; } -void calculate_ids(JoystickImpl* device) +static void calculate_ids(JoystickImpl* device) { int i; int axis = 0; @@ -437,7 +436,7 @@ void calculate_ids(JoystickImpl* device) } } -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 @@ static HRESULT alloc_device(REFGUID rguid, LPVOID jvt, IDirectInputImpl *dinput, 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 @@ static ULONG WINAPI JoystickAImpl_Release(LPDIRECTINPUTDEVICE8A iface) /* 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 @@ static HRESULT WINAPI JoystickAImpl_Unacquire(LPDIRECTINPUTDEVICE8A iface) 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 @@ LONG map_axis(JoystickImpl * This, short val, short index) } /* 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 @@ static HRESULT WINAPI JoystickAImpl_GetDeviceData( 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 @@ static HRESULT WINAPI JoystickAImpl_SetProperty( _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 @@ static HRESULT WINAPI JoystickAImpl_SetProperty( 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 @@ static HRESULT WINAPI JoystickAImpl_SetEventNotification( ) { 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 @@ static HRESULT WINAPI JoystickAImpl_GetProperty( _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 @@ static HRESULT WINAPI JoystickAImpl_GetProperty( 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 @@ HRESULT WINAPI JoystickWImpl_GetDeviceInfo( return DI_OK; } -static IDirectInputDevice8AVtbl JoystickAvt = +static const IDirectInputDevice8AVtbl JoystickAvt = { IDirectInputDevice2AImpl_QueryInterface, IDirectInputDevice2AImpl_AddRef, @@ -1682,7 +1681,7 @@ static IDirectInputDevice8AVtbl JoystickAvt = # define XCAST(fun) (void*) #endif -static IDirectInputDevice8WVtbl SysJoystickWvt = +static const IDirectInputDevice8WVtbl SysJoystickWvt = { IDirectInputDevice2WImpl_QueryInterface, XCAST(AddRef)IDirectInputDevice2AImpl_AddRef, diff --git a/reactos/lib/dinput/joystick_linuxinput.c b/reactos/lib/dinput/joystick_linuxinput.c index 3b17f51371f..4660ca440d0 100644 --- a/reactos/lib/dinput/joystick_linuxinput.c +++ b/reactos/lib/dinput/joystick_linuxinput.c @@ -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 +# if defined(EVIOCGBIT) && defined(EV_ABS) && defined(BTN_PINKIE) +# define HAVE_CORRECT_LINUXINPUT_H +# endif #endif #include "wine/debug.h" @@ -65,13 +69,25 @@ WINE_DEFAULT_DEBUG_CHANNEL(dinput); #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 @@ struct JoystickImpl 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 @@ struct JoystickImpl #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 @@ static void fake_current_js_state(JoystickImpl *ji); #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 @@ static int joydev_have(void) 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 @@ static BOOL joydev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTAN (((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 @@ static BOOL joydev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTAN (((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 @@ static BOOL joydev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTAN 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 @@ static JoystickImpl *alloc_device(REFGUID rguid, LPVOID jvt, IDirectInputImpl *d 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;iwantmin[i] = -32768; @@ -269,7 +324,7 @@ static HRESULT joydev_create_deviceA(IDirectInputImpl *dinput, REFGUID rguid, RE { int havejoy = 0; - havejoy = joydev_have(); + havejoy = joydev_have(FALSE); if (!havejoy) return DIERR_DEVICENOTREG; @@ -296,7 +351,7 @@ static HRESULT joydev_create_deviceW(IDirectInputImpl *dinput, REFGUID rguid, RE { int havejoy = 0; - havejoy = joydev_have(); + havejoy = joydev_have(FALSE); if (!havejoy) return DIERR_DEVICENOTREG; @@ -338,6 +393,9 @@ static ULONG WINAPI JoystickAImpl_Release(LPDIRECTINPUTDEVICE8A iface) 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 @@ static HRESULT WINAPI JoystickAImpl_Acquire(LPDIRECTINPUTDEVICE8A iface) 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->absbits)) && + 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->absbits)) && (-1!=ioctl(This->joyfd,EVIOCGBIT(EV_KEY,sizeof(This->keybits)),This->keybits)) && (test_bit(This->absbits,ABS_X) && test_bit(This->absbits,ABS_Y) && (test_bit(This->keybits,BTN_TRIGGER)|| @@ -407,6 +478,30 @@ static HRESULT WINAPI JoystickAImpl_Acquire(LPDIRECTINPUTDEVICE8A iface) 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->ffbits)) { + 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;iabsbits,i)) { if (-1==ioctl(This->joyfd,EVIOCGABS(i),&(This->axes[i]))) @@ -468,7 +563,9 @@ map_axis(JoystickImpl* This, int axis, int val) { 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*/ @@ -492,6 +589,8 @@ static void fake_current_js_state(JoystickImpl *ji) 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 @@ static void joy_polldev(JoystickImpl *This) { This->js.lRz = map_axis(This,ABS_RZ,ie.value); GEN_EVENT(DIJOFS_RZ,This->js.lRz,ie.time.tv_usec,(This->dinput->evsequence)++); 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 @@ static HRESULT WINAPI JoystickAImpl_SetProperty(LPDIRECTINPUTDEVICE8A iface, 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 @@ static HRESULT WINAPI JoystickAImpl_SetProperty(LPDIRECTINPUTDEVICE8A iface, 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 @@ static HRESULT WINAPI JoystickAImpl_SetProperty(LPDIRECTINPUTDEVICE8A iface, 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 @@ static HRESULT WINAPI JoystickAImpl_SetEventNotification( ) { 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 @@ static HRESULT WINAPI JoystickAImpl_GetCapabilities( buttons=0; for (i=0;ikeybits,i)) buttons++; + if (This->has_ff) + lpDIDevCaps->dwFlags |= DIDC_FORCEFEEDBACK; + lpDIDevCaps->dwAxes = axes; lpDIDevCaps->dwButtons = buttons; @@ -795,7 +912,6 @@ static HRESULT WINAPI JoystickAImpl_EnumObjects( 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 @@ static HRESULT WINAPI JoystickAImpl_EnumObjects( 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 @@ static HRESULT WINAPI JoystickAImpl_EnumObjects( 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<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 @@ static HRESULT WINAPI JoystickAImpl_EnumObjects( } 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 @@ static HRESULT WINAPI JoystickAImpl_GetProperty(LPDIRECTINPUTDEVICE8A iface, _dump_DIPROPHEADER(pdiph); if (!HIWORD(rguid)) { - switch ((DWORD)rguid) { + switch (LOWORD(rguid)) { case (DWORD) DIPROP_BUFFERSIZE: { LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph; @@ -999,7 +1135,7 @@ static HRESULT WINAPI JoystickAImpl_GetProperty(LPDIRECTINPUTDEVICE8A iface, } default: - FIXME("Unknown type %ld (%s)\n",(DWORD)rguid,debugstr_guid(rguid)); + FIXME("Unknown type %p (%s)\n",rguid,debugstr_guid(rguid)); break; } } @@ -1008,7 +1144,351 @@ static HRESULT WINAPI JoystickAImpl_GetProperty(LPDIRECTINPUTDEVICE8A iface, 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; +} + +static HRESULT WINAPI JoystickWImpl_EnumEffects(LPDIRECTINPUTDEVICE8W iface, + LPDIENUMEFFECTSCALLBACKW lpCallback, + LPVOID pvRef, + DWORD dwEffType) +{ +#ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION + /* seems silly to duplicate all this code but all the structures and functions + * are actually different (A/W) */ + DIEFFECTINFOW 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(DIEFFECTINFOW); + + /* 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; +} + +/******************************************************************************* + * GetEffectInfo - Get information about a particular effect + */ +static HRESULT WINAPI JoystickAImpl_GetEffectInfo(LPDIRECTINPUTDEVICE8A iface, + LPDIEFFECTINFOA pdei, + REFGUID guid) +{ + JoystickImpl* This = (JoystickImpl*)iface; + + TRACE("(this=%p,%p,%s)\n", This, pdei, _dump_dinput_GUID(guid)); + +#ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION + return linuxinput_get_info_A(This->joyfd, guid, pdei); +#else + return DI_OK; +#endif +} + +static HRESULT WINAPI JoystickWImpl_GetEffectInfo(LPDIRECTINPUTDEVICE8W iface, + LPDIEFFECTINFOW pdei, + REFGUID guid) +{ + JoystickImpl* This = (JoystickImpl*)iface; + + TRACE("(this=%p,%p,%s)\n", This, pdei, _dump_dinput_GUID(guid)); + +#ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION + return linuxinput_get_info_W(This->joyfd, guid, pdei); +#else + return DI_OK; +#endif +} + +/******************************************************************************* + * GetForceFeedbackState - Get information about the device's FF state + */ +static HRESULT WINAPI JoystickAImpl_GetForceFeedbackState( + LPDIRECTINPUTDEVICE8A iface, + LPDWORD pdwOut) +{ + JoystickImpl* This = (JoystickImpl*)iface; + + TRACE("(this=%p,%p)\n", This, pdwOut); + + (*pdwOut) = 0; + +#ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION + /* DIGFFS_STOPPED is the only mandatory flag to report */ + if (This->ff_state == FF_STATUS_STOPPED) + (*pdwOut) |= DIGFFS_STOPPED; +#endif + + return DI_OK; +} + +/******************************************************************************* + * SendForceFeedbackCommand - Send a command to the device's FF system + */ +static HRESULT WINAPI JoystickAImpl_SendForceFeedbackCommand( + LPDIRECTINPUTDEVICE8A iface, + DWORD dwFlags) +{ + JoystickImpl* This = (JoystickImpl*)iface; + TRACE("(this=%p,%ld)\n", This, dwFlags); + +#ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION + if (dwFlags == DISFFC_STOPALL) { + /* Stop all effects */ + EffectListItem* itr = This->top_effect; + while (itr) { + IDirectInputEffect_Stop(itr->ref); + itr = itr->next; + } + } else if (dwFlags == DISFFC_RESET) { + /* Stop, unload, release and free all effects */ + /* This returns the device to its "bare" state */ + while (This->top_effect) { + EffectListItem* temp = This->top_effect; + IDirectInputEffect_Stop(temp->ref); + IDirectInputEffect_Unload(temp->ref); + IDirectInputEffect_Release(temp->ref); + This->top_effect = temp->next; + free(temp); + } + } else if (dwFlags == DISFFC_PAUSE || dwFlags == DISFFC_CONTINUE) { + FIXME("No support for Pause or Continue in linux\n"); + } else if (dwFlags == DISFFC_SETACTUATORSOFF + || dwFlags == DISFFC_SETACTUATORSON) { + FIXME("No direct actuator control in linux\n"); + } else { + FIXME("Unknown Force Feedback Command!\n"); + return DIERR_INVALIDPARAM; + } + return DI_OK; +#else + return DIERR_UNSUPPORTED; +#endif +} + +/******************************************************************************* + * EnumCreatedEffectObjects - Enumerate all the effects that have been + * created for this device. + */ +static HRESULT WINAPI JoystickAImpl_EnumCreatedEffectObjects( + LPDIRECTINPUTDEVICE8A iface, + LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback, + LPVOID pvRef, + DWORD dwFlags) +{ + /* this function is safe to call on non-ff-enabled builds */ + + JoystickImpl* This = (JoystickImpl*)iface; + EffectListItem* itr = This->top_effect; + TRACE("(this=%p,%p,%p,%ld)\n", This, lpCallback, pvRef, dwFlags); + + if (!lpCallback) + return DIERR_INVALIDPARAM; + + if (dwFlags != 0) + FIXME("Flags specified, but no flags exist yet (DX9)!"); + + while (itr) { + (*lpCallback)(itr->ref, pvRef); + itr = itr->next; + } + + return DI_OK; +} + +static const IDirectInputDevice8AVtbl JoystickAvt = { IDirectInputDevice2AImpl_QueryInterface, IDirectInputDevice2AImpl_AddRef, @@ -1028,12 +1508,12 @@ static IDirectInputDevice8AVtbl JoystickAvt = IDirectInputDevice2AImpl_GetDeviceInfo, IDirectInputDevice2AImpl_RunControlPanel, IDirectInputDevice2AImpl_Initialize, - IDirectInputDevice2AImpl_CreateEffect, - IDirectInputDevice2AImpl_EnumEffects, - IDirectInputDevice2AImpl_GetEffectInfo, - IDirectInputDevice2AImpl_GetForceFeedbackState, - IDirectInputDevice2AImpl_SendForceFeedbackCommand, - IDirectInputDevice2AImpl_EnumCreatedEffectObjects, + JoystickAImpl_CreateEffect, + JoystickAImpl_EnumEffects, + JoystickAImpl_GetEffectInfo, + JoystickAImpl_GetForceFeedbackState, + JoystickAImpl_SendForceFeedbackCommand, + JoystickAImpl_EnumCreatedEffectObjects, IDirectInputDevice2AImpl_Escape, JoystickAImpl_Poll, IDirectInputDevice2AImpl_SendDeviceData, @@ -1050,7 +1530,7 @@ static IDirectInputDevice8AVtbl JoystickAvt = # define XCAST(fun) (void*) #endif -static IDirectInputDevice8WVtbl JoystickWvt = +static const IDirectInputDevice8WVtbl JoystickWvt = { IDirectInputDevice2WImpl_QueryInterface, XCAST(AddRef)IDirectInputDevice2AImpl_AddRef, @@ -1070,12 +1550,12 @@ static IDirectInputDevice8WVtbl JoystickWvt = IDirectInputDevice2WImpl_GetDeviceInfo, XCAST(RunControlPanel)IDirectInputDevice2AImpl_RunControlPanel, XCAST(Initialize)IDirectInputDevice2AImpl_Initialize, - XCAST(CreateEffect)IDirectInputDevice2AImpl_CreateEffect, - IDirectInputDevice2WImpl_EnumEffects, - IDirectInputDevice2WImpl_GetEffectInfo, - XCAST(GetForceFeedbackState)IDirectInputDevice2AImpl_GetForceFeedbackState, - XCAST(SendForceFeedbackCommand)IDirectInputDevice2AImpl_SendForceFeedbackCommand, - XCAST(EnumCreatedEffectObjects)IDirectInputDevice2AImpl_EnumCreatedEffectObjects, + XCAST(CreateEffect)JoystickAImpl_CreateEffect, + JoystickWImpl_EnumEffects, + JoystickWImpl_GetEffectInfo, + XCAST(GetForceFeedbackState)JoystickAImpl_GetForceFeedbackState, + XCAST(SendForceFeedbackCommand)JoystickAImpl_SendForceFeedbackCommand, + XCAST(EnumCreatedEffectObjects)JoystickAImpl_EnumCreatedEffectObjects, XCAST(Escape)IDirectInputDevice2AImpl_Escape, XCAST(Poll)JoystickAImpl_Poll, XCAST(SendDeviceData)IDirectInputDevice2AImpl_SendDeviceData, diff --git a/reactos/lib/dinput/keyboard.c b/reactos/lib/dinput/keyboard.c index c8269ab63cb..aa6cbcbe387 100644 --- a/reactos/lib/dinput/keyboard.c +++ b/reactos/lib/dinput/keyboard.c @@ -40,14 +40,14 @@ WINE_DEFAULT_DEBUG_CHANNEL(dinput); #define WINE_DINPUT_KEYBOARD_MAX_KEYS 256 -static IDirectInputDevice8AVtbl SysKeyboardAvt; -static IDirectInputDevice8WVtbl SysKeyboardWvt; +static const IDirectInputDevice8AVtbl SysKeyboardAvt; +static const IDirectInputDevice8WVtbl SysKeyboardWvt; typedef struct SysKeyboardImpl SysKeyboardImpl; struct SysKeyboardImpl { - LPVOID lpVtbl; - DWORD ref; + const void *lpVtbl; + LONG ref; GUID guid; IDirectInputImpl* dinput; @@ -83,11 +83,11 @@ static CRITICAL_SECTION_DEBUG critsect_debug = { 0, 0, &keyboard_crit, { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList }, - 0, 0, { 0, (DWORD)(__FILE__ ": keyboard_crit") } + 0, 0, { (DWORD_PTR)(__FILE__ ": keyboard_crit") } }; static CRITICAL_SECTION keyboard_crit = { &critsect_debug, -1, 0, 0, 0, 0 }; -static DWORD keyboard_users = 0; +static LONG keyboard_users = 0; static HHOOK keyboard_hook = NULL; LRESULT CALLBACK KeyboardCallback( int code, WPARAM wparam, LPARAM lparam ) @@ -238,7 +238,7 @@ static BOOL keyboarddev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEI return FALSE; } -static SysKeyboardImpl *alloc_device(REFGUID rguid, LPVOID kvt, IDirectInputImpl *dinput) +static SysKeyboardImpl *alloc_device(REFGUID rguid, const void *kvt, IDirectInputImpl *dinput) { SysKeyboardImpl* newDevice; DWORD kbd_users; @@ -342,7 +342,7 @@ static HRESULT WINAPI SysKeyboardAImpl_SetProperty( TRACE("(size=%ld,headersize=%ld,obj=%ld,how=%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; @@ -356,7 +356,7 @@ static HRESULT WINAPI SysKeyboardAImpl_SetProperty( break; } default: - WARN("Unknown type %ld\n",(DWORD)rguid); + WARN("Unknown type %p\n",rguid); break; } } @@ -373,7 +373,7 @@ static HRESULT WINAPI SysKeyboardAImpl_GetProperty( TRACE("(size=%ld,headersize=%ld,obj=%ld,how=%ld\n", ph->dwSize,ph->dwHeaderSize,ph->dwObj,ph->dwHow); if (!HIWORD(rguid)) { - switch ((DWORD)rguid) { + switch (LOWORD(rguid)) { case (DWORD) DIPROP_BUFFERSIZE: { LPDIPROPDWORD pd = (LPDIPROPDWORD)ph; @@ -387,7 +387,7 @@ static HRESULT WINAPI SysKeyboardAImpl_GetProperty( break; } default: - WARN("Unknown type %ld\n",(DWORD)rguid); + WARN("Unknown type %p\n",rguid); break; } } @@ -597,7 +597,7 @@ static HRESULT WINAPI SysKeyboardAImpl_SetEventNotification(LPDIRECTINPUTDEVICE8 HANDLE hnd) { SysKeyboardImpl *This = (SysKeyboardImpl *)iface; - TRACE("(this=%p,0x%08lx)\n",This,(DWORD)hnd); + TRACE("(this=%p,%p)\n",This,hnd); This->hEvent = hnd; return DI_OK; @@ -747,7 +747,7 @@ static HRESULT WINAPI SysKeyboardWImpl_GetDeviceInfo(LPDIRECTINPUTDEVICE8W iface return DI_OK; } -static IDirectInputDevice8AVtbl SysKeyboardAvt = +static const IDirectInputDevice8AVtbl SysKeyboardAvt = { IDirectInputDevice2AImpl_QueryInterface, IDirectInputDevice2AImpl_AddRef, @@ -789,7 +789,7 @@ static IDirectInputDevice8AVtbl SysKeyboardAvt = # define XCAST(fun) (void*) #endif -static IDirectInputDevice8WVtbl SysKeyboardWvt = +static const IDirectInputDevice8WVtbl SysKeyboardWvt = { IDirectInputDevice2WImpl_QueryInterface, XCAST(AddRef)IDirectInputDevice2AImpl_AddRef, diff --git a/reactos/lib/dinput/mouse.c b/reactos/lib/dinput/mouse.c index eb1c64c571d..f731d12a062 100644 --- a/reactos/lib/dinput/mouse.c +++ b/reactos/lib/dinput/mouse.c @@ -95,8 +95,8 @@ static const DIDATAFORMAT Wine_InternalMouseFormat = { (LPDIOBJECTDATAFORMAT) Wine_InternalMouseObjectFormat }; -static IDirectInputDevice8AVtbl SysMouseAvt; -static IDirectInputDevice8WVtbl SysMouseWvt; +static const IDirectInputDevice8AVtbl SysMouseAvt; +static const IDirectInputDevice8WVtbl SysMouseWvt; typedef struct SysMouseImpl SysMouseImpl; @@ -108,8 +108,8 @@ typedef enum { struct SysMouseImpl { - LPVOID lpVtbl; - DWORD ref; + const void *lpVtbl; + LONG ref; GUID guid; IDirectInputImpl *dinput; @@ -241,7 +241,7 @@ static BOOL mousedev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINST return FALSE; } -static SysMouseImpl *alloc_device(REFGUID rguid, LPVOID mvt, IDirectInputImpl *dinput) +static SysMouseImpl *alloc_device(REFGUID rguid, const void *mvt, IDirectInputImpl *dinput) { int offset_array[WINE_INTERNALMOUSE_NUM_OBJS] = { FIELD_OFFSET(Wine_InternalMouseData, lX), @@ -363,7 +363,7 @@ static HRESULT WINAPI SysMouseAImpl_SetCooperativeLevel( { SysMouseImpl *This = (SysMouseImpl *)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 : "); @@ -865,7 +865,7 @@ static HRESULT WINAPI SysMouseAImpl_SetProperty(LPDIRECTINPUTDEVICE8A iface, TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(rguid),ph); if (!HIWORD(rguid)) { - switch ((DWORD)rguid) { + switch (LOWORD(rguid)) { case (DWORD) DIPROP_BUFFERSIZE: { LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph; @@ -884,7 +884,7 @@ static HRESULT WINAPI SysMouseAImpl_SetProperty(LPDIRECTINPUTDEVICE8A iface, break; } default: - FIXME("Unknown type %ld (%s)\n",(DWORD)rguid,debugstr_guid(rguid)); + FIXME("Unknown type %p (%s)\n",rguid,debugstr_guid(rguid)); break; } } @@ -908,7 +908,7 @@ static HRESULT WINAPI SysMouseAImpl_GetProperty(LPDIRECTINPUTDEVICE8A iface, _dump_DIPROPHEADER(pdiph); if (!HIWORD(rguid)) { - switch ((DWORD)rguid) { + switch (LOWORD(rguid)) { case (DWORD) DIPROP_BUFFERSIZE: { LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph; @@ -943,7 +943,7 @@ static HRESULT WINAPI SysMouseAImpl_GetProperty(LPDIRECTINPUTDEVICE8A iface, } default: - FIXME("Unknown type %ld (%s)\n",(DWORD)rguid,debugstr_guid(rguid)); + FIXME("Unknown type %p (%s)\n",rguid,debugstr_guid(rguid)); break; } } @@ -960,7 +960,7 @@ static HRESULT WINAPI SysMouseAImpl_SetEventNotification(LPDIRECTINPUTDEVICE8A i HANDLE hnd) { SysMouseImpl *This = (SysMouseImpl *)iface; - TRACE("(this=%p,0x%08lx)\n",This,(DWORD)hnd); + TRACE("(this=%p,%p)\n",This,hnd); This->hEvent = hnd; @@ -1133,7 +1133,7 @@ static HRESULT WINAPI SysMouseWImpl_GetDeviceInfo(LPDIRECTINPUTDEVICE8W iface, L } -static IDirectInputDevice8AVtbl SysMouseAvt = +static const IDirectInputDevice8AVtbl SysMouseAvt = { IDirectInputDevice2AImpl_QueryInterface, IDirectInputDevice2AImpl_AddRef, @@ -1175,7 +1175,7 @@ static IDirectInputDevice8AVtbl SysMouseAvt = # define XCAST(fun) (void*) #endif -static IDirectInputDevice8WVtbl SysMouseWvt = +static const IDirectInputDevice8WVtbl SysMouseWvt = { IDirectInputDevice2WImpl_QueryInterface, XCAST(AddRef)IDirectInputDevice2AImpl_AddRef, diff --git a/reactos/lib/dinput/regsvr.c b/reactos/lib/dinput/regsvr.c index 6bdd46a0e3c..e005f727396 100644 --- a/reactos/lib/dinput/regsvr.c +++ b/reactos/lib/dinput/regsvr.c @@ -530,7 +530,7 @@ static struct regsvr_interface const interface_list[] = { /*********************************************************************** * DllRegisterServer (DINPUT.@) */ -HRESULT WINAPI DINPUT_DllRegisterServer(void) +HRESULT WINAPI DllRegisterServer(void) { HRESULT hr; @@ -545,7 +545,7 @@ HRESULT WINAPI DINPUT_DllRegisterServer(void) /*********************************************************************** * DllUnregisterServer (DINPUT.@) */ -HRESULT WINAPI DINPUT_DllUnregisterServer(void) +HRESULT WINAPI DllUnregisterServer(void) { HRESULT hr; diff --git a/reactos/lib/dinput/version.rc b/reactos/lib/dinput/version.rc index 53df0b62226..65dc50a1512 100644 --- a/reactos/lib/dinput/version.rc +++ b/reactos/lib/dinput/version.rc @@ -1,26 +1,26 @@ -/* - * Copyright 2001 Ove Kaaven - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#define WINE_FILEDESCRIPTION_STR "Wine DirectInput" -#define WINE_FILENAME_STR "dinput.dll" -#define WINE_FILEVERSION 5,1,2600,881 -#define WINE_FILEVERSION_STR "5.1.2600.881" -#define WINE_PRODUCTVERSION 5,1,2600,881 -#define WINE_PRODUCTVERSION_STR "5.1" - -#include "wine/wine_common_ver.rc" +/* + * Copyright 2001 Ove Kaaven + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define WINE_FILEDESCRIPTION_STR "Wine DirectInput" +#define WINE_FILENAME_STR "dinput.dll" +#define WINE_FILEVERSION 5,1,2600,881 +#define WINE_FILEVERSION_STR "5.1.2600.881" +#define WINE_PRODUCTVERSION 5,1,2600,881 +#define WINE_PRODUCTVERSION_STR "5.1" + +#include "wine/wine_common_ver.rc"