From: Rémi Bernon rbernon@codeweavers.com
--- dlls/dinput/device.c | 139 +++++++++++++++++----------------- dlls/dinput/tests/joystick8.c | 79 ++++--------------- 2 files changed, 84 insertions(+), 134 deletions(-)
diff --git a/dlls/dinput/device.c b/dlls/dinput/device.c index c001d1ef29a..77051eaa620 100644 --- a/dlls/dinput/device.c +++ b/dlls/dinput/device.c @@ -314,31 +314,23 @@ static int id_to_offset( struct dinput_device *impl, int id ) return -1; }
-static DWORD semantic_to_obj_id( struct dinput_device *This, DWORD dwSemantic ) +static BOOL object_matches_semantics( const DIOBJECTDATAFORMAT *object, DWORD semantic, BOOL exact ) { - DWORD type = (0x0000ff00 & dwSemantic) >> 8; - BOOL byofs = (dwSemantic & 0x80000000) != 0; - DWORD value = (dwSemantic & 0x000000ff); - BOOL found = FALSE; - DWORD instance; - int i; + DWORD value = semantic & 0xff, axis = (semantic >> 15) & 3, type;
- for (i = 0; i < This->device_format.dwNumObjs && !found; i++) + switch (semantic & 0x700) { - LPDIOBJECTDATAFORMAT odf = dataformat_to_odf( &This->device_format, i ); - - if (byofs && value != odf->dwOfs) continue; - if (!byofs && value != DIDFT_GETINSTANCE(odf->dwType)) continue; - instance = DIDFT_GETINSTANCE(odf->dwType); - found = TRUE; + case 0x200: type = DIDFT_ABSAXIS; break; + case 0x300: type = DIDFT_RELAXIS; break; + case 0x400: type = DIDFT_BUTTON; break; + case 0x600: type = DIDFT_POV; break; + default: return FALSE; }
- if (!found) return 0; - - if (type & DIDFT_AXIS) type = DIDFT_RELAXIS; - if (type & DIDFT_BUTTON) type = DIDFT_PSHBUTTON; - - return type | (0x0000ff00 & (instance << 8)); + if (!(DIDFT_GETTYPE( object->dwType ) & type)) return FALSE; + if ((semantic & 0xf0000000) == 0x80000000) return object->dwOfs == value; + if (axis && (axis - 1) != DIDFT_GETINSTANCE( object->dwType )) return FALSE; + return !exact || !value || value == DIDFT_GETINSTANCE( object->dwType ) + 1; }
/* @@ -1857,34 +1849,34 @@ static HRESULT WINAPI dinput_device_BuildActionMap( IDirectInputDevice8W *iface, const WCHAR *username, DWORD flags ) { struct dinput_device *impl = impl_from_IDirectInputDevice8W( iface ); - BOOL load_success = FALSE, has_actions = FALSE; - DWORD genre, username_len = MAX_PATH; + DIOBJECTDATAFORMAT *object, *object_end; + DIACTIONW *action, *action_end; + DWORD i, username_len = MAX_PATH; WCHAR username_buf[MAX_PATH]; - const DIDATAFORMAT *df; - DWORD devMask; - int i; + BOOL load_success = FALSE; + BOOL *mapped;
FIXME( "iface %p, format %p, username %s, flags %#lx stub!\n", iface, format, debugstr_w(username), flags );
if (!format) return DIERR_INVALIDPARAM; + if (flags != DIDBAM_DEFAULT && flags != DIDBAM_PRESERVE && + flags != DIDBAM_INITIALIZE && flags != DIDBAM_HWDEFAULTS) + return DIERR_INVALIDPARAM; + if (format->dwNumActions * 4 != format->dwDataSize) + return DIERR_INVALIDPARAM;
- switch (GET_DIDEVICE_TYPE( impl->instance.dwDevType )) + action_end = format->rgoAction + format->dwNumActions; + for (action = format->rgoAction; action < action_end; action++) { - case DIDEVTYPE_KEYBOARD: - case DI8DEVTYPE_KEYBOARD: - devMask = DIKEYBOARD_MASK; - df = &c_dfDIKeyboard; - break; - case DIDEVTYPE_MOUSE: - case DI8DEVTYPE_MOUSE: - devMask = DIMOUSE_MASK; - df = &c_dfDIMouse2; - break; - default: - devMask = DIGENRE_ANY; - df = &impl->device_format; - break; + if (!action->dwSemantic) return DIERR_INVALIDPARAM; + if (action->dwFlags & DIA_APPMAPPED) action->dwHow = DIAH_APPREQUESTED; + else if (action->dwFlags & DIA_APPNOMAP) continue; + else + { + action->dwHow = 0; + action->guidInstance = GUID_NULL; + } }
/* Unless asked the contrary by these flags, try to load a previous mapping */ @@ -1897,46 +1889,51 @@ static HRESULT WINAPI dinput_device_BuildActionMap( IDirectInputDevice8W *iface, }
if (load_success) return DI_OK; + if (!(mapped = calloc( impl->device_format.dwNumObjs, sizeof(*mapped) ))) return DIERR_OUTOFMEMORY;
- for (i = 0; i < format->dwNumActions; i++) + action_end = format->rgoAction + format->dwNumActions; + for (action = format->rgoAction; action < action_end; action++) { - /* Don't touch a user configured action */ - if (format->rgoAction[i].dwHow == DIAH_USERCONFIG) continue; + if (action->dwHow || (action->dwFlags & DIA_APPNOMAP)) continue; /* already mapped */ + if (action->dwSemantic & 0x4000) continue; /* priority 1 */
- genre = format->rgoAction[i].dwSemantic & DIGENRE_ANY; - if (devMask == genre || (devMask == DIGENRE_ANY && genre != DIMOUSE_MASK && genre != DIKEYBOARD_MASK)) + object_end = impl->device_format.rgodf + impl->device_format.dwNumObjs; + for (object = impl->device_format.rgodf; object < object_end; object++) { - DWORD obj_id = semantic_to_obj_id( impl, format->rgoAction[i].dwSemantic ); - DWORD type = DIDFT_GETTYPE( obj_id ); - DWORD inst = DIDFT_GETINSTANCE( obj_id ); - - LPDIOBJECTDATAFORMAT odf; - - if (type == DIDFT_PSHBUTTON) type = DIDFT_BUTTON; - if (type == DIDFT_RELAXIS) type = DIDFT_AXIS; + if (mapped[object - impl->device_format.rgodf]) continue; + if (!object_matches_semantics( object, action->dwSemantic, TRUE )) continue; + if ((action->dwFlags & DIA_FORCEFEEDBACK) && !(object->dwType & DIDFT_FFACTUATOR)) continue; + action->dwObjID = object->dwType; + action->guidInstance = impl->guid; + action->dwHow = DIAH_DEFAULT; + mapped[object - impl->device_format.rgodf] = TRUE; + break; + } + }
- /* Make sure the object exists */ - odf = dataformat_to_odf_by_type( df, inst, type ); + for (action = format->rgoAction; action < action_end; action++) + { + if (action->dwHow || (action->dwFlags & DIA_APPNOMAP)) continue; /* already mapped */ + if (!(action->dwSemantic & 0x4000)) continue; /* priority 2 */
- if (odf != NULL) - { - format->rgoAction[i].dwObjID = obj_id; - format->rgoAction[i].guidInstance = impl->guid; - format->rgoAction[i].dwHow = DIAH_DEFAULT; - has_actions = TRUE; - } - } - else if (!(flags & DIDBAM_PRESERVE)) + object_end = impl->device_format.rgodf + impl->device_format.dwNumObjs; + for (object = impl->device_format.rgodf; object < object_end; object++) { - /* We must clear action data belonging to other devices */ - memset( &format->rgoAction[i].guidInstance, 0, sizeof(GUID) ); - format->rgoAction[i].dwHow = DIAH_UNMAPPED; + if (mapped[object - impl->device_format.rgodf]) continue; + if (!object_matches_semantics( object, action->dwSemantic, FALSE )) continue; + if ((action->dwFlags & DIA_FORCEFEEDBACK) && !(object->dwType & DIDFT_FFACTUATOR)) continue; + action->dwObjID = object->dwType; + action->guidInstance = impl->guid; + action->dwHow = DIAH_DEFAULT; + mapped[object - impl->device_format.rgodf] = TRUE; + break; } }
- if (!has_actions) return DI_NOEFFECT; - if (flags & (DIDBAM_DEFAULT|DIDBAM_PRESERVE|DIDBAM_INITIALIZE|DIDBAM_HWDEFAULTS)) - FIXME( "Unimplemented flags %#lx\n", flags ); + for (i = 0; i < impl->device_format.dwNumObjs; ++i) if (mapped[i]) break; + free( mapped ); + + if (i == impl->device_format.dwNumObjs) return DI_NOEFFECT; return DI_OK; }
@@ -2008,7 +2005,7 @@ static HRESULT WINAPI dinput_device_SetActionMap( IDirectInputDevice8W *iface, D if (type == DIDFT_PSHBUTTON) type = DIDFT_BUTTON; if (type == DIDFT_RELAXIS) type = DIDFT_AXIS;
- obj = dataformat_to_odf_by_type( df, inst, type ); + if (!(obj = dataformat_to_odf_by_type( df, inst, type ))) continue;
memcpy( &obj_df[action], obj, df->dwObjSize );
diff --git a/dlls/dinput/tests/joystick8.c b/dlls/dinput/tests/joystick8.c index 70be8f76e1a..5295ee6c169 100644 --- a/dlls/dinput/tests/joystick8.c +++ b/dlls/dinput/tests/joystick8.c @@ -208,16 +208,8 @@ static BOOL CALLBACK check_no_created_effect_objects( IDirectInputEffect *effect return DIENUM_CONTINUE; }
-struct diaction_todo -{ - BOOL instance; - BOOL objid; - BOOL how; -}; - -#define check_diactionw( a, b ) check_diactionw_( __LINE__, a, b, NULL ) -static void check_diactionw_( int line, const DIACTIONW *actual, const DIACTIONW *expected, - const struct diaction_todo *todos ) +#define check_diactionw( a, b ) check_diactionw_( __LINE__, a, b ) +static void check_diactionw_( int line, const DIACTIONW *actual, const DIACTIONW *expected ) { check_member_( __FILE__, line, *actual, *expected, "%#Ix", uAppData ); check_member_( __FILE__, line, *actual, *expected, "%#lx", dwSemantic ); @@ -226,17 +218,13 @@ static void check_diactionw_( int line, const DIACTIONW *actual, const DIACTIONW check_member_wstr_( __FILE__, line, *actual, *expected, lptszActionName ); else check_member_( __FILE__, line, *actual, *expected, "%p", lptszActionName ); - todo_wine_if( todos->instance ) check_member_guid_( __FILE__, line, *actual, *expected, guidInstance ); - todo_wine_if( todos->objid ) check_member_( __FILE__, line, *actual, *expected, "%#lx", dwObjID ); - todo_wine_if( todos->how ) check_member_( __FILE__, line, *actual, *expected, "%#lx", dwHow ); }
-#define check_diactionformatw( a, b ) check_diactionformatw_( __LINE__, a, b, NULL ) -static void check_diactionformatw_( int line, const DIACTIONFORMATW *actual, const DIACTIONFORMATW *expected, - const struct diaction_todo *todos ) +#define check_diactionformatw( a, b ) check_diactionformatw_( __LINE__, a, b ) +static void check_diactionformatw_( int line, const DIACTIONFORMATW *actual, const DIACTIONFORMATW *expected ) { DWORD i; check_member_( __FILE__, line, *actual, *expected, "%#lx", dwSize ); @@ -246,7 +234,7 @@ static void check_diactionformatw_( int line, const DIACTIONFORMATW *actual, con for (i = 0; i < min( actual->dwNumActions, expected->dwNumActions ); ++i) { winetest_push_context( "action[%lu]", i ); - check_diactionw_( line, actual->rgoAction + i, expected->rgoAction + i, todos ? todos + i : NULL ); + check_diactionw_( line, actual->rgoAction + i, expected->rgoAction + i ); winetest_pop_context(); if (expected->dwActionSize != sizeof(DIACTIONW)) break; if (actual->dwActionSize != sizeof(DIACTIONW)) break; @@ -749,29 +737,6 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e .lAxisMax = +128, .tszActionMap = L"Action Map Filled", }; - struct diaction_todo actions_todos_1 = {.instance = TRUE, .objid = TRUE, .how = TRUE}; - struct diaction_todo actions_todos_2[ARRAY_SIZE(expect_actions)] = - { - {.instance = TRUE, .objid = TRUE, .how = TRUE}, - {.instance = TRUE, .objid = TRUE, .how = TRUE}, - {0}, - {.instance = TRUE, .objid = TRUE, .how = TRUE}, - {.instance = TRUE, .objid = TRUE, .how = TRUE}, - {.instance = TRUE, .objid = TRUE, .how = TRUE}, - {.instance = TRUE, .objid = TRUE, .how = TRUE}, - {.objid = TRUE}, - }; - struct diaction_todo actions_todos_2_filled[ARRAY_SIZE(expect_actions)] = - { - {.how = TRUE}, - {0}, - {.instance = TRUE, .how = TRUE}, - {.how = TRUE}, - {.instance = TRUE, .how = TRUE}, - {.objid = TRUE, .how = TRUE}, - {.objid = TRUE}, - {.objid = TRUE, .how = TRUE}, - }; DIPROPRANGE prop_range = { .diph = @@ -827,19 +792,15 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e hr = IDirectInputDevice8_BuildActionMap( device, NULL, L"username", DIDBAM_DEFAULT ); ok( hr == DIERR_INVALIDPARAM, "BuildActionMap returned %#lx\n", hr ); hr = IDirectInputDevice8_BuildActionMap( device, &action_format_1, L"username", 0xdeadbeef ); - todo_wine ok( hr == DIERR_INVALIDPARAM, "BuildActionMap returned %#lx\n", hr ); flags = DIDBAM_HWDEFAULTS | DIDBAM_INITIALIZE; hr = IDirectInputDevice8_BuildActionMap( device, &action_format_1, L"username", flags ); - todo_wine ok( hr == DIERR_INVALIDPARAM, "BuildActionMap returned %#lx\n", hr ); flags = DIDBAM_HWDEFAULTS | DIDBAM_PRESERVE; hr = IDirectInputDevice8_BuildActionMap( device, &action_format_1, L"username", flags ); - todo_wine ok( hr == DIERR_INVALIDPARAM, "BuildActionMap returned %#lx\n", hr ); flags = DIDBAM_INITIALIZE | DIDBAM_PRESERVE; hr = IDirectInputDevice8_BuildActionMap( device, &action_format_1, L"username", flags ); - todo_wine ok( hr == DIERR_INVALIDPARAM, "BuildActionMap returned %#lx\n", hr );
hr = IDirectInputDevice8_SetActionMap( device, NULL, NULL, DIDSAM_DEFAULT ); @@ -887,13 +848,11 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e memset( actions, 0, sizeof(actions) ); actions[0] = default_actions[0]; hr = IDirectInputDevice8_BuildActionMap( device, &action_format, NULL, DIDBAM_DEFAULT ); - todo_wine ok( hr == DI_OK, "BuildActionMap returned %#lx\n", hr ); - check_diactionformatw_( __LINE__, &action_format, &expect_action_format_1, &actions_todos_1 ); + check_diactionformatw( &action_format, &expect_action_format_1 ); hr = IDirectInputDevice8_SetActionMap( device, &action_format, NULL, DIDSAM_DEFAULT ); - todo_wine ok( hr == DI_OK, "SetActionMap returned %#lx\n", hr ); - check_diactionformatw_( __LINE__, &action_format, &expect_action_format_1, &actions_todos_1 ); + check_diactionformatw( &action_format, &expect_action_format_1 );
action_format = action_format_1; @@ -901,9 +860,8 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e memset( actions, 0, sizeof(actions) ); actions[0] = default_actions[0]; hr = IDirectInputDevice8_BuildActionMap( device, &action_format, L"username", DIDBAM_DEFAULT ); - todo_wine ok( hr == DI_OK, "BuildActionMap returned %#lx\n", hr ); - check_diactionformatw_( __LINE__, &action_format, &expect_action_format_1, &actions_todos_1 ); + check_diactionformatw( &action_format, &expect_action_format_1 );
/* first SetActionMap call for a user always return DI_SETTINGSNOTSAVED */
@@ -911,13 +869,11 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e todo_wine ok( hr == DI_SETTINGSNOTSAVED, "SetActionMap returned %#lx\n", hr ); hr = IDirectInputDevice8_SetActionMap( device, &action_format, L"username", DIDSAM_DEFAULT ); - todo_wine ok( hr == DI_OK, "SetActionMap returned %#lx\n", hr );
/* same SetActionMap call returns DI_OK */
hr = IDirectInputDevice8_SetActionMap( device, &action_format, L"username", DIDSAM_DEFAULT ); - todo_wine ok( hr == DI_OK, "SetActionMap returned %#lx\n", hr );
/* DIDSAM_FORCESAVE always returns DI_SETTINGSNOTSAVED */ @@ -928,7 +884,7 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e hr = IDirectInputDevice8_SetActionMap( device, &action_format, L"username", DIDSAM_FORCESAVE ); todo_wine ok( hr == DI_SETTINGSNOTSAVED, "SetActionMap returned %#lx\n", hr ); - check_diactionformatw_( __LINE__, &action_format, &expect_action_format_1, &actions_todos_1 ); + check_diactionformatw( &action_format, &expect_action_format_1 );
/* action format dwDataSize and dwNumActions have to match, actions require a dwSemantic */ @@ -939,11 +895,9 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e actions[0] = default_actions[0]; action_format.dwDataSize = 8; hr = IDirectInputDevice8_BuildActionMap( device, &action_format, L"username", DIDBAM_DEFAULT ); - todo_wine ok( hr == DIERR_INVALIDPARAM, "BuildActionMap returned %#lx\n", hr ); action_format.dwNumActions = 2; hr = IDirectInputDevice8_BuildActionMap( device, &action_format, L"username", DIDBAM_DEFAULT ); - todo_wine ok( hr == DIERR_INVALIDPARAM, "BuildActionMap returned %#lx\n", hr ); action_format.dwNumActions = 1; action_format.dwDataSize = 4; @@ -954,7 +908,7 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e memcpy( actions, default_actions, sizeof(default_actions) ); hr = IDirectInputDevice8_BuildActionMap( device, &action_format, L"username", DIDBAM_DEFAULT ); ok( hr == DI_OK, "BuildActionMap returned %#lx\n", hr ); - check_diactionformatw_( __LINE__, &action_format, &expect_action_format_2, actions_todos_2 ); + check_diactionformatw( &action_format, &expect_action_format_2 );
hr = IDirectInputDevice8_SetActionMap( device, &action_format, L"username", DIDSAM_DEFAULT ); ok( hr == DI_OK, "SetActionMap returned %#lx\n", hr ); @@ -997,16 +951,15 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e action_format.rgoAction = actions; memcpy( actions, filled_actions, sizeof(filled_actions) ); hr = IDirectInputDevice8_BuildActionMap( device, &action_format, L"username", DIDBAM_DEFAULT ); - todo_wine ok( hr == DI_OK, "BuildActionMap returned %#lx\n", hr ); - check_diactionformatw_( __LINE__, &action_format, &expect_action_format_2_filled, actions_todos_2_filled ); + check_diactionformatw( &action_format, &expect_action_format_2_filled ); hr = IDirectInputDevice8_SetActionMap( device, &action_format, L"username", DIDSAM_DEFAULT ); ok( hr == DI_OK, "SetActionMap returned %#lx\n", hr ); - check_diactionformatw_( __LINE__, &action_format, &expect_action_format_2_filled, actions_todos_2_filled ); + check_diactionformatw( &action_format, &expect_action_format_2_filled ); hr = IDirectInputDevice8_SetActionMap( device, &action_format, L"username", DIDSAM_FORCESAVE ); todo_wine ok( hr == DI_SETTINGSNOTSAVED, "SetActionMap returned %#lx\n", hr ); - check_diactionformatw_( __LINE__, &action_format, &expect_action_format_2_filled, actions_todos_2_filled ); + check_diactionformatw( &action_format, &expect_action_format_2_filled );
prop_pointer.diph.dwHow = DIPH_DEVICE; @@ -1060,21 +1013,21 @@ static void test_action_map( IDirectInputDevice8W *device, HANDLE file, HANDLE e memcpy( actions, default_actions, sizeof(default_actions) ); hr = IDirectInputDevice8_BuildActionMap( device, &action_format, L"username", DIDBAM_HWDEFAULTS ); ok( hr == DI_OK, "BuildActionMap returned %#lx\n", hr ); - check_diactionformatw_( __LINE__, &action_format, &expect_action_format_2, actions_todos_2 ); + check_diactionformatw( &action_format, &expect_action_format_2 );
action_format = action_format_2; action_format.rgoAction = actions; memcpy( actions, default_actions, sizeof(default_actions) ); hr = IDirectInputDevice8_BuildActionMap( device, &action_format, L"username", DIDBAM_INITIALIZE ); ok( hr == DI_OK, "BuildActionMap returned %#lx\n", hr ); - check_diactionformatw_( __LINE__, &action_format, &expect_action_format_2, actions_todos_2 ); + check_diactionformatw( &action_format, &expect_action_format_2 );
action_format = action_format_2; action_format.rgoAction = actions; memcpy( actions, default_actions, sizeof(default_actions) ); hr = IDirectInputDevice8_BuildActionMap( device, &action_format, L"username", DIDBAM_PRESERVE ); ok( hr == DI_OK, "BuildActionMap returned %#lx\n", hr ); - check_diactionformatw_( __LINE__, &action_format, &expect_action_format_2, actions_todos_2 ); + check_diactionformatw( &action_format, &expect_action_format_2 );
hr = IDirectInputDevice8_Acquire( device );