[PATCH 5/6] dinput: Implement internal enum_objects for mouse and keyboard.

Rémi Bernon rbernon at codeweavers.com
Fri Oct 15 04:57:43 CDT 2021


Signed-off-by: Rémi Bernon <rbernon at codeweavers.com>
---
 dlls/dinput/device.c        |  23 ------
 dlls/dinput/keyboard.c      |  93 ++++++++++++++++-------
 dlls/dinput/mouse.c         | 142 ++++++++++++++++++++++++++++++------
 dlls/dinput8/tests/device.c |   9 +--
 4 files changed, 187 insertions(+), 80 deletions(-)

diff --git a/dlls/dinput/device.c b/dlls/dinput/device.c
index bee9ac8ab45..74f687c5966 100644
--- a/dlls/dinput/device.c
+++ b/dlls/dinput/device.c
@@ -1158,29 +1158,6 @@ HRESULT WINAPI IDirectInputDevice2WImpl_EnumObjects( IDirectInputDevice8W *iface
     if (flags & ~(DIDFT_AXIS | DIDFT_POV | DIDFT_BUTTON | DIDFT_NODATA | DIDFT_COLLECTION))
         return DIERR_INVALIDPARAM;
 
-    if (!impl->vtbl->enum_objects)
-    {
-        DIDEVICEOBJECTINSTANCEW ddoi;
-        DWORD i;
-
-        /* Only the fields till dwFFMaxForce are relevant */
-        memset( &ddoi, 0, sizeof(ddoi) );
-        ddoi.dwSize = FIELD_OFFSET( DIDEVICEOBJECTINSTANCEW, dwFFMaxForce );
-
-        for (i = 0; i < impl->data_format.wine_df->dwNumObjs; i++)
-        {
-            LPDIOBJECTDATAFORMAT odf = dataformat_to_odf( impl->data_format.wine_df, i );
-
-            if (flags != DIDFT_ALL && !(flags & DIDFT_GETTYPE( odf->dwType ))) continue;
-            if (IDirectInputDevice_GetObjectInfo( iface, &ddoi, odf->dwType, DIPH_BYID ) != DI_OK)
-                continue;
-
-            if (callback( &ddoi, context ) != DIENUM_CONTINUE) break;
-        }
-
-        return DI_OK;
-    }
-
     if (flags == DIDFT_ALL || (flags & DIDFT_AXIS))
     {
         hr = impl->vtbl->enum_objects( iface, &filter, DIDFT_AXIS, callback, context );
diff --git a/dlls/dinput/keyboard.c b/dlls/dinput/keyboard.c
index a296ebc98ce..50e292abaad 100644
--- a/dlls/dinput/keyboard.c
+++ b/dlls/dinput/keyboard.c
@@ -196,14 +196,11 @@ static HRESULT alloc_device( REFGUID rguid, IDirectInputImpl *dinput, SysKeyboar
 {
     BYTE subtype = get_keyboard_subtype();
     SysKeyboardImpl* newDevice;
-    LPDIDATAFORMAT df = NULL;
-    int i, idx = 0;
     HRESULT hr;
 
     if (FAILED(hr = direct_input_device_alloc( sizeof(SysKeyboardImpl), &SysKeyboardWvt, &keyboard_internal_vtbl,
                                                rguid, dinput, (void **)&newDevice )))
         return hr;
-    df = newDevice->base.data_format.wine_df;
     newDevice->base.crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": SysKeyboardImpl*->base.crit");
 
     fill_keyboard_dideviceinstanceW( &newDevice->base.instance, newDevice->base.dinput->dwVersion, subtype );
@@ -211,33 +208,14 @@ static HRESULT alloc_device( REFGUID rguid, IDirectInputImpl *dinput, SysKeyboar
     newDevice->base.caps.dwFirmwareRevision = 100;
     newDevice->base.caps.dwHardwareRevision = 100;
 
-    /* Create copy of default data format */
-    memcpy(df, &c_dfDIKeyboard, c_dfDIKeyboard.dwSize);
-    if (!(df->rgodf = malloc( df->dwNumObjs * df->dwObjSize ))) goto failed;
-
-    for (i = 0; i < df->dwNumObjs; i++)
+    if (FAILED(hr = direct_input_device_init( &newDevice->base.IDirectInputDevice8W_iface )))
     {
-        char buf[MAX_PATH];
-        BYTE dik_code;
-
-        if (!GetKeyNameTextA(((i & 0x7f) << 16) | ((i & 0x80) << 17), buf, sizeof(buf)))
-            continue;
-
-        dik_code = map_dik_code( i, 0, subtype, dinput->dwVersion );
-        memcpy(&df->rgodf[idx], &c_dfDIKeyboard.rgodf[dik_code], df->dwObjSize);
-        df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(dik_code) | DIDFT_PSHBUTTON;
+        IDirectInputDevice_Release( &newDevice->base.IDirectInputDevice8W_iface );
+        return hr;
     }
-    df->dwNumObjs = idx;
-    newDevice->base.caps.dwButtons = idx;
 
     *out = newDevice;
     return DI_OK;
-
-failed:
-    if (df) free( df->rgodf );
-    free( df );
-    free( newDevice );
-    return DIERR_OUTOFMEMORY;
 }
 
 static HRESULT keyboarddev_create_device( IDirectInputImpl *dinput, REFGUID rguid, IDirectInputDevice8W **out )
@@ -407,12 +385,75 @@ static HRESULT keyboard_internal_unacquire( IDirectInputDevice8W *iface )
     return DI_OK;
 }
 
+static BOOL try_enum_object( const DIPROPHEADER *filter, DWORD flags, LPDIENUMDEVICEOBJECTSCALLBACKW callback,
+                             DIDEVICEOBJECTINSTANCEW *instance, void *data )
+{
+    if (flags != DIDFT_ALL && !(flags & DIDFT_GETTYPE( instance->dwType ))) return DIENUM_CONTINUE;
+
+    switch (filter->dwHow)
+    {
+    case DIPH_DEVICE:
+        return callback( instance, data );
+    case DIPH_BYOFFSET:
+        if (filter->dwObj != instance->dwOfs) return DIENUM_CONTINUE;
+        return callback( instance, data );
+    case DIPH_BYID:
+        if ((filter->dwObj & 0x00ffffff) != (instance->dwType & 0x00ffffff)) return DIENUM_CONTINUE;
+        return callback( instance, data );
+    }
+
+    return DIENUM_CONTINUE;
+}
+
+static HRESULT keyboard_internal_enum_objects( IDirectInputDevice8W *iface, const DIPROPHEADER *header, DWORD flags,
+                                               LPDIENUMDEVICEOBJECTSCALLBACKW callback, void *context )
+{
+    SysKeyboardImpl *impl = impl_from_IDirectInputDevice8W( iface );
+    BYTE subtype = GET_DIDEVICE_SUBTYPE( impl->base.instance.dwDevType );
+    DIDEVICEOBJECTINSTANCEW instance =
+    {
+        .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW),
+        .guidType = GUID_Key,
+        .dwOfs = DIK_ESCAPE,
+        .dwType = DIDFT_PSHBUTTON | DIDFT_MAKEINSTANCE( DIK_ESCAPE ),
+    };
+    DIDATAFORMAT *format = impl->base.data_format.wine_df;
+    int *offsets = impl->base.data_format.offsets;
+    DIPROPHEADER filter = *header;
+    DWORD i, dik;
+    BOOL ret;
+
+    if (header->dwHow != DIPH_DEVICE && header->dwHow != DIPH_BYOFFSET && header->dwHow != DIPH_BYID)
+        return DIERR_UNSUPPORTED;
+
+    if (filter.dwHow == DIPH_BYOFFSET)
+    {
+        if (!offsets) return DIENUM_CONTINUE;
+        for (i = 0; i < format->dwNumObjs; ++i)
+            if (offsets[i] == filter.dwObj) break;
+        if (i == format->dwNumObjs) return DIENUM_CONTINUE;
+        filter.dwObj = format->rgodf[i].dwOfs;
+    }
+
+    for (i = 0; i < 512; ++i)
+    {
+        if (!GetKeyNameTextW( i << 16, instance.tszName, ARRAY_SIZE(instance.tszName) )) continue;
+        if (!(dik = map_dik_code( i, 0, subtype, impl->base.dinput->dwVersion ))) continue;
+        instance.dwOfs = dik;
+        instance.dwType = DIDFT_PSHBUTTON | DIDFT_MAKEINSTANCE( dik );
+        ret = try_enum_object( &filter, flags, callback, &instance, context );
+        if (ret != DIENUM_CONTINUE) return DIENUM_STOP;
+    }
+
+    return DIENUM_CONTINUE;
+}
+
 static const struct dinput_device_vtbl keyboard_internal_vtbl =
 {
     NULL,
     keyboard_internal_acquire,
     keyboard_internal_unacquire,
-    NULL,
+    keyboard_internal_enum_objects,
 };
 
 static const IDirectInputDevice8WVtbl SysKeyboardWvt =
diff --git a/dlls/dinput/mouse.c b/dlls/dinput/mouse.c
index ea3fcbb5581..cdbdd083c00 100644
--- a/dlls/dinput/mouse.c
+++ b/dlls/dinput/mouse.c
@@ -138,8 +138,6 @@ static HRESULT mousedev_enum_device(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEIN
 static HRESULT alloc_device( REFGUID rguid, IDirectInputImpl *dinput, SysMouseImpl **out )
 {
     SysMouseImpl* newDevice;
-    LPDIDATAFORMAT df = NULL;
-    unsigned i;
     WCHAR buffer[20];
     HKEY hkey, appkey;
     HRESULT hr;
@@ -147,13 +145,10 @@ static HRESULT alloc_device( REFGUID rguid, IDirectInputImpl *dinput, SysMouseIm
     if (FAILED(hr = direct_input_device_alloc( sizeof(SysMouseImpl), &SysMouseWvt, &mouse_internal_vtbl,
                                                rguid, dinput, (void **)&newDevice )))
         return hr;
-    df = newDevice->base.data_format.wine_df;
     newDevice->base.crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": SysMouseImpl*->base.crit");
 
     fill_mouse_dideviceinstanceW( &newDevice->base.instance, newDevice->base.dinput->dwVersion );
     newDevice->base.caps.dwDevType = newDevice->base.instance.dwDevType;
-    newDevice->base.caps.dwAxes = 3;
-    newDevice->base.caps.dwButtons = 8;
     newDevice->base.caps.dwFirmwareRevision = 100;
     newDevice->base.caps.dwHardwareRevision = 100;
     newDevice->base.dwCoopLevel = DISCL_NONEXCLUSIVE | DISCL_BACKGROUND;
@@ -167,17 +162,11 @@ static HRESULT alloc_device( REFGUID rguid, IDirectInputImpl *dinput, SysMouseIm
     if (appkey) RegCloseKey(appkey);
     if (hkey) RegCloseKey(hkey);
 
-    /* Create copy of default data format */
-    memcpy(df, &c_dfDIMouse2, c_dfDIMouse2.dwSize);
-    if (!(df->rgodf = malloc( df->dwNumObjs * df->dwObjSize ))) goto failed;
-    memcpy(df->rgodf, c_dfDIMouse2.rgodf, df->dwNumObjs * df->dwObjSize);
-
-    /* Because we don't do any detection yet just modify instance and type */
-    for (i = 0; i < df->dwNumObjs; i++)
-        if (DIDFT_GETTYPE(df->rgodf[i].dwType) & DIDFT_AXIS)
-            df->rgodf[i].dwType = DIDFT_MAKEINSTANCE(i) | DIDFT_RELAXIS;
-        else
-            df->rgodf[i].dwType = DIDFT_MAKEINSTANCE(i) | DIDFT_PSHBUTTON;
+    if (FAILED(hr = direct_input_device_init( &newDevice->base.IDirectInputDevice8W_iface )))
+    {
+        IDirectInputDevice_Release( &newDevice->base.IDirectInputDevice8W_iface );
+        return hr;
+    }
 
     if (dinput->dwVersion >= 0x0800)
     {
@@ -188,12 +177,6 @@ static HRESULT alloc_device( REFGUID rguid, IDirectInputImpl *dinput, SysMouseIm
 
     *out = newDevice;
     return DI_OK;
-
-failed:
-    if (df) free( df->rgodf );
-    free( df );
-    free( newDevice );
-    return DIERR_OUTOFMEMORY;
 }
 
 static HRESULT mousedev_create_device( IDirectInputImpl *dinput, REFGUID rguid, IDirectInputDevice8W **out )
@@ -663,12 +646,125 @@ static HRESULT mouse_internal_unacquire( IDirectInputDevice8W *iface )
     return DI_OK;
 }
 
+static BOOL try_enum_object( const DIPROPHEADER *filter, DWORD flags, LPDIENUMDEVICEOBJECTSCALLBACKW callback,
+                             DIDEVICEOBJECTINSTANCEW *instance, void *data )
+{
+    if (flags != DIDFT_ALL && !(flags & DIDFT_GETTYPE( instance->dwType ))) return DIENUM_CONTINUE;
+
+    switch (filter->dwHow)
+    {
+    case DIPH_DEVICE:
+        return callback( instance, data );
+    case DIPH_BYOFFSET:
+        if (filter->dwObj != instance->dwOfs) return DIENUM_CONTINUE;
+        return callback( instance, data );
+    case DIPH_BYID:
+        if ((filter->dwObj & 0x00ffffff) != (instance->dwType & 0x00ffffff)) return DIENUM_CONTINUE;
+        return callback( instance, data );
+    }
+
+    return DIENUM_CONTINUE;
+}
+
+static HRESULT mouse_internal_enum_objects( IDirectInputDevice8W *iface, const DIPROPHEADER *header, DWORD flags,
+                                            LPDIENUMDEVICEOBJECTSCALLBACKW callback, void *context )
+{
+    DIDEVICEOBJECTINSTANCEW instances[] =
+    {
+        {
+            .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW),
+            .guidType = GUID_XAxis,
+            .dwOfs = DIMOFS_X,
+            .dwType = DIDFT_RELAXIS|DIDFT_MAKEINSTANCE(0),
+            .dwFlags = DIDOI_ASPECTPOSITION,
+            .tszName = L"X-axis",
+        },
+        {
+            .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW),
+            .guidType = GUID_YAxis,
+            .dwOfs = DIMOFS_Y,
+            .dwType = DIDFT_RELAXIS|DIDFT_MAKEINSTANCE(1),
+            .dwFlags = DIDOI_ASPECTPOSITION,
+            .tszName = L"Y-axis",
+        },
+        {
+            .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW),
+            .guidType = GUID_ZAxis,
+            .dwOfs = DIMOFS_Z,
+            .dwType = DIDFT_RELAXIS|DIDFT_MAKEINSTANCE(2),
+            .dwFlags = DIDOI_ASPECTPOSITION,
+            .tszName = L"Wheel",
+        },
+        {
+            .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW),
+            .guidType = GUID_Button,
+            .dwOfs = DIMOFS_BUTTON0,
+            .dwType = DIDFT_PSHBUTTON|DIDFT_MAKEINSTANCE(3),
+            .tszName = L"Button 0",
+        },
+        {
+            .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW),
+            .guidType = GUID_Button,
+            .dwOfs = DIMOFS_BUTTON1,
+            .dwType = DIDFT_PSHBUTTON|DIDFT_MAKEINSTANCE(4),
+            .tszName = L"Button 1",
+        },
+        {
+            .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW),
+            .guidType = GUID_Button,
+            .dwOfs = DIMOFS_BUTTON2,
+            .dwType = DIDFT_PSHBUTTON|DIDFT_MAKEINSTANCE(5),
+            .tszName = L"Button 2",
+        },
+        {
+            .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW),
+            .guidType = GUID_Button,
+            .dwOfs = DIMOFS_BUTTON3,
+            .dwType = DIDFT_PSHBUTTON|DIDFT_MAKEINSTANCE(6),
+            .tszName = L"Button 3",
+        },
+        {
+            .dwSize = sizeof(DIDEVICEOBJECTINSTANCEW),
+            .guidType = GUID_Button,
+            .dwOfs = DIMOFS_BUTTON4,
+            .dwType = DIDFT_PSHBUTTON|DIDFT_MAKEINSTANCE(7),
+            .tszName = L"Button 4",
+        },
+    };
+    SysMouseImpl *impl = impl_from_IDirectInputDevice8W( iface );
+    DIDATAFORMAT *format = impl->base.data_format.wine_df;
+    int *offsets = impl->base.data_format.offsets;
+    DIPROPHEADER filter = *header;
+    BOOL ret;
+    DWORD i;
+
+    if (header->dwHow != DIPH_DEVICE && header->dwHow != DIPH_BYOFFSET && header->dwHow != DIPH_BYID)
+        return DIERR_UNSUPPORTED;
+
+    if (filter.dwHow == DIPH_BYOFFSET)
+    {
+        if (!offsets) return DIENUM_CONTINUE;
+        for (i = 0; i < format->dwNumObjs; ++i)
+            if (offsets[i] == filter.dwObj) break;
+        if (i == format->dwNumObjs) return DIENUM_CONTINUE;
+        filter.dwObj = format->rgodf[i].dwOfs;
+    }
+
+    for (i = 0; i < ARRAY_SIZE(instances); ++i)
+    {
+        ret = try_enum_object( &filter, flags, callback, instances + i, context );
+        if (ret != DIENUM_CONTINUE) return DIENUM_STOP;
+    }
+
+    return DIENUM_CONTINUE;
+}
+
 static const struct dinput_device_vtbl mouse_internal_vtbl =
 {
     NULL,
     mouse_internal_acquire,
     mouse_internal_unacquire,
-    NULL,
+    mouse_internal_enum_objects,
 };
 
 static const IDirectInputDevice8WVtbl SysMouseWvt =
diff --git a/dlls/dinput8/tests/device.c b/dlls/dinput8/tests/device.c
index 1819d597a6b..ca8a7d89bc8 100644
--- a/dlls/dinput8/tests/device.c
+++ b/dlls/dinput8/tests/device.c
@@ -1068,7 +1068,6 @@ static BOOL CALLBACK check_objects( const DIDEVICEOBJECTINSTANCEW *obj, void *ar
 
     winetest_push_context( "obj[%d]", params->index );
 
-    todo_wine
     check_member( *obj, *exp, "%u", dwSize );
     check_member_guid( *obj, *exp, guidType );
     todo_wine_if( todo->offset )
@@ -1183,11 +1182,7 @@ static void test_mouse_info(void)
             .tszName = L"Button 4",
         },
     };
-    struct check_objects_todos todo_objects[ARRAY_SIZE(expect_objects)] =
-    {
-        {.name = TRUE},
-        {.name = TRUE},
-    };
+    struct check_objects_todos todo_objects[ARRAY_SIZE(expect_objects)] = {{0}};
     struct check_objects_params check_objects_params =
     {
         .expect_count = ARRAY_SIZE(expect_objects),
@@ -1283,7 +1278,6 @@ static void test_mouse_info(void)
     todo_wine
     check_member( caps, expect_caps, "%#x", dwDevType );
     check_member( caps, expect_caps, "%d", dwAxes );
-    todo_wine
     check_member( caps, expect_caps, "%d", dwButtons );
     check_member( caps, expect_caps, "%d", dwPOVs );
     check_member( caps, expect_caps, "%d", dwFFSamplePeriod );
@@ -1410,7 +1404,6 @@ static void test_mouse_info(void)
     res = 0;
     hr = IDirectInputDevice8_EnumObjects( device, check_object_count, &res, DIDFT_AXIS | DIDFT_PSHBUTTON );
     ok( hr == DI_OK, "EnumObjects returned %#x\n", hr );
-    todo_wine
     ok( res == 8, "got %u expected %u\n", res, 8 );
     hr = IDirectInputDevice8_EnumObjects( device, check_objects, &check_objects_params, DIDFT_ALL );
     ok( hr == DI_OK, "EnumObjects returned %#x\n", hr );
-- 
2.33.0




More information about the wine-devel mailing list