diff --git a/reactos/dll/directx/dinput/data_formats.c b/reactos/dll/directx/dinput/data_formats.c index 49ce8fc1736..1f25556665f 100644 --- a/reactos/dll/directx/dinput/data_formats.c +++ b/reactos/dll/directx/dinput/data_formats.c @@ -13,7 +13,7 @@ * * 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 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include @@ -74,7 +74,7 @@ const DIDATAFORMAT c_dfDIJoystick = { sizeof(DIDATAFORMAT), sizeof(DIOBJECTDATAFORMAT), DIDF_ABSAXIS, - sizeof(DIJOYSTATE2), + sizeof(DIJOYSTATE), numObjects(dfDIJoystick), (LPDIOBJECTDATAFORMAT)dfDIJoystick }; diff --git a/reactos/dll/directx/dinput/device.c b/reactos/dll/directx/dinput/device.c index a1e40316adc..941206ccf3b 100644 --- a/reactos/dll/directx/dinput/device.c +++ b/reactos/dll/directx/dinput/device.c @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ /* This file contains all the Device specific functions that can be used as stubs @@ -32,16 +32,19 @@ #include "wine/unicode.h" #include "windef.h" #include "winbase.h" +#include "winreg.h" +#include "winuser.h" #include "winerror.h" #include "dinput.h" #include "device_private.h" +#include "dinput_private.h" WINE_DEFAULT_DEBUG_CHANNEL(dinput); /****************************************************************************** * Various debugging tools */ -void _dump_cooperativelevel_DI(DWORD dwFlags) { +static void _dump_cooperativelevel_DI(DWORD dwFlags) { if (TRACE_ON(dinput)) { unsigned int i; static const struct { @@ -52,17 +55,19 @@ void _dump_cooperativelevel_DI(DWORD dwFlags) { FE(DISCL_BACKGROUND), FE(DISCL_EXCLUSIVE), FE(DISCL_FOREGROUND), - FE(DISCL_NONEXCLUSIVE) + FE(DISCL_NONEXCLUSIVE), + FE(DISCL_NOWINKEY) #undef FE }; + TRACE(" cooperative level : "); for (i = 0; i < (sizeof(flags) / sizeof(flags[0])); i++) if (flags[i].mask & dwFlags) - DPRINTF("%s ",flags[i].name); - DPRINTF("\n"); + TRACE("%s ",flags[i].name); + TRACE("\n"); } } -void _dump_EnumObjects_flags(DWORD dwFlags) { +static void _dump_EnumObjects_flags(DWORD dwFlags) { if (TRACE_ON(dinput)) { unsigned int i; DWORD type, instance; @@ -77,7 +82,7 @@ void _dump_EnumObjects_flags(DWORD dwFlags) { FE(DIDFT_TGLBUTTON), FE(DIDFT_POV), FE(DIDFT_COLLECTION), - FE(DIDFT_NODATA), + FE(DIDFT_NODATA), FE(DIDFT_FFACTUATOR), FE(DIDFT_FFEFFECTTRIGGER), FE(DIDFT_OUTPUT), @@ -88,51 +93,47 @@ void _dump_EnumObjects_flags(DWORD dwFlags) { }; type = (dwFlags & 0xFF0000FF); instance = ((dwFlags >> 8) & 0xFFFF); - DPRINTF("Type:"); + TRACE("Type:"); if (type == DIDFT_ALL) { - DPRINTF(" DIDFT_ALL"); + TRACE(" DIDFT_ALL"); } else { for (i = 0; i < (sizeof(flags) / sizeof(flags[0])); i++) { if (flags[i].mask & type) { type &= ~flags[i].mask; - DPRINTF(" %s",flags[i].name); + TRACE(" %s",flags[i].name); } } if (type) { - DPRINTF(" (unhandled: %08lx)", type); + TRACE(" (unhandled: %08x)", type); } } - DPRINTF(" / Instance: "); + TRACE(" / Instance: "); if (instance == ((DIDFT_ANYINSTANCE >> 8) & 0xFFFF)) { - DPRINTF("DIDFT_ANYINSTANCE"); + TRACE("DIDFT_ANYINSTANCE"); } else { - DPRINTF("%3ld", instance); + TRACE("%3d", instance); } } } void _dump_DIPROPHEADER(LPCDIPROPHEADER diph) { if (TRACE_ON(dinput)) { - DPRINTF(" - dwObj = 0x%08lx\n", diph->dwObj); - DPRINTF(" - dwHow = %s\n", - ((diph->dwHow == DIPH_DEVICE) ? "DIPH_DEVICE" : - ((diph->dwHow == DIPH_BYOFFSET) ? "DIPH_BYOFFSET" : - ((diph->dwHow == DIPH_BYID)) ? "DIPH_BYID" : "unknown"))); + TRACE(" - dwObj = 0x%08x\n", diph->dwObj); + TRACE(" - dwHow = %s\n", + ((diph->dwHow == DIPH_DEVICE) ? "DIPH_DEVICE" : + ((diph->dwHow == DIPH_BYOFFSET) ? "DIPH_BYOFFSET" : + ((diph->dwHow == DIPH_BYID)) ? "DIPH_BYID" : "unknown"))); } } -void _dump_OBJECTINSTANCEA(DIDEVICEOBJECTINSTANCEA *ddoi) { - if (TRACE_ON(dinput)) { - DPRINTF(" - enumerating : %s ('%s') - %2ld - 0x%08lx - %s\n", - debugstr_guid(&ddoi->guidType), _dump_dinput_GUID(&ddoi->guidType), ddoi->dwOfs, ddoi->dwType, ddoi->tszName); - } +void _dump_OBJECTINSTANCEA(const DIDEVICEOBJECTINSTANCEA *ddoi) { + TRACE(" - enumerating : %s ('%s') - %2d - 0x%08x - %s\n", + debugstr_guid(&ddoi->guidType), _dump_dinput_GUID(&ddoi->guidType), ddoi->dwOfs, ddoi->dwType, ddoi->tszName); } -void _dump_OBJECTINSTANCEW(DIDEVICEOBJECTINSTANCEW *ddoi) { - if (TRACE_ON(dinput)) { - DPRINTF(" - enumerating : %s ('%s'), - %2ld - 0x%08lx - %s\n", - debugstr_guid(&ddoi->guidType), _dump_dinput_GUID(&ddoi->guidType), ddoi->dwOfs, ddoi->dwType, debugstr_w(ddoi->tszName)); - } +void _dump_OBJECTINSTANCEW(const DIDEVICEOBJECTINSTANCEW *ddoi) { + TRACE(" - enumerating : %s ('%s'), - %2d - 0x%08x - %s\n", + debugstr_guid(&ddoi->guidType), _dump_dinput_GUID(&ddoi->guidType), ddoi->dwOfs, ddoi->dwType, debugstr_w(ddoi->tszName)); } /* This function is a helper to convert a GUID into any possible DInput GUID out there */ @@ -178,70 +179,122 @@ const char *_dump_dinput_GUID(const GUID *guid) { return guids[i].name; } } - return "Unknown GUID"; + return debugstr_guid(guid); } void _dump_DIDATAFORMAT(const DIDATAFORMAT *df) { unsigned int i; TRACE("Dumping DIDATAFORMAT structure:\n"); - TRACE(" - dwSize: %ld\n", df->dwSize); + TRACE(" - dwSize: %d\n", df->dwSize); if (df->dwSize != sizeof(DIDATAFORMAT)) { - WARN("Non-standard DIDATAFORMAT structure size (%ld instead of %d).\n", df->dwSize, sizeof(DIDATAFORMAT)); + WARN("Non-standard DIDATAFORMAT structure size %d\n", df->dwSize); } - TRACE(" - dwObjsize: %ld\n", df->dwObjSize); + TRACE(" - dwObjsize: %d\n", df->dwObjSize); if (df->dwObjSize != sizeof(DIOBJECTDATAFORMAT)) { - WARN("Non-standard DIOBJECTDATAFORMAT structure size (%ld instead of %d).\n", df->dwObjSize, sizeof(DIOBJECTDATAFORMAT)); + WARN("Non-standard DIOBJECTDATAFORMAT structure size %d\n", df->dwObjSize); } - TRACE(" - dwFlags: 0x%08lx (", df->dwFlags); + TRACE(" - dwFlags: 0x%08x (", df->dwFlags); switch (df->dwFlags) { case DIDF_ABSAXIS: TRACE("DIDF_ABSAXIS"); break; case DIDF_RELAXIS: TRACE("DIDF_RELAXIS"); break; default: TRACE("unknown"); break; } TRACE(")\n"); - TRACE(" - dwDataSize: %ld\n", df->dwDataSize); - TRACE(" - dwNumObjs: %ld\n", df->dwNumObjs); - + TRACE(" - dwDataSize: %d\n", df->dwDataSize); + TRACE(" - dwNumObjs: %d\n", df->dwNumObjs); + for (i = 0; i < df->dwNumObjs; i++) { TRACE(" - Object %d:\n", i); TRACE(" * GUID: %s ('%s')\n", debugstr_guid(df->rgodf[i].pguid), _dump_dinput_GUID(df->rgodf[i].pguid)); - TRACE(" * dwOfs: %ld\n", df->rgodf[i].dwOfs); - TRACE(" * dwType: 0x%08lx\n", df->rgodf[i].dwType); + TRACE(" * dwOfs: %d\n", df->rgodf[i].dwOfs); + TRACE(" * dwType: 0x%08x\n", df->rgodf[i].dwType); TRACE(" "); _dump_EnumObjects_flags(df->rgodf[i].dwType); TRACE("\n"); - TRACE(" * dwFlags: 0x%08lx\n", df->rgodf[i].dwFlags); + TRACE(" * dwFlags: 0x%08x\n", df->rgodf[i].dwFlags); } } -/* Conversion between internal data buffer and external data buffer */ -void fill_DataFormat(void *out, const void *in, DataFormat *df) { - int i; - char *in_c = (char *) in; - char *out_c = (char *) out; +/****************************************************************************** + * Get the default and the app-specific config keys. + */ +BOOL get_app_key(HKEY *defkey, HKEY *appkey) +{ + char buffer[MAX_PATH+16]; + DWORD len; + *appkey = 0; + + /* @@ Wine registry key: HKCU\Software\Wine\DirectInput */ + if (RegOpenKeyA(HKEY_CURRENT_USER, "Software\\Wine\\DirectInput", defkey)) + *defkey = 0; + + len = GetModuleFileNameA(0, buffer, MAX_PATH); + if (len && len < MAX_PATH) + { + HKEY 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); + } + } + + return *defkey || *appkey; +} + +/****************************************************************************** + * Get a config key from either the app-specific or the default config + */ +DWORD get_config_key( HKEY defkey, HKEY appkey, const char *name, + char *buffer, DWORD size ) +{ + if (appkey && !RegQueryValueExA( appkey, name, 0, NULL, (LPBYTE)buffer, &size )) + return 0; + + if (defkey && !RegQueryValueExA( defkey, name, 0, NULL, (LPBYTE)buffer, &size )) + return 0; + + return ERROR_FILE_NOT_FOUND; +} + +/* Conversion between internal data buffer and external data buffer */ +void fill_DataFormat(void *out, DWORD size, const void *in, const DataFormat *df) +{ + int i; + const char *in_c = in; + char *out_c = out; + + memset(out, 0, size); if (df->dt == NULL) { /* This means that the app uses Wine's internal data format */ - memcpy(out, in, df->internal_format_size); + memcpy(out, in, min(size, df->internal_format_size)); } else { for (i = 0; i < df->size; i++) { if (df->dt[i].offset_in >= 0) { switch (df->dt[i].size) { case 1: TRACE("Copying (c) to %d from %d (value %d)\n", - df->dt[i].offset_out, df->dt[i].offset_in, *((char *) (in_c + df->dt[i].offset_in))); - *((char *) (out_c + df->dt[i].offset_out)) = *((char *) (in_c + df->dt[i].offset_in)); + df->dt[i].offset_out, df->dt[i].offset_in, *(in_c + df->dt[i].offset_in)); + *(out_c + df->dt[i].offset_out) = *(in_c + df->dt[i].offset_in); break; case 2: TRACE("Copying (s) to %d from %d (value %d)\n", - df->dt[i].offset_out, df->dt[i].offset_in, *((short *) (in_c + df->dt[i].offset_in))); - *((short *) (out_c + df->dt[i].offset_out)) = *((short *) (in_c + df->dt[i].offset_in)); + df->dt[i].offset_out, df->dt[i].offset_in, *((const short *)(in_c + df->dt[i].offset_in))); + *((short *)(out_c + df->dt[i].offset_out)) = *((const short *)(in_c + df->dt[i].offset_in)); break; case 4: TRACE("Copying (i) to %d from %d (value %d)\n", - df->dt[i].offset_out, df->dt[i].offset_in, *((int *) (in_c + df->dt[i].offset_in))); - *((int *) (out_c + df->dt[i].offset_out)) = *((int *) (in_c + df->dt[i].offset_in)); + df->dt[i].offset_out, df->dt[i].offset_in, *((const int *)(in_c + df->dt[i].offset_in))); + *((int *)(out_c + df->dt[i].offset_out)) = *((const int *)(in_c + df->dt[i].offset_in)); break; default: @@ -253,23 +306,23 @@ void fill_DataFormat(void *out, const void *in, DataFormat *df) { case 1: TRACE("Copying (c) to %d default value %d\n", df->dt[i].offset_out, df->dt[i].value); - *((char *) (out_c + df->dt[i].offset_out)) = (char) df->dt[i].value; + *(out_c + df->dt[i].offset_out) = (char) df->dt[i].value; break; - + case 2: TRACE("Copying (s) to %d default value %d\n", df->dt[i].offset_out, df->dt[i].value); *((short *) (out_c + df->dt[i].offset_out)) = (short) df->dt[i].value; break; - + case 4: TRACE("Copying (i) to %d default value %d\n", df->dt[i].offset_out, df->dt[i].value); - *((int *) (out_c + df->dt[i].offset_out)) = (int) df->dt[i].value; + *((int *) (out_c + df->dt[i].offset_out)) = df->dt[i].value; break; - + default: - memset((out_c + df->dt[i].offset_out), df->dt[i].size, 0); + memset((out_c + df->dt[i].offset_out), 0, df->dt[i].size); break; } } @@ -279,13 +332,24 @@ void fill_DataFormat(void *out, const void *in, DataFormat *df) { void release_DataFormat(DataFormat * format) { - TRACE("Deleting DataTransform :\n"); + TRACE("Deleting DataFormat: %p\n", format); HeapFree(GetProcessHeap(), 0, format->dt); + format->dt = NULL; + HeapFree(GetProcessHeap(), 0, format->offsets); + format->offsets = NULL; + HeapFree(GetProcessHeap(), 0, format->user_df); + format->user_df = NULL; } -DataFormat *create_DataFormat(const DIDATAFORMAT *wine_format, LPCDIDATAFORMAT asked_format, int *offset) { - DataFormat *ret; +static inline LPDIOBJECTDATAFORMAT dataformat_to_odf(LPCDIDATAFORMAT df, int idx) +{ + if (idx < 0 || idx >= df->dwNumObjs) return NULL; + return (LPDIOBJECTDATAFORMAT)((LPBYTE)df->rgodf + idx * df->dwObjSize); +} + +static HRESULT create_DataFormat(LPCDIDATAFORMAT asked_format, DataFormat *format) +{ DataTransform *dt; unsigned int i, j; int same = 1; @@ -293,84 +357,81 @@ DataFormat *create_DataFormat(const DIDATAFORMAT *wine_format, LPCDIDATAFORMAT a int index = 0; DWORD next = 0; - ret = HeapAlloc(GetProcessHeap(), 0, sizeof(DataFormat)); - - done = HeapAlloc(GetProcessHeap(), 0, sizeof(int) * asked_format->dwNumObjs); - memset(done, 0, sizeof(int) * asked_format->dwNumObjs); - + if (!format->wine_df) return DIERR_INVALIDPARAM; + done = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, asked_format->dwNumObjs * sizeof(int)); dt = HeapAlloc(GetProcessHeap(), 0, asked_format->dwNumObjs * sizeof(DataTransform)); + if (!dt || !done) goto failed; + + if (!(format->offsets = HeapAlloc(GetProcessHeap(), 0, format->wine_df->dwNumObjs * sizeof(int)))) + goto failed; + + if (!(format->user_df = HeapAlloc(GetProcessHeap(), 0, asked_format->dwSize))) + goto failed; + memcpy(format->user_df, asked_format, asked_format->dwSize); TRACE("Creating DataTransform :\n"); - - for (i = 0; i < wine_format->dwNumObjs; i++) { - offset[i] = -1; + + for (i = 0; i < format->wine_df->dwNumObjs; i++) + { + format->offsets[i] = -1; for (j = 0; j < asked_format->dwNumObjs; j++) { if (done[j] == 1) continue; - + if (/* Check if the application either requests any GUID and if not, it if matches * the GUID of the Wine object. */ ((asked_format->rgodf[j].pguid == NULL) || - (wine_format->rgodf[i].pguid == NULL) || - (IsEqualGUID(wine_format->rgodf[i].pguid, asked_format->rgodf[j].pguid))) + (format->wine_df->rgodf[i].pguid == NULL) || + (IsEqualGUID(format->wine_df->rgodf[i].pguid, asked_format->rgodf[j].pguid))) && (/* Then check if it accepts any instance id, and if not, if it matches Wine's * instance id. */ - (DIDFT_GETINSTANCE(asked_format->rgodf[j].dwType) == 0xFFFF) || + ((asked_format->rgodf[j].dwType & DIDFT_INSTANCEMASK) == DIDFT_ANYINSTANCE) || (DIDFT_GETINSTANCE(asked_format->rgodf[j].dwType) == 0x00FF) || /* This is mentionned in no DX docs, but it works fine - tested on WinXP */ - (DIDFT_GETINSTANCE(asked_format->rgodf[j].dwType) == DIDFT_GETINSTANCE(wine_format->rgodf[i].dwType))) + (DIDFT_GETINSTANCE(asked_format->rgodf[j].dwType) == DIDFT_GETINSTANCE(format->wine_df->rgodf[i].dwType))) && ( /* Then if the asked type matches the one Wine provides */ - wine_format->rgodf[i].dwType & asked_format->rgodf[j].dwType)) { - + DIDFT_GETTYPE(asked_format->rgodf[j].dwType) & format->wine_df->rgodf[i].dwType)) + { done[j] = 1; - + TRACE("Matching :\n"); TRACE(" - Asked (%d) :\n", j); TRACE(" * GUID: %s ('%s')\n", debugstr_guid(asked_format->rgodf[j].pguid), _dump_dinput_GUID(asked_format->rgodf[j].pguid)); - TRACE(" * Offset: %3ld\n", asked_format->rgodf[j].dwOfs); - TRACE(" * dwType: %08lx\n", asked_format->rgodf[j].dwType); + TRACE(" * Offset: %3d\n", asked_format->rgodf[j].dwOfs); + TRACE(" * dwType: %08x\n", asked_format->rgodf[j].dwType); TRACE(" "); _dump_EnumObjects_flags(asked_format->rgodf[j].dwType); TRACE("\n"); - + TRACE(" - Wine (%d) :\n", i); TRACE(" * GUID: %s ('%s')\n", - debugstr_guid(wine_format->rgodf[i].pguid), - _dump_dinput_GUID(wine_format->rgodf[i].pguid)); - TRACE(" * Offset: %3ld\n", wine_format->rgodf[i].dwOfs); - TRACE(" * dwType: %08lx\n", wine_format->rgodf[i].dwType); - TRACE(" "); _dump_EnumObjects_flags(wine_format->rgodf[i].dwType); TRACE("\n"); - - if (wine_format->rgodf[i].dwType & DIDFT_BUTTON) + debugstr_guid(format->wine_df->rgodf[i].pguid), + _dump_dinput_GUID(format->wine_df->rgodf[i].pguid)); + TRACE(" * Offset: %3d\n", format->wine_df->rgodf[i].dwOfs); + TRACE(" * dwType: %08x\n", format->wine_df->rgodf[i].dwType); + TRACE(" "); _dump_EnumObjects_flags(format->wine_df->rgodf[i].dwType); TRACE("\n"); + + if (format->wine_df->rgodf[i].dwType & DIDFT_BUTTON) dt[index].size = sizeof(BYTE); else dt[index].size = sizeof(DWORD); - dt[index].offset_in = wine_format->rgodf[i].dwOfs; - if (asked_format->rgodf[j].dwOfs < next) { - WARN("bad format: dwOfs=%ld, changing to %ld\n", asked_format->rgodf[j].dwOfs, next); - dt[index].offset_out = next; - offset[i] = next; - } else { - dt[index].offset_out = asked_format->rgodf[j].dwOfs; - offset[i] = asked_format->rgodf[j].dwOfs; - } + dt[index].offset_in = format->wine_df->rgodf[i].dwOfs; + dt[index].offset_out = asked_format->rgodf[j].dwOfs; + format->offsets[i] = asked_format->rgodf[j].dwOfs; dt[index].value = 0; next = next + dt[index].size; - - if (wine_format->rgodf[i].dwOfs != dt[index].offset_out) + + if (format->wine_df->rgodf[i].dwOfs != dt[index].offset_out) same = 0; - + index++; break; } } - - if (j == asked_format->dwNumObjs) - same = 0; } TRACE("Setting to default value :\n"); @@ -380,68 +441,170 @@ DataFormat *create_DataFormat(const DIDATAFORMAT *wine_format, LPCDIDATAFORMAT a TRACE(" * GUID: %s ('%s')\n", debugstr_guid(asked_format->rgodf[j].pguid), _dump_dinput_GUID(asked_format->rgodf[j].pguid)); - TRACE(" * Offset: %3ld\n", asked_format->rgodf[j].dwOfs); - TRACE(" * dwType: %08lx\n", asked_format->rgodf[j].dwType); + TRACE(" * Offset: %3d\n", asked_format->rgodf[j].dwOfs); + TRACE(" * dwType: %08x\n", asked_format->rgodf[j].dwType); TRACE(" "); _dump_EnumObjects_flags(asked_format->rgodf[j].dwType); TRACE("\n"); - + if (asked_format->rgodf[j].dwType & DIDFT_BUTTON) dt[index].size = sizeof(BYTE); else dt[index].size = sizeof(DWORD); dt[index].offset_in = -1; dt[index].offset_out = asked_format->rgodf[j].dwOfs; - dt[index].value = 0; + if (asked_format->rgodf[j].dwType & DIDFT_POV) + dt[index].value = -1; + else + dt[index].value = 0; index++; same = 0; } } - - ret->internal_format_size = wine_format->dwDataSize; - ret->size = index; + + format->internal_format_size = format->wine_df->dwDataSize; + format->size = index; if (same) { - ret->dt = NULL; HeapFree(GetProcessHeap(), 0, dt); - } else { - ret->dt = dt; + dt = NULL; } + format->dt = dt; HeapFree(GetProcessHeap(), 0, done); - return ret; + return DI_OK; + +failed: + HeapFree(GetProcessHeap(), 0, done); + HeapFree(GetProcessHeap(), 0, dt); + format->dt = NULL; + HeapFree(GetProcessHeap(), 0, format->offsets); + format->offsets = NULL; + HeapFree(GetProcessHeap(), 0, format->user_df); + format->user_df = NULL; + + return DIERR_OUTOFMEMORY; } -BOOL DIEnumDevicesCallbackAtoW(LPCDIDEVICEOBJECTINSTANCEA lpddi, LPVOID lpvRef) { - DIDEVICEOBJECTINSTANCEW ddtmp; - device_enumobjects_AtoWcb_data* data; +/* find an object by it's offset in a data format */ +static int offset_to_object(const DataFormat *df, int offset) +{ + int i; - data = (device_enumobjects_AtoWcb_data*) lpvRef; + if (!df->offsets) return -1; - memset(&ddtmp, 0, sizeof(ddtmp)); + for (i = 0; i < df->wine_df->dwNumObjs; i++) + if (df->offsets[i] == offset) return i; - ddtmp.dwSize = sizeof(DIDEVICEINSTANCEW); - ddtmp.guidType = lpddi->guidType; - ddtmp.dwOfs = lpddi->dwOfs; - ddtmp.dwType = lpddi->dwType; - ddtmp.dwFlags = lpddi->dwFlags; - MultiByteToWideChar(CP_ACP, 0, lpddi->tszName, -1, ddtmp.tszName, MAX_PATH); + return -1; +} - if (lpddi->dwSize == sizeof(DIDEVICEINSTANCEA)) { - /** - * if dwSize < sizeof(DIDEVICEINSTANCEA of DInput version >= 5) - * force feedback and other newer datas aren't available - */ - ddtmp.dwFFMaxForce = lpddi->dwFFMaxForce; - ddtmp.dwFFForceResolution = lpddi->dwFFForceResolution; - ddtmp.wCollectionNumber = lpddi->wCollectionNumber; - ddtmp.wDesignatorIndex = lpddi->wDesignatorIndex; - ddtmp.wUsagePage = lpddi->wUsagePage; - ddtmp.wUsage = lpddi->wUsage; - ddtmp.dwDimension = lpddi->dwDimension; - ddtmp.wExponent = lpddi->wExponent; - ddtmp.wReserved = lpddi->wReserved; +int id_to_object(LPCDIDATAFORMAT df, int id) +{ + int i; + + id &= 0x00ffffff; + for (i = 0; i < df->dwNumObjs; i++) + if ((dataformat_to_odf(df, i)->dwType & 0x00ffffff) == id) + return i; + + return -1; +} + +int id_to_offset(const DataFormat *df, int id) +{ + int obj = id_to_object(df->wine_df, id); + + return obj >= 0 && df->offsets ? df->offsets[obj] : -1; +} + +int find_property(const DataFormat *df, LPCDIPROPHEADER ph) +{ + switch (ph->dwHow) + { + case DIPH_BYID: return id_to_object(df->wine_df, ph->dwObj); + case DIPH_BYOFFSET: return offset_to_object(df, ph->dwObj); } - return data->lpCallBack(&ddtmp, data->lpvRef); + FIXME("Unhandled ph->dwHow=='%04X'\n", (unsigned int)ph->dwHow); + + return -1; +} + +/****************************************************************************** + * queue_event - add new event to the ring queue + */ + +void queue_event(LPDIRECTINPUTDEVICE8A iface, int ofs, DWORD data, DWORD time, DWORD seq) +{ + IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface; + int next_pos; + + /* Event is being set regardless of the queue state */ + if (This->hEvent) SetEvent(This->hEvent); + + if (!This->queue_len || This->overflow || ofs < 0) return; + + next_pos = (This->queue_head + 1) % This->queue_len; + if (next_pos == This->queue_tail) + { + TRACE(" queue overflowed\n"); + This->overflow = TRUE; + return; + } + + TRACE(" queueing %d at offset %d (queue head %d / size %d)\n", + data, ofs, This->queue_head, This->queue_len); + + This->data_queue[This->queue_head].dwOfs = ofs; + This->data_queue[This->queue_head].dwData = data; + This->data_queue[This->queue_head].dwTimeStamp = time; + This->data_queue[This->queue_head].dwSequence = seq; + This->queue_head = next_pos; + /* Send event if asked */ +} + +/****************************************************************************** + * Acquire + */ + +HRESULT WINAPI IDirectInputDevice2AImpl_Acquire(LPDIRECTINPUTDEVICE8A iface) +{ + IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface; + HRESULT res; + + if (!This->data_format.user_df) return DIERR_INVALIDPARAM; + if (This->dwCoopLevel & DISCL_FOREGROUND && This->win != GetForegroundWindow()) + return DIERR_OTHERAPPHASPRIO; + + EnterCriticalSection(&This->crit); + res = This->acquired ? S_FALSE : DI_OK; + This->acquired = 1; + if (res == DI_OK) + { + This->queue_head = This->queue_tail = This->overflow = 0; + check_dinput_hooks(iface); + } + LeaveCriticalSection(&This->crit); + + return res; +} + +/****************************************************************************** + * Unacquire + */ + +HRESULT WINAPI IDirectInputDevice2AImpl_Unacquire(LPDIRECTINPUTDEVICE8A iface) +{ + IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface; + HRESULT res; + + EnterCriticalSection(&This->crit); + res = !This->acquired ? DI_NOEFFECT : DI_OK; + This->acquired = 0; + if (res == DI_OK) + check_dinput_hooks(iface); + LeaveCriticalSection(&This->crit); + + return res; } /****************************************************************************** @@ -449,34 +612,80 @@ BOOL DIEnumDevicesCallbackAtoW(LPCDIDEVICEOBJECTINSTANCEA lpddi, LPVOID lpvRef) */ HRESULT WINAPI IDirectInputDevice2AImpl_SetDataFormat( - LPDIRECTINPUTDEVICE8A iface,LPCDIDATAFORMAT df -) { + LPDIRECTINPUTDEVICE8A iface, LPCDIDATAFORMAT df) +{ IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface; + HRESULT res = DI_OK; - TRACE("(this=%p,%p)\n",This,df); - + if (!df) return E_POINTER; + TRACE("(%p) %p\n", This, df); _dump_DIDATAFORMAT(df); - return DI_OK; + if (df->dwSize != sizeof(DIDATAFORMAT)) return DIERR_INVALIDPARAM; + if (This->acquired) return DIERR_ACQUIRED; + + EnterCriticalSection(&This->crit); + + release_DataFormat(&This->data_format); + res = create_DataFormat(df, &This->data_format); + + LeaveCriticalSection(&This->crit); + return res; } +/****************************************************************************** + * SetCooperativeLevel + * + * Set cooperative level and the source window for the events. + */ HRESULT WINAPI IDirectInputDevice2AImpl_SetCooperativeLevel( - LPDIRECTINPUTDEVICE8A iface,HWND hwnd,DWORD dwflags -) { + LPDIRECTINPUTDEVICE8A iface, HWND hwnd, DWORD dwflags) +{ IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface; - TRACE("(this=%p,%p,0x%08lx)\n",This,hwnd,dwflags); - if (TRACE_ON(dinput)) { - TRACE(" cooperative level : "); - _dump_cooperativelevel_DI(dwflags); - } + + TRACE("(%p) %p,0x%08x\n", This, hwnd, dwflags); + _dump_cooperativelevel_DI(dwflags); + + if ((dwflags & (DISCL_EXCLUSIVE | DISCL_NONEXCLUSIVE)) == 0 || + (dwflags & (DISCL_EXCLUSIVE | DISCL_NONEXCLUSIVE)) == (DISCL_EXCLUSIVE | DISCL_NONEXCLUSIVE) || + (dwflags & (DISCL_FOREGROUND | DISCL_BACKGROUND)) == 0 || + (dwflags & (DISCL_FOREGROUND | DISCL_BACKGROUND)) == (DISCL_FOREGROUND | DISCL_BACKGROUND)) + return DIERR_INVALIDPARAM; + + if (dwflags == (DISCL_NONEXCLUSIVE | DISCL_BACKGROUND)) + hwnd = GetDesktopWindow(); + + if (!hwnd) return E_HANDLE; + + /* For security reasons native does not allow exclusive background level + for mouse and keyboard only */ + if (dwflags & DISCL_EXCLUSIVE && dwflags & DISCL_BACKGROUND && + (IsEqualGUID(&This->guid, &GUID_SysMouse) || + IsEqualGUID(&This->guid, &GUID_SysKeyboard))) + return DIERR_UNSUPPORTED; + + /* Store the window which asks for the mouse */ + EnterCriticalSection(&This->crit); + This->win = hwnd; + This->dwCoopLevel = dwflags; + LeaveCriticalSection(&This->crit); + return DI_OK; } +/****************************************************************************** + * SetEventNotification : specifies event to be sent on state change + */ HRESULT WINAPI IDirectInputDevice2AImpl_SetEventNotification( - LPDIRECTINPUTDEVICE8A iface,HANDLE hnd -) { + LPDIRECTINPUTDEVICE8A iface, HANDLE event) +{ IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface; - FIXME("(this=%p,%p): stub\n",This,hnd); + + TRACE("(%p) %p\n", This, event); + + EnterCriticalSection(&This->crit); + This->hEvent = event; + LeaveCriticalSection(&This->crit); return DI_OK; } @@ -484,10 +693,32 @@ ULONG WINAPI IDirectInputDevice2AImpl_Release(LPDIRECTINPUTDEVICE8A iface) { IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface; ULONG ref; + ref = InterlockedDecrement(&(This->ref)); - if (ref == 0) - HeapFree(GetProcessHeap(),0,This); - return ref; + if (ref) return ref; + + IDirectInputDevice_Unacquire(iface); + /* Reset the FF state, free all effects, etc */ + IDirectInputDevice8_SendForceFeedbackCommand(iface, DISFFC_RESET); + + HeapFree(GetProcessHeap(), 0, This->data_queue); + + /* Free data format */ + HeapFree(GetProcessHeap(), 0, This->data_format.wine_df->rgodf); + HeapFree(GetProcessHeap(), 0, This->data_format.wine_df); + release_DataFormat(&This->data_format); + + EnterCriticalSection( &This->dinput->crit ); + list_remove( &This->entry ); + LeaveCriticalSection( &This->dinput->crit ); + + IDirectInput_Release((LPDIRECTINPUTDEVICE8A)This->dinput); + This->crit.DebugInfo->Spare[0] = 0; + DeleteCriticalSection(&This->crit); + + HeapFree(GetProcessHeap(), 0, This); + + return DI_OK; } HRESULT WINAPI IDirectInputDevice2AImpl_QueryInterface( @@ -495,7 +726,7 @@ HRESULT WINAPI IDirectInputDevice2AImpl_QueryInterface( ) { IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface; - + TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(riid),ppobj); if (IsEqualGUID(&IID_IUnknown,riid)) { IDirectInputDevice2_AddRef(iface); @@ -531,7 +762,7 @@ HRESULT WINAPI IDirectInputDevice2WImpl_QueryInterface( ) { IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface; - + TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(riid),ppobj); if (IsEqualGUID(&IID_IUnknown,riid)) { IDirectInputDevice2_AddRef(iface); @@ -569,48 +800,160 @@ ULONG WINAPI IDirectInputDevice2AImpl_AddRef( return InterlockedIncrement(&(This->ref)); } -HRESULT WINAPI IDirectInputDevice2AImpl_EnumObjects( - LPDIRECTINPUTDEVICE8A iface, - LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback, - LPVOID lpvRef, - DWORD dwFlags) +HRESULT WINAPI IDirectInputDevice2AImpl_EnumObjects(LPDIRECTINPUTDEVICE8A iface, + LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback, LPVOID lpvRef, DWORD dwFlags) { - FIXME("(this=%p,%p,%p,%08lx): stub!\n", iface, lpCallback, lpvRef, dwFlags); - if (TRACE_ON(dinput)) { - DPRINTF(" - flags = "); - _dump_EnumObjects_flags(dwFlags); - DPRINTF("\n"); + IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface; + DIDEVICEOBJECTINSTANCEA ddoi; + int i; + + TRACE("(%p) %p,%p flags:%08x)\n", iface, lpCallback, lpvRef, dwFlags); + TRACE(" - flags = "); + _dump_EnumObjects_flags(dwFlags); + TRACE("\n"); + + /* Only the fields till dwFFMaxForce are relevant */ + memset(&ddoi, 0, sizeof(ddoi)); + ddoi.dwSize = FIELD_OFFSET(DIDEVICEOBJECTINSTANCEA, dwFFMaxForce); + + for (i = 0; i < This->data_format.wine_df->dwNumObjs; i++) + { + LPDIOBJECTDATAFORMAT odf = dataformat_to_odf(This->data_format.wine_df, i); + + if (dwFlags != DIDFT_ALL && !(dwFlags & DIEFT_GETTYPE(odf->dwType))) continue; + if (IDirectInputDevice_GetObjectInfo(iface, &ddoi, odf->dwType, DIPH_BYID) != DI_OK) + continue; + + if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) break; } return DI_OK; } -HRESULT WINAPI IDirectInputDevice2WImpl_EnumObjects( - LPDIRECTINPUTDEVICE8W iface, - LPDIENUMDEVICEOBJECTSCALLBACKW lpCallback, - LPVOID lpvRef, - DWORD dwFlags) +HRESULT WINAPI IDirectInputDevice2WImpl_EnumObjects(LPDIRECTINPUTDEVICE8W iface, + LPDIENUMDEVICEOBJECTSCALLBACKW lpCallback, LPVOID lpvRef, DWORD dwFlags) { - FIXME("(this=%p,%p,%p,%08lx): stub!\n", iface, lpCallback, lpvRef, dwFlags); - if (TRACE_ON(dinput)) { - DPRINTF(" - flags = "); - _dump_EnumObjects_flags(dwFlags); - DPRINTF("\n"); + IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface; + DIDEVICEOBJECTINSTANCEW ddoi; + int i; + + TRACE("(%p) %p,%p flags:%08x)\n", iface, lpCallback, lpvRef, dwFlags); + TRACE(" - flags = "); + _dump_EnumObjects_flags(dwFlags); + TRACE("\n"); + + /* Only the fields till dwFFMaxForce are relevant */ + memset(&ddoi, 0, sizeof(ddoi)); + ddoi.dwSize = FIELD_OFFSET(DIDEVICEOBJECTINSTANCEW, dwFFMaxForce); + + for (i = 0; i < This->data_format.wine_df->dwNumObjs; i++) + { + LPDIOBJECTDATAFORMAT odf = dataformat_to_odf(This->data_format.wine_df, i); + + if (dwFlags != DIDFT_ALL && !(dwFlags & DIEFT_GETTYPE(odf->dwType))) continue; + if (IDirectInputDevice_GetObjectInfo(iface, &ddoi, odf->dwType, DIPH_BYID) != DI_OK) + continue; + + if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) break; } return DI_OK; } +/****************************************************************************** + * GetProperty + */ + HRESULT WINAPI IDirectInputDevice2AImpl_GetProperty( - LPDIRECTINPUTDEVICE8A iface, - REFGUID rguid, - LPDIPROPHEADER pdiph) + LPDIRECTINPUTDEVICE8A iface, REFGUID rguid, LPDIPROPHEADER pdiph) { - FIXME("(this=%p,%s,%p): stub!\n", - iface, debugstr_guid(rguid), pdiph); + IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface; - if (TRACE_ON(dinput)) - _dump_DIPROPHEADER(pdiph); + TRACE("(%p) %s,%p\n", iface, debugstr_guid(rguid), pdiph); + _dump_DIPROPHEADER(pdiph); + + if (HIWORD(rguid)) return DI_OK; + + switch (LOWORD(rguid)) + { + case (DWORD_PTR) DIPROP_BUFFERSIZE: + { + LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph; + + if (pdiph->dwSize != sizeof(DIPROPDWORD)) return DIERR_INVALIDPARAM; + + pd->dwData = This->queue_len; + TRACE("buffersize = %d\n", pd->dwData); + break; + } + default: + WARN("Unknown property %s\n", debugstr_guid(rguid)); + break; + } + + return DI_OK; +} + +/****************************************************************************** + * SetProperty + */ + +HRESULT WINAPI IDirectInputDevice2AImpl_SetProperty( + LPDIRECTINPUTDEVICE8A iface, REFGUID rguid, LPCDIPROPHEADER pdiph) +{ + IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface; + + TRACE("(%p) %s,%p\n", iface, debugstr_guid(rguid), pdiph); + _dump_DIPROPHEADER(pdiph); + + if (HIWORD(rguid)) return DI_OK; + + switch (LOWORD(rguid)) + { + case (DWORD_PTR) DIPROP_AXISMODE: + { + LPCDIPROPDWORD pd = (LPCDIPROPDWORD)pdiph; + + if (pdiph->dwSize != sizeof(DIPROPDWORD)) return DIERR_INVALIDPARAM; + if (pdiph->dwHow == DIPH_DEVICE && pdiph->dwObj) return DIERR_INVALIDPARAM; + if (This->acquired) return DIERR_ACQUIRED; + if (pdiph->dwHow != DIPH_DEVICE) return DIERR_UNSUPPORTED; + if (!This->data_format.user_df) return DI_OK; + + TRACE("Axis mode: %s\n", pd->dwData == DIPROPAXISMODE_ABS ? "absolute" : + "relative"); + + EnterCriticalSection(&This->crit); + This->data_format.user_df->dwFlags &= ~DIDFT_AXIS; + This->data_format.user_df->dwFlags |= pd->dwData == DIPROPAXISMODE_ABS ? + DIDF_ABSAXIS : DIDF_RELAXIS; + LeaveCriticalSection(&This->crit); + break; + } + case (DWORD_PTR) DIPROP_BUFFERSIZE: + { + LPCDIPROPDWORD pd = (LPCDIPROPDWORD)pdiph; + + if (pdiph->dwSize != sizeof(DIPROPDWORD)) return DIERR_INVALIDPARAM; + if (This->acquired) return DIERR_ACQUIRED; + + TRACE("buffersize = %d\n", pd->dwData); + + EnterCriticalSection(&This->crit); + HeapFree(GetProcessHeap(), 0, This->data_queue); + + This->data_queue = !pd->dwData ? NULL : HeapAlloc(GetProcessHeap(), 0, + pd->dwData * sizeof(DIDEVICEOBJECTDATA)); + This->queue_head = This->queue_tail = This->overflow = 0; + This->queue_len = pd->dwData; + + LeaveCriticalSection(&This->crit); + break; + } + default: + WARN("Unknown property %s\n", debugstr_guid(rguid)); + return DIERR_UNSUPPORTED; + } return DI_OK; } @@ -621,10 +964,29 @@ HRESULT WINAPI IDirectInputDevice2AImpl_GetObjectInfo( DWORD dwObj, DWORD dwHow) { - FIXME("(this=%p,%p,%ld,0x%08lx): stub!\n", - iface, pdidoi, dwObj, dwHow); + DIDEVICEOBJECTINSTANCEW didoiW; + HRESULT res; - return DI_OK; + if (!pdidoi || + (pdidoi->dwSize != sizeof(DIDEVICEOBJECTINSTANCEA) && + pdidoi->dwSize != sizeof(DIDEVICEOBJECTINSTANCE_DX3A))) + return DIERR_INVALIDPARAM; + + didoiW.dwSize = sizeof(didoiW); + res = IDirectInputDevice2WImpl_GetObjectInfo((LPDIRECTINPUTDEVICE8W)iface, &didoiW, dwObj, dwHow); + if (res == DI_OK) + { + DWORD dwSize = pdidoi->dwSize; + + memset(pdidoi, 0, pdidoi->dwSize); + pdidoi->dwSize = dwSize; + pdidoi->guidType = didoiW.guidType; + pdidoi->dwOfs = didoiW.dwOfs; + pdidoi->dwType = didoiW.dwType; + pdidoi->dwFlags = didoiW.dwFlags; + } + + return res; } HRESULT WINAPI IDirectInputDevice2WImpl_GetObjectInfo( @@ -633,30 +995,104 @@ HRESULT WINAPI IDirectInputDevice2WImpl_GetObjectInfo( DWORD dwObj, DWORD dwHow) { - FIXME("(this=%p,%p,%ld,0x%08lx): stub!\n", - iface, pdidoi, dwObj, dwHow); + IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface; + DWORD dwSize; + LPDIOBJECTDATAFORMAT odf; + int idx = -1; + + TRACE("(%p) %d(0x%08x) -> %p\n", This, dwHow, dwObj, pdidoi); + + if (!pdidoi || + (pdidoi->dwSize != sizeof(DIDEVICEOBJECTINSTANCEW) && + pdidoi->dwSize != sizeof(DIDEVICEOBJECTINSTANCE_DX3W))) + return DIERR_INVALIDPARAM; + + switch (dwHow) + { + case DIPH_BYOFFSET: + if (!This->data_format.offsets) break; + for (idx = This->data_format.wine_df->dwNumObjs - 1; idx >= 0; idx--) + if (This->data_format.offsets[idx] == dwObj) break; + break; + case DIPH_BYID: + dwObj &= 0x00ffffff; + for (idx = This->data_format.wine_df->dwNumObjs - 1; idx >= 0; idx--) + if ((dataformat_to_odf(This->data_format.wine_df, idx)->dwType & 0x00ffffff) == dwObj) + break; + break; + + case DIPH_BYUSAGE: + FIXME("dwHow = DIPH_BYUSAGE not implemented\n"); + break; + default: + WARN("invalid parameter: dwHow = %08x\n", dwHow); + return DIERR_INVALIDPARAM; + } + if (idx < 0) return DIERR_OBJECTNOTFOUND; + + odf = dataformat_to_odf(This->data_format.wine_df, idx); + dwSize = pdidoi->dwSize; /* save due to memset below */ + memset(pdidoi, 0, pdidoi->dwSize); + pdidoi->dwSize = dwSize; + if (odf->pguid) pdidoi->guidType = *odf->pguid; + pdidoi->dwOfs = This->data_format.offsets ? This->data_format.offsets[idx] : odf->dwOfs; + pdidoi->dwType = odf->dwType; + pdidoi->dwFlags = odf->dwFlags; return DI_OK; } -HRESULT WINAPI IDirectInputDevice2AImpl_GetDeviceInfo( - LPDIRECTINPUTDEVICE8A iface, - LPDIDEVICEINSTANCEA pdidi) +HRESULT WINAPI IDirectInputDevice2AImpl_GetDeviceData( + LPDIRECTINPUTDEVICE8A iface, DWORD dodsize, LPDIDEVICEOBJECTDATA dod, + LPDWORD entries, DWORD flags) { - FIXME("(this=%p,%p): stub!\n", - iface, pdidi); + IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface; + HRESULT ret = DI_OK; + int len; - return DI_OK; -} + TRACE("(%p) %p -> %p(%d) x%d, 0x%08x\n", + This, dod, entries, entries ? *entries : 0, dodsize, flags); -HRESULT WINAPI IDirectInputDevice2WImpl_GetDeviceInfo( - LPDIRECTINPUTDEVICE8W iface, - LPDIDEVICEINSTANCEW pdidi) -{ - FIXME("(this=%p,%p): stub!\n", - iface, pdidi); + if (!This->acquired) + return DIERR_NOTACQUIRED; + if (!This->queue_len) + return DIERR_NOTBUFFERED; + if (dodsize < sizeof(DIDEVICEOBJECTDATA_DX3)) + return DIERR_INVALIDPARAM; - return DI_OK; + IDirectInputDevice2_Poll(iface); + EnterCriticalSection(&This->crit); + + len = This->queue_head - This->queue_tail; + if (len < 0) len += This->queue_len; + + if ((*entries != INFINITE) && (len > *entries)) len = *entries; + + if (dod) + { + int i; + for (i = 0; i < len; i++) + { + int n = (This->queue_tail + i) % This->queue_len; + memcpy((char *)dod + dodsize * i, This->data_queue + n, dodsize); + } + } + *entries = len; + + if (This->overflow) + ret = DI_BUFFEROVERFLOW; + + if (!(flags & DIGDD_PEEK)) + { + /* Advance reading position */ + This->queue_tail = (This->queue_tail + len) % This->queue_len; + This->overflow = FALSE; + } + + LeaveCriticalSection(&This->crit); + + TRACE("Returning %d events queued\n", *entries); + return ret; } HRESULT WINAPI IDirectInputDevice2AImpl_RunControlPanel( @@ -664,7 +1100,7 @@ HRESULT WINAPI IDirectInputDevice2AImpl_RunControlPanel( HWND hwndOwner, DWORD dwFlags) { - FIXME("(this=%p,%p,0x%08lx): stub!\n", + FIXME("(this=%p,%p,0x%08x): stub!\n", iface, hwndOwner, dwFlags); return DI_OK; @@ -676,7 +1112,7 @@ HRESULT WINAPI IDirectInputDevice2AImpl_Initialize( DWORD dwVersion, REFGUID rguid) { - FIXME("(this=%p,%p,%ld,%s): stub!\n", + FIXME("(this=%p,%p,%d,%s): stub!\n", iface, hinst, dwVersion, debugstr_guid(rguid)); return DI_OK; } @@ -703,9 +1139,9 @@ HRESULT WINAPI IDirectInputDevice2AImpl_EnumEffects( LPVOID lpvRef, DWORD dwFlags) { - FIXME("(this=%p,%p,%p,0x%08lx): stub!\n", + FIXME("(this=%p,%p,%p,0x%08x): stub!\n", iface, lpCallback, lpvRef, dwFlags); - + return DI_OK; } @@ -715,9 +1151,9 @@ HRESULT WINAPI IDirectInputDevice2WImpl_EnumEffects( LPVOID lpvRef, DWORD dwFlags) { - FIXME("(this=%p,%p,%p,0x%08lx): stub!\n", + FIXME("(this=%p,%p,%p,0x%08x): stub!\n", iface, lpCallback, lpvRef, dwFlags); - + return DI_OK; } @@ -754,9 +1190,8 @@ HRESULT WINAPI IDirectInputDevice2AImpl_SendForceFeedbackCommand( LPDIRECTINPUTDEVICE8A iface, DWORD dwFlags) { - FIXME("(this=%p,0x%08lx): stub!\n", - iface, dwFlags); - return DI_OK; + TRACE("(%p) 0x%08x:\n", iface, dwFlags); + return DI_NOEFFECT; } HRESULT WINAPI IDirectInputDevice2AImpl_EnumCreatedEffectObjects( @@ -765,7 +1200,7 @@ HRESULT WINAPI IDirectInputDevice2AImpl_EnumCreatedEffectObjects( LPVOID lpvRef, DWORD dwFlags) { - FIXME("(this=%p,%p,%p,0x%08lx): stub!\n", + FIXME("(this=%p,%p,%p,0x%08x): stub!\n", iface, lpCallback, lpvRef, dwFlags); return DI_OK; } @@ -782,6 +1217,9 @@ HRESULT WINAPI IDirectInputDevice2AImpl_Escape( HRESULT WINAPI IDirectInputDevice2AImpl_Poll( LPDIRECTINPUTDEVICE8A iface) { + IDirectInputDevice2AImpl *This = (IDirectInputDevice2AImpl *)iface; + + if (!This->acquired) return DIERR_NOTACQUIRED; /* Because wine devices do not need to be polled, just return DI_NOEFFECT */ return DI_NOEFFECT; } @@ -793,9 +1231,9 @@ HRESULT WINAPI IDirectInputDevice2AImpl_SendDeviceData( LPDWORD pdwInOut, DWORD dwFlags) { - FIXME("(this=%p,0x%08lx,%p,%p,0x%08lx): stub!\n", + FIXME("(this=%p,0x%08x,%p,%p,0x%08x): stub!\n", iface, cbObjectData, rgdod, pdwInOut, dwFlags); - + return DI_OK; } @@ -805,8 +1243,8 @@ HRESULT WINAPI IDirectInputDevice7AImpl_EnumEffectsInFile(LPDIRECTINPUTDEVICE8A LPVOID pvRef, DWORD dwFlags) { - FIXME("(%p)->(%s,%p,%p,%08lx): stub !\n", iface, lpszFileName, pec, pvRef, dwFlags); - + FIXME("(%p)->(%s,%p,%p,%08x): stub !\n", iface, lpszFileName, pec, pvRef, dwFlags); + return DI_OK; } @@ -816,8 +1254,8 @@ HRESULT WINAPI IDirectInputDevice7WImpl_EnumEffectsInFile(LPDIRECTINPUTDEVICE8W LPVOID pvRef, DWORD dwFlags) { - FIXME("(%p)->(%s,%p,%p,%08lx): stub !\n", iface, debugstr_w(lpszFileName), pec, pvRef, dwFlags); - + FIXME("(%p)->(%s,%p,%p,%08x): stub !\n", iface, debugstr_w(lpszFileName), pec, pvRef, dwFlags); + return DI_OK; } @@ -827,8 +1265,8 @@ HRESULT WINAPI IDirectInputDevice7AImpl_WriteEffectToFile(LPDIRECTINPUTDEVICE8A LPDIFILEEFFECT rgDiFileEft, DWORD dwFlags) { - FIXME("(%p)->(%s,%08lx,%p,%08lx): stub !\n", iface, lpszFileName, dwEntries, rgDiFileEft, dwFlags); - + FIXME("(%p)->(%s,%08x,%p,%08x): stub !\n", iface, lpszFileName, dwEntries, rgDiFileEft, dwFlags); + return DI_OK; } @@ -838,8 +1276,8 @@ HRESULT WINAPI IDirectInputDevice7WImpl_WriteEffectToFile(LPDIRECTINPUTDEVICE8W LPDIFILEEFFECT rgDiFileEft, DWORD dwFlags) { - FIXME("(%p)->(%s,%08lx,%p,%08lx): stub !\n", iface, debugstr_w(lpszFileName), dwEntries, rgDiFileEft, dwFlags); - + FIXME("(%p)->(%s,%08x,%p,%08x): stub !\n", iface, debugstr_w(lpszFileName), dwEntries, rgDiFileEft, dwFlags); + return DI_OK; } @@ -848,8 +1286,14 @@ HRESULT WINAPI IDirectInputDevice8AImpl_BuildActionMap(LPDIRECTINPUTDEVICE8A ifa LPCSTR lpszUserName, DWORD dwFlags) { - FIXME("(%p)->(%p,%s,%08lx): stub !\n", iface, lpdiaf, lpszUserName, dwFlags); - + FIXME("(%p)->(%p,%s,%08x): stub !\n", iface, lpdiaf, lpszUserName, dwFlags); +#define X(x) if (dwFlags & x) FIXME("\tdwFlags =|"#x"\n"); + X(DIDBAM_DEFAULT) + X(DIDBAM_PRESERVE) + X(DIDBAM_INITIALIZE) + X(DIDBAM_HWDEFAULTS) +#undef X + _dump_diactionformatA(lpdiaf); return DI_OK; } @@ -858,8 +1302,14 @@ HRESULT WINAPI IDirectInputDevice8WImpl_BuildActionMap(LPDIRECTINPUTDEVICE8W ifa LPCWSTR lpszUserName, DWORD dwFlags) { - FIXME("(%p)->(%p,%s,%08lx): stub !\n", iface, lpdiaf, debugstr_w(lpszUserName), dwFlags); - + FIXME("(%p)->(%p,%s,%08x): stub !\n", iface, lpdiaf, debugstr_w(lpszUserName), dwFlags); +#define X(x) if (dwFlags & x) FIXME("\tdwFlags =|"#x"\n"); + X(DIDBAM_DEFAULT) + X(DIDBAM_PRESERVE) + X(DIDBAM_INITIALIZE) + X(DIDBAM_HWDEFAULTS) +#undef X + return DI_OK; } @@ -868,8 +1318,8 @@ HRESULT WINAPI IDirectInputDevice8AImpl_SetActionMap(LPDIRECTINPUTDEVICE8A iface LPCSTR lpszUserName, DWORD dwFlags) { - FIXME("(%p)->(%p,%s,%08lx): stub !\n", iface, lpdiaf, lpszUserName, dwFlags); - + FIXME("(%p)->(%p,%s,%08x): stub !\n", iface, lpdiaf, lpszUserName, dwFlags); + return DI_OK; } @@ -878,8 +1328,8 @@ HRESULT WINAPI IDirectInputDevice8WImpl_SetActionMap(LPDIRECTINPUTDEVICE8W iface LPCWSTR lpszUserName, DWORD dwFlags) { - FIXME("(%p)->(%p,%s,%08lx): stub !\n", iface, lpdiaf, debugstr_w(lpszUserName), dwFlags); - + FIXME("(%p)->(%p,%s,%08x): stub !\n", iface, lpdiaf, debugstr_w(lpszUserName), dwFlags); + return DI_OK; } @@ -887,7 +1337,7 @@ HRESULT WINAPI IDirectInputDevice8AImpl_GetImageInfo(LPDIRECTINPUTDEVICE8A iface LPDIDEVICEIMAGEINFOHEADERA lpdiDevImageInfoHeader) { FIXME("(%p)->(%p): stub !\n", iface, lpdiDevImageInfoHeader); - + return DI_OK; } @@ -895,6 +1345,6 @@ HRESULT WINAPI IDirectInputDevice8WImpl_GetImageInfo(LPDIRECTINPUTDEVICE8W iface LPDIDEVICEIMAGEINFOHEADERW lpdiDevImageInfoHeader) { FIXME("(%p)->(%p): stub !\n", iface, lpdiDevImageInfoHeader); - + return DI_OK; } diff --git a/reactos/dll/directx/dinput/device_private.h b/reactos/dll/directx/dinput/device_private.h index 4567c85409e..346338201e2 100644 --- a/reactos/dll/directx/dinput/device_private.h +++ b/reactos/dll/directx/dinput/device_private.h @@ -14,7 +14,7 @@ * * 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 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __WINE_DLLS_DINPUT_DINPUTDEVICE_PRIVATE_H @@ -25,78 +25,98 @@ #include "windef.h" #include "winbase.h" #include "dinput.h" +#include "wine/list.h" +#include "dinput_private.h" + +typedef struct +{ + int size; + int offset_in; + int offset_out; + int value; +} DataTransform; + +typedef struct +{ + int size; + int internal_format_size; + DataTransform *dt; + + int *offsets; /* object offsets */ + LPDIDATAFORMAT wine_df; /* wine internal data format */ + LPDIDATAFORMAT user_df; /* user defined data format */ +} DataFormat; /* Device implementation */ typedef struct IDirectInputDevice2AImpl IDirectInputDevice2AImpl; struct IDirectInputDevice2AImpl { - const IDirectInputDevice2AVtbl *lpVtbl; - LONG ref; - GUID guid; + const void *lpVtbl; + LONG ref; + GUID guid; + CRITICAL_SECTION crit; + IDirectInputImpl *dinput; + struct list entry; /* entry into IDirectInput devices list */ + HANDLE hEvent; + DWORD dwCoopLevel; + HWND win; + int acquired; + DI_EVENT_PROC event_proc; /* function to receive mouse & keyboard events */ + + LPDIDEVICEOBJECTDATA data_queue; /* buffer for 'GetDeviceData'. */ + int queue_len; /* size of the queue - set in 'SetProperty' */ + int queue_head; /* position to write new event into queue */ + int queue_tail; /* next event to read from queue */ + BOOL overflow; /* return DI_BUFFEROVERFLOW in 'GetDeviceData' */ + + DataFormat data_format; /* user data format and wine to user format converter */ }; +extern BOOL get_app_key(HKEY*, HKEY*); +extern DWORD get_config_key(HKEY, HKEY, const char*, char*, DWORD); + /* Routines to do DataFormat / WineFormat conversions */ -typedef struct { - int size; - int offset_in; - int offset_out; - int value; -} DataTransform; - -typedef struct { - int size; - int internal_format_size; - DataTransform *dt; -} DataFormat; -extern void fill_DataFormat(void *out, const void *in, DataFormat *df) ; -extern DataFormat *create_DataFormat(const DIDATAFORMAT *wine_format, LPCDIDATAFORMAT asked_format, int *offset) ; +extern void fill_DataFormat(void *out, DWORD size, const void *in, const DataFormat *df) ; extern void release_DataFormat(DataFormat *df) ; +extern void queue_event(LPDIRECTINPUTDEVICE8A iface, int ofs, DWORD data, DWORD time, DWORD seq); +/* Helper functions to work with data format */ +extern int id_to_object(LPCDIDATAFORMAT df, int id); +extern int id_to_offset(const DataFormat *df, int id); +extern int find_property(const DataFormat *df, LPCDIPROPHEADER ph); -/* Used to fill events in the queue */ -#define GEN_EVENT(offset,data,xtime,seq) \ -{ \ - /* If queue_len > 0, queuing is requested -> TRACE the event queued */ \ - if (This->queue_len > 0) { \ - int nq; \ - TRACE(" queueing %d at offset %d (queue head %d / size %d)\n", \ - (int) (data), (int) (offset), \ - (int) (This->queue_head), (int) (This->queue_len)); \ - \ - nq = This->queue_head+1; \ - while (nq >= This->queue_len) nq -= This->queue_len; \ - if ((offset >= 0) && (nq != This->queue_tail)) { \ - This->data_queue[This->queue_head].dwOfs = offset; \ - This->data_queue[This->queue_head].dwData = data; \ - This->data_queue[This->queue_head].dwTimeStamp = xtime; \ - This->data_queue[This->queue_head].dwSequence = seq; \ - This->queue_head = nq; \ - } else \ - This->overflow = TRUE; \ - } \ -} +/* Common joystick stuff */ +typedef struct +{ + LONG lDevMin; + LONG lDevMax; + LONG lMin; + LONG lMax; + LONG lDeadZone; + LONG lSaturation; +} ObjProps; -/** - * Callback Data used by specific callback - * for EnumObject on 'W' interfaces - */ -typedef struct { - LPDIENUMDEVICEOBJECTSCALLBACKW lpCallBack; - LPVOID lpvRef; -} device_enumobjects_AtoWcb_data; +extern DWORD joystick_map_pov(POINTL *p); +extern LONG joystick_map_axis(ObjProps *props, int val); -extern BOOL DIEnumDevicesCallbackAtoW(LPCDIDEVICEOBJECTINSTANCEA, LPVOID); +typedef struct +{ + struct list entry; + LPDIRECTINPUTEFFECT ref; +} effect_list_item; +extern const GUID DInput_Wine_Keyboard_GUID; +extern const GUID DInput_Wine_Mouse_GUID; /* Various debug tools */ -extern void _dump_cooperativelevel_DI(DWORD dwFlags) ; -extern void _dump_EnumObjects_flags(DWORD dwFlags) ; extern void _dump_DIPROPHEADER(LPCDIPROPHEADER diph) ; -extern void _dump_OBJECTINSTANCEA(DIDEVICEOBJECTINSTANCEA *ddoi) ; -extern void _dump_OBJECTINSTANCEW(DIDEVICEOBJECTINSTANCEW *ddoi) ; +extern void _dump_OBJECTINSTANCEA(const DIDEVICEOBJECTINSTANCEA *ddoi) ; +extern void _dump_OBJECTINSTANCEW(const DIDEVICEOBJECTINSTANCEW *ddoi) ; extern void _dump_DIDATAFORMAT(const DIDATAFORMAT *df) ; extern const char *_dump_dinput_GUID(const GUID *guid) ; /* And the stubs */ +extern HRESULT WINAPI IDirectInputDevice2AImpl_Acquire(LPDIRECTINPUTDEVICE8A iface); +extern HRESULT WINAPI IDirectInputDevice2AImpl_Unacquire(LPDIRECTINPUTDEVICE8A iface); extern HRESULT WINAPI IDirectInputDevice2AImpl_SetDataFormat( LPDIRECTINPUTDEVICE8A iface,LPCDIDATAFORMAT df ) ; extern HRESULT WINAPI IDirectInputDevice2AImpl_SetCooperativeLevel( @@ -118,25 +138,19 @@ extern HRESULT WINAPI IDirectInputDevice2WImpl_EnumObjects( LPDIENUMDEVICEOBJECTSCALLBACKW lpCallback, LPVOID lpvRef, DWORD dwFlags) ; -extern HRESULT WINAPI IDirectInputDevice2AImpl_GetProperty( - LPDIRECTINPUTDEVICE8A iface, - REFGUID rguid, - LPDIPROPHEADER pdiph) ; +extern HRESULT WINAPI IDirectInputDevice2AImpl_GetProperty(LPDIRECTINPUTDEVICE8A iface, REFGUID rguid, LPDIPROPHEADER pdiph); +extern HRESULT WINAPI IDirectInputDevice2AImpl_SetProperty(LPDIRECTINPUTDEVICE8A iface, REFGUID rguid, LPCDIPROPHEADER pdiph); extern HRESULT WINAPI IDirectInputDevice2AImpl_GetObjectInfo( LPDIRECTINPUTDEVICE8A iface, LPDIDEVICEOBJECTINSTANCEA pdidoi, DWORD dwObj, DWORD dwHow) ; -extern HRESULT WINAPI IDirectInputDevice2WImpl_GetObjectInfo(LPDIRECTINPUTDEVICE8W iface, +extern HRESULT WINAPI IDirectInputDevice2WImpl_GetObjectInfo(LPDIRECTINPUTDEVICE8W iface, LPDIDEVICEOBJECTINSTANCEW pdidoi, DWORD dwObj, DWORD dwHow); -extern HRESULT WINAPI IDirectInputDevice2AImpl_GetDeviceInfo( - LPDIRECTINPUTDEVICE8A iface, - LPDIDEVICEINSTANCEA pdidi) ; -extern HRESULT WINAPI IDirectInputDevice2WImpl_GetDeviceInfo( - LPDIRECTINPUTDEVICE8W iface, - LPDIDEVICEINSTANCEW pdidi) ; +extern HRESULT WINAPI IDirectInputDevice2AImpl_GetDeviceData(LPDIRECTINPUTDEVICE8A iface, + DWORD dodsize, LPDIDEVICEOBJECTDATA dod, LPDWORD entries, DWORD flags); extern HRESULT WINAPI IDirectInputDevice2AImpl_RunControlPanel( LPDIRECTINPUTDEVICE8A iface, HWND hwndOwner, diff --git a/reactos/dll/directx/dinput/dinput.rbuild b/reactos/dll/directx/dinput/dinput.rbuild index bca3429f876..127853bc2b4 100644 --- a/reactos/dll/directx/dinput/dinput.rbuild +++ b/reactos/dll/directx/dinput/dinput.rbuild @@ -3,6 +3,7 @@ + 0x600 . include/reactos/wine wine diff --git a/reactos/dll/directx/dinput/dinput_main.c b/reactos/dll/directx/dinput/dinput_main.c index bdb3d2f462f..46e4e281e73 100644 --- a/reactos/dll/directx/dinput/dinput_main.c +++ b/reactos/dll/directx/dinput/dinput_main.c @@ -3,6 +3,7 @@ * Copyright 1998 Marcus Meissner * Copyright 1998,1999 Lionel Ulmer * Copyright 2000-2002 TransGaming Technologies Inc. + * Copyright 2007 Vitaliy Margolen * * * This library is free software; you can redistribute it and/or @@ -17,7 +18,7 @@ * * 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 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ /* Status: * @@ -35,6 +36,7 @@ #include #define COBJMACROS +#define NONAMELESSUNION #include "wine/debug.h" #include "wine/unicode.h" @@ -43,6 +45,7 @@ #include "winuser.h" #include "winerror.h" #include "dinput_private.h" +#include "device_private.h" WINE_DEFAULT_DEBUG_CHANNEL(dinput); @@ -51,6 +54,26 @@ static const IDirectInput7WVtbl ddi7wvt; static const IDirectInput8AVtbl ddi8avt; static const IDirectInput8WVtbl ddi8wvt; +static inline IDirectInputImpl *impl_from_IDirectInput7W( IDirectInput7W *iface ) +{ + return CONTAINING_RECORD( iface, IDirectInputImpl, lpVtbl7w ); +} + +static inline IDirectInputImpl *impl_from_IDirectInput8A( IDirectInput8A *iface ) +{ + return CONTAINING_RECORD( iface, IDirectInputImpl, lpVtbl8a ); +} + +static inline IDirectInputImpl *impl_from_IDirectInput8W( IDirectInput8W *iface ) +{ + return CONTAINING_RECORD( iface, IDirectInputImpl, lpVtbl8w ); +} + +static inline IDirectInput7W *IDirectInput7W_from_impl( IDirectInputImpl *iface ) +{ + return (IDirectInput7W *)(&iface->lpVtbl7w); +} + static const struct dinput_device *dinput_devices[] = { &mouse_device, @@ -60,7 +83,7 @@ static const struct dinput_device *dinput_devices[] = }; #define NB_DINPUT_DEVICES (sizeof(dinput_devices)/sizeof(dinput_devices[0])) -HINSTANCE DINPUT_instance = NULL; +static HINSTANCE DINPUT_instance = NULL; BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserv) { @@ -76,63 +99,63 @@ BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, LPVOID reserv) return TRUE; } +static BOOL check_hook_thread(void); +static CRITICAL_SECTION dinput_hook_crit; +static struct list direct_input_list = LIST_INIT( direct_input_list ); /****************************************************************************** * DirectInputCreateEx (DINPUT.@) */ HRESULT WINAPI DirectInputCreateEx( HINSTANCE hinst, DWORD dwVersion, REFIID riid, LPVOID *ppDI, - LPUNKNOWN punkOuter) + LPUNKNOWN punkOuter) { - IDirectInputImpl* This; + IDirectInputImpl* This; - TRACE("(%p,%04lx,%s,%p,%p)\n", hinst,dwVersion,debugstr_guid(riid),ppDI,punkOuter); + TRACE("(%p,%04x,%s,%p,%p)\n", hinst, dwVersion, debugstr_guid(riid), ppDI, punkOuter); - if (IsEqualGUID(&IID_IDirectInputA,riid) || - IsEqualGUID(&IID_IDirectInput2A,riid) || - IsEqualGUID(&IID_IDirectInput7A,riid)) { - This = HeapAlloc(GetProcessHeap(),0,sizeof(IDirectInputImpl)); - This->lpVtbl = &ddi7avt; - This->ref = 1; - This->dwVersion = dwVersion; - *ppDI = This; + if (IsEqualGUID( &IID_IUnknown, riid ) || + IsEqualGUID( &IID_IDirectInputA, riid ) || + IsEqualGUID( &IID_IDirectInput2A, riid ) || + IsEqualGUID( &IID_IDirectInput7A, riid ) || + IsEqualGUID( &IID_IDirectInputW, riid ) || + IsEqualGUID( &IID_IDirectInput2W, riid ) || + IsEqualGUID( &IID_IDirectInput7W, riid ) || + IsEqualGUID( &IID_IDirectInput8A, riid ) || + IsEqualGUID( &IID_IDirectInput8W, riid )) + { + if (!(This = HeapAlloc( GetProcessHeap(), 0, sizeof(IDirectInputImpl) ))) + return DIERR_OUTOFMEMORY; + } + else + return DIERR_OLDDIRECTINPUTVERSION; - return DI_OK; - } + This->lpVtbl = &ddi7avt; + This->lpVtbl7w = &ddi7wvt; + This->lpVtbl8a = &ddi8avt; + This->lpVtbl8w = &ddi8wvt; + This->ref = 0; + This->dwVersion = dwVersion; + This->evsequence = 1; - if (IsEqualGUID(&IID_IDirectInputW,riid) || - IsEqualGUID(&IID_IDirectInput2W,riid) || - IsEqualGUID(&IID_IDirectInput7W,riid)) { - This = HeapAlloc(GetProcessHeap(),0,sizeof(IDirectInputImpl)); - This->lpVtbl = &ddi7wvt; - This->ref = 1; - This->dwVersion = dwVersion; - *ppDI = This; + InitializeCriticalSection(&This->crit); + This->crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": IDirectInputImpl*->crit"); - return DI_OK; - } + list_init( &This->devices_list ); - if (IsEqualGUID(&IID_IDirectInput8A,riid)) { - This = HeapAlloc(GetProcessHeap(),0,sizeof(IDirectInputImpl)); - This->lpVtbl = &ddi8avt; - This->ref = 1; - This->dwVersion = dwVersion; - *ppDI = This; + /* Add self to the list of the IDirectInputs */ + EnterCriticalSection( &dinput_hook_crit ); + list_add_head( &direct_input_list, &This->entry ); + LeaveCriticalSection( &dinput_hook_crit ); - return DI_OK; - } + if (!check_hook_thread()) + { + IUnknown_Release( (LPDIRECTINPUT7A)This ); + return DIERR_GENERIC; + } - if (IsEqualGUID(&IID_IDirectInput8W,riid)) { - This = HeapAlloc(GetProcessHeap(),0,sizeof(IDirectInputImpl)); - This->lpVtbl = &ddi8wvt; - This->ref = 1; - This->dwVersion = dwVersion; - *ppDI = This; - - return DI_OK; - } - - return DIERR_OLDDIRECTINPUTVERSION; + IDirectInput_QueryInterface( (IDirectInput7A *)This, riid, ppDI ); + return DI_OK; } /****************************************************************************** @@ -140,15 +163,7 @@ HRESULT WINAPI DirectInputCreateEx( */ HRESULT WINAPI DirectInputCreateA(HINSTANCE hinst, DWORD dwVersion, LPDIRECTINPUTA *ppDI, LPUNKNOWN punkOuter) { - IDirectInputImpl* This; - TRACE("(0x%08lx,%04lx,%p,%p)\n", (DWORD)hinst,dwVersion,ppDI,punkOuter); - This = HeapAlloc(GetProcessHeap(),0,sizeof(IDirectInputImpl)); - This->lpVtbl = &ddi7avt; - This->ref = 1; - This->dwVersion = dwVersion; - *ppDI = (IDirectInputA*)This; - return 0; - + return DirectInputCreateEx(hinst, dwVersion, &IID_IDirectInput7A, (LPVOID *)ppDI, punkOuter); } /****************************************************************************** @@ -156,14 +171,7 @@ HRESULT WINAPI DirectInputCreateA(HINSTANCE hinst, DWORD dwVersion, LPDIRECTINPU */ HRESULT WINAPI DirectInputCreateW(HINSTANCE hinst, DWORD dwVersion, LPDIRECTINPUTW *ppDI, LPUNKNOWN punkOuter) { - IDirectInputImpl* This; - TRACE("(0x%08lx,%04lx,%p,%p)\n", (DWORD)hinst,dwVersion,ppDI,punkOuter); - This = HeapAlloc(GetProcessHeap(),0,sizeof(IDirectInputImpl)); - This->lpVtbl = &ddi7wvt; - This->ref = 1; - This->dwVersion = dwVersion; - *ppDI = (IDirectInputW*)This; - return 0; + return DirectInputCreateEx(hinst, dwVersion, &IID_IDirectInput7W, (LPVOID *)ppDI, punkOuter); } static const char *_dump_DIDEVTYPE_value(DWORD dwDevType) { @@ -192,14 +200,45 @@ static void _dump_EnumDevices_dwFlags(DWORD dwFlags) { FE(DIEDFL_INCLUDEPHANTOMS) #undef FE }; + TRACE(" flags: "); if (dwFlags == 0) { - DPRINTF("DIEDFL_ALLDEVICES"); + TRACE("DIEDFL_ALLDEVICES"); return; } for (i = 0; i < (sizeof(flags) / sizeof(flags[0])); i++) if (flags[i].mask & dwFlags) - DPRINTF("%s ",flags[i].name); + TRACE("%s ",flags[i].name); } + TRACE("\n"); +} + +void _dump_diactionformatA(LPDIACTIONFORMATA lpdiActionFormat) { + unsigned int i; + + FIXME("diaf.dwSize = %d\n", lpdiActionFormat->dwSize); + FIXME("diaf.dwActionSize = %d\n", lpdiActionFormat->dwActionSize); + FIXME("diaf.dwDataSize = %d\n", lpdiActionFormat->dwDataSize); + FIXME("diaf.dwNumActions = %d\n", lpdiActionFormat->dwNumActions); + FIXME("diaf.rgoAction = %p\n", lpdiActionFormat->rgoAction); + for (i=0;idwNumActions;i++) { + FIXME("diaf.rgoAction[%u]:\n", i); + FIXME("\tuAppData=%lx\n", lpdiActionFormat->rgoAction[i].uAppData); + FIXME("\tdwSemantics=%x\n", lpdiActionFormat->rgoAction[i].dwSemantics); + FIXME("\tdwFlags=%x\n", lpdiActionFormat->rgoAction[i].dwFlags); + FIXME("\tszActionName=%s\n", debugstr_a(lpdiActionFormat->rgoAction[i].u.lptszActionName)); + FIXME("\tguidInstance=%s\n", debugstr_guid(&lpdiActionFormat->rgoAction[i].guidInstance)); + FIXME("\tdwObjID=%x\n", lpdiActionFormat->rgoAction[i].dwObjID); + FIXME("\tdwHow=%x\n", lpdiActionFormat->rgoAction[i].dwHow); + } + FIXME("diaf.guidActionMap = %s\n", debugstr_guid(&lpdiActionFormat->guidActionMap)); + FIXME("diaf.dwGenre = %d\n", lpdiActionFormat->dwGenre); + FIXME("diaf.dwBufferSize = %d\n", lpdiActionFormat->dwBufferSize); + FIXME("diaf.lAxisMin = %d\n", lpdiActionFormat->lAxisMin); + FIXME("diaf.lAxisMax = %d\n", lpdiActionFormat->lAxisMax); + FIXME("diaf.hInstString = %p\n", lpdiActionFormat->hInstString); + FIXME("diaf.ftTimeStamp ...\n"); + FIXME("diaf.dwCRC = %x\n", lpdiActionFormat->dwCRC); + FIXME("diaf.tszActionMap = %s\n", debugstr_a(lpdiActionFormat->tszActionMap)); } /****************************************************************************** @@ -211,25 +250,26 @@ static HRESULT WINAPI IDirectInputAImpl_EnumDevices( { IDirectInputImpl *This = (IDirectInputImpl *)iface; DIDEVICEINSTANCEA devInstance; - int i, j, r; + unsigned int i; + int j, r; - TRACE("(this=%p,0x%04lx '%s',%p,%p,%04lx)\n", + TRACE("(this=%p,0x%04x '%s',%p,%p,%04x)\n", This, dwDevType, _dump_DIDEVTYPE_value(dwDevType), lpCallback, pvRef, dwFlags); - TRACE(" flags: "); _dump_EnumDevices_dwFlags(dwFlags); TRACE("\n"); + _dump_EnumDevices_dwFlags(dwFlags); for (i = 0; i < NB_DINPUT_DEVICES; i++) { if (!dinput_devices[i]->enum_deviceA) continue; for (j = 0, r = -1; r != 0; j++) { devInstance.dwSize = sizeof(devInstance); - TRACE(" - checking device %d ('%s')\n", i, dinput_devices[i]->name); + TRACE(" - checking device %u ('%s')\n", i, dinput_devices[i]->name); if ((r = dinput_devices[i]->enum_deviceA(dwDevType, dwFlags, &devInstance, This->dwVersion, j))) { if (lpCallback(&devInstance,pvRef) == DIENUM_STOP) return 0; } } } - + return 0; } /****************************************************************************** @@ -237,172 +277,203 @@ static HRESULT WINAPI IDirectInputAImpl_EnumDevices( */ static HRESULT WINAPI IDirectInputWImpl_EnumDevices( LPDIRECTINPUT7W iface, DWORD dwDevType, LPDIENUMDEVICESCALLBACKW lpCallback, - LPVOID pvRef, DWORD dwFlags) + LPVOID pvRef, DWORD dwFlags) { - IDirectInputImpl *This = (IDirectInputImpl *)iface; + IDirectInputImpl *This = impl_from_IDirectInput7W( iface ); DIDEVICEINSTANCEW devInstance; - int i, j, r; + unsigned int i; + int j, r; - TRACE("(this=%p,0x%04lx '%s',%p,%p,%04lx)\n", + TRACE("(this=%p,0x%04x '%s',%p,%p,%04x)\n", This, dwDevType, _dump_DIDEVTYPE_value(dwDevType), lpCallback, pvRef, dwFlags); - TRACE(" flags: "); _dump_EnumDevices_dwFlags(dwFlags); TRACE("\n"); + _dump_EnumDevices_dwFlags(dwFlags); for (i = 0; i < NB_DINPUT_DEVICES; i++) { if (!dinput_devices[i]->enum_deviceW) continue; for (j = 0, r = -1; r != 0; j++) { devInstance.dwSize = sizeof(devInstance); - TRACE(" - checking device %d ('%s')\n", i, dinput_devices[i]->name); + TRACE(" - checking device %u ('%s')\n", i, dinput_devices[i]->name); if ((r = dinput_devices[i]->enum_deviceW(dwDevType, dwFlags, &devInstance, This->dwVersion, j))) { if (lpCallback(&devInstance,pvRef) == DIENUM_STOP) return 0; } } } - + return 0; } static ULONG WINAPI IDirectInputAImpl_AddRef(LPDIRECTINPUT7A iface) { - IDirectInputImpl *This = (IDirectInputImpl *)iface; - return InterlockedIncrement((&This->ref)); + IDirectInputImpl *This = (IDirectInputImpl *)iface; + ULONG ref = InterlockedIncrement(&This->ref); + + TRACE( "(%p) incrementing from %d\n", This, ref - 1); + return ref; +} + +static ULONG WINAPI IDirectInputWImpl_AddRef(LPDIRECTINPUT7W iface) +{ + IDirectInputImpl *This = impl_from_IDirectInput7W( iface ); + return IDirectInputAImpl_AddRef( (IDirectInput7A *)This ); } static ULONG WINAPI IDirectInputAImpl_Release(LPDIRECTINPUT7A iface) { - IDirectInputImpl *This = (IDirectInputImpl *)iface; - ULONG ref; - ref = InterlockedDecrement(&(This->ref)); - if (ref == 0) - HeapFree(GetProcessHeap(),0,This); - return ref; + IDirectInputImpl *This = (IDirectInputImpl *)iface; + ULONG ref = InterlockedDecrement( &This->ref ); + + TRACE( "(%p) releasing from %d\n", This, ref + 1 ); + + if (ref) return ref; + + /* Remove self from the list of the IDirectInputs */ + EnterCriticalSection( &dinput_hook_crit ); + list_remove( &This->entry ); + LeaveCriticalSection( &dinput_hook_crit ); + + check_hook_thread(); + + This->crit.DebugInfo->Spare[0] = 0; + DeleteCriticalSection( &This->crit ); + HeapFree( GetProcessHeap(), 0, This ); + + return 0; } -static HRESULT WINAPI IDirectInputAImpl_QueryInterface(LPDIRECTINPUT7A iface, REFIID riid, LPVOID *ppobj) { - IDirectInputImpl *This = (IDirectInputImpl *)iface; - - TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(riid),ppobj); - if (IsEqualGUID(&IID_IUnknown,riid) || - IsEqualGUID(&IID_IDirectInputA,riid) || - IsEqualGUID(&IID_IDirectInput2A,riid) || - IsEqualGUID(&IID_IDirectInput7A,riid)) { - IDirectInputAImpl_AddRef(iface); - *ppobj = This; - return 0; - } - TRACE("Unsupported interface !\n"); - return E_FAIL; +static ULONG WINAPI IDirectInputWImpl_Release(LPDIRECTINPUT7W iface) +{ + IDirectInputImpl *This = impl_from_IDirectInput7W( iface ); + return IDirectInputAImpl_Release( (IDirectInput7A *)This ); } -static HRESULT WINAPI IDirectInputWImpl_QueryInterface(LPDIRECTINPUT7W iface, REFIID riid, LPVOID *ppobj) { - IDirectInputImpl *This = (IDirectInputImpl *)iface; +static HRESULT WINAPI IDirectInputAImpl_QueryInterface(LPDIRECTINPUT7A iface, REFIID riid, LPVOID *ppobj) +{ + IDirectInputImpl *This = (IDirectInputImpl *)iface; - TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(riid),ppobj); - if (IsEqualGUID(&IID_IUnknown,riid) || - IsEqualGUID(&IID_IDirectInputW,riid) || - IsEqualGUID(&IID_IDirectInput2W,riid) || - IsEqualGUID(&IID_IDirectInput7W,riid)) { - IDirectInputAImpl_AddRef((LPDIRECTINPUT7A) iface); - *ppobj = This; - return 0; - } - TRACE("Unsupported interface !\n"); - return E_FAIL; + TRACE( "(%p)->(%s,%p)\n", This, debugstr_guid(riid), ppobj ); + + if (IsEqualGUID( &IID_IUnknown, riid ) || + IsEqualGUID( &IID_IDirectInputA, riid ) || + IsEqualGUID( &IID_IDirectInput2A, riid ) || + IsEqualGUID( &IID_IDirectInput7A, riid )) + { + *ppobj = &This->lpVtbl; + IUnknown_AddRef( (IUnknown*)*ppobj ); + + return DI_OK; + } + + if (IsEqualGUID( &IID_IDirectInputW, riid ) || + IsEqualGUID( &IID_IDirectInput2W, riid ) || + IsEqualGUID( &IID_IDirectInput7W, riid )) + { + *ppobj = &This->lpVtbl7w; + IUnknown_AddRef( (IUnknown*)*ppobj ); + + return DI_OK; + } + + if (IsEqualGUID( &IID_IDirectInput8A, riid )) + { + *ppobj = &This->lpVtbl8a; + IUnknown_AddRef( (IUnknown*)*ppobj ); + + return DI_OK; + } + + if (IsEqualGUID( &IID_IDirectInput8W, riid )) + { + *ppobj = &This->lpVtbl8w; + IUnknown_AddRef( (IUnknown*)*ppobj ); + + return DI_OK; + } + + FIXME( "Unsupported interface !\n" ); + return E_FAIL; } -static HRESULT WINAPI IDirectInputAImpl_CreateDevice( - LPDIRECTINPUT7A iface,REFGUID rguid,LPDIRECTINPUTDEVICEA* pdev, - LPUNKNOWN punk -) { - IDirectInputImpl *This = (IDirectInputImpl *)iface; - HRESULT ret_value = DIERR_DEVICENOTREG; - int i; - - TRACE("(this=%p,%s,%p,%p)\n",This,debugstr_guid(rguid),pdev,punk); - - if (pdev == NULL) { - WARN("invalid pointer: pdev == NULL\n"); - return E_POINTER; - } - - if (rguid == NULL) { - WARN("invalid pointer: rguid == NULL\n"); - return E_POINTER; - } - - /* Loop on all the devices to see if anyone matches the given GUID */ - for (i = 0; i < NB_DINPUT_DEVICES; i++) { - HRESULT ret; - if (!dinput_devices[i]->create_deviceA) continue; - if ((ret = dinput_devices[i]->create_deviceA(This, rguid, NULL, pdev)) == DI_OK) - return DI_OK; - - if (ret == DIERR_NOINTERFACE) - ret_value = DIERR_NOINTERFACE; - } - - return ret_value; -} - -static HRESULT WINAPI IDirectInputWImpl_CreateDevice(LPDIRECTINPUT7A iface, - REFGUID rguid, LPDIRECTINPUTDEVICEW* pdev, LPUNKNOWN punk) { - IDirectInputImpl *This = (IDirectInputImpl *)iface; - HRESULT ret_value = DIERR_DEVICENOTREG; - int i; - - TRACE("(this=%p,%s,%p,%p)\n",This,debugstr_guid(rguid),pdev,punk); - - /* Loop on all the devices to see if anyone matches the given GUID */ - for (i = 0; i < NB_DINPUT_DEVICES; i++) { - HRESULT ret; - if (!dinput_devices[i]->create_deviceW) continue; - if ((ret = dinput_devices[i]->create_deviceW(This, rguid, NULL, pdev)) == DI_OK) - return DI_OK; - - if (ret == DIERR_NOINTERFACE) - ret_value = DIERR_NOINTERFACE; - } - - return ret_value; +static HRESULT WINAPI IDirectInputWImpl_QueryInterface(LPDIRECTINPUT7W iface, REFIID riid, LPVOID *ppobj) +{ + IDirectInputImpl *This = impl_from_IDirectInput7W( iface ); + return IDirectInputAImpl_QueryInterface( (IDirectInput7A *)This, riid, ppobj ); } static HRESULT WINAPI IDirectInputAImpl_Initialize(LPDIRECTINPUT7A iface, HINSTANCE hinst, DWORD x) { - return DIERR_ALREADYINITIALIZED; + TRACE("(this=%p,%p,%x)\n",iface, hinst, x); + + /* Initialize can return: DIERR_BETADIRECTINPUTVERSION, DIERR_OLDDIRECTINPUTVERSION and DI_OK. + * Since we already initialized the device, return DI_OK. In the past we returned DIERR_ALREADYINITIALIZED + * which broke applications like Tomb Raider Legend because it isn't a legal return value. + */ + return DI_OK; } -static HRESULT WINAPI IDirectInputAImpl_GetDeviceStatus(LPDIRECTINPUT7A iface, - REFGUID rguid) { - IDirectInputImpl *This = (IDirectInputImpl *)iface; +static HRESULT WINAPI IDirectInputWImpl_Initialize(LPDIRECTINPUT7W iface, HINSTANCE hinst, DWORD x) +{ + IDirectInputImpl *This = impl_from_IDirectInput7W( iface ); + return IDirectInputAImpl_Initialize( (IDirectInput7A *)This, hinst, x ); +} - FIXME("(%p)->(%s): stub\n",This,debugstr_guid(rguid)); +static HRESULT WINAPI IDirectInputAImpl_GetDeviceStatus(LPDIRECTINPUT7A iface, REFGUID rguid) +{ + IDirectInputImpl *This = (IDirectInputImpl *)iface; + HRESULT hr; + LPDIRECTINPUTDEVICEA device; - return DI_OK; + TRACE( "(%p)->(%s)\n", This, debugstr_guid(rguid) ); + + hr = IDirectInput_CreateDevice( iface, rguid, &device, NULL ); + if (hr != DI_OK) return DI_NOTATTACHED; + + IUnknown_Release( device ); + + return DI_OK; +} + +static HRESULT WINAPI IDirectInputWImpl_GetDeviceStatus(LPDIRECTINPUT7W iface, REFGUID rguid) +{ + IDirectInputImpl *This = impl_from_IDirectInput7W( iface ); + return IDirectInputAImpl_GetDeviceStatus( (IDirectInput7A *)This, rguid ); } static HRESULT WINAPI IDirectInputAImpl_RunControlPanel(LPDIRECTINPUT7A iface, HWND hwndOwner, - DWORD dwFlags) { - IDirectInputImpl *This = (IDirectInputImpl *)iface; - FIXME("(%p)->(%p,%08lx): stub\n",This, hwndOwner, dwFlags); + DWORD dwFlags) +{ + IDirectInputImpl *This = (IDirectInputImpl *)iface; - return DI_OK; + FIXME( "(%p)->(%p,%08x): stub\n", This, hwndOwner, dwFlags ); + + return DI_OK; +} + +static HRESULT WINAPI IDirectInputWImpl_RunControlPanel(LPDIRECTINPUT7W iface, HWND hwndOwner, DWORD dwFlags) +{ + IDirectInputImpl *This = impl_from_IDirectInput7W( iface ); + return IDirectInputAImpl_RunControlPanel( (IDirectInput7A *)This, hwndOwner, dwFlags ); } static HRESULT WINAPI IDirectInput2AImpl_FindDevice(LPDIRECTINPUT7A iface, REFGUID rguid, - LPCSTR pszName, LPGUID pguidInstance) { - IDirectInputImpl *This = (IDirectInputImpl *)iface; - FIXME("(%p)->(%s, %s, %p): stub\n", This, debugstr_guid(rguid), pszName, pguidInstance); + LPCSTR pszName, LPGUID pguidInstance) +{ + IDirectInputImpl *This = (IDirectInputImpl *)iface; - return DI_OK; + FIXME( "(%p)->(%s, %s, %p): stub\n", This, debugstr_guid(rguid), pszName, pguidInstance ); + + return DI_OK; } static HRESULT WINAPI IDirectInput2WImpl_FindDevice(LPDIRECTINPUT7W iface, REFGUID rguid, - LPCWSTR pszName, LPGUID pguidInstance) { - IDirectInputImpl *This = (IDirectInputImpl *)iface; - FIXME("(%p)->(%s, %s, %p): stub\n", This, debugstr_guid(rguid), debugstr_w(pszName), pguidInstance); + LPCWSTR pszName, LPGUID pguidInstance) +{ + IDirectInputImpl *This = impl_from_IDirectInput7W( iface ); - return DI_OK; + FIXME( "(%p)->(%s, %s, %p): stub\n", This, debugstr_guid(rguid), debugstr_w(pszName), pguidInstance ); + + return DI_OK; } static HRESULT WINAPI IDirectInput7AImpl_CreateDeviceEx(LPDIRECTINPUT7A iface, REFGUID rguid, @@ -410,39 +481,60 @@ static HRESULT WINAPI IDirectInput7AImpl_CreateDeviceEx(LPDIRECTINPUT7A iface, R { IDirectInputImpl *This = (IDirectInputImpl *)iface; HRESULT ret_value = DIERR_DEVICENOTREG; - int i; + unsigned int i; TRACE("(%p)->(%s, %s, %p, %p)\n", This, debugstr_guid(rguid), debugstr_guid(riid), pvOut, lpUnknownOuter); + if (!rguid || !pvOut) return E_POINTER; + /* Loop on all the devices to see if anyone matches the given GUID */ for (i = 0; i < NB_DINPUT_DEVICES; i++) { HRESULT ret; + if (!dinput_devices[i]->create_deviceA) continue; if ((ret = dinput_devices[i]->create_deviceA(This, rguid, riid, (LPDIRECTINPUTDEVICEA*) pvOut)) == DI_OK) + { + EnterCriticalSection( &This->crit ); + list_add_tail( &This->devices_list, &(*(IDirectInputDevice2AImpl**)pvOut)->entry ); + LeaveCriticalSection( &This->crit ); return DI_OK; + } if (ret == DIERR_NOINTERFACE) ret_value = DIERR_NOINTERFACE; } + if (ret_value == DIERR_NOINTERFACE) + { + WARN("invalid device GUID %s\n", debugstr_guid(rguid)); + } + return ret_value; } static HRESULT WINAPI IDirectInput7WImpl_CreateDeviceEx(LPDIRECTINPUT7W iface, REFGUID rguid, REFIID riid, LPVOID* pvOut, LPUNKNOWN lpUnknownOuter) { - IDirectInputImpl *This = (IDirectInputImpl *)iface; + IDirectInputImpl *This = impl_from_IDirectInput7W( iface ); HRESULT ret_value = DIERR_DEVICENOTREG; - int i; + unsigned int i; TRACE("(%p)->(%s, %s, %p, %p)\n", This, debugstr_guid(rguid), debugstr_guid(riid), pvOut, lpUnknownOuter); + if (!rguid || !pvOut) return E_POINTER; + /* Loop on all the devices to see if anyone matches the given GUID */ for (i = 0; i < NB_DINPUT_DEVICES; i++) { HRESULT ret; + if (!dinput_devices[i]->create_deviceW) continue; if ((ret = dinput_devices[i]->create_deviceW(This, rguid, riid, (LPDIRECTINPUTDEVICEW*) pvOut)) == DI_OK) + { + EnterCriticalSection( &This->crit ); + list_add_tail( &This->devices_list, &(*(IDirectInputDevice2AImpl**)pvOut)->entry ); + LeaveCriticalSection( &This->crit ); return DI_OK; + } if (ret == DIERR_NOINTERFACE) ret_value = DIERR_NOINTERFACE; @@ -451,32 +543,132 @@ static HRESULT WINAPI IDirectInput7WImpl_CreateDeviceEx(LPDIRECTINPUT7W iface, R return ret_value; } -static HRESULT WINAPI IDirectInput8AImpl_QueryInterface(LPDIRECTINPUT8A iface, REFIID riid, LPVOID *ppobj) { - IDirectInputImpl *This = (IDirectInputImpl *)iface; - - TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(riid),ppobj); - if (IsEqualGUID(&IID_IUnknown,riid) || - IsEqualGUID(&IID_IDirectInput8A,riid)) { - IDirectInputAImpl_AddRef((LPDIRECTINPUT7A) iface); - *ppobj = This; - return 0; - } - TRACE("Unsupported interface !\n"); - return E_NOINTERFACE; +static HRESULT WINAPI IDirectInputAImpl_CreateDevice(LPDIRECTINPUT7A iface, REFGUID rguid, + LPDIRECTINPUTDEVICEA* pdev, LPUNKNOWN punk) +{ + return IDirectInput7AImpl_CreateDeviceEx(iface, rguid, NULL, (LPVOID*)pdev, punk); } -static HRESULT WINAPI IDirectInput8WImpl_QueryInterface(LPDIRECTINPUT8W iface, REFIID riid, LPVOID *ppobj) { - IDirectInputImpl *This = (IDirectInputImpl *)iface; +static HRESULT WINAPI IDirectInputWImpl_CreateDevice(LPDIRECTINPUT7W iface, REFGUID rguid, + LPDIRECTINPUTDEVICEW* pdev, LPUNKNOWN punk) +{ + return IDirectInput7WImpl_CreateDeviceEx(iface, rguid, NULL, (LPVOID*)pdev, punk); +} - TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(riid),ppobj); - if (IsEqualGUID(&IID_IUnknown,riid) || - IsEqualGUID(&IID_IDirectInput8W,riid)) { - IDirectInputAImpl_AddRef((LPDIRECTINPUT7A) iface); - *ppobj = This; - return 0; - } - TRACE("Unsupported interface !\n"); - return E_NOINTERFACE; +/******************************************************************************* + * DirectInput8 + */ + +static ULONG WINAPI IDirectInput8AImpl_AddRef(LPDIRECTINPUT8A iface) +{ + IDirectInputImpl *This = impl_from_IDirectInput8A( iface ); + return IDirectInputAImpl_AddRef( (IDirectInput7A *)This ); +} + +static ULONG WINAPI IDirectInput8WImpl_AddRef(LPDIRECTINPUT8W iface) +{ + IDirectInputImpl *This = impl_from_IDirectInput8W( iface ); + return IDirectInputAImpl_AddRef( (IDirectInput7A *)This ); +} + +static HRESULT WINAPI IDirectInput8AImpl_QueryInterface(LPDIRECTINPUT8A iface, REFIID riid, LPVOID *ppobj) +{ + IDirectInputImpl *This = impl_from_IDirectInput8A( iface ); + return IDirectInputAImpl_QueryInterface( (IDirectInput7A *)This, riid, ppobj ); +} + +static HRESULT WINAPI IDirectInput8WImpl_QueryInterface(LPDIRECTINPUT8W iface, REFIID riid, LPVOID *ppobj) +{ + IDirectInputImpl *This = impl_from_IDirectInput8W( iface ); + return IDirectInputAImpl_QueryInterface( (IDirectInput7A *)This, riid, ppobj ); +} + +static ULONG WINAPI IDirectInput8AImpl_Release(LPDIRECTINPUT8A iface) +{ + IDirectInputImpl *This = impl_from_IDirectInput8A( iface ); + return IDirectInputAImpl_Release( (IDirectInput7A *)This ); +} + +static ULONG WINAPI IDirectInput8WImpl_Release(LPDIRECTINPUT8W iface) +{ + IDirectInputImpl *This = impl_from_IDirectInput8W( iface ); + return IDirectInputAImpl_Release( (IDirectInput7A *)This ); +} + +static HRESULT WINAPI IDirectInput8AImpl_CreateDevice(LPDIRECTINPUT8A iface, REFGUID rguid, + LPDIRECTINPUTDEVICE8A* pdev, LPUNKNOWN punk) +{ + IDirectInputImpl *This = impl_from_IDirectInput8A( iface ); + return IDirectInput7AImpl_CreateDeviceEx( (IDirectInput7A *)This, rguid, NULL, (LPVOID*)pdev, punk ); +} + +static HRESULT WINAPI IDirectInput8WImpl_CreateDevice(LPDIRECTINPUT8W iface, REFGUID rguid, + LPDIRECTINPUTDEVICE8W* pdev, LPUNKNOWN punk) +{ + IDirectInputImpl *This = impl_from_IDirectInput8W( iface ); + return IDirectInput7WImpl_CreateDeviceEx( IDirectInput7W_from_impl( This ), rguid, NULL, (LPVOID*)pdev, punk ); +} + +static HRESULT WINAPI IDirectInput8AImpl_EnumDevices(LPDIRECTINPUT8A iface, DWORD dwDevType, LPDIENUMDEVICESCALLBACKA lpCallback, + LPVOID pvRef, DWORD dwFlags) +{ + IDirectInputImpl *This = impl_from_IDirectInput8A( iface ); + return IDirectInputAImpl_EnumDevices( (IDirectInput7A *)This, dwDevType, lpCallback, pvRef, dwFlags ); +} + +static HRESULT WINAPI IDirectInput8WImpl_EnumDevices(LPDIRECTINPUT8W iface, DWORD dwDevType, LPDIENUMDEVICESCALLBACKW lpCallback, + LPVOID pvRef, DWORD dwFlags) +{ + IDirectInputImpl *This = impl_from_IDirectInput8W( iface ); + return IDirectInputWImpl_EnumDevices( IDirectInput7W_from_impl( This ), dwDevType, lpCallback, pvRef, dwFlags ); +} + +static HRESULT WINAPI IDirectInput8AImpl_GetDeviceStatus(LPDIRECTINPUT8A iface, REFGUID rguid) +{ + IDirectInputImpl *This = impl_from_IDirectInput8A( iface ); + return IDirectInputAImpl_GetDeviceStatus( (IDirectInput7A *)This, rguid ); +} + +static HRESULT WINAPI IDirectInput8WImpl_GetDeviceStatus(LPDIRECTINPUT8W iface, REFGUID rguid) +{ + IDirectInputImpl *This = impl_from_IDirectInput8W( iface ); + return IDirectInputAImpl_GetDeviceStatus( (IDirectInput7A *)This, rguid ); +} + +static HRESULT WINAPI IDirectInput8AImpl_RunControlPanel(LPDIRECTINPUT8A iface, HWND hwndOwner, DWORD dwFlags) +{ + IDirectInputImpl *This = impl_from_IDirectInput8A( iface ); + return IDirectInputAImpl_RunControlPanel( (IDirectInput7A *)This, hwndOwner, dwFlags ); +} + +static HRESULT WINAPI IDirectInput8WImpl_RunControlPanel(LPDIRECTINPUT8W iface, HWND hwndOwner, DWORD dwFlags) +{ + IDirectInputImpl *This = impl_from_IDirectInput8W( iface ); + return IDirectInputAImpl_RunControlPanel( (IDirectInput7A *)This, hwndOwner, dwFlags ); +} + +static HRESULT WINAPI IDirectInput8AImpl_Initialize(LPDIRECTINPUT8A iface, HINSTANCE hinst, DWORD x) +{ + IDirectInputImpl *This = impl_from_IDirectInput8A( iface ); + return IDirectInputAImpl_Initialize( (IDirectInput7A *)This, hinst, x ); +} + +static HRESULT WINAPI IDirectInput8WImpl_Initialize(LPDIRECTINPUT8W iface, HINSTANCE hinst, DWORD x) +{ + IDirectInputImpl *This = impl_from_IDirectInput8W( iface ); + return IDirectInputAImpl_Initialize( (IDirectInput7A *)This, hinst, x ); +} + +static HRESULT WINAPI IDirectInput8AImpl_FindDevice(LPDIRECTINPUT8A iface, REFGUID rguid, LPCSTR pszName, LPGUID pguidInstance) +{ + IDirectInputImpl *This = impl_from_IDirectInput8A( iface ); + return IDirectInput2AImpl_FindDevice( (IDirectInput7A *)This, rguid, pszName, pguidInstance ); +} + +static HRESULT WINAPI IDirectInput8WImpl_FindDevice(LPDIRECTINPUT8W iface, REFGUID rguid, LPCWSTR pszName, LPGUID pguidInstance) +{ + IDirectInput7W *This = IDirectInput7W_from_impl( impl_from_IDirectInput8W( iface ) ); + return IDirectInput2WImpl_FindDevice( This, rguid, pszName, pguidInstance ); } static HRESULT WINAPI IDirectInput8AImpl_EnumDevicesBySemantics( @@ -485,11 +677,22 @@ static HRESULT WINAPI IDirectInput8AImpl_EnumDevicesBySemantics( LPVOID pvRef, DWORD dwFlags ) { - IDirectInputImpl *This = (IDirectInputImpl *)iface; + IDirectInputImpl *This = impl_from_IDirectInput8A( iface ); - FIXME("(this=%p,%s,%p,%p,%p,%04lx): stub\n", This, ptszUserName, lpdiActionFormat, - lpCallback, pvRef, dwFlags); - return 0; + FIXME("(this=%p,%s,%p,%p,%p,%04x): stub\n", This, ptszUserName, lpdiActionFormat, + lpCallback, pvRef, dwFlags); +#define X(x) if (dwFlags & x) FIXME("\tdwFlags |= "#x"\n"); + X(DIEDBSFL_ATTACHEDONLY) + X(DIEDBSFL_THISUSER) + X(DIEDBSFL_FORCEFEEDBACK) + X(DIEDBSFL_AVAILABLEDEVICES) + X(DIEDBSFL_MULTIMICEKEYBOARDS) + X(DIEDBSFL_NONGAMINGDEVICES) +#undef X + + _dump_diactionformatA(lpdiActionFormat); + + return DI_OK; } static HRESULT WINAPI IDirectInput8WImpl_EnumDevicesBySemantics( @@ -498,9 +701,9 @@ static HRESULT WINAPI IDirectInput8WImpl_EnumDevicesBySemantics( LPVOID pvRef, DWORD dwFlags ) { - IDirectInputImpl *This = (IDirectInputImpl *)iface; + IDirectInputImpl *This = impl_from_IDirectInput8W( iface ); - FIXME("(this=%p,%s,%p,%p,%p,%04lx): stub\n", This, debugstr_w(ptszUserName), lpdiActionFormat, + FIXME("(this=%p,%s,%p,%p,%p,%04x): stub\n", This, debugstr_w(ptszUserName), lpdiActionFormat, lpCallback, pvRef, dwFlags); return 0; } @@ -510,9 +713,9 @@ static HRESULT WINAPI IDirectInput8AImpl_ConfigureDevices( LPDICONFIGUREDEVICESPARAMSA lpdiCDParams, DWORD dwFlags, LPVOID pvRefData ) { - IDirectInputImpl *This = (IDirectInputImpl *)iface; + IDirectInputImpl *This = impl_from_IDirectInput8A( iface ); - FIXME("(this=%p,%p,%p,%04lx,%p): stub\n", This, lpdiCallback, lpdiCDParams, + FIXME("(this=%p,%p,%p,%04x,%p): stub\n", This, lpdiCallback, lpdiCDParams, dwFlags, pvRefData); return 0; } @@ -522,93 +725,66 @@ static HRESULT WINAPI IDirectInput8WImpl_ConfigureDevices( LPDICONFIGUREDEVICESPARAMSW lpdiCDParams, DWORD dwFlags, LPVOID pvRefData ) { - IDirectInputImpl *This = (IDirectInputImpl *)iface; + IDirectInputImpl *This = impl_from_IDirectInput8W( iface ); - FIXME("(this=%p,%p,%p,%04lx,%p): stub\n", This, lpdiCallback, lpdiCDParams, + FIXME("(this=%p,%p,%p,%04x,%p): stub\n", This, lpdiCallback, lpdiCDParams, dwFlags, pvRefData); return 0; } -#if !defined(__STRICT_ANSI__) && defined(__GNUC__) -# define XCAST(fun) (typeof(ddi7avt.fun)) -#else -# define XCAST(fun) (void*) -#endif - static const IDirectInput7AVtbl ddi7avt = { - XCAST(QueryInterface)IDirectInputAImpl_QueryInterface, - XCAST(AddRef)IDirectInputAImpl_AddRef, - XCAST(Release)IDirectInputAImpl_Release, - XCAST(CreateDevice)IDirectInputAImpl_CreateDevice, - XCAST(EnumDevices)IDirectInputAImpl_EnumDevices, - XCAST(GetDeviceStatus)IDirectInputAImpl_GetDeviceStatus, - XCAST(RunControlPanel)IDirectInputAImpl_RunControlPanel, - XCAST(Initialize)IDirectInputAImpl_Initialize, - XCAST(FindDevice)IDirectInput2AImpl_FindDevice, - XCAST(CreateDeviceEx)IDirectInput7AImpl_CreateDeviceEx + IDirectInputAImpl_QueryInterface, + IDirectInputAImpl_AddRef, + IDirectInputAImpl_Release, + IDirectInputAImpl_CreateDevice, + IDirectInputAImpl_EnumDevices, + IDirectInputAImpl_GetDeviceStatus, + IDirectInputAImpl_RunControlPanel, + IDirectInputAImpl_Initialize, + IDirectInput2AImpl_FindDevice, + IDirectInput7AImpl_CreateDeviceEx }; -#undef XCAST -#if !defined(__STRICT_ANSI__) && defined(__GNUC__) -# define XCAST(fun) (typeof(ddi7wvt.fun)) -#else -# define XCAST(fun) (void*) -#endif - static const IDirectInput7WVtbl ddi7wvt = { - XCAST(QueryInterface)IDirectInputWImpl_QueryInterface, - XCAST(AddRef)IDirectInputAImpl_AddRef, - XCAST(Release)IDirectInputAImpl_Release, - XCAST(CreateDevice)IDirectInputWImpl_CreateDevice, - XCAST(EnumDevices)IDirectInputWImpl_EnumDevices, - XCAST(GetDeviceStatus)IDirectInputAImpl_GetDeviceStatus, - XCAST(RunControlPanel)IDirectInputAImpl_RunControlPanel, - XCAST(Initialize)IDirectInputAImpl_Initialize, - XCAST(FindDevice)IDirectInput2WImpl_FindDevice, - XCAST(CreateDeviceEx)IDirectInput7WImpl_CreateDeviceEx + IDirectInputWImpl_QueryInterface, + IDirectInputWImpl_AddRef, + IDirectInputWImpl_Release, + IDirectInputWImpl_CreateDevice, + IDirectInputWImpl_EnumDevices, + IDirectInputWImpl_GetDeviceStatus, + IDirectInputWImpl_RunControlPanel, + IDirectInputWImpl_Initialize, + IDirectInput2WImpl_FindDevice, + IDirectInput7WImpl_CreateDeviceEx }; -#undef XCAST - -#if !defined(__STRICT_ANSI__) && defined(__GNUC__) -# define XCAST(fun) (typeof(ddi8avt.fun)) -#else -# define XCAST(fun) (void*) -#endif static const IDirectInput8AVtbl ddi8avt = { - XCAST(QueryInterface)IDirectInput8AImpl_QueryInterface, - XCAST(AddRef)IDirectInputAImpl_AddRef, - XCAST(Release)IDirectInputAImpl_Release, - XCAST(CreateDevice)IDirectInputAImpl_CreateDevice, - XCAST(EnumDevices)IDirectInputAImpl_EnumDevices, - XCAST(GetDeviceStatus)IDirectInputAImpl_GetDeviceStatus, - XCAST(RunControlPanel)IDirectInputAImpl_RunControlPanel, - XCAST(Initialize)IDirectInputAImpl_Initialize, - XCAST(FindDevice)IDirectInput2AImpl_FindDevice, - XCAST(EnumDevicesBySemantics)IDirectInput8AImpl_EnumDevicesBySemantics, - XCAST(ConfigureDevices)IDirectInput8AImpl_ConfigureDevices + IDirectInput8AImpl_QueryInterface, + IDirectInput8AImpl_AddRef, + IDirectInput8AImpl_Release, + IDirectInput8AImpl_CreateDevice, + IDirectInput8AImpl_EnumDevices, + IDirectInput8AImpl_GetDeviceStatus, + IDirectInput8AImpl_RunControlPanel, + IDirectInput8AImpl_Initialize, + IDirectInput8AImpl_FindDevice, + IDirectInput8AImpl_EnumDevicesBySemantics, + IDirectInput8AImpl_ConfigureDevices }; -#undef XCAST -#if !defined(__STRICT_ANSI__) && defined(__GNUC__) -# define XCAST(fun) (typeof(ddi8wvt.fun)) -#else -# define XCAST(fun) (void*) -#endif static const IDirectInput8WVtbl ddi8wvt = { - XCAST(QueryInterface)IDirectInput8WImpl_QueryInterface, - XCAST(AddRef)IDirectInputAImpl_AddRef, - XCAST(Release)IDirectInputAImpl_Release, - XCAST(CreateDevice)IDirectInputWImpl_CreateDevice, - XCAST(EnumDevices)IDirectInputWImpl_EnumDevices, - XCAST(GetDeviceStatus)IDirectInputAImpl_GetDeviceStatus, - XCAST(RunControlPanel)IDirectInputAImpl_RunControlPanel, - XCAST(Initialize)IDirectInputAImpl_Initialize, - XCAST(FindDevice)IDirectInput2WImpl_FindDevice, - XCAST(EnumDevicesBySemantics)IDirectInput8WImpl_EnumDevicesBySemantics, - XCAST(ConfigureDevices)IDirectInput8WImpl_ConfigureDevices + IDirectInput8WImpl_QueryInterface, + IDirectInput8WImpl_AddRef, + IDirectInput8WImpl_Release, + IDirectInput8WImpl_CreateDevice, + IDirectInput8WImpl_EnumDevices, + IDirectInput8WImpl_GetDeviceStatus, + IDirectInput8WImpl_RunControlPanel, + IDirectInput8WImpl_Initialize, + IDirectInput8WImpl_FindDevice, + IDirectInput8WImpl_EnumDevicesBySemantics, + IDirectInput8WImpl_ConfigureDevices }; -#undef XCAST /******************************************************************************* * DirectInput ClassFactory @@ -644,7 +820,8 @@ static HRESULT WINAPI DICF_CreateInstance( IClassFactoryImpl *This = (IClassFactoryImpl *)iface; TRACE("(%p)->(%p,%s,%p)\n",This,pOuter,debugstr_guid(riid),ppobj); - if ( IsEqualGUID( &IID_IDirectInputA, riid ) || + if ( IsEqualGUID( &IID_IUnknown, riid ) || + IsEqualGUID( &IID_IDirectInputA, riid ) || IsEqualGUID( &IID_IDirectInputW, riid ) || IsEqualGUID( &IID_IDirectInput2A, riid ) || IsEqualGUID( &IID_IDirectInput2W, riid ) || @@ -656,7 +833,7 @@ static HRESULT WINAPI DICF_CreateInstance( return DirectInputCreateEx(0,0,riid,ppobj,pOuter); } - FIXME("(%p,%p,%s,%p) Interface not found!\n",This,pOuter,debugstr_guid(riid),ppobj); + FIXME("(%p,%p,%s,%p) Interface not found!\n",This,pOuter,debugstr_guid(riid),ppobj); return E_NOINTERFACE; } @@ -692,7 +869,7 @@ 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 ) ) { - *ppv = (LPVOID)&DINPUT_CF; + *ppv = &DINPUT_CF; IClassFactory_AddRef((IClassFactory*)*ppv); return S_OK; } @@ -700,3 +877,224 @@ HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) FIXME("(%s,%s,%p): no interface found.\n", debugstr_guid(rclsid), debugstr_guid(riid), ppv); return CLASS_E_CLASSNOTAVAILABLE; } + +/****************************************************************************** + * DInput hook thread + */ + +static LRESULT CALLBACK LL_hook_proc( int code, WPARAM wparam, LPARAM lparam ) +{ + IDirectInputImpl *dinput; + + if (code != HC_ACTION) return CallNextHookEx( 0, code, wparam, lparam ); + + EnterCriticalSection( &dinput_hook_crit ); + LIST_FOR_EACH_ENTRY( dinput, &direct_input_list, IDirectInputImpl, entry ) + { + IDirectInputDevice2AImpl *dev; + + EnterCriticalSection( &dinput->crit ); + LIST_FOR_EACH_ENTRY( dev, &dinput->devices_list, IDirectInputDevice2AImpl, entry ) + if (dev->acquired && dev->event_proc) + { + TRACE("calling %p->%p (%lx %lx)\n", dev, dev->event_proc, wparam, lparam); + dev->event_proc( (LPDIRECTINPUTDEVICE8A)dev, wparam, lparam ); + } + LeaveCriticalSection( &dinput->crit ); + } + LeaveCriticalSection( &dinput_hook_crit ); + + return CallNextHookEx( 0, code, wparam, lparam ); +} + +static LRESULT CALLBACK callwndproc_proc( int code, WPARAM wparam, LPARAM lparam ) +{ + CWPSTRUCT *msg = (CWPSTRUCT *)lparam; + IDirectInputImpl *dinput; + HWND foreground; + + if (code != HC_ACTION || (msg->message != WM_KILLFOCUS && + msg->message != WM_ACTIVATEAPP && msg->message != WM_ACTIVATE)) + return CallNextHookEx( 0, code, wparam, lparam ); + + foreground = GetForegroundWindow(); + + EnterCriticalSection( &dinput_hook_crit ); + + LIST_FOR_EACH_ENTRY( dinput, &direct_input_list, IDirectInputImpl, entry ) + { + IDirectInputDevice2AImpl *dev; + + EnterCriticalSection( &dinput->crit ); + LIST_FOR_EACH_ENTRY( dev, &dinput->devices_list, IDirectInputDevice2AImpl, entry ) + { + if (!dev->acquired) continue; + + if (msg->hwnd == dev->win && msg->hwnd != foreground) + { + TRACE( "%p window is not foreground - unacquiring %p\n", dev->win, dev ); + IDirectInputDevice_Unacquire( (LPDIRECTINPUTDEVICE8A)dev ); + } + } + LeaveCriticalSection( &dinput->crit ); + } + LeaveCriticalSection( &dinput_hook_crit ); + + return CallNextHookEx( 0, code, wparam, lparam ); +} + +static DWORD WINAPI hook_thread_proc(void *param) +{ + static HHOOK kbd_hook, mouse_hook; + MSG msg; + + /* Force creation of the message queue */ + PeekMessageW( &msg, 0, 0, 0, PM_NOREMOVE ); + SetEvent(*(LPHANDLE)param); + + while (GetMessageW( &msg, 0, 0, 0 )) + { + UINT kbd_cnt = 0, mice_cnt = 0; + + if (msg.message == WM_USER+0x10) + { + IDirectInputImpl *dinput; + + TRACE( "Processing hook change notification lp:%ld\n", msg.lParam ); + + if (!msg.wParam && !msg.lParam) + { + if (kbd_hook) UnhookWindowsHookEx( kbd_hook ); + if (mouse_hook) UnhookWindowsHookEx( mouse_hook ); + kbd_hook = mouse_hook = NULL; + break; + } + + EnterCriticalSection( &dinput_hook_crit ); + + /* Count acquired keyboards and mice*/ + LIST_FOR_EACH_ENTRY( dinput, &direct_input_list, IDirectInputImpl, entry ) + { + IDirectInputDevice2AImpl *dev; + + EnterCriticalSection( &dinput->crit ); + LIST_FOR_EACH_ENTRY( dev, &dinput->devices_list, IDirectInputDevice2AImpl, entry ) + { + if (!dev->acquired || !dev->event_proc) continue; + + if (IsEqualGUID( &dev->guid, &GUID_SysKeyboard ) || + IsEqualGUID( &dev->guid, &DInput_Wine_Keyboard_GUID )) + kbd_cnt++; + else + if (IsEqualGUID( &dev->guid, &GUID_SysMouse ) || + IsEqualGUID( &dev->guid, &DInput_Wine_Mouse_GUID )) + mice_cnt++; + } + LeaveCriticalSection( &dinput->crit ); + } + LeaveCriticalSection( &dinput_hook_crit ); + + if (kbd_cnt && !kbd_hook) + kbd_hook = SetWindowsHookExW( WH_KEYBOARD_LL, LL_hook_proc, DINPUT_instance, 0 ); + else if (!kbd_cnt && kbd_hook) + { + UnhookWindowsHookEx( kbd_hook ); + kbd_hook = NULL; + } + + if (mice_cnt && !mouse_hook) + mouse_hook = SetWindowsHookExW( WH_MOUSE_LL, LL_hook_proc, DINPUT_instance, 0 ); + else if (!mice_cnt && mouse_hook) + { + UnhookWindowsHookEx( mouse_hook ); + mouse_hook = NULL; + } + } + TranslateMessage(&msg); + DispatchMessageW(&msg); + } + + return 0; +} + +static DWORD hook_thread_id; + +static CRITICAL_SECTION_DEBUG dinput_critsect_debug = +{ + 0, 0, &dinput_hook_crit, + { &dinput_critsect_debug.ProcessLocksList, &dinput_critsect_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": dinput_hook_crit") } +}; +static CRITICAL_SECTION dinput_hook_crit = { &dinput_critsect_debug, -1, 0, 0, 0, 0 }; + +static BOOL check_hook_thread(void) +{ + static HANDLE hook_thread; + + EnterCriticalSection(&dinput_hook_crit); + + TRACE("IDirectInputs left: %d\n", list_count(&direct_input_list)); + if (!list_empty(&direct_input_list) && !hook_thread) + { + HANDLE event; + + event = CreateEventW(NULL, FALSE, FALSE, NULL); + hook_thread = CreateThread(NULL, 0, hook_thread_proc, &event, 0, &hook_thread_id); + if (event && hook_thread) + { + HANDLE handles[2]; + handles[0] = event; + handles[1] = hook_thread; + WaitForMultipleObjects(2, handles, FALSE, INFINITE); + } + LeaveCriticalSection(&dinput_hook_crit); + CloseHandle(event); + } + else if (list_empty(&direct_input_list) && hook_thread) + { + DWORD tid = hook_thread_id; + + hook_thread_id = 0; + PostThreadMessageW(tid, WM_USER+0x10, 0, 0); + LeaveCriticalSection(&dinput_hook_crit); + + /* wait for hook thread to exit */ + WaitForSingleObject(hook_thread, INFINITE); + CloseHandle(hook_thread); + hook_thread = NULL; + } + else + LeaveCriticalSection(&dinput_hook_crit); + + return hook_thread_id != 0; +} + +void check_dinput_hooks(LPDIRECTINPUTDEVICE8A iface) +{ + static HHOOK callwndproc_hook; + static ULONG foreground_cnt; + IDirectInputDevice2AImpl *dev = (IDirectInputDevice2AImpl *)iface; + + EnterCriticalSection(&dinput_hook_crit); + + if (dev->dwCoopLevel & DISCL_FOREGROUND) + { + if (dev->acquired) + foreground_cnt++; + else + foreground_cnt--; + } + + if (foreground_cnt && !callwndproc_hook) + callwndproc_hook = SetWindowsHookExW( WH_CALLWNDPROC, callwndproc_proc, + DINPUT_instance, GetCurrentThreadId() ); + else if (!foreground_cnt && callwndproc_hook) + { + UnhookWindowsHookEx( callwndproc_hook ); + callwndproc_hook = NULL; + } + + PostThreadMessageW( hook_thread_id, WM_USER+0x10, 1, 0 ); + + LeaveCriticalSection(&dinput_hook_crit); +} diff --git a/reactos/dll/directx/dinput/dinput_private.h b/reactos/dll/directx/dinput/dinput_private.h index 51385815e48..15783e2bb28 100644 --- a/reactos/dll/directx/dinput/dinput_private.h +++ b/reactos/dll/directx/dinput/dinput_private.h @@ -13,7 +13,7 @@ * * 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 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __WINE_DLLS_DINPUT_DINPUT_PRIVATE_H @@ -24,18 +24,25 @@ #include "windef.h" #include "winbase.h" #include "dinput.h" +#include "wine/list.h" /* Implementation specification */ typedef struct IDirectInputImpl IDirectInputImpl; struct IDirectInputImpl { - const void *lpVtbl; - LONG ref; + const IDirectInput7AVtbl *lpVtbl; + const IDirectInput7WVtbl *lpVtbl7w; + const IDirectInput8AVtbl *lpVtbl8a; + const IDirectInput8WVtbl *lpVtbl8w; - /* Used to have an unique sequence number for all the events */ - DWORD evsequence; + LONG ref; - DWORD dwVersion; + CRITICAL_SECTION crit; + struct list entry; /* entry into list of all IDirectInputs */ + + DWORD evsequence; /* unique sequence number for events */ + DWORD dwVersion; /* direct input version number */ + struct list devices_list; /* list of all created dinput devices */ }; /* Function called by all devices that Wine supports */ @@ -52,6 +59,9 @@ extern const struct dinput_device keyboard_device; extern const struct dinput_device joystick_linux_device; extern const struct dinput_device joystick_linuxinput_device; -extern HINSTANCE DINPUT_instance; +extern void check_dinput_hooks(LPDIRECTINPUTDEVICE8A); +typedef void (*DI_EVENT_PROC)(LPDIRECTINPUTDEVICE8A, WPARAM, LPARAM); + +extern void _dump_diactionformatA(LPDIACTIONFORMATA); #endif /* __WINE_DLLS_DINPUT_DINPUT_PRIVATE_H */ diff --git a/reactos/dll/directx/dinput/effect_linuxinput.c b/reactos/dll/directx/dinput/effect_linuxinput.c index 77531965f55..155d800d97a 100644 --- a/reactos/dll/directx/dinput/effect_linuxinput.c +++ b/reactos/dll/directx/dinput/effect_linuxinput.c @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include "config.h" @@ -27,6 +27,7 @@ #include #ifdef HAVE_LINUX_INPUT_H # include +# undef SW_MAX #endif #include #ifdef HAVE_UNISTD_H @@ -52,11 +53,10 @@ struct LinuxInputEffectImpl LONG ref; GUID guid; - /* Effect data */ - struct ff_effect effect; - - /* Parent device */ - int* fd; + struct ff_effect effect; /* Effect data */ + int gain; /* Effect gain */ + int* fd; /* Parent device */ + struct list *entry; /* Entry into the parent's list of effects */ }; @@ -91,7 +91,7 @@ static DWORD _typeFromGUID(REFGUID guid) /****************************************************************************** - * DirectInputEffect debug helpers + * DirectInputEffect debug helpers */ static void _dump_DIEFFECT_flags(DWORD dwFlags) @@ -112,59 +112,58 @@ static void _dump_DIEFFECT_flags(DWORD dwFlags) }; for (i = 0; i < (sizeof(flags) / sizeof(flags[0])); i++) if (flags[i].mask & dwFlags) - DPRINTF("%s ", flags[i].name); - DPRINTF("\n"); - } + TRACE("%s ", flags[i].name); + TRACE("\n"); + } } -static void _dump_DIENVELOPE(LPDIENVELOPE env) +static void _dump_DIENVELOPE(LPCDIENVELOPE env) { if (env->dwSize != sizeof(DIENVELOPE)) { - WARN("Non-standard DIENVELOPE structure size (%ld instead of %d).\n", - env->dwSize, sizeof(DIENVELOPE)); + WARN("Non-standard DIENVELOPE structure size %d.\n", env->dwSize); } - TRACE("Envelope has attack (level: %ld time: %ld), fade (level: %ld time: %ld)\n", + TRACE("Envelope has attack (level: %d time: %d), fade (level: %d time: %d)\n", env->dwAttackLevel, env->dwAttackTime, env->dwFadeLevel, env->dwFadeTime); +} + +static void _dump_DICONSTANTFORCE(LPCDICONSTANTFORCE frc) +{ + TRACE("Constant force has magnitude %d\n", frc->lMagnitude); } -static void _dump_DICONSTANTFORCE(LPDICONSTANTFORCE frc) +static void _dump_DIPERIODIC(LPCDIPERIODIC 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", + TRACE("Periodic force has magnitude %d, offset %d, phase %d, period %d\n", frc->dwMagnitude, frc->lOffset, frc->dwPhase, frc->dwPeriod); } -static void _dump_DIRAMPFORCE(LPDIRAMPFORCE frc) +static void _dump_DIRAMPFORCE(LPCDIRAMPFORCE frc) { - TRACE("Ramp force has start %ld, end %ld\n", + TRACE("Ramp force has start %d, end %d\n", frc->lStart, frc->lEnd); } -static void _dump_DICONDITION(LPDICONDITION frc) +static void _dump_DICONDITION(LPCDICONDITION frc) { - TRACE("Condition has offset %ld, pos/neg coefficients %ld and %ld, pos/neg saturations %ld and %ld, deadband %ld\n", + TRACE("Condition has offset %d, pos/neg coefficients %d and %d, pos/neg saturations %d and %d, deadband %d\n", frc->lOffset, frc->lPositiveCoefficient, frc->lNegativeCoefficient, frc->dwPositiveSaturation, frc->dwNegativeSaturation, frc->lDeadBand); } -static void _dump_DICUSTOMFORCE(LPDICUSTOMFORCE frc) +static void _dump_DICUSTOMFORCE(LPCDICUSTOMFORCE frc) { unsigned int i; - TRACE("Custom force uses %ld channels, sample period %ld. Has %ld samples at %p.\n", + TRACE("Custom force uses %d channels, sample period %d. Has %d 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"); + TRACE("Custom force data (time aligned, axes in order):\n"); for (i = 1; i <= frc->cSamples; ++i) { - DPRINTF("%ld ", frc->rglForceData[i]); + TRACE("%d ", frc->rglForceData[i]); if (i % frc->cChannels == 0) - DPRINTF("\n"); - } + TRACE("\n"); + } } } @@ -174,43 +173,42 @@ static void _dump_DIEFFECT(LPCDIEFFECT eff, REFGUID guid) DWORD type = _typeFromGUID(guid); TRACE("Dumping DIEFFECT structure:\n"); - TRACE(" - dwSize: %ld\n", eff->dwSize); + TRACE(" - dwSize: %d\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)); + WARN("Non-standard DIEFFECT structure size %d\n", eff->dwSize); } - TRACE(" - dwFlags: %ld\n", eff->dwFlags); + TRACE(" - dwFlags: %d\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); + _dump_DIEFFECT_flags(eff->dwFlags); + TRACE(" - dwDuration: %d\n", eff->dwDuration); + TRACE(" - dwGain: %d\n", eff->dwGain); + if (eff->dwGain > 10000) + WARN("dwGain is out of range (>10,000)\n"); + TRACE(" - dwTriggerButton: %d\n", eff->dwTriggerButton); + TRACE(" - dwTriggerRepeatInterval: %d\n", eff->dwTriggerRepeatInterval); + TRACE(" - cAxes: %d\n", eff->cAxes); TRACE(" - rgdwAxes: %p\n", eff->rgdwAxes); - if (TRACE_ON(dinput)) { - TRACE(" "); + if (TRACE_ON(dinput) && eff->rgdwAxes) { + TRACE(" "); for (i = 0; i < eff->cAxes; ++i) - DPRINTF("%ld ", eff->rgdwAxes[i]); - DPRINTF("\n"); + TRACE("%d ", eff->rgdwAxes[i]); + TRACE("\n"); } TRACE(" - rglDirection: %p\n", eff->rglDirection); TRACE(" - lpEnvelope: %p\n", eff->lpEnvelope); - TRACE(" - cbTypeSpecificParams: %ld\n", eff->cbTypeSpecificParams); + TRACE(" - cbTypeSpecificParams: %d\n", eff->cbTypeSpecificParams); TRACE(" - lpvTypeSpecificParams: %p\n", eff->lpvTypeSpecificParams); if (eff->dwSize > sizeof(DIEFFECT_DX5)) - TRACE(" - dwStartDelay: %ld\n", eff->dwStartDelay); + TRACE(" - dwStartDelay: %d\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"); + 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) { + } 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 { @@ -222,7 +220,7 @@ static void _dump_DIEFFECT(LPCDIEFFECT eff, REFGUID guid) } else { _dump_DIRAMPFORCE(eff->lpvTypeSpecificParams); } - } else if (type == DIEFT_CONDITION) { + } 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 { @@ -239,7 +237,7 @@ static void _dump_DIEFFECT(LPCDIEFFECT eff, REFGUID guid) /****************************************************************************** - * LinuxInputEffectImpl + * LinuxInputEffectImpl */ static ULONG WINAPI LinuxInputEffectImpl_AddRef( @@ -260,7 +258,7 @@ static HRESULT WINAPI LinuxInputEffectImpl_Download( if (errno == ENOMEM) { return DIERR_DEVICEFULL; } else { - FIXME("Could not upload effect. Assuming a disconnected device.\n"); + FIXME("Could not upload effect. Assuming a disconnected device %d \"%s\".\n", *This->fd, strerror(errno)); return DIERR_INPUTLOST; } } @@ -272,7 +270,7 @@ static HRESULT WINAPI LinuxInputEffectImpl_Escape( LPDIRECTINPUTEFFECT iface, LPDIEFFESCAPE pesc) { - WARN("(this=%p,%p): invalid: no hardware-specific escape codes in this" + WARN("(this=%p,%p): invalid: no hardware-specific escape codes in this" " driver!\n", iface, pesc); return DI_OK; @@ -287,7 +285,7 @@ static HRESULT WINAPI LinuxInputEffectImpl_GetEffectGuid( TRACE("(this=%p,%p)\n", This, pguid); pguid = &This->guid; - + return DI_OK; } @@ -314,7 +312,7 @@ static HRESULT WINAPI LinuxInputEffectImpl_GetParameters( { HRESULT diErr = DI_OK; LinuxInputEffectImpl *This = (LinuxInputEffectImpl *)iface; - TRACE("(this=%p,%p,%ld)\n", This, peff, dwFlags); + TRACE("(this=%p,%p,%d)\n", This, peff, dwFlags); /* Major conversion factors are: * times: millisecond (linux) -> microsecond (windows) (x * 1000) @@ -326,7 +324,7 @@ static HRESULT WINAPI LinuxInputEffectImpl_GetParameters( if (dwFlags & DIEP_AXES) { if (peff->cAxes < 2 /* linuxinput effects always use 2 axes, x and y */) diErr = DIERR_MOREDATA; - peff->cAxes = 2; + peff->cAxes = 2; if (diErr) return diErr; else { @@ -334,11 +332,11 @@ static HRESULT WINAPI LinuxInputEffectImpl_GetParameters( peff->rgdwAxes[1] = DIJOFS_Y; } } - + if (dwFlags & DIEP_DIRECTION) { if (peff->cAxes < 2) diErr = DIERR_MOREDATA; - peff->cAxes = 2; + peff->cAxes = 2; if (diErr) return diErr; else { @@ -373,7 +371,7 @@ static HRESULT WINAPI LinuxInputEffectImpl_GetParameters( peff->lpEnvelope = NULL; } else if (peff->lpEnvelope == NULL) { return DIERR_INVALIDPARAM; - } else { + } else { peff->lpEnvelope->dwAttackLevel = (env->attack_level / 33) * 10; peff->lpEnvelope->dwAttackTime = env->attack_length * 1000; peff->lpEnvelope->dwFadeLevel = (env->fade_level / 33) * 10; @@ -382,9 +380,7 @@ static HRESULT WINAPI LinuxInputEffectImpl_GetParameters( } if (dwFlags & DIEP_GAIN) { - /* the linux input ff driver apparently has no support - * for setting the device's gain. */ - peff->dwGain = DI_FFNOMINALMAX; + peff->dwGain = This->gain * 10000 / 0xFFFF; } if (dwFlags & DIEP_SAMPLEPERIOD) { @@ -407,14 +403,14 @@ static HRESULT WINAPI LinuxInputEffectImpl_GetParameters( } if (dwFlags & DIEP_TYPESPECIFICPARAMS) { - int expectedsize = 0; + DWORD 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 + } 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) { @@ -427,35 +423,35 @@ static HRESULT WINAPI LinuxInputEffectImpl_GetParameters( return diErr; else { if (This->effect.type == FF_PERIODIC) { - LPDIPERIODIC tsp = (LPDIPERIODIC)(peff->lpvTypeSpecificParams); + LPDIPERIODIC tsp = 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); + LPDICONSTANTFORCE tsp = 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 + } 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); + LPDICONDITION tsp = peff->lpvTypeSpecificParams; int i; for (i = 0; i < 2; ++i) { - tsp[i].lOffset = (This->effect.u.condition[i].center / 33) * 10; + 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].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); + LPDIRAMPFORCE tsp = peff->lpvTypeSpecificParams; tsp->lStart = (This->effect.u.ramp.start_level / 33) * 10; tsp->lEnd = (This->effect.u.ramp.end_level / 33) * 10; } } - } + } return diErr; } @@ -466,7 +462,7 @@ static HRESULT WINAPI LinuxInputEffectImpl_Initialize( DWORD dwVersion, REFGUID rguid) { - FIXME("(this=%p,%p,%ld,%s): stub!\n", + FIXME("(this=%p,%p,%d,%s): stub!\n", iface, hinst, dwVersion, debugstr_guid(rguid)); return DI_OK; @@ -500,7 +496,7 @@ static HRESULT WINAPI LinuxInputEffectImpl_Start( struct input_event event; LinuxInputEffectImpl* This = (LinuxInputEffectImpl*)iface; - TRACE("(this=%p,%ld,%ld)\n", This, dwIterations, dwFlags); + TRACE("(this=%p,%d,%d)\n", This, dwIterations, dwFlags); if (!(dwFlags & DIES_NODOWNLOAD)) { /* Download the effect if necessary */ @@ -516,6 +512,12 @@ static HRESULT WINAPI LinuxInputEffectImpl_Start( } event.type = EV_FF; + + event.code = FF_GAIN; + event.value = This->gain; + if (write(*(This->fd), &event, sizeof(event)) == -1) + FIXME("Failed setting gain. Error: %d \"%s\".\n", errno, strerror(errno)); + event.code = This->effect.id; event.value = dwIterations; if (write(*(This->fd), &event, sizeof(event)) == -1) { @@ -530,16 +532,16 @@ static HRESULT WINAPI LinuxInputEffectImpl_SetParameters( LPDIRECTINPUTEFFECT iface, LPCDIEFFECT peff, DWORD dwFlags) -{ - LinuxInputEffectImpl* This = (LinuxInputEffectImpl*)iface; +{ + LinuxInputEffectImpl* This = (LinuxInputEffectImpl*)iface; DWORD type = _typeFromGUID(&This->guid); HRESULT retval = DI_OK; - TRACE("(this=%p,%p,%ld)\n", This, peff, dwFlags); + TRACE("(this=%p,%p,%d)\n", This, peff, dwFlags); _dump_DIEFFECT(peff, &This->guid); - if ((dwFlags & !DIEP_NORESTART & !DIEP_NODOWNLOAD & !DIEP_START) == 0) { + 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 | @@ -556,7 +558,7 @@ static HRESULT WINAPI LinuxInputEffectImpl_SetParameters( /* 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). */ + * axis (left), linux has it along the y axis (down). */ if (dwFlags & DIEP_DIRECTION) { if (peff->cAxes == 1) { if (peff->dwFlags & DIEFF_CARTESIAN) { @@ -601,11 +603,11 @@ static HRESULT WINAPI LinuxInputEffectImpl_SetParameters( 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; + 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 */ + * note that length can never be zero, so we set it to something minuscule */ if (env) { env->attack_length = 0x10; env->attack_level = 0x7FFF; @@ -626,7 +628,7 @@ static HRESULT WINAPI LinuxInputEffectImpl_SetParameters( /* 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"); + This->gain = 0xFFFF * peff->dwGain / 10000; if (dwFlags & DIEP_SAMPLEPERIOD) TRACE("Sample period requested but no sample period functionality present.\n"); @@ -652,7 +654,7 @@ static HRESULT WINAPI LinuxInputEffectImpl_SetParameters( LPCDIPERIODIC tsp; if (peff->cbTypeSpecificParams != sizeof(DIPERIODIC)) return DIERR_INVALIDPARAM; - tsp = (LPCDIPERIODIC)(peff->lpvTypeSpecificParams); + tsp = 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) */ @@ -661,17 +663,17 @@ static HRESULT WINAPI LinuxInputEffectImpl_SetParameters( LPCDICONSTANTFORCE tsp; if (peff->cbTypeSpecificParams != sizeof(DICONSTANTFORCE)) return DIERR_INVALIDPARAM; - tsp = (LPCDICONSTANTFORCE)(peff->lpvTypeSpecificParams); - This->effect.u.constant.level = (tsp->lMagnitude / 10) * 32; + tsp = peff->lpvTypeSpecificParams; + This->effect.u.constant.level = (max(min(tsp->lMagnitude, 10000), -10000) / 10) * 32; } else if (type == DIEFT_RAMPFORCE) { LPCDIRAMPFORCE tsp; if (peff->cbTypeSpecificParams != sizeof(DIRAMPFORCE)) return DIERR_INVALIDPARAM; - tsp = (LPCDIRAMPFORCE)(peff->lpvTypeSpecificParams); + tsp = 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); + LPCDICONDITION tsp = 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. */ @@ -682,7 +684,7 @@ static HRESULT WINAPI LinuxInputEffectImpl_SetParameters( 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].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); @@ -702,7 +704,7 @@ static HRESULT WINAPI LinuxInputEffectImpl_SetParameters( return DIERR_INVALIDPARAM; } } else { - FIXME("Custom force types are not supported\n"); + FIXME("Custom force types are not supported\n"); return DIERR_INVALIDPARAM; } } @@ -719,20 +721,9 @@ static HRESULT WINAPI LinuxInputEffectImpl_SetParameters( 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) @@ -767,6 +758,22 @@ static HRESULT WINAPI LinuxInputEffectImpl_Unload( return DI_OK; } +static ULONG WINAPI LinuxInputEffectImpl_Release(LPDIRECTINPUTEFFECT iface) +{ + LinuxInputEffectImpl *This = (LinuxInputEffectImpl *)iface; + ULONG ref = InterlockedDecrement(&(This->ref)); + + if (ref == 0) + { + LinuxInputEffectImpl_Stop(iface); + LinuxInputEffectImpl_Unload(iface); + list_remove(This->entry); + HeapFree(GetProcessHeap(), 0, LIST_ENTRY(This->entry, effect_list_item, entry)); + HeapFree(GetProcessHeap(), 0, This); + } + return ref; +} + /****************************************************************************** * LinuxInputEffect */ @@ -774,20 +781,22 @@ static HRESULT WINAPI LinuxInputEffectImpl_Unload( HRESULT linuxinput_create_effect( int* fd, REFGUID rguid, + struct list *parent_list_entry, LPDIRECTINPUTEFFECT* peff) { - LinuxInputEffectImpl* newEffect = HeapAlloc(GetProcessHeap(), + 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->guid = *rguid; newEffect->fd = fd; + newEffect->gain = 0xFFFF; /* set the type. this cannot be changed over the effect's life. */ switch (type) { - case DIEFT_PERIODIC: + case DIEFT_PERIODIC: newEffect->effect.type = FF_PERIODIC; if (IsEqualGUID(rguid, &GUID_Sine)) { newEffect->effect.u.periodic.waveform = FF_SINE; @@ -801,13 +810,13 @@ HRESULT linuxinput_create_effect( newEffect->effect.u.periodic.waveform = FF_SAW_DOWN; } break; - case DIEFT_CONSTANTFORCE: + case DIEFT_CONSTANTFORCE: newEffect->effect.type = FF_CONSTANT; break; - case DIEFT_RAMPFORCE: + case DIEFT_RAMPFORCE: newEffect->effect.type = FF_RAMP; break; - case DIEFT_CONDITION: + case DIEFT_CONDITION: if (IsEqualGUID(rguid, &GUID_Spring)) { newEffect->effect.type = FF_SPRING; } else if (IsEqualGUID(rguid, &GUID_Friction)) { @@ -823,7 +832,7 @@ HRESULT linuxinput_create_effect( HeapFree(GetProcessHeap(), 0, newEffect); return DIERR_INVALIDPARAM; default: - FIXME("Unknown force type.\n"); + FIXME("Unknown force type 0x%x.\n", type); HeapFree(GetProcessHeap(), 0, newEffect); return DIERR_INVALIDPARAM; } @@ -831,9 +840,11 @@ HRESULT linuxinput_create_effect( /* mark as non-uploaded */ newEffect->effect.id = -1; - *peff = (LPDIRECTINPUTEFFECT)newEffect; + newEffect->entry = parent_list_entry; - TRACE("Creating linux input system effect (%p) with guid %s\n", + *peff = (LPDIRECTINPUTEFFECT)newEffect; + + TRACE("Creating linux input system effect (%p) with guid %s\n", *peff, _dump_dinput_GUID(rguid)); return DI_OK; @@ -846,29 +857,29 @@ HRESULT linuxinput_get_info_A( { DWORD type = _typeFromGUID(rguid); - TRACE("(%d, %s, %p) type=%ld\n", fd, _dump_dinput_GUID(rguid), info, type); + TRACE("(%d, %s, %p) type=%d\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; + + 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 + info->dwEffType |= DIEFT_DEADBAND | DIEFT_FFATTACK | DIEFT_FFFADE | DIEFT_POSNEGCOEFFICIENTS | DIEFT_POSNEGSATURATION - | DIEFT_SATURATION | DIEFT_STARTDELAY; + | 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)); + strcpy(info->tszName, _dump_dinput_GUID(rguid)); return DI_OK; } @@ -880,7 +891,7 @@ HRESULT linuxinput_get_info_W( { DWORD type = _typeFromGUID(rguid); - TRACE("(%d, %s, %p) type=%ld\n", fd, _dump_dinput_GUID(rguid), info, type); + TRACE("(%d, %s, %p) type=%d\n", fd, _dump_dinput_GUID(rguid), info, type); if (!info) return E_POINTER; @@ -895,15 +906,15 @@ HRESULT linuxinput_get_info_W( * ignore parameters they claim to support anyway */ info->dwEffType |= DIEFT_DEADBAND | DIEFT_FFATTACK | DIEFT_FFFADE | DIEFT_POSNEGCOEFFICIENTS | DIEFT_POSNEGSATURATION - | DIEFT_SATURATION | DIEFT_STARTDELAY; + | 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); + MultiByteToWideChar(CP_ACP, 0, _dump_dinput_GUID(rguid), -1, + info->tszName, MAX_PATH); return DI_OK; } diff --git a/reactos/dll/directx/dinput/joystick_linux.c b/reactos/dll/directx/dinput/joystick_linux.c index 6c494277861..e9b6916e432 100644 --- a/reactos/dll/directx/dinput/joystick_linux.c +++ b/reactos/dll/directx/dinput/joystick_linux.c @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ /* @@ -32,14 +32,13 @@ #include #include #include -#include #ifdef HAVE_UNISTD_H # include #endif #ifdef HAVE_SYS_TIME_H # include #endif -#include +#include #ifdef HAVE_SYS_IOCTL_H # include #endif @@ -52,6 +51,10 @@ #endif #ifdef HAVE_LINUX_JOYSTICK_H # include +# undef SW_MAX +#endif +#ifdef HAVE_SYS_POLL_H +# include #endif #include "wine/debug.h" @@ -69,89 +72,100 @@ WINE_DEFAULT_DEBUG_CHANNEL(dinput); #ifdef HAVE_LINUX_22_JOYSTICK_API -#define JOYDEV "/dev/js" - -typedef struct { - LONG lMin; - LONG lMax; - LONG lDeadZone; - LONG lSaturation; -} ObjProps; - -typedef struct { - LONG lX; - LONG lY; -} POV; +#define JOYDEV_NEW "/dev/input/js" +#define JOYDEV_OLD "/dev/js" typedef struct JoystickImpl JoystickImpl; static const IDirectInputDevice8AVtbl JoystickAvt; static const IDirectInputDevice8WVtbl JoystickWvt; struct JoystickImpl { - const void *lpVtbl; - LONG ref; - GUID guid; - char dev[32]; + struct IDirectInputDevice2AImpl base; - /* The 'parent' DInput */ - IDirectInputImpl *dinput; + char dev[32]; /* joystick private */ int joyfd; DIJOYSTATE2 js; /* wine data */ - LPDIDATAFORMAT user_df; /* user defined format */ - DataFormat *transform; /* wine to user format converter */ - int *offsets; /* object offsets */ ObjProps *props; - HANDLE hEvent; - LPDIDEVICEOBJECTDATA data_queue; - int queue_head, queue_tail, queue_len; - BOOL acquired; char *name; DIDEVCAPS devcaps; LONG deadzone; int *axis_map; int axes; - int buttons; - POV povs[4]; - CRITICAL_SECTION crit; - BOOL overflow; + POINTL povs[4]; }; -static GUID DInput_Wine_Joystick_GUID = { /* 9e573ed9-7734-11d2-8d4a-23903fb6bdf7 */ +static const GUID DInput_Wine_Joystick_GUID = { /* 9e573ed9-7734-11d2-8d4a-23903fb6bdf7 */ 0x9e573ed9, 0x7734, 0x11d2, {0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf7} }; -static void _dump_DIDEVCAPS(LPDIDEVCAPS lpDIDevCaps) +static void _dump_DIDEVCAPS(const DIDEVCAPS *lpDIDevCaps) { - TRACE("dwSize: %ld\n", lpDIDevCaps->dwSize); - TRACE("dwFlags: %08lx\n",lpDIDevCaps->dwFlags); - TRACE("dwDevType: %08lx %s\n", lpDIDevCaps->dwDevType, + TRACE("dwSize: %d\n", lpDIDevCaps->dwSize); + TRACE("dwFlags: %08x\n", lpDIDevCaps->dwFlags); + TRACE("dwDevType: %08x %s\n", lpDIDevCaps->dwDevType, lpDIDevCaps->dwDevType == DIDEVTYPE_DEVICE ? "DIDEVTYPE_DEVICE" : lpDIDevCaps->dwDevType == DIDEVTYPE_DEVICE ? "DIDEVTYPE_DEVICE" : lpDIDevCaps->dwDevType == DIDEVTYPE_MOUSE ? "DIDEVTYPE_MOUSE" : lpDIDevCaps->dwDevType == DIDEVTYPE_KEYBOARD ? "DIDEVTYPE_KEYBOARD" : lpDIDevCaps->dwDevType == DIDEVTYPE_JOYSTICK ? "DIDEVTYPE_JOYSTICK" : lpDIDevCaps->dwDevType == DIDEVTYPE_HID ? "DIDEVTYPE_HID" : "UNKNOWN"); - TRACE("dwAxes: %ld\n",lpDIDevCaps->dwAxes); - TRACE("dwButtons: %ld\n",lpDIDevCaps->dwButtons); - TRACE("dwPOVs: %ld\n",lpDIDevCaps->dwPOVs); + TRACE("dwAxes: %d\n", lpDIDevCaps->dwAxes); + TRACE("dwButtons: %d\n", lpDIDevCaps->dwButtons); + TRACE("dwPOVs: %d\n", lpDIDevCaps->dwPOVs); if (lpDIDevCaps->dwSize > sizeof(DIDEVCAPS_DX3)) { - TRACE("dwFFSamplePeriod: %ld\n",lpDIDevCaps->dwFFSamplePeriod); - TRACE("dwFFMinTimeResolution: %ld\n",lpDIDevCaps->dwFFMinTimeResolution); - TRACE("dwFirmwareRevision: %ld\n",lpDIDevCaps->dwFirmwareRevision); - TRACE("dwHardwareRevision: %ld\n",lpDIDevCaps->dwHardwareRevision); - TRACE("dwFFDriverVersion: %ld\n",lpDIDevCaps->dwFFDriverVersion); + TRACE("dwFFSamplePeriod: %d\n", lpDIDevCaps->dwFFSamplePeriod); + TRACE("dwFFMinTimeResolution: %d\n", lpDIDevCaps->dwFFMinTimeResolution); + TRACE("dwFirmwareRevision: %d\n", lpDIDevCaps->dwFirmwareRevision); + TRACE("dwHardwareRevision: %d\n", lpDIDevCaps->dwHardwareRevision); + TRACE("dwFFDriverVersion: %d\n", lpDIDevCaps->dwFFDriverVersion); } } +#define MAX_JOYSTICKS 64 +static INT joystick_devices_count = -1; +static LPSTR joystick_devices[MAX_JOYSTICKS]; + +static INT find_joystick_devices(void) +{ + INT i; + + if (joystick_devices_count != -1) return joystick_devices_count; + + joystick_devices_count = 0; + for (i = 0; i < MAX_JOYSTICKS; i++) + { + CHAR device_name[MAX_PATH], *str; + INT len; + int fd; + + len = sprintf(device_name, "%s%d", JOYDEV_NEW, i) + 1; + if ((fd = open(device_name, O_RDONLY)) < 0) + { + len = sprintf(device_name, "%s%d", JOYDEV_OLD, i) + 1; + if ((fd = open(device_name, O_RDONLY)) < 0) continue; + } + + close(fd); + + if (!(str = HeapAlloc(GetProcessHeap(), 0, len))) break; + memcpy(str, device_name, len); + + joystick_devices[joystick_devices_count++] = str; + } + + return joystick_devices_count; +} + static BOOL joydev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, DWORD version, int id) { int fd = -1; - char dev[32]; + + if (id >= find_joystick_devices()) return FALSE; if (dwFlags & DIEDFL_FORCEFEEDBACK) { WARN("force feedback not supported\n"); @@ -162,9 +176,9 @@ static BOOL joydev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTAN ((dwDevType == DIDEVTYPE_JOYSTICK) && (version > 0x0300 && version < 0x0800)) || (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800))) { /* check whether we have a joystick */ - sprintf(dev, "%s%d", JOYDEV, id); - if ((fd = open(dev,O_RDONLY)) < 0) { - WARN("open(%s,O_RDONLY) failed: %s\n", dev, strerror(errno)); + if ((fd = open(joystick_devices[id], O_RDONLY)) < 0) + { + WARN("open(%s, O_RDONLY) failed: %s\n", joystick_devices[id], strerror(errno)); return FALSE; } @@ -180,7 +194,7 @@ static BOOL joydev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTAN sprintf(lpddi->tszInstanceName, "Joystick %d", id); #if defined(JSIOCGNAME) if (ioctl(fd,JSIOCGNAME(sizeof(lpddi->tszProductName)),lpddi->tszProductName) < 0) { - WARN("ioctl(%s,JSIOCGNAME) failed: %s\n", dev, strerror(errno)); + WARN("ioctl(%s,JSIOCGNAME) failed: %s\n", joystick_devices[id], strerror(errno)); strcpy(lpddi->tszProductName, "Wine Joystick"); } #else @@ -189,7 +203,7 @@ static BOOL joydev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTAN lpddi->guidFFDriver = GUID_NULL; close(fd); - TRACE("Enumerating the linux Joystick device: %s (%s)\n", dev, lpddi->tszProductName); + TRACE("Enumerating the linux Joystick device: %s (%s)\n", joystick_devices[id], lpddi->tszProductName); return TRUE; } @@ -200,9 +214,10 @@ static BOOL joydev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTAN { int fd = -1; char name[MAX_PATH]; - char dev[32]; char friendly[32]; + if (id >= find_joystick_devices()) return FALSE; + if (dwFlags & DIEDFL_FORCEFEEDBACK) { WARN("force feedback not supported\n"); return FALSE; @@ -212,9 +227,9 @@ static BOOL joydev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTAN ((dwDevType == DIDEVTYPE_JOYSTICK) && (version > 0x0300 && version < 0x0800)) || (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800))) { /* check whether we have a joystick */ - sprintf(dev, "%s%d", JOYDEV, id); - if ((fd = open(dev,O_RDONLY)) < 0) { - WARN("open(%s,O_RDONLY) failed: %s\n", dev, strerror(errno)); + if ((fd = open(joystick_devices[id], O_RDONLY)) < 0) + { + WARN("open(%s,O_RDONLY) failed: %s\n", joystick_devices[id], strerror(errno)); return FALSE; } @@ -231,7 +246,7 @@ static BOOL joydev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTAN MultiByteToWideChar(CP_ACP, 0, friendly, -1, lpddi->tszInstanceName, MAX_PATH); #if defined(JSIOCGNAME) if (ioctl(fd,JSIOCGNAME(sizeof(name)),name) < 0) { - WARN("ioctl(%s,JSIOCGNAME) failed: %s\n", dev, strerror(errno)); + WARN("ioctl(%s, JSIOCGNAME) failed: %s\n", joystick_devices[id], strerror(errno)); strcpy(name, "Wine Joystick"); } #else @@ -240,29 +255,13 @@ static BOOL joydev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTAN MultiByteToWideChar(CP_ACP, 0, name, -1, lpddi->tszProductName, MAX_PATH); lpddi->guidFFDriver = GUID_NULL; close(fd); - TRACE("Enumerating the linux Joystick device: %s (%s)\n",dev,name); + TRACE("Enumerating the linux Joystick device: %s (%s)\n", joystick_devices[id], name); return TRUE; } return FALSE; } -/* - * Get a config key from either the app-specific or the default config - */ - -inline static DWORD get_config_key( HKEY defkey, HKEY appkey, const char *name, - char *buffer, DWORD size ) -{ - if (appkey && !RegQueryValueExA( appkey, name, 0, NULL, (LPBYTE)buffer, &size )) - return 0; - - if (defkey && !RegQueryValueExA( defkey, name, 0, NULL, (LPBYTE)buffer, &size )) - return 0; - - return ERROR_FILE_NOT_FOUND; -} - /* * Setup the dinput options. */ @@ -270,111 +269,103 @@ inline static DWORD get_config_key( HKEY defkey, HKEY appkey, const char *name, static HRESULT setup_dinput_options(JoystickImpl * device) { char buffer[MAX_PATH+16]; - HKEY hkey, appkey = 0; - DWORD len; + HKEY hkey, appkey; + int tokens = 0; + int axis = 0; + int pov = 0; buffer[MAX_PATH]='\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; - /* @@ 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 ); - } - } + get_app_key(&hkey, &appkey); /* get options */ if (!get_config_key( hkey, appkey, "DefaultDeadZone", buffer, MAX_PATH )) { device->deadzone = atoi(buffer); - TRACE("setting default deadzone to: \"%s\" %ld\n", buffer, device->deadzone); + TRACE("setting default deadzone to: \"%s\" %d\n", buffer, device->deadzone); } + device->axis_map = HeapAlloc(GetProcessHeap(), 0, device->axes * sizeof(int)); + if (!device->axis_map) return DIERR_OUTOFMEMORY; + if (!get_config_key( hkey, appkey, device->name, buffer, MAX_PATH )) { - int tokens = 0; - int axis = 0; - int pov = 0; + static const char *axis_names[] = {"X", "Y", "Z", "Rx", "Ry", "Rz", + "Slider1", "Slider2", + "POV1", "POV2", "POV3", "POV4"}; const char *delim = ","; char * ptr; TRACE("\"%s\" = \"%s\"\n", device->name, buffer); - device->axis_map = HeapAlloc(GetProcessHeap(), 0, device->axes * sizeof(int)); - if (device->axis_map == 0) - return DIERR_OUTOFMEMORY; - if ((ptr = strtok(buffer, delim)) != NULL) { do { - if (strcmp(ptr, "X") == 0) { - device->axis_map[tokens] = 0; - axis++; - } else if (strcmp(ptr, "Y") == 0) { - device->axis_map[tokens] = 1; - axis++; - } else if (strcmp(ptr, "Z") == 0) { - device->axis_map[tokens] = 2; - axis++; - } else if (strcmp(ptr, "Rx") == 0) { - device->axis_map[tokens] = 3; - axis++; - } else if (strcmp(ptr, "Ry") == 0) { - device->axis_map[tokens] = 4; - axis++; - } else if (strcmp(ptr, "Rz") == 0) { - device->axis_map[tokens] = 5; - axis++; - } else if (strcmp(ptr, "Slider1") == 0) { - device->axis_map[tokens] = 6; - axis++; - } else if (strcmp(ptr, "Slider2") == 0) { - device->axis_map[tokens] = 7; - axis++; - } else if (strcmp(ptr, "POV1") == 0) { - device->axis_map[tokens++] = 8; - device->axis_map[tokens] = 8; - pov++; - } else if (strcmp(ptr, "POV2") == 0) { - device->axis_map[tokens++] = 9; - device->axis_map[tokens] = 9; - pov++; - } else if (strcmp(ptr, "POV3") == 0) { - device->axis_map[tokens++] = 10; - device->axis_map[tokens] = 10; - pov++; - } else if (strcmp(ptr, "POV4") == 0) { - device->axis_map[tokens++] = 11; - device->axis_map[tokens] = 11; - pov++; - } else { - ERR("invalid joystick axis type: %s\n", ptr); - device->axis_map[tokens] = tokens; - axis++; + int i; + + for (i = 0; i < sizeof(axis_names) / sizeof(axis_names[0]); i++) + if (!strcmp(ptr, axis_names[i])) + { + if (!strncmp(ptr, "POV", 3)) + { + if (pov >= 4) + { + WARN("Only 4 POVs supported - ignoring extra\n"); + i = -1; + } + else + { + /* Pov takes two axes */ + device->axis_map[tokens++] = i; + pov++; + } + } + else + { + if (axis >= 8) + { + FIXME("Only 8 Axes supported - ignoring extra\n"); + i = -1; + } + else + axis++; + } + break; + } + + if (i == sizeof(axis_names) / sizeof(axis_names[0])) + { + ERR("invalid joystick axis type: \"%s\"\n", ptr); + i = -1; } + device->axis_map[tokens] = i; tokens++; } while ((ptr = strtok(NULL, delim)) != NULL); - if (tokens != device->devcaps.dwAxes) { + if (tokens != device->axes) { ERR("not all joystick axes mapped: %d axes(%d,%d), %d arguments\n", device->axes, axis, pov,tokens); while (tokens < device->axes) { - device->axis_map[tokens] = tokens; + device->axis_map[tokens] = -1; tokens++; } } } - - device->devcaps.dwAxes = axis; - device->devcaps.dwPOVs = pov; } + else + { + for (tokens = 0; tokens < device->axes; tokens++) + { + if (tokens < 8) + device->axis_map[tokens] = axis++; + else if (tokens < 16) + { + device->axis_map[tokens++] = 8 + pov; + device->axis_map[tokens ] = 8 + pov++; + } + else + device->axis_map[tokens] = -1; + } + } + device->devcaps.dwAxes = axis; + device->devcaps.dwPOVs = pov; if (appkey) RegCloseKey( appkey ); @@ -385,63 +376,17 @@ static HRESULT setup_dinput_options(JoystickImpl * device) return DI_OK; } -static void calculate_ids(JoystickImpl* device) -{ - int i; - int axis = 0; - int button = 0; - int pov = 0; - int axis_base; - int pov_base; - int button_base; - - /* Make two passes over the format. The first counts the number - * for each type and the second sets the id */ - for (i = 0; i < device->user_df->dwNumObjs; i++) { - if (DIDFT_GETTYPE(device->user_df->rgodf[i].dwType) & DIDFT_AXIS) - axis++; - else if (DIDFT_GETTYPE(device->user_df->rgodf[i].dwType) & DIDFT_POV) - pov++; - else if (DIDFT_GETTYPE(device->user_df->rgodf[i].dwType) & DIDFT_BUTTON) - button++; - } - - axis_base = 0; - pov_base = axis; - button_base = axis + pov; - - axis = 0; - button = 0; - pov = 0; - - for (i = 0; i < device->user_df->dwNumObjs; i++) { - DWORD type = 0; - if (DIDFT_GETTYPE(device->user_df->rgodf[i].dwType) & DIDFT_AXIS) { - axis++; - type = DIDFT_GETTYPE(device->user_df->rgodf[i].dwType) | - DIDFT_MAKEINSTANCE(axis + axis_base); - TRACE("axis type = 0x%08lx\n", type); - } else if (DIDFT_GETTYPE(device->user_df->rgodf[i].dwType) & DIDFT_POV) { - pov++; - type = DIDFT_GETTYPE(device->user_df->rgodf[i].dwType) | - DIDFT_MAKEINSTANCE(pov + pov_base); - TRACE("POV type = 0x%08lx\n", type); - } else if (DIDFT_GETTYPE(device->user_df->rgodf[i].dwType) & DIDFT_BUTTON) { - button++; - type = DIDFT_GETTYPE(device->user_df->rgodf[i].dwType) | - DIDFT_MAKEINSTANCE(button + button_base); - TRACE("button type = 0x%08lx\n", type); - } - device->user_df->rgodf[i].dwType = type; - } -} - -static HRESULT alloc_device(REFGUID rguid, const void *jvt, IDirectInputImpl *dinput, LPDIRECTINPUTDEVICEA* pdev) +static HRESULT alloc_device(REFGUID rguid, const void *jvt, IDirectInputImpl *dinput, + LPDIRECTINPUTDEVICEA* pdev, unsigned short index) { DWORD i; JoystickImpl* newDevice; char name[MAX_PATH]; HRESULT hr; + LPDIDATAFORMAT df = NULL; + int idx = 0; + + TRACE("%s %p %p %p %hu\n", debugstr_guid(rguid), jvt, dinput, pdev, index); newDevice = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(JoystickImpl)); if (newDevice == 0) { @@ -450,10 +395,10 @@ static HRESULT alloc_device(REFGUID rguid, const void *jvt, IDirectInputImpl *di return DIERR_OUTOFMEMORY; } - sprintf(newDevice->dev, "%s%d", JOYDEV, rguid->Data3); - - if ((newDevice->joyfd = open(newDevice->dev,O_RDONLY)) < 0) { - WARN("open(%s,O_RDONLY) failed: %s\n", newDevice->dev, strerror(errno)); + if (!lstrcpynA(newDevice->dev, joystick_devices[index], sizeof(newDevice->dev)) || + (newDevice->joyfd = open(newDevice->dev, O_RDONLY)) < 0) + { + WARN("open(%s, O_RDONLY) failed: %s\n", newDevice->dev, strerror(errno)); HeapFree(GetProcessHeap(), 0, newDevice); return DIERR_DEVICENOTREG; } @@ -479,53 +424,62 @@ static HRESULT alloc_device(REFGUID rguid, const void *jvt, IDirectInputImpl *di } #endif #ifdef JSIOCGBUTTONS - if (ioctl(newDevice->joyfd,JSIOCGBUTTONS,&newDevice->buttons) < 0) { + if (ioctl(newDevice->joyfd, JSIOCGBUTTONS, &newDevice->devcaps.dwButtons) < 0) { WARN("ioctl(%s,JSIOCGBUTTONS) failed: %s, defauting to 2\n", newDevice->dev, strerror(errno)); - newDevice->buttons = 2; + newDevice->devcaps.dwButtons = 2; } #endif - newDevice->lpVtbl = jvt; - newDevice->ref = 1; - newDevice->dinput = dinput; - newDevice->acquired = FALSE; - newDevice->overflow = FALSE; - CopyMemory(&(newDevice->guid),rguid,sizeof(*rguid)); + if (newDevice->devcaps.dwButtons > 128) + { + WARN("Can't support %d buttons. Clamping down to 128\n", newDevice->devcaps.dwButtons); + newDevice->devcaps.dwButtons = 128; + } + + newDevice->base.lpVtbl = jvt; + newDevice->base.ref = 1; + newDevice->base.dinput = dinput; + newDevice->base.guid = *rguid; + InitializeCriticalSection(&newDevice->base.crit); + newDevice->base.crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": JoystickImpl*->base.crit"); /* setup_dinput_options may change these */ - newDevice->deadzone = 5000; - newDevice->devcaps.dwButtons = newDevice->buttons; - newDevice->devcaps.dwAxes = newDevice->axes; - newDevice->devcaps.dwPOVs = 0; + newDevice->deadzone = 0; /* do any user specified configuration */ hr = setup_dinput_options(newDevice); if (hr != DI_OK) goto FAILED1; - if (newDevice->axis_map == 0) { - newDevice->axis_map = HeapAlloc(GetProcessHeap(), 0, newDevice->axes * sizeof(int)); - if (newDevice->axis_map == 0) - goto FAILED; + /* Create copy of default data format */ + if (!(df = HeapAlloc(GetProcessHeap(), 0, c_dfDIJoystick2.dwSize))) goto FAILED; + memcpy(df, &c_dfDIJoystick2, c_dfDIJoystick2.dwSize); - for (i = 0; i < newDevice->axes; i++) - newDevice->axis_map[i] = i; + df->dwNumObjs = newDevice->devcaps.dwAxes + newDevice->devcaps.dwPOVs + newDevice->devcaps.dwButtons; + if (!(df->rgodf = HeapAlloc(GetProcessHeap(), 0, df->dwNumObjs * df->dwObjSize))) goto FAILED; + + for (i = 0; i < newDevice->axes; i++) + { + int wine_obj = newDevice->axis_map[i]; + + if (wine_obj < 0) continue; + + memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[wine_obj], df->dwObjSize); + if (wine_obj < 8) + df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(wine_obj) | DIDFT_ABSAXIS; + else + { + df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(wine_obj - 8) | DIDFT_POV; + i++; /* POV takes 2 axes */ + } } - - /* wine uses DIJOYSTATE2 as it's internal format so copy - * the already defined format c_dfDIJoystick2 */ - newDevice->user_df = HeapAlloc(GetProcessHeap(),0,c_dfDIJoystick2.dwSize); - if (newDevice->user_df == 0) - goto FAILED; - - CopyMemory(newDevice->user_df, &c_dfDIJoystick2, c_dfDIJoystick2.dwSize); - - /* copy default objects */ - newDevice->user_df->rgodf = HeapAlloc(GetProcessHeap(),0,c_dfDIJoystick2.dwNumObjs*c_dfDIJoystick2.dwObjSize); - if (newDevice->user_df->rgodf == 0) - goto FAILED; - - CopyMemory(newDevice->user_df->rgodf,c_dfDIJoystick2.rgodf,c_dfDIJoystick2.dwNumObjs*c_dfDIJoystick2.dwObjSize); + for (i = 0; i < newDevice->devcaps.dwButtons; i++) + { + memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[i + 12], df->dwObjSize); + df->rgodf[idx ].pguid = &GUID_Button; + df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(i) | DIDFT_PSHBUTTON; + } + newDevice->base.data_format.wine_df = df; /* create default properties */ newDevice->props = HeapAlloc(GetProcessHeap(),0,c_dfDIJoystick2.dwNumObjs*sizeof(ObjProps)); @@ -534,29 +488,19 @@ static HRESULT alloc_device(REFGUID rguid, const void *jvt, IDirectInputImpl *di /* initialize default properties */ for (i = 0; i < c_dfDIJoystick2.dwNumObjs; i++) { + newDevice->props[i].lDevMin = -32767; + newDevice->props[i].lDevMax = +32767; newDevice->props[i].lMin = 0; newDevice->props[i].lMax = 0xffff; newDevice->props[i].lDeadZone = newDevice->deadzone; /* % * 1000 */ newDevice->props[i].lSaturation = 0; } - /* create an offsets array */ - newDevice->offsets = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,c_dfDIJoystick2.dwNumObjs*sizeof(int)); - if (newDevice->offsets == 0) - goto FAILED; - - /* create the default transform filter */ - newDevice->transform = create_DataFormat(&c_dfDIJoystick2, newDevice->user_df, newDevice->offsets); - - calculate_ids(newDevice); - - IDirectInputDevice_AddRef((LPDIRECTINPUTDEVICE8A)newDevice->dinput); - InitializeCriticalSection(&(newDevice->crit)); - newDevice->crit.DebugInfo->Spare[0] = (DWORD_PTR)"DINPUT_Mouse"; + IDirectInput_AddRef((LPDIRECTINPUTDEVICE8A)newDevice->base.dinput); newDevice->devcaps.dwSize = sizeof(newDevice->devcaps); newDevice->devcaps.dwFlags = DIDC_ATTACHED; - if (newDevice->dinput->dwVersion >= 0x0800) + if (newDevice->base.dinput->dwVersion >= 0x0800) newDevice->devcaps.dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8); else newDevice->devcaps.dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8); @@ -567,9 +511,9 @@ static HRESULT alloc_device(REFGUID rguid, const void *jvt, IDirectInputImpl *di newDevice->devcaps.dwFFDriverVersion = 0; if (TRACE_ON(dinput)) { - _dump_DIDATAFORMAT(newDevice->user_df); + _dump_DIDATAFORMAT(newDevice->base.data_format.wine_df); for (i = 0; i < (newDevice->axes); i++) - TRACE("axis_map[%ld] = %d\n", i, newDevice->axis_map[i]); + TRACE("axis_map[%d] = %d\n", i, newDevice->axis_map[i]); _dump_DIDEVCAPS(&newDevice->devcaps); } @@ -580,18 +524,22 @@ static HRESULT alloc_device(REFGUID rguid, const void *jvt, IDirectInputImpl *di FAILED: hr = DIERR_OUTOFMEMORY; FAILED1: + if (df) HeapFree(GetProcessHeap(), 0, df->rgodf); + HeapFree(GetProcessHeap(), 0, df); + release_DataFormat(&newDevice->base.data_format); HeapFree(GetProcessHeap(),0,newDevice->axis_map); HeapFree(GetProcessHeap(),0,newDevice->name); HeapFree(GetProcessHeap(),0,newDevice->props); - HeapFree(GetProcessHeap(),0,newDevice->user_df->rgodf); - HeapFree(GetProcessHeap(),0,newDevice->user_df); HeapFree(GetProcessHeap(),0,newDevice); *pdev = 0; return hr; } -static BOOL IsJoystickGUID(REFGUID guid) +/****************************************************************************** + * get_joystick_index : Get the joystick index from a given GUID + */ +static unsigned short get_joystick_index(REFGUID guid) { GUID wine_joystick = DInput_Wine_Joystick_GUID; GUID dev_guid = *guid; @@ -599,53 +547,71 @@ static BOOL IsJoystickGUID(REFGUID guid) wine_joystick.Data3 = 0; dev_guid.Data3 = 0; - return IsEqualGUID(&wine_joystick, &dev_guid); + /* for the standard joystick GUID use index 0 */ + if(IsEqualGUID(&GUID_Joystick,guid)) return 0; + + /* for the wine joystick GUIDs use the index stored in Data3 */ + if(IsEqualGUID(&wine_joystick, &dev_guid)) return guid->Data3; + + return MAX_JOYSTICKS; } static HRESULT joydev_create_deviceA(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEA* pdev) { - if ((IsEqualGUID(&GUID_Joystick,rguid)) || - (IsJoystickGUID(rguid))) { - if ((riid == NULL) || - IsEqualGUID(&IID_IDirectInputDeviceA,riid) || - IsEqualGUID(&IID_IDirectInputDevice2A,riid) || - IsEqualGUID(&IID_IDirectInputDevice7A,riid) || - IsEqualGUID(&IID_IDirectInputDevice8A,riid)) { - return alloc_device(rguid, &JoystickAvt, dinput, pdev); - } else { - WARN("no interface\n"); - *pdev = 0; - return DIERR_NOINTERFACE; - } - } + unsigned short index; - WARN("invalid device GUID\n"); - *pdev = 0; - return DIERR_DEVICENOTREG; + TRACE("%p %s %p %p\n",dinput, debugstr_guid(rguid), riid, pdev); + find_joystick_devices(); + *pdev = NULL; + + if ((index = get_joystick_index(rguid)) < MAX_JOYSTICKS && + joystick_devices_count && index < joystick_devices_count) + { + if ((riid == NULL) || + IsEqualGUID(&IID_IDirectInputDeviceA, riid) || + IsEqualGUID(&IID_IDirectInputDevice2A, riid) || + IsEqualGUID(&IID_IDirectInputDevice7A, riid) || + IsEqualGUID(&IID_IDirectInputDevice8A, riid)) + { + return alloc_device(rguid, &JoystickAvt, dinput, pdev, index); + } + + WARN("no interface\n"); + return DIERR_NOINTERFACE; + } + + return DIERR_DEVICENOTREG; } static HRESULT joydev_create_deviceW(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEW* pdev) { - if ((IsEqualGUID(&GUID_Joystick,rguid)) || - (IsJoystickGUID(rguid))) { - if ((riid == NULL) || - IsEqualGUID(&IID_IDirectInputDeviceW,riid) || - IsEqualGUID(&IID_IDirectInputDevice2W,riid) || - IsEqualGUID(&IID_IDirectInputDevice7W,riid) || - IsEqualGUID(&IID_IDirectInputDevice8W,riid)) { - return alloc_device(rguid, &JoystickWvt, dinput, (LPDIRECTINPUTDEVICEA *)pdev); - } else { - WARN("no interface\n"); - *pdev = 0; - return DIERR_NOINTERFACE; - } - } + unsigned short index; - WARN("invalid device GUID\n"); - *pdev = 0; - return DIERR_DEVICENOTREG; + TRACE("%p %s %p %p\n",dinput, debugstr_guid(rguid), riid, pdev); + find_joystick_devices(); + *pdev = NULL; + + if ((index = get_joystick_index(rguid)) < MAX_JOYSTICKS && + joystick_devices_count && index < joystick_devices_count) + { + if ((riid == NULL) || + IsEqualGUID(&IID_IDirectInputDeviceW, riid) || + IsEqualGUID(&IID_IDirectInputDevice2W, riid) || + IsEqualGUID(&IID_IDirectInputDevice7W, riid) || + IsEqualGUID(&IID_IDirectInputDevice8W, riid)) + { + return alloc_device(rguid, &JoystickWvt, dinput, (LPDIRECTINPUTDEVICEA *)pdev, index); + } + WARN("no interface\n"); + return DIERR_NOINTERFACE; + } + + WARN("invalid device GUID %s\n",debugstr_guid(rguid)); + return DIERR_DEVICENOTREG; } +#undef MAX_JOYSTICKS + const struct dinput_device joystick_linux_device = { "Wine Linux joystick driver", joydev_enum_deviceA, @@ -654,125 +620,6 @@ const struct dinput_device joystick_linux_device = { joydev_create_deviceW }; -/****************************************************************************** - * Joystick - */ -static ULONG WINAPI JoystickAImpl_Release(LPDIRECTINPUTDEVICE8A iface) -{ - JoystickImpl *This = (JoystickImpl *)iface; - ULONG ref; - - ref = InterlockedDecrement((&This->ref)); - if (ref) - return ref; - - /* Free the device name */ - HeapFree(GetProcessHeap(),0,This->name); - - /* Free the axis map */ - HeapFree(GetProcessHeap(),0,This->axis_map); - - /* Free the data queue */ - HeapFree(GetProcessHeap(),0,This->data_queue); - - /* Free the DataFormat */ - HeapFree(GetProcessHeap(), 0, This->user_df->rgodf); - HeapFree(GetProcessHeap(), 0, This->user_df); - - /* Free the properties */ - HeapFree(GetProcessHeap(), 0, This->props); - - /* Free the offsets array */ - HeapFree(GetProcessHeap(),0,This->offsets); - - /* release the data transform filter */ - release_DataFormat(This->transform); - - This->crit.DebugInfo->Spare[0] = 0; - DeleteCriticalSection(&(This->crit)); - IDirectInputDevice_Release((LPDIRECTINPUTDEVICE8A)This->dinput); - - HeapFree(GetProcessHeap(),0,This); - return 0; -} - -/****************************************************************************** - * SetDataFormat : the application can choose the format of the data - * the device driver sends back with GetDeviceState. - */ -static HRESULT WINAPI JoystickAImpl_SetDataFormat( - LPDIRECTINPUTDEVICE8A iface, - LPCDIDATAFORMAT df) -{ - JoystickImpl *This = (JoystickImpl *)iface; - unsigned int i; - LPDIDATAFORMAT new_df = 0; - LPDIOBJECTDATAFORMAT new_rgodf = 0; - ObjProps * new_props = 0; - - TRACE("(%p,%p)\n",This,df); - - if (df == NULL) { - WARN("invalid pointer\n"); - return E_POINTER; - } - - if (df->dwSize != sizeof(*df)) { - WARN("invalid argument\n"); - return DIERR_INVALIDPARAM; - } - - if (This->acquired) { - WARN("acquired\n"); - return DIERR_ACQUIRED; - } - - if (TRACE_ON(dinput)) - _dump_DIDATAFORMAT(df); - - /* Store the new data format */ - new_df = HeapAlloc(GetProcessHeap(),0,df->dwSize); - if (new_df == 0) - goto FAILED; - - new_rgodf = HeapAlloc(GetProcessHeap(),0,df->dwNumObjs*df->dwObjSize); - if (new_rgodf == 0) - goto FAILED; - - new_props = HeapAlloc(GetProcessHeap(),0,df->dwNumObjs*sizeof(ObjProps)); - if (new_props == 0) - goto FAILED; - - HeapFree(GetProcessHeap(),0,This->user_df); - HeapFree(GetProcessHeap(),0,This->user_df->rgodf); - HeapFree(GetProcessHeap(),0,This->props); - release_DataFormat(This->transform); - - This->user_df = new_df; - CopyMemory(This->user_df, df, df->dwSize); - This->user_df->rgodf = new_rgodf; - CopyMemory(This->user_df->rgodf,df->rgodf,df->dwNumObjs*df->dwObjSize); - This->props = new_props; - for (i = 0; i < df->dwNumObjs; i++) { - This->props[i].lMin = 0; - This->props[i].lMax = 0xffff; - This->props[i].lDeadZone = 1000; - This->props[i].lSaturation = 0; - } - This->transform = create_DataFormat(&c_dfDIJoystick2, This->user_df, This->offsets); - - calculate_ids(This); - - return DI_OK; - -FAILED: - WARN("out of memory\n"); - HeapFree(GetProcessHeap(),0,new_props); - HeapFree(GetProcessHeap(),0,new_rgodf); - HeapFree(GetProcessHeap(),0,new_df); - return DIERR_OUTOFMEMORY; -} - /****************************************************************************** * Acquire : gets exclusive control of the joystick */ @@ -782,7 +629,7 @@ static HRESULT WINAPI JoystickAImpl_Acquire(LPDIRECTINPUTDEVICE8A iface) TRACE("(%p)\n",This); - if (This->acquired) { + if (This->base.acquired) { WARN("already acquired\n"); return S_FALSE; } @@ -798,7 +645,7 @@ static HRESULT WINAPI JoystickAImpl_Acquire(LPDIRECTINPUTDEVICE8A iface) } } - This->acquired = TRUE; + This->base.acquired = 1; return DI_OK; } @@ -809,88 +656,24 @@ static HRESULT WINAPI JoystickAImpl_Acquire(LPDIRECTINPUTDEVICE8A iface) static HRESULT WINAPI JoystickAImpl_Unacquire(LPDIRECTINPUTDEVICE8A iface) { JoystickImpl *This = (JoystickImpl *)iface; + HRESULT res; TRACE("(%p)\n",This); - if (!This->acquired) { - WARN("not acquired\n"); - return DIERR_NOTACQUIRED; - } + if ((res = IDirectInputDevice2AImpl_Unacquire(iface)) != DI_OK) return res; if (This->joyfd!=-1) { TRACE("closing joystick device\n"); close(This->joyfd); This->joyfd = -1; - This->acquired = FALSE; return DI_OK; } - This->acquired = FALSE; - return DI_NOEFFECT; } -static LONG map_axis(JoystickImpl * This, short val, short index) -{ - double fval = val; - double fmin = This->props[index].lMin; - double fmax = This->props[index].lMax; - double fret; - - fret = (((fval + 32767.0) * (fmax - fmin)) / (32767.0*2.0)) + fmin; - - if (fret >= 0.0) - fret += 0.5; - else - fret -= 0.5; - - return fret; -} - -/* convert wine format offset to user format object index */ -static int offset_to_object(JoystickImpl *This, int offset) -{ - int i; - - for (i = 0; i < This->user_df->dwNumObjs; i++) { - if (This->user_df->rgodf[i].dwOfs == offset) - return i; - } - - return -1; -} - -static LONG calculate_pov(JoystickImpl *This, int index) -{ - if (This->povs[index].lX < 16384) { - if (This->povs[index].lY < 16384) - This->js.rgdwPOV[index] = 31500; - else if (This->povs[index].lY > 49150) - This->js.rgdwPOV[index] = 22500; - else - This->js.rgdwPOV[index] = 27000; - } else if (This->povs[index].lX > 49150) { - if (This->povs[index].lY < 16384) - This->js.rgdwPOV[index] = 4500; - else if (This->povs[index].lY > 49150) - This->js.rgdwPOV[index] = 13500; - else - This->js.rgdwPOV[index] = 9000; - } else { - if (This->povs[index].lY < 16384) - This->js.rgdwPOV[index] = 0; - else if (This->povs[index].lY > 49150) - This->js.rgdwPOV[index] = 18000; - else - This->js.rgdwPOV[index] = -1; - } - - return This->js.rgdwPOV[index]; -} - static void joy_polldev(JoystickImpl *This) { - struct timeval tv; - fd_set readfds; + struct pollfd plfd; struct js_event jse; TRACE("(%p)\n", This); @@ -898,10 +681,14 @@ static void joy_polldev(JoystickImpl *This) { WARN("no device\n"); return; } - while (1) { - memset(&tv,0,sizeof(tv)); - FD_ZERO(&readfds);FD_SET(This->joyfd,&readfds); - if (1>select(This->joyfd+1,&readfds,NULL,NULL,&tv)) + while (1) + { + LONG value; + int inst_id = -1; + + plfd.fd = This->joyfd; + plfd.events = POLLIN; + if (poll(&plfd,1,0) != 1) return; /* we have one event, so we can read */ if (sizeof(jse)!=read(This->joyfd,&jse,sizeof(jse))) { @@ -909,82 +696,52 @@ static void joy_polldev(JoystickImpl *This) { } TRACE("js_event: type 0x%x, number %d, value %d\n", jse.type,jse.number,jse.value); - if (jse.type & JS_EVENT_BUTTON) { - int offset = This->offsets[jse.number + 12]; - int value = jse.value?0x80:0x00; + if (jse.type & JS_EVENT_BUTTON) + { + if (jse.number >= This->devcaps.dwButtons) return; - This->js.rgbButtons[jse.number] = value; - GEN_EVENT(offset,value,jse.time,(This->dinput->evsequence)++); - } else if (jse.type & JS_EVENT_AXIS) { + inst_id = DIDFT_MAKEINSTANCE(jse.number) | DIDFT_PSHBUTTON; + This->js.rgbButtons[jse.number] = value = jse.value ? 0x80 : 0x00; + } + else if (jse.type & JS_EVENT_AXIS) + { int number = This->axis_map[jse.number]; /* wine format object index */ - if (number < 12) { - int offset = This->offsets[number]; - int index = offset_to_object(This, offset); - LONG value = map_axis(This, jse.value, index); - /* FIXME do deadzone and saturation here */ + if (number < 0) return; + inst_id = DIDFT_MAKEINSTANCE(number) | (number < 8 ? DIDFT_ABSAXIS : DIDFT_POV); + value = joystick_map_axis(&This->props[id_to_object(This->base.data_format.wine_df, inst_id)], jse.value); - TRACE("changing axis %d => %d\n", jse.number, number); - switch (number) { - case 0: - This->js.lX = value; - break; - case 1: - This->js.lY = value; - break; - case 2: - This->js.lZ = value; - break; - case 3: - This->js.lRx = value; - break; - case 4: - This->js.lRy = value; - break; - case 5: - This->js.lRz = value; - break; - case 6: - This->js.rglSlider[0] = value; - break; - case 7: - This->js.rglSlider[1] = value; - break; - case 8: - /* FIXME don't go off array */ - if (This->axis_map[jse.number + 1] == number) - This->povs[0].lX = value; - else if (This->axis_map[jse.number - 1] == number) - This->povs[0].lY = value; - value = calculate_pov(This, 0); - break; - case 9: - if (This->axis_map[jse.number + 1] == number) - This->povs[1].lX = value; - else if (This->axis_map[jse.number - 1] == number) - This->povs[1].lY = value; - value = calculate_pov(This, 1); - break; - case 10: - if (This->axis_map[jse.number + 1] == number) - This->povs[2].lX = value; - else if (This->axis_map[jse.number - 1] == number) - This->povs[2].lY = value; - value = calculate_pov(This, 2); - break; - case 11: - if (This->axis_map[jse.number + 1] == number) - This->povs[3].lX = value; - else if (This->axis_map[jse.number - 1] == number) - This->povs[3].lY = value; - value = calculate_pov(This, 3); + TRACE("changing axis %d => %d\n", jse.number, number); + switch (number) + { + case 0: This->js.lX = value; break; + case 1: This->js.lY = value; break; + case 2: This->js.lZ = value; break; + case 3: This->js.lRx = value; break; + case 4: This->js.lRy = value; break; + case 5: This->js.lRz = value; break; + case 6: This->js.rglSlider[0] = value; break; + case 7: This->js.rglSlider[1] = value; break; + case 8: case 9: case 10: case 11: + { + int idx = number - 8; + + if (jse.number % 2) + This->povs[idx].y = jse.value; + else + This->povs[idx].x = jse.value; + + This->js.rgdwPOV[idx] = value = joystick_map_pov(&This->povs[idx]); break; } - - GEN_EVENT(offset,value,jse.time,(This->dinput->evsequence)++); - } else - WARN("axis %d not supported\n", number); + default: + WARN("axis %d not supported\n", number); + } } + if (inst_id >= 0) + queue_event((LPDIRECTINPUTDEVICE8A)This, + id_to_offset(&This->base.data_format, inst_id), + value, jse.time, This->base.dinput->evsequence++); } } @@ -999,9 +756,9 @@ static HRESULT WINAPI JoystickAImpl_GetDeviceState( { JoystickImpl *This = (JoystickImpl *)iface; - TRACE("(%p,0x%08lx,%p)\n",This,len,ptr); + TRACE("(%p,0x%08x,%p)\n", This, len, ptr); - if (!This->acquired) { + if (!This->base.acquired) { WARN("not acquired\n"); return DIERR_NOTACQUIRED; } @@ -1010,105 +767,11 @@ static HRESULT WINAPI JoystickAImpl_GetDeviceState( joy_polldev(This); /* convert and copy data to user supplied buffer */ - fill_DataFormat(ptr, &This->js, This->transform); + fill_DataFormat(ptr, len, &This->js, &This->base.data_format); return DI_OK; } -/****************************************************************************** - * GetDeviceData : gets buffered input data. - */ -static HRESULT WINAPI JoystickAImpl_GetDeviceData( - LPDIRECTINPUTDEVICE8A iface, - DWORD dodsize, - LPDIDEVICEOBJECTDATA dod, - LPDWORD entries, - DWORD flags) -{ - JoystickImpl *This = (JoystickImpl *)iface; - DWORD len; - int nqtail; - HRESULT hr = DI_OK; - - TRACE("(%p)->(dods=%ld,entries=%ld,fl=0x%08lx)\n",This,dodsize,*entries,flags); - - if (!This->acquired) { - WARN("not acquired\n"); - return DIERR_NOTACQUIRED; - } - - EnterCriticalSection(&(This->crit)); - - joy_polldev(This); - - len = ((This->queue_head < This->queue_tail) ? This->queue_len : 0) - + (This->queue_head - This->queue_tail); - if (len > *entries) - len = *entries; - - if (dod == NULL) { - if (len) - TRACE("Application discarding %ld event(s).\n", len); - - *entries = len; - nqtail = This->queue_tail + len; - while (nqtail >= This->queue_len) - nqtail -= This->queue_len; - } else { - if (dodsize < sizeof(DIDEVICEOBJECTDATA_DX3)) { - ERR("Wrong structure size !\n"); - LeaveCriticalSection(&(This->crit)); - return DIERR_INVALIDPARAM; - } - - if (len) - TRACE("Application retrieving %ld event(s).\n", len); - - *entries = 0; - nqtail = This->queue_tail; - while (len) { - /* Copy the buffered data into the application queue */ - memcpy((char *)dod + *entries * dodsize, This->data_queue + nqtail, dodsize); - /* Advance position */ - nqtail++; - if (nqtail >= This->queue_len) - nqtail -= This->queue_len; - (*entries)++; - len--; - } - } - - if (This->overflow) { - hr = DI_BUFFEROVERFLOW; - if (!(flags & DIGDD_PEEK)) { - This->overflow = FALSE; - } - } - - if (!(flags & DIGDD_PEEK)) - This->queue_tail = nqtail; - - LeaveCriticalSection(&(This->crit)); - - return hr; -} - -static int find_property(JoystickImpl * This, LPCDIPROPHEADER ph) -{ - int i; - if (ph->dwHow == DIPH_BYOFFSET) { - return offset_to_object(This, ph->dwObj); - } else if (ph->dwHow == DIPH_BYID) { - for (i = 0; i < This->user_df->dwNumObjs; i++) { - if ((This->user_df->rgodf[i].dwType & 0x00ffffff) == (ph->dwObj & 0x00ffffff)) { - return i; - } - } - } - - return -1; -} - /****************************************************************************** * SetProperty : change input device properties */ @@ -1118,7 +781,7 @@ static HRESULT WINAPI JoystickAImpl_SetProperty( LPCDIPROPHEADER ph) { JoystickImpl *This = (JoystickImpl *)iface; - int i; + DWORD i; TRACE("(%p,%s,%p)\n",This,debugstr_guid(rguid),ph); @@ -1132,29 +795,18 @@ static HRESULT WINAPI JoystickAImpl_SetProperty( if (!HIWORD(rguid)) { switch (LOWORD(rguid)) { - case (DWORD) DIPROP_BUFFERSIZE: { - LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph; - TRACE("buffersize = %ld\n",pd->dwData); - if (This->data_queue) - This->data_queue = HeapReAlloc(GetProcessHeap(),0, This->data_queue, pd->dwData * sizeof(DIDEVICEOBJECTDATA)); - else - This->data_queue = HeapAlloc(GetProcessHeap(),0, pd->dwData * sizeof(DIDEVICEOBJECTDATA)); - This->queue_head = 0; - This->queue_tail = 0; - This->queue_len = pd->dwData; - break; - } - case (DWORD)DIPROP_RANGE: { - LPCDIPROPRANGE pr = (LPCDIPROPRANGE)ph; + case (DWORD_PTR)DIPROP_RANGE: { + LPCDIPROPRANGE pr = (LPCDIPROPRANGE)ph; if (ph->dwHow == DIPH_DEVICE) { - TRACE("proprange(%ld,%ld) all\n",pr->lMin,pr->lMax); - for (i = 0; i < This->user_df->dwNumObjs; i++) { + TRACE("proprange(%d,%d) all\n", pr->lMin, pr->lMax); + for (i = 0; i < This->base.data_format.wine_df->dwNumObjs; i++) { This->props[i].lMin = pr->lMin; This->props[i].lMax = pr->lMax; } } else { - int obj = find_property(This, ph); - TRACE("proprange(%ld,%ld) obj=%d\n",pr->lMin,pr->lMax,obj); + int obj = find_property(&This->base.data_format, ph); + + TRACE("proprange(%d,%d) obj=%d\n", pr->lMin, pr->lMax, obj); if (obj >= 0) { This->props[obj].lMin = pr->lMin; This->props[obj].lMax = pr->lMax; @@ -1163,15 +815,16 @@ static HRESULT WINAPI JoystickAImpl_SetProperty( } break; } - case (DWORD)DIPROP_DEADZONE: { - LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph; + case (DWORD_PTR)DIPROP_DEADZONE: { + LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph; if (ph->dwHow == DIPH_DEVICE) { - TRACE("deadzone(%ld) all\n",pd->dwData); - for (i = 0; i < This->user_df->dwNumObjs; i++) + TRACE("deadzone(%d) all\n", pd->dwData); + for (i = 0; i < This->base.data_format.wine_df->dwNumObjs; i++) This->props[i].lDeadZone = pd->dwData; } else { - int obj = find_property(This, ph); - TRACE("deadzone(%ld) obj=%d\n",pd->dwData,obj); + int obj = find_property(&This->base.data_format, ph); + + TRACE("deadzone(%d) obj=%d\n", pd->dwData, obj); if (obj >= 0) { This->props[obj].lDeadZone = pd->dwData; return DI_OK; @@ -1179,15 +832,16 @@ static HRESULT WINAPI JoystickAImpl_SetProperty( } break; } - case (DWORD)DIPROP_SATURATION: { - LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph; + case (DWORD_PTR)DIPROP_SATURATION: { + LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph; if (ph->dwHow == DIPH_DEVICE) { - TRACE("saturation(%ld) all\n",pd->dwData); - for (i = 0; i < This->user_df->dwNumObjs; i++) + TRACE("saturation(%d) all\n", pd->dwData); + for (i = 0; i < This->base.data_format.wine_df->dwNumObjs; i++) This->props[i].lSaturation = pd->dwData; } else { - int obj = find_property(This, ph); - TRACE("saturation(%ld) obj=%d\n",pd->dwData,obj); + int obj = find_property(&This->base.data_format, ph); + + TRACE("saturation(%d) obj=%d\n", pd->dwData, obj); if (obj >= 0) { This->props[obj].lSaturation = pd->dwData; return DI_OK; @@ -1196,27 +850,13 @@ static HRESULT WINAPI JoystickAImpl_SetProperty( break; } default: - FIXME("Unknown type %p (%s)\n",rguid,debugstr_guid(rguid)); - break; + return IDirectInputDevice2AImpl_SetProperty(iface, rguid, ph); } } return DI_OK; } -/****************************************************************************** - * SetEventNotification : specifies event to be sent on state change - */ -static HRESULT WINAPI JoystickAImpl_SetEventNotification( - LPDIRECTINPUTDEVICE8A iface, HANDLE hnd -) { - JoystickImpl *This = (JoystickImpl *)iface; - - TRACE("(this=%p,%p)\n",This,hnd); - This->hEvent = hnd; - return DI_OK; -} - static HRESULT WINAPI JoystickAImpl_GetCapabilities( LPDIRECTINPUTDEVICE8A iface, LPDIDEVCAPS lpDIDevCaps) @@ -1253,7 +893,7 @@ static HRESULT WINAPI JoystickAImpl_Poll(LPDIRECTINPUTDEVICE8A iface) TRACE("(%p)\n",This); - if (!This->acquired) { + if (!This->base.acquired) { WARN("not acquired\n"); return DIERR_NOTACQUIRED; } @@ -1262,155 +902,6 @@ static HRESULT WINAPI JoystickAImpl_Poll(LPDIRECTINPUTDEVICE8A iface) return DI_OK; } -/****************************************************************************** - * EnumObjects : enumerate the different buttons and axis... - */ -static HRESULT WINAPI JoystickAImpl_EnumObjects( - LPDIRECTINPUTDEVICE8A iface, - LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback, - LPVOID lpvRef, - DWORD dwFlags) -{ - JoystickImpl *This = (JoystickImpl *)iface; - DIDEVICEOBJECTINSTANCEA ddoi; - BYTE i; - int user_offset; - int user_object; - - TRACE("(this=%p,%p,%p,%08lx)\n", This, lpCallback, lpvRef, dwFlags); - if (TRACE_ON(dinput)) { - TRACE(" - flags = "); - _dump_EnumObjects_flags(dwFlags); - TRACE("\n"); - } - - /* Only the fields till dwFFMaxForce are relevant */ - ddoi.dwSize = FIELD_OFFSET(DIDEVICEOBJECTINSTANCEA, dwFFMaxForce); - - /* For the joystick, do as is done in the GetCapabilities function */ - if ((dwFlags == DIDFT_ALL) || - (dwFlags & DIDFT_AXIS) || - (dwFlags & DIDFT_POV)) { - int pov[4] = { 0, 0, 0, 0 }; - int axes = 0; - int povs = 0; - - for (i = 0; i < This->axes; i++) { - int wine_obj = This->axis_map[i]; - BOOL skip = FALSE; - - switch (wine_obj) { - case 0: - ddoi.guidType = GUID_XAxis; - break; - case 1: - ddoi.guidType = GUID_YAxis; - break; - case 2: - ddoi.guidType = GUID_ZAxis; - break; - case 3: - ddoi.guidType = GUID_RxAxis; - break; - case 4: - ddoi.guidType = GUID_RyAxis; - break; - case 5: - ddoi.guidType = GUID_RzAxis; - break; - case 6: - ddoi.guidType = GUID_Slider; - break; - case 7: - ddoi.guidType = GUID_Slider; - break; - case 8: - pov[0]++; - ddoi.guidType = GUID_POV; - break; - case 9: - pov[1]++; - ddoi.guidType = GUID_POV; - break; - case 10: - pov[2]++; - ddoi.guidType = GUID_POV; - break; - case 11: - pov[3]++; - ddoi.guidType = GUID_POV; - break; - default: - ddoi.guidType = GUID_Unknown; - } - if (wine_obj < 8) { - user_offset = This->offsets[wine_obj]; /* get user offset from wine index */ - user_object = offset_to_object(This, user_offset); - - ddoi.dwType = This->user_df->rgodf[user_object].dwType & 0x00ffffff; - ddoi.dwOfs = This->user_df->rgodf[user_object].dwOfs; - sprintf(ddoi.tszName, "Axis %d", axes); - axes++; - } else { - if (pov[wine_obj - 8] < 2) { - user_offset = This->offsets[wine_obj]; /* get user offset from wine index */ - user_object = offset_to_object(This, user_offset); - - ddoi.dwType = This->user_df->rgodf[user_object].dwType & 0x00ffffff; - ddoi.dwOfs = This->user_df->rgodf[user_object].dwOfs; - sprintf(ddoi.tszName, "POV %d", povs); - povs++; - } else - skip = TRUE; - } - if (!skip) { - _dump_OBJECTINSTANCEA(&ddoi); - if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) - return DI_OK; - } - } - } - - if ((dwFlags == DIDFT_ALL) || - (dwFlags & DIDFT_BUTTON)) { - - /* The DInput SDK says that GUID_Button is only for mouse buttons but well... */ - ddoi.guidType = GUID_Button; - - for (i = 0; i < This->buttons; i++) { - user_offset = This->offsets[i + 12]; /* get user offset from wine index */ - user_object = offset_to_object(This, user_offset); - ddoi.guidType = GUID_Button; - ddoi.dwType = This->user_df->rgodf[user_object].dwType & 0x00ffffff; - ddoi.dwOfs = This->user_df->rgodf[user_object].dwOfs; - sprintf(ddoi.tszName, "Button %d", i); - _dump_OBJECTINSTANCEA(&ddoi); - if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK; - } - } - - return DI_OK; -} - -/****************************************************************************** - * EnumObjects : enumerate the different buttons and axis... - */ -static HRESULT WINAPI JoystickWImpl_EnumObjects( - LPDIRECTINPUTDEVICE8W iface, - LPDIENUMDEVICEOBJECTSCALLBACKW lpCallback, - LPVOID lpvRef, - DWORD dwFlags) -{ - JoystickImpl *This = (JoystickImpl *)iface; - - device_enumobjects_AtoWcb_data data; - - data.lpCallBack = lpCallback; - data.lpvRef = lpvRef; - - return JoystickAImpl_EnumObjects((LPDIRECTINPUTDEVICE8A) This, (LPDIENUMDEVICEOBJECTSCALLBACKA) DIEnumDevicesCallbackAtoW, (LPVOID) &data, dwFlags); -} - /****************************************************************************** * GetProperty : get input device properties */ @@ -1428,48 +919,44 @@ static HRESULT WINAPI JoystickAImpl_GetProperty( if (!HIWORD(rguid)) { switch (LOWORD(rguid)) { - case (DWORD) DIPROP_BUFFERSIZE: { - LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph; - TRACE(" return buffersize = %d\n",This->queue_len); - pd->dwData = This->queue_len; - break; - } - case (DWORD) DIPROP_RANGE: { - LPDIPROPRANGE pr = (LPDIPROPRANGE) pdiph; - int obj = find_property(This, pdiph); + case (DWORD_PTR) DIPROP_RANGE: { + LPDIPROPRANGE pr = (LPDIPROPRANGE)pdiph; + int obj = find_property(&This->base.data_format, pdiph); + /* The app is querying the current range of the axis * return the lMin and lMax values */ if (obj >= 0) { pr->lMin = This->props[obj].lMin; pr->lMax = This->props[obj].lMax; - TRACE("range(%ld, %ld) obj=%d\n", pr->lMin, pr->lMax, obj); + TRACE("range(%d, %d) obj=%d\n", pr->lMin, pr->lMax, obj); return DI_OK; } break; } - case (DWORD) DIPROP_DEADZONE: { - LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph; - int obj = find_property(This, pdiph); + case (DWORD_PTR) DIPROP_DEADZONE: { + LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph; + int obj = find_property(&This->base.data_format, pdiph); + if (obj >= 0) { pd->dwData = This->props[obj].lDeadZone; - TRACE("deadzone(%ld) obj=%d\n", pd->dwData, obj); + TRACE("deadzone(%d) obj=%d\n", pd->dwData, obj); return DI_OK; } break; } - case (DWORD) DIPROP_SATURATION: { - LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph; - int obj = find_property(This, pdiph); + case (DWORD_PTR) DIPROP_SATURATION: { + LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph; + int obj = find_property(&This->base.data_format, pdiph); + if (obj >= 0) { pd->dwData = This->props[obj].lSaturation; - TRACE("saturation(%ld) obj=%d\n", pd->dwData, obj); + TRACE("saturation(%d) obj=%d\n", pd->dwData, obj); return DI_OK; } break; } default: - FIXME("Unknown type %p (%s)\n",rguid,debugstr_guid(rguid)); - break; + return IDirectInputDevice2AImpl_GetProperty(iface, rguid, pdiph); } } @@ -1479,95 +966,52 @@ static HRESULT WINAPI JoystickAImpl_GetProperty( /****************************************************************************** * GetObjectInfo : get object info */ -HRESULT WINAPI JoystickAImpl_GetObjectInfo( - LPDIRECTINPUTDEVICE8A iface, - LPDIDEVICEOBJECTINSTANCEA pdidoi, - DWORD dwObj, - DWORD dwHow) +static HRESULT WINAPI JoystickWImpl_GetObjectInfo(LPDIRECTINPUTDEVICE8W iface, + LPDIDEVICEOBJECTINSTANCEW pdidoi, DWORD dwObj, DWORD dwHow) { - JoystickImpl *This = (JoystickImpl *)iface; - DIDEVICEOBJECTINSTANCEA didoiA; - unsigned int i; + static const WCHAR axisW[] = {'A','x','i','s',' ','%','d',0}; + static const WCHAR povW[] = {'P','O','V',' ','%','d',0}; + static const WCHAR buttonW[] = {'B','u','t','t','o','n',' ','%','d',0}; + HRESULT res; - TRACE("(%p,%p,%ld,0x%08lx(%s))\n", - iface, pdidoi, dwObj, dwHow, - dwHow == DIPH_BYOFFSET ? "DIPH_BYOFFSET" : - dwHow == DIPH_BYID ? "DIPH_BYID" : - dwHow == DIPH_BYUSAGE ? "DIPH_BYUSAGE" : - "UNKNOWN"); + res = IDirectInputDevice2WImpl_GetObjectInfo(iface, pdidoi, dwObj, dwHow); + if (res != DI_OK) return res; - if (pdidoi == NULL) { - WARN("invalid parameter: pdidoi = NULL\n"); - return DIERR_INVALIDPARAM; - } + if (pdidoi->dwType & DIDFT_AXIS) + sprintfW(pdidoi->tszName, axisW, DIDFT_GETINSTANCE(pdidoi->dwType)); + else if (pdidoi->dwType & DIDFT_POV) + sprintfW(pdidoi->tszName, povW, DIDFT_GETINSTANCE(pdidoi->dwType)); + else if (pdidoi->dwType & DIDFT_BUTTON) + sprintfW(pdidoi->tszName, buttonW, DIDFT_GETINSTANCE(pdidoi->dwType)); - if ((pdidoi->dwSize != sizeof(DIDEVICEOBJECTINSTANCEA)) && - (pdidoi->dwSize != sizeof(DIDEVICEOBJECTINSTANCE_DX3A))) { - WARN("invalid parameter: pdidoi->dwSize = %ld != %d or %d\n", - pdidoi->dwSize, sizeof(DIDEVICEOBJECTINSTANCEA), - sizeof(DIDEVICEOBJECTINSTANCE_DX3A)); - return DIERR_INVALIDPARAM; - } + _dump_OBJECTINSTANCEW(pdidoi); + return res; +} - ZeroMemory(&didoiA, sizeof(didoiA)); - didoiA.dwSize = pdidoi->dwSize; +static HRESULT WINAPI JoystickAImpl_GetObjectInfo(LPDIRECTINPUTDEVICE8A iface, + LPDIDEVICEOBJECTINSTANCEA pdidoi, DWORD dwObj, DWORD dwHow) +{ + HRESULT res; + DIDEVICEOBJECTINSTANCEW didoiW; + DWORD dwSize = pdidoi->dwSize; - switch (dwHow) { - case DIPH_BYOFFSET: { - int axis = 0; - int pov = 0; - int button = 0; - for (i = 0; i < This->user_df->dwNumObjs; i++) { - if (This->user_df->rgodf[i].dwOfs == dwObj) { - if (This->user_df->rgodf[i].pguid) - didoiA.guidType = *This->user_df->rgodf[i].pguid; - else - didoiA.guidType = GUID_NULL; + didoiW.dwSize = sizeof(didoiW); + res = JoystickWImpl_GetObjectInfo((LPDIRECTINPUTDEVICE8W)iface, &didoiW, dwObj, dwHow); + if (res != DI_OK) return res; - didoiA.dwOfs = dwObj; - didoiA.dwType = This->user_df->rgodf[i].dwType; - didoiA.dwFlags = This->user_df->rgodf[i].dwFlags; + memset(pdidoi, 0, pdidoi->dwSize); + memcpy(pdidoi, &didoiW, FIELD_OFFSET(DIDEVICEOBJECTINSTANCEW, tszName)); + pdidoi->dwSize = dwSize; + WideCharToMultiByte(CP_ACP, 0, didoiW.tszName, -1, pdidoi->tszName, + sizeof(pdidoi->tszName), NULL, NULL); - if (DIDFT_GETTYPE(This->user_df->rgodf[i].dwType) & DIDFT_AXIS) - sprintf(didoiA.tszName, "Axis %d", axis); - else if (DIDFT_GETTYPE(This->user_df->rgodf[i].dwType) & DIDFT_POV) - sprintf(didoiA.tszName, "POV %d", pov); - else if (DIDFT_GETTYPE(This->user_df->rgodf[i].dwType) & DIDFT_BUTTON) - sprintf(didoiA.tszName, "Button %d", button); - - CopyMemory(pdidoi, &didoiA, pdidoi->dwSize); - return DI_OK; - } - - if (DIDFT_GETTYPE(This->user_df->rgodf[i].dwType) & DIDFT_AXIS) - axis++; - else if (DIDFT_GETTYPE(This->user_df->rgodf[i].dwType) & DIDFT_POV) - pov++; - else if (DIDFT_GETTYPE(This->user_df->rgodf[i].dwType) & DIDFT_BUTTON) - button++; - } - break; - } - case DIPH_BYID: - FIXME("dwHow = DIPH_BYID not implemented\n"); - break; - case DIPH_BYUSAGE: - FIXME("dwHow = DIPH_BYUSAGE not implemented\n"); - break; - default: - WARN("invalid parameter: dwHow = %08lx\n", dwHow); - return DIERR_INVALIDPARAM; - } - - CopyMemory(pdidoi, &didoiA, pdidoi->dwSize); - - return DI_OK; + return res; } /****************************************************************************** * GetDeviceInfo : get information about a device's identity */ -HRESULT WINAPI JoystickAImpl_GetDeviceInfo( +static HRESULT WINAPI JoystickAImpl_GetDeviceInfo( LPDIRECTINPUTDEVICE8A iface, LPDIDEVICEINSTANCEA pdidi) { @@ -1582,9 +1026,7 @@ HRESULT WINAPI JoystickAImpl_GetDeviceInfo( if ((pdidi->dwSize != sizeof(DIDEVICEINSTANCE_DX3A)) && (pdidi->dwSize != sizeof(DIDEVICEINSTANCEA))) { - WARN("invalid parameter: pdidi->dwSize = %ld != %d or %d\n", - pdidi->dwSize, sizeof(DIDEVICEINSTANCE_DX3A), - sizeof(DIDEVICEINSTANCEA)); + WARN("invalid parameter: pdidi->dwSize = %d\n", pdidi->dwSize); return DIERR_INVALIDPARAM; } @@ -1607,7 +1049,7 @@ HRESULT WINAPI JoystickAImpl_GetDeviceInfo( /****************************************************************************** * GetDeviceInfo : get information about a device's identity */ -HRESULT WINAPI JoystickWImpl_GetDeviceInfo( +static HRESULT WINAPI JoystickWImpl_GetDeviceInfo( LPDIRECTINPUTDEVICE8W iface, LPDIDEVICEINSTANCEW pdidi) { @@ -1617,9 +1059,7 @@ HRESULT WINAPI JoystickWImpl_GetDeviceInfo( if ((pdidi->dwSize != sizeof(DIDEVICEINSTANCE_DX3W)) && (pdidi->dwSize != sizeof(DIDEVICEINSTANCEW))) { - WARN("invalid parameter: pdidi->dwSize = %ld != %d or %d\n", - pdidi->dwSize, sizeof(DIDEVICEINSTANCE_DX3W), - sizeof(DIDEVICEINSTANCEW)); + WARN("invalid parameter: pdidi->dwSize = %d\n", pdidi->dwSize); return DIERR_INVALIDPARAM; } @@ -1643,17 +1083,17 @@ static const IDirectInputDevice8AVtbl JoystickAvt = { IDirectInputDevice2AImpl_QueryInterface, IDirectInputDevice2AImpl_AddRef, - JoystickAImpl_Release, + IDirectInputDevice2AImpl_Release, JoystickAImpl_GetCapabilities, - JoystickAImpl_EnumObjects, + IDirectInputDevice2AImpl_EnumObjects, JoystickAImpl_GetProperty, JoystickAImpl_SetProperty, JoystickAImpl_Acquire, JoystickAImpl_Unacquire, JoystickAImpl_GetDeviceState, - JoystickAImpl_GetDeviceData, - JoystickAImpl_SetDataFormat, - JoystickAImpl_SetEventNotification, + IDirectInputDevice2AImpl_GetDeviceData, + IDirectInputDevice2AImpl_SetDataFormat, + IDirectInputDevice2AImpl_SetEventNotification, IDirectInputDevice2AImpl_SetCooperativeLevel, JoystickAImpl_GetObjectInfo, JoystickAImpl_GetDeviceInfo, @@ -1676,28 +1116,28 @@ static const IDirectInputDevice8AVtbl JoystickAvt = }; #if !defined(__STRICT_ANSI__) && defined(__GNUC__) -# define XCAST(fun) (typeof(SysJoystickWvt.fun)) +# define XCAST(fun) (typeof(JoystickWvt.fun)) #else # define XCAST(fun) (void*) #endif -static const IDirectInputDevice8WVtbl SysJoystickWvt = +static const IDirectInputDevice8WVtbl JoystickWvt = { IDirectInputDevice2WImpl_QueryInterface, XCAST(AddRef)IDirectInputDevice2AImpl_AddRef, - XCAST(Release)JoystickAImpl_Release, + XCAST(Release)IDirectInputDevice2AImpl_Release, XCAST(GetCapabilities)JoystickAImpl_GetCapabilities, - JoystickWImpl_EnumObjects, + IDirectInputDevice2WImpl_EnumObjects, XCAST(GetProperty)JoystickAImpl_GetProperty, XCAST(SetProperty)JoystickAImpl_SetProperty, XCAST(Acquire)JoystickAImpl_Acquire, XCAST(Unacquire)JoystickAImpl_Unacquire, XCAST(GetDeviceState)JoystickAImpl_GetDeviceState, - XCAST(GetDeviceData)JoystickAImpl_GetDeviceData, - XCAST(SetDataFormat)JoystickAImpl_SetDataFormat, - XCAST(SetEventNotification)JoystickAImpl_SetEventNotification, + XCAST(GetDeviceData)IDirectInputDevice2AImpl_GetDeviceData, + XCAST(SetDataFormat)IDirectInputDevice2AImpl_SetDataFormat, + XCAST(SetEventNotification)IDirectInputDevice2AImpl_SetEventNotification, XCAST(SetCooperativeLevel)IDirectInputDevice2AImpl_SetCooperativeLevel, - IDirectInputDevice2WImpl_GetObjectInfo, + JoystickWImpl_GetObjectInfo, JoystickWImpl_GetDeviceInfo, XCAST(RunControlPanel)IDirectInputDevice2AImpl_RunControlPanel, XCAST(Initialize)IDirectInputDevice2AImpl_Initialize, diff --git a/reactos/dll/directx/dinput/joystick_linuxinput.c b/reactos/dll/directx/dinput/joystick_linuxinput.c index 9b494b8ee99..e1b92f7313c 100644 --- a/reactos/dll/directx/dinput/joystick_linuxinput.c +++ b/reactos/dll/directx/dinput/joystick_linuxinput.c @@ -17,7 +17,7 @@ * * 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 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include "config.h" @@ -34,7 +34,7 @@ #ifdef HAVE_SYS_TIME_H # include #endif -#include +#include #ifdef HAVE_SYS_IOCTL_H # include #endif @@ -44,16 +44,22 @@ #endif #ifdef HAVE_LINUX_INPUT_H # include +# undef SW_MAX # if defined(EVIOCGBIT) && defined(EV_ABS) && defined(BTN_PINKIE) # define HAVE_CORRECT_LINUXINPUT_H # endif #endif +#ifdef HAVE_SYS_POLL_H +# include +#endif #include "wine/debug.h" #include "wine/unicode.h" +#include "wine/list.h" #include "windef.h" #include "winbase.h" #include "winerror.h" +#include "winreg.h" #include "dinput.h" #include "dinput_private.h" @@ -61,167 +67,334 @@ WINE_DEFAULT_DEBUG_CHANNEL(dinput); + +/* + * Maps POV x & y event values to a DX "clock" position: + * 0 + * 31500 4500 + * 27000 -1 9000 + * 22500 13500 + * 18000 + */ +DWORD joystick_map_pov(POINTL *p) +{ + if (p->x > 0) + return p->y < 0 ? 4500 : !p->y ? 9000 : 13500; + else if (p->x < 0) + return p->y < 0 ? 31500 : !p->y ? 27000 : 22500; + else + return p->y < 0 ? 0 : !p->y ? -1 : 18000; +} + +/* + * This maps the read value (from the input event) to a value in the + * 'wanted' range. + * Notes: + * Dead zone is in % multiplied by a 100 (range 0..10000) + */ +LONG joystick_map_axis(ObjProps *props, int val) +{ + LONG ret; + LONG dead_zone = MulDiv( props->lDeadZone, props->lDevMax - props->lDevMin, 10000 ); + LONG dev_range = props->lDevMax - props->lDevMin - dead_zone; + + /* Center input */ + val -= (props->lDevMin + props->lDevMax) / 2; + + /* Remove dead zone */ + if (abs( val ) <= dead_zone / 2) + val = 0; + else + val = val < 0 ? val + dead_zone / 2 : val - dead_zone / 2; + + /* Scale and map the value from the device range into the required range */ + ret = MulDiv( val, props->lMax - props->lMin, dev_range ) + + (props->lMin + props->lMax) / 2; + + /* Clamp in case or rounding errors */ + if (ret > props->lMax) ret = props->lMax; + else if (ret < props->lMin) ret = props->lMin; + + TRACE( "(%d <%d> %d) -> (%d <%d> %d): val=%d ret=%d\n", + props->lDevMin, dead_zone, props->lDevMax, + props->lMin, props->lDeadZone, props->lMax, + val, ret ); + + return ret; +} + #ifdef HAVE_CORRECT_LINUXINPUT_H #define EVDEVPREFIX "/dev/input/event" /* Wine joystick driver object instances */ -#define WINE_JOYSTICK_AXIS_BASE 0 -#define WINE_JOYSTICK_BUTTON_BASE 8 +#define WINE_JOYSTICK_MAX_AXES 8 +#define WINE_JOYSTICK_MAX_POVS 4 +#define WINE_JOYSTICK_MAX_BUTTONS 128 -typedef struct EffectListItem EffectListItem; -struct EffectListItem -{ - LPDIRECTINPUTEFFECT ref; - struct EffectListItem* next; +struct wine_input_absinfo { + LONG value; + LONG minimum; + LONG maximum; + LONG fuzz; + LONG flat; }; /* implemented in effect_linuxinput.c */ -HRESULT linuxinput_create_effect(int* fd, REFGUID rguid, LPDIRECTINPUTEFFECT* peff); +HRESULT linuxinput_create_effect(int* fd, REFGUID rguid, struct list *parent_list_entry, 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 const IDirectInputDevice8AVtbl JoystickAvt; static const IDirectInputDevice8WVtbl JoystickWvt; -struct JoystickImpl -{ - const void *lpVtbl; - LONG ref; - GUID guid; +struct JoyDev { + char *device; + char *name; + GUID guid; - /* The 'parent' DInput */ - IDirectInputImpl *dinput; - - /* joystick private */ - /* what range and deadzone the game wants */ - LONG wantmin[ABS_MAX]; - LONG wantmax[ABS_MAX]; - LONG deadz[ABS_MAX]; - - /* autodetecting ranges per axe by following movement */ - LONG havemax[ABS_MAX]; - LONG havemin[ABS_MAX]; - - int joyfd; - - LPDIDATAFORMAT df; - HANDLE hEvent; - LPDIDEVICEOBJECTDATA data_queue; - int queue_head, queue_tail, queue_len; - 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]; - -#define AXE_ABS 0 -#define AXE_ABSMIN 1 -#define AXE_ABSMAX 2 -#define AXE_ABSFUZZ 3 -#define AXE_ABSFLAT 4 - + int has_ff; + int num_effects; /* 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]; + BYTE ffbits[(FF_MAX+7)/8]; + + /* data returned by the EVIOCGABS() ioctl */ + struct wine_input_absinfo axes[ABS_MAX]; }; +struct JoystickImpl +{ + struct IDirectInputDevice2AImpl base; + + struct JoyDev *joydev; + + /* joystick private */ + int joyfd; + + DIJOYSTATE2 js; + + ObjProps props[ABS_MAX]; + + int axes[ABS_MAX]; + POINTL povs[4]; + + /* LUT for KEY_ to offset in rgbButtons */ + BYTE buttons[KEY_MAX]; + + DWORD numAxes; + DWORD numPOVs; + DWORD numButtons; + + /* Force feedback variables */ + struct list ff_effects; + int ff_state; + int ff_autocenter; +}; + +static void fake_current_js_state(JoystickImpl *ji); +static void find_joydevs(void); + /* This GUID is slightly different from the linux joystick one. Take note. */ -static GUID DInput_Wine_Joystick_GUID = { /* 9e573eda-7734-11d2-8d4a-23903fb6bdf7 */ +static const GUID DInput_Wine_Joystick_Base_GUID = { /* 9e573eda-7734-11d2-8d4a-23903fb6bdf7 */ 0x9e573eda, 0x7734, 0x11d2, {0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf7} }; -static void fake_current_js_state(JoystickImpl *ji); -static int find_property_offset(JoystickImpl *This, LPCDIPROPHEADER ph); +#define test_bit(arr,bit) (((BYTE*)(arr))[(bit)>>3]&(1<<((bit)&7))) -#define test_bit(arr,bit) (((BYTE*)arr)[bit>>3]&(1<<(bit&7))) +#define MAX_JOYDEV 64 -static int joydev_have(BOOL require_ff) +static int have_joydevs = -1; +static struct JoyDev *joydevs = NULL; + +static void find_joydevs(void) { - int i, fd, flags, num_effects; - int havejoy = 0; + int i; - 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]; + if (InterlockedCompareExchange(&have_joydevs, 0, -1) != -1) + /* Someone beat us to it */ + return; - sprintf(buf,EVDEVPREFIX"%d",i); + for (i = 0; i < MAX_JOYDEV; i++) + { + char buf[MAX_PATH]; + struct JoyDev joydev = {0}; + int fd; + int no_ff_check = 0; + int j; + struct JoyDev *new_joydevs; - if (require_ff) - flags = O_RDWR; - else - flags = O_RDONLY; + snprintf(buf, sizeof(buf), EVDEVPREFIX"%d", i); - if (-1!=(fd=open(buf,flags))) { - if (-1==ioctl(fd,EVIOCGBIT(EV_ABS,sizeof(absbits)),absbits)) { - perror("EVIOCGBIT EV_ABS"); - close(fd); - continue; - } - if (-1==ioctl(fd,EVIOCGBIT(EV_KEY,sizeof(keybits)),keybits)) { - perror("EVIOCGBIT EV_KEY"); - close(fd); - continue; - } + if ((fd = open(buf, O_RDWR)) == -1) + { + fd = open(buf, O_RDONLY); + no_ff_check = 1; + } - /* 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; - } - } + if (fd == -1) + { + WARN("Failed to open \"%s\": %d %s\n", buf, errno, strerror(errno)); + 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) && - ( test_bit(keybits,BTN_TRIGGER) || - test_bit(keybits,BTN_A) || - test_bit(keybits,BTN_1) - ) - ) { - FIXME("found a joystick at %s!\n",buf); - havejoy = 1; - } - close(fd); - } - if (havejoy || (errno==ENODEV)) - break; - } - return havejoy; + if (ioctl(fd, EVIOCGBIT(0, sizeof(joydev.evbits)), joydev.evbits) == -1) + { + WARN("ioct(EVIOCGBIT, 0) failed: %d %s\n", errno, strerror(errno)); + close(fd); + continue; + } + if (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(joydev.absbits)), joydev.absbits) == -1) + { + WARN("ioct(EVIOCGBIT, EV_ABS) failed: %d %s\n", errno, strerror(errno)); + close(fd); + continue; + } + if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(joydev.keybits)), joydev.keybits) == -1) + { + WARN("ioct(EVIOCGBIT, EV_KEY) failed: %d %s\n", errno, strerror(errno)); + 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(joydev.absbits, ABS_X) || !test_bit(joydev.absbits, ABS_Y) || + !(test_bit(joydev.keybits, BTN_TRIGGER) || + test_bit(joydev.keybits, BTN_A) || + test_bit(joydev.keybits, BTN_1))) + { + close(fd); + continue; + } + + if (!(joydev.device = HeapAlloc(GetProcessHeap(), 0, strlen(buf) + 1))) + { + close(fd); + continue; + } + strcpy(joydev.device, buf); + + buf[MAX_PATH - 1] = 0; + if (ioctl(fd, EVIOCGNAME(MAX_PATH - 1), buf) != -1 && + (joydev.name = HeapAlloc(GetProcessHeap(), 0, strlen(buf) + 1))) + strcpy(joydev.name, buf); + else + joydev.name = joydev.device; + + joydev.guid = DInput_Wine_Joystick_Base_GUID; + joydev.guid.Data3 += have_joydevs; + + TRACE("Found a joystick on %s: %s (%s)\n", + joydev.device, joydev.name, + debugstr_guid(&joydev.guid) + ); + +#ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION + if (!no_ff_check && + test_bit(joydev.evbits, EV_FF) && + ioctl(fd, EVIOCGBIT(EV_FF, sizeof(joydev.ffbits)), joydev.ffbits) != -1 && + ioctl(fd, EVIOCGEFFECTS, &joydev.num_effects) != -1 && + joydev.num_effects > 0) + { + TRACE(" ... with force feedback\n"); + joydev.has_ff = 1; + } +#endif + + for (j = 0; j < ABS_MAX;j ++) + { + if (!test_bit(joydev.absbits, j)) continue; + if (ioctl(fd, EVIOCGABS(j), &(joydev.axes[j])) != -1) + { + TRACE(" ... with axis %d: cur=%d, min=%d, max=%d, fuzz=%d, flat=%d\n", + j, + joydev.axes[j].value, + joydev.axes[j].minimum, + joydev.axes[j].maximum, + joydev.axes[j].fuzz, + joydev.axes[j].flat + ); + } + } + + if (!have_joydevs) + new_joydevs = HeapAlloc(GetProcessHeap(), 0, sizeof(struct JoyDev)); + else + new_joydevs = HeapReAlloc(GetProcessHeap(), 0, joydevs, (1 + have_joydevs) * sizeof(struct JoyDev)); + + if (!new_joydevs) + { + close(fd); + continue; + } + joydevs = new_joydevs; + memcpy(joydevs + have_joydevs, &joydev, sizeof(joydev)); + have_joydevs++; + + close(fd); + } +} + +static void fill_joystick_dideviceinstanceA(LPDIDEVICEINSTANCEA lpddi, DWORD version, int id) +{ + DWORD dwSize = lpddi->dwSize; + + TRACE("%d %p\n", dwSize, lpddi); + memset(lpddi, 0, dwSize); + + lpddi->dwSize = dwSize; + lpddi->guidInstance = joydevs[id].guid; + lpddi->guidProduct = DInput_Wine_Joystick_Base_GUID; + lpddi->guidFFDriver = GUID_NULL; + + if (version >= 0x0800) + lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8); + else + lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8); + + strcpy(lpddi->tszInstanceName, joydevs[id].name); + strcpy(lpddi->tszProductName, joydevs[id].device); +} + +static void fill_joystick_dideviceinstanceW(LPDIDEVICEINSTANCEW lpddi, DWORD version, int id) +{ + DWORD dwSize = lpddi->dwSize; + + TRACE("%d %p\n", dwSize, lpddi); + memset(lpddi, 0, dwSize); + + lpddi->dwSize = dwSize; + lpddi->guidInstance = joydevs[id].guid; + lpddi->guidProduct = DInput_Wine_Joystick_Base_GUID; + lpddi->guidFFDriver = GUID_NULL; + + if (version >= 0x0800) + lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8); + else + lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8); + + MultiByteToWideChar(CP_ACP, 0, joydevs[id].name, -1, lpddi->tszInstanceName, MAX_PATH); + MultiByteToWideChar(CP_ACP, 0, joydevs[id].device, -1, lpddi->tszProductName, MAX_PATH); } static BOOL joydev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, DWORD version, int id) { - int havejoy = 0; + find_joydevs(); - if (id != 0) - return FALSE; + if (id >= have_joydevs) { + return FALSE; + } if (!((dwDevType == 0) || - ((dwDevType == DIDEVTYPE_JOYSTICK) && (version < 0x0800)) || + ((dwDevType == DIDEVTYPE_JOYSTICK) && (version > 0x0300 && version < 0x0800)) || (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800)))) return FALSE; @@ -230,38 +403,23 @@ static BOOL joydev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTAN return FALSE; #endif - havejoy = joydev_have(dwFlags & DIEDFL_FORCEFEEDBACK); - - if (!havejoy) - return FALSE; - - TRACE("Enumerating the linuxinput Joystick device\n"); - - /* Return joystick */ - lpddi->guidInstance = GUID_Joystick; - lpddi->guidProduct = DInput_Wine_Joystick_GUID; - - lpddi->guidFFDriver = GUID_NULL; - if (version >= 0x0800) - lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8); - else - lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8); - - strcpy(lpddi->tszInstanceName, "Joystick"); - /* ioctl JSIOCGNAME(len) */ - strcpy(lpddi->tszProductName, "Wine Joystick"); - return TRUE; + if (!(dwFlags & DIEDFL_FORCEFEEDBACK) || joydevs[id].has_ff) { + fill_joystick_dideviceinstanceA(lpddi, version, id); + return TRUE; + } + return FALSE; } static BOOL joydev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEW lpddi, DWORD version, int id) { - int havejoy = 0; + find_joydevs(); - if (id != 0) - return FALSE; + if (id >= have_joydevs) { + return FALSE; + } if (!((dwDevType == 0) || - ((dwDevType == DIDEVTYPE_JOYSTICK) && (version < 0x0800)) || + ((dwDevType == DIDEVTYPE_JOYSTICK) && (version > 0x0300 && version < 0x0800)) || (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800)))) return FALSE; @@ -270,108 +428,205 @@ static BOOL joydev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTAN return FALSE; #endif - havejoy = joydev_have(dwFlags & DIEDFL_FORCEFEEDBACK); - - if (!havejoy) - return FALSE; - - TRACE("Enumerating the linuxinput Joystick device\n"); - - /* Return joystick */ - lpddi->guidInstance = GUID_Joystick; - lpddi->guidProduct = DInput_Wine_Joystick_GUID; - - lpddi->guidFFDriver = GUID_NULL; - if (version >= 0x0800) - lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8); - else - lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8); - - MultiByteToWideChar(CP_ACP, 0, "Joystick", -1, lpddi->tszInstanceName, MAX_PATH); - /* ioctl JSIOCGNAME(len) */ - MultiByteToWideChar(CP_ACP, 0, "Wine Joystick", -1, lpddi->tszProductName, MAX_PATH); - return TRUE; + if (!(dwFlags & DIEDFL_FORCEFEEDBACK) || joydevs[id].has_ff) { + fill_joystick_dideviceinstanceW(lpddi, version, id); + return TRUE; + } + return FALSE; } -static JoystickImpl *alloc_device(REFGUID rguid, const void *jvt, IDirectInputImpl *dinput) +static JoystickImpl *alloc_device(REFGUID rguid, const void *jvt, IDirectInputImpl *dinput, unsigned short index) { - JoystickImpl* newDevice; - int i; + JoystickImpl* newDevice; + LPDIDATAFORMAT df = NULL; + int i, idx = 0; + char buffer[MAX_PATH+16]; + HKEY hkey, appkey; + LONG def_deadzone = 0; - newDevice = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(JoystickImpl)); - newDevice->lpVtbl = jvt; - newDevice->ref = 1; - newDevice->joyfd = -1; - newDevice->dinput = dinput; + newDevice = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(JoystickImpl)); + if (!newDevice) return NULL; + + newDevice->base.lpVtbl = jvt; + newDevice->base.ref = 1; + newDevice->base.guid = *rguid; + newDevice->base.dinput = dinput; + newDevice->joyfd = -1; + newDevice->joydev = &joydevs[index]; + list_init(&newDevice->ff_effects); #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION - newDevice->ff_state = FF_STATUS_STOPPED; + newDevice->ff_state = FF_STATUS_STOPPED; #endif - memcpy(&(newDevice->guid),rguid,sizeof(*rguid)); - for (i=0;iwantmin[i] = -32768; - newDevice->wantmax[i] = 32767; - /* TODO: - * direct input defines a default for the deadzone somewhere; but as long - * as in map_axis the code for the dead zone is commented out its no - * problem - */ - newDevice->deadz[i] = 0; - } - fake_current_js_state(newDevice); - return newDevice; + /* There is no way in linux to query force feedback autocenter status. + Instead, track it with ff_autocenter, and assume it's initialy + enabled. */ + newDevice->ff_autocenter = 1; + InitializeCriticalSection(&newDevice->base.crit); + newDevice->base.crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": JoystickImpl*->base.crit"); + + /* get options */ + get_app_key(&hkey, &appkey); + + if (!get_config_key(hkey, appkey, "DefaultDeadZone", buffer, MAX_PATH)) + { + def_deadzone = atoi(buffer); + TRACE("setting default deadzone to: %d\n", def_deadzone); + } + if (appkey) RegCloseKey(appkey); + if (hkey) RegCloseKey(hkey); + + /* Create copy of default data format */ + if (!(df = HeapAlloc(GetProcessHeap(), 0, c_dfDIJoystick2.dwSize))) goto failed; + memcpy(df, &c_dfDIJoystick2, c_dfDIJoystick2.dwSize); + if (!(df->rgodf = HeapAlloc(GetProcessHeap(), 0, df->dwNumObjs * df->dwObjSize))) goto failed; + + /* Supported Axis & POVs should map 1-to-1 */ + for (i = 0; i < WINE_JOYSTICK_MAX_AXES; i++) + { + if (!test_bit(newDevice->joydev->absbits, i)) { + newDevice->axes[i] = -1; + continue; + } + + memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[i], df->dwObjSize); + newDevice->axes[i] = idx; + newDevice->props[idx].lDevMin = newDevice->joydev->axes[i].minimum; + newDevice->props[idx].lDevMax = newDevice->joydev->axes[i].maximum; + newDevice->props[idx].lMin = 0; + newDevice->props[idx].lMax = 0xffff; + newDevice->props[idx].lSaturation = 0; + newDevice->props[idx].lDeadZone = def_deadzone; + + /* Linux supports force-feedback on X & Y axes only */ + if (newDevice->joydev->has_ff && (i == 0 || i == 1)) + df->rgodf[idx].dwFlags |= DIDOI_FFACTUATOR; + + df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(newDevice->numAxes++) | DIDFT_ABSAXIS; + } + + for (i = 0; i < WINE_JOYSTICK_MAX_POVS; i++) + { + if (!test_bit(newDevice->joydev->absbits, ABS_HAT0X + i * 2) || + !test_bit(newDevice->joydev->absbits, ABS_HAT0Y + i * 2)) { + newDevice->axes[ABS_HAT0X + i * 2] = newDevice->axes[ABS_HAT0Y + i * 2] = -1; + continue; + } + + memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[i + WINE_JOYSTICK_MAX_AXES], df->dwObjSize); + newDevice->axes[ABS_HAT0X + i * 2] = newDevice->axes[ABS_HAT0Y + i * 2] = i; + df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(newDevice->numPOVs++) | DIDFT_POV; + } + + /* Buttons can be anywhere, so check all */ + for (i = 0; i < KEY_MAX && newDevice->numButtons < WINE_JOYSTICK_MAX_BUTTONS; i++) + { + if (!test_bit(newDevice->joydev->keybits, i)) continue; + + memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[newDevice->numButtons + WINE_JOYSTICK_MAX_AXES + WINE_JOYSTICK_MAX_POVS], df->dwObjSize); + newDevice->buttons[i] = 0x80 | newDevice->numButtons; + df->rgodf[idx ].pguid = &GUID_Button; + df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(newDevice->numButtons++) | DIDFT_PSHBUTTON; + } + df->dwNumObjs = idx; + + fake_current_js_state(newDevice); + + newDevice->base.data_format.wine_df = df; + IDirectInput_AddRef((LPDIRECTINPUTDEVICE8A)newDevice->base.dinput); + return newDevice; + +failed: + if (df) HeapFree(GetProcessHeap(), 0, df->rgodf); + HeapFree(GetProcessHeap(), 0, df); + HeapFree(GetProcessHeap(), 0, newDevice); + return NULL; +} + +/****************************************************************************** + * get_joystick_index : Get the joystick index from a given GUID + */ +static unsigned short get_joystick_index(REFGUID guid) +{ + GUID wine_joystick = DInput_Wine_Joystick_Base_GUID; + GUID dev_guid = *guid; + + wine_joystick.Data3 = 0; + dev_guid.Data3 = 0; + + /* for the standard joystick GUID use index 0 */ + if(IsEqualGUID(&GUID_Joystick,guid)) return 0; + + /* for the wine joystick GUIDs use the index stored in Data3 */ + if(IsEqualGUID(&wine_joystick, &dev_guid)) return guid->Data3 - DInput_Wine_Joystick_Base_GUID.Data3; + + return MAX_JOYDEV; } static HRESULT joydev_create_deviceA(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEA* pdev) { - int havejoy = 0; + unsigned short index; - havejoy = joydev_have(FALSE); + find_joydevs(); - if (!havejoy) - return DIERR_DEVICENOTREG; + if ((index = get_joystick_index(rguid)) < MAX_JOYDEV && + have_joydevs && index < have_joydevs) + { + if ((riid == NULL) || + IsEqualGUID(&IID_IDirectInputDeviceA, riid) || + IsEqualGUID(&IID_IDirectInputDevice2A, riid) || + IsEqualGUID(&IID_IDirectInputDevice7A, riid) || + IsEqualGUID(&IID_IDirectInputDevice8A, riid)) + { + *pdev = (IDirectInputDeviceA*) alloc_device(rguid, &JoystickAvt, dinput, index); + TRACE("Created a Joystick device (%p)\n", *pdev); - if ((IsEqualGUID(&GUID_Joystick,rguid)) || - (IsEqualGUID(&DInput_Wine_Joystick_GUID,rguid))) { - if ((riid == NULL) || - IsEqualGUID(&IID_IDirectInputDeviceA,riid) || - IsEqualGUID(&IID_IDirectInputDevice2A,riid) || - IsEqualGUID(&IID_IDirectInputDevice7A,riid) || - IsEqualGUID(&IID_IDirectInputDevice8A,riid)) { - *pdev = (IDirectInputDeviceA*) alloc_device(rguid, &JoystickAvt, dinput); - TRACE("Creating a Joystick device (%p)\n", *pdev); - return DI_OK; - } else - return DIERR_NOINTERFACE; - } + if (*pdev == NULL) + { + ERR("out of memory\n"); + return DIERR_OUTOFMEMORY; + } + return DI_OK; + } - return DIERR_DEVICENOTREG; + WARN("no interface\n"); + return DIERR_NOINTERFACE; + } + + return DIERR_DEVICENOTREG; } static HRESULT joydev_create_deviceW(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEW* pdev) { - int havejoy = 0; + unsigned short index; - havejoy = joydev_have(FALSE); + find_joydevs(); - if (!havejoy) - return DIERR_DEVICENOTREG; + if ((index = get_joystick_index(rguid)) < MAX_JOYDEV && + have_joydevs && index < have_joydevs) + { + if ((riid == NULL) || + IsEqualGUID(&IID_IDirectInputDeviceW, riid) || + IsEqualGUID(&IID_IDirectInputDevice2W, riid) || + IsEqualGUID(&IID_IDirectInputDevice7W, riid) || + IsEqualGUID(&IID_IDirectInputDevice8W, riid)) + { + *pdev = (IDirectInputDeviceW*) alloc_device(rguid, &JoystickWvt, dinput, index); + TRACE("Created a Joystick device (%p)\n", *pdev); - if ((IsEqualGUID(&GUID_Joystick,rguid)) || - (IsEqualGUID(&DInput_Wine_Joystick_GUID,rguid))) { - if ((riid == NULL) || - IsEqualGUID(&IID_IDirectInputDeviceW,riid) || - IsEqualGUID(&IID_IDirectInputDevice2W,riid) || - IsEqualGUID(&IID_IDirectInputDevice7W,riid) || - IsEqualGUID(&IID_IDirectInputDevice8W,riid)) { - *pdev = (IDirectInputDeviceW*) alloc_device(rguid, &JoystickWvt, dinput); - TRACE("Creating a Joystick device (%p)\n", *pdev); - return DI_OK; - } else - return DIERR_NOINTERFACE; - } + if (*pdev == NULL) + { + ERR("out of memory\n"); + return DIERR_OUTOFMEMORY; + } + return DI_OK; + } + WARN("no interface\n"); + return DIERR_NOINTERFACE; + } - return DIERR_DEVICENOTREG; + WARN("invalid device GUID\n"); + return DIERR_DEVICENOTREG; } const struct dinput_device joystick_linuxinput_device = { @@ -382,170 +637,53 @@ const struct dinput_device joystick_linuxinput_device = { joydev_create_deviceW }; -/****************************************************************************** - * Joystick - */ -static ULONG WINAPI JoystickAImpl_Release(LPDIRECTINPUTDEVICE8A iface) -{ - JoystickImpl *This = (JoystickImpl *)iface; - ULONG ref; - - ref = InterlockedDecrement(&(This->ref)); - 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); - - /* Free the DataFormat */ - HeapFree(GetProcessHeap(), 0, This->df); - - HeapFree(GetProcessHeap(),0,This); - return 0; -} - -/****************************************************************************** - * SetDataFormat : the application can choose the format of the data - * the device driver sends back with GetDeviceState. - */ -static HRESULT WINAPI JoystickAImpl_SetDataFormat( - LPDIRECTINPUTDEVICE8A iface,LPCDIDATAFORMAT df -) -{ - JoystickImpl *This = (JoystickImpl *)iface; - - TRACE("(this=%p,%p)\n",This,df); - - if (df == NULL) { - WARN("invalid pointer\n"); - return E_POINTER; - } - - if (df->dwSize != sizeof(*df)) { - WARN("invalid argument\n"); - return DIERR_INVALIDPARAM; - } - - _dump_DIDATAFORMAT(df); - - if (This->joyfd!=-1) { - WARN("acquired\n"); - return DIERR_ACQUIRED; - } - - /* Store the new data format */ - This->df = HeapAlloc(GetProcessHeap(),0,df->dwSize); - if (This->df==NULL) { - return DIERR_OUTOFMEMORY; - } - memcpy(This->df, df, df->dwSize); - This->df->rgodf = HeapAlloc(GetProcessHeap(),0,df->dwNumObjs*df->dwObjSize); - if (This->df->rgodf==NULL) { - HeapFree(GetProcessHeap(), 0, This->df); - return DIERR_OUTOFMEMORY; - } - memcpy(This->df->rgodf,df->rgodf,df->dwNumObjs*df->dwObjSize); - - return DI_OK; -} - /****************************************************************************** * Acquire : gets exclusive control of the joystick */ static HRESULT WINAPI JoystickAImpl_Acquire(LPDIRECTINPUTDEVICE8A iface) { - int i; JoystickImpl *This = (JoystickImpl *)iface; - char buf[200]; - BOOL readonly = TRUE; + HRESULT res; 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_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); - } - } - 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)|| - test_bit(This->keybits,BTN_A) || - test_bit(This->keybits,BTN_1) - ) - ) - ) - break; - close(This->joyfd); - This->joyfd = -1; + + if ((res = IDirectInputDevice2AImpl_Acquire(iface)) != DI_OK) + { + WARN("Failed to acquire: %x\n", res); + return res; } - 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"); - } + if ((This->joyfd = open(This->joydev->device, O_RDWR)) == -1) + { + if ((This->joyfd = open(This->joydev->device, O_RDONLY)) == -1) + { + /* Couldn't open the device at all */ + ERR("Failed to open device %s: %d %s\n", This->joydev->device, errno, strerror(errno)); + IDirectInputDevice2AImpl_Unacquire(iface); + return DIERR_NOTFOUND; } - else { - TRACE("Could not get EV_FF bits; disabling force feedback.\n"); + 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", This->joydev->device); } } - else { - TRACE("Force feedback disabled (device is readonly or joystick incapable).\n"); + else + { + if (!This->ff_autocenter) + { + struct input_event event; + + /* Disable autocenter. */ + event.type = EV_FF; + event.code = FF_AUTOCENTER; + event.value = 0; + if (write(This->joyfd, &event, sizeof(event)) == -1) + ERR("Failed disabling autocenter: %d %s\n", errno, strerror(errno)); + } } -#endif - for (i=0;iabsbits,i)) { - if (-1==ioctl(This->joyfd,EVIOCGABS(i),&(This->axes[i]))) - continue; - FIXME("axe %d: cur=%d, min=%d, max=%d, fuzz=%d, flat=%d\n", - i, - This->axes[i][AXE_ABS], - This->axes[i][AXE_ABSMIN], - This->axes[i][AXE_ABSMAX], - This->axes[i][AXE_ABSFUZZ], - This->axes[i][AXE_ABSFLAT] - ); - This->havemin[i] = This->axes[i][AXE_ABSMIN]; - This->havemax[i] = This->axes[i][AXE_ABSMAX]; - } - } - MESSAGE("\n"); - - fake_current_js_state(This); - - return 0; + return DI_OK; } /****************************************************************************** @@ -554,123 +692,85 @@ static HRESULT WINAPI JoystickAImpl_Acquire(LPDIRECTINPUTDEVICE8A iface) static HRESULT WINAPI JoystickAImpl_Unacquire(LPDIRECTINPUTDEVICE8A iface) { JoystickImpl *This = (JoystickImpl *)iface; + HRESULT res; TRACE("(this=%p)\n",This); - if (This->joyfd!=-1) { - close(This->joyfd); - This->joyfd = -1; - return DI_OK; + res = IDirectInputDevice2AImpl_Unacquire(iface); + if (res==DI_OK && This->joyfd!=-1) { + effect_list_item *itr; + struct input_event event; + + /* For each known effect: + * - stop it + * - unload it + * But, unlike DISFFC_RESET, do not release the effect. + */ + LIST_FOR_EACH_ENTRY(itr, &This->ff_effects, effect_list_item, entry) { + IDirectInputEffect_Stop(itr->ref); + IDirectInputEffect_Unload(itr->ref); + } + + /* Enable autocenter. */ + event.type = EV_FF; + event.code = FF_AUTOCENTER; + /* TODO: Read autocenter strengh before disabling it, and use it here + * instead of 0xFFFF (maximum strengh). + */ + event.value = 0xFFFF; + if (write(This->joyfd, &event, sizeof(event)) == -1) + ERR("Failed to set autocenter to %04x: %d %s\n", event.value, errno, strerror(errno)); + + close(This->joyfd); + This->joyfd = -1; } - else - return DI_NOEFFECT; + return res; } -/* - * This maps the read value (from the input event) to a value in the - * 'wanted' range. It also autodetects the possible range of the axe and - * adapts values accordingly. - */ -static int -map_axis(JoystickImpl* This, int axis, int val) { - int xmin = This->axes[axis][AXE_ABSMIN]; - int xmax = This->axes[axis][AXE_ABSMAX]; - int hmax = This->havemax[axis]; - int hmin = This->havemin[axis]; - int wmin = This->wantmin[axis]; - int wmax = This->wantmax[axis]; - int ret; - - if (val > hmax) This->havemax[axis] = hmax = val; - if (val < hmin) This->havemin[axis] = hmin = val; - - if (xmin == xmax) return val; - - /* map the value from the hmin-hmax range into the wmin-wmax range */ - 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)) { - FIXME("%d in deadzone, return mid.\n",val); - return (wmax-wmin)/2+wmin; - } -#endif - return ret; -} - -/* +/* * set the current state of the js device as it would be with the middle * values on the axes */ +#define CENTER_AXIS(a) \ + (ji->axes[a] == -1 ? 0 : joystick_map_axis( &ji->props[ji->axes[a]], \ + ji->joydev->axes[a].value )) static void fake_current_js_state(JoystickImpl *ji) { - ji->js.lX = map_axis(ji, ABS_X, ji->axes[ABS_X ][AXE_ABS]); - ji->js.lY = map_axis(ji, ABS_Y, ji->axes[ABS_Y ][AXE_ABS]); - ji->js.lZ = map_axis(ji, ABS_Z, ji->axes[ABS_Z ][AXE_ABS]); - 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]); -} + int i; -static int find_property_offset(JoystickImpl *This, LPCDIPROPHEADER ph) + /* center the axes */ + ji->js.lX = CENTER_AXIS(ABS_X); + ji->js.lY = CENTER_AXIS(ABS_Y); + ji->js.lZ = CENTER_AXIS(ABS_Z); + ji->js.lRx = CENTER_AXIS(ABS_RX); + ji->js.lRy = CENTER_AXIS(ABS_RY); + ji->js.lRz = CENTER_AXIS(ABS_RZ); + ji->js.rglSlider[0] = CENTER_AXIS(ABS_THROTTLE); + ji->js.rglSlider[1] = CENTER_AXIS(ABS_RUDDER); + + /* POV center is -1 */ + for (i = 0; i < 4; i++) + ji->js.rgdwPOV[i] = -1; +} +#undef CENTER_AXIS + +/* convert wine format offset to user format object index */ +static void joy_polldev(JoystickImpl *This) { - int i,c; - switch (ph->dwHow) { - case DIPH_BYOFFSET: - for (i=0; idf->dwNumObjs; i++) { - if (This->df->rgodf[i].dwOfs == ph->dwObj) { - return i; - } - } - break; - case DIPH_BYID: - /* XXX: this is a hack - see below */ - c = DIDFT_GETINSTANCE(ph->dwObj)>>WINE_JOYSTICK_AXIS_BASE; - for (i=0; (c&1)==0 && i<0x0F; i++) { - c >>= 1; - } - if (i<0x0F) { - return i; - } - - /* XXX - the following part won't work with LiveForSpeed - * - the game sets the dwTypes to something else then - * the ddoi.dwType set in EnumObjects - */ -#if 0 - for (i=0; idf->dwNumObjs; i++) { - TRACE("dwType='%08x'\n", This->df->rgodf[i].dwType); - if ((This->df->rgodf[i].dwType & 0x00ffffff) == (ph->dwObj & 0x00ffffff)) { - return i; - } - } -#endif - break; - default: - FIXME("Unhandled ph->dwHow=='%04X'\n", (unsigned int)ph->dwHow); - } - - return -1; -} - -static void joy_polldev(JoystickImpl *This) { - struct timeval tv; - fd_set readfds; - struct input_event ie; + struct pollfd plfd; + struct input_event ie; if (This->joyfd==-1) return; - while (1) { - memset(&tv,0,sizeof(tv)); - FD_ZERO(&readfds); - FD_SET(This->joyfd,&readfds); + while (1) + { + LONG value = 0; + int inst_id = -1; - if (1>select(This->joyfd+1,&readfds,NULL,NULL,&tv)) + plfd.fd = This->joyfd; + plfd.events = POLLIN; + + if (poll(&plfd,1,0) != 1) return; /* we have one event, so we can read */ @@ -680,124 +780,72 @@ static void joy_polldev(JoystickImpl *This) { TRACE("input_event: type %d, code %d, value %d\n",ie.type,ie.code,ie.value); switch (ie.type) { case EV_KEY: /* button */ - switch (ie.code) { - case BTN_TRIGGER: /* normal flight stick */ - case BTN_A: /* gamepad */ - case BTN_1: /* generic */ - This->js.rgbButtons[0] = ie.value?0x80:0x00; - GEN_EVENT(DIJOFS_BUTTON(0),ie.value?0x80:0x0,ie.time.tv_usec,(This->dinput->evsequence)++); - break; - case BTN_THUMB: - case BTN_B: - case BTN_2: - This->js.rgbButtons[1] = ie.value?0x80:0x00; - GEN_EVENT(DIJOFS_BUTTON(1),ie.value?0x80:0x0,ie.time.tv_usec,(This->dinput->evsequence)++); - break; - case BTN_THUMB2: - case BTN_C: - case BTN_3: - This->js.rgbButtons[2] = ie.value?0x80:0x00; - GEN_EVENT(DIJOFS_BUTTON(2),ie.value?0x80:0x0,ie.time.tv_usec,(This->dinput->evsequence)++); - break; - case BTN_TOP: - case BTN_X: - case BTN_4: - This->js.rgbButtons[3] = ie.value?0x80:0x00; - GEN_EVENT(DIJOFS_BUTTON(3),ie.value?0x80:0x0,ie.time.tv_usec,(This->dinput->evsequence)++); - break; - case BTN_TOP2: - case BTN_Y: - case BTN_5: - This->js.rgbButtons[4] = ie.value?0x80:0x00; - GEN_EVENT(DIJOFS_BUTTON(4),ie.value?0x80:0x0,ie.time.tv_usec,(This->dinput->evsequence)++); - break; - case BTN_PINKIE: - case BTN_Z: - case BTN_6: - This->js.rgbButtons[5] = ie.value?0x80:0x00; - GEN_EVENT(DIJOFS_BUTTON(5),ie.value?0x80:0x0,ie.time.tv_usec,(This->dinput->evsequence)++); - break; - case BTN_BASE: - case BTN_TL: - case BTN_7: - This->js.rgbButtons[6] = ie.value?0x80:0x00; - GEN_EVENT(DIJOFS_BUTTON(6),ie.value?0x80:0x0,ie.time.tv_usec,(This->dinput->evsequence)++); - break; - case BTN_BASE2: - case BTN_TR: - case BTN_8: - This->js.rgbButtons[7] = ie.value?0x80:0x00; - GEN_EVENT(DIJOFS_BUTTON(7),ie.value?0x80:0x0,ie.time.tv_usec,(This->dinput->evsequence)++); - break; - case BTN_BASE3: - case BTN_TL2: - case BTN_9: - This->js.rgbButtons[8] = ie.value?0x80:0x00; - GEN_EVENT(DIJOFS_BUTTON(8),ie.value?0x80:0x0,ie.time.tv_usec,(This->dinput->evsequence)++); - break; - case BTN_BASE4: - case BTN_TR2: - This->js.rgbButtons[9] = ie.value?0x80:0x00; - GEN_EVENT(DIJOFS_BUTTON(9),ie.value?0x80:0x0,ie.time.tv_usec,(This->dinput->evsequence)++); - break; - case BTN_BASE5: - case BTN_SELECT: - This->js.rgbButtons[10] = ie.value?0x80:0x00; - GEN_EVENT(DIJOFS_BUTTON(10),ie.value?0x80:0x0,ie.time.tv_usec,(This->dinput->evsequence)++); - break; - default: - FIXME("unhandled joystick button %x, value %d\n",ie.code,ie.value); - break; - } - break; + { + int btn = This->buttons[ie.code]; + + TRACE("(%p) %d -> %d\n", This, ie.code, btn); + if (btn & 0x80) + { + btn &= 0x7F; + inst_id = DIDFT_MAKEINSTANCE(btn) | DIDFT_PSHBUTTON; + This->js.rgbButtons[btn] = value = ie.value ? 0x80 : 0x00; + } + break; + } case EV_ABS: + { + int axis = This->axes[ie.code]; + if (axis==-1) { + break; + } + inst_id = DIDFT_MAKEINSTANCE(axis) | (ie.code < ABS_HAT0X ? DIDFT_ABSAXIS : DIDFT_POV); + value = joystick_map_axis(&This->props[id_to_object(This->base.data_format.wine_df, inst_id)], ie.value); + switch (ie.code) { - case ABS_X: - This->js.lX = map_axis(This,ABS_X,ie.value); - GEN_EVENT(DIJOFS_X,This->js.lX,ie.time.tv_usec,(This->dinput->evsequence)++); - break; - case ABS_Y: - This->js.lY = map_axis(This,ABS_Y,ie.value); - GEN_EVENT(DIJOFS_Y,This->js.lY,ie.time.tv_usec,(This->dinput->evsequence)++); - break; - case ABS_Z: - This->js.lZ = map_axis(This,ABS_Z,ie.value); - GEN_EVENT(DIJOFS_Z,This->js.lZ,ie.time.tv_usec,(This->dinput->evsequence)++); - break; - case ABS_RX: - This->js.lRx = map_axis(This,ABS_RX,ie.value); - GEN_EVENT(DIJOFS_RX,This->js.lRx,ie.time.tv_usec,(This->dinput->evsequence)++); - break; - case ABS_RY: - This->js.lRy = map_axis(This,ABS_RY,ie.value); - GEN_EVENT(DIJOFS_RY,This->js.lRy,ie.time.tv_usec,(This->dinput->evsequence)++); - break; - case ABS_RZ: - 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)++); + case ABS_X: This->js.lX = value; break; + case ABS_Y: This->js.lY = value; break; + case ABS_Z: This->js.lZ = value; break; + case ABS_RX: This->js.lRx = value; break; + case ABS_RY: This->js.lRy = value; break; + case ABS_RZ: This->js.lRz = value; break; + case ABS_THROTTLE: This->js.rglSlider[0] = value; break; + case ABS_RUDDER: This->js.rglSlider[1] = value; break; + case ABS_HAT0X: case ABS_HAT0Y: case ABS_HAT1X: case ABS_HAT1Y: + case ABS_HAT2X: case ABS_HAT2Y: case ABS_HAT3X: case ABS_HAT3Y: + { + int idx = (ie.code - ABS_HAT0X) / 2; + + if (ie.code % 2) + This->povs[idx].y = ie.value; + else + This->povs[idx].x = ie.value; + + This->js.rgdwPOV[idx] = value = joystick_map_pov(&This->povs[idx]); break; + } default: - FIXME("unhandled joystick axe event (code %d, value %d)\n",ie.code,ie.value); - break; + FIXME("unhandled joystick axis event (code %d, value %d)\n",ie.code,ie.value); } break; + } #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION case EV_FF_STATUS: This->ff_state = ie.value; break; +#endif +#ifdef EV_SYN + case EV_SYN: + /* there is nothing to do */ + break; #endif default: FIXME("joystick cannot handle type %d event (code %d)\n",ie.type,ie.code); break; } + if (inst_id >= 0) + queue_event((LPDIRECTINPUTDEVICE8A)This, + id_to_offset(&This->base.data_format, inst_id), + value, ie.time.tv_usec, This->base.dinput->evsequence++); } } @@ -810,91 +858,20 @@ static HRESULT WINAPI JoystickAImpl_GetDeviceState( ) { JoystickImpl *This = (JoystickImpl *)iface; + TRACE("(this=%p,0x%08x,%p)\n", This, len, ptr); + + if (!This->base.acquired) + { + WARN("not acquired\n"); + return DIERR_NOTACQUIRED; + } + joy_polldev(This); - TRACE("(this=%p,0x%08lx,%p)\n",This,len,ptr); - if ((len != sizeof(DIJOYSTATE)) && (len != sizeof(DIJOYSTATE2))) { - FIXME("len %ld is not sizeof(DIJOYSTATE) or DIJOYSTATE2, unsupported format.\n",len); - return E_FAIL; - } - memcpy(ptr,&(This->js),len); - This->queue_head = 0; - This->queue_tail = 0; - return 0; -} + /* convert and copy data to user supplied buffer */ + fill_DataFormat(ptr, len, &This->js, &This->base.data_format); -/****************************************************************************** - * GetDeviceData : gets buffered input data. - */ -static HRESULT WINAPI JoystickAImpl_GetDeviceData(LPDIRECTINPUTDEVICE8A iface, - DWORD dodsize, - LPDIDEVICEOBJECTDATA dod, - LPDWORD entries, - DWORD flags -) { - JoystickImpl *This = (JoystickImpl *)iface; - DWORD len; - int nqtail; - HRESULT hr = DI_OK; - - TRACE("(%p)->(dods=%ld,entries=%ld,fl=0x%08lx)\n",This,dodsize,*entries,flags); - - if (This->joyfd==-!1) { - WARN("not acquired\n"); - return DIERR_NOTACQUIRED; - } - - joy_polldev(This); - if (flags & DIGDD_PEEK) - FIXME("DIGDD_PEEK\n"); - - len = ((This->queue_head < This->queue_tail) ? This->queue_len : 0) - + (This->queue_head - This->queue_tail); - if (len > *entries) - len = *entries; - - if (dod == NULL) { - if (len) - TRACE("Application discarding %ld event(s).\n", len); - - *entries = len; - nqtail = This->queue_tail + len; - while (nqtail >= This->queue_len) - nqtail -= This->queue_len; - } else { - if (dodsize < sizeof(DIDEVICEOBJECTDATA_DX3)) { - ERR("Wrong structure size !\n"); - return DIERR_INVALIDPARAM; - } - - if (len) - TRACE("Application retrieving %ld event(s).\n", len); - - *entries = 0; - nqtail = This->queue_tail; - while (len) { - /* Copy the buffered data into the application queue */ - memcpy((char *)dod + *entries * dodsize, This->data_queue + nqtail, dodsize); - /* Advance position */ - nqtail++; - if (nqtail >= This->queue_len) - nqtail -= This->queue_len; - (*entries)++; - len--; - } - } - - if (This->overflow) { - hr = DI_BUFFEROVERFLOW; - if (!(flags & DIGDD_PEEK)) { - This->overflow = FALSE; - } - } - - if (!(flags & DIGDD_PEEK)) - This->queue_tail = nqtail; - - return hr; + return DI_OK; } /****************************************************************************** @@ -912,81 +889,96 @@ static HRESULT WINAPI JoystickAImpl_SetProperty(LPDIRECTINPUTDEVICE8A iface, } TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(rguid),ph); - TRACE("ph.dwSize = %ld, ph.dwHeaderSize =%ld, ph.dwObj = %ld, ph.dwHow= %ld\n",ph->dwSize, ph->dwHeaderSize,ph->dwObj,ph->dwHow); + TRACE("ph.dwSize = %d, ph.dwHeaderSize =%d, ph.dwObj = %d, ph.dwHow= %d\n", + ph->dwSize, ph->dwHeaderSize, ph->dwObj, ph->dwHow); if (!HIWORD(rguid)) { switch (LOWORD(rguid)) { - case (DWORD) DIPROP_BUFFERSIZE: { - LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph; + case (DWORD_PTR)DIPROP_RANGE: { + LPCDIPROPRANGE pr = (LPCDIPROPRANGE)ph; - TRACE("buffersize = %ld\n",pd->dwData); - if (This->data_queue) { - This->data_queue = HeapReAlloc(GetProcessHeap(),0, This->data_queue, pd->dwData * sizeof(DIDEVICEOBJECTDATA)); + if (ph->dwHow == DIPH_DEVICE) { + DWORD i; + TRACE("proprange(%d,%d) all\n", pr->lMin, pr->lMax); + for (i = 0; i < This->base.data_format.wine_df->dwNumObjs; i++) { + /* Scale dead-zone */ + This->props[i].lDeadZone = MulDiv(This->props[i].lDeadZone, pr->lMax - pr->lMin, + This->props[i].lMax - This->props[i].lMin); + This->props[i].lMin = pr->lMin; + This->props[i].lMax = pr->lMax; + } } else { - This->data_queue = HeapAlloc(GetProcessHeap(),0, pd->dwData * sizeof(DIDEVICEOBJECTDATA)); + int obj = find_property(&This->base.data_format, ph); + + TRACE("proprange(%d,%d) obj=%d\n", pr->lMin, pr->lMax, obj); + if (obj >= 0) { + /* Scale dead-zone */ + This->props[obj].lDeadZone = MulDiv(This->props[obj].lDeadZone, pr->lMax - pr->lMin, + This->props[obj].lMax - This->props[obj].lMin); + This->props[obj].lMin = pr->lMin; + This->props[obj].lMax = pr->lMax; + } } - This->queue_head = 0; - This->queue_tail = 0; - This->queue_len = pd->dwData; + fake_current_js_state(This); break; } - case (DWORD)DIPROP_RANGE: { - LPCDIPROPRANGE pr = (LPCDIPROPRANGE)ph; + case (DWORD_PTR)DIPROP_DEADZONE: { + LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph; + if (ph->dwHow == DIPH_DEVICE) { + DWORD i; + TRACE("deadzone(%d) all\n", pd->dwData); + for (i = 0; i < This->base.data_format.wine_df->dwNumObjs; i++) { + This->props[i].lDeadZone = pd->dwData; + } + } else { + int obj = find_property(&This->base.data_format, ph); + + TRACE("deadzone(%d) obj=%d\n", pd->dwData, obj); + if (obj >= 0) { + This->props[obj].lDeadZone = pd->dwData; + } + } + fake_current_js_state(This); + break; + } + case (DWORD_PTR)DIPROP_CALIBRATIONMODE: { + LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph; + FIXME("DIPROP_CALIBRATIONMODE(%d)\n", pd->dwData); + break; + } + case (DWORD_PTR)DIPROP_AUTOCENTER: { + LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph; + + TRACE("autocenter(%d)\n", pd->dwData); + This->ff_autocenter = pd->dwData == DIPROPAUTOCENTER_ON; + + break; + } + case (DWORD_PTR)DIPROP_SATURATION: { + LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph; if (ph->dwHow == DIPH_DEVICE) { - int i; - TRACE("proprange(%ld,%ld) all\n",pr->lMin,pr->lMax); - for (i = 0; i < This->df->dwNumObjs; i++) { - This->wantmin[i] = pr->lMin; - This->wantmax[i] = pr->lMax; - } + DWORD i; + + TRACE("saturation(%d) all\n", pd->dwData); + for (i = 0; i < This->base.data_format.wine_df->dwNumObjs; i++) + This->props[i].lSaturation = pd->dwData; } else { - int obj = find_property_offset(This, ph); - TRACE("proprange(%ld,%ld) obj=%d\n",pr->lMin,pr->lMax,obj); - if (obj >= 0) { - This->wantmin[obj] = pr->lMin; - This->wantmax[obj] = pr->lMax; - } + int obj = find_property(&This->base.data_format, ph); + + if (obj < 0) return DIERR_OBJECTNOTFOUND; + + TRACE("saturation(%d) obj=%d\n", pd->dwData, obj); + This->props[obj].lSaturation = pd->dwData; } - return DI_OK; - } - case (DWORD)DIPROP_DEADZONE: { - LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph; - if (ph->dwHow == DIPH_DEVICE) { - int i; - TRACE("deadzone(%ld) all\n",pd->dwData); - for (i = 0; i < This->df->dwNumObjs; i++) { - This->deadz[i] = pd->dwData; - } - } else { - int obj = find_property_offset(This, ph); - TRACE("deadzone(%ld) obj=%d\n",pd->dwData,obj); - if (obj >= 0) { - This->deadz[obj] = pd->dwData; - } - } - return DI_OK; + fake_current_js_state(This); + break; } default: - FIXME("Unknown type %p (%s)\n",rguid,debugstr_guid(rguid)); - break; + return IDirectInputDevice2AImpl_SetProperty(iface, rguid, ph); } } - fake_current_js_state(This); - return 0; -} - -/****************************************************************************** - * SetEventNotification : specifies event to be sent on state change - */ -static HRESULT WINAPI JoystickAImpl_SetEventNotification( - LPDIRECTINPUTDEVICE8A iface, HANDLE hnd -) { - JoystickImpl *This = (JoystickImpl *)iface; - - TRACE("(this=%p,%p)\n",This,hnd); - This->hEvent = hnd; - return DI_OK; + return DI_OK; } static HRESULT WINAPI JoystickAImpl_GetCapabilities( @@ -994,8 +986,6 @@ static HRESULT WINAPI JoystickAImpl_GetCapabilities( LPDIDEVCAPS lpDIDevCaps) { JoystickImpl *This = (JoystickImpl *)iface; - int xfd = This->joyfd; - int i,axes,buttons; TRACE("%p->(%p)\n",iface,lpDIDevCaps); @@ -1009,246 +999,35 @@ static HRESULT WINAPI JoystickAImpl_GetCapabilities( return DIERR_INVALIDPARAM; } - if (xfd==-1) { - /* yes, games assume we return something, even if unacquired */ - JoystickAImpl_Acquire(iface); - } - lpDIDevCaps->dwFlags = DIDC_ATTACHED; - if (This->dinput->dwVersion >= 0x0800) + if (This->base.dinput->dwVersion >= 0x0800) lpDIDevCaps->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8); else lpDIDevCaps->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8); - axes=0; - for (i=0;iabsbits,i)) axes++; - buttons=0; - for (i=0;ikeybits,i)) buttons++; - - if (This->has_ff) + if (This->joydev->has_ff) lpDIDevCaps->dwFlags |= DIDC_FORCEFEEDBACK; - lpDIDevCaps->dwAxes = axes; - lpDIDevCaps->dwButtons = buttons; - - if (xfd==-1) { - JoystickAImpl_Unacquire(iface); - } + lpDIDevCaps->dwAxes = This->numAxes; + lpDIDevCaps->dwButtons = This->numButtons; + lpDIDevCaps->dwPOVs = This->numPOVs; return DI_OK; } -static HRESULT WINAPI JoystickAImpl_Poll(LPDIRECTINPUTDEVICE8A iface) { +static HRESULT WINAPI JoystickAImpl_Poll(LPDIRECTINPUTDEVICE8A iface) +{ JoystickImpl *This = (JoystickImpl *)iface; + TRACE("(%p)\n",This); - if (This->joyfd==-1) { - return DIERR_NOTACQUIRED; - } + if (!This->base.acquired) + return DIERR_NOTACQUIRED; joy_polldev(This); return DI_OK; } -/****************************************************************************** - * EnumObjects : enumerate the different buttons and axis... - */ -static HRESULT WINAPI JoystickAImpl_EnumObjects( - LPDIRECTINPUTDEVICE8A iface, - LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback, - LPVOID lpvRef, - DWORD dwFlags) -{ - JoystickImpl *This = (JoystickImpl *)iface; - DIDEVICEOBJECTINSTANCEA ddoi; - int xfd = This->joyfd; - - TRACE("(this=%p,%p,%p,%08lx)\n", This, lpCallback, lpvRef, dwFlags); - if (TRACE_ON(dinput)) { - TRACE(" - flags = "); - _dump_EnumObjects_flags(dwFlags); - TRACE("\n"); - } - - /* 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); - - /* For the joystick, do as is done in the GetCapabilities function */ - /* FIXME: needs more items */ - if ((dwFlags == DIDFT_ALL) || - (dwFlags & DIDFT_AXIS)) { - BYTE i; - - for (i = 0; i < ABS_MAX; i++) { - if (!test_bit(This->absbits,i)) continue; - - switch (i) { - case ABS_X: - ddoi.guidType = GUID_XAxis; - ddoi.dwOfs = DIJOFS_X; - break; - case ABS_Y: - ddoi.guidType = GUID_YAxis; - ddoi.dwOfs = DIJOFS_Y; - break; - case ABS_Z: - ddoi.guidType = GUID_ZAxis; - ddoi.dwOfs = DIJOFS_Z; - break; - case ABS_RX: - ddoi.guidType = GUID_RxAxis; - ddoi.dwOfs = DIJOFS_RX; - break; - case ABS_RY: - ddoi.guidType = GUID_RyAxis; - ddoi.dwOfs = DIJOFS_RY; - break; - case ABS_RZ: - ddoi.guidType = GUID_RzAxis; - ddoi.dwOfs = DIJOFS_RZ; - break; - case ABS_THROTTLE: - 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 to unaquired state if that's where we were */ - if (xfd == -1) - IDirectInputDevice8_Unacquire(iface); - return DI_OK; - } - } - } - - if ((dwFlags == DIDFT_ALL) || - (dwFlags & DIDFT_BUTTON)) { - int i; - - /*The DInput SDK says that GUID_Button is only for mouse buttons but well*/ - - ddoi.guidType = GUID_Button; - - for (i = 0; i < KEY_MAX; i++) { - if (!test_bit(This->keybits,i)) continue; - - switch (i) { - case BTN_TRIGGER: - case BTN_A: - case BTN_1: - ddoi.dwOfs = DIJOFS_BUTTON(0); - ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 0) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON; - break; - case BTN_THUMB: - case BTN_B: - case BTN_2: - ddoi.dwOfs = DIJOFS_BUTTON(1); - ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 1) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON; - break; - case BTN_THUMB2: - case BTN_C: - case BTN_3: - ddoi.dwOfs = DIJOFS_BUTTON(2); - ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 2) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON; - break; - case BTN_TOP: - case BTN_X: - case BTN_4: - ddoi.dwOfs = DIJOFS_BUTTON(3); - ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 3) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON; - break; - case BTN_TOP2: - case BTN_Y: - case BTN_5: - ddoi.dwOfs = DIJOFS_BUTTON(4); - ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 4) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON; - break; - case BTN_PINKIE: - case BTN_Z: - case BTN_6: - ddoi.dwOfs = DIJOFS_BUTTON(5); - ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 5) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON; - break; - case BTN_BASE: - case BTN_TL: - case BTN_7: - ddoi.dwOfs = DIJOFS_BUTTON(6); - ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 6) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON; - break; - case BTN_BASE2: - case BTN_TR: - case BTN_8: - ddoi.dwOfs = DIJOFS_BUTTON(7); - ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 7) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON; - break; - case BTN_BASE3: - case BTN_TL2: - case BTN_9: - ddoi.dwOfs = DIJOFS_BUTTON(8); - ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 8) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON; - break; - case BTN_BASE4: - case BTN_TR2: - ddoi.dwOfs = DIJOFS_BUTTON(9); - ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 9) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON; - break; - case BTN_BASE5: - case BTN_SELECT: - ddoi.dwOfs = DIJOFS_BUTTON(10); - ddoi.dwType = DIDFT_MAKEINSTANCE((0x0001 << 10) << WINE_JOYSTICK_BUTTON_BASE) | DIDFT_PSHBUTTON; - break; - } - sprintf(ddoi.tszName, "%d-Button", i); - _dump_OBJECTINSTANCEA(&ddoi); - 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; - } - } - } - - /* return to unaquired state if that's where we were */ - if (xfd == -1) - IDirectInputDevice8_Unacquire(iface); - - return DI_OK; -} - -static HRESULT WINAPI JoystickWImpl_EnumObjects(LPDIRECTINPUTDEVICE8W iface, - LPDIENUMDEVICEOBJECTSCALLBACKW lpCallback, - LPVOID lpvRef, - DWORD dwFlags) -{ - JoystickImpl *This = (JoystickImpl *)iface; - - device_enumobjects_AtoWcb_data data; - - data.lpCallBack = lpCallback; - data.lpvRef = lpvRef; - - return JoystickAImpl_EnumObjects((LPDIRECTINPUTDEVICE8A) This, (LPDIENUMDEVICEOBJECTSCALLBACKA) DIEnumDevicesCallbackAtoW, (LPVOID) &data, dwFlags); -} - /****************************************************************************** * GetProperty : get input device properties */ @@ -1256,46 +1035,111 @@ static HRESULT WINAPI JoystickAImpl_GetProperty(LPDIRECTINPUTDEVICE8A iface, REFGUID rguid, LPDIPROPHEADER pdiph) { - JoystickImpl *This = (JoystickImpl *)iface; + JoystickImpl *This = (JoystickImpl *)iface; - TRACE("(this=%p,%s,%p)\n", - iface, debugstr_guid(rguid), pdiph); - - if (TRACE_ON(dinput)) + TRACE("(this=%p,%s,%p)\n", iface, debugstr_guid(rguid), pdiph); _dump_DIPROPHEADER(pdiph); - if (!HIWORD(rguid)) { + if (HIWORD(rguid)) return DI_OK; + switch (LOWORD(rguid)) { - case (DWORD) DIPROP_BUFFERSIZE: { - LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph; + case (DWORD_PTR) DIPROP_RANGE: + { + LPDIPROPRANGE pr = (LPDIPROPRANGE) pdiph; + int obj = find_property(&This->base.data_format, pdiph); - TRACE(" return buffersize = %d\n",This->queue_len); - pd->dwData = This->queue_len; - break; + if (obj < 0) return DIERR_OBJECTNOTFOUND; + + pr->lMin = This->props[obj].lMin; + pr->lMax = This->props[obj].lMax; + TRACE("range(%d, %d) obj=%d\n", pr->lMin, pr->lMax, obj); + break; } + case (DWORD_PTR) DIPROP_DEADZONE: + { + LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph; + int obj = find_property(&This->base.data_format, pdiph); - case (DWORD) DIPROP_RANGE: { - /* LPDIPROPRANGE pr = (LPDIPROPRANGE) pdiph; */ - if ((pdiph->dwHow == DIPH_BYID) && - (pdiph->dwObj & DIDFT_ABSAXIS)) { - /* The app is querying the current range of the axis : return the lMin and lMax values */ - FIXME("unimplemented axis range query.\n"); - } + if (obj < 0) return DIERR_OBJECTNOTFOUND; - break; + pd->dwData = This->props[obj].lDeadZone; + TRACE("deadzone(%d) obj=%d\n", pd->dwData, obj); + break; + } + case (DWORD_PTR) DIPROP_SATURATION: + { + LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph; + int obj = find_property(&This->base.data_format, pdiph); + + if (obj < 0) return DIERR_OBJECTNOTFOUND; + + pd->dwData = This->props[obj].lSaturation; + TRACE("saturation(%d) obj=%d\n", pd->dwData, obj); + break; + } + case (DWORD_PTR) DIPROP_AUTOCENTER: + { + LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph; + + pd->dwData = This->ff_autocenter ? DIPROPAUTOCENTER_ON : DIPROPAUTOCENTER_OFF; + TRACE("autocenter(%d)\n", pd->dwData); + break; } default: - FIXME("Unknown type %p (%s)\n",rguid,debugstr_guid(rguid)); - break; + return IDirectInputDevice2AImpl_GetProperty(iface, rguid, pdiph); } - } - - return DI_OK; + return DI_OK; } /****************************************************************************** + * GetObjectInfo : get information about a device object such as a button + * or axis + */ +static HRESULT WINAPI JoystickWImpl_GetObjectInfo(LPDIRECTINPUTDEVICE8W iface, + LPDIDEVICEOBJECTINSTANCEW pdidoi, DWORD dwObj, DWORD dwHow) +{ + static const WCHAR axisW[] = {'A','x','i','s',' ','%','d',0}; + static const WCHAR povW[] = {'P','O','V',' ','%','d',0}; + static const WCHAR buttonW[] = {'B','u','t','t','o','n',' ','%','d',0}; + HRESULT res; + + res = IDirectInputDevice2WImpl_GetObjectInfo(iface, pdidoi, dwObj, dwHow); + if (res != DI_OK) return res; + + if (pdidoi->dwType & DIDFT_AXIS) + sprintfW(pdidoi->tszName, axisW, DIDFT_GETINSTANCE(pdidoi->dwType)); + else if (pdidoi->dwType & DIDFT_POV) + sprintfW(pdidoi->tszName, povW, DIDFT_GETINSTANCE(pdidoi->dwType)); + else if (pdidoi->dwType & DIDFT_BUTTON) + sprintfW(pdidoi->tszName, buttonW, DIDFT_GETINSTANCE(pdidoi->dwType)); + + _dump_OBJECTINSTANCEW(pdidoi); + return res; +} + +static HRESULT WINAPI JoystickAImpl_GetObjectInfo(LPDIRECTINPUTDEVICE8A iface, + LPDIDEVICEOBJECTINSTANCEA pdidoi, DWORD dwObj, DWORD dwHow) +{ + HRESULT res; + DIDEVICEOBJECTINSTANCEW didoiW; + DWORD dwSize = pdidoi->dwSize; + + didoiW.dwSize = sizeof(didoiW); + res = JoystickWImpl_GetObjectInfo((LPDIRECTINPUTDEVICE8W)iface, &didoiW, dwObj, dwHow); + if (res != DI_OK) return res; + + memset(pdidoi, 0, pdidoi->dwSize); + memcpy(pdidoi, &didoiW, FIELD_OFFSET(DIDEVICEOBJECTINSTANCEW, tszName)); + pdidoi->dwSize = dwSize; + WideCharToMultiByte(CP_ACP, 0, didoiW.tszName, -1, pdidoi->tszName, + sizeof(pdidoi->tszName), NULL, NULL); + + return res; +} + +/****************************************************************************** * CreateEffect - Create a new FF effect with the specified params */ static HRESULT WINAPI JoystickAImpl_CreateEffect(LPDIRECTINPUTDEVICE8A iface, @@ -1305,7 +1149,7 @@ static HRESULT WINAPI JoystickAImpl_CreateEffect(LPDIRECTINPUTDEVICE8A iface, LPUNKNOWN pUnkOuter) { #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION - EffectListItem* new = NULL; + effect_list_item* new_effect = NULL; HRESULT retval = DI_OK; #endif @@ -1318,20 +1162,29 @@ static HRESULT WINAPI JoystickAImpl_CreateEffect(LPDIRECTINPUTDEVICE8A iface, return DI_OK; #else - new = malloc(sizeof(EffectListItem)); - new->next = This->top_effect; - This->top_effect = new; + if (!(new_effect = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_effect)))) + return DIERR_OUTOFMEMORY; - retval = linuxinput_create_effect(&(This->joyfd), rguid, &(new->ref)); + retval = linuxinput_create_effect(&This->joyfd, rguid, &new_effect->entry, &new_effect->ref); if (retval != DI_OK) - return retval; + { + HeapFree(GetProcessHeap(), 0, new_effect); + return retval; + } if (lpeff != NULL) - retval = IDirectInputEffect_SetParameters(new->ref, lpeff, 0); - if (retval != DI_OK && retval != DI_DOWNLOADSKIPPED) - return retval; + { + retval = IDirectInputEffect_SetParameters(new_effect->ref, lpeff, 0); - *ppdef = new->ref; + if (retval != DI_OK && retval != DI_DOWNLOADSKIPPED) + { + HeapFree(GetProcessHeap(), 0, new_effect); + return retval; + } + } + + list_add_tail(&This->ff_effects, &new_effect->entry); + *ppdef = new_effect->ref; if (pUnkOuter != NULL) FIXME("Interface aggregation not implemented.\n"); @@ -1339,7 +1192,7 @@ static HRESULT WINAPI JoystickAImpl_CreateEffect(LPDIRECTINPUTDEVICE8A iface, return DI_OK; #endif /* HAVE_STRUCT_FF_EFFECT_DIRECTION */ -} +} /******************************************************************************* * EnumEffects - Enumerate available FF effects @@ -1353,74 +1206,66 @@ static HRESULT WINAPI JoystickAImpl_EnumEffects(LPDIRECTINPUTDEVICE8A iface, 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); + TRACE("(this=%p,%p,%d) type=%d\n", This, pvRef, dwEffType, type); - dei.dwSize = sizeof(DIEFFECTINFOA); - - /* We need to return something even if we're not yet acquired */ - if (xfd == -1) - IDirectInputDevice8_Acquire(iface); + dei.dwSize = sizeof(DIEFFECTINFOA); if ((type == DIEFT_ALL || type == DIEFT_CONSTANTFORCE) - && test_bit(This->ffbits, FF_CONSTANT)) { + && test_bit(This->joydev->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)) { + && test_bit(This->joydev->ffbits, FF_PERIODIC)) { + if (test_bit(This->joydev->ffbits, FF_SQUARE)) { IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Square); (*lpCallback)(&dei, pvRef); } - if (test_bit(This->ffbits, FF_SINE)) { + if (test_bit(This->joydev->ffbits, FF_SINE)) { IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Sine); (*lpCallback)(&dei, pvRef); } - if (test_bit(This->ffbits, FF_TRIANGLE)) { + if (test_bit(This->joydev->ffbits, FF_TRIANGLE)) { IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Triangle); (*lpCallback)(&dei, pvRef); } - if (test_bit(This->ffbits, FF_SAW_UP)) { + if (test_bit(This->joydev->ffbits, FF_SAW_UP)) { IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_SawtoothUp); (*lpCallback)(&dei, pvRef); } - if (test_bit(This->ffbits, FF_SAW_DOWN)) { + if (test_bit(This->joydev->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)) { + && test_bit(This->joydev->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)) { + if (test_bit(This->joydev->ffbits, FF_SPRING)) { IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Spring); (*lpCallback)(&dei, pvRef); } - if (test_bit(This->ffbits, FF_DAMPER)) { + if (test_bit(This->joydev->ffbits, FF_DAMPER)) { IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Damper); (*lpCallback)(&dei, pvRef); } - if (test_bit(This->ffbits, FF_INERTIA)) { + if (test_bit(This->joydev->ffbits, FF_INERTIA)) { IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Inertia); (*lpCallback)(&dei, pvRef); } - if (test_bit(This->ffbits, FF_FRICTION)) { + if (test_bit(This->joydev->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; @@ -1439,70 +1284,66 @@ static HRESULT WINAPI JoystickWImpl_EnumEffects(LPDIRECTINPUTDEVICE8W iface, JoystickImpl* This = (JoystickImpl*)iface; int xfd = This->joyfd; - TRACE("(this=%p,%p,%ld) type=%ld fd=%d\n", This, pvRef, dwEffType, type, xfd); + TRACE("(this=%p,%p,%d) type=%d 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); + dei.dwSize = sizeof(DIEFFECTINFOW); if ((type == DIEFT_ALL || type == DIEFT_CONSTANTFORCE) - && test_bit(This->ffbits, FF_CONSTANT)) { + && test_bit(This->joydev->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)) { + && test_bit(This->joydev->ffbits, FF_PERIODIC)) { + if (test_bit(This->joydev->ffbits, FF_SQUARE)) { IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Square); (*lpCallback)(&dei, pvRef); } - if (test_bit(This->ffbits, FF_SINE)) { + if (test_bit(This->joydev->ffbits, FF_SINE)) { IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Sine); (*lpCallback)(&dei, pvRef); } - if (test_bit(This->ffbits, FF_TRIANGLE)) { + if (test_bit(This->joydev->ffbits, FF_TRIANGLE)) { IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Triangle); (*lpCallback)(&dei, pvRef); } - if (test_bit(This->ffbits, FF_SAW_UP)) { + if (test_bit(This->joydev->ffbits, FF_SAW_UP)) { IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_SawtoothUp); (*lpCallback)(&dei, pvRef); } - if (test_bit(This->ffbits, FF_SAW_DOWN)) { + if (test_bit(This->joydev->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)) { + && test_bit(This->joydev->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)) { + if (test_bit(This->joydev->ffbits, FF_SPRING)) { IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Spring); (*lpCallback)(&dei, pvRef); } - if (test_bit(This->ffbits, FF_DAMPER)) { + if (test_bit(This->joydev->ffbits, FF_DAMPER)) { IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Damper); (*lpCallback)(&dei, pvRef); } - if (test_bit(This->ffbits, FF_INERTIA)) { + if (test_bit(This->joydev->ffbits, FF_INERTIA)) { IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Inertia); (*lpCallback)(&dei, pvRef); } - if (test_bit(This->ffbits, FF_FRICTION)) { + if (test_bit(This->joydev->ffbits, FF_FRICTION)) { IDirectInputDevice8_GetEffectInfo(iface, &dei, &GUID_Friction); (*lpCallback)(&dei, pvRef); } } - /* return to unaquired state if that's where it was */ + /* return to unacquired state if that's where it was */ if (xfd == -1) IDirectInputDevice8_Unacquire(iface); #endif @@ -1511,7 +1352,7 @@ static HRESULT WINAPI JoystickWImpl_EnumEffects(LPDIRECTINPUTDEVICE8W iface, } /******************************************************************************* - * GetEffectInfo - Get information about a particular effect + * GetEffectInfo - Get information about a particular effect */ static HRESULT WINAPI JoystickAImpl_GetEffectInfo(LPDIRECTINPUTDEVICE8A iface, LPDIEFFECTINFOA pdei, @@ -1522,7 +1363,7 @@ static HRESULT WINAPI JoystickAImpl_GetEffectInfo(LPDIRECTINPUTDEVICE8A 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); + return linuxinput_get_info_A(This->joyfd, guid, pdei); #else return DI_OK; #endif @@ -1533,9 +1374,9 @@ static HRESULT WINAPI JoystickWImpl_GetEffectInfo(LPDIRECTINPUTDEVICE8W iface, 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 @@ -1544,7 +1385,7 @@ static HRESULT WINAPI JoystickWImpl_GetEffectInfo(LPDIRECTINPUTDEVICE8W iface, } /******************************************************************************* - * GetForceFeedbackState - Get information about the device's FF state + * GetForceFeedbackState - Get information about the device's FF state */ static HRESULT WINAPI JoystickAImpl_GetForceFeedbackState( LPDIRECTINPUTDEVICE8A iface, @@ -1573,33 +1414,42 @@ static HRESULT WINAPI JoystickAImpl_SendForceFeedbackCommand( DWORD dwFlags) { JoystickImpl* This = (JoystickImpl*)iface; - TRACE("(this=%p,%ld)\n", This, dwFlags); + TRACE("(this=%p,%d)\n", This, dwFlags); #ifdef HAVE_STRUCT_FF_EFFECT_DIRECTION - if (dwFlags == DISFFC_STOPALL) { + switch (dwFlags) + { + case DISFFC_STOPALL: + { /* Stop all effects */ - EffectListItem* itr = This->top_effect; - while (itr) { - IDirectInputEffect_Stop(itr->ref); - itr = itr->next; - } - } else if (dwFlags == DISFFC_RESET) { + effect_list_item *itr; + + LIST_FOR_EACH_ENTRY(itr, &This->ff_effects, effect_list_item, entry) + IDirectInputEffect_Stop(itr->ref); + break; + } + + case DISFFC_RESET: + { + effect_list_item *itr, *ptr; + /* 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) { + LIST_FOR_EACH_ENTRY_SAFE(itr, ptr, &This->ff_effects, effect_list_item, entry) + IDirectInputEffect_Release(itr->ref); + break; + } + case DISFFC_PAUSE: + case 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 { + break; + + case DISFFC_SETACTUATORSOFF: + case DISFFC_SETACTUATORSON: + FIXME("No direct actuator control in linux\n"); + break; + + default: FIXME("Unknown Force Feedback Command!\n"); return DIERR_INVALIDPARAM; } @@ -1620,43 +1470,78 @@ static HRESULT WINAPI JoystickAImpl_EnumCreatedEffectObjects( 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); + effect_list_item *itr, *ptr; + + TRACE("(this=%p,%p,%p,%d)\n", This, lpCallback, pvRef, dwFlags); if (!lpCallback) return DIERR_INVALIDPARAM; if (dwFlags != 0) - FIXME("Flags specified, but no flags exist yet (DX9)!"); + FIXME("Flags specified, but no flags exist yet (DX9)!\n"); - while (itr) { - (*lpCallback)(itr->ref, pvRef); - itr = itr->next; - } + LIST_FOR_EACH_ENTRY_SAFE(itr, ptr, &This->ff_effects, effect_list_item, entry) + (*lpCallback)(itr->ref, pvRef); return DI_OK; } +/****************************************************************************** + * GetDeviceInfo : get information about a device's identity + */ +static HRESULT WINAPI JoystickAImpl_GetDeviceInfo(LPDIRECTINPUTDEVICE8A iface, + LPDIDEVICEINSTANCEA pdidi) +{ + JoystickImpl *This = (JoystickImpl *)iface; + + TRACE("(%p) %p\n", This, pdidi); + + if (pdidi == NULL) return E_POINTER; + if ((pdidi->dwSize != sizeof(DIDEVICEINSTANCE_DX3A)) && + (pdidi->dwSize != sizeof(DIDEVICEINSTANCEA))) + return DIERR_INVALIDPARAM; + + fill_joystick_dideviceinstanceA(pdidi, This->base.dinput->dwVersion, + get_joystick_index(&This->base.guid)); + return DI_OK; +} + +static HRESULT WINAPI JoystickWImpl_GetDeviceInfo(LPDIRECTINPUTDEVICE8W iface, + LPDIDEVICEINSTANCEW pdidi) +{ + JoystickImpl *This = (JoystickImpl *)iface; + + TRACE("(%p) %p\n", This, pdidi); + + if (pdidi == NULL) return E_POINTER; + if ((pdidi->dwSize != sizeof(DIDEVICEINSTANCE_DX3W)) && + (pdidi->dwSize != sizeof(DIDEVICEINSTANCEW))) + return DIERR_INVALIDPARAM; + + fill_joystick_dideviceinstanceW(pdidi, This->base.dinput->dwVersion, + get_joystick_index(&This->base.guid)); + return DI_OK; +} + static const IDirectInputDevice8AVtbl JoystickAvt = { IDirectInputDevice2AImpl_QueryInterface, IDirectInputDevice2AImpl_AddRef, - JoystickAImpl_Release, + IDirectInputDevice2AImpl_Release, JoystickAImpl_GetCapabilities, - JoystickAImpl_EnumObjects, + IDirectInputDevice2AImpl_EnumObjects, JoystickAImpl_GetProperty, JoystickAImpl_SetProperty, JoystickAImpl_Acquire, JoystickAImpl_Unacquire, JoystickAImpl_GetDeviceState, - JoystickAImpl_GetDeviceData, - JoystickAImpl_SetDataFormat, - JoystickAImpl_SetEventNotification, + IDirectInputDevice2AImpl_GetDeviceData, + IDirectInputDevice2AImpl_SetDataFormat, + IDirectInputDevice2AImpl_SetEventNotification, IDirectInputDevice2AImpl_SetCooperativeLevel, - IDirectInputDevice2AImpl_GetObjectInfo, - IDirectInputDevice2AImpl_GetDeviceInfo, + JoystickAImpl_GetObjectInfo, + JoystickAImpl_GetDeviceInfo, IDirectInputDevice2AImpl_RunControlPanel, IDirectInputDevice2AImpl_Initialize, JoystickAImpl_CreateEffect, @@ -1685,20 +1570,20 @@ static const IDirectInputDevice8WVtbl JoystickWvt = { IDirectInputDevice2WImpl_QueryInterface, XCAST(AddRef)IDirectInputDevice2AImpl_AddRef, - XCAST(Release)JoystickAImpl_Release, + XCAST(Release)IDirectInputDevice2AImpl_Release, XCAST(GetCapabilities)JoystickAImpl_GetCapabilities, - JoystickWImpl_EnumObjects, + IDirectInputDevice2WImpl_EnumObjects, XCAST(GetProperty)JoystickAImpl_GetProperty, XCAST(SetProperty)JoystickAImpl_SetProperty, XCAST(Acquire)JoystickAImpl_Acquire, XCAST(Unacquire)JoystickAImpl_Unacquire, XCAST(GetDeviceState)JoystickAImpl_GetDeviceState, - XCAST(GetDeviceData)JoystickAImpl_GetDeviceData, - XCAST(SetDataFormat)JoystickAImpl_SetDataFormat, - XCAST(SetEventNotification)JoystickAImpl_SetEventNotification, + XCAST(GetDeviceData)IDirectInputDevice2AImpl_GetDeviceData, + XCAST(SetDataFormat)IDirectInputDevice2AImpl_SetDataFormat, + XCAST(SetEventNotification)IDirectInputDevice2AImpl_SetEventNotification, XCAST(SetCooperativeLevel)IDirectInputDevice2AImpl_SetCooperativeLevel, - IDirectInputDevice2WImpl_GetObjectInfo, - IDirectInputDevice2WImpl_GetDeviceInfo, + JoystickWImpl_GetObjectInfo, + JoystickWImpl_GetDeviceInfo, XCAST(RunControlPanel)IDirectInputDevice2AImpl_RunControlPanel, XCAST(Initialize)IDirectInputDevice2AImpl_Initialize, XCAST(CreateEffect)JoystickAImpl_CreateEffect, diff --git a/reactos/dll/directx/dinput/keyboard.c b/reactos/dll/directx/dinput/keyboard.c index f8bc71aaaa5..47536f7f68e 100644 --- a/reactos/dll/directx/dinput/keyboard.c +++ b/reactos/dll/directx/dinput/keyboard.c @@ -17,7 +17,7 @@ * * 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 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include "config.h" @@ -46,122 +46,79 @@ static const IDirectInputDevice8WVtbl SysKeyboardWvt; typedef struct SysKeyboardImpl SysKeyboardImpl; struct SysKeyboardImpl { - const void *lpVtbl; - LONG ref; - GUID guid; - - IDirectInputImpl* dinput; - - HANDLE hEvent; - /* SysKeyboardAImpl */ - int acquired; - int buffersize; /* set in 'SetProperty' */ - LPDIDEVICEOBJECTDATA buffer; /* buffer for 'GetDeviceData'. - Alloc at 'Acquire', Free at - 'Unacquire' */ - int count; /* number of objects in use in - 'buffer' */ - int start; /* 'buffer' rotates. This is the - first in use (if count > 0) */ - BOOL overflow; /* return DI_BUFFEROVERFLOW in - 'GetDeviceData' */ - CRITICAL_SECTION crit; + struct IDirectInputDevice2AImpl base; + BYTE DInputKeyState[WINE_DINPUT_KEYBOARD_MAX_KEYS]; }; -static SysKeyboardImpl* current_lock = NULL; -/* Today's acquired device - * FIXME: currently this can be only one. - * Maybe this should be a linked list or st. - * I don't know what the rules are for multiple acquired keyboards, - * but 'DI_LOSTFOCUS' and 'DI_UNACQUIRED' exist for a reason. -*/ - -static BYTE DInputKeyState[WINE_DINPUT_KEYBOARD_MAX_KEYS]; /* array for 'GetDeviceState' */ - -static CRITICAL_SECTION keyboard_crit; -static CRITICAL_SECTION_DEBUG critsect_debug = +static BYTE map_dik_code(DWORD scanCode, DWORD vkCode) { - 0, 0, &keyboard_crit, - { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList }, - 0, 0, { (DWORD_PTR)(__FILE__ ": keyboard_crit") } -}; -static CRITICAL_SECTION keyboard_crit = { &critsect_debug, -1, 0, 0, 0, 0 }; + static const BYTE asciiCodes[] = + {/*32*/ DIK_SPACE,0,0,0,0,0,0,DIK_APOSTROPHE, + /*40*/ 0,0,0,0,DIK_COMMA,DIK_MINUS,DIK_PERIOD,DIK_SLASH, + /*48*/ DIK_0,DIK_1,DIK_2,DIK_3,DIK_4,DIK_5,DIK_6,DIK_7, + /*56*/ DIK_8,DIK_9,DIK_COLON,DIK_SEMICOLON,0,DIK_EQUALS,0,0, + /*64*/ DIK_AT,DIK_A,DIK_B,DIK_C,DIK_D,DIK_E,DIK_F,DIK_G, + /*72*/ DIK_H,DIK_I,DIK_J,DIK_K,DIK_L,DIK_M,DIK_N,DIK_O, + /*80*/ DIK_P,DIK_Q,DIK_R,DIK_S,DIK_T,DIK_U,DIK_V,DIK_W, + /*88*/ DIK_X,DIK_Y,DIK_Z,DIK_LBRACKET,0,DIK_RBRACKET,DIK_CIRCUMFLEX,DIK_UNDERLINE} /*95*/ ; -static LONG keyboard_users = 0; -static HHOOK keyboard_hook = NULL; + BYTE out_code = 0; + WCHAR c = MapVirtualKeyW(vkCode,MAPVK_VK_TO_CHAR); -LRESULT CALLBACK KeyboardCallback( int code, WPARAM wparam, LPARAM lparam ) -{ - BYTE dik_code; - BOOL down; - DWORD timestamp; - KBDLLHOOKSTRUCT *hook = (KBDLLHOOKSTRUCT *)lparam; - BYTE new_diks; + if (c > 31 && c < 96) + out_code = asciiCodes[c - 32]; - TRACE("(%d,%d,%ld)\n", code, wparam, lparam); + if (out_code == 0) + out_code = scanCode; - /** returns now if not HC_ACTION */ - if (code != HC_ACTION) return CallNextHookEx(keyboard_hook, code, wparam, lparam); - - { - dik_code = hook->scanCode; - if (hook->flags & LLKHF_EXTENDED) dik_code |= 0x80; - down = !(hook->flags & LLKHF_UP); - timestamp = hook->time; - } - - /** returns now if key event already known */ - new_diks = (down ? 0x80 : 0); - /*if (new_diks != DInputKeyState[dik_code]) return CallNextHookEx(keyboard_hook, code, wparam, lparam); TO BE FIXED */ - - DInputKeyState[dik_code] = new_diks; - TRACE(" setting %02X to %02X\n", dik_code, DInputKeyState[dik_code]); - - if (current_lock != NULL) { - if (current_lock->hEvent) SetEvent(current_lock->hEvent); - - if (current_lock->buffer != NULL) { - int n; - - EnterCriticalSection(&(current_lock->crit)); - - n = (current_lock->start + current_lock->count) % current_lock->buffersize; - - current_lock->buffer[n].dwOfs = dik_code; - current_lock->buffer[n].dwData = down ? 0x80 : 0; - current_lock->buffer[n].dwTimeStamp = timestamp; - current_lock->buffer[n].dwSequence = current_lock->dinput->evsequence++; - - TRACE("Adding event at offset %d : %ld - %ld - %ld - %ld\n", n, - current_lock->buffer[n].dwOfs, current_lock->buffer[n].dwData, current_lock->buffer[n].dwTimeStamp, current_lock->buffer[n].dwSequence); - - if (current_lock->count == current_lock->buffersize) { - current_lock->start = ++current_lock->start % current_lock->buffersize; - current_lock->overflow = TRUE; - } else - current_lock->count++; - - LeaveCriticalSection(&(current_lock->crit)); - } - } - return CallNextHookEx(keyboard_hook, code, wparam, lparam); + return out_code; } -static GUID DInput_Wine_Keyboard_GUID = { /* 0ab8648a-7735-11d2-8c73-71df54a96441 */ - 0x0ab8648a, - 0x7735, - 0x11d2, - {0x8c, 0x73, 0x71, 0xdf, 0x54, 0xa9, 0x64, 0x41} +static void KeyboardCallback( LPDIRECTINPUTDEVICE8A iface, WPARAM wparam, LPARAM lparam ) +{ + SysKeyboardImpl *This = (SysKeyboardImpl *)iface; + int dik_code; + KBDLLHOOKSTRUCT *hook = (KBDLLHOOKSTRUCT *)lparam; + BYTE new_diks; + + if (wparam != WM_KEYDOWN && wparam != WM_KEYUP && + wparam != WM_SYSKEYDOWN && wparam != WM_SYSKEYUP) + return; + + TRACE("(%p) %ld,%ld\n", iface, wparam, lparam); + + dik_code = map_dik_code(hook->scanCode & 0xff,hook->vkCode); + /* R-Shift is special - it is an extended key with separate scan code */ + if (hook->flags & LLKHF_EXTENDED && dik_code != 0x36) + dik_code |= 0x80; + + new_diks = hook->flags & LLKHF_UP ? 0 : 0x80; + + /* returns now if key event already known */ + if (new_diks == This->DInputKeyState[dik_code]) + return; + + This->DInputKeyState[dik_code] = new_diks; + TRACE(" setting %02X to %02X\n", dik_code, This->DInputKeyState[dik_code]); + + dik_code = id_to_offset(&This->base.data_format, DIDFT_MAKEINSTANCE(dik_code) | DIDFT_PSHBUTTON); + EnterCriticalSection(&This->base.crit); + queue_event((LPDIRECTINPUTDEVICE8A)This, dik_code, new_diks, hook->time, This->base.dinput->evsequence++); + LeaveCriticalSection(&This->base.crit); +} + +const GUID DInput_Wine_Keyboard_GUID = { /* 0ab8648a-7735-11d2-8c73-71df54a96441 */ + 0x0ab8648a, 0x7735, 0x11d2, {0x8c, 0x73, 0x71, 0xdf, 0x54, 0xa9, 0x64, 0x41} }; static void fill_keyboard_dideviceinstanceA(LPDIDEVICEINSTANCEA lpddi, DWORD version) { DWORD dwSize; DIDEVICEINSTANCEA ddi; - + dwSize = lpddi->dwSize; - TRACE("%ld %p\n", dwSize, lpddi); - + TRACE("%d %p\n", dwSize, lpddi); + memset(lpddi, 0, dwSize); memset(&ddi, 0, sizeof(ddi)); @@ -181,14 +138,14 @@ static void fill_keyboard_dideviceinstanceA(LPDIDEVICEINSTANCEA lpddi, DWORD ver static void fill_keyboard_dideviceinstanceW(LPDIDEVICEINSTANCEW lpddi, DWORD version) { DWORD dwSize; DIDEVICEINSTANCEW ddi; - + dwSize = lpddi->dwSize; - TRACE("%ld %p\n", dwSize, lpddi); - + TRACE("%d %p\n", dwSize, lpddi); + memset(lpddi, 0, dwSize); memset(&ddi, 0, sizeof(ddi)); - + ddi.dwSize = dwSize; ddi.guidInstance = GUID_SysKeyboard;/* DInput's GUID */ ddi.guidProduct = DInput_Wine_Keyboard_GUID; /* Vendor's GUID */ @@ -201,7 +158,7 @@ static void fill_keyboard_dideviceinstanceW(LPDIDEVICEINSTANCEW lpddi, DWORD ver memcpy(lpddi, &ddi, (dwSize < sizeof(ddi) ? dwSize : sizeof(ddi))); } - + static BOOL keyboarddev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, DWORD version, int id) { if (id != 0) @@ -211,9 +168,9 @@ static BOOL keyboarddev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEI ((dwDevType == DIDEVTYPE_KEYBOARD) && (version < 0x0800)) || (((dwDevType == DI8DEVCLASS_KEYBOARD) || (dwDevType == DI8DEVTYPE_KEYBOARD)) && (version >= 0x0800))) { TRACE("Enumerating the Keyboard device\n"); - + fill_keyboard_dideviceinstanceA(lpddi, version); - + return TRUE; } @@ -231,7 +188,7 @@ static BOOL keyboarddev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEI TRACE("Enumerating the Keyboard device\n"); fill_keyboard_dideviceinstanceW(lpddi, version); - + return TRUE; } @@ -241,23 +198,44 @@ static BOOL keyboarddev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEI static SysKeyboardImpl *alloc_device(REFGUID rguid, const void *kvt, IDirectInputImpl *dinput) { SysKeyboardImpl* newDevice; - DWORD kbd_users; + LPDIDATAFORMAT df = NULL; + int i, idx = 0; newDevice = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(SysKeyboardImpl)); - newDevice->lpVtbl = kvt; - newDevice->ref = 1; - memcpy(&(newDevice->guid),rguid,sizeof(*rguid)); - newDevice->dinput = dinput; - InitializeCriticalSection(&(newDevice->crit)); + newDevice->base.lpVtbl = kvt; + newDevice->base.ref = 1; + memcpy(&newDevice->base.guid, rguid, sizeof(*rguid)); + newDevice->base.dinput = dinput; + newDevice->base.event_proc = KeyboardCallback; + InitializeCriticalSection(&newDevice->base.crit); + newDevice->base.crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": SysKeyboardImpl*->base.crit"); - EnterCriticalSection(&keyboard_crit); - kbd_users = InterlockedIncrement(&keyboard_users); - if (1 == kbd_users) { - keyboard_hook = SetWindowsHookExW( WH_KEYBOARD_LL, KeyboardCallback, DINPUT_instance, 0 ); + /* Create copy of default data format */ + if (!(df = HeapAlloc(GetProcessHeap(), 0, c_dfDIKeyboard.dwSize))) goto failed; + memcpy(df, &c_dfDIKeyboard, c_dfDIKeyboard.dwSize); + if (!(df->rgodf = HeapAlloc(GetProcessHeap(), 0, df->dwNumObjs * df->dwObjSize))) goto failed; + + for (i = 0; i < df->dwNumObjs; i++) + { + char buf[MAX_PATH]; + + if (!GetKeyNameTextA(((i & 0x7f) << 16) | ((i & 0x80) << 17), buf, sizeof(buf))) + continue; + + memcpy(&df->rgodf[idx], &c_dfDIKeyboard.rgodf[i], df->dwObjSize); + df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(i) | DIDFT_PSHBUTTON; } - LeaveCriticalSection(&keyboard_crit); + df->dwNumObjs = idx; + newDevice->base.data_format.wine_df = df; + IDirectInput_AddRef((LPDIRECTINPUTDEVICE8A)newDevice->base.dinput); return newDevice; + +failed: + if (df) HeapFree(GetProcessHeap(), 0, df->rgodf); + HeapFree(GetProcessHeap(), 0, df); + HeapFree(GetProcessHeap(), 0, newDevice); + return NULL; } @@ -272,6 +250,7 @@ static HRESULT keyboarddev_create_deviceA(IDirectInputImpl *dinput, REFGUID rgui IsEqualGUID(&IID_IDirectInputDevice8A,riid)) { *pdev = (IDirectInputDeviceA*) alloc_device(rguid, &SysKeyboardAvt, dinput); TRACE("Creating a Keyboard device (%p)\n", *pdev); + if (!*pdev) return DIERR_OUTOFMEMORY; return DI_OK; } else return DIERR_NOINTERFACE; @@ -290,6 +269,7 @@ static HRESULT keyboarddev_create_deviceW(IDirectInputImpl *dinput, REFGUID rgui IsEqualGUID(&IID_IDirectInputDevice8W,riid)) { *pdev = (IDirectInputDeviceW*) alloc_device(rguid, &SysKeyboardWvt, dinput); TRACE("Creating a Keyboard device (%p)\n", *pdev); + if (!*pdev) return DIERR_OUTOFMEMORY; return DI_OK; } else return DIERR_NOINTERFACE; @@ -305,306 +285,36 @@ const struct dinput_device keyboard_device = { keyboarddev_create_deviceW }; -static ULONG WINAPI SysKeyboardAImpl_Release(LPDIRECTINPUTDEVICE8A iface) -{ - SysKeyboardImpl *This = (SysKeyboardImpl *)iface; - ULONG ref; - DWORD kbd_users; - - ref = InterlockedDecrement(&(This->ref)); - if (ref) - return ref; - - EnterCriticalSection(&keyboard_crit); - kbd_users = InterlockedDecrement(&keyboard_users); - if (0 == kbd_users) { - UnhookWindowsHookEx( keyboard_hook ); - keyboard_hook = 0; - } - LeaveCriticalSection(&keyboard_crit); - - /* Free the data queue */ - HeapFree(GetProcessHeap(),0,This->buffer); - - DeleteCriticalSection(&(This->crit)); - - HeapFree(GetProcessHeap(),0,This); - return DI_OK; -} - -static HRESULT WINAPI SysKeyboardAImpl_SetProperty( - LPDIRECTINPUTDEVICE8A iface,REFGUID rguid,LPCDIPROPHEADER ph -) -{ - SysKeyboardImpl *This = (SysKeyboardImpl *)iface; - - TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(rguid),ph); - TRACE("(size=%ld,headersize=%ld,obj=%ld,how=%ld\n", - ph->dwSize,ph->dwHeaderSize,ph->dwObj,ph->dwHow); - if (!HIWORD(rguid)) { - switch (LOWORD(rguid)) { - case (DWORD) DIPROP_BUFFERSIZE: { - LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph; - - TRACE("(buffersize=%ld)\n",pd->dwData); - - if (This->acquired) - return DIERR_INVALIDPARAM; - - This->buffersize = pd->dwData; - - break; - } - default: - WARN("Unknown type %p\n",rguid); - break; - } - } - return DI_OK; -} - -static HRESULT WINAPI SysKeyboardAImpl_GetProperty( - LPDIRECTINPUTDEVICE8A iface,REFGUID rguid,LPDIPROPHEADER ph -) -{ - SysKeyboardImpl *This = (SysKeyboardImpl *)iface; - - TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(rguid),ph); - TRACE("(size=%ld,headersize=%ld,obj=%ld,how=%ld\n", - ph->dwSize,ph->dwHeaderSize,ph->dwObj,ph->dwHow); - if (!HIWORD(rguid)) { - switch (LOWORD(rguid)) { - case (DWORD) DIPROP_BUFFERSIZE: { - LPDIPROPDWORD pd = (LPDIPROPDWORD)ph; - - TRACE("(buffersize=%ld)\n",pd->dwData); - - if (This->acquired) - return DIERR_INVALIDPARAM; - - pd->dwData = This->buffersize; - - break; - } - default: - WARN("Unknown type %p\n",rguid); - break; - } - } - return DI_OK; -} - static HRESULT WINAPI SysKeyboardAImpl_GetDeviceState( LPDIRECTINPUTDEVICE8A iface,DWORD len,LPVOID ptr ) { SysKeyboardImpl *This = (SysKeyboardImpl *)iface; - TRACE("(%p)->(%ld,%p)\n", This, len, ptr); + TRACE("(%p)->(%d,%p)\n", This, len, ptr); - /* Note: device does not need to be acquired */ - if (len != WINE_DINPUT_KEYBOARD_MAX_KEYS) - return DIERR_INVALIDPARAM; + if (!This->base.acquired) return DIERR_NOTACQUIRED; - MsgWaitForMultipleObjectsEx(0, NULL, 0, QS_ALLINPUT, 0); + if (len != This->base.data_format.user_df->dwDataSize ) + return DIERR_INVALIDPARAM; - EnterCriticalSection(&(This->crit)); + EnterCriticalSection(&This->base.crit); if (TRACE_ON(dinput)) { int i; for (i = 0; i < WINE_DINPUT_KEYBOARD_MAX_KEYS; i++) { - if (DInputKeyState[i] != 0x00) { - TRACE(" - %02X: %02x\n", i, DInputKeyState[i]); - } + if (This->DInputKeyState[i] != 0x00) + TRACE(" - %02X: %02x\n", i, This->DInputKeyState[i]); } } - memcpy(ptr, DInputKeyState, WINE_DINPUT_KEYBOARD_MAX_KEYS); - LeaveCriticalSection(&(This->crit)); + fill_DataFormat(ptr, len, This->DInputKeyState, &This->base.data_format); + LeaveCriticalSection(&This->base.crit); return DI_OK; } -static HRESULT WINAPI SysKeyboardAImpl_GetDeviceData( - LPDIRECTINPUTDEVICE8A iface,DWORD dodsize,LPDIDEVICEOBJECTDATA dod, - LPDWORD entries,DWORD flags -) -{ - SysKeyboardImpl *This = (SysKeyboardImpl *)iface; - int ret = DI_OK, i = 0; - - TRACE("(this=%p,%ld,%p,%p(%ld)),0x%08lx)\n", - This,dodsize,dod,entries,entries?*entries:0,flags); - - if (This->acquired == 0) - return DIERR_NOTACQUIRED; - - if (This->buffer == NULL) - return DIERR_NOTBUFFERED; - - if (dodsize < sizeof(DIDEVICEOBJECTDATA_DX3)) - return DIERR_INVALIDPARAM; - - MsgWaitForMultipleObjectsEx(0, NULL, 0, QS_ALLINPUT, 0); - - EnterCriticalSection(&(This->crit)); - - /* Copy item at a time for the case dodsize > sizeof(buffer[n]) */ - while ((i < *entries || *entries == INFINITE) && i < This->count) - { - if (dod != NULL) - { - int n = (This->start + i) % This->buffersize; - LPDIDEVICEOBJECTDATA pd - = (LPDIDEVICEOBJECTDATA)((BYTE *)dod + dodsize * i); - pd->dwOfs = This->buffer[n].dwOfs; - pd->dwData = This->buffer[n].dwData; - pd->dwTimeStamp = This->buffer[n].dwTimeStamp; - pd->dwSequence = This->buffer[n].dwSequence; - } - i++; - } - - *entries = i; - - if (This->overflow) - ret = DI_BUFFEROVERFLOW; - - if (!(flags & DIGDD_PEEK)) - { - /* Empty buffer */ - This->count -= i; - This->start = (This->start + i) % This->buffersize; - This->overflow = FALSE; - } - - LeaveCriticalSection(&(This->crit)); - - TRACE("Returning %ld events queued\n", *entries); - - return ret; -} - -static HRESULT WINAPI SysKeyboardAImpl_EnumObjects( - LPDIRECTINPUTDEVICE8A iface, - LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback, - LPVOID lpvRef, - DWORD dwFlags) -{ - SysKeyboardImpl *This = (SysKeyboardImpl *)iface; - DIDEVICEOBJECTINSTANCEA ddoi; - int i; - - TRACE("(this=%p,%p,%p,%08lx)\n", This, lpCallback, lpvRef, dwFlags); - if (TRACE_ON(dinput)) { - TRACE(" - flags = "); - _dump_EnumObjects_flags(dwFlags); - TRACE("\n"); - } - - /* Only the fields till dwFFMaxForce are relevant */ - memset(&ddoi, 0, sizeof(ddoi)); - ddoi.dwSize = FIELD_OFFSET(DIDEVICEOBJECTINSTANCEA, dwFFMaxForce); - - for (i = 0; i < WINE_DINPUT_KEYBOARD_MAX_KEYS; i++) { - /* Report 255 keys :-) */ - ddoi.guidType = GUID_Key; - ddoi.dwOfs = i; - ddoi.dwType = DIDFT_MAKEINSTANCE(i) | DIDFT_BUTTON; - GetKeyNameTextA(((i & 0x7f) << 16) | ((i & 0x80) << 17), ddoi.tszName, sizeof(ddoi.tszName)); - _dump_OBJECTINSTANCEA(&ddoi); - if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK; - } - - return DI_OK; -} - -static HRESULT WINAPI SysKeyboardWImpl_EnumObjects(LPDIRECTINPUTDEVICE8W iface, - LPDIENUMDEVICEOBJECTSCALLBACKW lpCallback, - LPVOID lpvRef, - DWORD dwFlags) -{ - SysKeyboardImpl *This = (SysKeyboardImpl *)iface; - - device_enumobjects_AtoWcb_data data; - - data.lpCallBack = lpCallback; - data.lpvRef = lpvRef; - - return SysKeyboardAImpl_EnumObjects((LPDIRECTINPUTDEVICE8A) This, (LPDIENUMDEVICEOBJECTSCALLBACKA) DIEnumDevicesCallbackAtoW, (LPVOID) &data, dwFlags); -} - -static HRESULT WINAPI SysKeyboardAImpl_Unacquire(LPDIRECTINPUTDEVICE8A iface); - -static HRESULT WINAPI SysKeyboardAImpl_Acquire(LPDIRECTINPUTDEVICE8A iface) -{ - SysKeyboardImpl *This = (SysKeyboardImpl *)iface; - - TRACE("(this=%p)\n",This); - - if (This->acquired) - return S_FALSE; - - This->acquired = 1; - - if (current_lock != NULL) { - FIXME("Not more than one keyboard can be acquired at the same time.\n"); - SysKeyboardAImpl_Unacquire(iface); - } - - current_lock = This; - - if (This->buffersize > 0) { - This->buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, - This->buffersize * sizeof(*(This->buffer))); - This->start = 0; - This->count = 0; - This->overflow = FALSE; - } else { - This->buffer = NULL; - } - - /*keyboard_hook = SetWindowsHookExW( WH_KEYBOARD_LL, KeyboardCallback, DINPUT_instance, 0 );*/ - - return DI_OK; -} - -static HRESULT WINAPI SysKeyboardAImpl_Unacquire(LPDIRECTINPUTDEVICE8A iface) -{ - SysKeyboardImpl *This = (SysKeyboardImpl *)iface; - TRACE("(this=%p)\n",This); - - if (This->acquired == 0) - return DI_NOEFFECT; - - /* No more locks */ - if (current_lock == This) - current_lock = NULL; - else - ERR("this != current_lock\n"); - - /* Unacquire device */ - This->acquired = 0; - - if (This->buffersize >= 0) { - HeapFree(GetProcessHeap(), 0, This->buffer); - This->buffer = NULL; - } - - return DI_OK; -} - -static HRESULT WINAPI SysKeyboardAImpl_SetEventNotification(LPDIRECTINPUTDEVICE8A iface, - HANDLE hnd) { - SysKeyboardImpl *This = (SysKeyboardImpl *)iface; - - TRACE("(this=%p,%p)\n",This,hnd); - - This->hEvent = hnd; - return DI_OK; -} - /****************************************************************************** - * GetCapabilities : get the device capablitites + * GetCapabilities : get the device capabilities */ static HRESULT WINAPI SysKeyboardAImpl_GetCapabilities( LPDIRECTINPUTDEVICE8A iface, @@ -619,15 +329,15 @@ static HRESULT WINAPI SysKeyboardAImpl_GetCapabilities( WARN("invalid parameter\n"); return DIERR_INVALIDPARAM; } - + devcaps.dwSize = lpDIDevCaps->dwSize; devcaps.dwFlags = DIDC_ATTACHED; - if (This->dinput->dwVersion >= 0x0800) + if (This->base.dinput->dwVersion >= 0x0800) devcaps.dwDevType = DI8DEVTYPE_KEYBOARD | (DI8DEVTYPEKEYBOARD_UNKNOWN << 8); else devcaps.dwDevType = DIDEVTYPE_KEYBOARD | (DIDEVTYPEKEYBOARD_UNKNOWN << 8); devcaps.dwAxes = 0; - devcaps.dwButtons = WINE_DINPUT_KEYBOARD_MAX_KEYS; + devcaps.dwButtons = This->base.data_format.wine_df->dwNumObjs; devcaps.dwPOVs = 0; devcaps.dwFFSamplePeriod = 0; devcaps.dwFFMinTimeResolution = 0; @@ -636,7 +346,7 @@ static HRESULT WINAPI SysKeyboardAImpl_GetCapabilities( devcaps.dwFFDriverVersion = 0; memcpy(lpDIDevCaps, &devcaps, lpDIDevCaps->dwSize); - + return DI_OK; } @@ -651,32 +361,18 @@ SysKeyboardAImpl_GetObjectInfo( DWORD dwObj, DWORD dwHow) { - SysKeyboardImpl *This = (SysKeyboardImpl *)iface; - DIDEVICEOBJECTINSTANCEA ddoi; - DWORD dwSize = pdidoi->dwSize; + HRESULT res; - TRACE("(this=%p,%p,%ld,0x%08lx)\n", This, pdidoi, dwObj, dwHow); + res = IDirectInputDevice2AImpl_GetObjectInfo(iface, pdidoi, dwObj, dwHow); + if (res != DI_OK) return res; - if (dwHow == DIPH_BYID) { - WARN(" querying by id not supported yet...\n"); - return DI_OK; - } - - memset(pdidoi, 0, dwSize); - memset(&ddoi, 0, sizeof(ddoi)); - - ddoi.dwSize = dwSize; - ddoi.guidType = GUID_Key; - ddoi.dwOfs = dwObj; - ddoi.dwType = DIDFT_MAKEINSTANCE(dwObj) | DIDFT_BUTTON; - GetKeyNameTextA(((dwObj & 0x7f) << 16) | ((dwObj & 0x80) << 17), ddoi.tszName, sizeof(ddoi.tszName)); - - /* And return our just filled device object instance structure */ - memcpy(pdidoi, &ddoi, (dwSize < sizeof(ddoi) ? dwSize : sizeof(ddoi))); + if (!GetKeyNameTextA((DIDFT_GETINSTANCE(pdidoi->dwType) & 0x80) << 17 | + (DIDFT_GETINSTANCE(pdidoi->dwType) & 0x7f) << 16, + pdidoi->tszName, sizeof(pdidoi->tszName))) + return DIERR_OBJECTNOTFOUND; _dump_OBJECTINSTANCEA(pdidoi); - - return DI_OK; + return res; } static HRESULT WINAPI SysKeyboardWImpl_GetObjectInfo(LPDIRECTINPUTDEVICE8W iface, @@ -684,32 +380,19 @@ static HRESULT WINAPI SysKeyboardWImpl_GetObjectInfo(LPDIRECTINPUTDEVICE8W iface DWORD dwObj, DWORD dwHow) { - SysKeyboardImpl *This = (SysKeyboardImpl *)iface; - DIDEVICEOBJECTINSTANCEW ddoi; - DWORD dwSize = pdidoi->dwSize; + HRESULT res; - TRACE("(this=%p,%p,%ld,0x%08lx)\n", This, pdidoi, dwObj, dwHow); + res = IDirectInputDevice2WImpl_GetObjectInfo(iface, pdidoi, dwObj, dwHow); + if (res != DI_OK) return res; - if (dwHow == DIPH_BYID) { - WARN(" querying by id not supported yet...\n"); - return DI_OK; - } - - memset(pdidoi, 0, dwSize); - memset(&ddoi, 0, sizeof(ddoi)); - - ddoi.dwSize = dwSize; - ddoi.guidType = GUID_Key; - ddoi.dwOfs = dwObj; - ddoi.dwType = DIDFT_MAKEINSTANCE(dwObj) | DIDFT_BUTTON; - GetKeyNameTextW(((dwObj & 0x7f) << 16) | ((dwObj & 0x80) << 17), ddoi.tszName, sizeof(ddoi.tszName)); - - /* And return our just filled device object instance structure */ - memcpy(pdidoi, &ddoi, (dwSize < sizeof(ddoi) ? dwSize : sizeof(ddoi))); + if (!GetKeyNameTextW((DIDFT_GETINSTANCE(pdidoi->dwType) & 0x80) << 17 | + (DIDFT_GETINSTANCE(pdidoi->dwType) & 0x7f) << 16, + pdidoi->tszName, + sizeof(pdidoi->tszName)/sizeof(pdidoi->tszName[0]))) + return DIERR_OBJECTNOTFOUND; _dump_OBJECTINSTANCEW(pdidoi); - - return DI_OK; + return res; } /****************************************************************************** @@ -727,12 +410,12 @@ static HRESULT WINAPI SysKeyboardAImpl_GetDeviceInfo( return DI_OK; } - fill_keyboard_dideviceinstanceA(pdidi, This->dinput->dwVersion); - + fill_keyboard_dideviceinstanceA(pdidi, This->base.dinput->dwVersion); + return DI_OK; } -static HRESULT WINAPI SysKeyboardWImpl_GetDeviceInfo(LPDIRECTINPUTDEVICE8W iface, LPDIDEVICEINSTANCEW pdidi) +static HRESULT WINAPI SysKeyboardWImpl_GetDeviceInfo(LPDIRECTINPUTDEVICE8W iface, LPDIDEVICEINSTANCEW pdidi) { SysKeyboardImpl *This = (SysKeyboardImpl *)iface; TRACE("(this=%p,%p)\n", This, pdidi); @@ -742,8 +425,44 @@ static HRESULT WINAPI SysKeyboardWImpl_GetDeviceInfo(LPDIRECTINPUTDEVICE8W iface return DI_OK; } - fill_keyboard_dideviceinstanceW(pdidi, This->dinput->dwVersion); + fill_keyboard_dideviceinstanceW(pdidi, This->base.dinput->dwVersion); + + return DI_OK; +} +/****************************************************************************** + * GetProperty : Retrieves information about the input device. + */ +static HRESULT WINAPI SysKeyboardAImpl_GetProperty(LPDIRECTINPUTDEVICE8A iface, + REFGUID rguid, LPDIPROPHEADER pdiph) +{ + TRACE("(%p) %s,%p\n", iface, debugstr_guid(rguid), pdiph); + _dump_DIPROPHEADER(pdiph); + + if (HIWORD(rguid)) return DI_OK; + + switch (LOWORD(rguid)) + { + case (DWORD_PTR)DIPROP_KEYNAME: + { + HRESULT hr; + LPDIPROPSTRING ps = (LPDIPROPSTRING)pdiph; + DIDEVICEOBJECTINSTANCEW didoi; + + if (pdiph->dwSize != sizeof(DIPROPSTRING)) + return DIERR_INVALIDPARAM; + + didoi.dwSize = sizeof(DIDEVICEOBJECTINSTANCEW); + + hr = SysKeyboardWImpl_GetObjectInfo((LPDIRECTINPUTDEVICE8W)iface , &didoi, + ps->diph.dwObj, ps->diph.dwHow); + if (hr == DI_OK) + memcpy(ps->wsz, didoi.tszName, sizeof(ps->wsz)); + return hr; + } + default: + return IDirectInputDevice2AImpl_GetProperty( iface, rguid, pdiph ); + } return DI_OK; } @@ -751,17 +470,17 @@ static const IDirectInputDevice8AVtbl SysKeyboardAvt = { IDirectInputDevice2AImpl_QueryInterface, IDirectInputDevice2AImpl_AddRef, - SysKeyboardAImpl_Release, + IDirectInputDevice2AImpl_Release, SysKeyboardAImpl_GetCapabilities, - SysKeyboardAImpl_EnumObjects, - SysKeyboardAImpl_GetProperty, - SysKeyboardAImpl_SetProperty, - SysKeyboardAImpl_Acquire, - SysKeyboardAImpl_Unacquire, + IDirectInputDevice2AImpl_EnumObjects, + SysKeyboardAImpl_GetProperty, + IDirectInputDevice2AImpl_SetProperty, + IDirectInputDevice2AImpl_Acquire, + IDirectInputDevice2AImpl_Unacquire, SysKeyboardAImpl_GetDeviceState, - SysKeyboardAImpl_GetDeviceData, + IDirectInputDevice2AImpl_GetDeviceData, IDirectInputDevice2AImpl_SetDataFormat, - SysKeyboardAImpl_SetEventNotification, + IDirectInputDevice2AImpl_SetEventNotification, IDirectInputDevice2AImpl_SetCooperativeLevel, SysKeyboardAImpl_GetObjectInfo, SysKeyboardAImpl_GetDeviceInfo, @@ -774,7 +493,7 @@ static const IDirectInputDevice8AVtbl SysKeyboardAvt = IDirectInputDevice2AImpl_SendForceFeedbackCommand, IDirectInputDevice2AImpl_EnumCreatedEffectObjects, IDirectInputDevice2AImpl_Escape, - IDirectInputDevice2AImpl_Poll, + IDirectInputDevice2AImpl_Poll, IDirectInputDevice2AImpl_SendDeviceData, IDirectInputDevice7AImpl_EnumEffectsInFile, IDirectInputDevice7AImpl_WriteEffectToFile, @@ -793,17 +512,17 @@ static const IDirectInputDevice8WVtbl SysKeyboardWvt = { IDirectInputDevice2WImpl_QueryInterface, XCAST(AddRef)IDirectInputDevice2AImpl_AddRef, - XCAST(Release)SysKeyboardAImpl_Release, + XCAST(Release)IDirectInputDevice2AImpl_Release, XCAST(GetCapabilities)SysKeyboardAImpl_GetCapabilities, - SysKeyboardWImpl_EnumObjects, - XCAST(GetProperty)SysKeyboardAImpl_GetProperty, - XCAST(SetProperty)SysKeyboardAImpl_SetProperty, - XCAST(Acquire)SysKeyboardAImpl_Acquire, - XCAST(Unacquire)SysKeyboardAImpl_Unacquire, + IDirectInputDevice2WImpl_EnumObjects, + XCAST(GetProperty)SysKeyboardAImpl_GetProperty, + XCAST(SetProperty)IDirectInputDevice2AImpl_SetProperty, + XCAST(Acquire)IDirectInputDevice2AImpl_Acquire, + XCAST(Unacquire)IDirectInputDevice2AImpl_Unacquire, XCAST(GetDeviceState)SysKeyboardAImpl_GetDeviceState, - XCAST(GetDeviceData)SysKeyboardAImpl_GetDeviceData, + XCAST(GetDeviceData)IDirectInputDevice2AImpl_GetDeviceData, XCAST(SetDataFormat)IDirectInputDevice2AImpl_SetDataFormat, - XCAST(SetEventNotification)SysKeyboardAImpl_SetEventNotification, + XCAST(SetEventNotification)IDirectInputDevice2AImpl_SetEventNotification, XCAST(SetCooperativeLevel)IDirectInputDevice2AImpl_SetCooperativeLevel, SysKeyboardWImpl_GetObjectInfo, SysKeyboardWImpl_GetDeviceInfo, @@ -816,7 +535,7 @@ static const IDirectInputDevice8WVtbl SysKeyboardWvt = XCAST(SendForceFeedbackCommand)IDirectInputDevice2AImpl_SendForceFeedbackCommand, XCAST(EnumCreatedEffectObjects)IDirectInputDevice2AImpl_EnumCreatedEffectObjects, XCAST(Escape)IDirectInputDevice2AImpl_Escape, - XCAST(Poll)IDirectInputDevice2AImpl_Poll, + XCAST(Poll)IDirectInputDevice2AImpl_Poll, XCAST(SendDeviceData)IDirectInputDevice2AImpl_SendDeviceData, IDirectInputDevice7WImpl_EnumEffectsInFile, IDirectInputDevice7WImpl_WriteEffectToFile, diff --git a/reactos/dll/directx/dinput/mouse.c b/reactos/dll/directx/dinput/mouse.c index 1966b0f12cd..178b8fb4842 100644 --- a/reactos/dll/directx/dinput/mouse.c +++ b/reactos/dll/directx/dinput/mouse.c @@ -16,7 +16,7 @@ * * 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 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include "config.h" @@ -30,6 +30,7 @@ #include "wingdi.h" #include "winuser.h" #include "winerror.h" +#include "winreg.h" #include "dinput.h" #include "dinput_private.h" @@ -37,133 +38,70 @@ #include "wine/debug.h" #include "wine/unicode.h" -#define MOUSE_HACK - WINE_DEFAULT_DEBUG_CHANNEL(dinput); /* Wine mouse driver object instances */ #define WINE_MOUSE_X_AXIS_INSTANCE 0 #define WINE_MOUSE_Y_AXIS_INSTANCE 1 #define WINE_MOUSE_Z_AXIS_INSTANCE 2 -#define WINE_MOUSE_L_BUTTON_INSTANCE 0 -#define WINE_MOUSE_R_BUTTON_INSTANCE 1 -#define WINE_MOUSE_M_BUTTON_INSTANCE 2 -#define WINE_MOUSE_D_BUTTON_INSTANCE 3 - -/* ------------------------------- */ -/* Wine mouse internal data format */ -/* ------------------------------- */ - -/* Constants used to access the offset array */ -#define WINE_MOUSE_X_POSITION 0 -#define WINE_MOUSE_Y_POSITION 1 -#define WINE_MOUSE_Z_POSITION 2 -#define WINE_MOUSE_L_POSITION 3 -#define WINE_MOUSE_R_POSITION 4 -#define WINE_MOUSE_M_POSITION 5 - -typedef struct { - LONG lX; - LONG lY; - LONG lZ; - BYTE rgbButtons[4]; -} Wine_InternalMouseData; - -#define WINE_INTERNALMOUSE_NUM_OBJS 6 - -static const DIOBJECTDATAFORMAT Wine_InternalMouseObjectFormat[WINE_INTERNALMOUSE_NUM_OBJS] = { - { &GUID_XAxis, FIELD_OFFSET(Wine_InternalMouseData, lX), - DIDFT_MAKEINSTANCE(WINE_MOUSE_X_AXIS_INSTANCE) | DIDFT_RELAXIS, 0 }, - { &GUID_YAxis, FIELD_OFFSET(Wine_InternalMouseData, lY), - DIDFT_MAKEINSTANCE(WINE_MOUSE_Y_AXIS_INSTANCE) | DIDFT_RELAXIS, 0 }, - { &GUID_ZAxis, FIELD_OFFSET(Wine_InternalMouseData, lZ), - DIDFT_MAKEINSTANCE(WINE_MOUSE_Z_AXIS_INSTANCE) | DIDFT_RELAXIS, 0 }, - { &GUID_Button, (FIELD_OFFSET(Wine_InternalMouseData, rgbButtons)) + 0, - DIDFT_MAKEINSTANCE(WINE_MOUSE_L_BUTTON_INSTANCE) | DIDFT_PSHBUTTON, 0 }, - { &GUID_Button, (FIELD_OFFSET(Wine_InternalMouseData, rgbButtons)) + 1, - DIDFT_MAKEINSTANCE(WINE_MOUSE_R_BUTTON_INSTANCE) | DIDFT_PSHBUTTON, 0 }, - { &GUID_Button, (FIELD_OFFSET(Wine_InternalMouseData, rgbButtons)) + 2, - DIDFT_MAKEINSTANCE(WINE_MOUSE_M_BUTTON_INSTANCE) | DIDFT_PSHBUTTON, 0 } -}; - -static const DIDATAFORMAT Wine_InternalMouseFormat = { - 0, /* dwSize - unused */ - 0, /* dwObjsize - unused */ - 0, /* dwFlags - unused */ - sizeof(Wine_InternalMouseData), - WINE_INTERNALMOUSE_NUM_OBJS, /* dwNumObjs */ - (LPDIOBJECTDATAFORMAT) Wine_InternalMouseObjectFormat -}; +#define WINE_MOUSE_BUTTONS_INSTANCE 3 static const IDirectInputDevice8AVtbl SysMouseAvt; static const IDirectInputDevice8WVtbl SysMouseWvt; typedef struct SysMouseImpl SysMouseImpl; -typedef enum { - WARP_DONE, /* Warping has been done */ - WARP_NEEDED, /* Warping is needed */ - WARP_STARTED /* Warping has been done, waiting for the warp event */ -} WARP_STATUS; +typedef enum +{ + WARP_DEFAULT, + WARP_DISABLE, + WARP_FORCE_ON +} WARP_MOUSE; struct SysMouseImpl { - const void *lpVtbl; - LONG ref; - GUID guid; - - IDirectInputImpl *dinput; - - /* The current data format and the conversion between internal - and external data formats */ - DIDATAFORMAT *df; - DataFormat *wine_df; - int offset_array[WINE_INTERNALMOUSE_NUM_OBJS]; + struct IDirectInputDevice2AImpl base; /* SysMouseAImpl */ - BYTE absolute; - /* Previous position for relative moves */ - LONG prevX, prevY; /* These are used in case of relative -> absolute transitions */ POINT org_coords; - HHOOK hook; - HWND win; - DWORD dwCoopLevel; POINT mapped_center; DWORD win_centerX, win_centerY; - LPDIDEVICEOBJECTDATA data_queue; - int queue_head, queue_tail, queue_len; - BOOL overflow; /* warping: whether we need to move mouse back to middle once we * reach window borders (for e.g. shooters, "surface movement" games) */ - WARP_STATUS need_warp; - int acquired; - HANDLE hEvent; - CRITICAL_SECTION crit; - + BOOL need_warp; + DWORD last_warped; + /* This is for mouse reporting. */ - Wine_InternalMouseData m_state; + DIMOUSESTATE2 m_state; + + WARP_MOUSE warp_override; }; -/* FIXME: This is ugly and not thread safe :/ */ -static IDirectInputDevice8A* current_lock = NULL; +static void dinput_mouse_hook( LPDIRECTINPUTDEVICE8A iface, WPARAM wparam, LPARAM lparam ); -/* FIXME: This is ugly but needed on Windows */ -static int mouse_set = 0; -static GUID DInput_Wine_Mouse_GUID = { /* 9e573ed8-7734-11d2-8d4a-23903fb6bdf7 */ - 0x9e573ed8, - 0x7734, - 0x11d2, - {0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf7} +const GUID DInput_Wine_Mouse_GUID = { /* 9e573ed8-7734-11d2-8d4a-23903fb6bdf7 */ + 0x9e573ed8, 0x7734, 0x11d2, {0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf7} }; +static void _dump_mouse_state(DIMOUSESTATE2 *m_state) +{ + int i; + + if (!TRACE_ON(dinput)) return; + + TRACE("(X: %d Y: %d Z: %d", m_state->lX, m_state->lY, m_state->lZ); + for (i = 0; i < 5; i++) TRACE(" B%d: %02x", i, m_state->rgbButtons[i]); + TRACE(")\n"); +} + static void fill_mouse_dideviceinstanceA(LPDIDEVICEINSTANCEA lpddi, DWORD version) { DWORD dwSize; DIDEVICEINSTANCEA ddi; dwSize = lpddi->dwSize; - TRACE("%ld %p\n", dwSize, lpddi); + TRACE("%d %p\n", dwSize, lpddi); memset(lpddi, 0, dwSize); memset(&ddi, 0, sizeof(ddi)); @@ -187,7 +125,7 @@ static void fill_mouse_dideviceinstanceW(LPDIDEVICEINSTANCEW lpddi, DWORD versio dwSize = lpddi->dwSize; - TRACE("%ld %p\n", dwSize, lpddi); + TRACE("%d %p\n", dwSize, lpddi); memset(lpddi, 0, dwSize); memset(&ddi, 0, sizeof(ddi)); @@ -243,31 +181,56 @@ static BOOL mousedev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINST static SysMouseImpl *alloc_device(REFGUID rguid, const void *mvt, IDirectInputImpl *dinput) { - int offset_array[WINE_INTERNALMOUSE_NUM_OBJS] = { - FIELD_OFFSET(Wine_InternalMouseData, lX), - FIELD_OFFSET(Wine_InternalMouseData, lY), - FIELD_OFFSET(Wine_InternalMouseData, lZ), - FIELD_OFFSET(Wine_InternalMouseData, rgbButtons) + 0, - FIELD_OFFSET(Wine_InternalMouseData, rgbButtons) + 1, - FIELD_OFFSET(Wine_InternalMouseData, rgbButtons) + 2 - }; SysMouseImpl* newDevice; + LPDIDATAFORMAT df = NULL; + unsigned i; + char buffer[20]; + HKEY hkey, appkey; + newDevice = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(SysMouseImpl)); - newDevice->ref = 1; - newDevice->lpVtbl = mvt; - InitializeCriticalSection(&(newDevice->crit)); - memcpy(&(newDevice->guid),rguid,sizeof(*rguid)); + if (!newDevice) return NULL; + newDevice->base.lpVtbl = mvt; + newDevice->base.ref = 1; + newDevice->base.dwCoopLevel = DISCL_NONEXCLUSIVE | DISCL_BACKGROUND; + newDevice->base.guid = *rguid; + InitializeCriticalSection(&newDevice->base.crit); + newDevice->base.crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": SysMouseImpl*->base.crit"); + newDevice->base.dinput = dinput; + newDevice->base.event_proc = dinput_mouse_hook; - /* Per default, Wine uses its internal data format */ - newDevice->df = (DIDATAFORMAT *) &Wine_InternalMouseFormat; - memcpy(newDevice->offset_array, offset_array, WINE_INTERNALMOUSE_NUM_OBJS * sizeof(int)); - newDevice->wine_df = HeapAlloc(GetProcessHeap(), 0, sizeof(DataFormat)); - newDevice->wine_df->size = 0; - newDevice->wine_df->internal_format_size = Wine_InternalMouseFormat.dwDataSize; - newDevice->wine_df->dt = NULL; - newDevice->dinput = dinput; + get_app_key(&hkey, &appkey); + if (!get_config_key(hkey, appkey, "MouseWarpOverride", buffer, sizeof(buffer))) + { + if (!strcasecmp(buffer, "disable")) + newDevice->warp_override = WARP_DISABLE; + else if (!strcasecmp(buffer, "force")) + newDevice->warp_override = WARP_FORCE_ON; + } + if (appkey) RegCloseKey(appkey); + if (hkey) RegCloseKey(hkey); + /* Create copy of default data format */ + if (!(df = HeapAlloc(GetProcessHeap(), 0, c_dfDIMouse2.dwSize))) goto failed; + memcpy(df, &c_dfDIMouse2, c_dfDIMouse2.dwSize); + if (!(df->rgodf = HeapAlloc(GetProcessHeap(), 0, df->dwNumObjs * df->dwObjSize))) goto failed; + memcpy(df->rgodf, c_dfDIMouse2.rgodf, df->dwNumObjs * df->dwObjSize); + + /* Because we don't do any detection yet just modify instance and type */ + for (i = 0; i < df->dwNumObjs; i++) + if (DIDFT_GETTYPE(df->rgodf[i].dwType) & DIDFT_AXIS) + df->rgodf[i].dwType = DIDFT_MAKEINSTANCE(i) | DIDFT_RELAXIS; + else + df->rgodf[i].dwType = DIDFT_MAKEINSTANCE(i) | DIDFT_PSHBUTTON; + + newDevice->base.data_format.wine_df = df; + IDirectInput_AddRef((LPDIRECTINPUTDEVICE8A)newDevice->base.dinput); return newDevice; + +failed: + if (df) HeapFree(GetProcessHeap(), 0, df->rgodf); + HeapFree(GetProcessHeap(), 0, df); + HeapFree(GetProcessHeap(), 0, newDevice); + return NULL; } static HRESULT mousedev_create_deviceA(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEA* pdev) @@ -281,6 +244,7 @@ static HRESULT mousedev_create_deviceA(IDirectInputImpl *dinput, REFGUID rguid, IsEqualGUID(&IID_IDirectInputDevice8A,riid)) { *pdev = (IDirectInputDeviceA*) alloc_device(rguid, &SysMouseAvt, dinput); TRACE("Creating a Mouse device (%p)\n", *pdev); + if (!*pdev) return DIERR_OUTOFMEMORY; return DI_OK; } else return DIERR_NOINTERFACE; @@ -300,6 +264,7 @@ static HRESULT mousedev_create_deviceW(IDirectInputImpl *dinput, REFGUID rguid, IsEqualGUID(&IID_IDirectInputDevice8W,riid)) { *pdev = (IDirectInputDeviceW*) alloc_device(rguid, &SysMouseWvt, dinput); TRACE("Creating a Mouse device (%p)\n", *pdev); + if (!*pdev) return DIERR_OUTOFMEMORY; return DI_OK; } else return DIERR_NOINTERFACE; @@ -320,258 +285,111 @@ const struct dinput_device mouse_device = { * SysMouseA (DInput Mouse support) */ -/****************************************************************************** - * Release : release the mouse buffer. - */ -static ULONG WINAPI SysMouseAImpl_Release(LPDIRECTINPUTDEVICE8A iface) -{ - SysMouseImpl *This = (SysMouseImpl *)iface; - ULONG ref; - - ref = InterlockedDecrement(&(This->ref)); - if (ref) - return ref; - - /* Free the data queue */ - HeapFree(GetProcessHeap(),0,This->data_queue); - - if (This->hook) { - UnhookWindowsHookEx( This->hook ); - if (This->dwCoopLevel & DISCL_EXCLUSIVE) - ShowCursor(TRUE); /* show cursor */ - } - DeleteCriticalSection(&(This->crit)); - - /* Free the DataFormat */ - if (This->df != &(Wine_InternalMouseFormat)) { - HeapFree(GetProcessHeap(), 0, This->df->rgodf); - HeapFree(GetProcessHeap(), 0, This->df); - } - - HeapFree(GetProcessHeap(),0,This); - return 0; -} - - -/****************************************************************************** - * SetCooperativeLevel : store the window in which we will do our - * grabbing. - */ -static HRESULT WINAPI SysMouseAImpl_SetCooperativeLevel( - LPDIRECTINPUTDEVICE8A iface,HWND hwnd,DWORD dwflags -) -{ - SysMouseImpl *This = (SysMouseImpl *)iface; - - TRACE("(this=%p,%p,0x%08lx)\n",This,hwnd,dwflags); - - if (TRACE_ON(dinput)) { - TRACE(" cooperative level : "); - _dump_cooperativelevel_DI(dwflags); - } - - /* Store the window which asks for the mouse */ - if (!hwnd) - hwnd = GetDesktopWindow(); - This->win = hwnd; - This->dwCoopLevel = dwflags; - - return DI_OK; -} - - -/****************************************************************************** - * SetDataFormat : the application can choose the format of the data - * the device driver sends back with GetDeviceState. - * - * For the moment, only the "standard" configuration (c_dfDIMouse) is supported - * in absolute and relative mode. - */ -static HRESULT WINAPI SysMouseAImpl_SetDataFormat( - LPDIRECTINPUTDEVICE8A iface,LPCDIDATAFORMAT df -) -{ - SysMouseImpl *This = (SysMouseImpl *)iface; - - TRACE("(this=%p,%p)\n",This,df); - - _dump_DIDATAFORMAT(df); - - /* Tests under windows show that a call to SetDataFormat always sets the mouse - in relative mode whatever the dwFlags value (DIDF_ABSAXIS/DIDF_RELAXIS). - To switch in absolute mode, SetProperty must be used. */ - This->absolute = 0; - - /* Store the new data format */ - This->df = HeapAlloc(GetProcessHeap(),0,df->dwSize); - memcpy(This->df, df, df->dwSize); - This->df->rgodf = HeapAlloc(GetProcessHeap(),0,df->dwNumObjs*df->dwObjSize); - memcpy(This->df->rgodf,df->rgodf,df->dwNumObjs*df->dwObjSize); - - /* Prepare all the data-conversion filters */ - This->wine_df = create_DataFormat(&(Wine_InternalMouseFormat), df, This->offset_array); - - return DI_OK; -} - /* low-level mouse hook */ -static LRESULT CALLBACK dinput_mouse_hook( int code, WPARAM wparam, LPARAM lparam ) +static void dinput_mouse_hook( LPDIRECTINPUTDEVICE8A iface, WPARAM wparam, LPARAM lparam ) { - LRESULT ret; MSLLHOOKSTRUCT *hook = (MSLLHOOKSTRUCT *)lparam; - SysMouseImpl* This = (SysMouseImpl*) current_lock; + SysMouseImpl* This = (SysMouseImpl*) iface; DWORD dwCoop; - static long last_event = 0; - int wdata; - long lasttime = 0; + int wdata = 0, inst_id = -1; - if (code != HC_ACTION) return CallNextHookEx( This->hook, code, wparam, lparam ); + TRACE("msg %lx @ (%d %d)\n", wparam, hook->pt.x, hook->pt.y); - EnterCriticalSection(&(This->crit)); - dwCoop = This->dwCoopLevel; + EnterCriticalSection(&This->base.crit); + dwCoop = This->base.dwCoopLevel; - /* Only allow mouse events every 10 ms. - * This is to allow the cursor to start acceleration before - * the warps happen. But if it involves a mouse button event we - * allow it since we don't want to lose the clicks. - */ -#ifndef __REACTOS__ - if (((GetCurrentTime() - last_event) < 10) - && wparam == WM_MOUSEMOVE) - goto end; - else last_event = GetCurrentTime(); -#else - lasttime = GetCurrentTime() - last_event; - - if ((lasttime) < 1) - goto end; - else if ((lasttime) >= 10) - last_event = GetCurrentTime(); -#endif - - /* Mouse moved -> send event if asked */ - if (This->hEvent) - SetEvent(This->hEvent); - - if (wparam == WM_MOUSEMOVE) { - if (This->absolute) { - if (hook->pt.x != This->prevX) - GEN_EVENT(This->offset_array[WINE_MOUSE_X_POSITION], hook->pt.x, hook->time, 0); - if (hook->pt.y != This->prevY) - GEN_EVENT(This->offset_array[WINE_MOUSE_Y_POSITION], hook->pt.y, hook->time, 0); - } else { - /* Now, warp handling */ - if ((This->need_warp == WARP_STARTED) && - (hook->pt.x == This->mapped_center.x) && (hook->pt.y == This->mapped_center.y)) { - /* Warp has been done... */ - This->need_warp = WARP_DONE; - goto end; - } - - /* Relative mouse input with absolute mouse event : the real fun starts here... */ - if ((This->need_warp == WARP_NEEDED) || - (This->need_warp == WARP_STARTED)) { - if (hook->pt.x != This->prevX) - GEN_EVENT(This->offset_array[WINE_MOUSE_X_POSITION], hook->pt.x - This->prevX, - hook->time, (This->dinput->evsequence)++); - if (hook->pt.y != This->prevY) - GEN_EVENT(This->offset_array[WINE_MOUSE_Y_POSITION], hook->pt.y - This->prevY, - hook->time, (This->dinput->evsequence)++); - } else { - /* This is the first time the event handler has been called after a - GetDeviceData or GetDeviceState. */ - if (hook->pt.x != This->mapped_center.x) { - GEN_EVENT(This->offset_array[WINE_MOUSE_X_POSITION], hook->pt.x - This->mapped_center.x, - hook->time, (This->dinput->evsequence)++); - This->need_warp = WARP_NEEDED; - } - - if (hook->pt.y != This->mapped_center.y) { - GEN_EVENT(This->offset_array[WINE_MOUSE_Y_POSITION], hook->pt.y - This->mapped_center.y, - hook->time, (This->dinput->evsequence)++); - This->need_warp = WARP_NEEDED; - } - } - } - - This->prevX = hook->pt.x; - This->prevY = hook->pt.y; - - if (This->absolute) { - This->m_state.lX = hook->pt.x; - This->m_state.lY = hook->pt.y; - } else { - This->m_state.lX = hook->pt.x - This->mapped_center.x; - This->m_state.lY = hook->pt.y - This->mapped_center.y; - } - } - - TRACE(" msg %x pt %ld %ld (W=%d)\n", - wparam, hook->pt.x, hook->pt.y, (!This->absolute) && This->need_warp ); - switch(wparam) { + case WM_MOUSEMOVE: + { + POINT pt, pt1; + + GetCursorPos(&pt); + This->m_state.lX += pt.x = hook->pt.x - pt.x; + This->m_state.lY += pt.y = hook->pt.y - pt.y; + + if (This->base.data_format.user_df->dwFlags & DIDF_ABSAXIS) + { + pt1.x = This->m_state.lX; + pt1.y = This->m_state.lY; + } else + pt1 = pt; + + if (pt.x) + { + inst_id = DIDFT_MAKEINSTANCE(WINE_MOUSE_X_AXIS_INSTANCE) | DIDFT_RELAXIS; + wdata = pt1.x; + } + if (pt.y) + { + /* Already have X, need to queue it */ + if (inst_id != -1) + queue_event((LPDIRECTINPUTDEVICE8A)This, id_to_offset(&This->base.data_format, inst_id), + wdata, GetCurrentTime(), This->base.dinput->evsequence); + inst_id = DIDFT_MAKEINSTANCE(WINE_MOUSE_Y_AXIS_INSTANCE) | DIDFT_RELAXIS; + wdata = pt1.y; + } + + This->need_warp = This->warp_override != WARP_DISABLE && + (pt.x || pt.y) && + (dwCoop & DISCL_EXCLUSIVE || This->warp_override == WARP_FORCE_ON); + break; + } + case WM_MOUSEWHEEL: + inst_id = DIDFT_MAKEINSTANCE(WINE_MOUSE_Z_AXIS_INSTANCE) | DIDFT_RELAXIS; + This->m_state.lZ += wdata = (short)HIWORD(hook->mouseData); + break; case WM_LBUTTONDOWN: - GEN_EVENT(This->offset_array[WINE_MOUSE_L_POSITION], 0x80, - hook->time, This->dinput->evsequence++); - This->m_state.rgbButtons[0] = 0x80; + inst_id = DIDFT_MAKEINSTANCE(WINE_MOUSE_BUTTONS_INSTANCE + 0) | DIDFT_PSHBUTTON; + This->m_state.rgbButtons[0] = wdata = 0x80; break; case WM_LBUTTONUP: - GEN_EVENT(This->offset_array[WINE_MOUSE_L_POSITION], 0x00, - hook->time, This->dinput->evsequence++); - This->m_state.rgbButtons[0] = 0x00; + inst_id = DIDFT_MAKEINSTANCE(WINE_MOUSE_BUTTONS_INSTANCE + 0) | DIDFT_PSHBUTTON; + This->m_state.rgbButtons[0] = wdata = 0x00; break; case WM_RBUTTONDOWN: - GEN_EVENT(This->offset_array[WINE_MOUSE_R_POSITION], 0x80, - hook->time, This->dinput->evsequence++); - This->m_state.rgbButtons[1] = 0x80; + inst_id = DIDFT_MAKEINSTANCE(WINE_MOUSE_BUTTONS_INSTANCE + 1) | DIDFT_PSHBUTTON; + This->m_state.rgbButtons[1] = wdata = 0x80; break; case WM_RBUTTONUP: - GEN_EVENT(This->offset_array[WINE_MOUSE_R_POSITION], 0x00, - hook->time, This->dinput->evsequence++); - This->m_state.rgbButtons[1] = 0x00; + inst_id = DIDFT_MAKEINSTANCE(WINE_MOUSE_BUTTONS_INSTANCE + 1) | DIDFT_PSHBUTTON; + This->m_state.rgbButtons[1] = wdata = 0x00; break; case WM_MBUTTONDOWN: - GEN_EVENT(This->offset_array[WINE_MOUSE_M_POSITION], 0x80, - hook->time, This->dinput->evsequence++); - This->m_state.rgbButtons[2] = 0x80; + inst_id = DIDFT_MAKEINSTANCE(WINE_MOUSE_BUTTONS_INSTANCE + 2) | DIDFT_PSHBUTTON; + This->m_state.rgbButtons[2] = wdata = 0x80; break; case WM_MBUTTONUP: - GEN_EVENT(This->offset_array[WINE_MOUSE_M_POSITION], 0x00, - hook->time, This->dinput->evsequence++); - This->m_state.rgbButtons[2] = 0x00; - break; - case WM_MOUSEWHEEL: - wdata = (short)HIWORD(hook->mouseData); - GEN_EVENT(This->offset_array[WINE_MOUSE_Z_POSITION], wdata, - hook->time, This->dinput->evsequence++); - This->m_state.lZ += wdata; + inst_id = DIDFT_MAKEINSTANCE(WINE_MOUSE_BUTTONS_INSTANCE + 2) | DIDFT_PSHBUTTON; + This->m_state.rgbButtons[2] = wdata = 0x00; break; + case WM_XBUTTONDOWN: + inst_id = DIDFT_MAKEINSTANCE(WINE_MOUSE_BUTTONS_INSTANCE + 2 + HIWORD(hook->mouseData)) | DIDFT_PSHBUTTON; + This->m_state.rgbButtons[2 + HIWORD(hook->mouseData)] = wdata = 0x80; + break; + case WM_XBUTTONUP: + inst_id = DIDFT_MAKEINSTANCE(WINE_MOUSE_BUTTONS_INSTANCE + 2 + HIWORD(hook->mouseData)) | DIDFT_PSHBUTTON; + This->m_state.rgbButtons[2 + HIWORD(hook->mouseData)] = wdata = 0x00; + break; } - - TRACE("(X: %ld - Y: %ld L: %02x M: %02x R: %02x)\n", - This->m_state.lX, This->m_state.lY, - This->m_state.rgbButtons[0], This->m_state.rgbButtons[2], This->m_state.rgbButtons[1]); - - end: - LeaveCriticalSection(&(This->crit)); - - if (dwCoop & DISCL_NONEXCLUSIVE) { - /* Pass the events down to previous handlers (e.g. win32 input) */ - ret = CallNextHookEx( This->hook, code, wparam, lparam ); - } else { - /* Ignore message */ - ret = 1; + + + if (inst_id != -1) + { + _dump_mouse_state(&This->m_state); + queue_event((LPDIRECTINPUTDEVICE8A)This, id_to_offset(&This->base.data_format, inst_id), + wdata, GetCurrentTime(), This->base.dinput->evsequence++); } - return ret; + + LeaveCriticalSection(&This->base.crit); } - -static void dinput_window_check(SysMouseImpl* This) { +static BOOL dinput_window_check(SysMouseImpl* This) { RECT rect; DWORD centerX, centerY; - + /* make sure the window hasn't moved */ - GetWindowRect(This->win, &rect); + if(!GetWindowRect(This->base.win, &rect)) + return FALSE; centerX = (rect.right - rect.left) / 2; centerY = (rect.bottom - rect.top ) / 2; if (This->win_centerX != centerX || This->win_centerY != centerY) { @@ -580,7 +398,8 @@ static void dinput_window_check(SysMouseImpl* This) { } This->mapped_center.x = This->win_centerX; This->mapped_center.y = This->win_centerY; - MapWindowPoints(This->win, HWND_DESKTOP, &This->mapped_center, 1); + MapWindowPoints(This->base.win, HWND_DESKTOP, &This->mapped_center, 1); + return TRUE; } @@ -592,24 +411,18 @@ static HRESULT WINAPI SysMouseAImpl_Acquire(LPDIRECTINPUTDEVICE8A iface) SysMouseImpl *This = (SysMouseImpl *)iface; RECT rect; POINT point; + HRESULT res; TRACE("(this=%p)\n",This); - - if (This->acquired) - return S_FALSE; - - This->acquired = 1; - /* Store (in a global variable) the current lock */ - current_lock = (IDirectInputDevice8A*)This; - + if ((res = IDirectInputDevice2AImpl_Acquire(iface)) != DI_OK) return res; + /* Init the mouse state */ GetCursorPos( &point ); - if (This->absolute) { + if (This->base.data_format.user_df->dwFlags & DIDF_ABSAXIS) + { This->m_state.lX = point.x; This->m_state.lY = point.y; - This->prevX = point.x; - This->prevY = point.y; } else { This->m_state.lX = 0; This->m_state.lY = 0; @@ -621,29 +434,42 @@ static HRESULT WINAPI SysMouseAImpl_Acquire(LPDIRECTINPUTDEVICE8A iface) This->m_state.rgbButtons[2] = GetKeyState(VK_MBUTTON) & 0x80; /* Install our mouse hook */ - if (This->dwCoopLevel & DISCL_EXCLUSIVE) + if (This->base.dwCoopLevel & DISCL_EXCLUSIVE) + { + RECT rc; + ShowCursor(FALSE); /* hide cursor */ - This->hook = SetWindowsHookExA( WH_MOUSE_LL, dinput_mouse_hook, DINPUT_instance, 0 ); - + if (GetWindowRect(This->base.win, &rc)) + { + FIXME("Clipping cursor to %s\n", wine_dbgstr_rect( &rc )); + ClipCursor(&rc); + } + else + ERR("Failed to get RECT: %d\n", GetLastError()); + } + + /* Need a window to warp mouse in. */ + if (This->warp_override == WARP_FORCE_ON && !This->base.win) + This->base.win = GetDesktopWindow(); + /* Get the window dimension and find the center */ - GetWindowRect(This->win, &rect); + GetWindowRect(This->base.win, &rect); This->win_centerX = (rect.right - rect.left) / 2; This->win_centerY = (rect.bottom - rect.top ) / 2; - + /* Warp the mouse to the center of the window */ - if (This->absolute == 0) { + if (This->base.dwCoopLevel & DISCL_EXCLUSIVE || This->warp_override == WARP_FORCE_ON) + { This->mapped_center.x = This->win_centerX; This->mapped_center.y = This->win_centerY; - MapWindowPoints(This->win, HWND_DESKTOP, &This->mapped_center, 1); - TRACE("Warping mouse to %ld - %ld\n", This->mapped_center.x, This->mapped_center.y); + MapWindowPoints(This->base.win, HWND_DESKTOP, &This->mapped_center, 1); + TRACE("Warping mouse to %d - %d\n", This->mapped_center.x, This->mapped_center.y); SetCursorPos( This->mapped_center.x, This->mapped_center.y ); -#ifdef MOUSE_HACK - This->need_warp = WARP_DONE; -#else - This->need_warp = WARP_STARTED; -#endif + This->last_warped = GetCurrentTime(); + + This->need_warp = FALSE; } - + return DI_OK; } @@ -653,60 +479,28 @@ static HRESULT WINAPI SysMouseAImpl_Acquire(LPDIRECTINPUTDEVICE8A iface) static HRESULT WINAPI SysMouseAImpl_Unacquire(LPDIRECTINPUTDEVICE8A iface) { SysMouseImpl *This = (SysMouseImpl *)iface; + HRESULT res; TRACE("(this=%p)\n",This); - - if (0 == This->acquired) { - return DI_NOEFFECT; - } - - /* Reinstall previous mouse event handler */ - if (This->hook) { - UnhookWindowsHookEx( This->hook ); - This->hook = 0; - - if (This->dwCoopLevel & DISCL_EXCLUSIVE) - ShowCursor(TRUE); /* show cursor */ - } - - /* No more locks */ - if (current_lock == (IDirectInputDevice8A*) This) - current_lock = NULL; - else - ERR("this(%p) != current_lock(%p)\n", This, current_lock); - /* Unacquire device */ - This->acquired = 0; - + if ((res = IDirectInputDevice2AImpl_Unacquire(iface)) != DI_OK) return res; + + if (This->base.dwCoopLevel & DISCL_EXCLUSIVE) + { + ClipCursor(NULL); + ShowCursor(TRUE); /* show cursor */ + } + /* And put the mouse cursor back where it was at acquire time */ - if (This->absolute == 0) { - TRACE(" warping mouse back to (%ld , %ld)\n", This->org_coords.x, This->org_coords.y); + if (This->base.dwCoopLevel & DISCL_EXCLUSIVE || This->warp_override == WARP_FORCE_ON) + { + TRACE(" warping mouse back to (%d , %d)\n", This->org_coords.x, This->org_coords.y); SetCursorPos(This->org_coords.x, This->org_coords.y); } return DI_OK; } -// if you call poll then to getdevicestate -// it did not send back right value in windows -int poll_mouse=0; - - -static HRESULT WINAPI SysMouseAImpl_Poll(LPDIRECTINPUTDEVICE8A iface) -{ - int retValue = DI_OK; - - if (poll_mouse==0) { - retValue=SysMouseAImpl_Acquire(iface); - poll_mouse=1; - if (retValue!=DI_OK) retValue=DIERR_NOTACQUIRED; - else retValue = DI_OK; - } - - return retValue; -} - - /****************************************************************************** * GetDeviceState : returns the "state" of the mouse. * @@ -718,48 +512,36 @@ static HRESULT WINAPI SysMouseAImpl_GetDeviceState( ) { SysMouseImpl *This = (SysMouseImpl *)iface; - if(This->acquired == 0) return DIERR_NOTACQUIRED; + if(This->base.acquired == 0) return DIERR_NOTACQUIRED; - EnterCriticalSection(&(This->crit)); - TRACE("(this=%p,0x%08lx,%p):\n", This, len, ptr); - TRACE("(X: %ld - Y: %ld - Z: %ld L: %02x M: %02x R: %02x)\n", - This->m_state.lX, This->m_state.lY, This->m_state.lZ, - This->m_state.rgbButtons[0], This->m_state.rgbButtons[2], This->m_state.rgbButtons[1]); - + TRACE("(this=%p,0x%08x,%p):\n", This, len, ptr); + _dump_mouse_state(&This->m_state); + + EnterCriticalSection(&This->base.crit); /* Copy the current mouse state */ - fill_DataFormat(ptr, &(This->m_state), This->wine_df); - -#ifdef __REACTOS__ - // this fix windows bugs when - // some program calling on mouse poll - if (poll_mouse==1) poll_mouse=0; - else { - if (This->absolute == 0) { + fill_DataFormat(ptr, len, &This->m_state, &This->base.data_format); + + /* Initialize the buffer when in relative mode */ + if (!(This->base.data_format.user_df->dwFlags & DIDF_ABSAXIS)) + { This->m_state.lX = 0; This->m_state.lY = 0; This->m_state.lZ = 0; } - } -#endif - + LeaveCriticalSection(&This->base.crit); + /* Check if we need to do a mouse warping */ - if (This->need_warp == WARP_NEEDED) { - dinput_window_check(This); - TRACE("Warping mouse to %ld - %ld\n", This->mapped_center.x, This->mapped_center.y); - if (mouse_set==0){ + if (This->need_warp && (GetCurrentTime() - This->last_warped > 10)) + { + if(!dinput_window_check(This)) + return DIERR_GENERIC; + TRACE("Warping mouse to %d - %d\n", This->mapped_center.x, This->mapped_center.y); SetCursorPos( This->mapped_center.x, This->mapped_center.y ); - mouse_set++; - } - -#ifdef MOUSE_HACK - This->need_warp = WARP_DONE; -#else - This->need_warp = WARP_STARTED; -#endif + This->last_warped = GetCurrentTime(); + + This->need_warp = FALSE; } - LeaveCriticalSection(&(This->crit)); - return DI_OK; } @@ -767,139 +549,26 @@ static HRESULT WINAPI SysMouseAImpl_GetDeviceState( * GetDeviceData : gets buffered input data. */ static HRESULT WINAPI SysMouseAImpl_GetDeviceData(LPDIRECTINPUTDEVICE8A iface, - DWORD dodsize, - LPDIDEVICEOBJECTDATA dod, - LPDWORD entries, - DWORD flags -) { - SysMouseImpl *This = (SysMouseImpl *)iface; - DWORD len; - int nqtail = 0; - - TRACE("(%p)->(dods=%ld,dod=%p,entries=%p (%ld)%s,fl=0x%08lx%s)\n",This,dodsize,dod, - entries, *entries,*entries == INFINITE ? " (INFINITE)" : "", - flags, (flags & DIGDD_PEEK) ? " (DIGDD_PEEK)": "" ); - - if (This->acquired == 0) { - WARN(" application tries to get data from an unacquired device !\n"); - //return DIERR_NOTACQUIRED; - - // windows does not get any data if - // we do not call manual to mouse Acquire - // this is only need if some apps calling on getdevice data direcly - // in windows GetdeviceData does always update first the data - // then return it. - SysMouseAImpl_Acquire(iface); - } - - EnterCriticalSection(&(This->crit)); - - len = ((This->queue_head < This->queue_tail) ? This->queue_len : 0) - + (This->queue_head - This->queue_tail); - if ((*entries != INFINITE) && (len > *entries)) len = *entries; - - if (dod == NULL) { - *entries = len; - - if (!(flags & DIGDD_PEEK)) { - if (len) - TRACE("Application discarding %ld event(s).\n", len); - - nqtail = This->queue_tail + len; - while (nqtail >= This->queue_len) nqtail -= This->queue_len; - } else { - TRACE("Telling application that %ld event(s) are in the queue.\n", len); - } - } else { - if (dodsize < sizeof(DIDEVICEOBJECTDATA_DX3)) { - ERR("Wrong structure size !\n"); - LeaveCriticalSection(&(This->crit)); - return DIERR_INVALIDPARAM; - } - - if (len) - TRACE("Application retrieving %ld event(s):\n", len); - - *entries = 0; - nqtail = This->queue_tail; - while (len) { - /* Copy the buffered data into the application queue */ - TRACE(" - queuing Offs:%2ld Data:%5ld TS:%8ld Seq:%8ld at address %p from queue tail %4d\n", - (This->data_queue)->dwOfs, - (This->data_queue)->dwData, - (This->data_queue)->dwTimeStamp, - (This->data_queue)->dwSequence, - (char *)dod + *entries * dodsize, - nqtail); - memcpy((char *)dod + *entries * dodsize, This->data_queue + nqtail, dodsize); - /* Advance position */ - nqtail++; - if (nqtail >= This->queue_len) - nqtail -= This->queue_len; - (*entries)++; - len--; - } - } - if (!(flags & DIGDD_PEEK)) - This->queue_tail = nqtail; - - LeaveCriticalSection(&(This->crit)); - - /* Check if we need to do a mouse warping */ - if (This->need_warp == WARP_NEEDED) { - dinput_window_check(This); - TRACE("Warping mouse to %ld - %ld\n", This->mapped_center.x, This->mapped_center.y); - if (mouse_set==0){ - SetCursorPos( This->mapped_center.x, This->mapped_center.y ); - mouse_set++; - } - -#ifdef MOUSE_HACK - This->need_warp = WARP_DONE; -#else - This->need_warp = WARP_STARTED; -#endif - } - return DI_OK; -} - -/****************************************************************************** - * SetProperty : change input device properties - */ -static HRESULT WINAPI SysMouseAImpl_SetProperty(LPDIRECTINPUTDEVICE8A iface, - REFGUID rguid, - LPCDIPROPHEADER ph) + DWORD dodsize, LPDIDEVICEOBJECTDATA dod, LPDWORD entries, DWORD flags) { SysMouseImpl *This = (SysMouseImpl *)iface; - - TRACE("(this=%p,%s,%p)\n",This,debugstr_guid(rguid),ph); - - if (!HIWORD(rguid)) { - switch (LOWORD(rguid)) { - case (DWORD) DIPROP_BUFFERSIZE: { - LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph; - - TRACE("buffersize = %ld\n",pd->dwData); - - This->data_queue = HeapAlloc(GetProcessHeap(),0, pd->dwData * sizeof(DIDEVICEOBJECTDATA)); - This->queue_head = 0; - This->queue_tail = 0; - This->queue_len = pd->dwData; - break; - } - case (DWORD) DIPROP_AXISMODE: { - LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph; - This->absolute = !(pd->dwData); - TRACE("Using %s coordinates mode now\n", This->absolute ? "absolute" : "relative"); - break; - } - default: - FIXME("Unknown type %p (%s)\n",rguid,debugstr_guid(rguid)); - break; - } + HRESULT res; + + res = IDirectInputDevice2AImpl_GetDeviceData(iface, dodsize, dod, entries, flags); + if (FAILED(res)) return res; + + /* Check if we need to do a mouse warping */ + if (This->need_warp && (GetCurrentTime() - This->last_warped > 10)) + { + if(!dinput_window_check(This)) + return DIERR_GENERIC; + TRACE("Warping mouse to %d - %d\n", This->mapped_center.x, This->mapped_center.y); + SetCursorPos( This->mapped_center.x, This->mapped_center.y ); + This->last_warped = GetCurrentTime(); + + This->need_warp = FALSE; } - - return DI_OK; + return res; } /****************************************************************************** @@ -911,23 +580,12 @@ static HRESULT WINAPI SysMouseAImpl_GetProperty(LPDIRECTINPUTDEVICE8A iface, { SysMouseImpl *This = (SysMouseImpl *)iface; - TRACE("(this=%p,%s,%p)\n", - iface, debugstr_guid(rguid), pdiph); - - if (TRACE_ON(dinput)) - _dump_DIPROPHEADER(pdiph); + TRACE("(%p) %s,%p\n", This, debugstr_guid(rguid), pdiph); + _dump_DIPROPHEADER(pdiph); if (!HIWORD(rguid)) { switch (LOWORD(rguid)) { - case (DWORD) DIPROP_BUFFERSIZE: { - LPDIPROPDWORD pd = (LPDIPROPDWORD)pdiph; - - TRACE(" return buffersize = %d\n",This->queue_len); - pd->dwData = This->queue_len; - break; - } - - case (DWORD) DIPROP_GRANULARITY: { + case (DWORD_PTR) DIPROP_GRANULARITY: { LPDIPROPDWORD pr = (LPDIPROPDWORD) pdiph; /* We'll just assume that the app asks about the Z axis */ @@ -936,7 +594,7 @@ static HRESULT WINAPI SysMouseAImpl_GetProperty(LPDIRECTINPUTDEVICE8A iface, break; } - case (DWORD) DIPROP_RANGE: { + case (DWORD_PTR) DIPROP_RANGE: { LPDIPROPRANGE pr = (LPDIPROPRANGE) pdiph; if ((pdiph->dwHow == DIPH_BYID) && @@ -951,34 +609,17 @@ static HRESULT WINAPI SysMouseAImpl_GetProperty(LPDIRECTINPUTDEVICE8A iface, break; } - + default: - FIXME("Unknown type %p (%s)\n",rguid,debugstr_guid(rguid)); - break; - } - } - - return DI_OK; -} - - - -/****************************************************************************** - * SetEventNotification : specifies event to be sent on state change - */ -static HRESULT WINAPI SysMouseAImpl_SetEventNotification(LPDIRECTINPUTDEVICE8A iface, - HANDLE hnd) { - SysMouseImpl *This = (SysMouseImpl *)iface; - - TRACE("(this=%p,%p)\n",This,hnd); - - This->hEvent = hnd; + return IDirectInputDevice2AImpl_GetProperty(iface, rguid, pdiph); + } + } return DI_OK; } /****************************************************************************** - * GetCapabilities : get the device capablitites + * GetCapabilities : get the device capabilities */ static HRESULT WINAPI SysMouseAImpl_GetCapabilities( LPDIRECTINPUTDEVICE8A iface, @@ -996,12 +637,12 @@ static HRESULT WINAPI SysMouseAImpl_GetCapabilities( devcaps.dwSize = lpDIDevCaps->dwSize; devcaps.dwFlags = DIDC_ATTACHED; - if (This->dinput->dwVersion >= 0x0800) + if (This->base.dinput->dwVersion >= 0x0800) devcaps.dwDevType = DI8DEVTYPE_MOUSE | (DI8DEVTYPEMOUSE_TRADITIONAL << 8); else devcaps.dwDevType = DIDEVTYPE_MOUSE | (DIDEVTYPEMOUSE_TRADITIONAL << 8); devcaps.dwAxes = 3; - devcaps.dwButtons = 3; + devcaps.dwButtons = 8; devcaps.dwPOVs = 0; devcaps.dwFFSamplePeriod = 0; devcaps.dwFFMinTimeResolution = 0; @@ -1014,97 +655,50 @@ static HRESULT WINAPI SysMouseAImpl_GetCapabilities( return DI_OK; } - /****************************************************************************** - * EnumObjects : enumerate the different buttons and axis... + * GetObjectInfo : get information about a device object such as a button + * or axis */ -static HRESULT WINAPI SysMouseAImpl_EnumObjects( - LPDIRECTINPUTDEVICE8A iface, - LPDIENUMDEVICEOBJECTSCALLBACKA lpCallback, - LPVOID lpvRef, - DWORD dwFlags) +static HRESULT WINAPI SysMouseWImpl_GetObjectInfo(LPDIRECTINPUTDEVICE8W iface, + LPDIDEVICEOBJECTINSTANCEW pdidoi, DWORD dwObj, DWORD dwHow) { - SysMouseImpl *This = (SysMouseImpl *)iface; - DIDEVICEOBJECTINSTANCEA ddoi; - - TRACE("(this=%p,%p,%p,%08lx)\n", This, lpCallback, lpvRef, dwFlags); - if (TRACE_ON(dinput)) { - TRACE(" - flags = "); - _dump_EnumObjects_flags(dwFlags); - TRACE("\n"); - } - - /* Only the fields till dwFFMaxForce are relevant */ - memset(&ddoi, 0, sizeof(ddoi)); - ddoi.dwSize = FIELD_OFFSET(DIDEVICEOBJECTINSTANCEA, dwFFMaxForce); - - /* In a mouse, we have : two relative axis and three buttons */ - if ((dwFlags == DIDFT_ALL) || - (dwFlags & DIDFT_AXIS)) { - /* X axis */ - ddoi.guidType = GUID_XAxis; - ddoi.dwOfs = This->offset_array[WINE_MOUSE_X_POSITION]; - ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_X_AXIS_INSTANCE) | DIDFT_RELAXIS; - strcpy(ddoi.tszName, "X-Axis"); - _dump_OBJECTINSTANCEA(&ddoi); - if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK; - - /* Y axis */ - ddoi.guidType = GUID_YAxis; - ddoi.dwOfs = This->offset_array[WINE_MOUSE_Y_POSITION]; - ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_Y_AXIS_INSTANCE) | DIDFT_RELAXIS; - strcpy(ddoi.tszName, "Y-Axis"); - _dump_OBJECTINSTANCEA(&ddoi); - if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK; - - /* Z axis */ - ddoi.guidType = GUID_ZAxis; - ddoi.dwOfs = This->offset_array[WINE_MOUSE_Z_POSITION]; - ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_Z_AXIS_INSTANCE) | DIDFT_RELAXIS; - strcpy(ddoi.tszName, "Z-Axis"); - _dump_OBJECTINSTANCEA(&ddoi); - if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK; - } + static const WCHAR x_axisW[] = {'X','-','A','x','i','s',0}; + static const WCHAR y_axisW[] = {'Y','-','A','x','i','s',0}; + static const WCHAR wheelW[] = {'W','h','e','e','l',0}; + static const WCHAR buttonW[] = {'B','u','t','t','o','n',' ','%','d',0}; + HRESULT res; - if ((dwFlags == DIDFT_ALL) || - (dwFlags & DIDFT_BUTTON)) { - ddoi.guidType = GUID_Button; - - /* Left button */ - ddoi.dwOfs = This->offset_array[WINE_MOUSE_L_POSITION]; - ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_L_BUTTON_INSTANCE) | DIDFT_PSHBUTTON; - strcpy(ddoi.tszName, "Left-Button"); - _dump_OBJECTINSTANCEA(&ddoi); - if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK; - - /* Right button */ - ddoi.dwOfs = This->offset_array[WINE_MOUSE_R_POSITION]; - ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_R_BUTTON_INSTANCE) | DIDFT_PSHBUTTON; - strcpy(ddoi.tszName, "Right-Button"); - _dump_OBJECTINSTANCEA(&ddoi); - if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK; - - /* Middle button */ - ddoi.dwOfs = This->offset_array[WINE_MOUSE_M_POSITION]; - ddoi.dwType = DIDFT_MAKEINSTANCE(WINE_MOUSE_M_BUTTON_INSTANCE) | DIDFT_PSHBUTTON; - strcpy(ddoi.tszName, "Middle-Button"); - _dump_OBJECTINSTANCEA(&ddoi); - if (lpCallback(&ddoi, lpvRef) != DIENUM_CONTINUE) return DI_OK; - } - - return DI_OK; + res = IDirectInputDevice2WImpl_GetObjectInfo(iface, pdidoi, dwObj, dwHow); + if (res != DI_OK) return res; + + if (IsEqualGUID(&pdidoi->guidType, &GUID_XAxis)) strcpyW(pdidoi->tszName, x_axisW); + else if (IsEqualGUID(&pdidoi->guidType, &GUID_YAxis)) strcpyW(pdidoi->tszName, y_axisW); + else if (IsEqualGUID(&pdidoi->guidType, &GUID_ZAxis)) strcpyW(pdidoi->tszName, wheelW); + else if (pdidoi->dwType & DIDFT_BUTTON) + wsprintfW(pdidoi->tszName, buttonW, DIDFT_GETINSTANCE(pdidoi->dwType) - 3); + + _dump_OBJECTINSTANCEW(pdidoi); + return res; } -static HRESULT WINAPI SysMouseWImpl_EnumObjects(LPDIRECTINPUTDEVICE8W iface, LPDIENUMDEVICEOBJECTSCALLBACKW lpCallback, LPVOID lpvRef,DWORD dwFlags) +static HRESULT WINAPI SysMouseAImpl_GetObjectInfo(LPDIRECTINPUTDEVICE8A iface, + LPDIDEVICEOBJECTINSTANCEA pdidoi, DWORD dwObj, DWORD dwHow) { - SysMouseImpl *This = (SysMouseImpl *)iface; - - device_enumobjects_AtoWcb_data data; - - data.lpCallBack = lpCallback; - data.lpvRef = lpvRef; - - return SysMouseAImpl_EnumObjects((LPDIRECTINPUTDEVICE8A) This, (LPDIENUMDEVICEOBJECTSCALLBACKA) DIEnumDevicesCallbackAtoW, (LPVOID) &data, dwFlags); + HRESULT res; + DIDEVICEOBJECTINSTANCEW didoiW; + DWORD dwSize = pdidoi->dwSize; + + didoiW.dwSize = sizeof(didoiW); + res = SysMouseWImpl_GetObjectInfo((LPDIRECTINPUTDEVICE8W)iface, &didoiW, dwObj, dwHow); + if (res != DI_OK) return res; + + memset(pdidoi, 0, pdidoi->dwSize); + memcpy(pdidoi, &didoiW, FIELD_OFFSET(DIDEVICEOBJECTINSTANCEW, tszName)); + pdidoi->dwSize = dwSize; + WideCharToMultiByte(CP_ACP, 0, didoiW.tszName, -1, pdidoi->tszName, + sizeof(pdidoi->tszName), NULL, NULL); + + return res; } /****************************************************************************** @@ -1122,7 +716,7 @@ static HRESULT WINAPI SysMouseAImpl_GetDeviceInfo( return DI_OK; } - fill_mouse_dideviceinstanceA(pdidi, This->dinput->dwVersion); + fill_mouse_dideviceinstanceA(pdidi, This->base.dinput->dwVersion); return DI_OK; } @@ -1137,7 +731,7 @@ static HRESULT WINAPI SysMouseWImpl_GetDeviceInfo(LPDIRECTINPUTDEVICE8W iface, L return DI_OK; } - fill_mouse_dideviceinstanceW(pdidi, This->dinput->dwVersion); + fill_mouse_dideviceinstanceW(pdidi, This->base.dinput->dwVersion); return DI_OK; } @@ -1147,19 +741,19 @@ static const IDirectInputDevice8AVtbl SysMouseAvt = { IDirectInputDevice2AImpl_QueryInterface, IDirectInputDevice2AImpl_AddRef, - SysMouseAImpl_Release, + IDirectInputDevice2AImpl_Release, SysMouseAImpl_GetCapabilities, - SysMouseAImpl_EnumObjects, + IDirectInputDevice2AImpl_EnumObjects, SysMouseAImpl_GetProperty, - SysMouseAImpl_SetProperty, + IDirectInputDevice2AImpl_SetProperty, SysMouseAImpl_Acquire, SysMouseAImpl_Unacquire, SysMouseAImpl_GetDeviceState, SysMouseAImpl_GetDeviceData, - SysMouseAImpl_SetDataFormat, - SysMouseAImpl_SetEventNotification, - SysMouseAImpl_SetCooperativeLevel, - IDirectInputDevice2AImpl_GetObjectInfo, + IDirectInputDevice2AImpl_SetDataFormat, + IDirectInputDevice2AImpl_SetEventNotification, + IDirectInputDevice2AImpl_SetCooperativeLevel, + SysMouseAImpl_GetObjectInfo, SysMouseAImpl_GetDeviceInfo, IDirectInputDevice2AImpl_RunControlPanel, IDirectInputDevice2AImpl_Initialize, @@ -1170,7 +764,7 @@ static const IDirectInputDevice8AVtbl SysMouseAvt = IDirectInputDevice2AImpl_SendForceFeedbackCommand, IDirectInputDevice2AImpl_EnumCreatedEffectObjects, IDirectInputDevice2AImpl_Escape, - SysMouseAImpl_Poll, + IDirectInputDevice2AImpl_Poll, IDirectInputDevice2AImpl_SendDeviceData, IDirectInputDevice7AImpl_EnumEffectsInFile, IDirectInputDevice7AImpl_WriteEffectToFile, @@ -1189,19 +783,19 @@ static const IDirectInputDevice8WVtbl SysMouseWvt = { IDirectInputDevice2WImpl_QueryInterface, XCAST(AddRef)IDirectInputDevice2AImpl_AddRef, - XCAST(Release)SysMouseAImpl_Release, + XCAST(Release)IDirectInputDevice2AImpl_Release, XCAST(GetCapabilities)SysMouseAImpl_GetCapabilities, - SysMouseWImpl_EnumObjects, + IDirectInputDevice2WImpl_EnumObjects, XCAST(GetProperty)SysMouseAImpl_GetProperty, - XCAST(SetProperty)SysMouseAImpl_SetProperty, + XCAST(SetProperty)IDirectInputDevice2AImpl_SetProperty, XCAST(Acquire)SysMouseAImpl_Acquire, XCAST(Unacquire)SysMouseAImpl_Unacquire, XCAST(GetDeviceState)SysMouseAImpl_GetDeviceState, XCAST(GetDeviceData)SysMouseAImpl_GetDeviceData, - XCAST(SetDataFormat)SysMouseAImpl_SetDataFormat, - XCAST(SetEventNotification)SysMouseAImpl_SetEventNotification, - XCAST(SetCooperativeLevel)SysMouseAImpl_SetCooperativeLevel, - IDirectInputDevice2WImpl_GetObjectInfo, + XCAST(SetDataFormat)IDirectInputDevice2AImpl_SetDataFormat, + XCAST(SetEventNotification)IDirectInputDevice2AImpl_SetEventNotification, + XCAST(SetCooperativeLevel)IDirectInputDevice2AImpl_SetCooperativeLevel, + SysMouseWImpl_GetObjectInfo, SysMouseWImpl_GetDeviceInfo, XCAST(RunControlPanel)IDirectInputDevice2AImpl_RunControlPanel, XCAST(Initialize)IDirectInputDevice2AImpl_Initialize, @@ -1212,7 +806,7 @@ static const IDirectInputDevice8WVtbl SysMouseWvt = XCAST(SendForceFeedbackCommand)IDirectInputDevice2AImpl_SendForceFeedbackCommand, XCAST(EnumCreatedEffectObjects)IDirectInputDevice2AImpl_EnumCreatedEffectObjects, XCAST(Escape)IDirectInputDevice2AImpl_Escape, - XCAST(Poll)SysMouseAImpl_Poll, + XCAST(Poll)IDirectInputDevice2AImpl_Poll, XCAST(SendDeviceData)IDirectInputDevice2AImpl_SendDeviceData, IDirectInputDevice7WImpl_EnumEffectsInFile, IDirectInputDevice7WImpl_WriteEffectToFile, diff --git a/reactos/dll/directx/dinput/regsvr.c b/reactos/dll/directx/dinput/regsvr.c index e005f727396..77e2fc7350d 100644 --- a/reactos/dll/directx/dinput/regsvr.c +++ b/reactos/dll/directx/dinput/regsvr.c @@ -15,7 +15,7 @@ * * 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 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include @@ -31,6 +31,7 @@ #include "dinput.h" #include "wine/debug.h" +#include "wine/unicode.h" WINE_DEFAULT_DEBUG_CHANNEL(dinput); @@ -115,9 +116,6 @@ static LONG register_key_defvalueA(HKEY base, WCHAR const *name, static LONG register_progid(WCHAR const *clsid, char const *progid, char const *curver_progid, char const *name, char const *extra); -static LONG recursive_delete_key(HKEY key); -static LONG recursive_delete_keyA(HKEY base, char const *name); -static LONG recursive_delete_keyW(HKEY base, WCHAR const *name); /*********************************************************************** * register_interfaces @@ -148,7 +146,7 @@ static HRESULT register_interfaces(struct regsvr_interface const *list) } if (list->base_iid) { - register_key_guid(iid_key, base_ifa_keyname, list->base_iid); + res = register_key_guid(iid_key, base_ifa_keyname, list->base_iid); if (res != ERROR_SUCCESS) goto error_close_iid_key; } @@ -160,7 +158,7 @@ static HRESULT register_interfaces(struct regsvr_interface const *list) KEY_READ | KEY_WRITE, NULL, &key, NULL); if (res != ERROR_SUCCESS) goto error_close_iid_key; - wsprintfW(buf, fmt, list->num_methods); + sprintfW(buf, fmt, list->num_methods); res = RegSetValueExW(key, NULL, 0, REG_SZ, (CONST BYTE*)buf, (lstrlenW(buf) + 1) * sizeof(WCHAR)); @@ -170,12 +168,12 @@ static HRESULT register_interfaces(struct regsvr_interface const *list) } if (list->ps_clsid) { - register_key_guid(iid_key, ps_clsid_keyname, list->ps_clsid); + res = register_key_guid(iid_key, ps_clsid_keyname, list->ps_clsid); if (res != ERROR_SUCCESS) goto error_close_iid_key; } if (list->ps_clsid32) { - register_key_guid(iid_key, ps_clsid32_keyname, list->ps_clsid32); + res = register_key_guid(iid_key, ps_clsid32_keyname, list->ps_clsid32); if (res != ERROR_SUCCESS) goto error_close_iid_key; } @@ -206,7 +204,8 @@ static HRESULT unregister_interfaces(struct regsvr_interface const *list) WCHAR buf[39]; StringFromGUID2(list->iid, buf, 39); - res = recursive_delete_keyW(interface_key, buf); + //res = RegDeleteTreeW(interface_key, buf); + if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS; } RegCloseKey(interface_key); @@ -313,16 +312,19 @@ static HRESULT unregister_coclasses(struct regsvr_coclass const *list) WCHAR buf[39]; StringFromGUID2(list->clsid, buf, 39); - res = recursive_delete_keyW(coclass_key, buf); + //res = RegDeleteTreeW(coclass_key, buf); + if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS; if (res != ERROR_SUCCESS) goto error_close_coclass_key; if (list->progid) { - res = recursive_delete_keyA(HKEY_CLASSES_ROOT, list->progid); + // res = RegDeleteTreeA(HKEY_CLASSES_ROOT, list->progid); + if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS; if (res != ERROR_SUCCESS) goto error_close_coclass_key; } if (list->viprogid) { - res = recursive_delete_keyA(HKEY_CLASSES_ROOT, list->viprogid); + //res = RegDeleteTreeA(HKEY_CLASSES_ROOT, list->viprogid); + if (res == ERROR_FILE_NOT_FOUND) res = ERROR_SUCCESS; if (res != ERROR_SUCCESS) goto error_close_coclass_key; } } @@ -434,70 +436,6 @@ error_close_progid_key: return res; } -/*********************************************************************** - * recursive_delete_key - */ -static LONG recursive_delete_key(HKEY key) -{ - LONG res; - WCHAR subkey_name[MAX_PATH]; - DWORD cName; - HKEY subkey; - - for (;;) { - cName = sizeof(subkey_name) / sizeof(WCHAR); - res = RegEnumKeyExW(key, 0, subkey_name, &cName, - NULL, NULL, NULL, NULL); - if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) { - res = ERROR_SUCCESS; /* presumably we're done enumerating */ - break; - } - res = RegOpenKeyExW(key, subkey_name, 0, - KEY_READ | KEY_WRITE, &subkey); - if (res == ERROR_FILE_NOT_FOUND) continue; - if (res != ERROR_SUCCESS) break; - - res = recursive_delete_key(subkey); - RegCloseKey(subkey); - if (res != ERROR_SUCCESS) break; - } - - if (res == ERROR_SUCCESS) res = RegDeleteKeyW(key, 0); - return res; -} - -/*********************************************************************** - * recursive_delete_keyA - */ -static LONG recursive_delete_keyA(HKEY base, char const *name) -{ - LONG res; - HKEY key; - - res = RegOpenKeyExA(base, name, 0, KEY_READ | KEY_WRITE, &key); - if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS; - if (res != ERROR_SUCCESS) return res; - res = recursive_delete_key(key); - RegCloseKey(key); - return res; -} - -/*********************************************************************** - * recursive_delete_keyW - */ -static LONG recursive_delete_keyW(HKEY base, WCHAR const *name) -{ - LONG res; - HKEY key; - - res = RegOpenKeyExW(base, name, 0, KEY_READ | KEY_WRITE, &key); - if (res == ERROR_FILE_NOT_FOUND) return ERROR_SUCCESS; - if (res != ERROR_SUCCESS) return res; - res = recursive_delete_key(key); - RegCloseKey(key); - return res; -} - /*********************************************************************** * coclass list */ diff --git a/reactos/dll/directx/dinput/version.rc b/reactos/dll/directx/dinput/version.rc index 65dc50a1512..fd91f51877b 100644 --- a/reactos/dll/directx/dinput/version.rc +++ b/reactos/dll/directx/dinput/version.rc @@ -13,7 +13,7 @@ * * 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 + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #define WINE_FILEDESCRIPTION_STR "Wine DirectInput" diff --git a/reactos/include/psdk/dinput.h b/reactos/include/psdk/dinput.h index c1c8aa01f96..75ec2ae5755 100644 --- a/reactos/include/psdk/dinput.h +++ b/reactos/include/psdk/dinput.h @@ -440,6 +440,14 @@ DECL_WINELIB_TYPE_AW(DIDEVICEINSTANCE) DECL_WINELIB_TYPE_AW(LPDIDEVICEINSTANCE) DECL_WINELIB_TYPE_AW(LPCDIDEVICEINSTANCE) +#define DIEDBSFL_ATTACHEDONLY 0x00000000 +#define DIEDBSFL_THISUSER 0x00000010 +#define DIEDBSFL_FORCEFEEDBACK DIEDFL_FORCEFEEDBACK +#define DIEDBSFL_AVAILABLEDEVICES 0x00001000 +#define DIEDBSFL_MULTIMICEKEYBOARDS 0x00002000 +#define DIEDBSFL_NONGAMINGDEVICES 0x00004000 +#define DIEDBSFL_VALID 0x00007110 + typedef BOOL (CALLBACK *LPDIENUMDEVICESCALLBACKA)(LPCDIDEVICEINSTANCEA,LPVOID); typedef BOOL (CALLBACK *LPDIENUMDEVICESCALLBACKW)(LPCDIDEVICEINSTANCEW,LPVOID); DECL_WINELIB_TYPE_AW(LPDIENUMDEVICESCALLBACK) @@ -827,6 +835,10 @@ typedef struct DIDEVCAPS { #define DISCL_NONEXCLUSIVE 0x00000002 #define DISCL_FOREGROUND 0x00000004 #define DISCL_BACKGROUND 0x00000008 +#define DISCL_NOWINKEY 0x00000010 + +/* Device FF flags */ +#define DISFFC_RESET 0x00000001 #define DIEFT_ALL 0x00000000 diff --git a/reactos/media/doc/README.WINE b/reactos/media/doc/README.WINE index caf2b53a413..b4459bbcb74 100644 --- a/reactos/media/doc/README.WINE +++ b/reactos/media/doc/README.WINE @@ -121,7 +121,7 @@ reactos/dll/win32/winmm/wavemap # Forked at Wine-20050628 reactos/dll/win32/wldap32 # Autosync reactos/dll/win32/wmi # Autosync reactos/dll/win32/wtsapi32 # Autosync -reactos/dll/directx/dinput # Synced to Wine-0_9_5 +reactos/dll/directx/dinput # Synced to Wine-1_1_4 reactos/dll/directx/dinput8 # Synced to Wine-0_9_5 reactos/dll/directx/dplay # Synced to Wine-0_9_5 reactos/dll/directx/dplayx # Synced to Wine-0_9_5