[PATCH 1/3] dinput: Use user object data format array to keep user offsets.

Rémi Bernon rbernon at codeweavers.com
Fri Oct 29 02:40:39 CDT 2021


Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---
 dlls/dinput/device.c         | 229 +++++++++++++----------------------
 dlls/dinput/device_private.h |   4 -
 dlls/dinput/joystick_hid.c   |  21 ++--
 dlls/dinput8/tests/hid.c     |   1 -
 4 files changed, 99 insertions(+), 156 deletions(-)

diff --git a/dlls/dinput/device.c b/dlls/dinput/device.c
index 6601d705462..ed9bdee98ea 100644
--- a/dlls/dinput/device.c
+++ b/dlls/dinput/device.c
@@ -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 );
diff --git a/dlls/dinput/device_private.h b/dlls/dinput/device_private.h
index 1b81a374058..3f07a3a0f8a 100644
--- a/dlls/dinput/device_private.h
+++ b/dlls/dinput/device_private.h
@@ -38,10 +38,6 @@ typedef struct
 
 typedef struct
 {
-    int                         size;
-    DataTransform              *dt;
-
-    int                        *offsets;     /* object offsets */
     LPDIDATAFORMAT              wine_df;     /* wine internal data format */
 } DataFormat;
 
diff --git a/dlls/dinput/joystick_hid.c b/dlls/dinput/joystick_hid.c
index 3a8c7213ebc..13d71a270b6 100644
--- a/dlls/dinput/joystick_hid.c
+++ b/dlls/dinput/joystick_hid.c
@@ -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;
 }
 
diff --git a/dlls/dinput8/tests/hid.c b/dlls/dinput8/tests/hid.c
index 2f2efbe09e3..dab6ea4478e 100644
--- a/dlls/dinput8/tests/hid.c
+++ b/dlls/dinput8/tests/hid.c
@@ -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 );
-- 
2.33.0




More information about the wine-devel mailing list