Skip to content

Instantly share code, notes, and snippets.

@lfzawacki
Created August 20, 2011 18:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lfzawacki/1159426 to your computer and use it in GitHub Desktop.
Save lfzawacki/1159426 to your computer and use it in GitHub Desktop.
Device username patches
From 6933394d92b073d3701860073c7e448cccdd923f Mon Sep 17 00:00:00 2001
From: Lucas Fialho Zawacki <lfzawacki@gmail.com>
Date: Wed, 10 Aug 2011 00:15:00 -0300
Subject: dinput: SetActionMap saving simple configurations to an .ini file
Just the action mapping GUID, number of actions and the time the mapping was applied.
The helper function heap_printfW was copied from winemenubuilder.c
---
dlls/dinput/device.c | 99 ++++++++++++++++++++++++++++++++++++++++++
dlls/dinput/dinput_main.c | 45 +++++++++++++++++++
dlls/dinput/dinput_private.h | 3 +
3 files changed, 147 insertions(+), 0 deletions(-)
diff --git a/dlls/dinput/device.c b/dlls/dinput/device.c
index ead1052..2a233ce 100644
--- a/dlls/dinput/device.c
+++ b/dlls/dinput/device.c
@@ -598,6 +598,94 @@ DWORD semantic_to_obj_id(IDirectInputDeviceImpl* This, DWORD dwSemantic)
return type | (0x0000ff00 & (obj_instance << 8));
}
+/*
+ * _write_private_profile_int_W
+ * An utility function to write an integer, with a specified format, to an .ini file.
+ */
+static void _write_private_profile_intW(const char *format, WCHAR* section, WCHAR* key, int value, WCHAR* file)
+{
+ WCHAR* value_str = heap_printfW(format, value);
+ WritePrivateProfileStringW(section, key, value_str, file);
+ HeapFree(GetProcessHeap(), 0, value_str);
+}
+
+/*
+ * _get_mapping_path
+ * For a given username and device name, returns the filename with path of the
+ * mapping settings files.
+ * The caller has to free the returned string.
+ */
+WCHAR* _get_mapping_path(const WCHAR *device, const WCHAR *username)
+{
+ WCHAR path[] = {
+ '%','C','o','m','m','o','n','P','r','o','g','r','a','m','F','i','l','e','s','%','\\',
+ 'D','i','r','e','c','t','X','\\',
+ 'D','i','r','e','c','t','I','n','p','u','t','\\',
+ 'U','s','e','r',' ','M','a','p','s','\0'};
+ WCHAR *expanded_path, *ret;
+ int expanded_path_size;
+
+ expanded_path_size = ExpandEnvironmentStringsW(path, NULL, 0);
+ expanded_path = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*expanded_path_size);
+ ExpandEnvironmentStringsW(path, expanded_path, expanded_path_size);
+
+ /* The filename is like this: PATH\TO\FILE\USERNAMEX_DEVICEX_0.INI */
+ ret = heap_printfW("%s\\%sX_%sX_0.INI", expanded_path, username, device);
+
+ /* Unallocate */
+ HeapFree(GetProcessHeap(), 0, expanded_path);
+
+ return ret;
+}
+
+static HRESULT _save_mapping_settings(IDirectInputDevice8W *iface, LPDIACTIONFORMATW lpdiaf, LPCWSTR lpszUsername)
+{
+ DIDEVICEINSTANCEW didev;
+ SYSTEMTIME stime;
+ FILETIME ftime;
+ const char* guid_strA;
+ int guid_size;
+
+ WCHAR *map_path, *app_section, *guid_str, *time_high, *time_low;
+ WCHAR mapexists[] = {'M','a','p','E','x','i','s','t','s','\0'};
+ WCHAR numactions[] = {'N','u','m','A','c','t','i','o','n','\0'};
+
+ didev.dwSize = sizeof(didev);
+ IDirectInputDevice8_GetDeviceInfo(iface, &didev);
+
+ map_path = _get_mapping_path(didev.tszInstanceName, lpszUsername);
+
+ /* Guid and Timestamp */
+ guid_strA = debugstr_guid(&lpdiaf->guidActionMap);
+ guid_size = MultiByteToWideChar(CP_ACP, 0, guid_strA, -1, NULL, 0);
+ guid_str = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * guid_size);
+ MultiByteToWideChar(CP_ACP, 0, guid_strA, -1, guid_str, guid_size);
+
+ GetSystemTime(&stime);
+ SystemTimeToFileTime(&stime, &ftime);
+
+ time_high = heap_printfW("%s.TimestampHigh", guid_str);
+ time_low = heap_printfW("%s.TimestampLow", guid_str);
+
+ _write_private_profile_intW("0x%08x", didev.tszInstanceName, time_high, ftime.dwHighDateTime, map_path);
+ _write_private_profile_intW("0x%08x", didev.tszInstanceName, time_low, ftime.dwLowDateTime, map_path);
+
+ /* Device app section */
+ /* Something like this: [DEVICENAME.Application.GUID.Genre.NUMBER] */
+ app_section = heap_printfW("%s.Application.%s.Genre.%d", didev.tszInstanceName, guid_str, HIBYTE(HIWORD(lpdiaf->dwGenre)));
+
+ _write_private_profile_intW("%d", app_section, mapexists, 1, map_path);
+ _write_private_profile_intW("%d", app_section, numactions, lpdiaf->dwNumActions, map_path);
+
+ /* Unallocate everything */
+ HeapFree(GetProcessHeap(), 0, map_path);
+ HeapFree(GetProcessHeap(), 0, guid_str);
+ HeapFree(GetProcessHeap(), 0, time_high);
+ HeapFree(GetProcessHeap(), 0, time_low);
+
+ return DI_OK;
+}
+
HRESULT _build_action_map(LPDIRECTINPUTDEVICE8W iface, LPDIACTIONFORMATW lpdiaf, LPCWSTR lpszUserName, DWORD dwFlags, DWORD devMask, LPCDIDATAFORMAT df)
{
IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8W(iface);
@@ -650,6 +738,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 +812,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_main.c b/dlls/dinput/dinput_main.c
index 6aed515..a6d4a5c 100644
--- a/dlls/dinput/dinput_main.c
+++ b/dlls/dinput/dinput_main.c
@@ -349,6 +349,51 @@ static DWORD _diactionformat_priorityW(LPDIACTIONFORMATW lpdiaf, DWORD genre)
return priorityFlags;
}
+/*
+ * heap_printfW
+ *
+ * An utility function that acts just like sprintfW, but returns a heap allocated WCHAR string.
+ * To make the code that uses it more readable the format is accepted as a CHAR string, but note
+ * that other strings that are eventually used as parameters should be WCHAR.
+ * The caller has to free the returned string.
+ */
+WCHAR* heap_printfW(const char *format, ...)
+{
+ va_list args;
+ int size = 512*sizeof(WCHAR), format_size;
+ WCHAR *buffer, *ret, *formatW = NULL;
+ int n;
+
+ format_size = MultiByteToWideChar(CP_ACP, 0, format, -1, formatW, 0);
+ formatW = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*format_size);
+ MultiByteToWideChar(CP_ACP, 0, format, -1, formatW, format_size);
+
+ va_start(args, format);
+ while (1)
+ {
+ buffer = HeapAlloc(GetProcessHeap(), 0, size);
+ if (buffer == NULL)
+ break;
+ n = vsnprintfW(buffer, size, formatW, args);
+ if (n == -1)
+ size *= 2;
+ else if (n >= size)
+ size = n + 1;
+ else
+ break;
+ HeapFree(GetProcessHeap(), 0, buffer);
+ }
+ va_end(args);
+
+ if (buffer == NULL) return NULL;
+ ret = HeapReAlloc(GetProcessHeap(), 0, buffer, sizeof(WCHAR)*(strlenW(buffer)+1) );
+ if (ret == NULL) ret = buffer;
+
+ HeapFree(GetProcessHeap(), 0, formatW);
+
+ return ret;
+}
+
/******************************************************************************
* IDirectInputA_EnumDevices
*/
diff --git a/dlls/dinput/dinput_private.h b/dlls/dinput/dinput_private.h
index 6427ffa..0cafcab 100644
--- a/dlls/dinput/dinput_private.h
+++ b/dlls/dinput/dinput_private.h
@@ -66,6 +66,9 @@ typedef int (*DI_EVENT_PROC)(LPDIRECTINPUTDEVICE8A, WPARAM, LPARAM);
extern void _copy_diactionformatAtoW(LPDIACTIONFORMATW, LPDIACTIONFORMATA) DECLSPEC_HIDDEN;
extern void _copy_diactionformatWtoA(LPDIACTIONFORMATA, LPDIACTIONFORMATW) DECLSPEC_HIDDEN;
+extern WCHAR* heap_printfW(const char *format, ...) DECLSPEC_HIDDEN;
+extern WCHAR* _get_mapping_path(const WCHAR *device, const WCHAR *username) DECLSPEC_HIDDEN;
+
extern HRESULT _configure_devices(LPDIRECTINPUT8W iface, LPDICONFIGUREDEVICESCALLBACK lpdiCallback, LPDICONFIGUREDEVICESPARAMSW lpdiCDParams, DWORD dwFlags, LPVOID pvRefData, HINSTANCE hinstance) DECLSPEC_HIDDEN;
#define IS_DIPROP(x) (((ULONG_PTR)(x) >> 16) == 0)
--
1.7.0.4
From 221d38a58de40e0e49f08a396cbabbcfd8ec2d87 Mon Sep 17 00:00:00 2001
From: Lucas Fialho Zawacki <lfzawacki@gmail.com>
Date: Thu, 11 Aug 2011 23:38:49 -0300
Subject: dinput: SetActionMap setting username
---
dlls/dinput/device.c | 8 ++++++++
dlls/dinput/device_private.h | 1 +
2 files changed, 9 insertions(+), 0 deletions(-)
diff --git a/dlls/dinput/device.c b/dlls/dinput/device.c
index 2a233ce..81a79ab 100644
--- a/dlls/dinput/device.c
+++ b/dlls/dinput/device.c
@@ -818,6 +818,11 @@ HRESULT _set_action_map(LPDIRECTINPUTDEVICE8W iface, LPDIACTIONFORMATW lpdiaf, L
else
lstrcpynW(username, lpszUserName, MAX_PATH);
+ /* Set username */
+ HeapFree(GetProcessHeap(), 0, This->username);
+ This->username = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * (lstrlenW(username) + 1));
+ lstrcpyW(This->username, username);
+
/* Save the settings to disk */
_save_mapping_settings(iface, lpdiaf, username);
@@ -1051,6 +1056,9 @@ ULONG WINAPI IDirectInputDevice2WImpl_Release(LPDIRECTINPUTDEVICE8W iface)
/* Free action mapping */
HeapFree(GetProcessHeap(), 0, This->action_map);
+ /* Free username */
+ HeapFree(GetProcessHeap(), 0, This->username);
+
EnterCriticalSection( &This->dinput->crit );
list_remove( &This->entry );
LeaveCriticalSection( &This->dinput->crit );
diff --git a/dlls/dinput/device_private.h b/dlls/dinput/device_private.h
index 347c642..ca452b9 100644
--- a/dlls/dinput/device_private.h
+++ b/dlls/dinput/device_private.h
@@ -81,6 +81,7 @@ struct IDirectInputDeviceImpl
/* Action mapping */
int num_actions; /* number of actions mapped */
ActionMap *action_map; /* array of mappings */
+ WCHAR *username; /* username of the device assigned owner */
};
extern BOOL get_app_key(HKEY*, HKEY*) DECLSPEC_HIDDEN;
--
1.7.0.4
From c5abd001e4b49d46421cfa99d9d64b4c8f3b0484 Mon Sep 17 00:00:00 2001
From: Lucas Fialho Zawacki <lfzawacki@gmail.com>
Date: Mon, 15 Aug 2011 23:26:02 -0300
Subject: dinput: Device username being assigned at creation time
---
dlls/dinput/device.c | 57 +++++++++++++++++++++++++++++++++++++
dlls/dinput/device_private.h | 2 +
dlls/dinput/joystick_linux.c | 3 ++
dlls/dinput/joystick_linuxinput.c | 3 ++
dlls/dinput/joystick_osx.c | 3 ++
dlls/dinput/keyboard.c | 3 ++
dlls/dinput/mouse.c | 3 ++
7 files changed, 74 insertions(+), 0 deletions(-)
diff --git a/dlls/dinput/device.c b/dlls/dinput/device.c
index 81a79ab..c40658d 100644
--- a/dlls/dinput/device.c
+++ b/dlls/dinput/device.c
@@ -610,6 +610,63 @@ static void _write_private_profile_intW(const char *format, WCHAR* section, WCHA
}
/*
+ * _get_mapping_username
+ * Retrieves a device username from the respective mapping file.
+ * The caller has to free the returned string.
+ */
+WCHAR * _get_mapping_username(IDirectInputDeviceImpl *This)
+{
+ static WCHAR fake_username[] = {'*','\0'};
+ WCHAR username[MAX_PATH];
+ WCHAR *ret, *map_path;
+ WIN32_FIND_DATAW find_data;
+ DIDEVICEINSTANCEW didevi;
+ FILETIME most_recent, created;
+ HANDLE handle;
+ int found = 0;
+
+ didevi.dwSize = sizeof(didevi);
+ IDirectInputDevice_GetDeviceInfo(&This->IDirectInputDevice8W_iface, &didevi);
+
+ /* This path is used to find usernames. Something like: PATH\TO\FILE\*X_DEVICEX_0.INI */
+ map_path = _get_mapping_path(didevi.tszInstanceName, fake_username);
+
+ /* We are only interested in the creation time */
+ GetProcessTimes(GetCurrentProcess(), &created, &most_recent, &most_recent, &most_recent);
+ most_recent = created;
+
+ /* Step through each possible username file */
+ handle = FindFirstFileW(map_path, &find_data);
+ do
+ {
+ /* If file was writen to after the proccess was initiated */
+ if (CompareFileTime(&find_data.ftLastWriteTime, &created) > 0)
+ {
+ /* If it is more recent than all the other files */
+ if (CompareFileTime(&find_data.ftLastWriteTime, &most_recent) > 0)
+ {
+ WCHAR delimiter[] = {'X','_','\0'};
+ WCHAR *end;
+
+ /* Store filetime as most recent and retrieve the username */
+ most_recent = find_data.ftLastWriteTime;
+ end = strstrW(find_data.cFileName, delimiter);
+ memcpy(username, find_data.cFileName, (end - find_data.cFileName) * sizeof(WCHAR));
+ username[end-find_data.cFileName] = '\0';
+ found = 1;
+ }
+ }
+ } while (FindNextFileW(handle, &find_data));
+
+ ret = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*lstrlenW(username)+1);
+ lstrcpynW(ret, username, lstrlenW(username));
+
+ HeapFree(GetProcessHeap(), 0, map_path);
+
+ return found ? ret : NULL;
+}
+
+/*
* _get_mapping_path
* For a given username and device name, returns the filename with path of the
* mapping settings files.
diff --git a/dlls/dinput/device_private.h b/dlls/dinput/device_private.h
index ca452b9..8c82747 100644
--- a/dlls/dinput/device_private.h
+++ b/dlls/dinput/device_private.h
@@ -95,6 +95,8 @@ extern void queue_event(LPDIRECTINPUTDEVICE8A iface, int inst_id, DWORD data, DW
extern int id_to_object(LPCDIDATAFORMAT df, int id) DECLSPEC_HIDDEN;
extern int find_property(const DataFormat *df, LPCDIPROPHEADER ph) DECLSPEC_HIDDEN;
+extern WCHAR* _get_mapping_username(IDirectInputDeviceImpl *This) DECLSPEC_HIDDEN;
+
/* Common joystick stuff */
typedef struct
{
diff --git a/dlls/dinput/joystick_linux.c b/dlls/dinput/joystick_linux.c
index 3ad592d..232c898 100644
--- a/dlls/dinput/joystick_linux.c
+++ b/dlls/dinput/joystick_linux.c
@@ -348,6 +348,9 @@ static HRESULT alloc_device(REFGUID rguid, IDirectInputImpl *dinput,
if (hr != DI_OK)
goto FAILED1;
+ /* If the device was assigned a username with SetActionMap, retrieve it */
+ newDevice->generic.base.username = _get_mapping_username(&newDevice->generic.base);
+
/* Create copy of default data format */
if (!(df = HeapAlloc(GetProcessHeap(), 0, c_dfDIJoystick2.dwSize))) goto FAILED;
memcpy(df, &c_dfDIJoystick2, c_dfDIJoystick2.dwSize);
diff --git a/dlls/dinput/joystick_linuxinput.c b/dlls/dinput/joystick_linuxinput.c
index a88391c..11a7b47 100644
--- a/dlls/dinput/joystick_linuxinput.c
+++ b/dlls/dinput/joystick_linuxinput.c
@@ -473,6 +473,9 @@ static JoystickImpl *alloc_device(REFGUID rguid, IDirectInputImpl *dinput, unsig
/* do any user specified configuration */
if (setup_dinput_options(&newDevice->generic, default_axis_map) != DI_OK) goto failed;
+ /* If the device was assigned a username with SetActionMap, retrieve it */
+ newDevice->generic.base.username = _get_mapping_username(&newDevice->generic.base);
+
/* Create copy of default data format */
if (!(df = HeapAlloc(GetProcessHeap(), 0, c_dfDIJoystick2.dwSize))) goto failed;
memcpy(df, &c_dfDIJoystick2, c_dfDIJoystick2.dwSize);
diff --git a/dlls/dinput/joystick_osx.c b/dlls/dinput/joystick_osx.c
index cbd005c..e5bbcf9 100644
--- a/dlls/dinput/joystick_osx.c
+++ b/dlls/dinput/joystick_osx.c
@@ -777,6 +777,9 @@ static HRESULT alloc_device(REFGUID rguid, IDirectInputImpl *dinput,
InitializeCriticalSection(&newDevice->generic.base.crit);
newDevice->generic.base.crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": JoystickImpl*->generic.base.crit");
+ /* If the device was assigned a username with SetActionMap, retrieve it */
+ newDevice->generic.base.username = _get_mapping_username(&newDevice->generic.base);
+
/* Create copy of default data format */
if (!(df = HeapAlloc(GetProcessHeap(), 0, c_dfDIJoystick2.dwSize))) goto FAILED;
memcpy(df, &c_dfDIJoystick2, c_dfDIJoystick2.dwSize);
diff --git a/dlls/dinput/keyboard.c b/dlls/dinput/keyboard.c
index 4de8692..4877469 100644
--- a/dlls/dinput/keyboard.c
+++ b/dlls/dinput/keyboard.c
@@ -236,6 +236,9 @@ static SysKeyboardImpl *alloc_device(REFGUID rguid, IDirectInputImpl *dinput)
InitializeCriticalSection(&newDevice->base.crit);
newDevice->base.crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": SysKeyboardImpl*->base.crit");
+ /* If the device was assigned a username with SetActionMap, retrieve it */
+ newDevice->base.username = _get_mapping_username(&newDevice->base);
+
/* Create copy of default data format */
if (!(df = HeapAlloc(GetProcessHeap(), 0, c_dfDIKeyboard.dwSize))) goto failed;
memcpy(df, &c_dfDIKeyboard, c_dfDIKeyboard.dwSize);
diff --git a/dlls/dinput/mouse.c b/dlls/dinput/mouse.c
index 011deb0..2890f93 100644
--- a/dlls/dinput/mouse.c
+++ b/dlls/dinput/mouse.c
@@ -227,6 +227,9 @@ static SysMouseImpl *alloc_device(REFGUID rguid, IDirectInputImpl *dinput)
if (appkey) RegCloseKey(appkey);
if (hkey) RegCloseKey(hkey);
+ /* If the device was assigned a username with SetActionMap, retrieve it */
+ newDevice->base.username = _get_mapping_username(&newDevice->base);
+
/* Create copy of default data format */
if (!(df = HeapAlloc(GetProcessHeap(), 0, c_dfDIMouse2.dwSize))) goto failed;
memcpy(df, &c_dfDIMouse2, c_dfDIMouse2.dwSize);
--
1.7.0.4
From fb29d74766bb26f98256f075f9f2fc2240deae11 Mon Sep 17 00:00:00 2001
From: Lucas Fialho Zawacki <lfzawacki@gmail.com>
Date: Sat, 13 Aug 2011 18:09:45 -0300
Subject: dinput: GetProperty for DIPROP_USERNAME
---
dlls/dinput/device.c | 12 ++++++++++++
dlls/dinput8/tests/device.c | 4 ++--
2 files changed, 14 insertions(+), 2 deletions(-)
diff --git a/dlls/dinput/device.c b/dlls/dinput/device.c
index c40658d..1068660 100644
--- a/dlls/dinput/device.c
+++ b/dlls/dinput/device.c
@@ -1270,6 +1270,18 @@ HRESULT WINAPI IDirectInputDevice2WImpl_GetProperty(LPDIRECTINPUTDEVICE8W iface,
case (DWORD_PTR) DIPROP_VIDPID:
FIXME("DIPROP_VIDPID not implemented\n");
return DIERR_UNSUPPORTED;
+ case (DWORD_PTR) DIPROP_USERNAME:
+ {
+ LPDIPROPSTRING ps = (LPDIPROPSTRING)pdiph;
+
+ if (pdiph->dwSize != sizeof(DIPROPSTRING)) return DIERR_INVALIDPARAM;
+
+ if (This->username == NULL) return S_FALSE;
+
+ lstrcpynW(ps->wsz, This->username, MAX_PATH);
+ TRACE("username = %s\n", debugstr_w(ps->wsz));
+ break;
+ }
default:
FIXME("Unknown property %s\n", debugstr_guid(rguid));
return DIERR_INVALIDPARAM;
diff --git a/dlls/dinput8/tests/device.c b/dlls/dinput8/tests/device.c
index 29ac1fb..b7e7420 100644
--- a/dlls/dinput8/tests/device.c
+++ b/dlls/dinput8/tests/device.c
@@ -190,8 +190,8 @@ static BOOL CALLBACK enumeration_callback(
dps.diph.dwHow = DIPH_DEVICE;
hr = IDirectInputDevice_GetProperty(lpdid, DIPROP_USERNAME, &dps.diph);
- todo_wine ok (SUCCEEDED(hr), "GetProperty failed hr=%08x\n", hr);
- todo_wine ok (!lstrcmpW(usernameW, dps.wsz), "Username not set correctly expected=%s, got=%s\n", wine_dbgstr_wn(usernameW, -1), wine_dbgstr_wn(dps.wsz,-1));
+ ok (SUCCEEDED(hr), "GetProperty failed hr=%08x\n", hr);
+ ok (!lstrcmpW(usernameW, dps.wsz), "Username not set correctly expected=%s, got=%s\n", wine_dbgstr_wn(usernameW, -1), wine_dbgstr_wn(dps.wsz,-1));
/* Test buffer size */
memset(&dp, 0, sizeof(dp));
--
1.7.0.4
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment