dinput: Use user object data format array to keep user offsets.

Signed-off-by: Rémi Bernon <rbernon@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Rémi Bernon 2021-10-29 09:40:39 +02:00 committed by Alexandre Julliard
parent 6677ba7834
commit 621af39c11
4 changed files with 99 additions and 156 deletions

View file

@ -334,73 +334,9 @@ BOOL device_instance_is_disabled( DIDEVICEINSTANCEW *instance, BOOL *override )
return disable;
}
/* Conversion between internal data buffer and external data buffer */
static void fill_DataFormat( void *out, DWORD size, const void *in, const DataFormat *df )
{
int i;
const char *in_c = in;
char *out_c = out;
memset(out, 0, size);
for (i = 0; i < df->size; i++) {
if (df->dt[i].offset_in >= 0) {
switch (df->dt[i].size) {
case 1:
TRACE("Copying (c) to %d from %d (value %d)\n",
df->dt[i].offset_out, df->dt[i].offset_in, *(in_c + df->dt[i].offset_in));
*(out_c + df->dt[i].offset_out) = *(in_c + df->dt[i].offset_in);
break;
case 2:
TRACE("Copying (s) to %d from %d (value %d)\n",
df->dt[i].offset_out, df->dt[i].offset_in, *((const short *)(in_c + df->dt[i].offset_in)));
*((short *)(out_c + df->dt[i].offset_out)) = *((const short *)(in_c + df->dt[i].offset_in));
break;
case 4:
TRACE("Copying (i) to %d from %d (value %d)\n",
df->dt[i].offset_out, df->dt[i].offset_in, *((const int *)(in_c + df->dt[i].offset_in)));
*((int *)(out_c + df->dt[i].offset_out)) = *((const int *)(in_c + df->dt[i].offset_in));
break;
default:
memcpy((out_c + df->dt[i].offset_out), (in_c + df->dt[i].offset_in), df->dt[i].size);
break;
}
} else {
switch (df->dt[i].size) {
case 1:
TRACE("Copying (c) to %d default value %d\n",
df->dt[i].offset_out, df->dt[i].value);
*(out_c + df->dt[i].offset_out) = (char) df->dt[i].value;
break;
case 2:
TRACE("Copying (s) to %d default value %d\n",
df->dt[i].offset_out, df->dt[i].value);
*((short *) (out_c + df->dt[i].offset_out)) = (short) df->dt[i].value;
break;
case 4:
TRACE("Copying (i) to %d default value %d\n",
df->dt[i].offset_out, df->dt[i].value);
*((int *) (out_c + df->dt[i].offset_out)) = df->dt[i].value;
break;
default:
memset((out_c + df->dt[i].offset_out), 0, df->dt[i].size);
break;
}
}
}
}
static void dinput_device_release_user_format( struct dinput_device *impl )
{
free( impl->data_format.dt );
impl->data_format.dt = NULL;
free( impl->data_format.offsets );
impl->data_format.offsets = NULL;
if (impl->user_format) free( impl->user_format->rgodf );
free( impl->user_format );
impl->user_format = NULL;
}
@ -436,33 +372,35 @@ LPDIOBJECTDATAFORMAT dataformat_to_odf_by_type(LPCDIDATAFORMAT df, int n, DWORD
static HRESULT dinput_device_init_user_format( struct dinput_device *impl, const DIDATAFORMAT *asked_format )
{
DIOBJECTDATAFORMAT *device_obj, *user_obj;
DataFormat *format = &impl->data_format;
DataTransform *dt;
DIDATAFORMAT *user_format = NULL;
unsigned int i, j;
int *done;
int index = 0;
DWORD next = 0;
if (!format->wine_df) return DIERR_INVALIDPARAM;
done = calloc( asked_format->dwNumObjs, sizeof(int) );
dt = malloc( asked_format->dwNumObjs * sizeof(DataTransform) );
if (!dt || !done) goto failed;
if (!done) goto failed;
if (!(format->offsets = malloc( format->wine_df->dwNumObjs * sizeof(int) ))) goto failed;
if (!(impl->user_format = malloc( asked_format->dwSize ))) goto failed;
memcpy( impl->user_format, asked_format, asked_format->dwSize );
if (!(user_format = malloc( sizeof(DIDATAFORMAT) ))) goto failed;
*user_format = *format->wine_df;
user_format->dwFlags = asked_format->dwFlags;
user_format->dwDataSize = asked_format->dwDataSize;
user_format->dwNumObjs += asked_format->dwNumObjs;
if (!(user_format->rgodf = calloc( user_format->dwNumObjs, sizeof(DIOBJECTDATAFORMAT) ))) goto failed;
TRACE("Creating DataTransform :\n");
for (i = 0; i < format->wine_df->dwNumObjs; i++)
{
format->offsets[i] = -1;
device_obj = format->wine_df->rgodf + i;
user_obj = user_format->rgodf + i;
for (j = 0; j < asked_format->dwNumObjs; j++) {
if (done[j] == 1)
continue;
if (/* Check if the application either requests any GUID and if not, it if matches
for (j = 0; j < asked_format->dwNumObjs; j++)
{
if (done[j] == 1) continue;
if (/* Check if the application either requests any GUID and if not, it if matches
* the GUID of the Wine object.
*/
((asked_format->rgodf[j].pguid == NULL) ||
@ -501,26 +439,19 @@ static HRESULT dinput_device_init_user_format( struct dinput_device *impl, const
TRACE(" "); _dump_EnumObjects_flags(format->wine_df->rgodf[i].dwType); TRACE("\n");
TRACE(" * dwFlags: 0x%08x\n", format->wine_df->rgodf[i].dwFlags);
TRACE(" "); _dump_ObjectDataFormat_flags(format->wine_df->rgodf[i].dwFlags); TRACE("\n");
if (format->wine_df->rgodf[i].dwType & DIDFT_BUTTON)
dt[index].size = sizeof(BYTE);
else
dt[index].size = sizeof(DWORD);
dt[index].offset_in = format->wine_df->rgodf[i].dwOfs;
dt[index].offset_out = asked_format->rgodf[j].dwOfs;
format->offsets[i] = asked_format->rgodf[j].dwOfs;
dt[index].value = 0;
next = next + dt[index].size;
index++;
break;
}
}
*user_obj = *device_obj;
user_obj->dwOfs = asked_format->rgodf[j].dwOfs;
break;
}
}
}
TRACE("Setting to default value :\n");
for (j = 0; j < asked_format->dwNumObjs; j++) {
if (done[j] == 0) {
user_obj = user_format->rgodf + format->wine_df->dwNumObjs + j;
if (done[j] == 0) {
TRACE(" - Asked (%d) :\n", j);
TRACE(" * GUID: %s ('%s')\n",
debugstr_guid(asked_format->rgodf[j].pguid),
@ -534,55 +465,40 @@ static HRESULT dinput_device_init_user_format( struct dinput_device *impl, const
if (!(asked_format->rgodf[j].dwType & DIDFT_POV))
continue; /* fill_DataFormat memsets the buffer to 0 */
if (asked_format->rgodf[j].dwType & DIDFT_BUTTON)
dt[index].size = sizeof(BYTE);
else
dt[index].size = sizeof(DWORD);
dt[index].offset_in = -1;
dt[index].offset_out = asked_format->rgodf[j].dwOfs;
dt[index].value = -1;
index++;
}
*user_obj = asked_format->rgodf[j];
}
}
format->size = index;
format->dt = dt;
free( done );
impl->user_format = user_format;
return DI_OK;
failed:
free( done );
free( dt );
format->dt = NULL;
free( format->offsets );
format->offsets = NULL;
free( impl->user_format );
impl->user_format = NULL;
if (user_format) free( user_format->rgodf );
free( user_format );
return DIERR_OUTOFMEMORY;
}
static int id_to_object( LPCDIDATAFORMAT df, int id )
static int id_to_offset( struct dinput_device *impl, int id )
{
int i;
DIDATAFORMAT *device_format = impl->data_format.wine_df, *user_format = impl->user_format;
DIOBJECTDATAFORMAT *user_obj;
id &= 0x00ffffff;
for (i = 0; i < df->dwNumObjs; i++)
if ((dataformat_to_odf(df, i)->dwType & 0x00ffffff) == id)
return i;
if (!user_format) return -1;
user_obj = user_format->rgodf + device_format->dwNumObjs;
while (user_obj-- > user_format->rgodf)
{
if (!user_obj->dwType) continue;
if ((user_obj->dwType & 0x00ffffff) == (id & 0x00ffffff)) return user_obj->dwOfs;
}
return -1;
}
static int id_to_offset(const DataFormat *df, int id)
{
int obj = id_to_object(df->wine_df, id);
return obj >= 0 && df->offsets ? df->offsets[obj] : -1;
}
static DWORD semantic_to_obj_id( struct dinput_device *This, DWORD dwSemantic )
{
DWORD type = (0x0000ff00 & dwSemantic) >> 8;
@ -769,7 +685,7 @@ void queue_event( IDirectInputDevice8W *iface, int inst_id, DWORD data, DWORD ti
{
static ULONGLONG notify_ms = 0;
struct dinput_device *This = impl_from_IDirectInputDevice8W( iface );
int next_pos, ofs = id_to_offset(&This->data_format, inst_id);
int next_pos, ofs = id_to_offset( This, inst_id );
ULONGLONG time_ms = GetTickCount64();
if (time_ms - notify_ms > 1000)
@ -1138,19 +1054,25 @@ static HRESULT WINAPI dinput_device_EnumObjects( IDirectInputDevice8W *iface,
static HRESULT enum_object_filter_init( struct dinput_device *impl, DIPROPHEADER *filter )
{
DIDATAFORMAT *format = impl->data_format.wine_df;
int i, *offsets = impl->data_format.offsets;
DIDATAFORMAT *device_format = impl->data_format.wine_df, *user_format = impl->user_format;
DIOBJECTDATAFORMAT *device_obj, *user_obj;
if (filter->dwHow > DIPH_BYUSAGE) return DIERR_INVALIDPARAM;
if (filter->dwHow == DIPH_BYUSAGE && !(impl->instance.dwDevType & DIDEVTYPE_HID)) return DIERR_UNSUPPORTED;
if (filter->dwHow != DIPH_BYOFFSET) return DI_OK;
if (!offsets) return DIERR_NOTFOUND;
if (!impl->user_format) return DIERR_NOTFOUND;
for (i = 0; i < format->dwNumObjs; ++i) if (offsets[i] == filter->dwObj) break;
if (i == format->dwNumObjs) return DIERR_NOTFOUND;
user_obj = user_format->rgodf + device_format->dwNumObjs;
device_obj = device_format->rgodf + device_format->dwNumObjs;
while (user_obj-- > user_format->rgodf && device_obj-- > device_format->rgodf)
{
if (!user_obj->dwType) continue;
if (user_obj->dwOfs == filter->dwObj) break;
}
if (user_obj < user_format->rgodf) return DIERR_NOTFOUND;
filter->dwObj = format->rgodf[i].dwOfs;
filter->dwObj = device_obj->dwOfs;
return DI_OK;
}
@ -1397,7 +1319,7 @@ static HRESULT WINAPI dinput_device_SetProperty( IDirectInputDevice8W *iface, co
hr = impl->vtbl->enum_objects( iface, &filter, object_mask, find_object, &instance );
if (FAILED(hr)) return hr;
if (hr == DIENUM_CONTINUE) return DIERR_OBJECTNOTFOUND;
if ((user_offset = id_to_offset( &impl->data_format, instance.dwType )) < 0) return DIERR_OBJECTNOTFOUND;
if ((user_offset = id_to_offset( impl, instance.dwType )) < 0) return DIERR_OBJECTNOTFOUND;
if (!set_app_data( impl, user_offset, value->uData )) return DIERR_OUTOFMEMORY;
return DI_OK;
}
@ -1469,15 +1391,12 @@ static HRESULT WINAPI dinput_device_GetObjectInfo( IDirectInputDevice8W *iface,
return DI_OK;
}
static BOOL CALLBACK reset_axis_data( const DIDEVICEOBJECTINSTANCEW *instance, void *data )
{
*(ULONG *)((char *)data + instance->dwOfs) = 0;
return DIENUM_CONTINUE;
}
static HRESULT WINAPI dinput_device_GetDeviceState( IDirectInputDevice8W *iface, DWORD size, void *data )
{
struct dinput_device *impl = impl_from_IDirectInputDevice8W( iface );
DIDATAFORMAT *device_format = impl->data_format.wine_df, *user_format;
DIOBJECTDATAFORMAT *device_obj, *user_obj;
BYTE *user_state = data;
DIPROPHEADER filter =
{
.dwSize = sizeof(filter),
@ -1496,13 +1415,37 @@ static HRESULT WINAPI dinput_device_GetDeviceState( IDirectInputDevice8W *iface,
EnterCriticalSection( &impl->crit );
if (!impl->acquired)
hr = DIERR_NOTACQUIRED;
else if (size != impl->user_format->dwDataSize)
else if (!(user_format = impl->user_format))
hr = DIERR_INVALIDPARAM;
else if (size != user_format->dwDataSize)
hr = DIERR_INVALIDPARAM;
else
{
fill_DataFormat( data, size, impl->device_state, &impl->data_format );
if (!(impl->user_format->dwFlags & DIDF_ABSAXIS))
impl->vtbl->enum_objects( iface, &filter, DIDFT_RELAXIS, reset_axis_data, impl->device_state );
memset( user_state, 0, size );
user_obj = user_format->rgodf + device_format->dwNumObjs;
device_obj = device_format->rgodf + device_format->dwNumObjs;
while (user_obj-- > user_format->rgodf && device_obj-- > device_format->rgodf)
{
if (user_obj->dwType & DIDFT_BUTTON)
user_state[user_obj->dwOfs] = impl->device_state[device_obj->dwOfs];
}
/* reset optional POVs to their default */
user_obj = user_format->rgodf + user_format->dwNumObjs;
while (user_obj-- > user_format->rgodf + device_format->dwNumObjs)
if (user_obj->dwType & DIDFT_POV) *(ULONG *)(user_state + user_obj->dwOfs) = 0xffffffff;
user_obj = user_format->rgodf + device_format->dwNumObjs;
device_obj = device_format->rgodf + device_format->dwNumObjs;
while (user_obj-- > user_format->rgodf && device_obj-- > device_format->rgodf)
{
if (user_obj->dwType & (DIDFT_POV | DIDFT_AXIS))
*(ULONG *)(user_state + user_obj->dwOfs) = *(ULONG *)(impl->device_state + device_obj->dwOfs);
if (!(user_format->dwFlags & DIDF_ABSAXIS) && (device_obj->dwType & DIDFT_RELAXIS))
*(ULONG *)(impl->device_state + device_obj->dwOfs) = 0;
}
hr = DI_OK;
}
LeaveCriticalSection( &impl->crit );

View file

@ -38,10 +38,6 @@ typedef struct
typedef struct
{
int size;
DataTransform *dt;
int *offsets; /* object offsets */
LPDIDATAFORMAT wine_df; /* wine internal data format */
} DataFormat;

View file

@ -2009,16 +2009,21 @@ static BOOL get_parameters_object_id( struct hid_joystick *impl, struct hid_valu
static BOOL get_parameters_object_ofs( struct hid_joystick *impl, struct hid_value_caps *caps,
DIDEVICEOBJECTINSTANCEW *instance, void *data )
{
DIDATAFORMAT *format = impl->base.data_format.wine_df;
int *offsets = impl->base.data_format.offsets;
ULONG i;
DIDATAFORMAT *device_format = impl->base.data_format.wine_df, *user_format = impl->base.user_format;
DIOBJECTDATAFORMAT *device_obj, *user_obj;
if (!offsets) return DIENUM_CONTINUE;
for (i = 0; i < format->dwNumObjs; ++i)
if (format->rgodf[i].dwOfs == instance->dwOfs) break;
if (i == format->dwNumObjs) return DIENUM_CONTINUE;
*(DWORD *)data = offsets[i];
if (!user_format) return DIENUM_CONTINUE;
user_obj = user_format->rgodf + device_format->dwNumObjs;
device_obj = device_format->rgodf + device_format->dwNumObjs;
while (user_obj-- > user_format->rgodf && device_obj-- > device_format->rgodf)
{
if (!user_obj->dwType) continue;
if (device_obj->dwType == instance->dwType) break;
}
if (user_obj < user_format->rgodf) return DIENUM_CONTINUE;
*(DWORD *)data = user_obj->dwOfs;
return DIENUM_STOP;
}

View file

@ -4539,7 +4539,6 @@ static void test_simple_joystick(void)
hr = IDirectInputDevice8_GetDeviceState( device, dataformat.dwDataSize, buffer );
ok( hr == DI_OK, "GetDeviceState returned: %#x\n", hr );
todo_wine
ok( ((ULONG *)buffer)[0] == 0x512b, "got %#x, expected %#x\n", ((ULONG *)buffer)[0], 0x512b );
ok( ((ULONG *)buffer)[1] == 0, "got %#x, expected %#x\n", ((ULONG *)buffer)[1], 0 );
ok( ((ULONG *)buffer)[2] == 0x7fff, "got %#x, expected %#x\n", ((ULONG *)buffer)[2], 0x7fff );