https://git.reactos.org/?p=reactos.git;a=commitdiff;h=41c8c312e1a167c179a55…
commit 41c8c312e1a167c179a557a3a435e0bd108b39af
Author: Amine Khaldi <amine.khaldi(a)reactos.org>
AuthorDate: Sat Oct 26 13:03:34 2019 +0100
Commit: Amine Khaldi <amine.khaldi(a)reactos.org>
CommitDate: Sat Oct 26 13:03:34 2019 +0100
[DINPUT] Sync with Wine Staging 4.18. CORE-16441
---
dll/directx/wine/dinput/CMakeLists.txt | 2 +-
dll/directx/wine/dinput/config.c | 203 +++++++++++++------
dll/directx/wine/dinput/device.c | 212 +++++++++++++++-----
dll/directx/wine/dinput/device_private.h | 5 +
dll/directx/wine/dinput/dinput_main.c | 124 +++++++-----
dll/directx/wine/dinput/dinput_private.h | 1 +
dll/directx/wine/dinput/effect_linuxinput.c | 6 +-
dll/directx/wine/dinput/joystick.c | 271 +++++++++++++++++++-------
dll/directx/wine/dinput/joystick_linux.c | 118 ++++++++---
dll/directx/wine/dinput/joystick_linuxinput.c | 255 +++++++++++++++++-------
dll/directx/wine/dinput/joystick_osx.c | 116 +++++++++--
dll/directx/wine/dinput/joystick_private.h | 5 +
dll/directx/wine/dinput/keyboard.c | 21 +-
dll/directx/wine/dinput/mouse.c | 24 ++-
dll/directx/wine/dinput/precomp.h | 2 -
media/doc/README.WINE | 2 +-
16 files changed, 996 insertions(+), 371 deletions(-)
diff --git a/dll/directx/wine/dinput/CMakeLists.txt
b/dll/directx/wine/dinput/CMakeLists.txt
index 7244903e99f..638312f44b9 100644
--- a/dll/directx/wine/dinput/CMakeLists.txt
+++ b/dll/directx/wine/dinput/CMakeLists.txt
@@ -1,5 +1,5 @@
-add_definitions(-D__WINESRC__)
+add_definitions(-D__WINESRC__ -DDIRECTINPUT_VERSION=0x0700)
include_directories(${REACTOS_SOURCE_DIR}/sdk/include/reactos/wine)
spec2def(dinput.dll dinput.spec ADD_IMPORTLIB)
diff --git a/dll/directx/wine/dinput/config.c b/dll/directx/wine/dinput/config.c
index 885f1f4b8ee..b8a280adac7 100644
--- a/dll/directx/wine/dinput/config.c
+++ b/dll/directx/wine/dinput/config.c
@@ -18,17 +18,23 @@
#define NONAMELESSUNION
+
#include "wine/unicode.h"
#include "objbase.h"
#include "dinput_private.h"
#include "device_private.h"
#include "resource.h"
+#include "wine/heap.h"
+
typedef struct {
int nobjects;
IDirectInputDevice8W *lpdid;
DIDEVICEINSTANCEW ddi;
DIDEVICEOBJECTINSTANCEW ddo[256];
+ /* ActionFormat for every user.
+ * In same order as ConfigureDevicesData usernames */
+ DIACTIONFORMATW *user_afs;
} DeviceData;
typedef struct {
@@ -38,10 +44,11 @@ typedef struct {
typedef struct {
IDirectInput8W *lpDI;
- LPDIACTIONFORMATW lpdiaf;
LPDIACTIONFORMATW original_lpdiaf;
DIDevicesData devices_data;
int display_only;
+ int nusernames;
+ WCHAR **usernames;
} ConfigureDevicesData;
/*
@@ -57,27 +64,43 @@ static BOOL CALLBACK collect_objects(LPCDIDEVICEOBJECTINSTANCEW lpddo,
LPVOID pv
return DIENUM_CONTINUE;
}
-static BOOL CALLBACK count_devices(LPCDIDEVICEINSTANCEW lpddi, IDirectInputDevice8W
*lpdid, DWORD dwFlags, DWORD dwRemaining, LPVOID pvRef)
+static BOOL CALLBACK collect_devices(LPCDIDEVICEINSTANCEW lpddi, IDirectInputDevice8W
*lpdid, DWORD dwFlags, DWORD dwRemaining, LPVOID pvRef)
{
- DIDevicesData *data = (DIDevicesData*) pvRef;
+ ConfigureDevicesData *data = (ConfigureDevicesData*) pvRef;
+ DeviceData *device;
+ int i, j;
- data->ndevices++;
- return DIENUM_CONTINUE;
-}
+ IDirectInputDevice_AddRef(lpdid);
-static BOOL CALLBACK collect_devices(LPCDIDEVICEINSTANCEW lpddi, IDirectInputDevice8W
*lpdid, DWORD dwFlags, DWORD dwRemaining, LPVOID pvRef)
-{
- DIDevicesData *data = (DIDevicesData*) pvRef;
- DeviceData *device = &data->devices[data->ndevices];
+ /* alloc array for devices if this is our first device */
+ if (!data->devices_data.ndevices)
+ data->devices_data.devices = HeapAlloc(GetProcessHeap(), 0, sizeof(DeviceData)
* (dwRemaining + 1));
+ device = &data->devices_data.devices[data->devices_data.ndevices];
device->lpdid = lpdid;
device->ddi = *lpddi;
- IDirectInputDevice_AddRef(lpdid);
-
device->nobjects = 0;
IDirectInputDevice_EnumObjects(lpdid, collect_objects, (LPVOID) device, DIDFT_ALL);
- data->ndevices++;
+ device->user_afs = heap_alloc(sizeof(*device->user_afs) *
data->nusernames);
+ memset(device->user_afs, 0, sizeof(*device->user_afs) * data->nusernames);
+ for (i = 0; i < data->nusernames; i++)
+ {
+ DIACTIONFORMATW *user_af = &device->user_afs[i];
+ user_af->dwNumActions = data->original_lpdiaf->dwNumActions;
+ user_af->guidActionMap = data->original_lpdiaf->guidActionMap;
+ user_af->rgoAction = heap_alloc(sizeof(DIACTIONW) *
data->original_lpdiaf->dwNumActions);
+ memset(user_af->rgoAction, 0, sizeof(DIACTIONW) *
data->original_lpdiaf->dwNumActions);
+ for (j = 0; j < user_af->dwNumActions; j++)
+ {
+ user_af->rgoAction[j].dwSemantic =
data->original_lpdiaf->rgoAction[j].dwSemantic;
+ user_af->rgoAction[j].dwFlags =
data->original_lpdiaf->rgoAction[j].dwFlags;
+ user_af->rgoAction[j].u.lptszActionName =
data->original_lpdiaf->rgoAction[j].u.lptszActionName;
+ }
+ IDirectInputDevice8_BuildActionMap(lpdid, user_af, data->usernames[i], 0);
+ }
+
+ data->devices_data.ndevices++;
return DIENUM_CONTINUE;
}
@@ -170,10 +193,18 @@ static DeviceData* get_cur_device(HWND dialog)
return &data->devices_data.devices[sel];
}
-static LPDIACTIONFORMATW get_cur_lpdiaf(HWND dialog)
+static DIACTIONFORMATW *get_cur_lpdiaf(HWND dialog)
{
ConfigureDevicesData *data = (ConfigureDevicesData*) GetWindowLongPtrW(dialog,
DWLP_USER);
- return data->lpdiaf;
+ int controller_sel = SendDlgItemMessageW(dialog, IDC_CONTROLLERCOMBO, CB_GETCURSEL,
0, 0);
+ int player_sel = SendDlgItemMessageW(dialog, IDC_PLAYERCOMBO, CB_GETCURSEL, 0, 0);
+ return &data->devices_data.devices[controller_sel].user_afs[player_sel];
+}
+
+static DIACTIONFORMATW *get_original_lpdiaf(HWND dialog)
+{
+ ConfigureDevicesData *data = (ConfigureDevicesData*) GetWindowLongPtrW(dialog,
DWLP_USER);
+ return data->original_lpdiaf;
}
static int dialog_display_only(HWND dialog)
@@ -182,40 +213,36 @@ static int dialog_display_only(HWND dialog)
return data->display_only;
}
-static void init_devices(HWND dialog, IDirectInput8W *lpDI, DIDevicesData *data,
LPDIACTIONFORMATW lpdiaf)
+static void init_devices(HWND dialog, ConfigureDevicesData *data)
{
int i;
- /* Count devices */
- data->ndevices = 0;
- IDirectInput8_EnumDevicesBySemantics(lpDI, NULL, lpdiaf, count_devices, (LPVOID)
data, 0);
-
- /* Allocate devices */
- data->devices = HeapAlloc(GetProcessHeap(), 0, sizeof(DeviceData) *
data->ndevices);
-
/* Collect and insert */
- data->ndevices = 0;
- IDirectInput8_EnumDevicesBySemantics(lpDI, NULL, lpdiaf, collect_devices, (LPVOID)
data, 0);
+ data->devices_data.ndevices = 0;
+ IDirectInput8_EnumDevicesBySemantics(data->lpDI, NULL, data->original_lpdiaf,
collect_devices, (LPVOID) data, 0);
- for (i=0; i < data->ndevices; i++)
- SendDlgItemMessageW(dialog, IDC_CONTROLLERCOMBO, CB_ADDSTRING, 0, (LPARAM)
data->devices[i].ddi.tszProductName );
+ for (i = 0; i < data->devices_data.ndevices; i++)
+ SendDlgItemMessageW(dialog, IDC_CONTROLLERCOMBO, CB_ADDSTRING, 0, (LPARAM)
data->devices_data.devices[i].ddi.tszProductName );
+ for (i = 0; i < data->nusernames; i++)
+ SendDlgItemMessageW(dialog, IDC_PLAYERCOMBO, CB_ADDSTRING, 0, (LPARAM)
data->usernames[i]);
}
static void destroy_data(HWND dialog)
{
- int i;
+ int i, j;
ConfigureDevicesData *data = (ConfigureDevicesData*) GetWindowLongPtrW(dialog,
DWLP_USER);
DIDevicesData *devices_data = &data->devices_data;
/* Free the devices */
for (i=0; i < devices_data->ndevices; i++)
+ {
IDirectInputDevice8_Release(devices_data->devices[i].lpdid);
+ for (j=0; j < data->nusernames; j++)
+ heap_free(devices_data->devices[i].user_afs[j].rgoAction);
+ heap_free(devices_data->devices[i].user_afs);
+ }
HeapFree(GetProcessHeap(), 0, devices_data->devices);
-
- /* Free the backup LPDIACTIONFORMATW */
- HeapFree(GetProcessHeap(), 0, data->original_lpdiaf->rgoAction);
- HeapFree(GetProcessHeap(), 0, data->original_lpdiaf);
}
static void fill_device_object_list(HWND dialog)
@@ -231,6 +258,7 @@ static void fill_device_object_list(HWND dialog)
/* Add each object */
for (i=0; i < device->nobjects; i++)
{
+ DWORD ddo_inst, ddo_type;
int action = -1;
item.mask = LVIF_TEXT | LVIF_PARAM;
@@ -241,12 +269,20 @@ static void fill_device_object_list(HWND dialog)
/* Add the item */
SendDlgItemMessageW(dialog, IDC_DEVICEOBJECTSLIST, LVM_INSERTITEMW, 0, (LPARAM)
&item);
+ ddo_inst = DIDFT_GETINSTANCE(device->ddo[i].dwType);
+ ddo_type = DIDFT_GETTYPE(device->ddo[i].dwType);
- /* Search for an assigned action for this device */
+ /* Search for an assigned action for this device */
for (j=0; j < lpdiaf->dwNumActions; j++)
{
+ DWORD af_inst = DIDFT_GETINSTANCE(lpdiaf->rgoAction[j].dwObjID);
+ DWORD af_type = DIDFT_GETTYPE(lpdiaf->rgoAction[j].dwObjID);
+ if (af_type == DIDFT_PSHBUTTON) af_type = DIDFT_BUTTON;
+ if (af_type == DIDFT_RELAXIS) af_type = DIDFT_AXIS;
+ /* NOTE previously compared dwType == dwObjId but default buildActionMap
actions
+ * were PSHBUTTON and RELAXS and didnt show up on config */
if (IsEqualGUID(&lpdiaf->rgoAction[j].guidInstance,
&device->ddi.guidInstance) &&
- lpdiaf->rgoAction[j].dwObjID == device->ddo[i].dwType)
+ ddo_inst == af_inst && ddo_type & af_type)
{
action = j;
break;
@@ -260,7 +296,7 @@ static void fill_device_object_list(HWND dialog)
static void show_suitable_actions(HWND dialog)
{
DeviceData *device = get_cur_device(dialog);
- LPDIACTIONFORMATW lpdiaf = get_cur_lpdiaf(dialog);
+ LPDIACTIONFORMATW lpdiaf = get_original_lpdiaf(dialog);
int i, added = 0;
int obj = lv_get_cur_item(dialog);
@@ -298,10 +334,13 @@ static void assign_action(HWND dialog)
int obj = lv_get_cur_item(dialog);
int old_action = lv_get_item_data(dialog, obj);
int used_obj;
-
- DIDEVICEOBJECTINSTANCEW ddo = device->ddo[obj];
+ DWORD type;
if (old_action == action) return;
+ if (obj < 0) return;
+ if (lpdiaf->rgoAction[old_action].dwFlags & DIA_APPFIXED) return;
+
+ type = device->ddo[obj].dwType;
/* Clear old action */
if (old_action != -1)
@@ -320,7 +359,7 @@ static void assign_action(HWND dialog)
lv_set_action(dialog, used_obj, -1, lpdiaf);
/* Set new action */
- lpdiaf->rgoAction[action].dwObjID = ddo.dwType;
+ lpdiaf->rgoAction[action].dwObjID = type;
lpdiaf->rgoAction[action].guidInstance = device->ddi.guidInstance;
lpdiaf->rgoAction[action].dwHow = DIAH_USERCONFIG;
@@ -328,24 +367,35 @@ static void assign_action(HWND dialog)
lv_set_action(dialog, obj, action, lpdiaf);
}
-static void copy_actions(LPDIACTIONFORMATW to, LPDIACTIONFORMATW from)
+static void reset_actions(HWND dialog)
{
- DWORD i;
- for (i=0; i < from->dwNumActions; i++)
+ ConfigureDevicesData *data = (ConfigureDevicesData*) GetWindowLongPtrW(dialog,
DWLP_USER);
+ DIDevicesData *ddata = (DIDevicesData*) &data->devices_data;
+ unsigned i, j;
+
+ for (i = 0; i < data->devices_data.ndevices; i++)
{
- to->rgoAction[i].guidInstance = from->rgoAction[i].guidInstance;
- to->rgoAction[i].dwObjID = from->rgoAction[i].dwObjID;
- to->rgoAction[i].dwHow = from->rgoAction[i].dwHow;
- to->rgoAction[i].u.lptszActionName = from->rgoAction[i].u.lptszActionName;
+ DeviceData *device = &ddata->devices[i];
+ for (j = 0; j < data->nusernames; j++)
+ IDirectInputDevice8_BuildActionMap(device->lpdid,
&device->user_afs[j], data->usernames[j], DIDBAM_HWDEFAULTS);
}
}
-static void reset_actions(HWND dialog)
-{
+static void save_actions(HWND dialog) {
ConfigureDevicesData *data = (ConfigureDevicesData*) GetWindowLongPtrW(dialog,
DWLP_USER);
- LPDIACTIONFORMATW to = data->lpdiaf, from = data->original_lpdiaf;
-
- copy_actions(to, from);
+ DIDevicesData *ddata = (DIDevicesData*) &data->devices_data;
+ unsigned i, j;
+ if (!data->display_only) {
+ for (i = 0; i < ddata->ndevices; i++)
+ {
+ DeviceData *device = &ddata->devices[i];
+ for (j = 0; j < data->nusernames; j++)
+ {
+ if (save_mapping_settings(device->lpdid, &device->user_afs[j],
data->usernames[j]) != DI_OK)
+ MessageBoxA(dialog, "Could not save settings", 0,
MB_ICONERROR);
+ }
+ }
+ }
}
static INT_PTR CALLBACK ConfigureDevicesDlgProc(HWND dialog, UINT uMsg, WPARAM wParam,
LPARAM lParam)
@@ -357,26 +407,27 @@ static INT_PTR CALLBACK ConfigureDevicesDlgProc(HWND dialog, UINT
uMsg, WPARAM w
ConfigureDevicesData *data = (ConfigureDevicesData*) lParam;
/* Initialize action format and enumerate devices */
- init_devices(dialog, data->lpDI, &data->devices_data,
data->lpdiaf);
+ init_devices(dialog, data);
/* Store information in the window */
SetWindowLongPtrW(dialog, DWLP_USER, (LONG_PTR) data);
init_listview_columns(dialog);
- /* Create a backup action format for CANCEL and RESET operations */
- data->original_lpdiaf = HeapAlloc(GetProcessHeap(), 0,
sizeof(*data->original_lpdiaf));
- data->original_lpdiaf->dwNumActions =
data->lpdiaf->dwNumActions;
- data->original_lpdiaf->rgoAction = HeapAlloc(GetProcessHeap(), 0,
sizeof(DIACTIONW)*data->lpdiaf->dwNumActions);
- copy_actions(data->original_lpdiaf, data->lpdiaf);
-
/* Select the first device and show its actions */
SendDlgItemMessageW(dialog, IDC_CONTROLLERCOMBO, CB_SETCURSEL, 0, 0);
+ SendDlgItemMessageW(dialog, IDC_PLAYERCOMBO, CB_SETCURSEL, 0, 0);
fill_device_object_list(dialog);
+ ShowCursor(TRUE);
+
break;
}
+ case WM_DESTROY:
+ ShowCursor(FALSE);
+ break;
+
case WM_NOTIFY:
switch (((LPNMHDR)lParam)->code)
@@ -407,6 +458,7 @@ static INT_PTR CALLBACK ConfigureDevicesDlgProc(HWND dialog, UINT
uMsg, WPARAM w
break;
case IDC_CONTROLLERCOMBO:
+ case IDC_PLAYERCOMBO:
switch (HIWORD(wParam))
{
@@ -417,12 +469,12 @@ static INT_PTR CALLBACK ConfigureDevicesDlgProc(HWND dialog, UINT
uMsg, WPARAM w
break;
case IDOK:
+ save_actions(dialog);
EndDialog(dialog, 0);
destroy_data(dialog);
break;
case IDCANCEL:
- reset_actions(dialog);
EndDialog(dialog, 0);
destroy_data(dialog);
break;
@@ -445,15 +497,48 @@ HRESULT _configure_devices(IDirectInput8W *iface,
LPVOID pvRefData
)
{
+ int i;
+ DWORD size;
+ WCHAR *username = NULL;
ConfigureDevicesData data;
data.lpDI = iface;
- data.lpdiaf = lpdiCDParams->lprgFormats;
+ data.original_lpdiaf = lpdiCDParams->lprgFormats;
data.display_only = !(dwFlags & DICD_EDIT);
+ data.nusernames = lpdiCDParams->dwcUsers;
+ if (lpdiCDParams->lptszUserNames == NULL)
+ {
+ /* Get default user name */
+ GetUserNameW(NULL, &size);
+ username = heap_alloc(size * sizeof(WCHAR) );
+ GetUserNameW(username, &size);
+ data.nusernames = 1;
+ data.usernames = heap_alloc(sizeof(WCHAR *));
+ data.usernames[0] = username;
+ }
+ else
+ {
+ WCHAR *p = lpdiCDParams->lptszUserNames;
+ data.usernames = heap_alloc(sizeof(WCHAR *) * data.nusernames);
+ for (i = 0; i < data.nusernames; i++)
+ {
+ if (*p)
+ {
+ data.usernames[i] = p;
+ while (*(p++));
+ }
+ else
+ /* Return if there is an empty string */
+ return DIERR_INVALIDPARAM;
+ }
+ }
InitCommonControls();
DialogBoxParamW(DINPUT_instance, (const WCHAR
*)MAKEINTRESOURCE(IDD_CONFIGUREDEVICES),
lpdiCDParams->hwnd, ConfigureDevicesDlgProc, (LPARAM)&data);
+ heap_free(username);
+ heap_free(data.usernames);
+
return DI_OK;
}
diff --git a/dll/directx/wine/dinput/device.c b/dll/directx/wine/dinput/device.c
index 6c446163d16..df7a22a303b 100644
--- a/dll/directx/wine/dinput/device.c
+++ b/dll/directx/wine/dinput/device.c
@@ -30,6 +30,7 @@
#include <string.h>
#include "wine/debug.h"
#include "wine/unicode.h"
+#include "wine/heap.h"
#include "windef.h"
#include "winbase.h"
#include "winreg.h"
@@ -643,12 +644,29 @@ static DWORD semantic_to_obj_id(IDirectInputDeviceImpl* This, DWORD
dwSemantic)
return type | (0x0000ff00 & (obj_instance << 8));
}
+static void del_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'};
+ WCHAR *keyname;
+
+ keyname = heap_alloc(sizeof(WCHAR) * (lstrlenW(subkey) + strlenW(username) +
strlenW(device) + strlenW(guid)));
+ sprintfW(keyname, subkey, username, device, guid);
+
+ /* Remove old key mappings so there will be no overlapping mappings */
+ RegDeleteKeyW(HKEY_CURRENT_USER, keyname);
+
+ heap_free(keyname);
+}
+
/*
* 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 HKEY get_mapping_key(const WCHAR *device, const WCHAR *username, const WCHAR
*guid, BOOL create)
{
static const WCHAR subkey[] = {
'S','o','f','t','w','a','r','e','\\',
@@ -663,15 +681,18 @@ static HKEY get_mapping_key(const WCHAR *device, const WCHAR
*username, const WC
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;
+ if (create) {
+ if (RegCreateKeyW(HKEY_CURRENT_USER, keyname, &hkey))
+ hkey = 0;
+ } else if (RegOpenKeyW(HKEY_CURRENT_USER, keyname, &hkey))
+ hkey = 0;
HeapFree(GetProcessHeap(), 0, keyname);
return hkey;
}
-static HRESULT save_mapping_settings(IDirectInputDevice8W *iface, LPDIACTIONFORMATW
lpdiaf, LPCWSTR lpszUsername)
+HRESULT save_mapping_settings(IDirectInputDevice8W *iface, LPDIACTIONFORMATW lpdiaf,
LPCWSTR lpszUsername)
{
WCHAR *guid_str = NULL;
DIDEVICEINSTANCEW didev;
@@ -684,7 +705,9 @@ static HRESULT save_mapping_settings(IDirectInputDevice8W *iface,
LPDIACTIONFORM
if (StringFromCLSID(&lpdiaf->guidActionMap, &guid_str) != S_OK)
return DI_SETTINGSNOTSAVED;
- hkey = get_mapping_key(didev.tszInstanceName, lpszUsername, guid_str);
+ del_mapping_key(didev.tszInstanceName, lpszUsername, guid_str);
+
+ hkey = get_mapping_key(didev.tszInstanceName, lpszUsername, guid_str, TRUE);
if (!hkey)
{
@@ -714,12 +737,12 @@ static HRESULT save_mapping_settings(IDirectInputDevice8W *iface,
LPDIACTIONFORM
return DI_OK;
}
-static BOOL load_mapping_settings(IDirectInputDeviceImpl *This, LPDIACTIONFORMATW lpdiaf,
const WCHAR *username)
+BOOL load_mapping_settings(IDirectInputDeviceImpl *This, LPDIACTIONFORMATW lpdiaf, const
WCHAR *username)
{
HKEY hkey;
WCHAR *guid_str;
DIDEVICEINSTANCEW didev;
- int i, mapped = 0;
+ int i;
didev.dwSize = sizeof(didev);
IDirectInputDevice8_GetDeviceInfo(&This->IDirectInputDevice8W_iface,
&didev);
@@ -727,7 +750,7 @@ static BOOL load_mapping_settings(IDirectInputDeviceImpl *This,
LPDIACTIONFORMAT
if (StringFromCLSID(&lpdiaf->guidActionMap, &guid_str) != S_OK)
return FALSE;
- hkey = get_mapping_key(didev.tszInstanceName, username, guid_str);
+ hkey = get_mapping_key(didev.tszInstanceName, username, guid_str, FALSE);
if (!hkey)
{
@@ -748,15 +771,21 @@ static BOOL load_mapping_settings(IDirectInputDeviceImpl *This,
LPDIACTIONFORMAT
{
lpdiaf->rgoAction[i].dwObjID = id;
lpdiaf->rgoAction[i].guidInstance = didev.guidInstance;
- lpdiaf->rgoAction[i].dwHow = DIAH_DEFAULT;
- mapped += 1;
+ lpdiaf->rgoAction[i].dwHow = DIAH_USERCONFIG;
+ }
+ else
+ {
+ memset(&lpdiaf->rgoAction[i].guidInstance, 0, sizeof(GUID));
+ lpdiaf->rgoAction[i].dwHow = DIAH_UNMAPPED;
}
+
}
RegCloseKey(hkey);
CoTaskMemFree(guid_str);
- return mapped > 0;
+ /* On Windows BuildActionMap can open empty mapping, so always return TRUE if
get_mapping_key is success */
+ return TRUE;
}
HRESULT _build_action_map(LPDIRECTINPUTDEVICE8W iface, LPDIACTIONFORMATW lpdiaf, LPCWSTR
lpszUserName, DWORD dwFlags, DWORD devMask, LPCDIDATAFORMAT df)
@@ -779,13 +808,18 @@ HRESULT _build_action_map(LPDIRECTINPUTDEVICE8W iface,
LPDIACTIONFORMATW lpdiaf,
load_success = load_mapping_settings(This, lpdiaf, username);
}
- if (load_success) return DI_OK;
+ if (load_success) {
+ /* Update dwCRC to track if action format has changed */
+ for (i=0; i < lpdiaf->dwNumActions; i++)
+ {
+ lpdiaf->dwCRC ^= (lpdiaf->rgoAction[i].dwObjID << i * 2) |
(lpdiaf->rgoAction[i].dwObjID >> (sizeof(lpdiaf->dwCRC) * 8 - i * 2));
+ lpdiaf->dwCRC ^= (lpdiaf->rgoAction[i].dwSemantic << (i * 2 + 5))
| (lpdiaf->rgoAction[i].dwSemantic >> (sizeof(lpdiaf->dwCRC) * 8 - (i * 2 +
5)));
+ }
+ return DI_OK;
+ }
for (i=0; i < lpdiaf->dwNumActions; i++)
{
- /* Don't touch a user configured action */
- if (lpdiaf->rgoAction[i].dwHow == DIAH_USERCONFIG) continue;
-
if ((lpdiaf->rgoAction[i].dwSemantic & devMask) == devMask)
{
DWORD obj_id = semantic_to_obj_id(This, lpdiaf->rgoAction[i].dwSemantic);
@@ -816,6 +850,14 @@ HRESULT _build_action_map(LPDIRECTINPUTDEVICE8W iface,
LPDIACTIONFORMATW lpdiaf,
}
}
+ /* Update dwCRC to track if action format has changed */
+ lpdiaf->dwCRC = 0;
+ for (i=0; i < lpdiaf->dwNumActions; i++)
+ {
+ lpdiaf->dwCRC ^= (lpdiaf->rgoAction[i].dwObjID << i * 2) |
(lpdiaf->rgoAction[i].dwObjID >> (sizeof(lpdiaf->dwCRC) * 8 - i * 2));
+ lpdiaf->dwCRC ^= (lpdiaf->rgoAction[i].dwSemantic << (i * 2 + 5)) |
(lpdiaf->rgoAction[i].dwSemantic >> (sizeof(lpdiaf->dwCRC) * 8 - (i * 2 +
5)));
+ }
+
if (!has_actions) return DI_NOEFFECT;
return IDirectInputDevice8WImpl_BuildActionMap(iface, lpdiaf, lpszUserName,
dwFlags);
@@ -831,6 +873,7 @@ HRESULT _set_action_map(LPDIRECTINPUTDEVICE8W iface, LPDIACTIONFORMATW
lpdiaf, L
DIPROPSTRING dps;
WCHAR username[MAX_PATH];
DWORD username_size = MAX_PATH;
+ DWORD new_crc = 0;
int i, action = 0, num_actions = 0;
unsigned int offset = 0;
@@ -841,12 +884,30 @@ HRESULT _set_action_map(LPDIRECTINPUTDEVICE8W iface,
LPDIACTIONFORMATW lpdiaf, L
data_format.dwFlags = DIDF_RELAXIS;
data_format.dwDataSize = lpdiaf->dwDataSize;
+ /* Calculate checksum for actionformat */
+ for (i=0; i < lpdiaf->dwNumActions; i++)
+ {
+ new_crc ^= (lpdiaf->rgoAction[i].dwObjID << i * 2) |
(lpdiaf->rgoAction[i].dwObjID >> (sizeof(lpdiaf->dwCRC) * 8 - i * 2));
+ new_crc ^= (lpdiaf->rgoAction[i].dwSemantic << (i * 2 + 5)) |
(lpdiaf->rgoAction[i].dwSemantic >> (sizeof(lpdiaf->dwCRC) * 8 - (i * 2 +
5)));
+ }
+
/* Count the actions */
for (i=0; i < lpdiaf->dwNumActions; i++)
- if (IsEqualGUID(&This->guid, &lpdiaf->rgoAction[i].guidInstance))
+ {
+ if (IsEqualGUID(&This->guid, &lpdiaf->rgoAction[i].guidInstance)
||
+ (IsEqualGUID(&IID_NULL, &lpdiaf->rgoAction[i].guidInstance)
&&
+ ((lpdiaf->rgoAction[i].dwSemantic & lpdiaf->dwGenre) ==
lpdiaf->dwGenre ||
+ (lpdiaf->rgoAction[i].dwSemantic & 0xff000000) == 0xff000000 /*
Any Axis */) ))
+ {
num_actions++;
+ }
+ }
- if (num_actions == 0) return DI_NOEFFECT;
+ /* Should return DI_NOEFFECT if we dont have any actions and actionformat has not
changed */
+ if (num_actions == 0 && lpdiaf->dwCRC == new_crc && !(dwFlags
& DIDSAM_FORCESAVE)) return DI_NOEFFECT;
+
+ /* update dwCRC to track if action format has changed */
+ lpdiaf->dwCRC = new_crc;
This->num_actions = num_actions;
@@ -880,7 +941,39 @@ HRESULT _set_action_map(LPDIRECTINPUTDEVICE8W iface,
LPDIACTIONFORMATW lpdiaf, L
action++;
}
+ else if ((lpdiaf->rgoAction[i].dwSemantic & lpdiaf->dwGenre) ==
lpdiaf->dwGenre ||
+ (lpdiaf->rgoAction[i].dwSemantic & 0xff000000) == 0xff000000 /*
Any Axis */)
+ {
+ DWORD obj_id = semantic_to_obj_id(This, lpdiaf->rgoAction[i].dwSemantic);
+ DWORD type = DIDFT_GETTYPE(obj_id);
+ DWORD inst = DIDFT_GETINSTANCE(obj_id);
+ LPDIOBJECTDATAFORMAT obj;
+
+ if (type == DIDFT_PSHBUTTON) type = DIDFT_BUTTON;
+ else if (type == DIDFT_RELAXIS) type = DIDFT_AXIS;
+
+ obj = dataformat_to_odf_by_type(df, inst, type);
+ TRACE("obj %p, inst 0x%08x, type 0x%08x\n", obj, inst, type);
+ if(obj)
+ {
+ memcpy(&obj_df[action], obj, df->dwObjSize);
+
+ This->action_map[action].uAppData = lpdiaf->rgoAction[i].uAppData;
+ This->action_map[action].offset = offset;
+ obj_df[action].dwOfs = offset;
+ offset += (type & DIDFT_BUTTON) ? 1 : 4;
+
+ action++;
+ }
+ }
+ }
+
+ if (action == 0)
+ {
+ HeapFree(GetProcessHeap(), 0, obj_df);
+ return DI_NOEFFECT;
}
+ data_format.dwNumObjs = action;
IDirectInputDevice8_SetDataFormat(iface, &data_format);
@@ -1140,7 +1233,7 @@ ULONG WINAPI IDirectInputDevice2WImpl_Release(LPDIRECTINPUTDEVICE8W
iface)
IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8W(iface);
ULONG ref = InterlockedDecrement(&(This->ref));
- TRACE("(%p) releasing from %d\n", This, ref + 1);
+ TRACE("(%p) ref %d\n", This, ref);
if (ref) return ref;
@@ -1168,7 +1261,7 @@ ULONG WINAPI IDirectInputDevice2WImpl_Release(LPDIRECTINPUTDEVICE8W
iface)
HeapFree(GetProcessHeap(), 0, This);
- return DI_OK;
+ return ref;
}
ULONG WINAPI IDirectInputDevice2AImpl_Release(LPDIRECTINPUTDEVICE8A iface)
@@ -1181,7 +1274,7 @@ HRESULT WINAPI
IDirectInputDevice2WImpl_QueryInterface(LPDIRECTINPUTDEVICE8W ifa
{
IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8W(iface);
- TRACE("(%p this=%p,%s,%p)\n", iface, This, debugstr_guid(riid), ppobj);
+ TRACE("(%p)->(%s,%p)\n", This, debugstr_guid(riid), ppobj);
if (IsEqualGUID(&IID_IUnknown, riid) ||
IsEqualGUID(&IID_IDirectInputDeviceA, riid) ||
IsEqualGUID(&IID_IDirectInputDevice2A, riid) ||
@@ -1203,7 +1296,7 @@ HRESULT WINAPI
IDirectInputDevice2WImpl_QueryInterface(LPDIRECTINPUTDEVICE8W ifa
}
WARN("Unsupported interface!\n");
- return E_FAIL;
+ return E_NOINTERFACE;
}
HRESULT WINAPI IDirectInputDevice2AImpl_QueryInterface(LPDIRECTINPUTDEVICE8A iface,
REFIID riid, LPVOID *ppobj)
@@ -1215,7 +1308,9 @@ HRESULT WINAPI
IDirectInputDevice2AImpl_QueryInterface(LPDIRECTINPUTDEVICE8A ifa
ULONG WINAPI IDirectInputDevice2WImpl_AddRef(LPDIRECTINPUTDEVICE8W iface)
{
IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8W(iface);
- return InterlockedIncrement(&This->ref);
+ ULONG ref = InterlockedIncrement(&This->ref);
+ TRACE( "(%p) ref %d\n", This, ref );
+ return ref;
}
ULONG WINAPI IDirectInputDevice2AImpl_AddRef(LPDIRECTINPUTDEVICE8A iface)
@@ -1231,7 +1326,7 @@ HRESULT WINAPI
IDirectInputDevice2AImpl_EnumObjects(LPDIRECTINPUTDEVICE8A iface,
DIDEVICEOBJECTINSTANCEA ddoi;
int i;
- TRACE("(%p) %p,%p flags:%08x)\n", iface, lpCallback, lpvRef, dwFlags);
+ TRACE("(%p)->(%p,%p flags:%08x)\n", This, lpCallback, lpvRef, dwFlags);
TRACE(" - flags = ");
_dump_EnumObjects_flags(dwFlags);
TRACE("\n");
@@ -1261,7 +1356,7 @@ HRESULT WINAPI
IDirectInputDevice2WImpl_EnumObjects(LPDIRECTINPUTDEVICE8W iface,
DIDEVICEOBJECTINSTANCEW ddoi;
int i;
- TRACE("(%p) %p,%p flags:%08x)\n", iface, lpCallback, lpvRef, dwFlags);
+ TRACE("(%p)->(%p,%p flags:%08x)\n", This, lpCallback, lpvRef, dwFlags);
TRACE(" - flags = ");
_dump_EnumObjects_flags(dwFlags);
TRACE("\n");
@@ -1292,7 +1387,7 @@ HRESULT WINAPI
IDirectInputDevice2WImpl_GetProperty(LPDIRECTINPUTDEVICE8W iface,
{
IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8W(iface);
- TRACE("(%p) %s,%p\n", iface, debugstr_guid(rguid), pdiph);
+ TRACE("(%p)->(%s,%p)\n", This, debugstr_guid(rguid), pdiph);
_dump_DIPROPHEADER(pdiph);
if (!IS_DIPROP(rguid)) return DI_OK;
@@ -1357,7 +1452,7 @@ HRESULT WINAPI IDirectInputDevice2WImpl_SetProperty(
{
IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8W(iface);
- TRACE("(%p) %s,%p\n", iface, debugstr_guid(rguid), pdiph);
+ TRACE("(%p)->(%s,%p)\n", This, debugstr_guid(rguid), pdiph);
_dump_DIPROPHEADER(pdiph);
if (!IS_DIPROP(rguid)) return DI_OK;
@@ -1596,7 +1691,8 @@ HRESULT WINAPI
IDirectInputDevice2AImpl_GetDeviceData(LPDIRECTINPUTDEVICE8A ifac
HRESULT WINAPI IDirectInputDevice2WImpl_RunControlPanel(LPDIRECTINPUTDEVICE8W iface, HWND
hwndOwner, DWORD dwFlags)
{
- FIXME("(this=%p,%p,0x%08x): stub!\n", iface, hwndOwner, dwFlags);
+ IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8W(iface);
+ FIXME("%p)->(%p,0x%08x): stub!\n", This, hwndOwner, dwFlags);
return DI_OK;
}
@@ -1610,7 +1706,8 @@ HRESULT WINAPI
IDirectInputDevice2AImpl_RunControlPanel(LPDIRECTINPUTDEVICE8A if
HRESULT WINAPI IDirectInputDevice2WImpl_Initialize(LPDIRECTINPUTDEVICE8W iface, HINSTANCE
hinst, DWORD dwVersion,
REFGUID rguid)
{
- FIXME("(this=%p,%p,%d,%s): stub!\n", iface, hinst, dwVersion,
debugstr_guid(rguid));
+ IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8W(iface);
+ FIXME("(%p)->(%p,%d,%s): stub!\n", This, hinst, dwVersion,
debugstr_guid(rguid));
return DI_OK;
}
@@ -1628,7 +1725,8 @@ HRESULT WINAPI
IDirectInputDevice2AImpl_Initialize(LPDIRECTINPUTDEVICE8A iface,
HRESULT WINAPI IDirectInputDevice2WImpl_CreateEffect(LPDIRECTINPUTDEVICE8W iface, REFGUID
rguid, LPCDIEFFECT lpeff,
LPDIRECTINPUTEFFECT *ppdef,
LPUNKNOWN pUnkOuter)
{
- FIXME("(this=%p,%s,%p,%p,%p): stub!\n", iface, debugstr_guid(rguid), lpeff,
ppdef, pUnkOuter);
+ IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8W(iface);
+ FIXME("(%p)->(%s,%p,%p,%p): stub!\n", This, debugstr_guid(rguid), lpeff,
ppdef, pUnkOuter);
FIXME("not available in the generic implementation\n");
*ppdef = NULL;
@@ -1648,9 +1746,9 @@ HRESULT WINAPI IDirectInputDevice2AImpl_EnumEffects(
LPVOID lpvRef,
DWORD dwFlags)
{
- FIXME("(this=%p,%p,%p,0x%08x): stub!\n",
- iface, lpCallback, lpvRef, dwFlags);
-
+ IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8A(iface);
+ FIXME("%p)->(%p,%p,0x%08x): stub!\n", This, lpCallback, lpvRef,
dwFlags);
+
return DI_OK;
}
@@ -1660,9 +1758,9 @@ HRESULT WINAPI IDirectInputDevice2WImpl_EnumEffects(
LPVOID lpvRef,
DWORD dwFlags)
{
- FIXME("(this=%p,%p,%p,0x%08x): stub!\n",
- iface, lpCallback, lpvRef, dwFlags);
-
+ IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8W(iface);
+ FIXME("(%p)->(%p,%p,0x%08x): stub!\n", This, lpCallback, lpvRef,
dwFlags);
+
return DI_OK;
}
@@ -1671,8 +1769,8 @@ HRESULT WINAPI IDirectInputDevice2AImpl_GetEffectInfo(
LPDIEFFECTINFOA lpdei,
REFGUID rguid)
{
- FIXME("(this=%p,%p,%s): stub!\n",
- iface, lpdei, debugstr_guid(rguid));
+ IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8A(iface);
+ FIXME("(%p)->(%p,%s): stub!\n", This, lpdei, debugstr_guid(rguid));
return DI_OK;
}
@@ -1681,14 +1779,15 @@ HRESULT WINAPI IDirectInputDevice2WImpl_GetEffectInfo(
LPDIEFFECTINFOW lpdei,
REFGUID rguid)
{
- FIXME("(this=%p,%p,%s): stub!\n",
- iface, lpdei, debugstr_guid(rguid));
+ IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8W(iface);
+ FIXME("(%p)->(%p,%s): stub!\n", This, lpdei, debugstr_guid(rguid));
return DI_OK;
}
HRESULT WINAPI IDirectInputDevice2WImpl_GetForceFeedbackState(LPDIRECTINPUTDEVICE8W
iface, LPDWORD pdwOut)
{
- FIXME("(this=%p,%p): stub!\n", iface, pdwOut);
+ IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8W(iface);
+ FIXME("(%p)->(%p): stub!\n", This, pdwOut);
return DI_OK;
}
@@ -1700,7 +1799,8 @@ HRESULT WINAPI
IDirectInputDevice2AImpl_GetForceFeedbackState(LPDIRECTINPUTDEVIC
HRESULT WINAPI IDirectInputDevice2WImpl_SendForceFeedbackCommand(LPDIRECTINPUTDEVICE8W
iface, DWORD dwFlags)
{
- TRACE("(%p) 0x%08x:\n", iface, dwFlags);
+ IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8W(iface);
+ TRACE("(%p)->(0x%08x)\n", This, dwFlags);
return DI_NOEFFECT;
}
@@ -1713,7 +1813,8 @@ HRESULT WINAPI
IDirectInputDevice2AImpl_SendForceFeedbackCommand(LPDIRECTINPUTDE
HRESULT WINAPI IDirectInputDevice2WImpl_EnumCreatedEffectObjects(LPDIRECTINPUTDEVICE8W
iface,
LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback, LPVOID lpvRef, DWORD dwFlags)
{
- FIXME("(this=%p,%p,%p,0x%08x): stub!\n", iface, lpCallback, lpvRef,
dwFlags);
+ IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8W(iface);
+ FIXME("(%p)0>(%p,%p,0x%08x): stub!\n", This, lpCallback, lpvRef,
dwFlags);
return DI_OK;
}
@@ -1726,7 +1827,8 @@ HRESULT WINAPI
IDirectInputDevice2AImpl_EnumCreatedEffectObjects(LPDIRECTINPUTDE
HRESULT WINAPI IDirectInputDevice2WImpl_Escape(LPDIRECTINPUTDEVICE8W iface, LPDIEFFESCAPE
lpDIEEsc)
{
- FIXME("(this=%p,%p): stub!\n", iface, lpDIEEsc);
+ IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8W(iface);
+ FIXME("(%p)->(%p): stub!\n", This, lpDIEEsc);
return DI_OK;
}
@@ -1756,7 +1858,8 @@ HRESULT WINAPI
IDirectInputDevice2WImpl_SendDeviceData(LPDIRECTINPUTDEVICE8W ifa
LPCDIDEVICEOBJECTDATA rgdod,
LPDWORD pdwInOut,
DWORD dwFlags)
{
- FIXME("(this=%p,0x%08x,%p,%p,0x%08x): stub!\n", iface, cbObjectData, rgdod,
pdwInOut, dwFlags);
+ IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8W(iface);
+ FIXME("(%p)->(0x%08x,%p,%p,0x%08x): stub!\n", This, cbObjectData, rgdod,
pdwInOut, dwFlags);
return DI_OK;
}
@@ -1776,7 +1879,8 @@ HRESULT WINAPI
IDirectInputDevice7AImpl_EnumEffectsInFile(LPDIRECTINPUTDEVICE8A
LPVOID pvRef,
DWORD dwFlags)
{
- FIXME("(%p)->(%s,%p,%p,%08x): stub !\n", iface, lpszFileName, pec,
pvRef, dwFlags);
+ IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8A(iface);
+ FIXME("(%p)->(%s,%p,%p,%08x): stub !\n", This, lpszFileName, pec, pvRef,
dwFlags);
return DI_OK;
}
@@ -1787,7 +1891,8 @@ HRESULT WINAPI
IDirectInputDevice7WImpl_EnumEffectsInFile(LPDIRECTINPUTDEVICE8W
LPVOID pvRef,
DWORD dwFlags)
{
- FIXME("(%p)->(%s,%p,%p,%08x): stub !\n", iface,
debugstr_w(lpszFileName), pec, pvRef, dwFlags);
+ IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8W(iface);
+ FIXME("(%p)->(%s,%p,%p,%08x): stub !\n", This, debugstr_w(lpszFileName),
pec, pvRef, dwFlags);
return DI_OK;
}
@@ -1798,7 +1903,8 @@ HRESULT WINAPI
IDirectInputDevice7AImpl_WriteEffectToFile(LPDIRECTINPUTDEVICE8A
LPDIFILEEFFECT rgDiFileEft,
DWORD dwFlags)
{
- FIXME("(%p)->(%s,%08x,%p,%08x): stub !\n", iface, lpszFileName,
dwEntries, rgDiFileEft, dwFlags);
+ IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8A(iface);
+ FIXME("(%p)->(%s,%08x,%p,%08x): stub !\n", This, lpszFileName,
dwEntries, rgDiFileEft, dwFlags);
return DI_OK;
}
@@ -1809,7 +1915,8 @@ HRESULT WINAPI
IDirectInputDevice7WImpl_WriteEffectToFile(LPDIRECTINPUTDEVICE8W
LPDIFILEEFFECT rgDiFileEft,
DWORD dwFlags)
{
- FIXME("(%p)->(%s,%08x,%p,%08x): stub !\n", iface,
debugstr_w(lpszFileName), dwEntries, rgDiFileEft, dwFlags);
+ IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8W(iface);
+ FIXME("(%p)->(%s,%08x,%p,%08x): stub !\n", This,
debugstr_w(lpszFileName), dwEntries, rgDiFileEft, dwFlags);
return DI_OK;
}
@@ -1819,7 +1926,8 @@ HRESULT WINAPI
IDirectInputDevice8WImpl_BuildActionMap(LPDIRECTINPUTDEVICE8W ifa
LPCWSTR lpszUserName,
DWORD dwFlags)
{
- FIXME("(%p)->(%p,%s,%08x): semi-stub !\n", iface, lpdiaf,
debugstr_w(lpszUserName), dwFlags);
+ IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8W(iface);
+ FIXME("(%p)->(%p,%s,%08x): semi-stub !\n", This, lpdiaf,
debugstr_w(lpszUserName), dwFlags);
#define X(x) if (dwFlags & x) FIXME("\tdwFlags =|"#x"\n");
X(DIDBAM_DEFAULT)
X(DIDBAM_PRESERVE)
@@ -1833,7 +1941,8 @@ HRESULT WINAPI
IDirectInputDevice8WImpl_BuildActionMap(LPDIRECTINPUTDEVICE8W ifa
HRESULT WINAPI IDirectInputDevice8AImpl_GetImageInfo(LPDIRECTINPUTDEVICE8A iface,
LPDIDEVICEIMAGEINFOHEADERA lpdiDevImageInfoHeader)
{
- FIXME("(%p)->(%p): stub !\n", iface, lpdiDevImageInfoHeader);
+ IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8A(iface);
+ FIXME("(%p)->(%p): stub !\n", This, lpdiDevImageInfoHeader);
return DI_OK;
}
@@ -1841,7 +1950,8 @@ HRESULT WINAPI
IDirectInputDevice8AImpl_GetImageInfo(LPDIRECTINPUTDEVICE8A iface
HRESULT WINAPI IDirectInputDevice8WImpl_GetImageInfo(LPDIRECTINPUTDEVICE8W iface,
LPDIDEVICEIMAGEINFOHEADERW lpdiDevImageInfoHeader)
{
- FIXME("(%p)->(%p): stub !\n", iface, lpdiDevImageInfoHeader);
+ IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8W(iface);
+ FIXME("(%p)->(%p): stub !\n", This, lpdiDevImageInfoHeader);
return DI_OK;
}
diff --git a/dll/directx/wine/dinput/device_private.h
b/dll/directx/wine/dinput/device_private.h
index d9e2997eaaf..114e3971ed8 100644
--- a/dll/directx/wine/dinput/device_private.h
+++ b/dll/directx/wine/dinput/device_private.h
@@ -114,6 +114,8 @@ typedef struct
LPDIRECTINPUTEFFECT ref;
} effect_list_item;
+extern const GUID DInput_PIDVID_Product_GUID DECLSPEC_HIDDEN;
+
/* Various debug tools */
extern void _dump_DIPROPHEADER(LPCDIPROPHEADER diph) DECLSPEC_HIDDEN;
extern void _dump_OBJECTINSTANCEA(const DIDEVICEOBJECTINSTANCEA *ddoi) DECLSPEC_HIDDEN;
@@ -123,6 +125,9 @@ extern const char *_dump_dinput_GUID(const GUID *guid)
DECLSPEC_HIDDEN;
extern LPDIOBJECTDATAFORMAT dataformat_to_odf_by_type(LPCDIDATAFORMAT df, int n, DWORD
type) DECLSPEC_HIDDEN;
+extern HRESULT save_mapping_settings(IDirectInputDevice8W *iface, LPDIACTIONFORMATW
lpdiaf, LPCWSTR lpszUsername) DECLSPEC_HIDDEN;
+extern BOOL load_mapping_settings(IDirectInputDeviceImpl *This, LPDIACTIONFORMATW lpdiaf,
const WCHAR *username) DECLSPEC_HIDDEN;
+
extern HRESULT _build_action_map(LPDIRECTINPUTDEVICE8W iface, LPDIACTIONFORMATW lpdiaf,
LPCWSTR lpszUserName, DWORD dwFlags, DWORD devMask, LPCDIDATAFORMAT df) DECLSPEC_HIDDEN;
extern HRESULT _set_action_map(LPDIRECTINPUTDEVICE8W iface, LPDIACTIONFORMATW lpdiaf,
LPCWSTR lpszUserName, DWORD dwFlags, LPCDIDATAFORMAT df) DECLSPEC_HIDDEN;
diff --git a/dll/directx/wine/dinput/dinput_main.c
b/dll/directx/wine/dinput/dinput_main.c
index 4b058891d93..645d29dfd87 100644
--- a/dll/directx/wine/dinput/dinput_main.c
+++ b/dll/directx/wine/dinput/dinput_main.c
@@ -30,7 +30,6 @@
* - Fallout : works great in X and DGA mode
*/
-#include "config.h"
#include <assert.h>
#include <stdarg.h>
#include <string.h>
@@ -39,7 +38,9 @@
#define NONAMELESSUNION
#include "wine/debug.h"
+#include "wine/heap.h"
#include "wine/unicode.h"
+#include "wine/asm.h"
#include "windef.h"
#include "winbase.h"
#include "winuser.h"
@@ -47,6 +48,7 @@
#include "objbase.h"
#include "rpcproxy.h"
#include "initguid.h"
+#include "devguid.h"
#include "dinput_private.h"
#include "device_private.h"
#include "dinputd.h"
@@ -289,6 +291,20 @@ static void _dump_EnumDevices_dwFlags(DWORD dwFlags)
TRACE("\n");
}
+static const char *dump_semantic(DWORD semantic)
+{
+ if((semantic & 0xff000000) == 0xff000000)
+ return "Any AXIS";
+ else if((semantic & 0x82000000) == 0x82000000)
+ return "Mouse";
+ else if((semantic & 0x81000000) == 0x81000000)
+ return "Keybaord";
+ else if((semantic & DIVIRTUAL_FLYING_HELICOPTER) == DIVIRTUAL_FLYING_HELICOPTER)
+ return "Helicopter";
+
+ return "Unknown";
+}
+
static void _dump_diactionformatA(LPDIACTIONFORMATA lpdiActionFormat)
{
unsigned int i;
@@ -311,7 +327,7 @@ static void _dump_diactionformatA(LPDIACTIONFORMATA lpdiActionFormat)
{
TRACE("diaf.rgoAction[%u]:\n", i);
TRACE("\tuAppData=0x%lx\n",
lpdiActionFormat->rgoAction[i].uAppData);
- TRACE("\tdwSemantic=0x%08x\n",
lpdiActionFormat->rgoAction[i].dwSemantic);
+ TRACE("\tdwSemantic=0x%08x (%s)\n",
lpdiActionFormat->rgoAction[i].dwSemantic,
dump_semantic(lpdiActionFormat->rgoAction[i].dwSemantic));
TRACE("\tdwFlags=0x%x\n", lpdiActionFormat->rgoAction[i].dwFlags);
TRACE("\tszActionName=%s\n",
debugstr_a(lpdiActionFormat->rgoAction[i].u.lptszActionName));
TRACE("\tguidInstance=%s\n",
debugstr_guid(&lpdiActionFormat->rgoAction[i].guidInstance));
@@ -467,9 +483,10 @@ static HRESULT WINAPI IDirectInputAImpl_EnumDevices(
for (i = 0; i < ARRAY_SIZE(dinput_devices); i++) {
if (!dinput_devices[i]->enum_deviceA) continue;
+
+ TRACE(" Checking device %u ('%s')\n", i,
dinput_devices[i]->name);
for (j = 0, r = S_OK; SUCCEEDED(r); j++) {
devInstance.dwSize = sizeof(devInstance);
- TRACE(" - checking device %u ('%s')\n", i,
dinput_devices[i]->name);
r = dinput_devices[i]->enum_deviceA(dwDevType, dwFlags, &devInstance,
This->dwVersion, j);
if (r == S_OK)
if (enum_callback_wrapper(lpCallback, &devInstance, pvRef) ==
DIENUM_STOP)
@@ -525,7 +542,7 @@ static ULONG WINAPI IDirectInputAImpl_AddRef(LPDIRECTINPUT7A iface)
IDirectInputImpl *This = impl_from_IDirectInput7A( iface );
ULONG ref = InterlockedIncrement(&This->ref);
- TRACE( "(%p) incrementing from %d\n", This, ref - 1);
+ TRACE( "(%p) ref %d\n", This, ref );
return ref;
}
@@ -540,7 +557,7 @@ static ULONG WINAPI IDirectInputAImpl_Release(LPDIRECTINPUT7A iface)
IDirectInputImpl *This = impl_from_IDirectInput7A( iface );
ULONG ref = InterlockedDecrement( &This->ref );
- TRACE( "(%p) releasing from %d\n", This, ref + 1 );
+ TRACE( "(%p) ref %d\n", This, ref );
if (ref == 0)
{
@@ -566,53 +583,39 @@ static HRESULT WINAPI
IDirectInputAImpl_QueryInterface(LPDIRECTINPUT7A iface, RE
if (!riid || !ppobj)
return E_POINTER;
+ *ppobj = NULL;
+
+#if DIRECTINPUT_VERSION == 0x0700
if (IsEqualGUID( &IID_IUnknown, riid ) ||
- IsEqualGUID( &IID_IDirectInputA, riid ) ||
- IsEqualGUID( &IID_IDirectInput2A, riid ) ||
- IsEqualGUID( &IID_IDirectInput7A, riid ))
- {
+ IsEqualGUID( &IID_IDirectInputA, riid ) ||
+ IsEqualGUID( &IID_IDirectInput2A, riid ) ||
+ IsEqualGUID( &IID_IDirectInput7A, riid ))
*ppobj = &This->IDirectInput7A_iface;
- IUnknown_AddRef( (IUnknown*)*ppobj );
-
- return DI_OK;
- }
-
- if (IsEqualGUID( &IID_IDirectInputW, riid ) ||
- IsEqualGUID( &IID_IDirectInput2W, riid ) ||
- IsEqualGUID( &IID_IDirectInput7W, riid ))
- {
+ else if (IsEqualGUID( &IID_IDirectInputW, riid ) ||
+ IsEqualGUID( &IID_IDirectInput2W, riid ) ||
+ IsEqualGUID( &IID_IDirectInput7W, riid ))
*ppobj = &This->IDirectInput7W_iface;
- IUnknown_AddRef( (IUnknown*)*ppobj );
-
- return DI_OK;
- }
- if (IsEqualGUID( &IID_IDirectInput8A, riid ))
- {
+#else
+ if (IsEqualGUID( &IID_IUnknown, riid ) ||
+ IsEqualGUID( &IID_IDirectInput8A, riid ))
*ppobj = &This->IDirectInput8A_iface;
- IUnknown_AddRef( (IUnknown*)*ppobj );
-
- return DI_OK;
- }
- if (IsEqualGUID( &IID_IDirectInput8W, riid ))
- {
+ else if (IsEqualGUID( &IID_IDirectInput8W, riid ))
*ppobj = &This->IDirectInput8W_iface;
- IUnknown_AddRef( (IUnknown*)*ppobj );
- return DI_OK;
- }
+#endif
if (IsEqualGUID( &IID_IDirectInputJoyConfig8, riid ))
- {
*ppobj = &This->IDirectInputJoyConfig8_iface;
- IUnknown_AddRef( (IUnknown*)*ppobj );
+ if(*ppobj)
+ {
+ IUnknown_AddRef( (IUnknown*)*ppobj );
return DI_OK;
}
- FIXME( "Unsupported interface: %s\n", debugstr_guid(riid));
- *ppobj = NULL;
+ WARN( "Unsupported interface: %s\n", debugstr_guid(riid));
return E_NOINTERFACE;
}
@@ -690,7 +693,7 @@ static HRESULT WINAPI IDirectInputAImpl_Initialize(LPDIRECTINPUT7A
iface, HINSTA
{
IDirectInputImpl *This = impl_from_IDirectInput7A( iface );
- TRACE("(%p)->(%p, 0x%04x)\n", iface, hinst, version);
+ TRACE("(%p)->(%p, 0x%04x)\n", This, hinst, version);
if (!hinst)
return DIERR_INVALIDPARAM;
@@ -947,7 +950,7 @@ static HRESULT WINAPI IDirectInput8AImpl_Initialize(LPDIRECTINPUT8A
iface, HINST
{
IDirectInputImpl *This = impl_from_IDirectInput8A( iface );
- TRACE("(%p)->(%p, 0x%04x)\n", iface, hinst, version);
+ TRACE("(%p)->(%p, 0x%04x)\n", This, hinst, version);
if (!hinst)
return DIERR_INVALIDPARAM;
@@ -1104,10 +1107,12 @@ static HRESULT WINAPI IDirectInput8AImpl_EnumDevicesBySemantics(
if (lpCallback(&didevis[i], lpdid, callbackFlags, --remain, pvRef) ==
DIENUM_STOP)
{
+ IDirectInputDevice_Release(lpdid);
HeapFree(GetProcessHeap(), 0, didevis);
HeapFree(GetProcessHeap(), 0, username_w);
return DI_OK;
}
+ IDirectInputDevice_Release(lpdid);
}
HeapFree(GetProcessHeap(), 0, didevis);
@@ -1130,9 +1135,11 @@ static HRESULT WINAPI IDirectInput8AImpl_EnumDevicesBySemantics(
if (lpCallback(&didevi, lpdid, callbackFlags, --remain, pvRef) ==
DIENUM_STOP)
{
+ IDirectInputDevice_Release(lpdid);
HeapFree(GetProcessHeap(), 0, username_w);
return DI_OK;
}
+ IDirectInputDevice_Release(lpdid);
}
}
@@ -1260,9 +1267,34 @@ static HRESULT WINAPI IDirectInput8AImpl_ConfigureDevices(
/* Copy parameters */
diCDParamsW.dwSize = sizeof(DICONFIGUREDEVICESPARAMSW);
+ diCDParamsW.dwcUsers = lpdiCDParams->dwcUsers;
diCDParamsW.dwcFormats = lpdiCDParams->dwcFormats;
diCDParamsW.lprgFormats = &diafW;
diCDParamsW.hwnd = lpdiCDParams->hwnd;
+ diCDParamsW.lptszUserNames = NULL;
+
+ if (lpdiCDParams->lptszUserNames) {
+ char *start = lpdiCDParams->lptszUserNames;
+ WCHAR *to = NULL;
+ int total_len = 0;
+ for (i = 0; i < lpdiCDParams->dwcUsers; i++)
+ {
+ char *end = start + 1;
+ int len;
+ while (*(end++));
+ len = MultiByteToWideChar(CP_ACP, 0, start, end - start, NULL, 0);
+ total_len += len + 2; /* length of string and two null char */
+ if (to)
+ to = HeapReAlloc(GetProcessHeap(), 0, to, sizeof(WCHAR) * total_len);
+ else
+ to = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * total_len);
+
+ MultiByteToWideChar(CP_ACP, 0, start, end - start, to + (total_len - len -
2), len);
+ to[total_len] = 0;
+ to[total_len - 1] = 0;
+ }
+ diCDParamsW.lptszUserNames = to;
+ }
diafW.rgoAction = HeapAlloc(GetProcessHeap(), 0,
sizeof(DIACTIONW)*lpdiCDParams->lprgFormats->dwNumActions);
_copy_diactionformatAtoW(&diafW, lpdiCDParams->lprgFormats);
@@ -1290,6 +1322,8 @@ static HRESULT WINAPI IDirectInput8AImpl_ConfigureDevices(
HeapFree(GetProcessHeap(), 0, diafW.rgoAction);
+ heap_free((void*) diCDParamsW.lptszUserNames);
+
return hr;
}
@@ -1777,7 +1811,7 @@ static DWORD WINAPI hook_thread_proc(void *param)
DispatchMessageW(&msg);
}
- return 0;
+ FreeLibraryAndExitThread(DINPUT_instance, 0);
}
static DWORD hook_thread_id;
@@ -1794,15 +1828,16 @@ static CRITICAL_SECTION dinput_hook_crit = {
&dinput_critsect_debug, -1, 0, 0, 0
static BOOL check_hook_thread(void)
{
static HANDLE hook_thread;
+ HMODULE module;
EnterCriticalSection(&dinput_hook_crit);
TRACE("IDirectInputs left: %d\n", list_count(&direct_input_list));
if (!list_empty(&direct_input_list) && !hook_thread)
{
+ GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, (const
WCHAR*)DINPUT_instance, &module);
hook_thread_event = CreateEventW(NULL, FALSE, FALSE, NULL);
hook_thread = CreateThread(NULL, 0, hook_thread_proc, hook_thread_event, 0,
&hook_thread_id);
- LeaveCriticalSection(&dinput_hook_crit);
}
else if (list_empty(&direct_input_list) && hook_thread)
{
@@ -1817,16 +1852,11 @@ static BOOL check_hook_thread(void)
hook_thread_id = 0;
PostThreadMessageW(tid, WM_USER+0x10, 0, 0);
- LeaveCriticalSection(&dinput_hook_crit);
-
- /* wait for hook thread to exit */
- WaitForSingleObject(hook_thread, INFINITE);
CloseHandle(hook_thread);
hook_thread = NULL;
}
- else
- LeaveCriticalSection(&dinput_hook_crit);
+ LeaveCriticalSection(&dinput_hook_crit);
return hook_thread_id != 0;
}
diff --git a/dll/directx/wine/dinput/dinput_private.h
b/dll/directx/wine/dinput/dinput_private.h
index acda6c80485..289b2f1f63d 100644
--- a/dll/directx/wine/dinput/dinput_private.h
+++ b/dll/directx/wine/dinput/dinput_private.h
@@ -81,6 +81,7 @@ 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;
+extern DWORD get_device_type(DWORD version, BOOL is_joystick) DECLSPEC_HIDDEN;
#define IS_DIPROP(x) (((ULONG_PTR)(x) >> 16) == 0)
diff --git a/dll/directx/wine/dinput/effect_linuxinput.c
b/dll/directx/wine/dinput/effect_linuxinput.c
index 7477bc757da..4b2f317ce37 100644
--- a/dll/directx/wine/dinput/effect_linuxinput.c
+++ b/dll/directx/wine/dinput/effect_linuxinput.c
@@ -167,7 +167,9 @@ static ULONG WINAPI LinuxInputEffectImpl_AddRef(
LPDIRECTINPUTEFFECT iface)
{
LinuxInputEffectImpl *This = impl_from_IDirectInputEffect(iface);
- return InterlockedIncrement(&(This->ref));
+ ULONG ref = InterlockedIncrement(&This->ref);
+ TRACE( "(%p) ref %d\n", This, ref );
+ return ref;
}
static HRESULT WINAPI LinuxInputEffectImpl_Download(
@@ -759,6 +761,8 @@ static ULONG WINAPI LinuxInputEffectImpl_Release(LPDIRECTINPUTEFFECT
iface)
LinuxInputEffectImpl *This = impl_from_IDirectInputEffect(iface);
ULONG ref = InterlockedDecrement(&(This->ref));
+ TRACE( "(%p) ref %d\n", This, ref );
+
if (ref == 0)
{
LinuxInputEffectImpl_Stop(iface);
diff --git a/dll/directx/wine/dinput/joystick.c b/dll/directx/wine/dinput/joystick.c
index 0ec1ceb2497..9d7baf411a4 100644
--- a/dll/directx/wine/dinput/joystick.c
+++ b/dll/directx/wine/dinput/joystick.c
@@ -28,12 +28,40 @@
#include <stdio.h>
+#include "device_private.h"
#include "joystick_private.h"
#include "wine/debug.h"
+#include "wine/heap.h"
#include "winreg.h"
WINE_DEFAULT_DEBUG_CHANNEL(dinput);
+#define VID_MICROSOFT 0x045e
+
+static const WORD PID_XBOX_CONTROLLERS[] = {
+ 0x0202, /* Xbox Controller */
+ 0x0285, /* Xbox Controller S */
+ 0x0289, /* Xbox Controller S */
+ 0x028e, /* Xbox360 Controller */
+ 0x028f, /* Xbox360 Wireless Controller */
+ 0x02d1, /* Xbox One Controller */
+ 0x02dd, /* Xbox One Controller (Covert Forces/Firmware 2015) */
+ 0x02e0, /* Xbox One X Controller */
+ 0x02e3, /* Xbox One Elite Controller */
+ 0x02e6, /* Wireless XBox Controller Dongle */
+ 0x02ea, /* Xbox One S Controller */
+ 0x02fd, /* Xbox One S Controller (Firmware 2017) */
+ 0x0719, /* Xbox 360 Wireless Adapter */
+};
+
+/* Windows uses this GUID for guidProduct on non-keyboard/mouse devices.
+ * Data1 contains the device VID (low word) and PID (high word).
+ * Data4 ends with the ASCII bytes "PIDVID".
+ */
+const GUID DInput_PIDVID_Product_GUID = { /* device_pidvid-0000-0000-0000-504944564944
*/
+ 0x00000000, 0x0000, 0x0000, {0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44}
+};
+
static inline JoystickGenericImpl *impl_from_IDirectInputDevice8A(IDirectInputDevice8A
*iface)
{
return CONTAINING_RECORD(CONTAINING_RECORD(iface, IDirectInputDeviceImpl,
IDirectInputDevice8A_iface), JoystickGenericImpl, base);
@@ -76,6 +104,16 @@ DWORD typeFromGUID(REFGUID guid)
}
}
+DWORD get_device_type(DWORD version, BOOL is_joystick)
+{
+ if (is_joystick)
+ return version >= 0x0800 ? DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD
<< 8) :
+ DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
+
+ return version >= 0x0800 ? DI8DEVTYPE_GAMEPAD | (DI8DEVTYPEJOYSTICK_STANDARD
<< 8) :
+ DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_GAMEPAD << 8);
+}
+
static void _dump_DIEFFECT_flags(DWORD dwFlags)
{
if (TRACE_ON(dinput)) {
@@ -271,6 +309,89 @@ BOOL device_disabled_registry(const char* name)
return do_disable;
}
+BOOL is_xinput_device(const DIDEVCAPS *devcaps, WORD vid, WORD pid)
+{
+ int i;
+
+ if (vid == VID_MICROSOFT)
+ {
+ for (i = 0; i < ARRAY_SIZE(PID_XBOX_CONTROLLERS); i++)
+ if (pid == PID_XBOX_CONTROLLERS[i]) return TRUE;
+ }
+
+ return (devcaps->dwAxes == 6 && devcaps->dwButtons >= 14);
+}
+
+static void remap_init(JoystickGenericImpl *This, int obj, ObjProps *remap_props)
+{
+ /* Configure as if nothing changed so the helper functions can only change
+ * what they need, thus reducing code duplication. */
+ remap_props->lDevMin = remap_props->lMin = This->props[obj].lMin;
+ remap_props->lDevMax = remap_props->lMax = This->props[obj].lMax;
+
+ remap_props->lDeadZone = This->props[obj].lDeadZone;
+ remap_props->lSaturation = This->props[obj].lSaturation;
+}
+
+static void remap_apply(JoystickGenericImpl *This, int obj, ObjProps *remap_props)
+{
+ /* Many games poll the joystick immediately after setting the range
+ * for calibration purposes, so the old values need to be remapped
+ * to the new range before it does so */
+ switch (This->base.data_format.wine_df->rgodf[obj].dwOfs){
+ case DIJOFS_X : This->js.lX = joystick_map_axis(remap_props,
This->js.lX); break;
+ case DIJOFS_Y : This->js.lY = joystick_map_axis(remap_props,
This->js.lY); break;
+ case DIJOFS_Z : This->js.lZ = joystick_map_axis(remap_props,
This->js.lZ); break;
+ case DIJOFS_RX : This->js.lRx = joystick_map_axis(remap_props,
This->js.lRx); break;
+ case DIJOFS_RY : This->js.lRy = joystick_map_axis(remap_props,
This->js.lRy); break;
+ case DIJOFS_RZ : This->js.lRz = joystick_map_axis(remap_props,
This->js.lRz); break;
+ case DIJOFS_SLIDER(0): This->js.rglSlider[0] = joystick_map_axis(remap_props,
This->js.rglSlider[0]); break;
+ case DIJOFS_SLIDER(1): This->js.rglSlider[1] = joystick_map_axis(remap_props,
This->js.rglSlider[1]); break;
+ default: break;
+ }
+}
+
+static void remap_range(JoystickGenericImpl *This, int obj, LPCDIPROPRANGE pr)
+{
+ ObjProps remap_props;
+ remap_init(This, obj, &remap_props);
+
+ remap_props.lMin = pr->lMin;
+ remap_props.lMax = pr->lMax;
+
+ remap_apply(This, obj, &remap_props);
+
+ /* Store new values */
+ This->props[obj].lMin = pr->lMin;
+ This->props[obj].lMax = pr->lMax;
+}
+
+static void remap_deadzone(JoystickGenericImpl *This, int obj, LPCDIPROPDWORD pd)
+{
+ ObjProps remap_props;
+ remap_init(This, obj, &remap_props);
+
+ remap_props.lDeadZone = pd->dwData;
+
+ remap_apply(This, obj, &remap_props);
+
+ /* Store new value */
+ This->props[obj].lDeadZone = pd->dwData;
+}
+
+static void remap_saturation(JoystickGenericImpl *This, int obj, LPCDIPROPDWORD pd)
+{
+ ObjProps remap_props;
+ remap_init(This, obj, &remap_props);
+
+ remap_props.lSaturation = pd->dwData;
+
+ remap_apply(This, obj, &remap_props);
+
+ /* Store new value */
+ This->props[obj].lSaturation = pd->dwData;
+}
+
/******************************************************************************
* SetProperty : change input device properties
*/
@@ -278,7 +399,6 @@ HRESULT WINAPI JoystickWGenericImpl_SetProperty(LPDIRECTINPUTDEVICE8W
iface, REF
{
JoystickGenericImpl *This = impl_from_IDirectInputDevice8W(iface);
DWORD i;
- ObjProps remap_props;
TRACE("(%p,%s,%p)\n",This,debugstr_guid(rguid),ph);
@@ -295,69 +415,15 @@ HRESULT WINAPI
JoystickWGenericImpl_SetProperty(LPDIRECTINPUTDEVICE8W iface, REF
case (DWORD_PTR)DIPROP_RANGE: {
LPCDIPROPRANGE pr = (LPCDIPROPRANGE)ph;
if (ph->dwHow == DIPH_DEVICE) {
-
- /* Many games poll the joystick immediately after setting the range
- * for calibration purposes, so the old values need to be remapped
- * to the new range before it does so */
-
TRACE("proprange(%d,%d) all\n", pr->lMin, pr->lMax);
- for (i = 0; i < This->base.data_format.wine_df->dwNumObjs; i++)
{
-
- remap_props.lDevMin = This->props[i].lMin;
- remap_props.lDevMax = This->props[i].lMax;
-
- remap_props.lDeadZone = This->props[i].lDeadZone;
- remap_props.lSaturation = This->props[i].lSaturation;
-
- remap_props.lMin = pr->lMin;
- remap_props.lMax = pr->lMax;
-
- switch (This->base.data_format.wine_df->rgodf[i].dwOfs) {
- case DIJOFS_X : This->js.lX =
joystick_map_axis(&remap_props, This->js.lX); break;
- case DIJOFS_Y : This->js.lY =
joystick_map_axis(&remap_props, This->js.lY); break;
- case DIJOFS_Z : This->js.lZ =
joystick_map_axis(&remap_props, This->js.lZ); break;
- case DIJOFS_RX : This->js.lRx =
joystick_map_axis(&remap_props, This->js.lRx); break;
- case DIJOFS_RY : This->js.lRy =
joystick_map_axis(&remap_props, This->js.lRy); break;
- case DIJOFS_RZ : This->js.lRz =
joystick_map_axis(&remap_props, This->js.lRz); break;
- case DIJOFS_SLIDER(0): This->js.rglSlider[0] =
joystick_map_axis(&remap_props, This->js.rglSlider[0]); break;
- case DIJOFS_SLIDER(1): This->js.rglSlider[1] =
joystick_map_axis(&remap_props, This->js.rglSlider[1]); break;
- default: break;
- }
-
- This->props[i].lMin = pr->lMin;
- This->props[i].lMax = pr->lMax;
- }
+ for (i = 0; i < This->base.data_format.wine_df->dwNumObjs; i++)
+ remap_range(This, i, pr);
} else {
int obj = find_property(&This->base.data_format, ph);
TRACE("proprange(%d,%d) obj=%d\n", pr->lMin, pr->lMax,
obj);
- if (obj >= 0) {
-
- remap_props.lDevMin = This->props[obj].lMin;
- remap_props.lDevMax = This->props[obj].lMax;
-
- remap_props.lDeadZone = This->props[obj].lDeadZone;
- remap_props.lSaturation = This->props[obj].lSaturation;
-
- remap_props.lMin = pr->lMin;
- remap_props.lMax = pr->lMax;
-
- switch (This->base.data_format.wine_df->rgodf[obj].dwOfs) {
- case DIJOFS_X : This->js.lX =
joystick_map_axis(&remap_props, This->js.lX); break;
- case DIJOFS_Y : This->js.lY =
joystick_map_axis(&remap_props, This->js.lY); break;
- case DIJOFS_Z : This->js.lZ =
joystick_map_axis(&remap_props, This->js.lZ); break;
- case DIJOFS_RX : This->js.lRx =
joystick_map_axis(&remap_props, This->js.lRx); break;
- case DIJOFS_RY : This->js.lRy =
joystick_map_axis(&remap_props, This->js.lRy); break;
- case DIJOFS_RZ : This->js.lRz =
joystick_map_axis(&remap_props, This->js.lRz); break;
- case DIJOFS_SLIDER(0): This->js.rglSlider[0] =
joystick_map_axis(&remap_props, This->js.rglSlider[0]); break;
- case DIJOFS_SLIDER(1): This->js.rglSlider[1] =
joystick_map_axis(&remap_props, This->js.rglSlider[1]); break;
- default: break;
- }
-
- This->props[obj].lMin = pr->lMin;
- This->props[obj].lMax = pr->lMax;
- return DI_OK;
- }
+ if (obj >= 0)
+ remap_range(This, obj, pr);
}
break;
}
@@ -366,15 +432,13 @@ HRESULT WINAPI
JoystickWGenericImpl_SetProperty(LPDIRECTINPUTDEVICE8W iface, REF
if (ph->dwHow == DIPH_DEVICE) {
TRACE("deadzone(%d) all\n", pd->dwData);
for (i = 0; i < This->base.data_format.wine_df->dwNumObjs; i++)
- This->props[i].lDeadZone = pd->dwData;
+ remap_deadzone(This, i, pd);
} else {
int obj = find_property(&This->base.data_format, ph);
TRACE("deadzone(%d) obj=%d\n", pd->dwData, obj);
- if (obj >= 0) {
- This->props[obj].lDeadZone = pd->dwData;
- return DI_OK;
- }
+ if (obj >= 0)
+ remap_deadzone(This, obj, pd);
}
break;
}
@@ -383,18 +447,21 @@ HRESULT WINAPI
JoystickWGenericImpl_SetProperty(LPDIRECTINPUTDEVICE8W iface, REF
if (ph->dwHow == DIPH_DEVICE) {
TRACE("saturation(%d) all\n", pd->dwData);
for (i = 0; i < This->base.data_format.wine_df->dwNumObjs; i++)
- This->props[i].lSaturation = pd->dwData;
+ remap_saturation(This, i, pd);
} else {
int obj = find_property(&This->base.data_format, ph);
TRACE("saturation(%d) obj=%d\n", pd->dwData, obj);
- if (obj >= 0) {
- This->props[obj].lSaturation = pd->dwData;
- return DI_OK;
- }
+ if (obj >= 0)
+ remap_saturation(This, obj, pd);
}
break;
}
+ case (DWORD_PTR)DIPROP_CALIBRATIONMODE: {
+ LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph;
+ FIXME("DIPROP_CALIBRATIONMODE(%d)\n", pd->dwData);
+ break;
+ }
default:
return IDirectInputDevice2WImpl_SetProperty(iface, rguid, ph);
}
@@ -461,7 +528,7 @@ HRESULT WINAPI
JoystickWGenericImpl_GetCapabilities(LPDIRECTINPUTDEVICE8W iface,
JoystickGenericImpl *This = impl_from_IDirectInputDevice8W(iface);
int size;
- TRACE("%p->(%p)\n",iface,lpDIDevCaps);
+ TRACE("%p->(%p)\n",This,lpDIDevCaps);
if (lpDIDevCaps == NULL) {
WARN("invalid pointer\n");
@@ -544,7 +611,7 @@ HRESULT WINAPI JoystickWGenericImpl_GetProperty(LPDIRECTINPUTDEVICE8W
iface, REF
{
JoystickGenericImpl *This = impl_from_IDirectInputDevice8W(iface);
- TRACE("(%p,%s,%p)\n", iface, debugstr_guid(rguid), pdiph);
+ TRACE("(%p,%s,%p)\n", This, debugstr_guid(rguid), pdiph);
if (TRACE_ON(dinput))
_dump_DIPROPHEADER(pdiph);
@@ -627,7 +694,7 @@ HRESULT WINAPI JoystickAGenericImpl_GetDeviceInfo(
DIPROPDWORD pd;
DWORD index = 0;
- TRACE("(%p,%p)\n", iface, pdidi);
+ TRACE("(%p,%p)\n", This, pdidi);
if (pdidi == NULL) {
WARN("invalid pointer\n");
@@ -654,7 +721,7 @@ HRESULT WINAPI JoystickAGenericImpl_GetDeviceInfo(
/* we only support traditional joysticks for now */
pdidi->dwDevType = This->devcaps.dwDevType;
snprintf(pdidi->tszInstanceName, MAX_PATH, "Joystick %d", index);
- strcpy(pdidi->tszProductName, This->name);
+ lstrcpynA(pdidi->tszProductName, This->name, MAX_PATH);
if (pdidi->dwSize > sizeof(DIDEVICEINSTANCE_DX3A)) {
pdidi->guidFFDriver = GUID_NULL;
pdidi->wUsagePage = 0;
@@ -771,8 +838,31 @@ HRESULT WINAPI
JoystickWGenericImpl_BuildActionMap(LPDIRECTINPUTDEVICE8W iface,
JoystickGenericImpl *This = impl_from_IDirectInputDevice8W(iface);
unsigned int i, j;
BOOL has_actions = FALSE;
+ WCHAR *username;
+ DWORD size;
+ BOOL load_success = FALSE;
+
+ FIXME("(%p)->(%p,%s,%08x): semi-stub !\n", This, lpdiaf,
debugstr_w(lpszUserName), dwFlags);
- FIXME("(%p)->(%p,%s,%08x): semi-stub !\n", iface, lpdiaf,
debugstr_w(lpszUserName), dwFlags);
+ /* Unless asked the contrary by these flags, try to load a previous mapping */
+ if (!(dwFlags & DIDBAM_HWDEFAULTS))
+ {
+ if (!lpszUserName)
+ GetUserNameW(NULL, &size);
+ else
+ size = lstrlenW(lpszUserName) + 1;
+
+ username = heap_alloc(size * sizeof(WCHAR));
+ if (!lpszUserName)
+ GetUserNameW(username, &size);
+ else
+ lstrcpynW(username, lpszUserName, size);
+
+ load_success = load_mapping_settings(&This->base, lpdiaf, username);
+ heap_free(username);
+ }
+
+ if (load_success) return DI_OK;
for (i=0; i < lpdiaf->dwNumActions; i++)
{
@@ -850,7 +940,7 @@ HRESULT WINAPI JoystickWGenericImpl_SetActionMap(LPDIRECTINPUTDEVICE8W
iface,
{
JoystickGenericImpl *This = impl_from_IDirectInputDevice8W(iface);
- FIXME("(%p)->(%p,%s,%08x): semi-stub !\n", iface, lpdiaf,
debugstr_w(lpszUserName), dwFlags);
+ FIXME("(%p)->(%p,%s,%08x): semi-stub !\n", This, lpdiaf,
debugstr_w(lpszUserName), dwFlags);
return _set_action_map(iface, lpdiaf, lpszUserName, dwFlags,
This->base.data_format.wine_df);
}
@@ -878,6 +968,8 @@ HRESULT WINAPI JoystickAGenericImpl_SetActionMap(LPDIRECTINPUTDEVICE8A
iface,
hr = JoystickWGenericImpl_SetActionMap(&This->base.IDirectInputDevice8W_iface,
&diafW, lpszUserNameW, dwFlags);
+ lpdiaf->dwCRC = diafW.dwCRC;
+
HeapFree(GetProcessHeap(), 0, diafW.rgoAction);
HeapFree(GetProcessHeap(), 0, lpszUserNameW);
@@ -950,6 +1042,7 @@ HRESULT setup_dinput_options(JoystickGenericImpl *This, const int
*default_axis_
int tokens = 0;
int axis = 0;
int pov = 0;
+ int button;
get_app_key(&hkey, &appkey);
@@ -961,6 +1054,34 @@ HRESULT setup_dinput_options(JoystickGenericImpl *This, const int
*default_axis_
TRACE("setting default deadzone to: \"%s\" %d\n", buffer,
This->deadzone);
}
+ for (button = 0; button < MAX_MAP_BUTTONS; button++)
+ This->button_map[button] = button;
+
+ if (!get_config_key(hkey, appkey, "ButtonMap", buffer, sizeof(buffer)))
+ {
+ static const char *delim = ",";
+ int button = 0;
+ char *token;
+
+ TRACE("ButtonMap = \"%s\"\n", buffer);
+ for (token = strtok(buffer, delim);
+ token != NULL && button < MAX_MAP_BUTTONS;
+ token = strtok(NULL, delim), button++)
+ {
+ char *s;
+ int value = strtol(token, &s, 10);
+ if (value < 0 || *s != '\0')
+ {
+ ERR("invalid button number: \"%s\"", token);
+ }
+ else
+ {
+ TRACE("mapping physical button %d to DInput button %d", value,
button);
+ This->button_map[value] = button;
+ }
+ }
+ }
+
This->axis_map = HeapAlloc(GetProcessHeap(), 0, This->device_axis_count *
sizeof(int));
if (!This->axis_map) return DIERR_OUTOFMEMORY;
diff --git a/dll/directx/wine/dinput/joystick_linux.c
b/dll/directx/wine/dinput/joystick_linux.c
index 963e62f017c..3ecbf441aad 100644
--- a/dll/directx/wine/dinput/joystick_linux.c
+++ b/dll/directx/wine/dinput/joystick_linux.c
@@ -59,6 +59,7 @@
#include "windef.h"
#include "winbase.h"
#include "winerror.h"
+#include "devguid.h"
#include "dinput.h"
#include "dinput_private.h"
@@ -84,6 +85,8 @@ struct JoyDev
int *dev_axes_map;
WORD vendor_id, product_id, bus_type;
+
+ BOOL is_joystick;
};
typedef struct JoystickImpl JoystickImpl;
@@ -123,19 +126,6 @@ static const GUID DInput_Wine_Joystick_GUID = { /*
9e573ed9-7734-11d2-8d4a-23903
{0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf7}
};
-/*
- * Construct the GUID in the same way of Windows doing this.
- * Data1 is concatenation of productid and vendorid.
- * Data2 and Data3 are NULL.
- * Data4 seems to be a constant.
- */
-static const GUID DInput_Wine_Joystick_Constant_Part_GUID = {
- 0x000000000,
- 0x0000,
- 0x0000,
- {0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44}
-};
-
#define MAX_JOYSTICKS 64
static INT joystick_devices_count = -1;
static struct JoyDev *joystick_devices;
@@ -177,6 +167,8 @@ static INT find_joystick_devices(void)
int fd;
struct JoyDev joydev, *new_joydevs;
BYTE axes_map[ABS_MAX + 1];
+ SHORT btn_map[KEY_MAX - BTN_MISC + 1];
+ BOOL is_stylus = FALSE;
snprintf(joydev.device, sizeof(joydev.device), "%s%d", JOYDEV_NEW, i);
if ((fd = open(joydev.device, O_RDONLY)) == -1)
@@ -220,6 +212,52 @@ static INT find_joystick_devices(void)
joydev.button_count = 2;
#endif
+ joydev.is_joystick = FALSE;
+ if (ioctl(fd, JSIOCGBTNMAP, btn_map) < 0)
+ {
+ WARN("ioctl(%s,JSIOCGBTNMAP) failed: %s\n", joydev.device,
strerror(errno));
+ }
+ else
+ {
+ INT j;
+ /* in lieu of properly reporting HID usage, detect presence of
+ * "joystick buttons" and report those devices as joysticks instead
of
+ * gamepads */
+ for (j = 0; !joydev.is_joystick && j < joydev.button_count; j++)
+ {
+ switch (btn_map[j])
+ {
+ case BTN_TRIGGER:
+ case BTN_THUMB:
+ case BTN_THUMB2:
+ case BTN_TOP:
+ case BTN_TOP2:
+ case BTN_PINKIE:
+ case BTN_BASE:
+ case BTN_BASE2:
+ case BTN_BASE3:
+ case BTN_BASE4:
+ case BTN_BASE5:
+ case BTN_BASE6:
+ case BTN_DEAD:
+ joydev.is_joystick = TRUE;
+ break;
+ case BTN_STYLUS:
+ is_stylus = TRUE;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ if(is_stylus)
+ {
+ TRACE("Stylus detected. Skipping\n");
+ close(fd);
+ continue;
+ }
+
if (ioctl(fd, JSIOCGAXMAP, axes_map) < 0)
{
WARN("ioctl(%s,JSIOCGAXMAP) failed: %s\n", joydev.device,
strerror(errno));
@@ -239,6 +277,14 @@ static INT find_joystick_devices(void)
joydev.dev_axes_map[j] = j;
found_axes++;
}
+ else if (axes_map[j] <= 10)
+ {
+ /* Axes 8 through 10 are Wheel, Gas and Brake,
+ * remap to 0, 1 and 2
+ */
+ joydev.dev_axes_map[j] = axes_map[j] - 8;
+ found_axes++;
+ }
else if (axes_map[j] == 16 ||
axes_map[j] == 17)
{
@@ -279,7 +325,7 @@ static INT find_joystick_devices(void)
else
{
/* Concatenate product_id with vendor_id to mimic Windows behaviour */
- joydev.guid_product = DInput_Wine_Joystick_Constant_Part_GUID;
+ joydev.guid_product = DInput_PIDVID_Product_GUID;
joydev.guid_product.Data1 = MAKELONG(joydev.vendor_id, joydev.product_id);
}
@@ -314,11 +360,7 @@ static void fill_joystick_dideviceinstanceW(LPDIDEVICEINSTANCEW
lpddi, DWORD ver
lpddi->guidInstance = DInput_Wine_Joystick_GUID;
lpddi->guidInstance.Data3 = id;
lpddi->guidProduct = joystick_devices[id].guid_product;
- /* we only support traditional joysticks for now */
- if (version >= 0x0800)
- lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD <<
8);
- else
- lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL
<< 8);
+ lpddi->dwDevType = get_device_type(version, joystick_devices[id].is_joystick);
/* Assume the joystick as HID if it is attached to USB bus and has a valid VID/PID
*/
if (joystick_devices[id].bus_type == BUS_USB &&
@@ -326,7 +368,7 @@ static void fill_joystick_dideviceinstanceW(LPDIDEVICEINSTANCEW lpddi,
DWORD ver
{
lpddi->dwDevType |= DIDEVTYPE_HID;
lpddi->wUsagePage = 0x01; /* Desktop */
- if (lpddi->dwDevType == DI8DEVTYPE_JOYSTICK || lpddi->dwDevType ==
DIDEVTYPE_JOYSTICK)
+ if (joystick_devices[id].is_joystick)
lpddi->wUsage = 0x04; /* Joystick */
else
lpddi->wUsage = 0x05; /* Game Pad */
@@ -372,7 +414,7 @@ static HRESULT joydev_enum_deviceA(DWORD dwDevType, DWORD dwFlags,
LPDIDEVICEINS
}
if ((dwDevType == 0) ||
- ((dwDevType == DIDEVTYPE_JOYSTICK) && (version > 0x0300 && version
< 0x0800)) ||
+ ((dwDevType == DIDEVTYPE_JOYSTICK) && (version >= 0x0300 && version
< 0x0800)) ||
(((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) &&
(version >= 0x0800))) {
/* check whether we have a joystick */
if ((fd = open(joystick_devices[id].device, O_RDONLY)) == -1)
@@ -401,7 +443,7 @@ static HRESULT joydev_enum_deviceW(DWORD dwDevType, DWORD dwFlags,
LPDIDEVICEINS
}
if ((dwDevType == 0) ||
- ((dwDevType == DIDEVTYPE_JOYSTICK) && (version > 0x0300 && version
< 0x0800)) ||
+ ((dwDevType == DIDEVTYPE_JOYSTICK) && (version >= 0x0300 && version
< 0x0800)) ||
(((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) &&
(version >= 0x0800))) {
/* check whether we have a joystick */
if ((fd = open(joystick_devices[id].device, O_RDONLY)) == -1)
@@ -673,7 +715,7 @@ static HRESULT WINAPI
JoystickLinuxWImpl_GetProperty(LPDIRECTINPUTDEVICE8W iface
{
JoystickImpl *This = impl_from_IDirectInputDevice8W(iface);
- TRACE("(this=%p,%s,%p)\n", iface, debugstr_guid(rguid), pdiph);
+ TRACE("(%p)->(%s,%p)\n", This, debugstr_guid(rguid), pdiph);
_dump_DIPROPHEADER(pdiph);
if (!IS_DIPROP(rguid)) return DI_OK;
@@ -699,6 +741,29 @@ static HRESULT WINAPI
JoystickLinuxWImpl_GetProperty(LPDIRECTINPUTDEVICE8W iface
break;
}
+ case (DWORD_PTR) DIPROP_GUIDANDPATH:
+ {
+ static const WCHAR formatW[] =
{'\\','\\','?','\\','h','i','d','#','v','i','d','_','%','0','4','x','&',
+
'p','i','d','_','%','0','4','x','&','%','s','_','%','h','u',0};
+ static const WCHAR miW[] = {'m','i',0};
+ static const WCHAR igW[] = {'i','g',0};
+
+ BOOL is_gamepad;
+ LPDIPROPGUIDANDPATH pd = (LPDIPROPGUIDANDPATH)pdiph;
+ WORD vid = This->joydev->vendor_id;
+ WORD pid = This->joydev->product_id;
+
+ if (!pid || !vid)
+ return DIERR_UNSUPPORTED;
+
+ is_gamepad = is_xinput_device(&This->generic.devcaps, vid, pid);
+ pd->guidClass = GUID_DEVCLASS_HIDCLASS;
+ sprintfW(pd->wszPath, formatW, vid, pid, is_gamepad ? igW : miW,
get_joystick_index(&This->generic.base.guid));
+
+ TRACE("DIPROP_GUIDANDPATH(%s, %s): returning fake path\n",
debugstr_guid(&pd->guidClass), debugstr_w(pd->wszPath));
+ break;
+ }
+
default:
return JoystickWGenericImpl_GetProperty(iface, rguid, pdiph);
}
@@ -807,10 +872,13 @@ static void joy_polldev(LPDIRECTINPUTDEVICE8A iface)
jse.type,jse.number,jse.value);
if (jse.type & JS_EVENT_BUTTON)
{
+ int button;
if (jse.number >= This->generic.devcaps.dwButtons) return;
- inst_id = DIDFT_MAKEINSTANCE(jse.number) | DIDFT_PSHBUTTON;
- This->generic.js.rgbButtons[jse.number] = value = jse.value ? 0x80 :
0x00;
+ button = This->generic.button_map[jse.number];
+
+ inst_id = DIDFT_MAKEINSTANCE(button) | DIDFT_PSHBUTTON;
+ This->generic.js.rgbButtons[button] = value = jse.value ? 0x80 : 0x00;
}
else if (jse.type & JS_EVENT_AXIS)
{
diff --git a/dll/directx/wine/dinput/joystick_linuxinput.c
b/dll/directx/wine/dinput/joystick_linuxinput.c
index 910e755d3ed..8865532d9d1 100644
--- a/dll/directx/wine/dinput/joystick_linuxinput.c
+++ b/dll/directx/wine/dinput/joystick_linuxinput.c
@@ -57,6 +57,7 @@
#include "winbase.h"
#include "winerror.h"
#include "winreg.h"
+#include "devguid.h"
#include "dinput.h"
#include "dinput_private.h"
@@ -83,6 +84,13 @@ struct wine_input_absinfo {
LONG flat;
};
+enum wine_joystick_linuxinput_fd_state {
+ WINE_FD_STATE_CLOSED = 0, /* No device has been opened yet */
+ WINE_FD_STATE_OK, /* File descriptor is open and ready for reading */
+ WINE_FD_STATE_DISCONNECTED, /* Read error occurred; might be able to reopen later
*/
+ WINE_FD_STATE_INVALID, /* Device is no longer available at original pathname
*/
+};
+
/* implemented in effect_linuxinput.c */
HRESULT linuxinput_create_effect(int* fd, REFGUID rguid, struct list *parent_list_entry,
LPDIRECTINPUTEFFECT* peff);
HRESULT linuxinput_get_info_A(int fd, REFGUID rguid, LPDIEFFECTINFOA info);
@@ -100,7 +108,7 @@ struct JoyDev {
GUID guid;
GUID guid_product;
- BOOL has_ff;
+ BOOL has_ff, is_joystick;
int num_effects;
/* data returned by EVIOCGBIT for caps, EV_ABS, EV_KEY, and EV_FF */
@@ -122,6 +130,7 @@ struct JoystickImpl
/* joystick private */
int joyfd;
+ enum wine_joystick_linuxinput_fd_state joyfd_state;
int dev_axes_to_di[ABS_MAX];
POINTL povs[4];
@@ -164,19 +173,6 @@ static const GUID DInput_Wine_Joystick_Base_GUID = { /*
9e573eda-7734-11d2-8d4a-
{0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf7}
};
-/*
- * Construct the GUID in the same way of Windows doing this.
- * Data1 is concatenation of productid and vendorid.
- * Data2 and Data3 are NULL.
- * Data4 seems to be a constant.
- */
-static const GUID DInput_Wine_Joystick_Constant_Part_GUID = {
- 0x000000000,
- 0x0000,
- 0x0000,
- {0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44}
-};
-
#define test_bit(arr,bit) (((BYTE*)(arr))[(bit)>>3]&(1<<((bit)&7)))
#define MAX_JOYDEV 64
@@ -211,10 +207,7 @@ static void find_joydevs(void)
}
if (fd == -1)
- {
- WARN("Failed to open \"%s\": %d %s\n", buf, errno,
strerror(errno));
continue;
- }
if (ioctl(fd, EVIOCGBIT(0, sizeof(joydev.evbits)), joydev.evbits) == -1)
{
@@ -237,15 +230,41 @@ static void find_joydevs(void)
/* A true joystick has at least axis X and Y, and at least 1
* button. copied from linux/drivers/input/joydev.c */
- if (!test_bit(joydev.absbits, ABS_X) || !test_bit(joydev.absbits, ABS_Y) ||
+ if (((!test_bit(joydev.absbits, ABS_X) || !test_bit(joydev.absbits, ABS_Y))
&&
+ !test_bit(joydev.absbits, ABS_WHEEL) &&
+ !test_bit(joydev.absbits, ABS_GAS) &&
+ !test_bit(joydev.absbits, ABS_BRAKE)) ||
!(test_bit(joydev.keybits, BTN_TRIGGER) ||
test_bit(joydev.keybits, BTN_A) ||
- test_bit(joydev.keybits, BTN_1)))
+ test_bit(joydev.keybits, BTN_1) ||
+ test_bit(joydev.keybits, BTN_BASE) ||
+ test_bit(joydev.keybits, BTN_GEAR_UP) ||
+ test_bit(joydev.keybits, BTN_GEAR_DOWN)))
{
close(fd);
continue;
}
+ /* in lieu of properly reporting HID usage, detect presence of
+ * "joystick buttons" and report those devices as joysticks instead of
+ * gamepads */
+ joydev.is_joystick =
+ test_bit(joydev.keybits, BTN_TRIGGER) ||
+ test_bit(joydev.keybits, BTN_THUMB) ||
+ test_bit(joydev.keybits, BTN_THUMB2) ||
+ test_bit(joydev.keybits, BTN_TOP) ||
+ test_bit(joydev.keybits, BTN_TOP2) ||
+ test_bit(joydev.keybits, BTN_PINKIE) ||
+ test_bit(joydev.keybits, BTN_BASE) ||
+ test_bit(joydev.keybits, BTN_BASE2) ||
+ test_bit(joydev.keybits, BTN_BASE3) ||
+ test_bit(joydev.keybits, BTN_BASE4) ||
+ test_bit(joydev.keybits, BTN_BASE5) ||
+ test_bit(joydev.keybits, BTN_BASE6) ||
+ test_bit(joydev.keybits, BTN_GEAR_UP) ||
+ test_bit(joydev.keybits, BTN_GEAR_DOWN) ||
+ test_bit(joydev.keybits, BTN_DEAD);
+
if (!(joydev.device = HeapAlloc(GetProcessHeap(), 0, strlen(buf) + 1)))
{
close(fd);
@@ -320,7 +339,7 @@ static void find_joydevs(void)
joydev.bus_type = device_id.bustype;
/* Concatenate product_id with vendor_id to mimic Windows behaviour */
- joydev.guid_product = DInput_Wine_Joystick_Constant_Part_GUID;
+ joydev.guid_product = DInput_PIDVID_Product_GUID;
joydev.guid_product.Data1 = MAKELONG(joydev.vendor_id, joydev.product_id);
}
@@ -353,11 +372,7 @@ static void fill_joystick_dideviceinstanceW(LPDIDEVICEINSTANCEW
lpddi, DWORD ver
lpddi->guidInstance = joydevs[id].guid;
lpddi->guidProduct = joydevs[id].guid_product;
lpddi->guidFFDriver = GUID_NULL;
-
- if (version >= 0x0800)
- lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD <<
8);
- else
- lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL
<< 8);
+ lpddi->dwDevType = get_device_type(version, joydevs[id].is_joystick);
/* Assume the joystick as HID if it is attached to USB bus and has a valid VID/PID
*/
if (joydevs[id].bus_type == BUS_USB &&
@@ -365,7 +380,7 @@ static void fill_joystick_dideviceinstanceW(LPDIDEVICEINSTANCEW lpddi,
DWORD ver
{
lpddi->dwDevType |= DIDEVTYPE_HID;
lpddi->wUsagePage = 0x01; /* Desktop */
- if (lpddi->dwDevType == DI8DEVTYPE_JOYSTICK || lpddi->dwDevType ==
DIDEVTYPE_JOYSTICK)
+ if (joydevs[id].is_joystick)
lpddi->wUsage = 0x04; /* Joystick */
else
lpddi->wUsage = 0x05; /* Game Pad */
@@ -391,8 +406,8 @@ static void fill_joystick_dideviceinstanceA(LPDIDEVICEINSTANCEA lpddi,
DWORD ver
lpddi->guidInstance = lpddiW.guidInstance;
lpddi->guidProduct = lpddiW.guidProduct;
lpddi->dwDevType = lpddiW.dwDevType;
- strcpy(lpddi->tszInstanceName, joydevs[id].name);
- strcpy(lpddi->tszProductName, joydevs[id].name);
+ lstrcpynA(lpddi->tszInstanceName, joydevs[id].name, MAX_PATH);
+ lstrcpynA(lpddi->tszProductName, joydevs[id].name, MAX_PATH);
lpddi->guidFFDriver = lpddiW.guidFFDriver;
lpddi->wUsagePage = lpddiW.wUsagePage;
lpddi->wUsage = lpddiW.wUsage;
@@ -407,7 +422,7 @@ static HRESULT joydev_enum_deviceA(DWORD dwDevType, DWORD dwFlags,
LPDIDEVICEINS
}
if (!((dwDevType == 0) ||
- ((dwDevType == DIDEVTYPE_JOYSTICK) && (version > 0x0300 &&
version < 0x0800)) ||
+ ((dwDevType == DIDEVTYPE_JOYSTICK) && (version >= 0x0300 &&
version < 0x0800)) ||
(((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK))
&& (version >= 0x0800))))
return S_FALSE;
@@ -432,7 +447,7 @@ static HRESULT joydev_enum_deviceW(DWORD dwDevType, DWORD dwFlags,
LPDIDEVICEINS
}
if (!((dwDevType == 0) ||
- ((dwDevType == DIDEVTYPE_JOYSTICK) && (version > 0x0300 &&
version < 0x0800)) ||
+ ((dwDevType == DIDEVTYPE_JOYSTICK) && (version >= 0x0300 &&
version < 0x0800)) ||
(((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK))
&& (version >= 0x0800))))
return S_FALSE;
@@ -466,6 +481,7 @@ static JoystickImpl *alloc_device(REFGUID rguid, IDirectInputImpl
*dinput, unsig
newDevice->generic.base.dinput = dinput;
newDevice->generic.joy_polldev = joy_polldev;
newDevice->joyfd = -1;
+ newDevice->joyfd_state = WINE_FD_STATE_CLOSED;
newDevice->joydev = &joydevs[index];
newDevice->generic.name = newDevice->joydev->name;
list_init(&newDevice->ff_effects);
@@ -483,14 +499,18 @@ static JoystickImpl *alloc_device(REFGUID rguid, IDirectInputImpl
*dinput, unsig
/* Count number of available axes - supported Axis & POVs */
for (i = 0; i < ABS_MAX; i++)
{
- if (i < WINE_JOYSTICK_MAX_AXES &&
+ if (idx < WINE_JOYSTICK_MAX_AXES &&
+ i < ABS_HAT0X &&
test_bit(newDevice->joydev->absbits, i))
{
newDevice->generic.device_axis_count++;
newDevice->dev_axes_to_di[i] = idx;
newDevice->generic.props[idx].lDevMin =
newDevice->joydev->axes[i].minimum;
newDevice->generic.props[idx].lDevMax =
newDevice->joydev->axes[i].maximum;
- default_axis_map[idx] = i;
+ if (i >= 8 && i <= 10) /* If it's a wheel axis... */
+ default_axis_map[idx] = i - 8; /* ... remap to X/Y/Z */
+ else
+ default_axis_map[idx] = i;
idx++;
}
else
@@ -669,38 +689,15 @@ static HRESULT joydev_create_device(IDirectInputImpl *dinput,
REFGUID rguid, REF
return DIERR_DEVICENOTREG;
}
-
-const struct dinput_device joystick_linuxinput_device = {
- "Wine Linux-input joystick driver",
- joydev_enum_deviceA,
- joydev_enum_deviceW,
- joydev_create_device
-};
-
-/******************************************************************************
- * Acquire : gets exclusive control of the joystick
- */
-static HRESULT WINAPI JoystickWImpl_Acquire(LPDIRECTINPUTDEVICE8W iface)
+static int joydev_open_evdev(JoystickImpl *This)
{
- JoystickImpl *This = impl_from_IDirectInputDevice8W(iface);
- HRESULT res;
+ int fd;
- TRACE("(this=%p)\n",This);
-
- if ((res = IDirectInputDevice2WImpl_Acquire(iface)) != DI_OK)
- {
- WARN("Failed to acquire: %x\n", res);
- return res;
- }
-
- if ((This->joyfd = open(This->joydev->device, O_RDWR)) == -1)
+ if ((fd = open(This->joydev->device, O_RDWR)) == -1)
{
- if ((This->joyfd = open(This->joydev->device, O_RDONLY)) == -1)
+ if ((fd = open(This->joydev->device, O_RDONLY)) == -1)
{
/* Couldn't open the device at all */
- ERR("Failed to open device %s: %d %s\n",
This->joydev->device, errno, strerror(errno));
- IDirectInputDevice2WImpl_Unacquire(iface);
- return DIERR_NOTFOUND;
}
else
{
@@ -715,18 +712,53 @@ static HRESULT WINAPI JoystickWImpl_Acquire(LPDIRECTINPUTDEVICE8W
iface)
event.type = EV_FF;
event.code = FF_GAIN;
event.value = This->ff_gain;
- if (write(This->joyfd, &event, sizeof(event)) == -1)
+ if (write(fd, &event, sizeof(event)) == -1)
ERR("Failed to set gain (%i): %d %s\n", This->ff_gain, errno,
strerror(errno));
if (!This->ff_autocenter)
{
/* Disable autocenter. */
event.code = FF_AUTOCENTER;
event.value = 0;
- if (write(This->joyfd, &event, sizeof(event)) == -1)
+ if (write(fd, &event, sizeof(event)) == -1)
ERR("Failed disabling autocenter: %d %s\n", errno,
strerror(errno));
}
}
+ return fd;
+}
+
+
+const struct dinput_device joystick_linuxinput_device = {
+ "Wine Linux-input joystick driver",
+ joydev_enum_deviceA,
+ joydev_enum_deviceW,
+ joydev_create_device
+};
+
+/******************************************************************************
+ * Acquire : gets exclusive control of the joystick
+ */
+static HRESULT WINAPI JoystickWImpl_Acquire(LPDIRECTINPUTDEVICE8W iface)
+{
+ JoystickImpl *This = impl_from_IDirectInputDevice8W(iface);
+ HRESULT res;
+
+ TRACE("(this=%p)\n",This);
+
+ if ((res = IDirectInputDevice2WImpl_Acquire(iface)) != DI_OK)
+ {
+ WARN("Failed to acquire: %x\n", res);
+ return res;
+ }
+
+ if ((This->joyfd = joydev_open_evdev(This)) == -1)
+ {
+ ERR("Failed to open device %s: %d %s\n", This->joydev->device,
errno, strerror(errno));
+ IDirectInputDevice2WImpl_Unacquire(iface);
+ return DIERR_NOTFOUND;
+ }
+
+ This->joyfd_state = WINE_FD_STATE_OK;
return DI_OK;
}
@@ -764,6 +796,7 @@ static HRESULT WINAPI JoystickWImpl_Unacquire(LPDIRECTINPUTDEVICE8W
iface)
close(This->joyfd);
This->joyfd = -1;
+ This->joyfd_state = WINE_FD_STATE_CLOSED;
}
return res;
}
@@ -808,23 +841,79 @@ static void joy_polldev(LPDIRECTINPUTDEVICE8A iface)
struct input_event ie;
JoystickImpl *This = impl_from_IDirectInputDevice8A(iface);
- if (This->joyfd==-1)
- return;
+ if (This->joyfd == -1)
+ {
+ int fd;
+ char namebuf[MAX_PATH + 8]; /* 8 == strlen(EVDEVDRIVER) */
+
+ if (This->joyfd_state != WINE_FD_STATE_DISCONNECTED)
+ return;
+ /* Try to reconnect to the device. */
+ fd = joydev_open_evdev(This);
+ if (fd == -1)
+ return;
+ namebuf[sizeof(namebuf) - strlen(EVDEVDRIVER) - 1] = 0;
+ if (ioctl(fd, EVIOCGNAME(sizeof(namebuf) - strlen(EVDEVDRIVER) - 1), namebuf) ==
-1)
+ {
+ /* Couldn't get the name; assume it's a different device. */
+ ERR("EVIOCGNAME(%s) failed: %d %s", This->joydev->device,
errno, strerror(errno));
+ This->joyfd_state = WINE_FD_STATE_INVALID;
+ return;
+ }
+ strcat(namebuf, EVDEVDRIVER); /* Guaranteed to be safe. */
+ if (strcmp(namebuf, This->joydev->name) != 0)
+ {
+ ERR("Device %s changed from \"%s\" to \"%s\"!
Can't reconnect.\n", This->joydev->device, This->joydev->name,
namebuf);
+ This->joyfd_state = WINE_FD_STATE_INVALID;
+ return;
+ }
+ if (InterlockedCompareExchange(&This->joyfd, fd, -1) == -1)
+ {
+ This->joyfd_state = WINE_FD_STATE_OK;
+ TRACE("Reconnected to \"%s\" on %s",
This->joydev->name, This->joydev->device);
+ }
+ else
+ {
+ /* Somebody beat us to it! Throw away our fd and use theirs. */
+ close(fd);
+ }
+ }
while (1)
{
LONG value = 0;
int inst_id = -1;
+ int result;
plfd.fd = This->joyfd;
plfd.events = POLLIN;
- if (poll(&plfd,1,0) != 1)
- return;
+ result = poll(&plfd,1,0);
+ if (result != 1)
+ {
+ if (result == -1)
+ {
+ ERR("poll failed: %d %s\n", errno, strerror(errno));
+ close(This->joyfd);
+ This->joyfd = -1;
+ This->joyfd_state = WINE_FD_STATE_DISCONNECTED;
+ }
+ return;
+ }
/* we have one event, so we can read */
- if (sizeof(ie)!=read(This->joyfd,&ie,sizeof(ie)))
- return;
+ result = read(This->joyfd,&ie,sizeof(ie));
+ if (result != sizeof(ie))
+ {
+ if (result == -1)
+ {
+ ERR("read failed: %d %s\n", errno, strerror(errno));
+ close(This->joyfd);
+ This->joyfd = -1;
+ This->joyfd_state = WINE_FD_STATE_DISCONNECTED;
+ }
+ return;
+ }
TRACE("input_event: type %d, code %d, value %d\n",ie.type,ie.code,ie.value);
switch (ie.type) {
@@ -836,6 +925,8 @@ static void joy_polldev(LPDIRECTINPUTDEVICE8A iface)
if (btn & 0x80)
{
btn &= 0x7F;
+ btn = This->generic.button_map[btn];
+
inst_id = DIDFT_MAKEINSTANCE(btn) | DIDFT_PSHBUTTON;
This->generic.js.rgbButtons[btn] = value = ie.value ? 0x80 : 0x00;
}
@@ -923,11 +1014,6 @@ static HRESULT WINAPI
JoystickWImpl_SetProperty(LPDIRECTINPUTDEVICE8W iface, REF
if (IS_DIPROP(rguid)) {
switch (LOWORD(rguid)) {
- case (DWORD_PTR)DIPROP_CALIBRATIONMODE: {
- LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph;
- FIXME("DIPROP_CALIBRATIONMODE(%d)\n", pd->dwData);
- break;
- }
case (DWORD_PTR)DIPROP_AUTOCENTER: {
LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph;
@@ -973,7 +1059,7 @@ static HRESULT WINAPI JoystickWImpl_GetProperty(LPDIRECTINPUTDEVICE8W
iface, REF
{
JoystickImpl *This = impl_from_IDirectInputDevice8W(iface);
- TRACE("(this=%p,%s,%p)\n", iface, debugstr_guid(rguid), pdiph);
+ TRACE("(%p)->(%s,%p)\n", This, debugstr_guid(rguid), pdiph);
_dump_DIPROPHEADER(pdiph);
if (!IS_DIPROP(rguid)) return DI_OK;
@@ -1016,6 +1102,29 @@ static HRESULT WINAPI
JoystickWImpl_GetProperty(LPDIRECTINPUTDEVICE8W iface, REF
break;
}
+ case (DWORD_PTR) DIPROP_GUIDANDPATH:
+ {
+ static const WCHAR formatW[] =
{'\\','\\','?','\\','h','i','d','#','v','i','d','_','%','0','4','x','&',
+
'p','i','d','_','%','0','4','x','&','%','s','_','%','h','u',0};
+ static const WCHAR miW[] = {'m','i',0};
+ static const WCHAR igW[] = {'i','g',0};
+
+ BOOL is_gamepad;
+ LPDIPROPGUIDANDPATH pd = (LPDIPROPGUIDANDPATH)pdiph;
+ WORD vid = This->joydev->vendor_id;
+ WORD pid = This->joydev->product_id;
+
+ if (!pid || !vid)
+ return DIERR_UNSUPPORTED;
+
+ is_gamepad = is_xinput_device(&This->generic.devcaps, vid, pid);
+ pd->guidClass = GUID_DEVCLASS_HIDCLASS;
+ sprintfW(pd->wszPath, formatW, vid, pid, is_gamepad ? igW : miW,
get_joystick_index(&This->generic.base.guid));
+
+ TRACE("DIPROP_GUIDANDPATH(%s, %s): returning fake path\n",
debugstr_guid(&pd->guidClass), debugstr_w(pd->wszPath));
+ break;
+ }
+
default:
return JoystickWGenericImpl_GetProperty(iface, rguid, pdiph);
}
diff --git a/dll/directx/wine/dinput/joystick_osx.c
b/dll/directx/wine/dinput/joystick_osx.c
index 0701b9f42cc..061423afaa0 100644
--- a/dll/directx/wine/dinput/joystick_osx.c
+++ b/dll/directx/wine/dinput/joystick_osx.c
@@ -85,6 +85,7 @@
#include "winbase.h"
#include "winerror.h"
#include "winreg.h"
+#include "devguid.h"
#include "dinput.h"
#include "dinput_private.h"
@@ -124,6 +125,11 @@ static inline JoystickImpl
*impl_from_IDirectInputDevice8W(IDirectInputDevice8W
JoystickGenericImpl, base), JoystickImpl, generic);
}
+static inline IDirectInputDevice8W *IDirectInputDevice8W_from_impl(JoystickImpl *This)
+{
+ return &This->generic.base.IDirectInputDevice8W_iface;
+}
+
typedef struct _EffectImpl {
IDirectInputEffect IDirectInputEffect_iface;
LONG ref;
@@ -801,7 +807,11 @@ static void poll_osx_device_state(LPDIRECTINPUTDEVICE8A iface)
TRACE("kIOHIDElementTypeInput_Button\n");
if(button_idx < 128)
{
- IOHIDDeviceGetValue(hid_device, element, &valueRef);
+ valueRef = NULL;
+ if (IOHIDDeviceGetValue(hid_device, element, &valueRef) !=
kIOReturnSuccess)
+ return;
+ if (valueRef == NULL)
+ return;
val = IOHIDValueGetIntegerValue(valueRef);
newVal = val ? 0x80 : 0x0;
oldVal = device->generic.js.rgbButtons[button_idx];
@@ -809,6 +819,8 @@ static void poll_osx_device_state(LPDIRECTINPUTDEVICE8A iface)
TRACE("valueRef %s val %d oldVal %d newVal %d\n",
debugstr_cf(valueRef), val, oldVal, newVal);
if (oldVal != newVal)
{
+ button_idx = device->generic.button_map[button_idx];
+
inst_id = DIDFT_MAKEINSTANCE(button_idx) | DIDFT_PSHBUTTON;
queue_event(iface,inst_id,newVal,GetCurrentTime(),device->generic.base.dinput->evsequence++);
}
@@ -823,7 +835,11 @@ static void poll_osx_device_state(LPDIRECTINPUTDEVICE8A iface)
case kHIDUsage_GD_Hatswitch:
{
TRACE("kIOHIDElementTypeInput_Misc /
kHIDUsage_GD_Hatswitch\n");
- IOHIDDeviceGetValue(hid_device, element, &valueRef);
+ valueRef = NULL;
+ if (IOHIDDeviceGetValue(hid_device, element, &valueRef)
!= kIOReturnSuccess)
+ return;
+ if (valueRef == NULL)
+ return;
val = IOHIDValueGetIntegerValue(valueRef);
oldVal = device->generic.js.rgdwPOV[pov_idx];
if (val >= 8)
@@ -850,7 +866,11 @@ static void poll_osx_device_state(LPDIRECTINPUTDEVICE8A iface)
{
int wine_obj = -1;
- IOHIDDeviceGetValue(hid_device, element, &valueRef);
+ valueRef = NULL;
+ if (IOHIDDeviceGetValue(hid_device, element, &valueRef)
!= kIOReturnSuccess)
+ return;
+ if (valueRef == NULL)
+ return;
val = IOHIDValueGetIntegerValue(valueRef);
newVal =
joystick_map_axis(&device->generic.props[idx], val);
switch (usage)
@@ -945,6 +965,7 @@ static DWORD make_vid_pid(IOHIDDeviceRef device)
static HRESULT joydev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA
lpddi, DWORD version, int id)
{
IOHIDDeviceRef device;
+ BOOL is_joystick;
TRACE("dwDevType %u dwFlags 0x%08x version 0x%04x id %d\n", dwDevType,
dwFlags, version, id);
@@ -953,7 +974,7 @@ static HRESULT joydev_enum_deviceA(DWORD dwDevType, DWORD dwFlags,
LPDIDEVICEINS
device = get_device_ref(id);
if ((dwDevType == 0) ||
- ((dwDevType == DIDEVTYPE_JOYSTICK) && (version > 0x0300 && version
< 0x0800)) ||
+ ((dwDevType == DIDEVTYPE_JOYSTICK) && (version >= 0x0300 &&
version < 0x0800)) ||
(((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK))
&& (version >= 0x0800)))
{
if (dwFlags & DIEDFL_FORCEFEEDBACK) {
@@ -962,16 +983,19 @@ static HRESULT joydev_enum_deviceA(DWORD dwDevType, DWORD dwFlags,
LPDIDEVICEINS
if(get_ff(device, NULL) != S_OK)
return S_FALSE;
}
+ is_joystick = get_device_property_long(device, CFSTR(kIOHIDDeviceUsageKey)) ==
kHIDUsage_GD_Joystick;
/* Return joystick */
lpddi->guidInstance = DInput_Wine_OsX_Joystick_GUID;
lpddi->guidInstance.Data3 = id;
- lpddi->guidProduct = DInput_Wine_OsX_Joystick_GUID;
+ lpddi->guidProduct = DInput_PIDVID_Product_GUID;
lpddi->guidProduct.Data1 = make_vid_pid(device);
- /* we only support traditional joysticks for now */
- if (version >= 0x0800)
- lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD
<< 8);
+ lpddi->dwDevType = get_device_type(version, is_joystick);
+ lpddi->dwDevType |= DIDEVTYPE_HID;
+ lpddi->wUsagePage = 0x01; /* Desktop */
+ if (is_joystick)
+ lpddi->wUsage = 0x04; /* Joystick */
else
- lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL
<< 8);
+ lpddi->wUsage = 0x05; /* Game Pad */
sprintf(lpddi->tszInstanceName, "Joystick %d", id);
/* get the device name */
@@ -989,6 +1013,7 @@ static HRESULT joydev_enum_deviceW(DWORD dwDevType, DWORD dwFlags,
LPDIDEVICEINS
char name[MAX_PATH];
char friendly[32];
IOHIDDeviceRef device;
+ BOOL is_joystick;
TRACE("dwDevType %u dwFlags 0x%08x version 0x%04x id %d\n", dwDevType,
dwFlags, version, id);
@@ -997,7 +1022,7 @@ static HRESULT joydev_enum_deviceW(DWORD dwDevType, DWORD dwFlags,
LPDIDEVICEINS
device = get_device_ref(id);
if ((dwDevType == 0) ||
- ((dwDevType == DIDEVTYPE_JOYSTICK) && (version > 0x0300 && version
< 0x0800)) ||
+ ((dwDevType == DIDEVTYPE_JOYSTICK) && (version >= 0x0300 &&
version < 0x0800)) ||
(((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK))
&& (version >= 0x0800))) {
if (dwFlags & DIEDFL_FORCEFEEDBACK) {
@@ -1006,18 +1031,22 @@ static HRESULT joydev_enum_deviceW(DWORD dwDevType, DWORD dwFlags,
LPDIDEVICEINS
if(get_ff(device, NULL) != S_OK)
return S_FALSE;
}
+ is_joystick = get_device_property_long(device, CFSTR(kIOHIDDeviceUsageKey)) ==
kHIDUsage_GD_Joystick;
/* Return joystick */
lpddi->guidInstance = DInput_Wine_OsX_Joystick_GUID;
lpddi->guidInstance.Data3 = id;
- lpddi->guidProduct = DInput_Wine_OsX_Joystick_GUID;
+ lpddi->guidProduct = DInput_PIDVID_Product_GUID;
lpddi->guidProduct.Data1 = make_vid_pid(device);
- /* we only support traditional joysticks for now */
- if (version >= 0x0800)
- lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD
<< 8);
+ lpddi->dwDevType = get_device_type(version, is_joystick);
+ lpddi->dwDevType |= DIDEVTYPE_HID;
+ lpddi->wUsagePage = 0x01; /* Desktop */
+ if (is_joystick)
+ lpddi->wUsage = 0x04; /* Joystick */
else
- lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL
<< 8);
+ lpddi->wUsage = 0x05; /* Game Pad */
sprintf(friendly, "Joystick %d", id);
MultiByteToWideChar(CP_ACP, 0, friendly, -1, lpddi->tszInstanceName,
MAX_PATH);
+
/* get the device name */
get_osx_device_name(id, name, MAX_PATH);
@@ -1082,7 +1111,7 @@ static HRESULT alloc_device(REFGUID rguid, IDirectInputImpl
*dinput,
newDevice->generic.guidInstance = DInput_Wine_OsX_Joystick_GUID;
newDevice->generic.guidInstance.Data3 = index;
- newDevice->generic.guidProduct = DInput_Wine_OsX_Joystick_GUID;
+ newDevice->generic.guidProduct = DInput_PIDVID_Product_GUID;
newDevice->generic.guidProduct.Data1 = make_vid_pid(device);
newDevice->generic.joy_polldev = poll_osx_device_state;
@@ -1327,6 +1356,53 @@ static HRESULT joydev_create_device(IDirectInputImpl *dinput,
REFGUID rguid, REF
return DIERR_DEVICENOTREG;
}
+static HRESULT WINAPI JoystickWImpl_GetProperty(LPDIRECTINPUTDEVICE8W iface, REFGUID
rguid, LPDIPROPHEADER pdiph)
+{
+ JoystickImpl *This = impl_from_IDirectInputDevice8W(iface);
+
+ TRACE("(%p)->(%s,%p)\n", This, debugstr_guid(rguid), pdiph);
+ _dump_DIPROPHEADER(pdiph);
+
+ if (!IS_DIPROP(rguid)) return DI_OK;
+
+ switch (LOWORD(rguid)) {
+ case (DWORD_PTR) DIPROP_GUIDANDPATH:
+ {
+ static const WCHAR formatW[] =
{'\\','\\','?','\\','h','i','d','#','v','i','d','_','%','0','4','x','&',
+
'p','i','d','_','%','0','4','x','&','%','s','_','%','i',0};
+ static const WCHAR miW[] = {'m','i',0};
+ static const WCHAR igW[] = {'i','g',0};
+
+ BOOL is_gamepad;
+ IOHIDDeviceRef device = get_device_ref(This->id);
+ LPDIPROPGUIDANDPATH pd = (LPDIPROPGUIDANDPATH)pdiph;
+ WORD vid = get_device_property_long(device, CFSTR(kIOHIDVendorIDKey));
+ WORD pid = get_device_property_long(device, CFSTR(kIOHIDProductIDKey));
+
+ if (!pid || !vid)
+ return DIERR_UNSUPPORTED;
+
+ is_gamepad = is_xinput_device(&This->generic.devcaps, vid, pid);
+ pd->guidClass = GUID_DEVCLASS_HIDCLASS;
+ sprintfW(pd->wszPath, formatW, vid, pid, is_gamepad ? igW : miW,
This->id);
+
+ TRACE("DIPROP_GUIDANDPATH(%s, %s): returning fake path\n",
debugstr_guid(&pd->guidClass), debugstr_w(pd->wszPath));
+ break;
+ }
+
+ default:
+ return JoystickWGenericImpl_GetProperty(iface, rguid, pdiph);
+ }
+
+ return DI_OK;
+}
+
+static HRESULT WINAPI JoystickAImpl_GetProperty(LPDIRECTINPUTDEVICE8A iface, REFGUID
rguid, LPDIPROPHEADER pdiph)
+{
+ JoystickImpl *This = impl_from_IDirectInputDevice8A(iface);
+ return JoystickWImpl_GetProperty(IDirectInputDevice8W_from_impl(This), rguid,
pdiph);
+}
+
static HRESULT osx_set_autocenter(JoystickImpl *This,
const DIPROPDWORD *header)
{
@@ -1418,7 +1494,7 @@ static HRESULT WINAPI
JoystickWImpl_CreateEffect(IDirectInputDevice8W *iface,
EffectImpl *effect;
HRESULT hr;
- TRACE("%p %s %p %p %p\n", iface, debugstr_guid(type), params, out, outer);
+ TRACE("(%p)->(%s %p %p %p)\n", This, debugstr_guid(type), params, out,
outer);
dump_DIEFFECT(params, type, 0);
if(!This->ff){
@@ -1459,7 +1535,7 @@ static HRESULT WINAPI
JoystickAImpl_CreateEffect(IDirectInputDevice8A *iface,
{
JoystickImpl *This = impl_from_IDirectInputDevice8A(iface);
- TRACE("%p %s %p %p %p\n", iface, debugstr_guid(type), params, out, outer);
+ TRACE("(%p)->(%s %p %p %p)\n", This, debugstr_guid(type), params, out,
outer);
return
JoystickWImpl_CreateEffect(&This->generic.base.IDirectInputDevice8W_iface,
type, params, out, outer);
@@ -1509,7 +1585,7 @@ static const IDirectInputDevice8AVtbl JoystickAvt =
IDirectInputDevice2AImpl_Release,
JoystickAGenericImpl_GetCapabilities,
IDirectInputDevice2AImpl_EnumObjects,
- JoystickAGenericImpl_GetProperty,
+ JoystickAImpl_GetProperty,
JoystickAImpl_SetProperty,
IDirectInputDevice2AImpl_Acquire,
IDirectInputDevice2AImpl_Unacquire,
@@ -1545,7 +1621,7 @@ static const IDirectInputDevice8WVtbl JoystickWvt =
IDirectInputDevice2WImpl_Release,
JoystickWGenericImpl_GetCapabilities,
IDirectInputDevice2WImpl_EnumObjects,
- JoystickWGenericImpl_GetProperty,
+ JoystickWImpl_GetProperty,
JoystickWImpl_SetProperty,
IDirectInputDevice2WImpl_Acquire,
IDirectInputDevice2WImpl_Unacquire,
diff --git a/dll/directx/wine/dinput/joystick_private.h
b/dll/directx/wine/dinput/joystick_private.h
index e758cacf6df..545304eabce 100644
--- a/dll/directx/wine/dinput/joystick_private.h
+++ b/dll/directx/wine/dinput/joystick_private.h
@@ -33,6 +33,9 @@
#define MAX_PROPS 164
struct JoystickGenericImpl;
+/* Number of buttons for which to allow remapping */
+#define MAX_MAP_BUTTONS 32
+
typedef void joy_polldev_handler(LPDIRECTINPUTDEVICE8A iface);
typedef struct JoystickGenericImpl
@@ -47,6 +50,7 @@ typedef struct JoystickGenericImpl
char *name;
int device_axis_count; /* Total number of axes in the device */
int *axis_map; /* User axes remapping */
+ int button_map[MAX_MAP_BUTTONS]; /* User button remapping */
LONG deadzone; /* Default dead-zone */
joy_polldev_handler *joy_polldev;
@@ -96,5 +100,6 @@ HRESULT WINAPI JoystickWGenericImpl_SetActionMap(LPDIRECTINPUTDEVICE8W
iface, LP
DWORD typeFromGUID(REFGUID guid) DECLSPEC_HIDDEN;
void dump_DIEFFECT(LPCDIEFFECT eff, REFGUID guid, DWORD dwFlags) DECLSPEC_HIDDEN;
+BOOL is_xinput_device(const DIDEVCAPS *devcaps, WORD vid, WORD pid) DECLSPEC_HIDDEN;
#endif /* __WINE_DLLS_DINPUT_JOYSTICK_PRIVATE_H */
diff --git a/dll/directx/wine/dinput/keyboard.c b/dll/directx/wine/dinput/keyboard.c
index 642d0c0beb8..0747f5d8c8b 100644
--- a/dll/directx/wine/dinput/keyboard.c
+++ b/dll/directx/wine/dinput/keyboard.c
@@ -215,6 +215,9 @@ static HRESULT keyboarddev_enum_deviceA(DWORD dwDevType, DWORD
dwFlags, LPDIDEVI
if (id != 0)
return E_FAIL;
+ if (dwFlags & DIEDFL_FORCEFEEDBACK)
+ return S_FALSE;
+
if ((dwDevType == 0) ||
((dwDevType == DIDEVTYPE_KEYBOARD) && (version < 0x0800)) ||
(((dwDevType == DI8DEVCLASS_KEYBOARD) || (dwDevType == DI8DEVTYPE_KEYBOARD))
&& (version >= 0x0800))) {
@@ -233,6 +236,9 @@ static HRESULT keyboarddev_enum_deviceW(DWORD dwDevType, DWORD
dwFlags, LPDIDEVI
if (id != 0)
return E_FAIL;
+ if (dwFlags & DIEDFL_FORCEFEEDBACK)
+ return S_FALSE;
+
if ((dwDevType == 0) ||
((dwDevType == DIDEVTYPE_KEYBOARD) && (version < 0x0800)) ||
(((dwDevType == DI8DEVCLASS_KEYBOARD) || (dwDevType == DI8DEVTYPE_KEYBOARD))
&& (version >= 0x0800))) {
@@ -520,11 +526,6 @@ static HRESULT WINAPI SysKeyboardAImpl_GetDeviceInfo(
SysKeyboardImpl *This = impl_from_IDirectInputDevice8A(iface);
TRACE("(this=%p,%p)\n", This, pdidi);
- if (pdidi->dwSize != sizeof(DIDEVICEINSTANCEA)) {
- WARN(" dinput3 not supported yet...\n");
- return DI_OK;
- }
-
fill_keyboard_dideviceinstanceA(pdidi, This->base.dinput->dwVersion,
This->subtype);
return DI_OK;
@@ -553,7 +554,7 @@ static HRESULT WINAPI
SysKeyboardWImpl_GetProperty(LPDIRECTINPUTDEVICE8W iface,
{
SysKeyboardImpl *This = impl_from_IDirectInputDevice8W(iface);
- TRACE("(%p) %s,%p\n", iface, debugstr_guid(rguid), pdiph);
+ TRACE("(%p)->(%s,%p)\n", This, debugstr_guid(rguid), pdiph);
_dump_DIPROPHEADER(pdiph);
if (!IS_DIPROP(rguid)) return DI_OK;
@@ -619,7 +620,8 @@ static HRESULT WINAPI
SysKeyboardWImpl_BuildActionMap(LPDIRECTINPUTDEVICE8W ifac
LPCWSTR lpszUserName,
DWORD dwFlags)
{
- FIXME("(%p)->(%p,%s,%08x): semi-stub !\n", iface, lpdiaf,
debugstr_w(lpszUserName), dwFlags);
+ SysKeyboardImpl *This = impl_from_IDirectInputDevice8W(iface);
+ FIXME("(%p)->(%p,%s,%08x): semi-stub !\n", This, lpdiaf,
debugstr_w(lpszUserName), dwFlags);
return _build_action_map(iface, lpdiaf, lpszUserName, dwFlags, DIKEYBOARD_MASK,
&c_dfDIKeyboard);
}
@@ -659,7 +661,8 @@ static HRESULT WINAPI
SysKeyboardWImpl_SetActionMap(LPDIRECTINPUTDEVICE8W iface,
LPCWSTR lpszUserName,
DWORD dwFlags)
{
- FIXME("(%p)->(%p,%s,%08x): semi-stub !\n", iface, lpdiaf,
debugstr_w(lpszUserName), dwFlags);
+ SysKeyboardImpl *This = impl_from_IDirectInputDevice8W(iface);
+ FIXME("(%p)->(%p,%s,%08x): semi-stub !\n", This, lpdiaf,
debugstr_w(lpszUserName), dwFlags);
return _set_action_map(iface, lpdiaf, lpszUserName, dwFlags, &c_dfDIKeyboard);
}
@@ -687,6 +690,8 @@ static HRESULT WINAPI
SysKeyboardAImpl_SetActionMap(LPDIRECTINPUTDEVICE8A iface,
hr = SysKeyboardWImpl_SetActionMap(&This->base.IDirectInputDevice8W_iface,
&diafW, lpszUserNameW, dwFlags);
+ lpdiaf->dwCRC = diafW.dwCRC;
+
HeapFree(GetProcessHeap(), 0, diafW.rgoAction);
HeapFree(GetProcessHeap(), 0, lpszUserNameW);
diff --git a/dll/directx/wine/dinput/mouse.c b/dll/directx/wine/dinput/mouse.c
index 71333593515..ef408bbad5e 100644
--- a/dll/directx/wine/dinput/mouse.c
+++ b/dll/directx/wine/dinput/mouse.c
@@ -28,6 +28,7 @@
#include "windef.h"
#include "winbase.h"
#include "wingdi.h"
+#include "wine/winternl.h"
#include "winuser.h"
#include "winerror.h"
#include "winreg.h"
@@ -157,6 +158,9 @@ static HRESULT mousedev_enum_deviceA(DWORD dwDevType, DWORD dwFlags,
LPDIDEVICEI
if (id != 0)
return E_FAIL;
+ if (dwFlags & DIEDFL_FORCEFEEDBACK)
+ return S_FALSE;
+
if ((dwDevType == 0) ||
((dwDevType == DIDEVTYPE_MOUSE) && (version < 0x0800)) ||
(((dwDevType == DI8DEVCLASS_POINTER) || (dwDevType == DI8DEVTYPE_MOUSE)) &&
(version >= 0x0800))) {
@@ -175,6 +179,9 @@ static HRESULT mousedev_enum_deviceW(DWORD dwDevType, DWORD dwFlags,
LPDIDEVICEI
if (id != 0)
return E_FAIL;
+ if (dwFlags & DIEDFL_FORCEFEEDBACK)
+ return S_FALSE;
+
if ((dwDevType == 0) ||
((dwDevType == DIDEVTYPE_MOUSE) && (version < 0x0800)) ||
(((dwDevType == DI8DEVCLASS_POINTER) || (dwDevType == DI8DEVTYPE_MOUSE)) &&
(version >= 0x0800))) {
@@ -211,9 +218,9 @@ static SysMouseImpl *alloc_device(REFGUID rguid, IDirectInputImpl
*dinput)
get_app_key(&hkey, &appkey);
if (!get_config_key(hkey, appkey, "MouseWarpOverride", buffer,
sizeof(buffer)))
{
- if (!strcasecmp(buffer, "disable"))
+ if (!_strnicmp(buffer, "disable", -1))
newDevice->warp_override = WARP_DISABLE;
- else if (!strcasecmp(buffer, "force"))
+ else if (!_strnicmp(buffer, "force", -1))
newDevice->warp_override = WARP_FORCE_ON;
}
if (appkey) RegCloseKey(appkey);
@@ -723,6 +730,9 @@ static HRESULT WINAPI
SysMouseWImpl_GetObjectInfo(LPDIRECTINPUTDEVICE8W iface,
else if (pdidoi->dwType & DIDFT_BUTTON)
wsprintfW(pdidoi->tszName, buttonW, DIDFT_GETINSTANCE(pdidoi->dwType) -
3);
+ if(pdidoi->dwType & DIDFT_AXIS)
+ pdidoi->dwFlags |= DIDOI_ASPECTPOSITION;
+
_dump_OBJECTINSTANCEW(pdidoi);
return res;
}
@@ -758,11 +768,6 @@ static HRESULT WINAPI SysMouseAImpl_GetDeviceInfo(
SysMouseImpl *This = impl_from_IDirectInputDevice8A(iface);
TRACE("(this=%p,%p)\n", This, pdidi);
- if (pdidi->dwSize != sizeof(DIDEVICEINSTANCEA)) {
- WARN(" dinput3 not supported yet...\n");
- return DI_OK;
- }
-
fill_mouse_dideviceinstanceA(pdidi, This->base.dinput->dwVersion);
return DI_OK;
@@ -828,7 +833,8 @@ static HRESULT WINAPI SysMouseWImpl_SetActionMap(LPDIRECTINPUTDEVICE8W
iface,
LPCWSTR lpszUserName,
DWORD dwFlags)
{
- FIXME("(%p)->(%p,%s,%08x): semi-stub !\n", iface, lpdiaf,
debugstr_w(lpszUserName), dwFlags);
+ SysMouseImpl *This = impl_from_IDirectInputDevice8W(iface);
+ FIXME("(%p)->(%p,%s,%08x): semi-stub !\n", This, lpdiaf,
debugstr_w(lpszUserName), dwFlags);
return _set_action_map(iface, lpdiaf, lpszUserName, dwFlags, &c_dfDIMouse2);
}
@@ -856,6 +862,8 @@ static HRESULT WINAPI SysMouseAImpl_SetActionMap(LPDIRECTINPUTDEVICE8A
iface,
hr = SysMouseWImpl_SetActionMap(&This->base.IDirectInputDevice8W_iface,
&diafW, lpszUserNameW, dwFlags);
+ lpdiaf->dwCRC = diafW.dwCRC;
+
HeapFree(GetProcessHeap(), 0, diafW.rgoAction);
HeapFree(GetProcessHeap(), 0, lpszUserNameW);
diff --git a/dll/directx/wine/dinput/precomp.h b/dll/directx/wine/dinput/precomp.h
index 9504beb6961..d7693306500 100644
--- a/dll/directx/wine/dinput/precomp.h
+++ b/dll/directx/wine/dinput/precomp.h
@@ -2,8 +2,6 @@
#ifndef __WINE_DINPUT_PRECOMP_H
#define __WINE_DINPUT_PRECOMP_H
-#include <wine/config.h>
-
#define WIN32_NO_STATUS
#define _INC_WINDOWS
#define COM_NO_WINDOWS_H
diff --git a/media/doc/README.WINE b/media/doc/README.WINE
index 7fc878f7c5c..4146f4e260d 100644
--- a/media/doc/README.WINE
+++ b/media/doc/README.WINE
@@ -30,7 +30,7 @@ dll/directx/wine/d3dx9_24 => 43 # Synced to WineStaging-4.0
dll/directx/wine/d3dxof # Synced to WineStaging-3.17
dll/directx/wine/ddraw # Synced to WineStaging-3.3
dll/directx/wine/devenum # Synced to WineStaging-4.18
-dll/directx/wine/dinput # Synced to WineStaging-4.0
+dll/directx/wine/dinput # Synced to WineStaging-4.18
dll/directx/wine/dinput8 # Synced to WineStaging-3.3
dll/directx/wine/dmusic # Synced to WineStaging-4.0
dll/directx/wine/dplay # Synced to WineStaging-3.3