Lucas Zawacki : dinput: SetActionMap saving mappings.

Alexandre Julliard julliard at winehq.org
Mon Aug 27 14:35:01 CDT 2012


Module: wine
Branch: master
Commit: af1dcde288b96e1e12a76861b78b1801f5d52d67
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=af1dcde288b96e1e12a76861b78b1801f5d52d67

Author: Lucas Zawacki <lfzawacki at gmail.com>
Date:   Fri Aug 24 14:04:52 2012 -0300

dinput: SetActionMap saving mappings.

---

 dlls/dinput/device.c         |  143 ++++++++++++++++++++++++++++++++++++++++++
 dlls/dinput/dinput_private.h |    2 +
 dlls/dinput8/tests/device.c  |    8 +-
 3 files changed, 149 insertions(+), 4 deletions(-)

diff --git a/dlls/dinput/device.c b/dlls/dinput/device.c
index bf5fd1b..098efb7 100644
--- a/dlls/dinput/device.c
+++ b/dlls/dinput/device.c
@@ -598,10 +598,142 @@ static DWORD semantic_to_obj_id(IDirectInputDeviceImpl* This, DWORD dwSemantic)
     return type | (0x0000ff00 & (obj_instance << 8));
 }
 
+/*
+ * get_mapping_key
+ * Retrieves an open registry key to save the mapping, parametrized for an username,
+ * specific device and specific action mapping guid.
+ */
+static HKEY get_mapping_key(const WCHAR *device, const WCHAR *username, const WCHAR *guid)
+{
+    static const WCHAR subkey[] = {
+        'S','o','f','t','w','a','r','e','\\',
+        'W','i','n','e','\\',
+        'D','i','r','e','c','t','I','n','p','u','t','\\',
+        'M','a','p','p','i','n','g','s','\\','%','s','\\','%','s','\\','%','s','\0'};
+    HKEY hkey;
+    WCHAR *keyname;
+
+    keyname = HeapAlloc(GetProcessHeap(), 0,
+        sizeof(WCHAR) * (lstrlenW(subkey) + strlenW(username) + strlenW(device) + strlenW(guid)));
+    sprintfW(keyname, subkey, username, device, guid);
+
+    /* The key used is HKCU\Software\Wine\DirectInput\Mappings\[username]\[device]\[mapping_guid] */
+    if (RegCreateKeyW(HKEY_CURRENT_USER, keyname, &hkey))
+        hkey = 0;
+
+    HeapFree(GetProcessHeap(), 0, keyname);
+
+    return hkey;
+}
+
+static HRESULT save_mapping_settings(IDirectInputDevice8W *iface, LPDIACTIONFORMATW lpdiaf, LPCWSTR lpszUsername)
+{
+    WCHAR *guid_str = NULL;
+    DIDEVICEINSTANCEW didev;
+    HKEY hkey;
+    int i;
+
+    didev.dwSize = sizeof(didev);
+    IDirectInputDevice8_GetDeviceInfo(iface, &didev);
+
+    if (StringFromCLSID(&lpdiaf->guidActionMap, &guid_str) != S_OK)
+        return DI_SETTINGSNOTSAVED;
+
+    hkey = get_mapping_key(didev.tszInstanceName, lpszUsername, guid_str);
+
+    if (!hkey)
+    {
+        CoTaskMemFree(guid_str);
+        return DI_SETTINGSNOTSAVED;
+    }
+
+    /* Write each of the actions mapped for this device.
+       Format is "dwSemantic"="dwObjID" and key is of type REG_DWORD
+    */
+    for (i = 0; i < lpdiaf->dwNumActions; i++)
+    {
+        static const WCHAR format[] = {'%','x','\0'};
+        WCHAR label[9];
+
+        if (IsEqualGUID(&didev.guidInstance, &lpdiaf->rgoAction[i].guidInstance) &&
+            lpdiaf->rgoAction[i].dwHow != DIAH_UNMAPPED)
+        {
+             sprintfW(label, format, lpdiaf->rgoAction[i].dwSemantic);
+             RegSetValueExW(hkey, label, 0, REG_DWORD, (const BYTE*) &lpdiaf->rgoAction[i].dwObjID, sizeof(DWORD));
+        }
+    }
+
+    RegCloseKey(hkey);
+    CoTaskMemFree(guid_str);
+
+    return DI_OK;
+}
+
+static BOOL load_mapping_settings(IDirectInputDeviceImpl *This, LPDIACTIONFORMATW lpdiaf, const WCHAR *username)
+{
+    HKEY hkey;
+    WCHAR *guid_str;
+    DIDEVICEINSTANCEW didev;
+    int i;
+
+    didev.dwSize = sizeof(didev);
+    IDirectInputDevice8_GetDeviceInfo(&This->IDirectInputDevice8W_iface, &didev);
+
+    if (StringFromCLSID(&lpdiaf->guidActionMap, &guid_str) != S_OK)
+        return FALSE;
+
+    hkey = get_mapping_key(didev.tszInstanceName, username, guid_str);
+
+    if (!hkey)
+    {
+        CoTaskMemFree(guid_str);
+        return FALSE;
+    }
+
+    /* Try to read each action in the DIACTIONFORMAT from registry */
+    for (i = 0; i < lpdiaf->dwNumActions; i++)
+    {
+        static const WCHAR format[] = {'%','x','\0'};
+        DWORD id, size = sizeof(DWORD);
+        WCHAR label[9];
+
+        sprintfW(label, format, lpdiaf->rgoAction[i].dwSemantic);
+
+        if (!RegQueryValueExW(hkey, label, 0, NULL, (LPBYTE) &id, &size))
+        {
+            lpdiaf->rgoAction[i].dwObjID = id;
+            lpdiaf->rgoAction[i].guidInstance = didev.guidInstance;
+            lpdiaf->rgoAction[i].dwHow = DIAH_USERCONFIG;
+        }
+    }
+
+    RegCloseKey(hkey);
+    CoTaskMemFree(guid_str);
+
+    return TRUE;
+}
+
 HRESULT _build_action_map(LPDIRECTINPUTDEVICE8W iface, LPDIACTIONFORMATW lpdiaf, LPCWSTR lpszUserName, DWORD dwFlags, DWORD devMask, LPCDIDATAFORMAT df)
 {
     IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8W(iface);
+    WCHAR username[MAX_PATH];
+    DWORD username_size = MAX_PATH;
     int i, has_actions = 0;
+    BOOL load_success = FALSE;
+
+    /* Unless asked the contrary by these flags, try to load a previous mapping */
+    if (!(dwFlags & DIDBAM_HWDEFAULTS))
+    {
+        /* Retrieve logged user name if necessary */
+        if (lpszUserName == NULL)
+            GetUserNameW(username, &username_size);
+        else
+            lstrcpynW(username, lpszUserName, MAX_PATH);
+
+        load_success = load_mapping_settings(This, lpdiaf, username);
+    }
+
+    if (load_success) return DI_OK;
 
     for (i=0; i < lpdiaf->dwNumActions; i++)
     {
@@ -650,6 +782,8 @@ HRESULT _set_action_map(LPDIRECTINPUTDEVICE8W iface, LPDIACTIONFORMATW lpdiaf, L
     DIOBJECTDATAFORMAT *obj_df = NULL;
     DIPROPDWORD dp;
     DIPROPRANGE dpr;
+    WCHAR username[MAX_PATH];
+    DWORD username_size = MAX_PATH;
     int i, action = 0, num_actions = 0;
     unsigned int offset = 0;
 
@@ -722,6 +856,15 @@ HRESULT _set_action_map(LPDIRECTINPUTDEVICE8W iface, LPDIACTIONFORMATW lpdiaf, L
         IDirectInputDevice8_SetProperty(iface, DIPROP_BUFFERSIZE, &dp.diph);
     }
 
+    /* Retrieve logged user name if necessary */
+    if (lpszUserName == NULL)
+        GetUserNameW(username, &username_size);
+    else
+        lstrcpynW(username, lpszUserName, MAX_PATH);
+
+    /* Save the settings to disk */
+    save_mapping_settings(iface, lpdiaf, username);
+
     return IDirectInputDevice8WImpl_SetActionMap(iface, lpdiaf, lpszUserName, dwFlags);
 }
 
diff --git a/dlls/dinput/dinput_private.h b/dlls/dinput/dinput_private.h
index 8efb42e..e593b40 100644
--- a/dlls/dinput/dinput_private.h
+++ b/dlls/dinput/dinput_private.h
@@ -70,6 +70,8 @@ extern void _copy_diactionformatWtoA(LPDIACTIONFORMATA, LPDIACTIONFORMATW) DECLS
 
 extern HRESULT _configure_devices(IDirectInput8W *iface, LPDICONFIGUREDEVICESCALLBACK lpdiCallback, LPDICONFIGUREDEVICESPARAMSW lpdiCDParams, DWORD dwFlags, LPVOID pvRefData) DECLSPEC_HIDDEN;
 
+extern WCHAR* get_mapping_path(const WCHAR *device, const WCHAR *username) DECLSPEC_HIDDEN;
+
 #define IS_DIPROP(x)    (((ULONG_PTR)(x) >> 16) == 0)
 
 #define DIKEYBOARD_MASK    0x81000000
diff --git a/dlls/dinput8/tests/device.c b/dlls/dinput8/tests/device.c
index e5b3f6a..76f9120 100644
--- a/dlls/dinput8/tests/device.c
+++ b/dlls/dinput8/tests/device.c
@@ -458,13 +458,13 @@ static void test_save_settings(void)
     hr = IDirectInputDevice8_BuildActionMap(pKey, &af, NULL, 0);
     ok (SUCCEEDED(hr), "BuildActionMap failed hr=%08x\n", hr);
 
-    todo_wine ok (other_results[0] == af.rgoAction[0].dwObjID,
+    ok (other_results[0] == af.rgoAction[0].dwObjID,
         "Mapped incorrectly expected: 0x%08x got: 0x%08x\n", other_results[0], af.rgoAction[0].dwObjID);
-    todo_wine ok (IsEqualGUID(&GUID_SysKeyboard, &af.rgoAction[0].guidInstance), "Action should be mapped to keyboard\n");
+    ok (IsEqualGUID(&GUID_SysKeyboard, &af.rgoAction[0].guidInstance), "Action should be mapped to keyboard\n");
 
-    todo_wine ok (other_results[1] == af.rgoAction[1].dwObjID,
+    ok (other_results[1] == af.rgoAction[1].dwObjID,
         "Mapped incorrectly expected: 0x%08x got: 0x%08x\n", other_results[1], af.rgoAction[1].dwObjID);
-    todo_wine ok (IsEqualGUID(&GUID_SysKeyboard, &af.rgoAction[1].guidInstance), "Action should be mapped to keyboard\n");
+    ok (IsEqualGUID(&GUID_SysKeyboard, &af.rgoAction[1].guidInstance), "Action should be mapped to keyboard\n");
 }
 
 START_TEST(device)




More information about the wine-cvs mailing list