This adds a new joystick backend, implemented on top of HID and without any host dependencies. This will be progressively implementated, and it's not going to be usable until at least a few more patches.
Because of that, and because it may also introduce regressions compared to the existing backends, it is disabled by default and is optionally enabled using the following global registry key:
[HKCU\Software\Wine\DirectInput\Joysticks] "HID"="enabled"
Or using the corresponding AppDefaults registry key:
[HKCU\Software\Wine\AppDefaults\<app.exe>\DirectInput\Joysticks] "HID"="enabled"
This setting will be removed later, when it becomes usable enough, to use the individual device disable mechanism available in joy.cpl.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com ---
v2: Make the backend disabled by default, optionally enabled in the registry. This is only temporary until we have at least input support.
dlls/dinput/Makefile.in | 3 +- dlls/dinput/dinput_main.c | 3 +- dlls/dinput/dinput_private.h | 1 + dlls/dinput/joystick.c | 17 +- dlls/dinput/joystick_hid.c | 450 ++++++++++++++++++++++++++++++ dlls/dinput/joystick_linux.c | 2 +- dlls/dinput/joystick_linuxinput.c | 2 +- dlls/dinput/joystick_private.h | 2 +- dlls/dinput8/Makefile.in | 3 +- 9 files changed, 472 insertions(+), 11 deletions(-) create mode 100644 dlls/dinput/joystick_hid.c
diff --git a/dlls/dinput/Makefile.in b/dlls/dinput/Makefile.in index a22c8a72180..f2347927ed6 100644 --- a/dlls/dinput/Makefile.in +++ b/dlls/dinput/Makefile.in @@ -1,6 +1,6 @@ MODULE = dinput.dll IMPORTLIB = dinput -IMPORTS = dinput dxguid uuid comctl32 ole32 user32 advapi32 +IMPORTS = dinput dxguid uuid comctl32 ole32 user32 advapi32 hid EXTRADEFS = -DDIRECTINPUT_VERSION=0x0700 EXTRALIBS = $(IOKIT_LIBS) $(FORCEFEEDBACK_LIBS)
@@ -12,6 +12,7 @@ C_SRCS = \ dinput_main.c \ effect_linuxinput.c \ joystick.c \ + joystick_hid.c \ joystick_linux.c \ joystick_linuxinput.c \ joystick_osx.c \ diff --git a/dlls/dinput/dinput_main.c b/dlls/dinput/dinput_main.c index c7b932aca44..88ee1855675 100644 --- a/dlls/dinput/dinput_main.c +++ b/dlls/dinput/dinput_main.c @@ -80,7 +80,8 @@ static const struct dinput_device *dinput_devices[] = &keyboard_device, &joystick_linuxinput_device, &joystick_linux_device, - &joystick_osx_device + &joystick_osx_device, + &joystick_hid_device, };
HINSTANCE DINPUT_instance; diff --git a/dlls/dinput/dinput_private.h b/dlls/dinput/dinput_private.h index 7e0f56c68df..c11b64585d9 100644 --- a/dlls/dinput/dinput_private.h +++ b/dlls/dinput/dinput_private.h @@ -67,6 +67,7 @@ struct DevicePlayer {
extern const struct dinput_device mouse_device DECLSPEC_HIDDEN; extern const struct dinput_device keyboard_device DECLSPEC_HIDDEN; +extern const struct dinput_device joystick_hid_device DECLSPEC_HIDDEN; extern const struct dinput_device joystick_linux_device DECLSPEC_HIDDEN; extern const struct dinput_device joystick_linuxinput_device DECLSPEC_HIDDEN; extern const struct dinput_device joystick_osx_device DECLSPEC_HIDDEN; diff --git a/dlls/dinput/joystick.c b/dlls/dinput/joystick.c index 8ea7850621c..60153d0d0f3 100644 --- a/dlls/dinput/joystick.c +++ b/dlls/dinput/joystick.c @@ -271,13 +271,13 @@ void dump_DIEFFECT(LPCDIEFFECT eff, REFGUID guid, DWORD dwFlags) } }
-BOOL device_disabled_registry(const char* name) +BOOL device_disabled_registry(const char* name, BOOL disable) { static const char disabled_str[] = "disabled"; + static const char enabled_str[] = "enabled"; static const char joystick_key[] = "Joysticks"; char buffer[MAX_PATH]; HKEY hkey, appkey, temp; - BOOL do_disable = FALSE;
get_app_key(&hkey, &appkey);
@@ -297,16 +297,23 @@ BOOL device_disabled_registry(const char* name)
/* Look for the "controllername"="disabled" key */ if (!get_config_key(hkey, appkey, name, buffer, sizeof(buffer))) - if (!strcmp(disabled_str, buffer)) + { + if (!disable && !strcmp(disabled_str, buffer)) { TRACE("Disabling joystick '%s' based on registry key.\n", name); - do_disable = TRUE; + disable = TRUE; + } + else if (disable && !strcmp(enabled_str, buffer)) + { + TRACE("Enabling joystick '%s' based on registry key.\n", name); + disable = FALSE; } + }
if (appkey) RegCloseKey(appkey); if (hkey) RegCloseKey(hkey);
- return do_disable; + return disable; }
BOOL is_xinput_device(const DIDEVCAPS *devcaps, WORD vid, WORD pid) diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c new file mode 100644 index 00000000000..fadc7d9efe4 --- /dev/null +++ b/dlls/dinput/joystick_hid.c @@ -0,0 +1,450 @@ +/* DirectInput HID Joystick device + * + * Copyright 2021 Rémi Bernon for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <assert.h> +#include <stdarg.h> +#include <string.h> + +#include "windef.h" +#include "winbase.h" +#include "winternl.h" +#include "winuser.h" +#include "winerror.h" +#include "winreg.h" + +#include "ddk/hidsdi.h" +#include "devguid.h" +#include "dinput.h" +#include "setupapi.h" + +#include "wine/debug.h" + +#include "dinput_private.h" +#include "device_private.h" +#include "joystick_private.h" + +#include "initguid.h" + +WINE_DEFAULT_DEBUG_CHANNEL(dinput); + +DEFINE_GUID( hid_joystick_guid, 0x9e573edb, 0x7734, 0x11d2, 0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf7 ); + +struct hid_joystick +{ + IDirectInputDeviceImpl base; + + HANDLE device; + PHIDP_PREPARSED_DATA preparsed; +}; + +static inline struct hid_joystick *impl_from_IDirectInputDevice8W( IDirectInputDevice8W *iface ) +{ + return CONTAINING_RECORD( CONTAINING_RECORD( iface, IDirectInputDeviceImpl, IDirectInputDevice8W_iface ), + struct hid_joystick, base ); +} + +static ULONG WINAPI hid_joystick_Release( IDirectInputDevice8W *iface ) +{ + struct hid_joystick *impl = impl_from_IDirectInputDevice8W( iface ); + struct hid_joystick tmp = *impl; + ULONG res; + + if (!(res = IDirectInputDevice2WImpl_Release( iface ))) + { + HidD_FreePreparsedData( tmp.preparsed ); + CloseHandle( tmp.device ); + } + + return res; +} + +static HRESULT WINAPI hid_joystick_GetCapabilities( IDirectInputDevice8W *iface, DIDEVCAPS *caps ) +{ + FIXME( "iface %p, caps %p stub!\n", iface, caps ); + + if (!caps) return E_POINTER; + + return E_NOTIMPL; +} + +static HRESULT WINAPI hid_joystick_EnumObjects( IDirectInputDevice8W *iface, LPDIENUMDEVICEOBJECTSCALLBACKW callback, + void *ref, DWORD flags ) +{ + FIXME( "iface %p, callback %p, ref %p, flags %#x stub!\n", iface, callback, ref, flags ); + + if (!callback) return DIERR_INVALIDPARAM; + + return E_NOTIMPL; +} + +static HRESULT WINAPI hid_joystick_GetProperty( IDirectInputDevice8W *iface, REFGUID guid, DIPROPHEADER *header ) +{ + FIXME( "iface %p, guid %s, header %p stub!\n", iface, debugstr_guid( guid ), header ); + + if (!header) return DIERR_INVALIDPARAM; + if (!IS_DIPROP( guid )) return DI_OK; + + switch (LOWORD( guid )) + { + default: return IDirectInputDevice2WImpl_GetProperty( iface, guid, header ); + } +} + +static HRESULT WINAPI hid_joystick_SetProperty( IDirectInputDevice8W *iface, REFGUID guid, const DIPROPHEADER *header ) +{ + FIXME( "iface %p, guid %s, header %p stub!\n", iface, debugstr_guid( guid ), header ); + + if (!header) return DIERR_INVALIDPARAM; + if (!IS_DIPROP( guid )) return DI_OK; + + switch (LOWORD( guid )) + { + default: return IDirectInputDevice2WImpl_SetProperty( iface, guid, header ); + } +} + +static HRESULT WINAPI hid_joystick_Acquire( IDirectInputDevice8W *iface ) +{ + HRESULT hr; + + TRACE( "iface %p.\n", iface ); + + if ((hr = IDirectInputDevice2WImpl_Acquire( iface )) != DI_OK) return hr; + + return DI_OK; +} + +static HRESULT WINAPI hid_joystick_Unacquire( IDirectInputDevice8W *iface ) +{ + HRESULT hr; + + TRACE( "iface %p.\n", iface ); + + if ((hr = IDirectInputDevice2WImpl_Unacquire( iface )) != DI_OK) return hr; + + return DI_OK; +} + +static HRESULT WINAPI hid_joystick_GetDeviceState( IDirectInputDevice8W *iface, DWORD len, void *ptr ) +{ + FIXME( "iface %p, len %u, ptr %p stub!\n", iface, len, ptr ); + + if (!ptr) return DIERR_INVALIDPARAM; + + return E_NOTIMPL; +} + +static HRESULT WINAPI hid_joystick_GetObjectInfo( IDirectInputDevice8W *iface, DIDEVICEOBJECTINSTANCEW *instance, + DWORD obj, DWORD how ) +{ + FIXME( "iface %p, instance %p, obj %#x, how %#x stub!\n", iface, instance, obj, how ); + + if (!instance) return E_POINTER; + if (instance->dwSize != sizeof(DIDEVICEOBJECTINSTANCE_DX3W) && + instance->dwSize != sizeof(DIDEVICEOBJECTINSTANCEW)) + return DIERR_INVALIDPARAM; + + return E_NOTIMPL; +} + +static HRESULT WINAPI hid_joystick_GetDeviceInfo( IDirectInputDevice8W *iface, DIDEVICEINSTANCEW *instance ) +{ + FIXME( "iface %p, instance %p stub!\n", iface, instance ); + + if (!instance) return E_POINTER; + if (instance->dwSize != sizeof(DIDEVICEINSTANCE_DX3W) && + instance->dwSize != sizeof(DIDEVICEINSTANCEW)) + return DIERR_INVALIDPARAM; + + return E_NOTIMPL; +} + +static HRESULT WINAPI hid_joystick_CreateEffect( IDirectInputDevice8W *iface, REFGUID rguid, + const DIEFFECT *effect, IDirectInputEffect **out, + IUnknown *outer ) +{ + FIXME( "iface %p, rguid %s, effect %p, out %p, outer %p stub!\n", iface, debugstr_guid( rguid ), + effect, out, outer ); + + if (!out) return E_POINTER; + if (!rguid || !effect) return DI_NOEFFECT; + + return E_NOTIMPL; +} + +static HRESULT WINAPI hid_joystick_EnumEffects( IDirectInputDevice8W *iface, LPDIENUMEFFECTSCALLBACKW callback, + void *ref, DWORD type ) +{ + FIXME( "iface %p, callback %p, ref %p, type %#x stub!\n", iface, callback, ref, type ); + + if (!callback) return DIERR_INVALIDPARAM; + + return E_NOTIMPL; +} + +static HRESULT WINAPI hid_joystick_GetEffectInfo( IDirectInputDevice8W *iface, DIEFFECTINFOW *info, REFGUID guid ) +{ + FIXME( "iface %p, info %p, guid %s stub!\n", iface, info, debugstr_guid( guid ) ); + + if (!info) return E_POINTER; + + return E_NOTIMPL; +} + +static HRESULT WINAPI hid_joystick_GetForceFeedbackState( IDirectInputDevice8W *iface, DWORD *out ) +{ + FIXME( "iface %p, out %p stub!\n", iface, out ); + + if (!out) return E_POINTER; + + return E_NOTIMPL; +} + +static HRESULT WINAPI hid_joystick_SendForceFeedbackCommand( IDirectInputDevice8W *iface, DWORD flags ) +{ + FIXME( "iface %p, flags %x stub!\n", iface, flags ); + return E_NOTIMPL; +} + +static HRESULT WINAPI hid_joystick_EnumCreatedEffectObjects( IDirectInputDevice8W *iface, + LPDIENUMCREATEDEFFECTOBJECTSCALLBACK callback, + void *ref, DWORD flags ) +{ + FIXME( "iface %p, callback %p, ref %p, flags %#x stub!\n", iface, callback, ref, flags ); + + if (!callback) return DIERR_INVALIDPARAM; + + return E_NOTIMPL; +} + +static HRESULT WINAPI hid_joystick_BuildActionMap( IDirectInputDevice8W *iface, DIACTIONFORMATW *format, + const WCHAR *username, DWORD flags ) +{ + FIXME( "iface %p, format %p, username %s, flags %#x stub!\n", iface, format, debugstr_w(username), flags ); + + if (!format) return DIERR_INVALIDPARAM; + + return E_NOTIMPL; +} + +static HRESULT WINAPI hid_joystick_SetActionMap( IDirectInputDevice8W *iface, DIACTIONFORMATW *format, + const WCHAR *username, DWORD flags ) +{ + struct hid_joystick *impl = impl_from_IDirectInputDevice8W( iface ); + + TRACE( "iface %p, format %p, username %s, flags %#x.\n", iface, format, debugstr_w(username), flags ); + + if (!format) return DIERR_INVALIDPARAM; + + return _set_action_map( iface, format, username, flags, impl->base.data_format.wine_df ); +} + +static const IDirectInputDevice8WVtbl hid_joystick_vtbl = +{ + /*** IUnknown methods ***/ + IDirectInputDevice2WImpl_QueryInterface, + IDirectInputDevice2WImpl_AddRef, + hid_joystick_Release, + /*** IDirectInputDevice methods ***/ + hid_joystick_GetCapabilities, + hid_joystick_EnumObjects, + hid_joystick_GetProperty, + hid_joystick_SetProperty, + hid_joystick_Acquire, + hid_joystick_Unacquire, + hid_joystick_GetDeviceState, + IDirectInputDevice2WImpl_GetDeviceData, + IDirectInputDevice2WImpl_SetDataFormat, + IDirectInputDevice2WImpl_SetEventNotification, + IDirectInputDevice2WImpl_SetCooperativeLevel, + hid_joystick_GetObjectInfo, + hid_joystick_GetDeviceInfo, + IDirectInputDevice2WImpl_RunControlPanel, + IDirectInputDevice2WImpl_Initialize, + /*** IDirectInputDevice2 methods ***/ + hid_joystick_CreateEffect, + hid_joystick_EnumEffects, + hid_joystick_GetEffectInfo, + hid_joystick_GetForceFeedbackState, + hid_joystick_SendForceFeedbackCommand, + hid_joystick_EnumCreatedEffectObjects, + IDirectInputDevice2WImpl_Escape, + IDirectInputDevice2WImpl_Poll, + IDirectInputDevice2WImpl_SendDeviceData, + /*** IDirectInputDevice7 methods ***/ + IDirectInputDevice7WImpl_EnumEffectsInFile, + IDirectInputDevice7WImpl_WriteEffectToFile, + /*** IDirectInputDevice8 methods ***/ + hid_joystick_BuildActionMap, + hid_joystick_SetActionMap, + IDirectInputDevice8WImpl_GetImageInfo, +}; + +static HRESULT hid_joystick_device_open( DWORD index, WCHAR *device_path, HANDLE *device, DWORD version, + PHIDP_PREPARSED_DATA *preparsed, HIDD_ATTRIBUTES *attrs, + HIDP_CAPS *caps, DIDEVICEINSTANCEW *instance ) +{ + RAWINPUTDEVICELIST *list; + DWORD count, i, j; + + GetRawInputDeviceList( NULL, &count, sizeof(*list) ); + if (!(list = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*list) ))) return DIERR_OUTOFMEMORY; + GetRawInputDeviceList( list, &count, sizeof(*list) ); + + for (i = 0; i < count; ++i) if (list[i].dwType == RIM_TYPEHID) break; + for (j = 0; j < index && i < count; ++i) if (list[i].dwType == RIM_TYPEHID) ++j; + if (i == count) + { + HeapFree( GetProcessHeap(), 0, list ); + return DIERR_DEVICENOTREG; + } + + count = MAX_PATH; + GetRawInputDeviceInfoW( list[i].hDevice, RIDI_DEVICENAME, device_path, &count ); + HeapFree( GetProcessHeap(), 0, list ); + + TRACE( "Opening %s\n", debugstr_w(device_path) ); + *device = CreateFileW( device_path, GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0 ); + *preparsed = NULL; + + if (*device == INVALID_HANDLE_VALUE) return DI_NOTATTACHED; + if (!HidD_GetPreparsedData( *device, preparsed )) goto failed; + if (!HidD_GetAttributes( *device, attrs )) goto failed; + if (HidP_GetCaps( *preparsed, caps ) != HIDP_STATUS_SUCCESS) goto failed; + + if (caps->UsagePage == HID_USAGE_PAGE_GAME) FIXME( "Unimplemented HID game usage page!\n" ); + if (caps->UsagePage == HID_USAGE_PAGE_SIMULATION) FIXME( "Unimplemented HID simulation usage page!\n" ); + if (caps->UsagePage != HID_USAGE_PAGE_GENERIC) goto failed; + if (caps->Usage != HID_USAGE_GENERIC_GAMEPAD && caps->Usage != HID_USAGE_GENERIC_JOYSTICK) goto failed; + + instance->guidInstance = hid_joystick_guid; + instance->guidInstance.Data3 = index; + instance->guidProduct = DInput_PIDVID_Product_GUID; + instance->guidProduct.Data1 = MAKELONG( attrs->VendorID, attrs->ProductID ); + instance->dwDevType = get_device_type( version, caps->Usage != HID_USAGE_GENERIC_GAMEPAD ) | DIDEVTYPE_HID; + instance->guidFFDriver = GUID_NULL; + instance->wUsagePage = caps->UsagePage; + instance->wUsage = caps->Usage; + + if (!HidD_GetProductString( *device, instance->tszInstanceName, MAX_PATH )) goto failed; + if (!HidD_GetProductString( *device, instance->tszProductName, MAX_PATH )) goto failed; + return DI_OK; + +failed: + CloseHandle( *device ); + *device = INVALID_HANDLE_VALUE; + HidD_FreePreparsedData( *preparsed ); + *preparsed = NULL; + return DI_NOTATTACHED; +} + +static HRESULT hid_joystick_enum_device( DWORD type, DWORD flags, DIDEVICEINSTANCEW *instance, + DWORD version, int index ) +{ + HIDD_ATTRIBUTES attrs = {sizeof(attrs)}; + PHIDP_PREPARSED_DATA preparsed; + WCHAR device_path[MAX_PATH]; + HIDP_CAPS caps; + HANDLE device; + HRESULT hr; + + TRACE( "type %x, flags %#x, instance %p, version %04x, index %d\n", type, flags, instance, version, index ); + + hr = hid_joystick_device_open( index, device_path, &device, version, + &preparsed, &attrs, &caps, instance ); + if (hr != DI_OK) return hr; + + HidD_FreePreparsedData( preparsed ); + CloseHandle( device ); + + if (instance->dwSize != sizeof(DIDEVICEINSTANCEW)) + return S_FALSE; + if (version < 0x0800 && type != DIDEVTYPE_JOYSTICK) + return S_FALSE; + if (version >= 0x0800 && type != DI8DEVCLASS_ALL && type != DI8DEVCLASS_GAMECTRL) + return S_FALSE; + + if (device_disabled_registry( "HID", TRUE )) + return DIERR_DEVICENOTREG; + + TRACE( "Found device with usage %04x:%04x, type %x, instance %s %s, product %s %s, ffdriver %s\n", + instance->wUsagePage, instance->wUsage, instance->dwDevType, debugstr_guid( &instance->guidProduct ), + debugstr_w( instance->tszProductName ), debugstr_guid( &instance->guidInstance ), + debugstr_w( instance->tszInstanceName ), debugstr_guid( &instance->guidFFDriver ) ); + + return DI_OK; +} + +static HRESULT hid_joystick_create_device( IDirectInputImpl *dinput, REFGUID guid, IDirectInputDevice8W **out ) +{ + DIDEVICEINSTANCEW instance = {sizeof(instance)}; + DWORD index, size = sizeof(struct hid_joystick); + HIDD_ATTRIBUTES attrs = {sizeof(attrs)}; + struct hid_joystick *impl = NULL; + PHIDP_PREPARSED_DATA preparsed; + DIDATAFORMAT *format = NULL; + WCHAR device_path[MAX_PATH]; + GUID tmp_guid = *guid; + HIDP_CAPS caps; + HANDLE device; + HRESULT hr; + + TRACE( "dinput %p, guid %s, out %p\n", dinput, debugstr_guid( guid ), out ); + + *out = NULL; + tmp_guid.Data3 = hid_joystick_guid.Data3; + if (!IsEqualGUID( &hid_joystick_guid, &tmp_guid )) return DIERR_DEVICENOTREG; + index = guid->Data3; + + hr = hid_joystick_device_open( index, device_path, &device, dinput->dwVersion, + &preparsed, &attrs, &caps, &instance ); + if (hr != DI_OK) return hr; + + hr = direct_input_device_alloc( size, &hid_joystick_vtbl, guid, dinput, (void **)&impl ); + if (FAILED(hr)) goto failed; + + impl->base.crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": hid_joystick.base.crit"); + impl->base.dwCoopLevel = DISCL_NONEXCLUSIVE | DISCL_BACKGROUND; + + impl->device = device; + impl->preparsed = preparsed; + + if (!(format = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*format) ))) goto failed; + impl->base.data_format.wine_df = format; + + TRACE( "Created %p\n", impl ); + + *out = &impl->base.IDirectInputDevice8W_iface; + return DI_OK; + +failed: + HeapFree( GetProcessHeap(), 0, format ); + HeapFree( GetProcessHeap(), 0, impl ); + HidD_FreePreparsedData( preparsed ); + CloseHandle( device ); + return hr; +} + +const struct dinput_device joystick_hid_device = +{ + "Wine HID joystick driver", + hid_joystick_enum_device, + hid_joystick_create_device, +}; diff --git a/dlls/dinput/joystick_linux.c b/dlls/dinput/joystick_linux.c index 3215978c995..312ef3d9c42 100644 --- a/dlls/dinput/joystick_linux.c +++ b/dlls/dinput/joystick_linux.c @@ -175,7 +175,7 @@ static INT find_joystick_devices(void) /* Append driver name */ strcat(joydev.name, JOYDEVDRIVER);
- if (device_disabled_registry(joydev.name)) { + if (device_disabled_registry(joydev.name, FALSE)) { close(fd); continue; } diff --git a/dlls/dinput/joystick_linuxinput.c b/dlls/dinput/joystick_linuxinput.c index 2b970271ec3..558c8cc19e5 100644 --- a/dlls/dinput/joystick_linuxinput.c +++ b/dlls/dinput/joystick_linuxinput.c @@ -264,7 +264,7 @@ static void find_joydevs(void) else joydev.name = joydev.device;
- if (device_disabled_registry(joydev.name)) { + if (device_disabled_registry(joydev.name, FALSE)) { close(fd); HeapFree(GetProcessHeap(), 0, joydev.name); if (joydev.name != joydev.device) diff --git a/dlls/dinput/joystick_private.h b/dlls/dinput/joystick_private.h index 874bf3e69a7..9cc30605234 100644 --- a/dlls/dinput/joystick_private.h +++ b/dlls/dinput/joystick_private.h @@ -57,7 +57,7 @@ HRESULT setup_dinput_options(JoystickGenericImpl *This, const int *default_axis_
DWORD joystick_map_pov(const POINTL *p) DECLSPEC_HIDDEN;
-BOOL device_disabled_registry(const char* name) DECLSPEC_HIDDEN; +BOOL device_disabled_registry(const char* name, BOOL disable) DECLSPEC_HIDDEN;
ULONG WINAPI JoystickWGenericImpl_Release(LPDIRECTINPUTDEVICE8W iface);
diff --git a/dlls/dinput8/Makefile.in b/dlls/dinput8/Makefile.in index 35b3bfb75f5..71eecd770b3 100644 --- a/dlls/dinput8/Makefile.in +++ b/dlls/dinput8/Makefile.in @@ -1,6 +1,6 @@ MODULE = dinput8.dll IMPORTLIB = dinput8 -IMPORTS = dinput8 dxguid uuid comctl32 ole32 user32 advapi32 +IMPORTS = dinput8 dxguid uuid comctl32 ole32 user32 advapi32 hid EXTRADEFS = -DDIRECTINPUT_VERSION=0x0800 EXTRALIBS = $(IOKIT_LIBS) $(FORCEFEEDBACK_LIBS) PARENTSRC = ../dinput @@ -13,6 +13,7 @@ C_SRCS = \ dinput_main.c \ effect_linuxinput.c \ joystick.c \ + joystick_hid.c \ joystick_linux.c \ joystick_linuxinput.c \ joystick_osx.c \
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/dinput/joystick_hid.c | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-)
diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c index fadc7d9efe4..ea7c55ab923 100644 --- a/dlls/dinput/joystick_hid.c +++ b/dlls/dinput/joystick_hid.c @@ -51,6 +51,8 @@ struct hid_joystick
HANDLE device; PHIDP_PREPARSED_DATA preparsed; + + DIDEVICEINSTANCEW instance; };
static inline struct hid_joystick *impl_from_IDirectInputDevice8W( IDirectInputDevice8W *iface ) @@ -95,13 +97,33 @@ static HRESULT WINAPI hid_joystick_EnumObjects( IDirectInputDevice8W *iface, LPD
static HRESULT WINAPI hid_joystick_GetProperty( IDirectInputDevice8W *iface, REFGUID guid, DIPROPHEADER *header ) { - FIXME( "iface %p, guid %s, header %p stub!\n", iface, debugstr_guid( guid ), header ); + struct hid_joystick *impl = impl_from_IDirectInputDevice8W( iface ); + + TRACE( "iface %p, guid %s, header %p\n", iface, debugstr_guid( guid ), header );
if (!header) return DIERR_INVALIDPARAM; if (!IS_DIPROP( guid )) return DI_OK;
switch (LOWORD( guid )) { + case (DWORD_PTR)DIPROP_PRODUCTNAME: + { + DIPROPSTRING *value = (DIPROPSTRING *)header; + lstrcpynW( value->wsz, impl->instance.tszProductName, MAX_PATH ); + return DI_OK; + } + case (DWORD_PTR)DIPROP_INSTANCENAME: + { + DIPROPSTRING *value = (DIPROPSTRING *)header; + lstrcpynW( value->wsz, impl->instance.tszInstanceName, MAX_PATH ); + return DI_OK; + } + case (DWORD_PTR)DIPROP_JOYSTICKID: + { + DIPROPDWORD *value = (DIPROPDWORD *)header; + value->dwData = impl->instance.guidInstance.Data3; + return DI_OK; + } default: return IDirectInputDevice2WImpl_GetProperty( iface, guid, header ); } } @@ -165,14 +187,17 @@ static HRESULT WINAPI hid_joystick_GetObjectInfo( IDirectInputDevice8W *iface, D
static HRESULT WINAPI hid_joystick_GetDeviceInfo( IDirectInputDevice8W *iface, DIDEVICEINSTANCEW *instance ) { - FIXME( "iface %p, instance %p stub!\n", iface, instance ); + struct hid_joystick *impl = impl_from_IDirectInputDevice8W( iface ); + + TRACE( "iface %p, instance %p.\n", iface, instance );
if (!instance) return E_POINTER; if (instance->dwSize != sizeof(DIDEVICEINSTANCE_DX3W) && instance->dwSize != sizeof(DIDEVICEINSTANCEW)) return DIERR_INVALIDPARAM;
- return E_NOTIMPL; + memcpy( instance, &impl->instance, instance->dwSize ); + return S_OK; }
static HRESULT WINAPI hid_joystick_CreateEffect( IDirectInputDevice8W *iface, REFGUID rguid, @@ -426,6 +451,8 @@ static HRESULT hid_joystick_create_device( IDirectInputImpl *dinput, REFGUID gui impl->device = device; impl->preparsed = preparsed;
+ impl->instance = instance; + if (!(format = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*format) ))) goto failed; impl->base.data_format.wine_df = format;
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/dinput/joystick_hid.c | 9 +++++++++ 1 file changed, 9 insertions(+)
diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c index ea7c55ab923..63cd5d7ca14 100644 --- a/dlls/dinput/joystick_hid.c +++ b/dlls/dinput/joystick_hid.c @@ -53,6 +53,7 @@ struct hid_joystick PHIDP_PREPARSED_DATA preparsed;
DIDEVICEINSTANCEW instance; + HIDD_ATTRIBUTES attrs; };
static inline struct hid_joystick *impl_from_IDirectInputDevice8W( IDirectInputDevice8W *iface ) @@ -118,6 +119,13 @@ static HRESULT WINAPI hid_joystick_GetProperty( IDirectInputDevice8W *iface, REF lstrcpynW( value->wsz, impl->instance.tszInstanceName, MAX_PATH ); return DI_OK; } + case (DWORD_PTR)DIPROP_VIDPID: + { + DIPROPDWORD *value = (DIPROPDWORD *)header; + if (!impl->attrs.VendorID || !impl->attrs.ProductID) return DIERR_UNSUPPORTED; + value->dwData = MAKELONG( impl->attrs.VendorID, impl->attrs.ProductID ); + return DI_OK; + } case (DWORD_PTR)DIPROP_JOYSTICKID: { DIPROPDWORD *value = (DIPROPDWORD *)header; @@ -452,6 +460,7 @@ static HRESULT hid_joystick_create_device( IDirectInputImpl *dinput, REFGUID gui impl->preparsed = preparsed;
impl->instance = instance; + impl->attrs = attrs;
if (!(format = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*format) ))) goto failed; impl->base.data_format.wine_df = format;
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/dinput/joystick_hid.c | 8 ++++++++ 1 file changed, 8 insertions(+)
diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c index 63cd5d7ca14..f8d7c5d21ac 100644 --- a/dlls/dinput/joystick_hid.c +++ b/dlls/dinput/joystick_hid.c @@ -53,6 +53,7 @@ struct hid_joystick PHIDP_PREPARSED_DATA preparsed;
DIDEVICEINSTANCEW instance; + WCHAR device_path[MAX_PATH]; HIDD_ATTRIBUTES attrs; };
@@ -132,6 +133,12 @@ static HRESULT WINAPI hid_joystick_GetProperty( IDirectInputDevice8W *iface, REF value->dwData = impl->instance.guidInstance.Data3; return DI_OK; } + case (DWORD_PTR)DIPROP_GUIDANDPATH: + { + DIPROPGUIDANDPATH *value = (DIPROPGUIDANDPATH *)header; + lstrcpynW( value->wszPath, impl->device_path, MAX_PATH ); + return DI_OK; + } default: return IDirectInputDevice2WImpl_GetProperty( iface, guid, header ); } } @@ -460,6 +467,7 @@ static HRESULT hid_joystick_create_device( IDirectInputImpl *dinput, REFGUID gui impl->preparsed = preparsed;
impl->instance = instance; + lstrcpynW( impl->device_path, device_path, MAX_PATH ); impl->attrs = attrs;
if (!(format = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*format) ))) goto failed;
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/dinput/joystick_hid.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c index f8d7c5d21ac..c8321829ea1 100644 --- a/dlls/dinput/joystick_hid.c +++ b/dlls/dinput/joystick_hid.c @@ -48,6 +48,7 @@ DEFINE_GUID( hid_joystick_guid, 0x9e573edb, 0x7734, 0x11d2, 0x8d, 0x4a, 0x23, 0x struct hid_joystick { IDirectInputDeviceImpl base; + DIJOYSTATE2 state;
HANDLE device; PHIDP_PREPARSED_DATA preparsed; @@ -180,11 +181,15 @@ static HRESULT WINAPI hid_joystick_Unacquire( IDirectInputDevice8W *iface )
static HRESULT WINAPI hid_joystick_GetDeviceState( IDirectInputDevice8W *iface, DWORD len, void *ptr ) { - FIXME( "iface %p, len %u, ptr %p stub!\n", iface, len, ptr ); + struct hid_joystick *impl = impl_from_IDirectInputDevice8W( iface ); + + TRACE( "iface %p, len %u, ptr %p.\n", iface, len, ptr );
if (!ptr) return DIERR_INVALIDPARAM;
- return E_NOTIMPL; + fill_DataFormat( ptr, len, &impl->state, &impl->base.data_format ); + + return DI_OK; }
static HRESULT WINAPI hid_joystick_GetObjectInfo( IDirectInputDevice8W *iface, DIDEVICEOBJECTINSTANCEW *instance,
On Tue, Jun 29, 2021 at 03:15:20PM +0200, Rémi Bernon wrote:
+static HRESULT WINAPI hid_joystick_Acquire( IDirectInputDevice8W *iface ) +{
- HRESULT hr;
- TRACE( "iface %p.\n", iface );
- if ((hr = IDirectInputDevice2WImpl_Acquire( iface )) != DI_OK) return hr;
- return DI_OK;
+}
+static HRESULT WINAPI hid_joystick_Unacquire( IDirectInputDevice8W *iface ) +{
- HRESULT hr;
- TRACE( "iface %p.\n", iface );
- if ((hr = IDirectInputDevice2WImpl_Unacquire( iface )) != DI_OK) return hr;
- return DI_OK;
+}
Is there a reason for not using the IDirectInputDevice2WImpl_Acquire / IDirectInputDevice2WImpl_Unacquire in the vtable directly or not returning the values without the extra steps?
+static HRESULT hid_joystick_device_open( DWORD index, WCHAR *device_path, HANDLE *device, DWORD version,
PHIDP_PREPARSED_DATA *preparsed, HIDD_ATTRIBUTES *attrs,
HIDP_CAPS *caps, DIDEVICEINSTANCEW *instance )
+{
- RAWINPUTDEVICELIST *list;
- DWORD count, i, j;
- GetRawInputDeviceList( NULL, &count, sizeof(*list) );
- if (!(list = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*list) ))) return DIERR_OUTOFMEMORY;
- GetRawInputDeviceList( list, &count, sizeof(*list) );
- for (i = 0; i < count; ++i) if (list[i].dwType == RIM_TYPEHID) break;
- for (j = 0; j < index && i < count; ++i) if (list[i].dwType == RIM_TYPEHID) ++j;
- if (i == count)
- {
HeapFree( GetProcessHeap(), 0, list );
return DIERR_DEVICENOTREG;
- }
I am not sure you can depend on RIM_TYPEMOUSE and RIM_TYPEKEYBOARD being clumped at the beggining of the list, as it's not guaranteed by the API an may break in Wine in the future.
- count = MAX_PATH;
- GetRawInputDeviceInfoW( list[i].hDevice, RIDI_DEVICENAME, device_path, &count );
- HeapFree( GetProcessHeap(), 0, list );
- TRACE( "Opening %s\n", debugstr_w(device_path) );
- *device = CreateFileW( device_path, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0 );
- *preparsed = NULL;
- if (*device == INVALID_HANDLE_VALUE) return DI_NOTATTACHED;
- if (!HidD_GetPreparsedData( *device, preparsed )) goto failed;
- if (!HidD_GetAttributes( *device, attrs )) goto failed;
- if (HidP_GetCaps( *preparsed, caps ) != HIDP_STATUS_SUCCESS) goto failed;
- if (caps->UsagePage == HID_USAGE_PAGE_GAME) FIXME( "Unimplemented HID game usage page!\n" );
- if (caps->UsagePage == HID_USAGE_PAGE_SIMULATION) FIXME( "Unimplemented HID simulation usage page!\n" );
- if (caps->UsagePage != HID_USAGE_PAGE_GENERIC) goto failed;
- if (caps->Usage != HID_USAGE_GENERIC_GAMEPAD && caps->Usage != HID_USAGE_GENERIC_JOYSTICK) goto failed;
- instance->guidInstance = hid_joystick_guid;
- instance->guidInstance.Data3 = index;
- instance->guidProduct = DInput_PIDVID_Product_GUID;
- instance->guidProduct.Data1 = MAKELONG( attrs->VendorID, attrs->ProductID );
- instance->dwDevType = get_device_type( version, caps->Usage != HID_USAGE_GENERIC_GAMEPAD ) | DIDEVTYPE_HID;
- instance->guidFFDriver = GUID_NULL;
- instance->wUsagePage = caps->UsagePage;
- instance->wUsage = caps->Usage;
- if (!HidD_GetProductString( *device, instance->tszInstanceName, MAX_PATH )) goto failed;
- if (!HidD_GetProductString( *device, instance->tszProductName, MAX_PATH )) goto failed;
- return DI_OK;
+failed:
- CloseHandle( *device );
- *device = INVALID_HANDLE_VALUE;
- HidD_FreePreparsedData( *preparsed );
- *preparsed = NULL;
- return DI_NOTATTACHED;
+}
+static HRESULT hid_joystick_enum_device( DWORD type, DWORD flags, DIDEVICEINSTANCEW *instance,
DWORD version, int index )
+{
- HIDD_ATTRIBUTES attrs = {sizeof(attrs)};
- PHIDP_PREPARSED_DATA preparsed;
- WCHAR device_path[MAX_PATH];
- HIDP_CAPS caps;
- HANDLE device;
- HRESULT hr;
- TRACE( "type %x, flags %#x, instance %p, version %04x, index %d\n", type, flags, instance, version, index );
- hr = hid_joystick_device_open( index, device_path, &device, version,
&preparsed, &attrs, &caps, instance );
Does GetRawInputDeviceList() give us guarantees on device ordering? I think the relative ordering should be preserved (plus/minus the hotplugs, but IMO that's not an issue), but I haven't checked.
- if (hr != DI_OK) return hr;
- HidD_FreePreparsedData( preparsed );
- CloseHandle( device );
- if (instance->dwSize != sizeof(DIDEVICEINSTANCEW))
return S_FALSE;
- if (version < 0x0800 && type != DIDEVTYPE_JOYSTICK)
return S_FALSE;
- if (version >= 0x0800 && type != DI8DEVCLASS_ALL && type != DI8DEVCLASS_GAMECTRL)
return S_FALSE;
- if (device_disabled_registry( "HID", TRUE ))
return DIERR_DEVICENOTREG;
- TRACE( "Found device with usage %04x:%04x, type %x, instance %s %s, product %s %s, ffdriver %s\n",
instance->wUsagePage, instance->wUsage, instance->dwDevType, debugstr_guid( &instance->guidProduct ),
debugstr_w( instance->tszProductName ), debugstr_guid( &instance->guidInstance ),
debugstr_w( instance->tszInstanceName ), debugstr_guid( &instance->guidFFDriver ) );
- return DI_OK;
+}
+static HRESULT hid_joystick_create_device( IDirectInputImpl *dinput, REFGUID guid, IDirectInputDevice8W **out ) +{
- DIDEVICEINSTANCEW instance = {sizeof(instance)};
- DWORD index, size = sizeof(struct hid_joystick);
- HIDD_ATTRIBUTES attrs = {sizeof(attrs)};
- struct hid_joystick *impl = NULL;
- PHIDP_PREPARSED_DATA preparsed;
- DIDATAFORMAT *format = NULL;
- WCHAR device_path[MAX_PATH];
- GUID tmp_guid = *guid;
- HIDP_CAPS caps;
- HANDLE device;
- HRESULT hr;
- TRACE( "dinput %p, guid %s, out %p\n", dinput, debugstr_guid( guid ), out );
- *out = NULL;
- tmp_guid.Data3 = hid_joystick_guid.Data3;
- if (!IsEqualGUID( &hid_joystick_guid, &tmp_guid )) return DIERR_DEVICENOTREG;
- index = guid->Data3;
It's undocumented but you can create device using the product guid, see 0a82d891fc0b ("dinput: Implement device creation using product GUID.")
- hr = hid_joystick_device_open( index, device_path, &device, dinput->dwVersion,
&preparsed, &attrs, &caps, &instance );
I find it unlikely that hotplug is going to be an issue for enumerating, but using only the idx for device creation may be problematic, especially that Enum -> Crate can be more separated in time.
How about using VID + PID + ordinal? This should also help with making the enumeration logic a bit more robust.
Otherwise looks good to me. Thanks for working on this, I think it's much needed :-)
On 6/29/21 5:23 PM, Arkadiusz Hiler wrote:
On Tue, Jun 29, 2021 at 03:15:20PM +0200, Rémi Bernon wrote:
+static HRESULT WINAPI hid_joystick_Acquire( IDirectInputDevice8W *iface ) +{
- HRESULT hr;
- TRACE( "iface %p.\n", iface );
- if ((hr = IDirectInputDevice2WImpl_Acquire( iface )) != DI_OK) return hr;
- return DI_OK;
+}
+static HRESULT WINAPI hid_joystick_Unacquire( IDirectInputDevice8W *iface ) +{
- HRESULT hr;
- TRACE( "iface %p.\n", iface );
- if ((hr = IDirectInputDevice2WImpl_Unacquire( iface )) != DI_OK) return hr;
- return DI_OK;
+}
Is there a reason for not using the IDirectInputDevice2WImpl_Acquire / IDirectInputDevice2WImpl_Unacquire in the vtable directly or not returning the values without the extra steps?
Yeah I added here all the methods that I'm going to implement later, so that FIXMEs get fixed as soon as things get implemented. I could also have used base methods for mostly everything and implement the real deal later.
Acquire and Unacquire will be used to start reading / stop reading the reports in dinput background thread, as doing it in Poll is going to be inefficient (and blocking).
+static HRESULT hid_joystick_device_open( DWORD index, WCHAR *device_path, HANDLE *device, DWORD version,
PHIDP_PREPARSED_DATA *preparsed, HIDD_ATTRIBUTES *attrs,
HIDP_CAPS *caps, DIDEVICEINSTANCEW *instance )
+{
- RAWINPUTDEVICELIST *list;
- DWORD count, i, j;
- GetRawInputDeviceList( NULL, &count, sizeof(*list) );
- if (!(list = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*list) ))) return DIERR_OUTOFMEMORY;
- GetRawInputDeviceList( list, &count, sizeof(*list) );
- for (i = 0; i < count; ++i) if (list[i].dwType == RIM_TYPEHID) break;
- for (j = 0; j < index && i < count; ++i) if (list[i].dwType == RIM_TYPEHID) ++j;
- if (i == count)
- {
HeapFree( GetProcessHeap(), 0, list );
return DIERR_DEVICENOTREG;
- }
I am not sure you can depend on RIM_TYPEMOUSE and RIM_TYPEKEYBOARD being clumped at the beggining of the list, as it's not guaranteed by the API an may break in Wine in the future.
I don't think I am? It's supposed to look for the first RIM_TYPEHID and then starts counting HID devices from there, ignoring non-HID devices.
- count = MAX_PATH;
- GetRawInputDeviceInfoW( list[i].hDevice, RIDI_DEVICENAME, device_path, &count );
- HeapFree( GetProcessHeap(), 0, list );
- TRACE( "Opening %s\n", debugstr_w(device_path) );
- *device = CreateFileW( device_path, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0 );
- *preparsed = NULL;
- if (*device == INVALID_HANDLE_VALUE) return DI_NOTATTACHED;
- if (!HidD_GetPreparsedData( *device, preparsed )) goto failed;
- if (!HidD_GetAttributes( *device, attrs )) goto failed;
- if (HidP_GetCaps( *preparsed, caps ) != HIDP_STATUS_SUCCESS) goto failed;
- if (caps->UsagePage == HID_USAGE_PAGE_GAME) FIXME( "Unimplemented HID game usage page!\n" );
- if (caps->UsagePage == HID_USAGE_PAGE_SIMULATION) FIXME( "Unimplemented HID simulation usage page!\n" );
- if (caps->UsagePage != HID_USAGE_PAGE_GENERIC) goto failed;
- if (caps->Usage != HID_USAGE_GENERIC_GAMEPAD && caps->Usage != HID_USAGE_GENERIC_JOYSTICK) goto failed;
- instance->guidInstance = hid_joystick_guid;
- instance->guidInstance.Data3 = index;
- instance->guidProduct = DInput_PIDVID_Product_GUID;
- instance->guidProduct.Data1 = MAKELONG( attrs->VendorID, attrs->ProductID );
- instance->dwDevType = get_device_type( version, caps->Usage != HID_USAGE_GENERIC_GAMEPAD ) | DIDEVTYPE_HID;
- instance->guidFFDriver = GUID_NULL;
- instance->wUsagePage = caps->UsagePage;
- instance->wUsage = caps->Usage;
- if (!HidD_GetProductString( *device, instance->tszInstanceName, MAX_PATH )) goto failed;
- if (!HidD_GetProductString( *device, instance->tszProductName, MAX_PATH )) goto failed;
- return DI_OK;
+failed:
- CloseHandle( *device );
- *device = INVALID_HANDLE_VALUE;
- HidD_FreePreparsedData( *preparsed );
- *preparsed = NULL;
- return DI_NOTATTACHED;
+}
+static HRESULT hid_joystick_enum_device( DWORD type, DWORD flags, DIDEVICEINSTANCEW *instance,
DWORD version, int index )
+{
- HIDD_ATTRIBUTES attrs = {sizeof(attrs)};
- PHIDP_PREPARSED_DATA preparsed;
- WCHAR device_path[MAX_PATH];
- HIDP_CAPS caps;
- HANDLE device;
- HRESULT hr;
- TRACE( "type %x, flags %#x, instance %p, version %04x, index %d\n", type, flags, instance, version, index );
- hr = hid_joystick_device_open( index, device_path, &device, version,
&preparsed, &attrs, &caps, instance );
Does GetRawInputDeviceList() give us guarantees on device ordering? I think the relative ordering should be preserved (plus/minus the hotplugs, but IMO that's not an issue), but I haven't checked.
It's using setupapi, and keeps its order, I think? I could use setupapi directly, but rawinput API is slightly simpler to use IMHO.
- if (hr != DI_OK) return hr;
- HidD_FreePreparsedData( preparsed );
- CloseHandle( device );
- if (instance->dwSize != sizeof(DIDEVICEINSTANCEW))
return S_FALSE;
- if (version < 0x0800 && type != DIDEVTYPE_JOYSTICK)
return S_FALSE;
- if (version >= 0x0800 && type != DI8DEVCLASS_ALL && type != DI8DEVCLASS_GAMECTRL)
return S_FALSE;
- if (device_disabled_registry( "HID", TRUE ))
return DIERR_DEVICENOTREG;
- TRACE( "Found device with usage %04x:%04x, type %x, instance %s %s, product %s %s, ffdriver %s\n",
instance->wUsagePage, instance->wUsage, instance->dwDevType, debugstr_guid( &instance->guidProduct ),
debugstr_w( instance->tszProductName ), debugstr_guid( &instance->guidInstance ),
debugstr_w( instance->tszInstanceName ), debugstr_guid( &instance->guidFFDriver ) );
- return DI_OK;
+}
+static HRESULT hid_joystick_create_device( IDirectInputImpl *dinput, REFGUID guid, IDirectInputDevice8W **out ) +{
- DIDEVICEINSTANCEW instance = {sizeof(instance)};
- DWORD index, size = sizeof(struct hid_joystick);
- HIDD_ATTRIBUTES attrs = {sizeof(attrs)};
- struct hid_joystick *impl = NULL;
- PHIDP_PREPARSED_DATA preparsed;
- DIDATAFORMAT *format = NULL;
- WCHAR device_path[MAX_PATH];
- GUID tmp_guid = *guid;
- HIDP_CAPS caps;
- HANDLE device;
- HRESULT hr;
- TRACE( "dinput %p, guid %s, out %p\n", dinput, debugstr_guid( guid ), out );
- *out = NULL;
- tmp_guid.Data3 = hid_joystick_guid.Data3;
- if (!IsEqualGUID( &hid_joystick_guid, &tmp_guid )) return DIERR_DEVICENOTREG;
- index = guid->Data3;
It's undocumented but you can create device using the product guid, see 0a82d891fc0b ("dinput: Implement device creation using product GUID.")
Oh, okay!
- hr = hid_joystick_device_open( index, device_path, &device, dinput->dwVersion,
&preparsed, &attrs, &caps, &instance );
I find it unlikely that hotplug is going to be an issue for enumerating, but using only the idx for device creation may be problematic, especially that Enum -> Crate can be more separated in time.
How about using VID + PID + ordinal? This should also help with making the enumeration logic a bit more robust.
Yeah I tried to use the same method as the other drivers, I'm not completely sure to understand what these instance / product GUIDs really are.
It was also handy to be able to re-use hid_joystick_device_open here, but that can probably be factored somehow.
Thanks for the comments!
On Tue, Jun 29, 2021 at 05:40:12PM +0200, Rémi Bernon wrote:
+static HRESULT hid_joystick_device_open( DWORD index, WCHAR *device_path, HANDLE *device, DWORD version,
PHIDP_PREPARSED_DATA *preparsed, HIDD_ATTRIBUTES *attrs,
HIDP_CAPS *caps, DIDEVICEINSTANCEW *instance )
+{
- RAWINPUTDEVICELIST *list;
- DWORD count, i, j;
- GetRawInputDeviceList( NULL, &count, sizeof(*list) );
- if (!(list = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*list) ))) return DIERR_OUTOFMEMORY;
- GetRawInputDeviceList( list, &count, sizeof(*list) );
- for (i = 0; i < count; ++i) if (list[i].dwType == RIM_TYPEHID) break;
- for (j = 0; j < index && i < count; ++i) if (list[i].dwType == RIM_TYPEHID) ++j;
- if (i == count)
- {
HeapFree( GetProcessHeap(), 0, list );
return DIERR_DEVICENOTREG;
- }
I am not sure you can depend on RIM_TYPEMOUSE and RIM_TYPEKEYBOARD being clumped at the beggining of the list, as it's not guaranteed by the API an may break in Wine in the future.
I don't think I am? It's supposed to look for the first RIM_TYPEHID and then starts counting HID devices from there, ignoring non-HID devices.
Oh, indeed you are not. It's just a bit confusing to read through the looping logic here.
- count = MAX_PATH;
- GetRawInputDeviceInfoW( list[i].hDevice, RIDI_DEVICENAME, device_path, &count );
You should check return value here, otherwise you may end up with uninitalized device_path.
- HeapFree( GetProcessHeap(), 0, list );
- TRACE( "Opening %s\n", debugstr_w(device_path) );
- *device = CreateFileW( device_path, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0 );
- *preparsed = NULL;
- if (*device == INVALID_HANDLE_VALUE) return DI_NOTATTACHED;
- if (!HidD_GetPreparsedData( *device, preparsed )) goto failed;
- if (!HidD_GetAttributes( *device, attrs )) goto failed;
- if (HidP_GetCaps( *preparsed, caps ) != HIDP_STATUS_SUCCESS) goto failed;
- if (caps->UsagePage == HID_USAGE_PAGE_GAME) FIXME( "Unimplemented HID game usage page!\n" );
- if (caps->UsagePage == HID_USAGE_PAGE_SIMULATION) FIXME( "Unimplemented HID simulation usage page!\n" );
- if (caps->UsagePage != HID_USAGE_PAGE_GENERIC) goto failed;
- if (caps->Usage != HID_USAGE_GENERIC_GAMEPAD && caps->Usage != HID_USAGE_GENERIC_JOYSTICK) goto failed;
- instance->guidInstance = hid_joystick_guid;
- instance->guidInstance.Data3 = index;
- instance->guidProduct = DInput_PIDVID_Product_GUID;
- instance->guidProduct.Data1 = MAKELONG( attrs->VendorID, attrs->ProductID );
- instance->dwDevType = get_device_type( version, caps->Usage != HID_USAGE_GENERIC_GAMEPAD ) | DIDEVTYPE_HID;
- instance->guidFFDriver = GUID_NULL;
- instance->wUsagePage = caps->UsagePage;
- instance->wUsage = caps->Usage;
- if (!HidD_GetProductString( *device, instance->tszInstanceName, MAX_PATH )) goto failed;
- if (!HidD_GetProductString( *device, instance->tszProductName, MAX_PATH )) goto failed;
- return DI_OK;
+failed:
- CloseHandle( *device );
- *device = INVALID_HANDLE_VALUE;
- HidD_FreePreparsedData( *preparsed );
- *preparsed = NULL;
- return DI_NOTATTACHED;
+}
+static HRESULT hid_joystick_enum_device( DWORD type, DWORD flags, DIDEVICEINSTANCEW *instance,
DWORD version, int index )
+{
- HIDD_ATTRIBUTES attrs = {sizeof(attrs)};
- PHIDP_PREPARSED_DATA preparsed;
- WCHAR device_path[MAX_PATH];
- HIDP_CAPS caps;
- HANDLE device;
- HRESULT hr;
- TRACE( "type %x, flags %#x, instance %p, version %04x, index %d\n", type, flags, instance, version, index );
- hr = hid_joystick_device_open( index, device_path, &device, version,
&preparsed, &attrs, &caps, instance );
Does GetRawInputDeviceList() give us guarantees on device ordering? I think the relative ordering should be preserved (plus/minus the hotplugs, but IMO that's not an issue), but I haven't checked.
It's using setupapi, and keeps its order, I think? I could use setupapi directly, but rawinput API is slightly simpler to use IMHO.
Fair enough. I think the ordering is also stable on Windows so that behavior should not change. Anyway it will be easy to notice if it regresses.
- hr = hid_joystick_device_open( index, device_path, &device, dinput->dwVersion,
&preparsed, &attrs, &caps, &instance );
I find it unlikely that hotplug is going to be an issue for enumerating, but using only the idx for device creation may be problematic, especially that Enum -> Crate can be more separated in time.
How about using VID + PID + ordinal? This should also help with making the enumeration logic a bit more robust.
Yeah I tried to use the same method as the other drivers, I'm not completely sure to understand what these instance / product GUIDs really are.
From my observations:
guidProduct - represents the product, i.e. all the Model 1914 Xbox controllers I have have the same guidProduct, so it makes sense to include vidpidrev in it.
guidInstance - uniquely identifies the given device, not sure how stable it across hotplus/reboots is though.
Just throwing some more ideas here, but since hDevice is an opaque value that's stable across processes and uniquely identifies the device (until the reboot), maybe we should try to fit it into the instance GUID? This will save you the need to do any counting and you can pass it directly to GetRawInputDeviceInfo().
It was also handy to be able to re-use hid_joystick_device_open here, but that can probably be factored somehow.
Thanks for the comments!
With enough refactoring anything is possible ;-)
On 6/29/21 8:15 AM, Rémi Bernon wrote:
This adds a new joystick backend, implemented on top of HID and without any host dependencies. This will be progressively implementated, and it's not going to be usable until at least a few more patches.
Because of that, and because it may also introduce regressions compared to the existing backends, it is disabled by default and is optionally enabled using the following global registry key:
[HKCU\Software\Wine\DirectInput\Joysticks] "HID"="enabled"
Or using the corresponding AppDefaults registry key:
[HKCU\Software\Wine\AppDefaults\<app.exe>\DirectInput\Joysticks] "HID"="enabled"
This setting will be removed later, when it becomes usable enough, to use the individual device disable mechanism available in joy.cpl.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com
v2: Make the backend disabled by default, optionally enabled in the registry. This is only temporary until we have at least input support.
dlls/dinput/Makefile.in | 3 +- dlls/dinput/dinput_main.c | 3 +- dlls/dinput/dinput_private.h | 1 + dlls/dinput/joystick.c | 17 +- dlls/dinput/joystick_hid.c | 450 ++++++++++++++++++++++++++++++ dlls/dinput/joystick_linux.c | 2 +- dlls/dinput/joystick_linuxinput.c | 2 +- dlls/dinput/joystick_private.h | 2 +- dlls/dinput8/Makefile.in | 3 +- 9 files changed, 472 insertions(+), 11 deletions(-) create mode 100644 dlls/dinput/joystick_hid.c
diff --git a/dlls/dinput/Makefile.in b/dlls/dinput/Makefile.in index a22c8a72180..f2347927ed6 100644 --- a/dlls/dinput/Makefile.in +++ b/dlls/dinput/Makefile.in @@ -1,6 +1,6 @@ MODULE = dinput.dll IMPORTLIB = dinput -IMPORTS = dinput dxguid uuid comctl32 ole32 user32 advapi32 +IMPORTS = dinput dxguid uuid comctl32 ole32 user32 advapi32 hid EXTRADEFS = -DDIRECTINPUT_VERSION=0x0700 EXTRALIBS = $(IOKIT_LIBS) $(FORCEFEEDBACK_LIBS)
@@ -12,6 +12,7 @@ C_SRCS = \ dinput_main.c \ effect_linuxinput.c \ joystick.c \
- joystick_hid.c \ joystick_linux.c \ joystick_linuxinput.c \ joystick_osx.c \
diff --git a/dlls/dinput/dinput_main.c b/dlls/dinput/dinput_main.c index c7b932aca44..88ee1855675 100644 --- a/dlls/dinput/dinput_main.c +++ b/dlls/dinput/dinput_main.c @@ -80,7 +80,8 @@ static const struct dinput_device *dinput_devices[] = &keyboard_device, &joystick_linuxinput_device, &joystick_linux_device,
- &joystick_osx_device
&joystick_osx_device,
&joystick_hid_device, };
HINSTANCE DINPUT_instance;
diff --git a/dlls/dinput/dinput_private.h b/dlls/dinput/dinput_private.h index 7e0f56c68df..c11b64585d9 100644 --- a/dlls/dinput/dinput_private.h +++ b/dlls/dinput/dinput_private.h @@ -67,6 +67,7 @@ struct DevicePlayer {
extern const struct dinput_device mouse_device DECLSPEC_HIDDEN; extern const struct dinput_device keyboard_device DECLSPEC_HIDDEN; +extern const struct dinput_device joystick_hid_device DECLSPEC_HIDDEN; extern const struct dinput_device joystick_linux_device DECLSPEC_HIDDEN; extern const struct dinput_device joystick_linuxinput_device DECLSPEC_HIDDEN; extern const struct dinput_device joystick_osx_device DECLSPEC_HIDDEN; diff --git a/dlls/dinput/joystick.c b/dlls/dinput/joystick.c index 8ea7850621c..60153d0d0f3 100644 --- a/dlls/dinput/joystick.c +++ b/dlls/dinput/joystick.c @@ -271,13 +271,13 @@ void dump_DIEFFECT(LPCDIEFFECT eff, REFGUID guid, DWORD dwFlags) } }
-BOOL device_disabled_registry(const char* name) +BOOL device_disabled_registry(const char* name, BOOL disable) { static const char disabled_str[] = "disabled";
- static const char enabled_str[] = "enabled"; static const char joystick_key[] = "Joysticks"; char buffer[MAX_PATH]; HKEY hkey, appkey, temp;
BOOL do_disable = FALSE;
get_app_key(&hkey, &appkey);
@@ -297,16 +297,23 @@ BOOL device_disabled_registry(const char* name)
/* Look for the "controllername"="disabled" key */ if (!get_config_key(hkey, appkey, name, buffer, sizeof(buffer)))
if (!strcmp(disabled_str, buffer))
- {
if (!disable && !strcmp(disabled_str, buffer)) { TRACE("Disabling joystick '%s' based on registry key.\n", name);
do_disable = TRUE;
disable = TRUE;
}
else if (disable && !strcmp(enabled_str, buffer))
{
TRACE("Enabling joystick '%s' based on registry key.\n", name);
disable = FALSE; }
}
if (appkey) RegCloseKey(appkey); if (hkey) RegCloseKey(hkey);
- return do_disable;
return disable; }
BOOL is_xinput_device(const DIDEVCAPS *devcaps, WORD vid, WORD pid)
diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c new file mode 100644 index 00000000000..fadc7d9efe4 --- /dev/null +++ b/dlls/dinput/joystick_hid.c @@ -0,0 +1,450 @@ +/* DirectInput HID Joystick device
- Copyright 2021 Rémi Bernon for CodeWeavers
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 2.1 of the License, or (at your option) any later version.
- This library is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
- You should have received a copy of the GNU Lesser General Public
- License along with this library; if not, write to the Free Software
- Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- */
+#include <assert.h> +#include <stdarg.h> +#include <string.h>
+#include "windef.h" +#include "winbase.h" +#include "winternl.h" +#include "winuser.h" +#include "winerror.h" +#include "winreg.h"
+#include "ddk/hidsdi.h" +#include "devguid.h" +#include "dinput.h" +#include "setupapi.h"
+#include "wine/debug.h"
+#include "dinput_private.h" +#include "device_private.h" +#include "joystick_private.h"
+#include "initguid.h"
+WINE_DEFAULT_DEBUG_CHANNEL(dinput);
+DEFINE_GUID( hid_joystick_guid, 0x9e573edb, 0x7734, 0x11d2, 0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf7 );
+struct hid_joystick +{
- IDirectInputDeviceImpl base;
- HANDLE device;
- PHIDP_PREPARSED_DATA preparsed;
+};
+static inline struct hid_joystick *impl_from_IDirectInputDevice8W( IDirectInputDevice8W *iface ) +{
- return CONTAINING_RECORD( CONTAINING_RECORD( iface, IDirectInputDeviceImpl, IDirectInputDevice8W_iface ),
struct hid_joystick, base );
+}
+static ULONG WINAPI hid_joystick_Release( IDirectInputDevice8W *iface ) +{
- struct hid_joystick *impl = impl_from_IDirectInputDevice8W( iface );
- struct hid_joystick tmp = *impl;
- ULONG res;
- if (!(res = IDirectInputDevice2WImpl_Release( iface )))
- {
HidD_FreePreparsedData( tmp.preparsed );
CloseHandle( tmp.device );
- }
- return res;
+}
+static HRESULT WINAPI hid_joystick_GetCapabilities( IDirectInputDevice8W *iface, DIDEVCAPS *caps ) +{
- FIXME( "iface %p, caps %p stub!\n", iface, caps );
- if (!caps) return E_POINTER;
- return E_NOTIMPL;
+}
+static HRESULT WINAPI hid_joystick_EnumObjects( IDirectInputDevice8W *iface, LPDIENUMDEVICEOBJECTSCALLBACKW callback,
void *ref, DWORD flags )
+{
- FIXME( "iface %p, callback %p, ref %p, flags %#x stub!\n", iface, callback, ref, flags );
- if (!callback) return DIERR_INVALIDPARAM;
- return E_NOTIMPL;
+}
+static HRESULT WINAPI hid_joystick_GetProperty( IDirectInputDevice8W *iface, REFGUID guid, DIPROPHEADER *header ) +{
- FIXME( "iface %p, guid %s, header %p stub!\n", iface, debugstr_guid( guid ), header );
- if (!header) return DIERR_INVALIDPARAM;
- if (!IS_DIPROP( guid )) return DI_OK;
- switch (LOWORD( guid ))
- {
- default: return IDirectInputDevice2WImpl_GetProperty( iface, guid, header );
- }
+}
+static HRESULT WINAPI hid_joystick_SetProperty( IDirectInputDevice8W *iface, REFGUID guid, const DIPROPHEADER *header ) +{
- FIXME( "iface %p, guid %s, header %p stub!\n", iface, debugstr_guid( guid ), header );
- if (!header) return DIERR_INVALIDPARAM;
- if (!IS_DIPROP( guid )) return DI_OK;
- switch (LOWORD( guid ))
- {
- default: return IDirectInputDevice2WImpl_SetProperty( iface, guid, header );
- }
+}
+static HRESULT WINAPI hid_joystick_Acquire( IDirectInputDevice8W *iface ) +{
- HRESULT hr;
- TRACE( "iface %p.\n", iface );
- if ((hr = IDirectInputDevice2WImpl_Acquire( iface )) != DI_OK) return hr;
- return DI_OK;
+}
+static HRESULT WINAPI hid_joystick_Unacquire( IDirectInputDevice8W *iface ) +{
- HRESULT hr;
- TRACE( "iface %p.\n", iface );
- if ((hr = IDirectInputDevice2WImpl_Unacquire( iface )) != DI_OK) return hr;
- return DI_OK;
+}
+static HRESULT WINAPI hid_joystick_GetDeviceState( IDirectInputDevice8W *iface, DWORD len, void *ptr ) +{
- FIXME( "iface %p, len %u, ptr %p stub!\n", iface, len, ptr );
- if (!ptr) return DIERR_INVALIDPARAM;
- return E_NOTIMPL;
+}
+static HRESULT WINAPI hid_joystick_GetObjectInfo( IDirectInputDevice8W *iface, DIDEVICEOBJECTINSTANCEW *instance,
DWORD obj, DWORD how )
+{
- FIXME( "iface %p, instance %p, obj %#x, how %#x stub!\n", iface, instance, obj, how );
- if (!instance) return E_POINTER;
- if (instance->dwSize != sizeof(DIDEVICEOBJECTINSTANCE_DX3W) &&
instance->dwSize != sizeof(DIDEVICEOBJECTINSTANCEW))
return DIERR_INVALIDPARAM;
- return E_NOTIMPL;
+}
+static HRESULT WINAPI hid_joystick_GetDeviceInfo( IDirectInputDevice8W *iface, DIDEVICEINSTANCEW *instance ) +{
- FIXME( "iface %p, instance %p stub!\n", iface, instance );
- if (!instance) return E_POINTER;
- if (instance->dwSize != sizeof(DIDEVICEINSTANCE_DX3W) &&
instance->dwSize != sizeof(DIDEVICEINSTANCEW))
return DIERR_INVALIDPARAM;
- return E_NOTIMPL;
+}
+static HRESULT WINAPI hid_joystick_CreateEffect( IDirectInputDevice8W *iface, REFGUID rguid,
const DIEFFECT *effect, IDirectInputEffect **out,
IUnknown *outer )
+{
- FIXME( "iface %p, rguid %s, effect %p, out %p, outer %p stub!\n", iface, debugstr_guid( rguid ),
effect, out, outer );
- if (!out) return E_POINTER;
- if (!rguid || !effect) return DI_NOEFFECT;
- return E_NOTIMPL;
+}
+static HRESULT WINAPI hid_joystick_EnumEffects( IDirectInputDevice8W *iface, LPDIENUMEFFECTSCALLBACKW callback,
void *ref, DWORD type )
+{
- FIXME( "iface %p, callback %p, ref %p, type %#x stub!\n", iface, callback, ref, type );
- if (!callback) return DIERR_INVALIDPARAM;
- return E_NOTIMPL;
+}
+static HRESULT WINAPI hid_joystick_GetEffectInfo( IDirectInputDevice8W *iface, DIEFFECTINFOW *info, REFGUID guid ) +{
- FIXME( "iface %p, info %p, guid %s stub!\n", iface, info, debugstr_guid( guid ) );
- if (!info) return E_POINTER;
- return E_NOTIMPL;
+}
+static HRESULT WINAPI hid_joystick_GetForceFeedbackState( IDirectInputDevice8W *iface, DWORD *out ) +{
- FIXME( "iface %p, out %p stub!\n", iface, out );
- if (!out) return E_POINTER;
- return E_NOTIMPL;
+}
+static HRESULT WINAPI hid_joystick_SendForceFeedbackCommand( IDirectInputDevice8W *iface, DWORD flags ) +{
- FIXME( "iface %p, flags %x stub!\n", iface, flags );
- return E_NOTIMPL;
+}
+static HRESULT WINAPI hid_joystick_EnumCreatedEffectObjects( IDirectInputDevice8W *iface,
LPDIENUMCREATEDEFFECTOBJECTSCALLBACK callback,
void *ref, DWORD flags )
+{
- FIXME( "iface %p, callback %p, ref %p, flags %#x stub!\n", iface, callback, ref, flags );
- if (!callback) return DIERR_INVALIDPARAM;
- return E_NOTIMPL;
+}
+static HRESULT WINAPI hid_joystick_BuildActionMap( IDirectInputDevice8W *iface, DIACTIONFORMATW *format,
const WCHAR *username, DWORD flags )
+{
- FIXME( "iface %p, format %p, username %s, flags %#x stub!\n", iface, format, debugstr_w(username), flags );
- if (!format) return DIERR_INVALIDPARAM;
- return E_NOTIMPL;
+}
+static HRESULT WINAPI hid_joystick_SetActionMap( IDirectInputDevice8W *iface, DIACTIONFORMATW *format,
const WCHAR *username, DWORD flags )
+{
- struct hid_joystick *impl = impl_from_IDirectInputDevice8W( iface );
- TRACE( "iface %p, format %p, username %s, flags %#x.\n", iface, format, debugstr_w(username), flags );
- if (!format) return DIERR_INVALIDPARAM;
- return _set_action_map( iface, format, username, flags, impl->base.data_format.wine_df );
+}
+static const IDirectInputDevice8WVtbl hid_joystick_vtbl = +{
- /*** IUnknown methods ***/
- IDirectInputDevice2WImpl_QueryInterface,
- IDirectInputDevice2WImpl_AddRef,
- hid_joystick_Release,
- /*** IDirectInputDevice methods ***/
- hid_joystick_GetCapabilities,
- hid_joystick_EnumObjects,
- hid_joystick_GetProperty,
- hid_joystick_SetProperty,
- hid_joystick_Acquire,
- hid_joystick_Unacquire,
- hid_joystick_GetDeviceState,
- IDirectInputDevice2WImpl_GetDeviceData,
- IDirectInputDevice2WImpl_SetDataFormat,
- IDirectInputDevice2WImpl_SetEventNotification,
- IDirectInputDevice2WImpl_SetCooperativeLevel,
- hid_joystick_GetObjectInfo,
- hid_joystick_GetDeviceInfo,
- IDirectInputDevice2WImpl_RunControlPanel,
- IDirectInputDevice2WImpl_Initialize,
- /*** IDirectInputDevice2 methods ***/
- hid_joystick_CreateEffect,
- hid_joystick_EnumEffects,
- hid_joystick_GetEffectInfo,
- hid_joystick_GetForceFeedbackState,
- hid_joystick_SendForceFeedbackCommand,
- hid_joystick_EnumCreatedEffectObjects,
- IDirectInputDevice2WImpl_Escape,
- IDirectInputDevice2WImpl_Poll,
- IDirectInputDevice2WImpl_SendDeviceData,
- /*** IDirectInputDevice7 methods ***/
- IDirectInputDevice7WImpl_EnumEffectsInFile,
- IDirectInputDevice7WImpl_WriteEffectToFile,
- /*** IDirectInputDevice8 methods ***/
- hid_joystick_BuildActionMap,
- hid_joystick_SetActionMap,
- IDirectInputDevice8WImpl_GetImageInfo,
+};
+static HRESULT hid_joystick_device_open( DWORD index, WCHAR *device_path, HANDLE *device, DWORD version,
PHIDP_PREPARSED_DATA *preparsed, HIDD_ATTRIBUTES *attrs,
HIDP_CAPS *caps, DIDEVICEINSTANCEW *instance )
+{
- RAWINPUTDEVICELIST *list;
- DWORD count, i, j;
- GetRawInputDeviceList( NULL, &count, sizeof(*list) );
- if (!(list = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*list) ))) return DIERR_OUTOFMEMORY;
- GetRawInputDeviceList( list, &count, sizeof(*list) );
Can't the count change between these two calls?
- for (i = 0; i < count; ++i) if (list[i].dwType == RIM_TYPEHID) break;
- for (j = 0; j < index && i < count; ++i) if (list[i].dwType == RIM_TYPEHID) ++j;
- if (i == count)
- {
HeapFree( GetProcessHeap(), 0, list );
return DIERR_DEVICENOTREG;
- }
This is very confusing. The first loop seems redundant; the variable naming is unclear; and the nesting of three levels on the same line is hard to read. Could I propose something like the following instead?
DWORD hid_count = 0, i;
for (i = 0; i < count; ++i) { if (list[i].dwType == RIM_TYPEHID && hid_count++ == req_index) break; } if (i == count) { ... }
(Personally I always like to take this for/if/break pattern and make it into a helper function, but I won't complain if not.)
- count = MAX_PATH;
- GetRawInputDeviceInfoW( list[i].hDevice, RIDI_DEVICENAME, device_path, &count );
- HeapFree( GetProcessHeap(), 0, list );
- TRACE( "Opening %s\n", debugstr_w(device_path) );
- *device = CreateFileW( device_path, GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0 );
- *preparsed = NULL;
- if (*device == INVALID_HANDLE_VALUE) return DI_NOTATTACHED;
- if (!HidD_GetPreparsedData( *device, preparsed )) goto failed;
- if (!HidD_GetAttributes( *device, attrs )) goto failed;
- if (HidP_GetCaps( *preparsed, caps ) != HIDP_STATUS_SUCCESS) goto failed;
- if (caps->UsagePage == HID_USAGE_PAGE_GAME) FIXME( "Unimplemented HID game usage page!\n" );
- if (caps->UsagePage == HID_USAGE_PAGE_SIMULATION) FIXME( "Unimplemented HID simulation usage page!\n" );
- if (caps->UsagePage != HID_USAGE_PAGE_GENERIC) goto failed;
- if (caps->Usage != HID_USAGE_GENERIC_GAMEPAD && caps->Usage != HID_USAGE_GENERIC_JOYSTICK) goto failed;
- instance->guidInstance = hid_joystick_guid;
- instance->guidInstance.Data3 = index;
- instance->guidProduct = DInput_PIDVID_Product_GUID;
- instance->guidProduct.Data1 = MAKELONG( attrs->VendorID, attrs->ProductID );
- instance->dwDevType = get_device_type( version, caps->Usage != HID_USAGE_GENERIC_GAMEPAD ) | DIDEVTYPE_HID;
- instance->guidFFDriver = GUID_NULL;
- instance->wUsagePage = caps->UsagePage;
- instance->wUsage = caps->Usage;
- if (!HidD_GetProductString( *device, instance->tszInstanceName, MAX_PATH )) goto failed;
- if (!HidD_GetProductString( *device, instance->tszProductName, MAX_PATH )) goto failed;
- return DI_OK;
+failed:
- CloseHandle( *device );
- *device = INVALID_HANDLE_VALUE;
- HidD_FreePreparsedData( *preparsed );
- *preparsed = NULL;
- return DI_NOTATTACHED;
+}
+static HRESULT hid_joystick_enum_device( DWORD type, DWORD flags, DIDEVICEINSTANCEW *instance,
DWORD version, int index )
+{
- HIDD_ATTRIBUTES attrs = {sizeof(attrs)};
- PHIDP_PREPARSED_DATA preparsed;
- WCHAR device_path[MAX_PATH];
- HIDP_CAPS caps;
- HANDLE device;
- HRESULT hr;
- TRACE( "type %x, flags %#x, instance %p, version %04x, index %d\n", type, flags, instance, version, index );
- hr = hid_joystick_device_open( index, device_path, &device, version,
&preparsed, &attrs, &caps, instance );
- if (hr != DI_OK) return hr;
- HidD_FreePreparsedData( preparsed );
- CloseHandle( device );
- if (instance->dwSize != sizeof(DIDEVICEINSTANCEW))
return S_FALSE;
- if (version < 0x0800 && type != DIDEVTYPE_JOYSTICK)
return S_FALSE;
- if (version >= 0x0800 && type != DI8DEVCLASS_ALL && type != DI8DEVCLASS_GAMECTRL)
return S_FALSE;
- if (device_disabled_registry( "HID", TRUE ))
return DIERR_DEVICENOTREG;
- TRACE( "Found device with usage %04x:%04x, type %x, instance %s %s, product %s %s, ffdriver %s\n",
instance->wUsagePage, instance->wUsage, instance->dwDevType, debugstr_guid( &instance->guidProduct ),
debugstr_w( instance->tszProductName ), debugstr_guid( &instance->guidInstance ),
debugstr_w( instance->tszInstanceName ), debugstr_guid( &instance->guidFFDriver ) );
- return DI_OK;
+}
+static HRESULT hid_joystick_create_device( IDirectInputImpl *dinput, REFGUID guid, IDirectInputDevice8W **out ) +{
- DIDEVICEINSTANCEW instance = {sizeof(instance)};
- DWORD index, size = sizeof(struct hid_joystick);
- HIDD_ATTRIBUTES attrs = {sizeof(attrs)};
- struct hid_joystick *impl = NULL;
- PHIDP_PREPARSED_DATA preparsed;
- DIDATAFORMAT *format = NULL;
- WCHAR device_path[MAX_PATH];
- GUID tmp_guid = *guid;
- HIDP_CAPS caps;
- HANDLE device;
- HRESULT hr;
- TRACE( "dinput %p, guid %s, out %p\n", dinput, debugstr_guid( guid ), out );
- *out = NULL;
- tmp_guid.Data3 = hid_joystick_guid.Data3;
- if (!IsEqualGUID( &hid_joystick_guid, &tmp_guid )) return DIERR_DEVICENOTREG;
- index = guid->Data3;
- hr = hid_joystick_device_open( index, device_path, &device, dinput->dwVersion,
&preparsed, &attrs, &caps, &instance );
- if (hr != DI_OK) return hr;
- hr = direct_input_device_alloc( size, &hid_joystick_vtbl, guid, dinput, (void **)&impl );
- if (FAILED(hr)) goto failed;
- impl->base.crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": hid_joystick.base.crit");
- impl->base.dwCoopLevel = DISCL_NONEXCLUSIVE | DISCL_BACKGROUND;
- impl->device = device;
- impl->preparsed = preparsed;
- if (!(format = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*format) ))) goto failed;
- impl->base.data_format.wine_df = format;
- TRACE( "Created %p\n", impl );
- *out = &impl->base.IDirectInputDevice8W_iface;
- return DI_OK;
+failed:
- HeapFree( GetProcessHeap(), 0, format );
- HeapFree( GetProcessHeap(), 0, impl );
- HidD_FreePreparsedData( preparsed );
- CloseHandle( device );
- return hr;
+}
+const struct dinput_device joystick_hid_device = +{
- "Wine HID joystick driver",
- hid_joystick_enum_device,
- hid_joystick_create_device,
+}; diff --git a/dlls/dinput/joystick_linux.c b/dlls/dinput/joystick_linux.c index 3215978c995..312ef3d9c42 100644 --- a/dlls/dinput/joystick_linux.c +++ b/dlls/dinput/joystick_linux.c @@ -175,7 +175,7 @@ static INT find_joystick_devices(void) /* Append driver name */ strcat(joydev.name, JOYDEVDRIVER);
if (device_disabled_registry(joydev.name)) {
if (device_disabled_registry(joydev.name, FALSE)) { close(fd); continue; }
diff --git a/dlls/dinput/joystick_linuxinput.c b/dlls/dinput/joystick_linuxinput.c index 2b970271ec3..558c8cc19e5 100644 --- a/dlls/dinput/joystick_linuxinput.c +++ b/dlls/dinput/joystick_linuxinput.c @@ -264,7 +264,7 @@ static void find_joydevs(void) else joydev.name = joydev.device;
if (device_disabled_registry(joydev.name)) {
if (device_disabled_registry(joydev.name, FALSE)) { close(fd); HeapFree(GetProcessHeap(), 0, joydev.name); if (joydev.name != joydev.device)
diff --git a/dlls/dinput/joystick_private.h b/dlls/dinput/joystick_private.h index 874bf3e69a7..9cc30605234 100644 --- a/dlls/dinput/joystick_private.h +++ b/dlls/dinput/joystick_private.h @@ -57,7 +57,7 @@ HRESULT setup_dinput_options(JoystickGenericImpl *This, const int *default_axis_
DWORD joystick_map_pov(const POINTL *p) DECLSPEC_HIDDEN;
-BOOL device_disabled_registry(const char* name) DECLSPEC_HIDDEN; +BOOL device_disabled_registry(const char* name, BOOL disable) DECLSPEC_HIDDEN;
ULONG WINAPI JoystickWGenericImpl_Release(LPDIRECTINPUTDEVICE8W iface);
diff --git a/dlls/dinput8/Makefile.in b/dlls/dinput8/Makefile.in index 35b3bfb75f5..71eecd770b3 100644 --- a/dlls/dinput8/Makefile.in +++ b/dlls/dinput8/Makefile.in @@ -1,6 +1,6 @@ MODULE = dinput8.dll IMPORTLIB = dinput8 -IMPORTS = dinput8 dxguid uuid comctl32 ole32 user32 advapi32 +IMPORTS = dinput8 dxguid uuid comctl32 ole32 user32 advapi32 hid EXTRADEFS = -DDIRECTINPUT_VERSION=0x0800 EXTRALIBS = $(IOKIT_LIBS) $(FORCEFEEDBACK_LIBS) PARENTSRC = ../dinput @@ -13,6 +13,7 @@ C_SRCS = \ dinput_main.c \ effect_linuxinput.c \ joystick.c \
- joystick_hid.c \ joystick_linux.c \ joystick_linuxinput.c \ joystick_osx.c \