Signed-off-by: Rémi Bernon rbernon@codeweavers.com ---
Sorry for the spam, a v2 seems actually worth it, to have IID_IDirectInputPIDDriver addition in a dedicated patch.
Also stripped out the outdated comment.
include/hidusage.h | 1 + 1 file changed, 1 insertion(+)
diff --git a/include/hidusage.h b/include/hidusage.h index 002040bddc0..da7274b5945 100644 --- a/include/hidusage.h +++ b/include/hidusage.h @@ -197,6 +197,7 @@ typedef USHORT USAGE, *PUSAGE; #define HID_USAGE_PAGE_CONSUMER ((USAGE) 0x0C) #define HID_USAGE_PAGE_DIGITIZER ((USAGE) 0x0D) #define HID_USAGE_PAGE_HAPTICS ((USAGE) 0x0E) +#define HID_USAGE_PAGE_PID ((USAGE) 0x0F) #define HID_USAGE_PAGE_UNICODE ((USAGE) 0x10) #define HID_USAGE_PAGE_ALPHANUMERIC ((USAGE) 0x14) #define HID_USAGE_PAGE_VENDOR_DEFINED_BEGIN ((USAGE) 0xff00)
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- include/wine/hid.h | 109 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+)
diff --git a/include/wine/hid.h b/include/wine/hid.h index 1d489a24c88..478fb55836d 100644 --- a/include/wine/hid.h +++ b/include/wine/hid.h @@ -117,4 +117,113 @@ struct hid_preparsed_data #define HID_FEATURE_VALUE_CAPS(d) ((d)->value_caps + (d)->feature_caps_start) #define HID_COLLECTION_NODES(d) (struct hid_collection_node *)((char *)(d)->value_caps + (d)->caps_size)
+/* Wine-specific Physical Interface Device usages */ +/* From https://www.usb.org/sites/default/files/documents/pid1_01.pdf */ +#define PID_USAGE_UNDEFINED ((USAGE) 0x00) +#define PID_USAGE_PID ((USAGE) 0x01) +#define PID_USAGE_NORMAL ((USAGE) 0x20) +#define PID_USAGE_SET_EFFECT_REPORT ((USAGE) 0x21) +#define PID_USAGE_EFFECT_BLOCK_INDEX ((USAGE) 0x22) +#define PID_USAGE_PARAMETER_BLOCK_OFFSET ((USAGE) 0x23) +#define PID_USAGE_ROM_FLAG ((USAGE) 0x24) +#define PID_USAGE_EFFECT_TYPE ((USAGE) 0x25) +#define PID_USAGE_ET_CONSTANT_FORCE ((USAGE) 0x26) +#define PID_USAGE_ET_RAMP ((USAGE) 0x27) +#define PID_USAGE_ET_CUSTOM_FORCE_DATA ((USAGE) 0x28) +#define PID_USAGE_ET_SQUARE ((USAGE) 0x30) +#define PID_USAGE_ET_SINE ((USAGE) 0x31) +#define PID_USAGE_ET_TRIANGLE ((USAGE) 0x32) +#define PID_USAGE_ET_SAWTOOTH_UP ((USAGE) 0x33) +#define PID_USAGE_ET_SAWTOOTH_DOWN ((USAGE) 0x34) +#define PID_USAGE_ET_SPRING ((USAGE) 0x40) +#define PID_USAGE_ET_DAMPER ((USAGE) 0x41) +#define PID_USAGE_ET_INERTIA ((USAGE) 0x42) +#define PID_USAGE_ET_FRICTION ((USAGE) 0x43) +#define PID_USAGE_DURATION ((USAGE) 0x50) +#define PID_USAGE_SAMPLE_PERIOD ((USAGE) 0x51) +#define PID_USAGE_GAIN ((USAGE) 0x52) +#define PID_USAGE_TRIGGER_BUTTON ((USAGE) 0x53) +#define PID_USAGE_TRIGGER_REPEAT_INTERVAL ((USAGE) 0x54) +#define PID_USAGE_AXES_ENABLE ((USAGE) 0x55) +#define PID_USAGE_DIRECTION_ENABLE ((USAGE) 0x56) +#define PID_USAGE_DIRECTION ((USAGE) 0x57) +#define PID_USAGE_TYPE_SPECIFIC_BLOCK_OFFSET ((USAGE) 0x58) +#define PID_USAGE_BLOCK_TYPE ((USAGE) 0x59) +#define PID_USAGE_SET_ENVELOPE_REPORT ((USAGE) 0x5a) +#define PID_USAGE_ATTACK_LEVEL ((USAGE) 0x5b) +#define PID_USAGE_ATTACK_TIME ((USAGE) 0x5c) +#define PID_USAGE_FADE_LEVEL ((USAGE) 0x5d) +#define PID_USAGE_FADE_TIME ((USAGE) 0x5e) +#define PID_USAGE_SET_CONDITION_REPORT ((USAGE) 0x5f) +#define PID_USAGE_CP_OFFSET ((USAGE) 0x60) +#define PID_USAGE_POSITIVE_COEFFICIENT ((USAGE) 0x61) +#define PID_USAGE_NEGATIVE_COEFFICIENT ((USAGE) 0x62) +#define PID_USAGE_POSITIVE_SATURATION ((USAGE) 0x63) +#define PID_USAGE_NEGATIVE_SATURATION ((USAGE) 0x64) +#define PID_USAGE_DEAD_BAND ((USAGE) 0x65) +#define PID_USAGE_DOWNLOAD_FORCE_SAMPLE ((USAGE) 0x66) +#define PID_USAGE_ISOCH_CUSTOM_FORCE_ENABLE ((USAGE) 0x67) +#define PID_USAGE_CUSTOM_FORCE_DATA_REPORT ((USAGE) 0x68) +#define PID_USAGE_CUSTOM_FORCE_DATA ((USAGE) 0x69) +#define PID_USAGE_CUSTOM_FORCE_VENDOR_DEFINED_DATA ((USAGE) 0x6a) +#define PID_USAGE_SET_CUSTOM_FORCE_REPORT ((USAGE) 0x6b) +#define PID_USAGE_CUSTOM_FORCE_DATA_OFFSET ((USAGE) 0x6c) +#define PID_USAGE_SAMPLE_COUNT ((USAGE) 0x6d) +#define PID_USAGE_SET_PERIODIC_REPORT ((USAGE) 0x6e) +#define PID_USAGE_OFFSET ((USAGE) 0x6f) +#define PID_USAGE_MAGNITUDE ((USAGE) 0x70) +#define PID_USAGE_PHASE ((USAGE) 0x71) +#define PID_USAGE_PERIOD ((USAGE) 0x72) +#define PID_USAGE_SET_CONSTANT_FORCE_REPORT ((USAGE) 0x73) +#define PID_USAGE_SET_RAMP_FORCE_REPORT ((USAGE) 0x74) +#define PID_USAGE_RAMP_START ((USAGE) 0x75) +#define PID_USAGE_RAMP_END ((USAGE) 0x76) +#define PID_USAGE_EFFECT_OPERATION_REPORT ((USAGE) 0x77) +#define PID_USAGE_EFFECT_OPERATION ((USAGE) 0x78) +#define PID_USAGE_OP_EFFECT_START ((USAGE) 0x79) +#define PID_USAGE_OP_EFFECT_START_SOLO ((USAGE) 0x7a) +#define PID_USAGE_OP_EFFECT_STOP ((USAGE) 0x7b) +#define PID_USAGE_LOOP_COUNT ((USAGE) 0x7c) +#define PID_USAGE_DEVICE_GAIN_REPORT ((USAGE) 0x7d) +#define PID_USAGE_DEVICE_GAIN ((USAGE) 0x7e) +#define PID_USAGE_POOL_REPORT ((USAGE) 0x7f) +#define PID_USAGE_RAM_POOL_SIZE ((USAGE) 0x80) +#define PID_USAGE_ROM_POOL_SIZE ((USAGE) 0x81) +#define PID_USAGE_ROM_EFFECT_BLOCK_COUNT ((USAGE) 0x82) +#define PID_USAGE_SIMULTANEOUS_EFFECTS_MAX ((USAGE) 0x83) +#define PID_USAGE_POOL_ALIGNMENT ((USAGE) 0x84) +#define PID_USAGE_POOL_MOVE_REPORT ((USAGE) 0x85) +#define PID_USAGE_MOVE_SOURCE ((USAGE) 0x86) +#define PID_USAGE_MOVE_DESTINATION ((USAGE) 0x87) +#define PID_USAGE_MOVE_LENGTH ((USAGE) 0x88) +#define PID_USAGE_BLOCK_LOAD_REPORT ((USAGE) 0x89) +#define PID_USAGE_BLOCK_LOAD_STATUS ((USAGE) 0x8b) +#define PID_USAGE_BLOCK_LOAD_SUCCESS ((USAGE) 0x8c) +#define PID_USAGE_BLOCK_LOAD_FULL ((USAGE) 0x8d) +#define PID_USAGE_BLOCK_LOAD_ERROR ((USAGE) 0x8e) +#define PID_USAGE_BLOCK_HANDLE ((USAGE) 0x8f) +#define PID_USAGE_BLOCK_FREE_REPORT ((USAGE) 0x90) +#define PID_USAGE_TYPE_SPECIFIC_BLOCK_HANDLE ((USAGE) 0x91) +#define PID_USAGE_STATE_REPORT ((USAGE) 0x92) +#define PID_USAGE_EFFECT_PLAYING ((USAGE) 0x94) +#define PID_USAGE_DEVICE_CONTROL_REPORT ((USAGE) 0x95) +#define PID_USAGE_DEVICE_CONTROL ((USAGE) 0x96) +#define PID_USAGE_DC_ENABLE_ACTUATORS ((USAGE) 0x97) +#define PID_USAGE_DC_DISABLE_ACTUATORS ((USAGE) 0x98) +#define PID_USAGE_DC_STOP_ALL_EFFECTS ((USAGE) 0x99) +#define PID_USAGE_DC_DEVICE_RESET ((USAGE) 0x9a) +#define PID_USAGE_DC_DEVICE_PAUSE ((USAGE) 0x9b) +#define PID_USAGE_DC_DEVICE_CONTINUE ((USAGE) 0x9c) +#define PID_USAGE_DEVICE_PAUSED ((USAGE) 0x9f) +#define PID_USAGE_ACTUATORS_ENABLED ((USAGE) 0xa0) +#define PID_USAGE_SAFETY_SWITCH ((USAGE) 0xa4) +#define PID_USAGE_ACTUATOR_OVERRIDE_SWITCH ((USAGE) 0xa5) +#define PID_USAGE_ACTUATOR_POWER ((USAGE) 0xa6) +#define PID_USAGE_START_DELAY ((USAGE) 0xa7) +#define PID_USAGE_PARAMETER_BLOCK_SIZE ((USAGE) 0xa8) +#define PID_USAGE_DEVICE_MANAGED_POOL ((USAGE) 0xa9) +#define PID_USAGE_SHARED_PARAMETER_BLOCKS ((USAGE) 0xaa) +#define PID_USAGE_CREATE_NEW_EFFECT_REPORT ((USAGE) 0xab) +#define PID_USAGE_RAM_POOL_AVAILABLE ((USAGE) 0xac) + #endif /* __WINE_PARSE_H */
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- include/dinputd.h | 1 + 1 file changed, 1 insertion(+)
diff --git a/include/dinputd.h b/include/dinputd.h index 9c3b435cc6c..141e634b59d 100644 --- a/include/dinputd.h +++ b/include/dinputd.h @@ -27,6 +27,7 @@ #endif
DEFINE_GUID(IID_IDirectInputJoyConfig8, 0xEB0D7DFA,0x1990,0x4F27,0xB4,0xD6,0xED,0xF2,0xEE,0xC4,0xA4,0x4C); +DEFINE_GUID(IID_IDirectInputPIDDriver, 0xeec6993a,0xb3fd,0x11d2,0xa9,0x16,0x00,0xc0,0x4f,0xb9,0x86,0x38);
typedef struct IDirectInputJoyConfig8 *LPDIRECTINPUTJOYCONFIG8;
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/dinput8/tests/hid.c | 402 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 402 insertions(+)
diff --git a/dlls/dinput8/tests/hid.c b/dlls/dinput8/tests/hid.c index 848619bd468..bd84bac0aca 100644 --- a/dlls/dinput8/tests/hid.c +++ b/dlls/dinput8/tests/hid.c @@ -45,6 +45,7 @@ #define COBJMACROS #include "wingdi.h" #include "dinput.h" +#include "dinputd.h"
#include "initguid.h" #include "ddk/wdm.h" @@ -57,6 +58,7 @@
#include "wine/test.h" #include "wine/mssign.h" +#include "wine/hid.h"
#include "driver_hid.h"
@@ -3288,7 +3290,11 @@ struct check_objects_todos { BOOL ofs; BOOL type; + BOOL flags; BOOL collection_number; + BOOL usage_page; + BOOL usage; + BOOL report_id; };
struct check_objects_params @@ -3317,6 +3323,7 @@ static BOOL CALLBACK check_objects( const DIDEVICEOBJECTINSTANCEW *obj, void *ar check_member( *obj, *exp, "%#x", dwOfs ); todo_wine_if( todo->type ) check_member( *obj, *exp, "%#x", dwType ); + todo_wine_if( todo->flags ) check_member( *obj, *exp, "%#x", dwFlags ); if (!localized) todo_wine check_member_wstr( *obj, *exp, tszName ); check_member( *obj, *exp, "%u", dwFFMaxForce ); @@ -3324,10 +3331,13 @@ static BOOL CALLBACK check_objects( const DIDEVICEOBJECTINSTANCEW *obj, void *ar todo_wine_if( todo->collection_number ) check_member( *obj, *exp, "%u", wCollectionNumber ); check_member( *obj, *exp, "%u", wDesignatorIndex ); + todo_wine_if( todo->usage_page ) check_member( *obj, *exp, "%#04x", wUsagePage ); + todo_wine_if( todo->usage ) check_member( *obj, *exp, "%#04x", wUsage ); check_member( *obj, *exp, "%#04x", dwDimension ); check_member( *obj, *exp, "%#04x", wExponent ); + todo_wine_if( todo->report_id ) check_member( *obj, *exp, "%u", wReportId );
winetest_pop_context(); @@ -4920,6 +4930,397 @@ static void test_device_types( void ) } }
+static void test_force_feedback_joystick( void ) +{ +#include "psh_hid_macros.h" + const unsigned char report_descriptor[] = { + USAGE_PAGE(1, HID_USAGE_PAGE_GENERIC), + USAGE(1, HID_USAGE_GENERIC_JOYSTICK), + COLLECTION(1, Application), + USAGE(1, HID_USAGE_GENERIC_JOYSTICK), + COLLECTION(1, Report), + REPORT_ID(1, 1), + + USAGE(1, HID_USAGE_GENERIC_X), + USAGE(1, HID_USAGE_GENERIC_Y), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(1, 0x7f), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(1, 0x7f), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 2), + INPUT(1, Data|Var|Abs), + + USAGE_PAGE(1, HID_USAGE_PAGE_BUTTON), + USAGE_MINIMUM(1, 1), + USAGE_MAXIMUM(1, 2), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(1, 1), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(1, 1), + REPORT_SIZE(1, 1), + REPORT_COUNT(1, 2), + INPUT(1, Data|Var|Abs), + REPORT_COUNT(1, 6), + INPUT(1, Cnst|Var|Abs), + END_COLLECTION, + + USAGE_PAGE(1, HID_USAGE_PAGE_PID), + USAGE(1, PID_USAGE_DEVICE_CONTROL_REPORT), + COLLECTION(1, Report), + REPORT_ID(1, 1), + END_COLLECTION, + + USAGE(1, PID_USAGE_EFFECT_OPERATION_REPORT), + COLLECTION(1, Report), + REPORT_ID(1, 2), + + USAGE(1, PID_USAGE_EFFECT_BLOCK_INDEX), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(1, 0x7f), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(1, 0x7f), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 1), + OUTPUT(1, Data|Var|Abs), + + USAGE(1, PID_USAGE_EFFECT_OPERATION), + COLLECTION(1, NamedArray), + USAGE(1, PID_USAGE_OP_EFFECT_START), + USAGE(1, PID_USAGE_OP_EFFECT_START_SOLO), + USAGE(1, PID_USAGE_OP_EFFECT_STOP), + LOGICAL_MINIMUM(1, 1), + LOGICAL_MAXIMUM(1, 3), + PHYSICAL_MINIMUM(1, 1), + PHYSICAL_MAXIMUM(1, 3), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 1), + OUTPUT(1, Data|Ary|Abs), + END_COLLECTION, + + USAGE(1, PID_USAGE_LOOP_COUNT), + LOGICAL_MINIMUM(1, 0), + LOGICAL_MAXIMUM(1, 0x7f), + PHYSICAL_MINIMUM(1, 0), + PHYSICAL_MAXIMUM(1, 0x7f), + REPORT_SIZE(1, 8), + REPORT_COUNT(1, 1), + OUTPUT(1, Data|Var|Abs), + END_COLLECTION, + END_COLLECTION, + }; +#undef REPORT_ID_OR_USAGE_PAGE +#include "pop_hid_macros.h" + + static const HIDP_CAPS hid_caps = + { + .InputReportByteLength = 4, + }; + static const DIDEVCAPS expect_caps = + { + .dwSize = sizeof(DIDEVCAPS), + .dwFlags = DIDC_ATTACHED | DIDC_EMULATED, + .dwDevType = DIDEVTYPE_HID | (DI8DEVTYPEJOYSTICK_LIMITED << 8) | DI8DEVTYPE_JOYSTICK, + .dwAxes = 2, + .dwButtons = 2, + .dwFFSamplePeriod = 1000000, + .dwFFMinTimeResolution = 1000000, + .dwHardwareRevision = 1, + .dwFFDriverVersion = 1, + }; + + const DIDEVICEINSTANCEW expect_devinst = + { + .dwSize = sizeof(DIDEVICEINSTANCEW), + .guidInstance = expect_guid_product, + .guidProduct = expect_guid_product, + .dwDevType = DIDEVTYPE_HID | (DI8DEVTYPEJOYSTICK_LIMITED << 8) | DI8DEVTYPE_JOYSTICK, + .tszInstanceName = L"Wine test root driver", + .tszProductName = L"Wine test root driver", + .guidFFDriver = IID_IDirectInputPIDDriver, + .wUsagePage = HID_USAGE_PAGE_GENERIC, + .wUsage = HID_USAGE_GENERIC_JOYSTICK, + }; + const DIDEVICEOBJECTINSTANCEW expect_objects[] = + { + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_YAxis, + .dwType = DIDFT_ABSAXIS|DIDFT_MAKEINSTANCE(1), + .dwFlags = DIDOI_ASPECTPOSITION, + .tszName = L"Y Axis", + .wCollectionNumber = 1, + .wUsagePage = HID_USAGE_PAGE_GENERIC, + .wUsage = HID_USAGE_GENERIC_Y, + .wReportId = 1, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_XAxis, + .dwOfs = 0x4, + .dwType = DIDFT_ABSAXIS|DIDFT_MAKEINSTANCE(0), + .dwFlags = DIDOI_ASPECTPOSITION, + .tszName = L"X Axis", + .wCollectionNumber = 1, + .wUsagePage = HID_USAGE_PAGE_GENERIC, + .wUsage = HID_USAGE_GENERIC_X, + .wReportId = 1, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Button, + .dwOfs = 0x10, + .dwType = DIDFT_PSHBUTTON|DIDFT_MAKEINSTANCE(0)|DIDFT_FFEFFECTTRIGGER, + .dwFlags = DIDOI_FFEFFECTTRIGGER, + .tszName = L"Button 0", + .wCollectionNumber = 1, + .wUsagePage = HID_USAGE_PAGE_BUTTON, + .wUsage = 0x1, + .wReportId = 1, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Button, + .dwOfs = 0x11, + .dwType = DIDFT_PSHBUTTON|DIDFT_MAKEINSTANCE(1)|DIDFT_FFEFFECTTRIGGER, + .dwFlags = DIDOI_FFEFFECTTRIGGER, + .tszName = L"Button 1", + .wCollectionNumber = 1, + .wUsagePage = HID_USAGE_PAGE_BUTTON, + .wUsage = 0x2, + .wReportId = 1, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwOfs = 0x8, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(4)|DIDFT_OUTPUT, + .dwFlags = 0x80008000, + .tszName = L"Effect Block Index", + .wCollectionNumber = 3, + .wUsagePage = HID_USAGE_PAGE_PID, + .wUsage = PID_USAGE_EFFECT_BLOCK_INDEX, + .wReportId = 2, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwOfs = 0x12, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(5)|DIDFT_OUTPUT, + .dwFlags = 0x80008000, + .tszName = L"Op Effect Start", + .wCollectionNumber = 4, + .wUsagePage = HID_USAGE_PAGE_PID, + .wUsage = PID_USAGE_OP_EFFECT_START, + .wReportId = 2, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwOfs = 0x13, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(6)|DIDFT_OUTPUT, + .dwFlags = 0x80008000, + .tszName = L"Op Effect Start Solo", + .wCollectionNumber = 4, + .wUsagePage = HID_USAGE_PAGE_PID, + .wUsage = PID_USAGE_OP_EFFECT_START_SOLO, + .wReportId = 2, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwOfs = 0x14, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(7)|DIDFT_OUTPUT, + .dwFlags = 0x80008000, + .tszName = L"Op Effect Stop", + .wCollectionNumber = 4, + .wUsagePage = HID_USAGE_PAGE_PID, + .wUsage = PID_USAGE_OP_EFFECT_STOP, + .wReportId = 2, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwOfs = 0xc, + .dwType = DIDFT_NODATA|DIDFT_MAKEINSTANCE(8)|DIDFT_OUTPUT, + .dwFlags = 0x80008000, + .tszName = L"Loop Count", + .wCollectionNumber = 3, + .wUsagePage = HID_USAGE_PAGE_PID, + .wUsage = PID_USAGE_LOOP_COUNT, + .wReportId = 2, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(0), + .tszName = L"Collection 0 - Joystick", + .wUsagePage = HID_USAGE_PAGE_GENERIC, + .wUsage = HID_USAGE_GENERIC_JOYSTICK, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(1), + .tszName = L"Collection 1 - Joystick", + .wUsagePage = HID_USAGE_PAGE_GENERIC, + .wUsage = HID_USAGE_GENERIC_JOYSTICK, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(2), + .tszName = L"Collection 2 - PID Device Control Report", + .wUsagePage = HID_USAGE_PAGE_PID, + .wUsage = PID_USAGE_DEVICE_CONTROL_REPORT, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(3), + .tszName = L"Collection 3 - Effect Operation Report", + .wUsagePage = HID_USAGE_PAGE_PID, + .wUsage = PID_USAGE_EFFECT_OPERATION_REPORT, + }, + { + .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW), + .guidType = GUID_Unknown, + .dwType = DIDFT_COLLECTION|DIDFT_NODATA|DIDFT_MAKEINSTANCE(4), + .tszName = L"Collection 4 - Effect Operation", + .wCollectionNumber = 3, + .wUsagePage = HID_USAGE_PAGE_PID, + .wUsage = PID_USAGE_EFFECT_OPERATION, + }, + }; + const struct check_objects_todos objects_todos[ARRAY_SIZE(expect_objects)] = + { + {}, + {}, + {.type = TRUE, .flags = TRUE}, + {.type = TRUE, .flags = TRUE}, + {.ofs = TRUE, .type = TRUE, .flags = TRUE, .collection_number = TRUE, .usage_page = TRUE, .usage = TRUE, .report_id = TRUE}, + {.ofs = TRUE, .type = TRUE, .flags = TRUE, .collection_number = TRUE, .usage_page = TRUE, .usage = TRUE, .report_id = TRUE}, + {.ofs = TRUE, .type = TRUE, .flags = TRUE, .collection_number = TRUE, .usage = TRUE, .report_id = TRUE}, + {.ofs = TRUE, .type = TRUE, .flags = TRUE, .collection_number = TRUE, .usage = TRUE, .report_id = TRUE}, + {.ofs = TRUE, .type = TRUE, .flags = TRUE, .usage = TRUE, .report_id = TRUE}, + }; + + struct check_objects_params check_objects_params = + { + .expect_count = ARRAY_SIZE(expect_objects), + .expect_objs = expect_objects, + .todo_objs = objects_todos, + }; + DIPROPDWORD prop_dword = + { + .diph = + { + .dwSize = sizeof(DIPROPDWORD), + .dwHeaderSize = sizeof(DIPROPHEADER), + .dwHow = DIPH_DEVICE, + }, + }; + WCHAR cwd[MAX_PATH], tempdir[MAX_PATH]; + DIDEVICEINSTANCEW devinst = {0}; + IDirectInputDevice8W *device; + DIDEVCAPS caps = {0}; + IDirectInput8W *di; + HRESULT hr; + ULONG ref; + + GetCurrentDirectoryW( ARRAY_SIZE(cwd), cwd ); + GetTempPathW( ARRAY_SIZE(tempdir), tempdir ); + SetCurrentDirectoryW( tempdir ); + + cleanup_registry_keys(); + if (!dinput_driver_start( report_descriptor, sizeof(report_descriptor), &hid_caps )) goto done; + + hr = DirectInput8Create( instance, DIRECTINPUT_VERSION, &IID_IDirectInput8W, (void **)&di, NULL ); + if (FAILED(hr)) + { + win_skip( "DirectInput8Create returned %#x\n", hr ); + goto done; + } + + hr = IDirectInput8_EnumDevices( di, DI8DEVCLASS_ALL, find_test_device, &devinst, DIEDFL_ALLDEVICES ); + ok( hr == DI_OK, "IDirectInput8_EnumDevices returned: %#x\n", hr ); + if (!IsEqualGUID( &devinst.guidProduct, &expect_guid_product )) + { + win_skip( "device not found, skipping tests\n" ); + IDirectInput8_Release( di ); + goto done; + } + + hr = IDirectInput8_CreateDevice( di, &expect_guid_product, &device, NULL ); + ok( hr == DI_OK, "IDirectInput8_CreateDevice returned %#x\n", hr ); + + hr = IDirectInputDevice8_GetDeviceInfo( device, &devinst ); + ok( hr == DI_OK, "IDirectInputDevice8_GetDeviceInfo returned %#x\n", hr ); + check_member( devinst, expect_devinst, "%d", dwSize ); + todo_wine + check_member_guid( devinst, expect_devinst, guidInstance ); + check_member_guid( devinst, expect_devinst, guidProduct ); + check_member( devinst, expect_devinst, "%#x", dwDevType ); + todo_wine + check_member_wstr( devinst, expect_devinst, tszInstanceName ); + todo_wine + check_member_wstr( devinst, expect_devinst, tszProductName ); + todo_wine + check_member_guid( devinst, expect_devinst, guidFFDriver ); + check_member( devinst, expect_devinst, "%04x", wUsagePage ); + check_member( devinst, expect_devinst, "%04x", wUsage ); + + caps.dwSize = sizeof(DIDEVCAPS); + hr = IDirectInputDevice8_GetCapabilities( device, &caps ); + ok( hr == DI_OK, "IDirectInputDevice8_GetCapabilities returned %#x\n", hr ); + check_member( caps, expect_caps, "%d", dwSize ); + check_member( caps, expect_caps, "%#x", dwFlags ); + check_member( caps, expect_caps, "%#x", dwDevType ); + check_member( caps, expect_caps, "%d", dwAxes ); + check_member( caps, expect_caps, "%d", dwButtons ); + check_member( caps, expect_caps, "%d", dwPOVs ); + todo_wine + check_member( caps, expect_caps, "%d", dwFFSamplePeriod ); + todo_wine + check_member( caps, expect_caps, "%d", dwFFMinTimeResolution ); + check_member( caps, expect_caps, "%d", dwFirmwareRevision ); + todo_wine + check_member( caps, expect_caps, "%d", dwHardwareRevision ); + todo_wine + check_member( caps, expect_caps, "%d", dwFFDriverVersion ); + + prop_dword.dwData = 0xdeadbeef; + hr = IDirectInputDevice8_GetProperty( device, DIPROP_FFGAIN, &prop_dword.diph ); + todo_wine + ok( hr == DI_OK, "IDirectInputDevice8_GetProperty DIPROP_FFGAIN returned %#x\n", hr ); + todo_wine + ok( prop_dword.dwData == 10000, "got %u expected %u\n", prop_dword.dwData, 10000 ); + + hr = IDirectInputDevice8_GetProperty( device, DIPROP_FFLOAD, &prop_dword.diph ); + todo_wine + ok( hr == DIERR_NOTEXCLUSIVEACQUIRED, "IDirectInputDevice8_GetProperty DIPROP_FFLOAD returned %#x\n", hr ); + + hr = IDirectInputDevice8_EnumObjects( device, check_objects, &check_objects_params, DIDFT_ALL ); + ok( hr == DI_OK, "IDirectInputDevice8_EnumObjects returned %#x\n", hr ); + todo_wine + ok( check_objects_params.index >= check_objects_params.expect_count, "missing %u objects\n", + check_objects_params.expect_count - check_objects_params.index ); + + hr = IDirectInputDevice8_SetDataFormat( device, &c_dfDIJoystick2 ); + ok( hr == DI_OK, "IDirectInputDevice8_SetDataFormat returned: %#x\n", hr ); + + ref = IDirectInputDevice8_Release( device ); + ok( ref == 0, "IDirectInputDeviceW_Release returned %d\n", ref ); + + ref = IDirectInput8_Release( di ); + ok( ref == 0, "IDirectInput8_Release returned %d\n", ref ); + +done: + pnp_driver_stop(); + cleanup_registry_keys(); + SetCurrentDirectoryW( cwd ); +} + START_TEST( hid ) { HANDLE mapping; @@ -4962,6 +5363,7 @@ START_TEST( hid ) CoInitialize( NULL ); test_device_types(); test_simple_joystick(); + test_force_feedback_joystick(); CoUninitialize();
UnmapViewOfFile( test_data );
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=99054
Your paranoid android.
=== w7u_el (32 bit report) ===
dinput8: hid: Timeout
Make sure we only read input object from the device state input report and only look for generic and button usage pages to find the report.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/dinput/joystick_hid.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-)
diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c index 29cb8990689..a20925b6176 100644 --- a/dlls/dinput/joystick_hid.c +++ b/dlls/dinput/joystick_hid.c @@ -937,6 +937,8 @@ static BOOL check_device_state_button( struct hid_joystick *impl, struct hid_cap struct parse_device_state_params *params = data; BYTE old_value, value;
+ if (instance->wReportId != impl->device_state_report_id) return DIENUM_CONTINUE; + value = params->buttons[instance->wUsage - 1]; old_value = params->old_state[instance->dwOfs]; impl->device_state[instance->dwOfs] = value; @@ -1008,6 +1010,8 @@ static BOOL read_device_state_value( struct hid_joystick *impl, struct hid_caps LONG old_value, value; NTSTATUS status;
+ if (instance->wReportId != impl->device_state_report_id) return DIENUM_CONTINUE; + extra = impl->input_extra_caps + (value_caps - impl->input_value_caps); status = HidP_GetUsageValue( HidP_Input, instance->wUsagePage, 0, instance->wUsage, &logical_value, impl->preparsed, report_buf, report_len ); @@ -1360,10 +1364,15 @@ static BOOL init_objects( struct hid_joystick *impl, struct hid_caps *caps, if (instance->dwType & DIDFT_AXIS) impl->dev_caps.dwAxes++; if (instance->dwType & DIDFT_POV) impl->dev_caps.dwPOVs++;
- if (!impl->device_state_report_id) - impl->device_state_report_id = instance->wReportId; - else if (impl->device_state_report_id != instance->wReportId) - FIXME( "multiple device state reports found!\n" ); + if (instance->dwType & (DIDFT_BUTTON|DIDFT_AXIS|DIDFT_POV) && + (instance->wUsagePage == HID_USAGE_PAGE_GENERIC || + instance->wUsagePage == HID_USAGE_PAGE_BUTTON)) + { + if (!impl->device_state_report_id) + impl->device_state_report_id = instance->wReportId; + else if (impl->device_state_report_id != instance->wReportId) + FIXME( "multiple device state reports found!\n" ); + }
return DIENUM_CONTINUE; }
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/dinput/joystick_hid.c | 349 +++++++++++++------------------------ 1 file changed, 123 insertions(+), 226 deletions(-)
diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c index a20925b6176..4d6d53b588e 100644 --- a/dlls/dinput/joystick_hid.c +++ b/dlls/dinput/joystick_hid.c @@ -22,6 +22,8 @@ #include <string.h> #include <math.h>
+#include "ntstatus.h" +#define WIN32_NO_STATUS #include "windef.h" #include "winbase.h" #include "winternl.h" @@ -36,6 +38,7 @@ #include "setupapi.h"
#include "wine/debug.h" +#include "wine/hid.h"
#include "dinput_private.h" #include "device_private.h" @@ -50,91 +53,23 @@ DEFINE_GUID( GUID_DEVINTERFACE_WINEXINPUT,0x6c53d5fd,0x6480,0x440f,0xb6,0x18,0x4 DEFINE_GUID( hid_joystick_guid, 0x9e573edb, 0x7734, 0x11d2, 0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf7 ); DEFINE_DEVPROPKEY( DEVPROPKEY_HID_HANDLE, 0xbc62e415, 0xf4fe, 0x405c, 0x8e, 0xda, 0x63, 0x6f, 0xb5, 0x9f, 0x08, 0x98, 2 );
-static inline const char *debugstr_hidp_link_collection_node( HIDP_LINK_COLLECTION_NODE *node ) +static inline const char *debugstr_hid_value_caps( struct hid_value_caps *caps ) { - if (!node) return "(null)"; - return wine_dbg_sprintf( "Usg %02x:%02x Par %u Nxt %u Cnt %u Chld %u Type %u Alias %d User %p", - node->LinkUsagePage, node->LinkUsage, node->Parent, node->NextSibling, - node->NumberOfChildren, node->FirstChild, node->CollectionType, node->IsAlias, - node->UserContext ); -} - -static inline const char *debugstr_hidp_button_caps( HIDP_BUTTON_CAPS *caps ) -{ - const char *str; - if (!caps) return "(null)"; - - str = wine_dbg_sprintf( "RId %d,", caps->ReportID ); - if (!caps->IsRange) - str = wine_dbg_sprintf( "%s Usg %02x:%02x Dat %02x,", str, caps->UsagePage, caps->NotRange.Usage, - caps->NotRange.DataIndex ); - else - str = wine_dbg_sprintf( "%s Usg %02x:%02x-%02x Dat %02x-%02x,", str, caps->UsagePage, caps->Range.UsageMin, - caps->Range.UsageMax, caps->Range.DataIndexMin, caps->Range.DataIndexMax ); - if (!caps->IsStringRange) - str = wine_dbg_sprintf( "%s Str %d,", str, caps->NotRange.StringIndex ); - else - str = wine_dbg_sprintf( "%s Str %d-%d,", str, caps->Range.StringMin, caps->Range.StringMax ); - if (!caps->IsDesignatorRange) - str = wine_dbg_sprintf( "%s Des %d,", str, caps->NotRange.DesignatorIndex ); - else - str = wine_dbg_sprintf( "%s Des %d-%d,", str, caps->Range.DesignatorMin, caps->Range.DesignatorMax ); - return wine_dbg_sprintf( "%s Bits %02x Alias %d Abs %d, LCol %u LUsg %02x-%02x", str, caps->BitField, caps->IsAlias, - caps->IsAbsolute, caps->LinkCollection, caps->LinkUsagePage, caps->LinkUsage ); -} - -static inline const char *debugstr_hidp_value_caps( HIDP_VALUE_CAPS *caps ) -{ - const char *str; if (!caps) return "(null)"; - - str = wine_dbg_sprintf( "RId %d,", caps->ReportID ); - if (!caps->IsRange) - str = wine_dbg_sprintf( "%s Usg %02x:%02x Dat %02x,", str, caps->UsagePage, caps->NotRange.Usage, - caps->NotRange.DataIndex ); - else - str = wine_dbg_sprintf( "%s Usg %02x:%02x-%02x Dat %02x-%02x,", str, caps->UsagePage, caps->Range.UsageMin, - caps->Range.UsageMax, caps->Range.DataIndexMin, caps->Range.DataIndexMax ); - if (!caps->IsStringRange) - str = wine_dbg_sprintf( "%s Str %d,", str, caps->NotRange.StringIndex ); - else - str = wine_dbg_sprintf( "%s Str %d-%d,", str, caps->Range.StringMin, caps->Range.StringMax ); - if (!caps->IsDesignatorRange) - str = wine_dbg_sprintf( "%s Des %d,", str, caps->NotRange.DesignatorIndex ); - else - str = wine_dbg_sprintf( "%s Des %d-%d,", str, caps->Range.DesignatorMin, caps->Range.DesignatorMax ); - return wine_dbg_sprintf( "%s Bits %02x Alias %d Abs %d Null %d, LCol %u LUsg %02x-%02x, " - "BitSz %d, RCnt %d, Unit %x E%+d, Log %+d-%+d, Phy %+d-%+d", - str, caps->BitField, caps->IsAlias, caps->IsAbsolute, caps->HasNull, - caps->LinkCollection, caps->LinkUsagePage, caps->LinkUsage, - caps->BitSize, caps->ReportCount, caps->Units, caps->UnitsExp, - caps->LogicalMin, caps->LogicalMax, caps->PhysicalMin, caps->PhysicalMax ); + return wine_dbg_sprintf( "RId %d, Usg %02x:%02x-%02x Dat %02x-%02x, Str %d-%d, Des %d-%d, " + "Bits %02x Flags %#x, LCol %d LUsg %02x:%02x, BitSz %d, RCnt %d, Unit %x E%+d, Log %+d-%+d, Phy %+d-%+d", + caps->report_id, caps->usage_page, caps->usage_min, caps->usage_max, caps->data_index_min, caps->data_index_max, + caps->string_min, caps->string_max, caps->designator_min, caps->designator_max, caps->bit_field, caps->flags, + caps->link_collection, caps->link_usage_page, caps->link_usage, caps->bit_size, caps->report_count, + caps->units, caps->units_exp, caps->logical_min, caps->logical_max, caps->physical_min, caps->physical_max ); }
-struct hid_caps +static inline const char *debugstr_hid_collection_node( struct hid_collection_node *node ) { - enum { LINK_COLLECTION_NODE, BUTTON_CAPS, VALUE_CAPS } type; - union - { - HIDP_LINK_COLLECTION_NODE *node; - HIDP_BUTTON_CAPS *button; - HIDP_VALUE_CAPS *value; - }; -}; - -static inline const char *debugstr_hid_caps( struct hid_caps *caps ) -{ - switch (caps->type) - { - case LINK_COLLECTION_NODE: - return debugstr_hidp_link_collection_node( caps->node ); - case BUTTON_CAPS: - return debugstr_hidp_button_caps( caps->button ); - case VALUE_CAPS: - return debugstr_hidp_value_caps( caps->value ); - } - - return "(unknown type)"; + if (!node) return "(null)"; + return wine_dbg_sprintf( "Usg %02x:%02x, Parent %u, Next %u, NbChild %u, Child %u, Type %02x", + node->usage_page, node->usage, node->parent, node->next_sibling, + node->number_of_children, node->first_child, node->collection_type ); }
struct extra_caps @@ -159,9 +94,6 @@ struct hid_joystick DIDEVCAPS dev_caps; HIDP_CAPS caps;
- HIDP_LINK_COLLECTION_NODE *collection_nodes; - HIDP_BUTTON_CAPS *input_button_caps; - HIDP_VALUE_CAPS *input_value_caps; struct extra_caps *input_extra_caps;
char *input_report_buf; @@ -202,10 +134,11 @@ static const GUID *object_usage_to_guid( USAGE usage_page, USAGE usage ) return &GUID_Unknown; }
-typedef BOOL (*enum_object_callback)( struct hid_joystick *impl, struct hid_caps *caps, DIDEVICEOBJECTINSTANCEW *instance, void *data ); +typedef BOOL (*enum_object_callback)( struct hid_joystick *impl, struct hid_value_caps *caps, + DIDEVICEOBJECTINSTANCEW *instance, void *data );
static BOOL enum_object( struct hid_joystick *impl, const DIPROPHEADER *filter, DWORD flags, - enum_object_callback callback, struct hid_caps *caps, + enum_object_callback callback, struct hid_value_caps *caps, DIDEVICEOBJECTINSTANCEW *instance, void *data ) { if (flags != DIDFT_ALL && !(flags & DIDFT_GETTYPE( instance->dwType ))) return DIENUM_CONTINUE; @@ -242,13 +175,15 @@ static void set_axis_type( DIDEVICEOBJECTINSTANCEW *instance, BOOL *seen, DWORD static BOOL enum_objects( struct hid_joystick *impl, const DIPROPHEADER *header, DWORD flags, enum_object_callback callback, void *data ) { - DIDEVICEOBJECTINSTANCEW instance = {.dwSize = sizeof(DIDEVICEOBJECTINSTANCEW)}; DWORD collection = 0, axis = 0, button = 0, pov = 0, value_ofs = 0, button_ofs = 0, i, j; + struct hid_preparsed_data *preparsed = (struct hid_preparsed_data *)impl->preparsed; + DIDEVICEOBJECTINSTANCEW instance = {.dwSize = sizeof(DIDEVICEOBJECTINSTANCEW)}; DIDATAFORMAT *format = impl->base.data_format.wine_df; int *offsets = impl->base.data_format.offsets; + struct hid_collection_node *node, *node_end; + struct hid_value_caps *caps, *caps_end; DIPROPHEADER filter = *header; BOOL ret, seen_axis[6] = {0}; - struct hid_caps caps = {0};
if (filter.dwHow == DIPH_BYOFFSET) { @@ -263,83 +198,83 @@ static BOOL enum_objects( struct hid_joystick *impl, const DIPROPHEADER *header, button_ofs += impl->caps.NumberOutputValueCaps * sizeof(LONG); button_ofs += impl->caps.NumberFeatureValueCaps * sizeof(LONG);
- for (i = 0; i < impl->caps.NumberInputValueCaps; ++i) + for (caps = HID_INPUT_VALUE_CAPS( preparsed ), caps_end = caps + preparsed->input_caps_count; + caps != caps_end; ++caps) { - caps.value = impl->input_value_caps + i; - - if (caps.value->UsagePage >= HID_USAGE_PAGE_VENDOR_DEFINED_BEGIN) - TRACE( "Ignoring input value %s, vendor specific.\n", debugstr_hid_caps( &caps ) ); - else if (caps.value->IsAlias) - TRACE( "Ignoring input value %s, aliased.\n", debugstr_hid_caps( &caps ) ); - else if (caps.value->IsRange) - FIXME( "Ignoring input value %s, usage range not implemented.\n", debugstr_hid_caps( &caps ) ); - else if (caps.value->ReportCount > 1) - FIXME( "Ignoring input value %s, array not implemented.\n", debugstr_hid_caps( &caps ) ); - else if (caps.value->UsagePage != HID_USAGE_PAGE_GENERIC) - TRACE( "Ignoring input value %s, usage page not implemented.\n", debugstr_hid_caps( &caps ) ); + if (!caps->usage_page) continue; + if (caps->flags & HID_VALUE_CAPS_IS_BUTTON) continue; + + if (caps->usage_page >= HID_USAGE_PAGE_VENDOR_DEFINED_BEGIN) + TRACE( "Ignoring input value %s, vendor specific.\n", debugstr_hid_value_caps( caps ) ); + else if (caps->flags & HID_VALUE_CAPS_IS_RANGE) + FIXME( "Ignoring input value %s, usage range not implemented.\n", debugstr_hid_value_caps( caps ) ); + else if (caps->report_count > 1) + FIXME( "Ignoring input value %s, array not implemented.\n", debugstr_hid_value_caps( caps ) ); + else if (caps->usage_page != HID_USAGE_PAGE_GENERIC) + TRACE( "Ignoring input value %s, usage page not implemented.\n", debugstr_hid_value_caps( caps ) ); else { instance.dwOfs = value_ofs; - instance.wUsagePage = caps.value->UsagePage; - instance.wUsage = caps.value->NotRange.Usage; + instance.wUsagePage = caps->usage_page; + instance.wUsage = caps->usage_min; instance.guidType = *object_usage_to_guid( instance.wUsagePage, instance.wUsage ); - instance.wReportId = caps.value->ReportID; - instance.wCollectionNumber = caps.value->LinkCollection; + instance.wReportId = caps->report_id; + instance.wCollectionNumber = caps->link_collection;
switch (instance.wUsage) { case HID_USAGE_GENERIC_X: set_axis_type( &instance, seen_axis, 0, &axis ); instance.dwFlags = DIDOI_ASPECTPOSITION; - ret = enum_object( impl, &filter, flags, callback, &caps, &instance, data ); + ret = enum_object( impl, &filter, flags, callback, caps, &instance, data ); if (ret != DIENUM_CONTINUE) return ret; break; case HID_USAGE_GENERIC_Y: set_axis_type( &instance, seen_axis, 1, &axis ); instance.dwFlags = DIDOI_ASPECTPOSITION; - ret = enum_object( impl, &filter, flags, callback, &caps, &instance, data ); + ret = enum_object( impl, &filter, flags, callback, caps, &instance, data ); if (ret != DIENUM_CONTINUE) return ret; break; case HID_USAGE_GENERIC_Z: case HID_USAGE_GENERIC_WHEEL: set_axis_type( &instance, seen_axis, 2, &axis ); instance.dwFlags = DIDOI_ASPECTPOSITION; - ret = enum_object( impl, &filter, flags, callback, &caps, &instance, data ); + ret = enum_object( impl, &filter, flags, callback, caps, &instance, data ); if (ret != DIENUM_CONTINUE) return ret; break; case HID_USAGE_GENERIC_RX: set_axis_type( &instance, seen_axis, 3, &axis ); instance.dwFlags = DIDOI_ASPECTPOSITION; - ret = enum_object( impl, &filter, flags, callback, &caps, &instance, data ); + ret = enum_object( impl, &filter, flags, callback, caps, &instance, data ); if (ret != DIENUM_CONTINUE) return ret; break; case HID_USAGE_GENERIC_RY: set_axis_type( &instance, seen_axis, 4, &axis ); instance.dwFlags = DIDOI_ASPECTPOSITION; - ret = enum_object( impl, &filter, flags, callback, &caps, &instance, data ); + ret = enum_object( impl, &filter, flags, callback, caps, &instance, data ); if (ret != DIENUM_CONTINUE) return ret; break; case HID_USAGE_GENERIC_RZ: set_axis_type( &instance, seen_axis, 5, &axis ); instance.dwFlags = DIDOI_ASPECTPOSITION; - ret = enum_object( impl, &filter, flags, callback, &caps, &instance, data ); + ret = enum_object( impl, &filter, flags, callback, caps, &instance, data ); if (ret != DIENUM_CONTINUE) return ret; break; case HID_USAGE_GENERIC_DIAL: case HID_USAGE_GENERIC_SLIDER: instance.dwType = DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 6 + axis++ ); instance.dwFlags = DIDOI_ASPECTPOSITION; - ret = enum_object( impl, &filter, flags, callback, &caps, &instance, data ); + ret = enum_object( impl, &filter, flags, callback, caps, &instance, data ); if (ret != DIENUM_CONTINUE) return ret; break; case HID_USAGE_GENERIC_HATSWITCH: instance.dwType = DIDFT_POV | DIDFT_MAKEINSTANCE( pov++ ); instance.dwFlags = 0; - ret = enum_object( impl, &filter, flags, callback, &caps, &instance, data ); + ret = enum_object( impl, &filter, flags, callback, caps, &instance, data ); if (ret != DIENUM_CONTINUE) return ret; break; default: - FIXME( "Ignoring input value %s, usage not implemented.\n", debugstr_hid_caps( &caps ) ); + FIXME( "Ignoring input value %s, usage not implemented.\n", debugstr_hid_value_caps( caps ) ); break; } } @@ -347,69 +282,53 @@ static BOOL enum_objects( struct hid_joystick *impl, const DIPROPHEADER *header, value_ofs += sizeof(LONG); }
- for (i = 0; i < impl->caps.NumberInputButtonCaps; ++i) + for (caps = HID_INPUT_VALUE_CAPS( preparsed ), caps_end = caps + preparsed->input_caps_count; + caps != caps_end; ++caps) { - caps.button = impl->input_button_caps + i; - - if (caps.button->UsagePage >= HID_USAGE_PAGE_VENDOR_DEFINED_BEGIN) - TRACE( "Ignoring input button %s, vendor specific.\n", debugstr_hid_caps( &caps ) ); - else if (caps.button->IsAlias) - TRACE( "Ignoring input button %s, aliased.\n", debugstr_hid_caps( &caps ) ); - else if (caps.button->UsagePage != HID_USAGE_PAGE_BUTTON) - TRACE( "Ignoring input button %s, usage page not implemented.\n", debugstr_hid_caps( &caps ) ); - else if (caps.button->IsRange) + if (!caps->usage_page) continue; + if (!(caps->flags & HID_VALUE_CAPS_IS_BUTTON)) continue; + + if (caps->usage_page >= HID_USAGE_PAGE_VENDOR_DEFINED_BEGIN) + TRACE( "Ignoring input button %s, vendor specific.\n", debugstr_hid_value_caps( caps ) ); + else if (caps->usage_page != HID_USAGE_PAGE_BUTTON) + TRACE( "Ignoring input button %s, usage page not implemented.\n", debugstr_hid_value_caps( caps ) ); + else { - for (j = caps.button->Range.UsageMin; j <= caps.button->Range.UsageMax; ++j) + for (j = caps->usage_min; j <= caps->usage_max; ++j) { - instance.dwOfs = button_ofs + (j - caps.button->Range.UsageMin); + instance.dwOfs = button_ofs + (j - caps->usage_min); instance.dwType = DIDFT_PSHBUTTON | DIDFT_MAKEINSTANCE( button++ ); instance.dwFlags = 0; - instance.wUsagePage = caps.button->UsagePage; + instance.wUsagePage = caps->usage_page; instance.wUsage = j; instance.guidType = *object_usage_to_guid( instance.wUsagePage, instance.wUsage ); - instance.wReportId = caps.button->ReportID; - instance.wCollectionNumber = caps.button->LinkCollection; - ret = enum_object( impl, &filter, flags, callback, &caps, &instance, data ); + instance.wReportId = caps->report_id; + instance.wCollectionNumber = caps->link_collection; + ret = enum_object( impl, &filter, flags, callback, caps, &instance, data ); if (ret != DIENUM_CONTINUE) return ret; } } - else - { - instance.dwOfs = button_ofs; - instance.dwType = DIDFT_PSHBUTTON | DIDFT_MAKEINSTANCE( button++ ); - instance.dwFlags = 0; - instance.wUsagePage = caps.button->UsagePage; - instance.wUsage = caps.button->NotRange.Usage; - instance.guidType = *object_usage_to_guid( instance.wUsagePage, instance.wUsage ); - instance.wReportId = caps.button->ReportID; - instance.wCollectionNumber = caps.button->LinkCollection; - ret = enum_object( impl, &filter, flags, callback, &caps, &instance, data ); - if (ret != DIENUM_CONTINUE) return ret; - }
- if (caps.button->IsRange) button_ofs += caps.button->Range.UsageMax - caps.button->Range.UsageMin; - button_ofs++; + button_ofs += caps->usage_max - caps->usage_min + 1; }
- for (i = 0; i < impl->caps.NumberLinkCollectionNodes; ++i) + for (node = HID_COLLECTION_NODES( preparsed ), node_end = node + preparsed->number_link_collection_nodes; + node != node_end; ++node) { - caps.node = impl->collection_nodes + i; - - if (caps.node->LinkUsagePage >= HID_USAGE_PAGE_VENDOR_DEFINED_BEGIN) - TRACE( "Ignoring collection %s, vendor specific.\n", debugstr_hid_caps( &caps ) ); - else if (caps.node->IsAlias) - TRACE( "Ignoring collection %s, aliased.\n", debugstr_hid_caps( &caps ) ); + if (!node->usage_page) continue; + if (node->usage_page >= HID_USAGE_PAGE_VENDOR_DEFINED_BEGIN) + TRACE( "Ignoring collection %s, vendor specific.\n", debugstr_hid_collection_node( node ) ); else { instance.dwOfs = 0; instance.dwType = DIDFT_COLLECTION | DIDFT_MAKEINSTANCE( collection++ ) | DIDFT_NODATA; instance.dwFlags = 0; - instance.wUsagePage = caps.node->LinkUsagePage; - instance.wUsage = caps.node->LinkUsage; + instance.wUsagePage = node->usage_page; + instance.wUsage = node->usage; instance.guidType = *object_usage_to_guid( instance.wUsagePage, instance.wUsage ); instance.wReportId = 0; - instance.wCollectionNumber = caps.node->Parent; - ret = enum_object( impl, &filter, flags, callback, &caps, &instance, data ); + instance.wCollectionNumber = node->parent; + ret = enum_object( impl, &filter, flags, callback, NULL, &instance, data ); if (ret != DIENUM_CONTINUE) return ret; } } @@ -428,9 +347,6 @@ static ULONG WINAPI hid_joystick_Release( IDirectInputDevice8W *iface ) HeapFree( GetProcessHeap(), 0, tmp.usages_buf ); HeapFree( GetProcessHeap(), 0, tmp.input_report_buf ); HeapFree( GetProcessHeap(), 0, tmp.input_extra_caps ); - HeapFree( GetProcessHeap(), 0, tmp.input_value_caps ); - HeapFree( GetProcessHeap(), 0, tmp.input_button_caps ); - HeapFree( GetProcessHeap(), 0, tmp.collection_nodes ); HidD_FreePreparsedData( tmp.preparsed ); CancelIoEx( tmp.device, &tmp.read_ovl ); CloseHandle( tmp.base.read_event ); @@ -459,7 +375,7 @@ struct enum_objects_params void *context; };
-static BOOL enum_objects_callback( struct hid_joystick *impl, struct hid_caps *caps, +static BOOL enum_objects_callback( struct hid_joystick *impl, struct hid_value_caps *caps, DIDEVICEOBJECTINSTANCEW *instance, void *data ) { struct enum_objects_params *params = data; @@ -513,37 +429,38 @@ static HRESULT WINAPI hid_joystick_EnumObjects( IDirectInputDevice8W *iface, LPD return DI_OK; }
-static BOOL get_property_prop_range( struct hid_joystick *impl, struct hid_caps *caps, +static BOOL get_property_prop_range( struct hid_joystick *impl, struct hid_value_caps *caps, DIDEVICEOBJECTINSTANCEW *instance, void *data ) { - HIDP_VALUE_CAPS *value_caps = caps->value; DIPROPRANGE *value = data; - value->lMin = value_caps->PhysicalMin; - value->lMax = value_caps->PhysicalMax; + value->lMin = caps->physical_min; + value->lMax = caps->physical_max; return DIENUM_STOP; }
-static BOOL get_property_prop_deadzone( struct hid_joystick *impl, struct hid_caps *caps, +static BOOL get_property_prop_deadzone( struct hid_joystick *impl, struct hid_value_caps *caps, DIDEVICEOBJECTINSTANCEW *instance, void *data ) { + struct hid_preparsed_data *preparsed = (struct hid_preparsed_data *)impl->preparsed; struct extra_caps *extra; DIPROPDWORD *deadzone = data; - extra = impl->input_extra_caps + (caps->value - impl->input_value_caps); + extra = impl->input_extra_caps + (caps - HID_INPUT_VALUE_CAPS( preparsed )); deadzone->dwData = extra->deadzone; return DIENUM_STOP; }
-static BOOL get_property_prop_saturation( struct hid_joystick *impl, struct hid_caps *caps, +static BOOL get_property_prop_saturation( struct hid_joystick *impl, struct hid_value_caps *caps, DIDEVICEOBJECTINSTANCEW *instance, void *data ) { + struct hid_preparsed_data *preparsed = (struct hid_preparsed_data *)impl->preparsed; struct extra_caps *extra; DIPROPDWORD *saturation = data; - extra = impl->input_extra_caps + (caps->value - impl->input_value_caps); + extra = impl->input_extra_caps + (caps - HID_INPUT_VALUE_CAPS( preparsed )); saturation->dwData = extra->saturation; return DIENUM_STOP; }
-static BOOL get_property_prop_granularity( struct hid_joystick *impl, struct hid_caps *caps, +static BOOL get_property_prop_granularity( struct hid_joystick *impl, struct hid_value_caps *caps, DIDEVICEOBJECTINSTANCEW *instance, void *data ) { DIPROPDWORD *granularity = data; @@ -634,47 +551,48 @@ static HRESULT WINAPI hid_joystick_GetProperty( IDirectInputDevice8W *iface, con return DI_OK; }
-static BOOL set_property_prop_range( struct hid_joystick *impl, struct hid_caps *caps, +static BOOL set_property_prop_range( struct hid_joystick *impl, struct hid_value_caps *caps, DIDEVICEOBJECTINSTANCEW *instance, void *data ) { - HIDP_VALUE_CAPS *value_caps = caps->value; DIPROPRANGE *value = data; LONG tmp;
- value_caps->PhysicalMin = value->lMin; - value_caps->PhysicalMax = value->lMax; + caps->physical_min = value->lMin; + caps->physical_max = value->lMax;
if (instance->dwType & DIDFT_AXIS) { - if (!value_caps->PhysicalMin) tmp = value_caps->PhysicalMax / 2; - else tmp = round( (value_caps->PhysicalMin + value_caps->PhysicalMax) / 2.0 ); + if (!caps->physical_min) tmp = caps->physical_max / 2; + else tmp = round( (caps->physical_min + caps->physical_max) / 2.0 ); *(LONG *)(impl->device_state + instance->dwOfs) = tmp; } else if (instance->dwType & DIDFT_POV) { - tmp = value_caps->LogicalMax - value_caps->LogicalMin; - if (tmp > 0) value_caps->PhysicalMax -= value->lMax / (tmp + 1); + tmp = caps->logical_max - caps->logical_min; + if (tmp > 0) caps->physical_max -= value->lMax / (tmp + 1); *(LONG *)(impl->device_state + instance->dwOfs) = -1; } return DIENUM_CONTINUE; }
-static BOOL set_property_prop_deadzone( struct hid_joystick *impl, struct hid_caps *caps, +static BOOL set_property_prop_deadzone( struct hid_joystick *impl, struct hid_value_caps *caps, DIDEVICEOBJECTINSTANCEW *instance, void *data ) { + struct hid_preparsed_data *preparsed = (struct hid_preparsed_data *)impl->preparsed; struct extra_caps *extra; DIPROPDWORD *deadzone = data; - extra = impl->input_extra_caps + (caps->value - impl->input_value_caps); + extra = impl->input_extra_caps + (caps - HID_INPUT_VALUE_CAPS( preparsed )); extra->deadzone = deadzone->dwData; return DIENUM_CONTINUE; }
-static BOOL set_property_prop_saturation( struct hid_joystick *impl, struct hid_caps *caps, +static BOOL set_property_prop_saturation( struct hid_joystick *impl, struct hid_value_caps *caps, DIDEVICEOBJECTINSTANCEW *instance, void *data ) { + struct hid_preparsed_data *preparsed = (struct hid_preparsed_data *)impl->preparsed; struct extra_caps *extra; DIPROPDWORD *saturation = data; - extra = impl->input_extra_caps + (caps->value - impl->input_value_caps); + extra = impl->input_extra_caps + (caps - HID_INPUT_VALUE_CAPS( preparsed )); extra->saturation = saturation->dwData; return DIENUM_CONTINUE; } @@ -797,7 +715,7 @@ static HRESULT WINAPI hid_joystick_GetDeviceState( IDirectInputDevice8W *iface, return hr; }
-static BOOL get_object_info( struct hid_joystick *impl, struct hid_caps *caps, +static BOOL get_object_info( struct hid_joystick *impl, struct hid_value_caps *caps, DIDEVICEOBJECTINSTANCEW *instance, void *data ) { DIDEVICEOBJECTINSTANCEW *dest = data; @@ -930,7 +848,7 @@ struct parse_device_state_params DWORD seq; };
-static BOOL check_device_state_button( struct hid_joystick *impl, struct hid_caps *caps, +static BOOL check_device_state_button( struct hid_joystick *impl, struct hid_value_caps *caps, DIDEVICEOBJECTINSTANCEW *instance, void *data ) { IDirectInputDevice8W *iface = &impl->base.IDirectInputDevice8W_iface; @@ -948,29 +866,29 @@ static BOOL check_device_state_button( struct hid_joystick *impl, struct hid_cap return DIENUM_CONTINUE; }
-static LONG sign_extend( ULONG value, const HIDP_VALUE_CAPS *caps ) +static LONG sign_extend( ULONG value, struct hid_value_caps *caps ) { - UINT sign = 1 << (caps->BitSize - 1); - if (sign <= 1 || caps->LogicalMin >= 0) return value; + UINT sign = 1 << (caps->bit_size - 1); + if (sign <= 1 || caps->logical_min >= 0) return value; return value - ((value & sign) << 1); }
-static LONG scale_value( ULONG value, const HIDP_VALUE_CAPS *caps, LONG min, LONG max ) +static LONG scale_value( ULONG value, struct hid_value_caps *caps, LONG min, LONG max ) { LONG tmp = sign_extend( value, caps ); - if (caps->LogicalMin > tmp || caps->LogicalMax < tmp) return -1; /* invalid / null value */ - return min + MulDiv( tmp - caps->LogicalMin, max - min, caps->LogicalMax - caps->LogicalMin ); + if (caps->logical_min > tmp || caps->logical_max < tmp) return -1; /* invalid / null value */ + return min + MulDiv( tmp - caps->logical_min, max - min, caps->logical_max - caps->logical_min ); }
-static LONG scale_axis_value( ULONG value, const HIDP_VALUE_CAPS *caps, struct extra_caps *extra ) +static LONG scale_axis_value( ULONG value, struct hid_value_caps *caps, struct extra_caps *extra ) { LONG tmp = sign_extend( value, caps ), log_ctr, log_min, log_max, phy_ctr, phy_min, phy_max; - ULONG bit_max = (1 << caps->BitSize) - 1; + ULONG bit_max = (1 << caps->bit_size) - 1;
- log_min = caps->LogicalMin; - log_max = caps->LogicalMax; - phy_min = caps->PhysicalMin; - phy_max = caps->PhysicalMax; + log_min = caps->logical_min; + log_max = caps->logical_max; + phy_min = caps->physical_min; + phy_max = caps->physical_max; /* xinput HID gamepad have bogus logical value range, let's use the bit range instead */ if (log_min == 0 && log_max == -1) log_max = bit_max;
@@ -998,27 +916,27 @@ static LONG scale_axis_value( ULONG value, const HIDP_VALUE_CAPS *caps, struct e return phy_min + MulDiv( tmp - log_min, phy_max - phy_min, log_max - log_min ); }
-static BOOL read_device_state_value( struct hid_joystick *impl, struct hid_caps *caps, +static BOOL read_device_state_value( struct hid_joystick *impl, struct hid_value_caps *caps, DIDEVICEOBJECTINSTANCEW *instance, void *data ) { + struct hid_preparsed_data *preparsed = (struct hid_preparsed_data *)impl->preparsed; IDirectInputDevice8W *iface = &impl->base.IDirectInputDevice8W_iface; ULONG logical_value, report_len = impl->caps.InputReportByteLength; struct parse_device_state_params *params = data; char *report_buf = impl->input_report_buf; - HIDP_VALUE_CAPS *value_caps = caps->value; struct extra_caps *extra; LONG old_value, value; NTSTATUS status;
if (instance->wReportId != impl->device_state_report_id) return DIENUM_CONTINUE;
- extra = impl->input_extra_caps + (value_caps - impl->input_value_caps); + extra = impl->input_extra_caps + (caps - HID_INPUT_VALUE_CAPS( preparsed )); status = HidP_GetUsageValue( HidP_Input, instance->wUsagePage, 0, instance->wUsage, &logical_value, impl->preparsed, report_buf, report_len ); if (status != HIDP_STATUS_SUCCESS) WARN( "HidP_GetUsageValue %04x:%04x returned %#x\n", instance->wUsagePage, instance->wUsage, status ); - if (instance->dwType & DIDFT_AXIS) value = scale_axis_value( logical_value, value_caps, extra ); - else value = scale_value( logical_value, value_caps, value_caps->PhysicalMin, value_caps->PhysicalMax ); + if (instance->dwType & DIDFT_AXIS) value = scale_axis_value( logical_value, caps, extra ); + else value = scale_value( logical_value, caps, caps->physical_min, caps->physical_max );
old_value = *(LONG *)(params->old_state + instance->dwOfs); *(LONG *)(impl->device_state + instance->dwOfs) = value; @@ -1353,7 +1271,7 @@ static HRESULT hid_joystick_enum_device( DWORD type, DWORD flags, DIDEVICEINSTAN return DI_OK; }
-static BOOL init_objects( struct hid_joystick *impl, struct hid_caps *caps, +static BOOL init_objects( struct hid_joystick *impl, struct hid_value_caps *caps, DIDEVICEOBJECTINSTANCEW *instance, void *data ) { DIDATAFORMAT *format = impl->base.data_format.wine_df; @@ -1377,7 +1295,7 @@ static BOOL init_objects( struct hid_joystick *impl, struct hid_caps *caps, return DIENUM_CONTINUE; }
-static BOOL init_data_format( struct hid_joystick *impl, struct hid_caps *caps, +static BOOL init_data_format( struct hid_joystick *impl, struct hid_value_caps *caps, DIDEVICEOBJECTINSTANCEW *instance, void *data ) { DIDATAFORMAT *format = impl->base.data_format.wine_df; @@ -1427,15 +1345,12 @@ static HRESULT hid_joystick_create_device( IDirectInputImpl *dinput, const GUID }, }; HIDD_ATTRIBUTES attrs = {.Size = sizeof(attrs)}; - HIDP_LINK_COLLECTION_NODE *nodes; + struct hid_preparsed_data *preparsed; struct hid_joystick *impl = NULL; struct extra_caps *extra; DIDATAFORMAT *format = NULL; - HIDP_BUTTON_CAPS *buttons; - HIDP_VALUE_CAPS *values; USAGE_AND_PAGE *usages; DWORD size, index; - NTSTATUS status; char *buffer; HRESULT hr;
@@ -1469,16 +1384,9 @@ static HRESULT hid_joystick_create_device( IDirectInputImpl *dinput, const GUID impl->dev_caps.dwFlags = DIDC_ATTACHED | DIDC_EMULATED; impl->dev_caps.dwDevType = instance.dwDevType;
- size = impl->caps.NumberLinkCollectionNodes * sizeof(HIDP_LINK_COLLECTION_NODE); - if (!(nodes = HeapAlloc( GetProcessHeap(), 0, size ))) goto failed; - impl->collection_nodes = nodes; - size = impl->caps.NumberInputButtonCaps * sizeof(HIDP_BUTTON_CAPS); - if (!(buttons = HeapAlloc( GetProcessHeap(), 0, size ))) goto failed; - impl->input_button_caps = buttons; - size = impl->caps.NumberInputValueCaps * sizeof(HIDP_VALUE_CAPS); - if (!(values = HeapAlloc( GetProcessHeap(), 0, size ))) goto failed; - impl->input_value_caps = values; - size = impl->caps.NumberInputValueCaps * sizeof(struct extra_caps); + preparsed = (struct hid_preparsed_data *)impl->preparsed; + + size = preparsed->input_caps_count * sizeof(struct extra_caps); if (!(extra = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size ))) goto failed; impl->input_extra_caps = extra;
@@ -1490,17 +1398,6 @@ static HRESULT hid_joystick_create_device( IDirectInputImpl *dinput, const GUID if (!(usages = HeapAlloc( GetProcessHeap(), 0, size ))) goto failed; impl->usages_buf = usages;
- size = impl->caps.NumberLinkCollectionNodes; - status = HidP_GetLinkCollectionNodes( nodes, &size, impl->preparsed ); - if (status != HIDP_STATUS_SUCCESS) goto failed; - impl->caps.NumberLinkCollectionNodes = size; - status = HidP_GetButtonCaps( HidP_Input, impl->input_button_caps, - &impl->caps.NumberInputButtonCaps, impl->preparsed ); - if (status != HIDP_STATUS_SUCCESS && status != HIDP_STATUS_USAGE_NOT_FOUND) goto failed; - status = HidP_GetValueCaps( HidP_Input, impl->input_value_caps, - &impl->caps.NumberInputValueCaps, impl->preparsed ); - if (status != HIDP_STATUS_SUCCESS && status != HIDP_STATUS_USAGE_NOT_FOUND) goto failed; - enum_objects( impl, &filter, DIDFT_ALL, init_objects, NULL );
format = impl->base.data_format.wine_df;
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/dinput/joystick_hid.c | 35 ++++++++++++++++++++++++++++++++++- dlls/dinput8/tests/hid.c | 18 ++++-------------- 2 files changed, 38 insertions(+), 15 deletions(-)
diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c index 4d6d53b588e..526cfaeb456 100644 --- a/dlls/dinput/joystick_hid.c +++ b/dlls/dinput/joystick_hid.c @@ -175,7 +175,7 @@ static void set_axis_type( DIDEVICEOBJECTINSTANCEW *instance, BOOL *seen, DWORD static BOOL enum_objects( struct hid_joystick *impl, const DIPROPHEADER *header, DWORD flags, enum_object_callback callback, void *data ) { - DWORD collection = 0, axis = 0, button = 0, pov = 0, value_ofs = 0, button_ofs = 0, i, j; + DWORD collection = 0, object = 0, axis = 0, button = 0, pov = 0, value_ofs = 0, button_ofs = 0, i, j; struct hid_preparsed_data *preparsed = (struct hid_preparsed_data *)impl->preparsed; DIDEVICEOBJECTINSTANCEW instance = {.dwSize = sizeof(DIDEVICEOBJECTINSTANCEW)}; DIDATAFORMAT *format = impl->base.data_format.wine_df; @@ -220,6 +220,7 @@ static BOOL enum_objects( struct hid_joystick *impl, const DIPROPHEADER *header, instance.guidType = *object_usage_to_guid( instance.wUsagePage, instance.wUsage ); instance.wReportId = caps->report_id; instance.wCollectionNumber = caps->link_collection; + object++;
switch (instance.wUsage) { @@ -306,12 +307,44 @@ static BOOL enum_objects( struct hid_joystick *impl, const DIPROPHEADER *header, instance.wCollectionNumber = caps->link_collection; ret = enum_object( impl, &filter, flags, callback, caps, &instance, data ); if (ret != DIENUM_CONTINUE) return ret; + object++; } }
button_ofs += caps->usage_max - caps->usage_min + 1; }
+ for (caps = HID_OUTPUT_VALUE_CAPS( preparsed ), caps_end = caps + preparsed->output_caps_count; + caps != caps_end; ++caps) + { + if (!caps->usage_page) continue; + + if (caps->usage_page >= HID_USAGE_PAGE_VENDOR_DEFINED_BEGIN) + { + TRACE( "Ignoring output caps %s, vendor specific.\n", debugstr_hid_value_caps( caps ) ); + if (caps->flags & HID_VALUE_CAPS_IS_BUTTON) button_ofs += caps->usage_max - caps->usage_min + 1; + else value_ofs += (caps->usage_max - caps->usage_min + 1) * sizeof(LONG); + } + else for (j = caps->usage_min; j <= caps->usage_max; ++j) + { + if (caps->flags & HID_VALUE_CAPS_IS_BUTTON) instance.dwOfs = button_ofs; + else instance.dwOfs = value_ofs; + + instance.dwType = DIDFT_NODATA | DIDFT_MAKEINSTANCE( object++ ) | DIDFT_OUTPUT; + instance.dwFlags = 0x80008000; + instance.wUsagePage = caps->usage_page; + instance.wUsage = j; + instance.guidType = GUID_Unknown; + instance.wReportId = caps->report_id; + instance.wCollectionNumber = caps->link_collection; + ret = enum_object( impl, &filter, flags, callback, caps, &instance, data ); + if (ret != DIENUM_CONTINUE) return ret; + + if (caps->flags & HID_VALUE_CAPS_IS_BUTTON) button_ofs++; + else value_ofs += sizeof(LONG); + } + } + for (node = HID_COLLECTION_NODES( preparsed ), node_end = node + preparsed->number_link_collection_nodes; node != node_end; ++node) { diff --git a/dlls/dinput8/tests/hid.c b/dlls/dinput8/tests/hid.c index bd84bac0aca..8f6b568eae9 100644 --- a/dlls/dinput8/tests/hid.c +++ b/dlls/dinput8/tests/hid.c @@ -3288,13 +3288,9 @@ static BOOL CALLBACK find_test_device( const DIDEVICEINSTANCEW *devinst, void *c
struct check_objects_todos { - BOOL ofs; BOOL type; BOOL flags; - BOOL collection_number; - BOOL usage_page; BOOL usage; - BOOL report_id; };
struct check_objects_params @@ -3319,7 +3315,6 @@ static BOOL CALLBACK check_objects( const DIDEVICEOBJECTINSTANCEW *obj, void *ar
check_member( *obj, *exp, "%u", dwSize ); check_member_guid( *obj, *exp, guidType ); - todo_wine_if( todo->ofs ) check_member( *obj, *exp, "%#x", dwOfs ); todo_wine_if( todo->type ) check_member( *obj, *exp, "%#x", dwType ); @@ -3328,16 +3323,13 @@ static BOOL CALLBACK check_objects( const DIDEVICEOBJECTINSTANCEW *obj, void *ar if (!localized) todo_wine check_member_wstr( *obj, *exp, tszName ); check_member( *obj, *exp, "%u", dwFFMaxForce ); check_member( *obj, *exp, "%u", dwFFForceResolution ); - todo_wine_if( todo->collection_number ) check_member( *obj, *exp, "%u", wCollectionNumber ); check_member( *obj, *exp, "%u", wDesignatorIndex ); - todo_wine_if( todo->usage_page ) check_member( *obj, *exp, "%#04x", wUsagePage ); todo_wine_if( todo->usage ) check_member( *obj, *exp, "%#04x", wUsage ); check_member( *obj, *exp, "%#04x", dwDimension ); check_member( *obj, *exp, "%#04x", wExponent ); - todo_wine_if( todo->report_id ) check_member( *obj, *exp, "%u", wReportId );
winetest_pop_context(); @@ -5198,11 +5190,10 @@ static void test_force_feedback_joystick( void ) {}, {.type = TRUE, .flags = TRUE}, {.type = TRUE, .flags = TRUE}, - {.ofs = TRUE, .type = TRUE, .flags = TRUE, .collection_number = TRUE, .usage_page = TRUE, .usage = TRUE, .report_id = TRUE}, - {.ofs = TRUE, .type = TRUE, .flags = TRUE, .collection_number = TRUE, .usage_page = TRUE, .usage = TRUE, .report_id = TRUE}, - {.ofs = TRUE, .type = TRUE, .flags = TRUE, .collection_number = TRUE, .usage = TRUE, .report_id = TRUE}, - {.ofs = TRUE, .type = TRUE, .flags = TRUE, .collection_number = TRUE, .usage = TRUE, .report_id = TRUE}, - {.ofs = TRUE, .type = TRUE, .flags = TRUE, .usage = TRUE, .report_id = TRUE}, + {}, + {.usage = TRUE}, + {}, + {.usage = TRUE}, };
struct check_objects_params check_objects_params = @@ -5302,7 +5293,6 @@ static void test_force_feedback_joystick( void )
hr = IDirectInputDevice8_EnumObjects( device, check_objects, &check_objects_params, DIDFT_ALL ); ok( hr == DI_OK, "IDirectInputDevice8_EnumObjects returned %#x\n", hr ); - todo_wine ok( check_objects_params.index >= check_objects_params.expect_count, "missing %u objects\n", check_objects_params.expect_count - check_objects_params.index );
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=99057
Your paranoid android.
=== w7u_el (32 bit report) ===
dinput8: hid: Timeout
On 9/29/21 11:21 AM, Marvin wrote:
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=99057
Your paranoid android.
=== w7u_el (32 bit report) ===
dinput8: hid: Timeout
I think somehow the device initialization is very slow on this VM, and this new test makes it take even more time. Sometimes it passes, like here:
https://testbot.winehq.org/JobDetails.pl?Key=99045
The test isn't doing anything on W7, as the device doesn't even appear as a dinput device there, so I guess we could instead bail out early of all tests.
I'll send a patch to do that later but I don't think it's worth re-sending this series just for that.
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/dinput/joystick_hid.c | 22 +++++++++++++++++++++- dlls/dinput8/tests/hid.c | 6 ------ 2 files changed, 21 insertions(+), 7 deletions(-)
diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c index 526cfaeb456..7cb2c223121 100644 --- a/dlls/dinput/joystick_hid.c +++ b/dlls/dinput/joystick_hid.c @@ -178,10 +178,10 @@ static BOOL enum_objects( struct hid_joystick *impl, const DIPROPHEADER *header, DWORD collection = 0, object = 0, axis = 0, button = 0, pov = 0, value_ofs = 0, button_ofs = 0, i, j; struct hid_preparsed_data *preparsed = (struct hid_preparsed_data *)impl->preparsed; DIDEVICEOBJECTINSTANCEW instance = {.dwSize = sizeof(DIDEVICEOBJECTINSTANCEW)}; + struct hid_value_caps *caps, *caps_end, *nary, *nary_end; DIDATAFORMAT *format = impl->base.data_format.wine_df; int *offsets = impl->base.data_format.offsets; struct hid_collection_node *node, *node_end; - struct hid_value_caps *caps, *caps_end; DIPROPHEADER filter = *header; BOOL ret, seen_axis[6] = {0};
@@ -325,6 +325,26 @@ static BOOL enum_objects( struct hid_joystick *impl, const DIPROPHEADER *header, if (caps->flags & HID_VALUE_CAPS_IS_BUTTON) button_ofs += caps->usage_max - caps->usage_min + 1; else value_ofs += (caps->usage_max - caps->usage_min + 1) * sizeof(LONG); } + else if (caps->flags & HID_VALUE_CAPS_ARRAY_HAS_MORE) + { + for (nary_end = caps - 1; caps != caps_end; caps++) + if (!(caps->flags & HID_VALUE_CAPS_ARRAY_HAS_MORE)) break; + + for (nary = caps; nary != nary_end; nary--) + { + instance.dwOfs = button_ofs; + instance.dwType = DIDFT_NODATA | DIDFT_MAKEINSTANCE( object++ ) | DIDFT_OUTPUT; + instance.dwFlags = 0x80008000; + instance.wUsagePage = nary->usage_page; + instance.wUsage = nary->usage_min; + instance.guidType = GUID_Unknown; + instance.wReportId = nary->report_id; + instance.wCollectionNumber = nary->link_collection; + ret = enum_object( impl, &filter, flags, callback, nary, &instance, data ); + if (ret != DIENUM_CONTINUE) return ret; + button_ofs++; + } + } else for (j = caps->usage_min; j <= caps->usage_max; ++j) { if (caps->flags & HID_VALUE_CAPS_IS_BUTTON) instance.dwOfs = button_ofs; diff --git a/dlls/dinput8/tests/hid.c b/dlls/dinput8/tests/hid.c index 8f6b568eae9..ce2a3792593 100644 --- a/dlls/dinput8/tests/hid.c +++ b/dlls/dinput8/tests/hid.c @@ -3290,7 +3290,6 @@ struct check_objects_todos { BOOL type; BOOL flags; - BOOL usage; };
struct check_objects_params @@ -3326,7 +3325,6 @@ static BOOL CALLBACK check_objects( const DIDEVICEOBJECTINSTANCEW *obj, void *ar check_member( *obj, *exp, "%u", wCollectionNumber ); check_member( *obj, *exp, "%u", wDesignatorIndex ); check_member( *obj, *exp, "%#04x", wUsagePage ); - todo_wine_if( todo->usage ) check_member( *obj, *exp, "%#04x", wUsage ); check_member( *obj, *exp, "%#04x", dwDimension ); check_member( *obj, *exp, "%#04x", wExponent ); @@ -5190,10 +5188,6 @@ static void test_force_feedback_joystick( void ) {}, {.type = TRUE, .flags = TRUE}, {.type = TRUE, .flags = TRUE}, - {}, - {.usage = TRUE}, - {}, - {.usage = TRUE}, };
struct check_objects_params check_objects_params =
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=99058
Your paranoid android.
=== w7u_el (32 bit report) ===
dinput8: hid: Timeout
Signed-off-by: Rémi Bernon rbernon@codeweavers.com --- dlls/dinput/joystick_hid.c | 120 +++++++++++++------------------------ 1 file changed, 41 insertions(+), 79 deletions(-)
diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c index 7cb2c223121..7c4b637d018 100644 --- a/dlls/dinput/joystick_hid.c +++ b/dlls/dinput/joystick_hid.c @@ -205,82 +205,47 @@ static BOOL enum_objects( struct hid_joystick *impl, const DIPROPHEADER *header, if (caps->flags & HID_VALUE_CAPS_IS_BUTTON) continue;
if (caps->usage_page >= HID_USAGE_PAGE_VENDOR_DEFINED_BEGIN) + { TRACE( "Ignoring input value %s, vendor specific.\n", debugstr_hid_value_caps( caps ) ); - else if (caps->flags & HID_VALUE_CAPS_IS_RANGE) - FIXME( "Ignoring input value %s, usage range not implemented.\n", debugstr_hid_value_caps( caps ) ); - else if (caps->report_count > 1) - FIXME( "Ignoring input value %s, array not implemented.\n", debugstr_hid_value_caps( caps ) ); - else if (caps->usage_page != HID_USAGE_PAGE_GENERIC) - TRACE( "Ignoring input value %s, usage page not implemented.\n", debugstr_hid_value_caps( caps ) ); - else + value_ofs += (caps->usage_max - caps->usage_min + 1) * sizeof(LONG); + } + else for (j = caps->usage_min; j <= caps->usage_max; ++j) { instance.dwOfs = value_ofs; - instance.wUsagePage = caps->usage_page; - instance.wUsage = caps->usage_min; - instance.guidType = *object_usage_to_guid( instance.wUsagePage, instance.wUsage ); - instance.wReportId = caps->report_id; - instance.wCollectionNumber = caps->link_collection; - object++; - - switch (instance.wUsage) + switch (MAKELONG(j, caps->usage_page)) { - case HID_USAGE_GENERIC_X: - set_axis_type( &instance, seen_axis, 0, &axis ); + case MAKELONG(HID_USAGE_GENERIC_X, HID_USAGE_PAGE_GENERIC): + case MAKELONG(HID_USAGE_GENERIC_Y, HID_USAGE_PAGE_GENERIC): + case MAKELONG(HID_USAGE_GENERIC_Z, HID_USAGE_PAGE_GENERIC): + case MAKELONG(HID_USAGE_GENERIC_RX, HID_USAGE_PAGE_GENERIC): + case MAKELONG(HID_USAGE_GENERIC_RY, HID_USAGE_PAGE_GENERIC): + case MAKELONG(HID_USAGE_GENERIC_RZ, HID_USAGE_PAGE_GENERIC): + set_axis_type( &instance, seen_axis, j - HID_USAGE_GENERIC_X, &axis ); instance.dwFlags = DIDOI_ASPECTPOSITION; - ret = enum_object( impl, &filter, flags, callback, caps, &instance, data ); - if (ret != DIENUM_CONTINUE) return ret; break; - case HID_USAGE_GENERIC_Y: - set_axis_type( &instance, seen_axis, 1, &axis ); - instance.dwFlags = DIDOI_ASPECTPOSITION; - ret = enum_object( impl, &filter, flags, callback, caps, &instance, data ); - if (ret != DIENUM_CONTINUE) return ret; - break; - case HID_USAGE_GENERIC_Z: - case HID_USAGE_GENERIC_WHEEL: + case MAKELONG(HID_USAGE_GENERIC_WHEEL, HID_USAGE_PAGE_GENERIC): set_axis_type( &instance, seen_axis, 2, &axis ); instance.dwFlags = DIDOI_ASPECTPOSITION; - ret = enum_object( impl, &filter, flags, callback, caps, &instance, data ); - if (ret != DIENUM_CONTINUE) return ret; break; - case HID_USAGE_GENERIC_RX: - set_axis_type( &instance, seen_axis, 3, &axis ); - instance.dwFlags = DIDOI_ASPECTPOSITION; - ret = enum_object( impl, &filter, flags, callback, caps, &instance, data ); - if (ret != DIENUM_CONTINUE) return ret; - break; - case HID_USAGE_GENERIC_RY: - set_axis_type( &instance, seen_axis, 4, &axis ); - instance.dwFlags = DIDOI_ASPECTPOSITION; - ret = enum_object( impl, &filter, flags, callback, caps, &instance, data ); - if (ret != DIENUM_CONTINUE) return ret; - break; - case HID_USAGE_GENERIC_RZ: - set_axis_type( &instance, seen_axis, 5, &axis ); - instance.dwFlags = DIDOI_ASPECTPOSITION; - ret = enum_object( impl, &filter, flags, callback, caps, &instance, data ); - if (ret != DIENUM_CONTINUE) return ret; - break; - case HID_USAGE_GENERIC_DIAL: - case HID_USAGE_GENERIC_SLIDER: - instance.dwType = DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 6 + axis++ ); - instance.dwFlags = DIDOI_ASPECTPOSITION; - ret = enum_object( impl, &filter, flags, callback, caps, &instance, data ); - if (ret != DIENUM_CONTINUE) return ret; - break; - case HID_USAGE_GENERIC_HATSWITCH: + case MAKELONG(HID_USAGE_GENERIC_HATSWITCH, HID_USAGE_PAGE_GENERIC): instance.dwType = DIDFT_POV | DIDFT_MAKEINSTANCE( pov++ ); instance.dwFlags = 0; - ret = enum_object( impl, &filter, flags, callback, caps, &instance, data ); - if (ret != DIENUM_CONTINUE) return ret; break; default: - FIXME( "Ignoring input value %s, usage not implemented.\n", debugstr_hid_value_caps( caps ) ); + instance.dwType = DIDFT_ABSAXIS | DIDFT_MAKEINSTANCE( 6 + axis++ ); + instance.dwFlags = DIDOI_ASPECTPOSITION; break; } + instance.wUsagePage = caps->usage_page; + instance.wUsage = j; + instance.guidType = *object_usage_to_guid( instance.wUsagePage, instance.wUsage ); + instance.wReportId = caps->report_id; + instance.wCollectionNumber = caps->link_collection; + ret = enum_object( impl, &filter, flags, callback, caps, &instance, data ); + if (ret != DIENUM_CONTINUE) return ret; + value_ofs += sizeof(LONG); + object++; } - - value_ofs += sizeof(LONG); }
for (caps = HID_INPUT_VALUE_CAPS( preparsed ), caps_end = caps + preparsed->input_caps_count; @@ -290,28 +255,25 @@ static BOOL enum_objects( struct hid_joystick *impl, const DIPROPHEADER *header, if (!(caps->flags & HID_VALUE_CAPS_IS_BUTTON)) continue;
if (caps->usage_page >= HID_USAGE_PAGE_VENDOR_DEFINED_BEGIN) + { TRACE( "Ignoring input button %s, vendor specific.\n", debugstr_hid_value_caps( caps ) ); - else if (caps->usage_page != HID_USAGE_PAGE_BUTTON) - TRACE( "Ignoring input button %s, usage page not implemented.\n", debugstr_hid_value_caps( caps ) ); - else + button_ofs += caps->usage_max - caps->usage_min + 1; + } + else for (j = caps->usage_min; j <= caps->usage_max; ++j) { - for (j = caps->usage_min; j <= caps->usage_max; ++j) - { - instance.dwOfs = button_ofs + (j - caps->usage_min); - instance.dwType = DIDFT_PSHBUTTON | DIDFT_MAKEINSTANCE( button++ ); - instance.dwFlags = 0; - instance.wUsagePage = caps->usage_page; - instance.wUsage = j; - instance.guidType = *object_usage_to_guid( instance.wUsagePage, instance.wUsage ); - instance.wReportId = caps->report_id; - instance.wCollectionNumber = caps->link_collection; - ret = enum_object( impl, &filter, flags, callback, caps, &instance, data ); - if (ret != DIENUM_CONTINUE) return ret; - object++; - } + instance.dwOfs = button_ofs; + instance.dwType = DIDFT_PSHBUTTON | DIDFT_MAKEINSTANCE( button++ ); + instance.dwFlags = 0; + instance.wUsagePage = caps->usage_page; + instance.wUsage = j; + instance.guidType = *object_usage_to_guid( instance.wUsagePage, instance.wUsage ); + instance.wReportId = caps->report_id; + instance.wCollectionNumber = caps->link_collection; + ret = enum_object( impl, &filter, flags, callback, caps, &instance, data ); + if (ret != DIENUM_CONTINUE) return ret; + button_ofs++; + object++; } - - button_ofs += caps->usage_max - caps->usage_min + 1; }
for (caps = HID_OUTPUT_VALUE_CAPS( preparsed ), caps_end = caps + preparsed->output_caps_count;