[DINPUT] Sync with Wine Staging 4.18. CORE-16441

This commit is contained in:
Amine Khaldi 2019-10-26 13:03:34 +01:00
parent 1477b2deb7
commit 41c8c312e1
16 changed files with 1001 additions and 376 deletions

View file

@ -1,5 +1,5 @@
add_definitions(-D__WINESRC__) add_definitions(-D__WINESRC__ -DDIRECTINPUT_VERSION=0x0700)
include_directories(${REACTOS_SOURCE_DIR}/sdk/include/reactos/wine) include_directories(${REACTOS_SOURCE_DIR}/sdk/include/reactos/wine)
spec2def(dinput.dll dinput.spec ADD_IMPORTLIB) spec2def(dinput.dll dinput.spec ADD_IMPORTLIB)

View file

@ -18,17 +18,23 @@
#define NONAMELESSUNION #define NONAMELESSUNION
#include "wine/unicode.h" #include "wine/unicode.h"
#include "objbase.h" #include "objbase.h"
#include "dinput_private.h" #include "dinput_private.h"
#include "device_private.h" #include "device_private.h"
#include "resource.h" #include "resource.h"
#include "wine/heap.h"
typedef struct { typedef struct {
int nobjects; int nobjects;
IDirectInputDevice8W *lpdid; IDirectInputDevice8W *lpdid;
DIDEVICEINSTANCEW ddi; DIDEVICEINSTANCEW ddi;
DIDEVICEOBJECTINSTANCEW ddo[256]; DIDEVICEOBJECTINSTANCEW ddo[256];
/* ActionFormat for every user.
* In same order as ConfigureDevicesData usernames */
DIACTIONFORMATW *user_afs;
} DeviceData; } DeviceData;
typedef struct { typedef struct {
@ -38,10 +44,11 @@ typedef struct {
typedef struct { typedef struct {
IDirectInput8W *lpDI; IDirectInput8W *lpDI;
LPDIACTIONFORMATW lpdiaf;
LPDIACTIONFORMATW original_lpdiaf; LPDIACTIONFORMATW original_lpdiaf;
DIDevicesData devices_data; DIDevicesData devices_data;
int display_only; int display_only;
int nusernames;
WCHAR **usernames;
} ConfigureDevicesData; } ConfigureDevicesData;
/* /*
@ -57,27 +64,43 @@ static BOOL CALLBACK collect_objects(LPCDIDEVICEOBJECTINSTANCEW lpddo, LPVOID pv
return DIENUM_CONTINUE; return DIENUM_CONTINUE;
} }
static BOOL CALLBACK count_devices(LPCDIDEVICEINSTANCEW lpddi, IDirectInputDevice8W *lpdid, DWORD dwFlags, DWORD dwRemaining, LPVOID pvRef)
{
DIDevicesData *data = (DIDevicesData*) pvRef;
data->ndevices++;
return DIENUM_CONTINUE;
}
static BOOL CALLBACK collect_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 = &data->devices[data->ndevices]; DeviceData *device;
device->lpdid = lpdid; int i, j;
device->ddi = *lpddi;
IDirectInputDevice_AddRef(lpdid); IDirectInputDevice_AddRef(lpdid);
/* 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;
device->nobjects = 0; device->nobjects = 0;
IDirectInputDevice_EnumObjects(lpdid, collect_objects, (LPVOID) device, DIDFT_ALL); 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; return DIENUM_CONTINUE;
} }
@ -170,10 +193,18 @@ static DeviceData* get_cur_device(HWND dialog)
return &data->devices_data.devices[sel]; 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); 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) static int dialog_display_only(HWND dialog)
@ -182,40 +213,36 @@ static int dialog_display_only(HWND dialog)
return data->display_only; 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; 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 */ /* Collect and insert */
data->ndevices = 0; data->devices_data.ndevices = 0;
IDirectInput8_EnumDevicesBySemantics(lpDI, NULL, lpdiaf, collect_devices, (LPVOID) data, 0); IDirectInput8_EnumDevicesBySemantics(data->lpDI, NULL, data->original_lpdiaf, collect_devices, (LPVOID) data, 0);
for (i=0; i < data->ndevices; i++) for (i = 0; i < data->devices_data.ndevices; i++)
SendDlgItemMessageW(dialog, IDC_CONTROLLERCOMBO, CB_ADDSTRING, 0, (LPARAM) data->devices[i].ddi.tszProductName ); 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) static void destroy_data(HWND dialog)
{ {
int i; int i, j;
ConfigureDevicesData *data = (ConfigureDevicesData*) GetWindowLongPtrW(dialog, DWLP_USER); ConfigureDevicesData *data = (ConfigureDevicesData*) GetWindowLongPtrW(dialog, DWLP_USER);
DIDevicesData *devices_data = &data->devices_data; DIDevicesData *devices_data = &data->devices_data;
/* Free the devices */ /* Free the devices */
for (i=0; i < devices_data->ndevices; i++) for (i=0; i < devices_data->ndevices; i++)
{
IDirectInputDevice8_Release(devices_data->devices[i].lpdid); 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); 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) static void fill_device_object_list(HWND dialog)
@ -231,6 +258,7 @@ static void fill_device_object_list(HWND dialog)
/* Add each object */ /* Add each object */
for (i=0; i < device->nobjects; i++) for (i=0; i < device->nobjects; i++)
{ {
DWORD ddo_inst, ddo_type;
int action = -1; int action = -1;
item.mask = LVIF_TEXT | LVIF_PARAM; item.mask = LVIF_TEXT | LVIF_PARAM;
@ -241,12 +269,20 @@ static void fill_device_object_list(HWND dialog)
/* Add the item */ /* Add the item */
SendDlgItemMessageW(dialog, IDC_DEVICEOBJECTSLIST, LVM_INSERTITEMW, 0, (LPARAM) &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++) 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) && 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; action = j;
break; break;
@ -260,7 +296,7 @@ static void fill_device_object_list(HWND dialog)
static void show_suitable_actions(HWND dialog) static void show_suitable_actions(HWND dialog)
{ {
DeviceData *device = get_cur_device(dialog); DeviceData *device = get_cur_device(dialog);
LPDIACTIONFORMATW lpdiaf = get_cur_lpdiaf(dialog); LPDIACTIONFORMATW lpdiaf = get_original_lpdiaf(dialog);
int i, added = 0; int i, added = 0;
int obj = lv_get_cur_item(dialog); 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 obj = lv_get_cur_item(dialog);
int old_action = lv_get_item_data(dialog, obj); int old_action = lv_get_item_data(dialog, obj);
int used_obj; int used_obj;
DWORD type;
DIDEVICEOBJECTINSTANCEW ddo = device->ddo[obj];
if (old_action == action) return; 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 */ /* Clear old action */
if (old_action != -1) if (old_action != -1)
@ -320,7 +359,7 @@ static void assign_action(HWND dialog)
lv_set_action(dialog, used_obj, -1, lpdiaf); lv_set_action(dialog, used_obj, -1, lpdiaf);
/* Set new action */ /* Set new action */
lpdiaf->rgoAction[action].dwObjID = ddo.dwType; lpdiaf->rgoAction[action].dwObjID = type;
lpdiaf->rgoAction[action].guidInstance = device->ddi.guidInstance; lpdiaf->rgoAction[action].guidInstance = device->ddi.guidInstance;
lpdiaf->rgoAction[action].dwHow = DIAH_USERCONFIG; lpdiaf->rgoAction[action].dwHow = DIAH_USERCONFIG;
@ -328,24 +367,35 @@ static void assign_action(HWND dialog)
lv_set_action(dialog, obj, action, lpdiaf); lv_set_action(dialog, obj, action, lpdiaf);
} }
static void copy_actions(LPDIACTIONFORMATW to, LPDIACTIONFORMATW from)
{
DWORD i;
for (i=0; i < from->dwNumActions; 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;
}
}
static void reset_actions(HWND dialog) static void reset_actions(HWND dialog)
{ {
ConfigureDevicesData *data = (ConfigureDevicesData*) GetWindowLongPtrW(dialog, DWLP_USER); ConfigureDevicesData *data = (ConfigureDevicesData*) GetWindowLongPtrW(dialog, DWLP_USER);
LPDIACTIONFORMATW to = data->lpdiaf, from = data->original_lpdiaf; DIDevicesData *ddata = (DIDevicesData*) &data->devices_data;
unsigned i, j;
copy_actions(to, from); for (i = 0; i < data->devices_data.ndevices; i++)
{
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 save_actions(HWND dialog) {
ConfigureDevicesData *data = (ConfigureDevicesData*) GetWindowLongPtrW(dialog, DWLP_USER);
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) 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; ConfigureDevicesData *data = (ConfigureDevicesData*) lParam;
/* Initialize action format and enumerate devices */ /* 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 */ /* Store information in the window */
SetWindowLongPtrW(dialog, DWLP_USER, (LONG_PTR) data); SetWindowLongPtrW(dialog, DWLP_USER, (LONG_PTR) data);
init_listview_columns(dialog); 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 */ /* Select the first device and show its actions */
SendDlgItemMessageW(dialog, IDC_CONTROLLERCOMBO, CB_SETCURSEL, 0, 0); SendDlgItemMessageW(dialog, IDC_CONTROLLERCOMBO, CB_SETCURSEL, 0, 0);
SendDlgItemMessageW(dialog, IDC_PLAYERCOMBO, CB_SETCURSEL, 0, 0);
fill_device_object_list(dialog); fill_device_object_list(dialog);
ShowCursor(TRUE);
break; break;
} }
case WM_DESTROY:
ShowCursor(FALSE);
break;
case WM_NOTIFY: case WM_NOTIFY:
switch (((LPNMHDR)lParam)->code) switch (((LPNMHDR)lParam)->code)
@ -407,6 +458,7 @@ static INT_PTR CALLBACK ConfigureDevicesDlgProc(HWND dialog, UINT uMsg, WPARAM w
break; break;
case IDC_CONTROLLERCOMBO: case IDC_CONTROLLERCOMBO:
case IDC_PLAYERCOMBO:
switch (HIWORD(wParam)) switch (HIWORD(wParam))
{ {
@ -417,12 +469,12 @@ static INT_PTR CALLBACK ConfigureDevicesDlgProc(HWND dialog, UINT uMsg, WPARAM w
break; break;
case IDOK: case IDOK:
save_actions(dialog);
EndDialog(dialog, 0); EndDialog(dialog, 0);
destroy_data(dialog); destroy_data(dialog);
break; break;
case IDCANCEL: case IDCANCEL:
reset_actions(dialog);
EndDialog(dialog, 0); EndDialog(dialog, 0);
destroy_data(dialog); destroy_data(dialog);
break; break;
@ -445,15 +497,48 @@ HRESULT _configure_devices(IDirectInput8W *iface,
LPVOID pvRefData LPVOID pvRefData
) )
{ {
int i;
DWORD size;
WCHAR *username = NULL;
ConfigureDevicesData data; ConfigureDevicesData data;
data.lpDI = iface; data.lpDI = iface;
data.lpdiaf = lpdiCDParams->lprgFormats; data.original_lpdiaf = lpdiCDParams->lprgFormats;
data.display_only = !(dwFlags & DICD_EDIT); 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(); InitCommonControls();
DialogBoxParamW(DINPUT_instance, (const WCHAR *)MAKEINTRESOURCE(IDD_CONFIGUREDEVICES), DialogBoxParamW(DINPUT_instance, (const WCHAR *)MAKEINTRESOURCE(IDD_CONFIGUREDEVICES),
lpdiCDParams->hwnd, ConfigureDevicesDlgProc, (LPARAM)&data); lpdiCDParams->hwnd, ConfigureDevicesDlgProc, (LPARAM)&data);
heap_free(username);
heap_free(data.usernames);
return DI_OK; return DI_OK;
} }

View file

@ -30,6 +30,7 @@
#include <string.h> #include <string.h>
#include "wine/debug.h" #include "wine/debug.h"
#include "wine/unicode.h" #include "wine/unicode.h"
#include "wine/heap.h"
#include "windef.h" #include "windef.h"
#include "winbase.h" #include "winbase.h"
#include "winreg.h" #include "winreg.h"
@ -643,12 +644,29 @@ static DWORD semantic_to_obj_id(IDirectInputDeviceImpl* This, DWORD dwSemantic)
return type | (0x0000ff00 & (obj_instance << 8)); 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 * get_mapping_key
* Retrieves an open registry key to save the mapping, parametrized for an username, * Retrieves an open registry key to save the mapping, parametrized for an username,
* specific device and specific action mapping guid. * 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[] = { static const WCHAR subkey[] = {
'S','o','f','t','w','a','r','e','\\', '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); sprintfW(keyname, subkey, username, device, guid);
/* The key used is HKCU\Software\Wine\DirectInput\Mappings\[username]\[device]\[mapping_guid] */ /* The key used is HKCU\Software\Wine\DirectInput\Mappings\[username]\[device]\[mapping_guid] */
if (RegCreateKeyW(HKEY_CURRENT_USER, keyname, &hkey)) if (create) {
hkey = 0; if (RegCreateKeyW(HKEY_CURRENT_USER, keyname, &hkey))
hkey = 0;
} else if (RegOpenKeyW(HKEY_CURRENT_USER, keyname, &hkey))
hkey = 0;
HeapFree(GetProcessHeap(), 0, keyname); HeapFree(GetProcessHeap(), 0, keyname);
return hkey; 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; WCHAR *guid_str = NULL;
DIDEVICEINSTANCEW didev; DIDEVICEINSTANCEW didev;
@ -684,7 +705,9 @@ static HRESULT save_mapping_settings(IDirectInputDevice8W *iface, LPDIACTIONFORM
if (StringFromCLSID(&lpdiaf->guidActionMap, &guid_str) != S_OK) if (StringFromCLSID(&lpdiaf->guidActionMap, &guid_str) != S_OK)
return DI_SETTINGSNOTSAVED; 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) if (!hkey)
{ {
@ -714,12 +737,12 @@ static HRESULT save_mapping_settings(IDirectInputDevice8W *iface, LPDIACTIONFORM
return DI_OK; 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; HKEY hkey;
WCHAR *guid_str; WCHAR *guid_str;
DIDEVICEINSTANCEW didev; DIDEVICEINSTANCEW didev;
int i, mapped = 0; int i;
didev.dwSize = sizeof(didev); didev.dwSize = sizeof(didev);
IDirectInputDevice8_GetDeviceInfo(&This->IDirectInputDevice8W_iface, &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) if (StringFromCLSID(&lpdiaf->guidActionMap, &guid_str) != S_OK)
return FALSE; return FALSE;
hkey = get_mapping_key(didev.tszInstanceName, username, guid_str); hkey = get_mapping_key(didev.tszInstanceName, username, guid_str, FALSE);
if (!hkey) if (!hkey)
{ {
@ -748,15 +771,21 @@ static BOOL load_mapping_settings(IDirectInputDeviceImpl *This, LPDIACTIONFORMAT
{ {
lpdiaf->rgoAction[i].dwObjID = id; lpdiaf->rgoAction[i].dwObjID = id;
lpdiaf->rgoAction[i].guidInstance = didev.guidInstance; lpdiaf->rgoAction[i].guidInstance = didev.guidInstance;
lpdiaf->rgoAction[i].dwHow = DIAH_DEFAULT; lpdiaf->rgoAction[i].dwHow = DIAH_USERCONFIG;
mapped += 1;
} }
else
{
memset(&lpdiaf->rgoAction[i].guidInstance, 0, sizeof(GUID));
lpdiaf->rgoAction[i].dwHow = DIAH_UNMAPPED;
}
} }
RegCloseKey(hkey); RegCloseKey(hkey);
CoTaskMemFree(guid_str); 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) 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); 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++) 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) if ((lpdiaf->rgoAction[i].dwSemantic & devMask) == devMask)
{ {
DWORD obj_id = semantic_to_obj_id(This, lpdiaf->rgoAction[i].dwSemantic); 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; if (!has_actions) return DI_NOEFFECT;
return IDirectInputDevice8WImpl_BuildActionMap(iface, lpdiaf, lpszUserName, dwFlags); return IDirectInputDevice8WImpl_BuildActionMap(iface, lpdiaf, lpszUserName, dwFlags);
@ -831,6 +873,7 @@ HRESULT _set_action_map(LPDIRECTINPUTDEVICE8W iface, LPDIACTIONFORMATW lpdiaf, L
DIPROPSTRING dps; DIPROPSTRING dps;
WCHAR username[MAX_PATH]; WCHAR username[MAX_PATH];
DWORD username_size = MAX_PATH; DWORD username_size = MAX_PATH;
DWORD new_crc = 0;
int i, action = 0, num_actions = 0; int i, action = 0, num_actions = 0;
unsigned int offset = 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.dwFlags = DIDF_RELAXIS;
data_format.dwDataSize = lpdiaf->dwDataSize; 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 */ /* Count the actions */
for (i=0; i < lpdiaf->dwNumActions; i++) 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++; 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; This->num_actions = num_actions;
@ -880,8 +941,40 @@ HRESULT _set_action_map(LPDIRECTINPUTDEVICE8W iface, LPDIACTIONFORMATW lpdiaf, L
action++; 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); IDirectInputDevice8_SetDataFormat(iface, &data_format);
HeapFree(GetProcessHeap(), 0, obj_df); HeapFree(GetProcessHeap(), 0, obj_df);
@ -1140,7 +1233,7 @@ ULONG WINAPI IDirectInputDevice2WImpl_Release(LPDIRECTINPUTDEVICE8W iface)
IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8W(iface); IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8W(iface);
ULONG ref = InterlockedDecrement(&(This->ref)); 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; if (ref) return ref;
@ -1168,7 +1261,7 @@ ULONG WINAPI IDirectInputDevice2WImpl_Release(LPDIRECTINPUTDEVICE8W iface)
HeapFree(GetProcessHeap(), 0, This); HeapFree(GetProcessHeap(), 0, This);
return DI_OK; return ref;
} }
ULONG WINAPI IDirectInputDevice2AImpl_Release(LPDIRECTINPUTDEVICE8A iface) ULONG WINAPI IDirectInputDevice2AImpl_Release(LPDIRECTINPUTDEVICE8A iface)
@ -1181,7 +1274,7 @@ HRESULT WINAPI IDirectInputDevice2WImpl_QueryInterface(LPDIRECTINPUTDEVICE8W ifa
{ {
IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8W(iface); 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) || if (IsEqualGUID(&IID_IUnknown, riid) ||
IsEqualGUID(&IID_IDirectInputDeviceA, riid) || IsEqualGUID(&IID_IDirectInputDeviceA, riid) ||
IsEqualGUID(&IID_IDirectInputDevice2A, riid) || IsEqualGUID(&IID_IDirectInputDevice2A, riid) ||
@ -1203,7 +1296,7 @@ HRESULT WINAPI IDirectInputDevice2WImpl_QueryInterface(LPDIRECTINPUTDEVICE8W ifa
} }
WARN("Unsupported interface!\n"); WARN("Unsupported interface!\n");
return E_FAIL; return E_NOINTERFACE;
} }
HRESULT WINAPI IDirectInputDevice2AImpl_QueryInterface(LPDIRECTINPUTDEVICE8A iface, REFIID riid, LPVOID *ppobj) 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) ULONG WINAPI IDirectInputDevice2WImpl_AddRef(LPDIRECTINPUTDEVICE8W iface)
{ {
IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8W(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) ULONG WINAPI IDirectInputDevice2AImpl_AddRef(LPDIRECTINPUTDEVICE8A iface)
@ -1231,7 +1326,7 @@ HRESULT WINAPI IDirectInputDevice2AImpl_EnumObjects(LPDIRECTINPUTDEVICE8A iface,
DIDEVICEOBJECTINSTANCEA ddoi; DIDEVICEOBJECTINSTANCEA ddoi;
int i; 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 = "); TRACE(" - flags = ");
_dump_EnumObjects_flags(dwFlags); _dump_EnumObjects_flags(dwFlags);
TRACE("\n"); TRACE("\n");
@ -1261,7 +1356,7 @@ HRESULT WINAPI IDirectInputDevice2WImpl_EnumObjects(LPDIRECTINPUTDEVICE8W iface,
DIDEVICEOBJECTINSTANCEW ddoi; DIDEVICEOBJECTINSTANCEW ddoi;
int i; 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 = "); TRACE(" - flags = ");
_dump_EnumObjects_flags(dwFlags); _dump_EnumObjects_flags(dwFlags);
TRACE("\n"); TRACE("\n");
@ -1292,7 +1387,7 @@ HRESULT WINAPI IDirectInputDevice2WImpl_GetProperty(LPDIRECTINPUTDEVICE8W iface,
{ {
IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8W(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); _dump_DIPROPHEADER(pdiph);
if (!IS_DIPROP(rguid)) return DI_OK; if (!IS_DIPROP(rguid)) return DI_OK;
@ -1357,7 +1452,7 @@ HRESULT WINAPI IDirectInputDevice2WImpl_SetProperty(
{ {
IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8W(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); _dump_DIPROPHEADER(pdiph);
if (!IS_DIPROP(rguid)) return DI_OK; 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) 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; return DI_OK;
} }
@ -1610,7 +1706,8 @@ HRESULT WINAPI IDirectInputDevice2AImpl_RunControlPanel(LPDIRECTINPUTDEVICE8A if
HRESULT WINAPI IDirectInputDevice2WImpl_Initialize(LPDIRECTINPUTDEVICE8W iface, HINSTANCE hinst, DWORD dwVersion, HRESULT WINAPI IDirectInputDevice2WImpl_Initialize(LPDIRECTINPUTDEVICE8W iface, HINSTANCE hinst, DWORD dwVersion,
REFGUID rguid) 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; return DI_OK;
} }
@ -1628,7 +1725,8 @@ HRESULT WINAPI IDirectInputDevice2AImpl_Initialize(LPDIRECTINPUTDEVICE8A iface,
HRESULT WINAPI IDirectInputDevice2WImpl_CreateEffect(LPDIRECTINPUTDEVICE8W iface, REFGUID rguid, LPCDIEFFECT lpeff, HRESULT WINAPI IDirectInputDevice2WImpl_CreateEffect(LPDIRECTINPUTDEVICE8W iface, REFGUID rguid, LPCDIEFFECT lpeff,
LPDIRECTINPUTEFFECT *ppdef, LPUNKNOWN pUnkOuter) 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"); FIXME("not available in the generic implementation\n");
*ppdef = NULL; *ppdef = NULL;
@ -1648,9 +1746,9 @@ HRESULT WINAPI IDirectInputDevice2AImpl_EnumEffects(
LPVOID lpvRef, LPVOID lpvRef,
DWORD dwFlags) DWORD dwFlags)
{ {
FIXME("(this=%p,%p,%p,0x%08x): stub!\n", IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8A(iface);
iface, lpCallback, lpvRef, dwFlags); FIXME("%p)->(%p,%p,0x%08x): stub!\n", This, lpCallback, lpvRef, dwFlags);
return DI_OK; return DI_OK;
} }
@ -1660,9 +1758,9 @@ HRESULT WINAPI IDirectInputDevice2WImpl_EnumEffects(
LPVOID lpvRef, LPVOID lpvRef,
DWORD dwFlags) DWORD dwFlags)
{ {
FIXME("(this=%p,%p,%p,0x%08x): stub!\n", IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8W(iface);
iface, lpCallback, lpvRef, dwFlags); FIXME("(%p)->(%p,%p,0x%08x): stub!\n", This, lpCallback, lpvRef, dwFlags);
return DI_OK; return DI_OK;
} }
@ -1671,8 +1769,8 @@ HRESULT WINAPI IDirectInputDevice2AImpl_GetEffectInfo(
LPDIEFFECTINFOA lpdei, LPDIEFFECTINFOA lpdei,
REFGUID rguid) REFGUID rguid)
{ {
FIXME("(this=%p,%p,%s): stub!\n", IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8A(iface);
iface, lpdei, debugstr_guid(rguid)); FIXME("(%p)->(%p,%s): stub!\n", This, lpdei, debugstr_guid(rguid));
return DI_OK; return DI_OK;
} }
@ -1681,14 +1779,15 @@ HRESULT WINAPI IDirectInputDevice2WImpl_GetEffectInfo(
LPDIEFFECTINFOW lpdei, LPDIEFFECTINFOW lpdei,
REFGUID rguid) REFGUID rguid)
{ {
FIXME("(this=%p,%p,%s): stub!\n", IDirectInputDeviceImpl *This = impl_from_IDirectInputDevice8W(iface);
iface, lpdei, debugstr_guid(rguid)); FIXME("(%p)->(%p,%s): stub!\n", This, lpdei, debugstr_guid(rguid));
return DI_OK; return DI_OK;
} }
HRESULT WINAPI IDirectInputDevice2WImpl_GetForceFeedbackState(LPDIRECTINPUTDEVICE8W iface, LPDWORD pdwOut) 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; return DI_OK;
} }
@ -1700,7 +1799,8 @@ HRESULT WINAPI IDirectInputDevice2AImpl_GetForceFeedbackState(LPDIRECTINPUTDEVIC
HRESULT WINAPI IDirectInputDevice2WImpl_SendForceFeedbackCommand(LPDIRECTINPUTDEVICE8W iface, DWORD dwFlags) 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; return DI_NOEFFECT;
} }
@ -1713,7 +1813,8 @@ HRESULT WINAPI IDirectInputDevice2AImpl_SendForceFeedbackCommand(LPDIRECTINPUTDE
HRESULT WINAPI IDirectInputDevice2WImpl_EnumCreatedEffectObjects(LPDIRECTINPUTDEVICE8W iface, HRESULT WINAPI IDirectInputDevice2WImpl_EnumCreatedEffectObjects(LPDIRECTINPUTDEVICE8W iface,
LPDIENUMCREATEDEFFECTOBJECTSCALLBACK lpCallback, LPVOID lpvRef, DWORD dwFlags) 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; return DI_OK;
} }
@ -1726,7 +1827,8 @@ HRESULT WINAPI IDirectInputDevice2AImpl_EnumCreatedEffectObjects(LPDIRECTINPUTDE
HRESULT WINAPI IDirectInputDevice2WImpl_Escape(LPDIRECTINPUTDEVICE8W iface, LPDIEFFESCAPE lpDIEEsc) 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; return DI_OK;
} }
@ -1756,7 +1858,8 @@ HRESULT WINAPI IDirectInputDevice2WImpl_SendDeviceData(LPDIRECTINPUTDEVICE8W ifa
LPCDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut, LPCDIDEVICEOBJECTDATA rgdod, LPDWORD pdwInOut,
DWORD dwFlags) 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; return DI_OK;
} }
@ -1776,7 +1879,8 @@ HRESULT WINAPI IDirectInputDevice7AImpl_EnumEffectsInFile(LPDIRECTINPUTDEVICE8A
LPVOID pvRef, LPVOID pvRef,
DWORD dwFlags) 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; return DI_OK;
} }
@ -1787,7 +1891,8 @@ HRESULT WINAPI IDirectInputDevice7WImpl_EnumEffectsInFile(LPDIRECTINPUTDEVICE8W
LPVOID pvRef, LPVOID pvRef,
DWORD dwFlags) 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; return DI_OK;
} }
@ -1798,7 +1903,8 @@ HRESULT WINAPI IDirectInputDevice7AImpl_WriteEffectToFile(LPDIRECTINPUTDEVICE8A
LPDIFILEEFFECT rgDiFileEft, LPDIFILEEFFECT rgDiFileEft,
DWORD dwFlags) 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; return DI_OK;
} }
@ -1809,7 +1915,8 @@ HRESULT WINAPI IDirectInputDevice7WImpl_WriteEffectToFile(LPDIRECTINPUTDEVICE8W
LPDIFILEEFFECT rgDiFileEft, LPDIFILEEFFECT rgDiFileEft,
DWORD dwFlags) 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; return DI_OK;
} }
@ -1819,7 +1926,8 @@ HRESULT WINAPI IDirectInputDevice8WImpl_BuildActionMap(LPDIRECTINPUTDEVICE8W ifa
LPCWSTR lpszUserName, LPCWSTR lpszUserName,
DWORD dwFlags) 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"); #define X(x) if (dwFlags & x) FIXME("\tdwFlags =|"#x"\n");
X(DIDBAM_DEFAULT) X(DIDBAM_DEFAULT)
X(DIDBAM_PRESERVE) X(DIDBAM_PRESERVE)
@ -1833,7 +1941,8 @@ HRESULT WINAPI IDirectInputDevice8WImpl_BuildActionMap(LPDIRECTINPUTDEVICE8W ifa
HRESULT WINAPI IDirectInputDevice8AImpl_GetImageInfo(LPDIRECTINPUTDEVICE8A iface, HRESULT WINAPI IDirectInputDevice8AImpl_GetImageInfo(LPDIRECTINPUTDEVICE8A iface,
LPDIDEVICEIMAGEINFOHEADERA lpdiDevImageInfoHeader) 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; return DI_OK;
} }
@ -1841,7 +1950,8 @@ HRESULT WINAPI IDirectInputDevice8AImpl_GetImageInfo(LPDIRECTINPUTDEVICE8A iface
HRESULT WINAPI IDirectInputDevice8WImpl_GetImageInfo(LPDIRECTINPUTDEVICE8W iface, HRESULT WINAPI IDirectInputDevice8WImpl_GetImageInfo(LPDIRECTINPUTDEVICE8W iface,
LPDIDEVICEIMAGEINFOHEADERW lpdiDevImageInfoHeader) 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; return DI_OK;
} }

View file

@ -114,6 +114,8 @@ typedef struct
LPDIRECTINPUTEFFECT ref; LPDIRECTINPUTEFFECT ref;
} effect_list_item; } effect_list_item;
extern const GUID DInput_PIDVID_Product_GUID DECLSPEC_HIDDEN;
/* Various debug tools */ /* Various debug tools */
extern void _dump_DIPROPHEADER(LPCDIPROPHEADER diph) DECLSPEC_HIDDEN; extern void _dump_DIPROPHEADER(LPCDIPROPHEADER diph) DECLSPEC_HIDDEN;
extern void _dump_OBJECTINSTANCEA(const DIDEVICEOBJECTINSTANCEA *ddoi) 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 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 _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; extern HRESULT _set_action_map(LPDIRECTINPUTDEVICE8W iface, LPDIACTIONFORMATW lpdiaf, LPCWSTR lpszUserName, DWORD dwFlags, LPCDIDATAFORMAT df) DECLSPEC_HIDDEN;

View file

@ -30,7 +30,6 @@
* - Fallout : works great in X and DGA mode * - Fallout : works great in X and DGA mode
*/ */
#include "config.h"
#include <assert.h> #include <assert.h>
#include <stdarg.h> #include <stdarg.h>
#include <string.h> #include <string.h>
@ -39,7 +38,9 @@
#define NONAMELESSUNION #define NONAMELESSUNION
#include "wine/debug.h" #include "wine/debug.h"
#include "wine/heap.h"
#include "wine/unicode.h" #include "wine/unicode.h"
#include "wine/asm.h"
#include "windef.h" #include "windef.h"
#include "winbase.h" #include "winbase.h"
#include "winuser.h" #include "winuser.h"
@ -47,6 +48,7 @@
#include "objbase.h" #include "objbase.h"
#include "rpcproxy.h" #include "rpcproxy.h"
#include "initguid.h" #include "initguid.h"
#include "devguid.h"
#include "dinput_private.h" #include "dinput_private.h"
#include "device_private.h" #include "device_private.h"
#include "dinputd.h" #include "dinputd.h"
@ -289,6 +291,20 @@ static void _dump_EnumDevices_dwFlags(DWORD dwFlags)
TRACE("\n"); 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) static void _dump_diactionformatA(LPDIACTIONFORMATA lpdiActionFormat)
{ {
unsigned int i; unsigned int i;
@ -311,7 +327,7 @@ static void _dump_diactionformatA(LPDIACTIONFORMATA lpdiActionFormat)
{ {
TRACE("diaf.rgoAction[%u]:\n", i); TRACE("diaf.rgoAction[%u]:\n", i);
TRACE("\tuAppData=0x%lx\n", lpdiActionFormat->rgoAction[i].uAppData); 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("\tdwFlags=0x%x\n", lpdiActionFormat->rgoAction[i].dwFlags);
TRACE("\tszActionName=%s\n", debugstr_a(lpdiActionFormat->rgoAction[i].u.lptszActionName)); TRACE("\tszActionName=%s\n", debugstr_a(lpdiActionFormat->rgoAction[i].u.lptszActionName));
TRACE("\tguidInstance=%s\n", debugstr_guid(&lpdiActionFormat->rgoAction[i].guidInstance)); 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++) { for (i = 0; i < ARRAY_SIZE(dinput_devices); i++) {
if (!dinput_devices[i]->enum_deviceA) continue; 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++) { for (j = 0, r = S_OK; SUCCEEDED(r); j++) {
devInstance.dwSize = sizeof(devInstance); 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); r = dinput_devices[i]->enum_deviceA(dwDevType, dwFlags, &devInstance, This->dwVersion, j);
if (r == S_OK) if (r == S_OK)
if (enum_callback_wrapper(lpCallback, &devInstance, pvRef) == DIENUM_STOP) 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 ); IDirectInputImpl *This = impl_from_IDirectInput7A( iface );
ULONG ref = InterlockedIncrement(&This->ref); ULONG ref = InterlockedIncrement(&This->ref);
TRACE( "(%p) incrementing from %d\n", This, ref - 1); TRACE( "(%p) ref %d\n", This, ref );
return ref; return ref;
} }
@ -540,7 +557,7 @@ static ULONG WINAPI IDirectInputAImpl_Release(LPDIRECTINPUT7A iface)
IDirectInputImpl *This = impl_from_IDirectInput7A( iface ); IDirectInputImpl *This = impl_from_IDirectInput7A( iface );
ULONG ref = InterlockedDecrement( &This->ref ); ULONG ref = InterlockedDecrement( &This->ref );
TRACE( "(%p) releasing from %d\n", This, ref + 1 ); TRACE( "(%p) ref %d\n", This, ref );
if (ref == 0) if (ref == 0)
{ {
@ -566,53 +583,39 @@ static HRESULT WINAPI IDirectInputAImpl_QueryInterface(LPDIRECTINPUT7A iface, RE
if (!riid || !ppobj) if (!riid || !ppobj)
return E_POINTER; return E_POINTER;
*ppobj = NULL;
#if DIRECTINPUT_VERSION == 0x0700
if (IsEqualGUID( &IID_IUnknown, riid ) || if (IsEqualGUID( &IID_IUnknown, riid ) ||
IsEqualGUID( &IID_IDirectInputA, riid ) || IsEqualGUID( &IID_IDirectInputA, riid ) ||
IsEqualGUID( &IID_IDirectInput2A, riid ) || IsEqualGUID( &IID_IDirectInput2A, riid ) ||
IsEqualGUID( &IID_IDirectInput7A, riid )) IsEqualGUID( &IID_IDirectInput7A, riid ))
{
*ppobj = &This->IDirectInput7A_iface; *ppobj = &This->IDirectInput7A_iface;
IUnknown_AddRef( (IUnknown*)*ppobj ); else if (IsEqualGUID( &IID_IDirectInputW, riid ) ||
IsEqualGUID( &IID_IDirectInput2W, riid ) ||
return DI_OK; IsEqualGUID( &IID_IDirectInput7W, riid ))
}
if (IsEqualGUID( &IID_IDirectInputW, riid ) ||
IsEqualGUID( &IID_IDirectInput2W, riid ) ||
IsEqualGUID( &IID_IDirectInput7W, riid ))
{
*ppobj = &This->IDirectInput7W_iface; *ppobj = &This->IDirectInput7W_iface;
IUnknown_AddRef( (IUnknown*)*ppobj );
return DI_OK; #else
} if (IsEqualGUID( &IID_IUnknown, riid ) ||
IsEqualGUID( &IID_IDirectInput8A, riid ))
if (IsEqualGUID( &IID_IDirectInput8A, riid ))
{
*ppobj = &This->IDirectInput8A_iface; *ppobj = &This->IDirectInput8A_iface;
IUnknown_AddRef( (IUnknown*)*ppobj );
return DI_OK; else if (IsEqualGUID( &IID_IDirectInput8W, riid ))
}
if (IsEqualGUID( &IID_IDirectInput8W, riid ))
{
*ppobj = &This->IDirectInput8W_iface; *ppobj = &This->IDirectInput8W_iface;
IUnknown_AddRef( (IUnknown*)*ppobj );
return DI_OK; #endif
}
if (IsEqualGUID( &IID_IDirectInputJoyConfig8, riid )) if (IsEqualGUID( &IID_IDirectInputJoyConfig8, riid ))
{
*ppobj = &This->IDirectInputJoyConfig8_iface; *ppobj = &This->IDirectInputJoyConfig8_iface;
IUnknown_AddRef( (IUnknown*)*ppobj );
if(*ppobj)
{
IUnknown_AddRef( (IUnknown*)*ppobj );
return DI_OK; return DI_OK;
} }
FIXME( "Unsupported interface: %s\n", debugstr_guid(riid)); WARN( "Unsupported interface: %s\n", debugstr_guid(riid));
*ppobj = NULL;
return E_NOINTERFACE; return E_NOINTERFACE;
} }
@ -690,7 +693,7 @@ static HRESULT WINAPI IDirectInputAImpl_Initialize(LPDIRECTINPUT7A iface, HINSTA
{ {
IDirectInputImpl *This = impl_from_IDirectInput7A( iface ); 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) if (!hinst)
return DIERR_INVALIDPARAM; return DIERR_INVALIDPARAM;
@ -947,7 +950,7 @@ static HRESULT WINAPI IDirectInput8AImpl_Initialize(LPDIRECTINPUT8A iface, HINST
{ {
IDirectInputImpl *This = impl_from_IDirectInput8A( iface ); 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) if (!hinst)
return DIERR_INVALIDPARAM; return DIERR_INVALIDPARAM;
@ -1104,10 +1107,12 @@ static HRESULT WINAPI IDirectInput8AImpl_EnumDevicesBySemantics(
if (lpCallback(&didevis[i], lpdid, callbackFlags, --remain, pvRef) == DIENUM_STOP) if (lpCallback(&didevis[i], lpdid, callbackFlags, --remain, pvRef) == DIENUM_STOP)
{ {
IDirectInputDevice_Release(lpdid);
HeapFree(GetProcessHeap(), 0, didevis); HeapFree(GetProcessHeap(), 0, didevis);
HeapFree(GetProcessHeap(), 0, username_w); HeapFree(GetProcessHeap(), 0, username_w);
return DI_OK; return DI_OK;
} }
IDirectInputDevice_Release(lpdid);
} }
HeapFree(GetProcessHeap(), 0, didevis); HeapFree(GetProcessHeap(), 0, didevis);
@ -1130,9 +1135,11 @@ static HRESULT WINAPI IDirectInput8AImpl_EnumDevicesBySemantics(
if (lpCallback(&didevi, lpdid, callbackFlags, --remain, pvRef) == DIENUM_STOP) if (lpCallback(&didevi, lpdid, callbackFlags, --remain, pvRef) == DIENUM_STOP)
{ {
IDirectInputDevice_Release(lpdid);
HeapFree(GetProcessHeap(), 0, username_w); HeapFree(GetProcessHeap(), 0, username_w);
return DI_OK; return DI_OK;
} }
IDirectInputDevice_Release(lpdid);
} }
} }
@ -1260,9 +1267,34 @@ static HRESULT WINAPI IDirectInput8AImpl_ConfigureDevices(
/* Copy parameters */ /* Copy parameters */
diCDParamsW.dwSize = sizeof(DICONFIGUREDEVICESPARAMSW); diCDParamsW.dwSize = sizeof(DICONFIGUREDEVICESPARAMSW);
diCDParamsW.dwcUsers = lpdiCDParams->dwcUsers;
diCDParamsW.dwcFormats = lpdiCDParams->dwcFormats; diCDParamsW.dwcFormats = lpdiCDParams->dwcFormats;
diCDParamsW.lprgFormats = &diafW; diCDParamsW.lprgFormats = &diafW;
diCDParamsW.hwnd = lpdiCDParams->hwnd; 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); diafW.rgoAction = HeapAlloc(GetProcessHeap(), 0, sizeof(DIACTIONW)*lpdiCDParams->lprgFormats->dwNumActions);
_copy_diactionformatAtoW(&diafW, lpdiCDParams->lprgFormats); _copy_diactionformatAtoW(&diafW, lpdiCDParams->lprgFormats);
@ -1290,6 +1322,8 @@ static HRESULT WINAPI IDirectInput8AImpl_ConfigureDevices(
HeapFree(GetProcessHeap(), 0, diafW.rgoAction); HeapFree(GetProcessHeap(), 0, diafW.rgoAction);
heap_free((void*) diCDParamsW.lptszUserNames);
return hr; return hr;
} }
@ -1777,7 +1811,7 @@ static DWORD WINAPI hook_thread_proc(void *param)
DispatchMessageW(&msg); DispatchMessageW(&msg);
} }
return 0; FreeLibraryAndExitThread(DINPUT_instance, 0);
} }
static DWORD hook_thread_id; 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 BOOL check_hook_thread(void)
{ {
static HANDLE hook_thread; static HANDLE hook_thread;
HMODULE module;
EnterCriticalSection(&dinput_hook_crit); EnterCriticalSection(&dinput_hook_crit);
TRACE("IDirectInputs left: %d\n", list_count(&direct_input_list)); TRACE("IDirectInputs left: %d\n", list_count(&direct_input_list));
if (!list_empty(&direct_input_list) && !hook_thread) 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_event = CreateEventW(NULL, FALSE, FALSE, NULL);
hook_thread = CreateThread(NULL, 0, hook_thread_proc, hook_thread_event, 0, &hook_thread_id); 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) else if (list_empty(&direct_input_list) && hook_thread)
{ {
@ -1817,16 +1852,11 @@ static BOOL check_hook_thread(void)
hook_thread_id = 0; hook_thread_id = 0;
PostThreadMessageW(tid, WM_USER+0x10, 0, 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); CloseHandle(hook_thread);
hook_thread = NULL; hook_thread = NULL;
} }
else
LeaveCriticalSection(&dinput_hook_crit);
LeaveCriticalSection(&dinput_hook_crit);
return hook_thread_id != 0; return hook_thread_id != 0;
} }

View file

@ -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 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 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) #define IS_DIPROP(x) (((ULONG_PTR)(x) >> 16) == 0)

View file

@ -167,7 +167,9 @@ static ULONG WINAPI LinuxInputEffectImpl_AddRef(
LPDIRECTINPUTEFFECT iface) LPDIRECTINPUTEFFECT iface)
{ {
LinuxInputEffectImpl *This = impl_from_IDirectInputEffect(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( static HRESULT WINAPI LinuxInputEffectImpl_Download(
@ -759,6 +761,8 @@ static ULONG WINAPI LinuxInputEffectImpl_Release(LPDIRECTINPUTEFFECT iface)
LinuxInputEffectImpl *This = impl_from_IDirectInputEffect(iface); LinuxInputEffectImpl *This = impl_from_IDirectInputEffect(iface);
ULONG ref = InterlockedDecrement(&(This->ref)); ULONG ref = InterlockedDecrement(&(This->ref));
TRACE( "(%p) ref %d\n", This, ref );
if (ref == 0) if (ref == 0)
{ {
LinuxInputEffectImpl_Stop(iface); LinuxInputEffectImpl_Stop(iface);

View file

@ -28,12 +28,40 @@
#include <stdio.h> #include <stdio.h>
#include "device_private.h"
#include "joystick_private.h" #include "joystick_private.h"
#include "wine/debug.h" #include "wine/debug.h"
#include "wine/heap.h"
#include "winreg.h" #include "winreg.h"
WINE_DEFAULT_DEBUG_CHANNEL(dinput); 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) static inline JoystickGenericImpl *impl_from_IDirectInputDevice8A(IDirectInputDevice8A *iface)
{ {
return CONTAINING_RECORD(CONTAINING_RECORD(iface, IDirectInputDeviceImpl, IDirectInputDevice8A_iface), JoystickGenericImpl, base); 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) static void _dump_DIEFFECT_flags(DWORD dwFlags)
{ {
if (TRACE_ON(dinput)) { if (TRACE_ON(dinput)) {
@ -271,6 +309,89 @@ BOOL device_disabled_registry(const char* name)
return do_disable; 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 * SetProperty : change input device properties
*/ */
@ -278,7 +399,6 @@ HRESULT WINAPI JoystickWGenericImpl_SetProperty(LPDIRECTINPUTDEVICE8W iface, REF
{ {
JoystickGenericImpl *This = impl_from_IDirectInputDevice8W(iface); JoystickGenericImpl *This = impl_from_IDirectInputDevice8W(iface);
DWORD i; DWORD i;
ObjProps remap_props;
TRACE("(%p,%s,%p)\n",This,debugstr_guid(rguid),ph); 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: { case (DWORD_PTR)DIPROP_RANGE: {
LPCDIPROPRANGE pr = (LPCDIPROPRANGE)ph; LPCDIPROPRANGE pr = (LPCDIPROPRANGE)ph;
if (ph->dwHow == DIPH_DEVICE) { 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); TRACE("proprange(%d,%d) all\n", pr->lMin, pr->lMax);
for (i = 0; i < This->base.data_format.wine_df->dwNumObjs; i++) { for (i = 0; i < This->base.data_format.wine_df->dwNumObjs; i++)
remap_range(This, i, pr);
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;
}
} else { } else {
int obj = find_property(&This->base.data_format, ph); int obj = find_property(&This->base.data_format, ph);
TRACE("proprange(%d,%d) obj=%d\n", pr->lMin, pr->lMax, obj); TRACE("proprange(%d,%d) obj=%d\n", pr->lMin, pr->lMax, obj);
if (obj >= 0) { if (obj >= 0)
remap_range(This, obj, pr);
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;
}
} }
break; break;
} }
@ -366,15 +432,13 @@ HRESULT WINAPI JoystickWGenericImpl_SetProperty(LPDIRECTINPUTDEVICE8W iface, REF
if (ph->dwHow == DIPH_DEVICE) { if (ph->dwHow == DIPH_DEVICE) {
TRACE("deadzone(%d) all\n", pd->dwData); TRACE("deadzone(%d) all\n", pd->dwData);
for (i = 0; i < This->base.data_format.wine_df->dwNumObjs; i++) for (i = 0; i < This->base.data_format.wine_df->dwNumObjs; i++)
This->props[i].lDeadZone = pd->dwData; remap_deadzone(This, i, pd);
} else { } else {
int obj = find_property(&This->base.data_format, ph); int obj = find_property(&This->base.data_format, ph);
TRACE("deadzone(%d) obj=%d\n", pd->dwData, obj); TRACE("deadzone(%d) obj=%d\n", pd->dwData, obj);
if (obj >= 0) { if (obj >= 0)
This->props[obj].lDeadZone = pd->dwData; remap_deadzone(This, obj, pd);
return DI_OK;
}
} }
break; break;
} }
@ -383,18 +447,21 @@ HRESULT WINAPI JoystickWGenericImpl_SetProperty(LPDIRECTINPUTDEVICE8W iface, REF
if (ph->dwHow == DIPH_DEVICE) { if (ph->dwHow == DIPH_DEVICE) {
TRACE("saturation(%d) all\n", pd->dwData); TRACE("saturation(%d) all\n", pd->dwData);
for (i = 0; i < This->base.data_format.wine_df->dwNumObjs; i++) for (i = 0; i < This->base.data_format.wine_df->dwNumObjs; i++)
This->props[i].lSaturation = pd->dwData; remap_saturation(This, i, pd);
} else { } else {
int obj = find_property(&This->base.data_format, ph); int obj = find_property(&This->base.data_format, ph);
TRACE("saturation(%d) obj=%d\n", pd->dwData, obj); TRACE("saturation(%d) obj=%d\n", pd->dwData, obj);
if (obj >= 0) { if (obj >= 0)
This->props[obj].lSaturation = pd->dwData; remap_saturation(This, obj, pd);
return DI_OK;
}
} }
break; break;
} }
case (DWORD_PTR)DIPROP_CALIBRATIONMODE: {
LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph;
FIXME("DIPROP_CALIBRATIONMODE(%d)\n", pd->dwData);
break;
}
default: default:
return IDirectInputDevice2WImpl_SetProperty(iface, rguid, ph); return IDirectInputDevice2WImpl_SetProperty(iface, rguid, ph);
} }
@ -461,7 +528,7 @@ HRESULT WINAPI JoystickWGenericImpl_GetCapabilities(LPDIRECTINPUTDEVICE8W iface,
JoystickGenericImpl *This = impl_from_IDirectInputDevice8W(iface); JoystickGenericImpl *This = impl_from_IDirectInputDevice8W(iface);
int size; int size;
TRACE("%p->(%p)\n",iface,lpDIDevCaps); TRACE("%p->(%p)\n",This,lpDIDevCaps);
if (lpDIDevCaps == NULL) { if (lpDIDevCaps == NULL) {
WARN("invalid pointer\n"); WARN("invalid pointer\n");
@ -544,7 +611,7 @@ HRESULT WINAPI JoystickWGenericImpl_GetProperty(LPDIRECTINPUTDEVICE8W iface, REF
{ {
JoystickGenericImpl *This = impl_from_IDirectInputDevice8W(iface); 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)) if (TRACE_ON(dinput))
_dump_DIPROPHEADER(pdiph); _dump_DIPROPHEADER(pdiph);
@ -627,7 +694,7 @@ HRESULT WINAPI JoystickAGenericImpl_GetDeviceInfo(
DIPROPDWORD pd; DIPROPDWORD pd;
DWORD index = 0; DWORD index = 0;
TRACE("(%p,%p)\n", iface, pdidi); TRACE("(%p,%p)\n", This, pdidi);
if (pdidi == NULL) { if (pdidi == NULL) {
WARN("invalid pointer\n"); WARN("invalid pointer\n");
@ -654,7 +721,7 @@ HRESULT WINAPI JoystickAGenericImpl_GetDeviceInfo(
/* we only support traditional joysticks for now */ /* we only support traditional joysticks for now */
pdidi->dwDevType = This->devcaps.dwDevType; pdidi->dwDevType = This->devcaps.dwDevType;
snprintf(pdidi->tszInstanceName, MAX_PATH, "Joystick %d", index); 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)) { if (pdidi->dwSize > sizeof(DIDEVICEINSTANCE_DX3A)) {
pdidi->guidFFDriver = GUID_NULL; pdidi->guidFFDriver = GUID_NULL;
pdidi->wUsagePage = 0; pdidi->wUsagePage = 0;
@ -771,8 +838,31 @@ HRESULT WINAPI JoystickWGenericImpl_BuildActionMap(LPDIRECTINPUTDEVICE8W iface,
JoystickGenericImpl *This = impl_from_IDirectInputDevice8W(iface); JoystickGenericImpl *This = impl_from_IDirectInputDevice8W(iface);
unsigned int i, j; unsigned int i, j;
BOOL has_actions = FALSE; BOOL has_actions = FALSE;
WCHAR *username;
DWORD size;
BOOL load_success = FALSE;
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);
/* 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++) for (i=0; i < lpdiaf->dwNumActions; i++)
{ {
@ -850,7 +940,7 @@ HRESULT WINAPI JoystickWGenericImpl_SetActionMap(LPDIRECTINPUTDEVICE8W iface,
{ {
JoystickGenericImpl *This = impl_from_IDirectInputDevice8W(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); 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); hr = JoystickWGenericImpl_SetActionMap(&This->base.IDirectInputDevice8W_iface, &diafW, lpszUserNameW, dwFlags);
lpdiaf->dwCRC = diafW.dwCRC;
HeapFree(GetProcessHeap(), 0, diafW.rgoAction); HeapFree(GetProcessHeap(), 0, diafW.rgoAction);
HeapFree(GetProcessHeap(), 0, lpszUserNameW); HeapFree(GetProcessHeap(), 0, lpszUserNameW);
@ -950,6 +1042,7 @@ HRESULT setup_dinput_options(JoystickGenericImpl *This, const int *default_axis_
int tokens = 0; int tokens = 0;
int axis = 0; int axis = 0;
int pov = 0; int pov = 0;
int button;
get_app_key(&hkey, &appkey); 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); 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)); This->axis_map = HeapAlloc(GetProcessHeap(), 0, This->device_axis_count * sizeof(int));
if (!This->axis_map) return DIERR_OUTOFMEMORY; if (!This->axis_map) return DIERR_OUTOFMEMORY;

View file

@ -59,6 +59,7 @@
#include "windef.h" #include "windef.h"
#include "winbase.h" #include "winbase.h"
#include "winerror.h" #include "winerror.h"
#include "devguid.h"
#include "dinput.h" #include "dinput.h"
#include "dinput_private.h" #include "dinput_private.h"
@ -84,6 +85,8 @@ struct JoyDev
int *dev_axes_map; int *dev_axes_map;
WORD vendor_id, product_id, bus_type; WORD vendor_id, product_id, bus_type;
BOOL is_joystick;
}; };
typedef struct JoystickImpl JoystickImpl; 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} {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 #define MAX_JOYSTICKS 64
static INT joystick_devices_count = -1; static INT joystick_devices_count = -1;
static struct JoyDev *joystick_devices; static struct JoyDev *joystick_devices;
@ -177,6 +167,8 @@ static INT find_joystick_devices(void)
int fd; int fd;
struct JoyDev joydev, *new_joydevs; struct JoyDev joydev, *new_joydevs;
BYTE axes_map[ABS_MAX + 1]; 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); snprintf(joydev.device, sizeof(joydev.device), "%s%d", JOYDEV_NEW, i);
if ((fd = open(joydev.device, O_RDONLY)) == -1) if ((fd = open(joydev.device, O_RDONLY)) == -1)
@ -220,6 +212,52 @@ static INT find_joystick_devices(void)
joydev.button_count = 2; joydev.button_count = 2;
#endif #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) if (ioctl(fd, JSIOCGAXMAP, axes_map) < 0)
{ {
WARN("ioctl(%s,JSIOCGAXMAP) failed: %s\n", joydev.device, strerror(errno)); 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; joydev.dev_axes_map[j] = j;
found_axes++; 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 || else if (axes_map[j] == 16 ||
axes_map[j] == 17) axes_map[j] == 17)
{ {
@ -279,7 +325,7 @@ static INT find_joystick_devices(void)
else else
{ {
/* Concatenate product_id with vendor_id to mimic Windows behaviour */ /* 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); 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 = DInput_Wine_Joystick_GUID;
lpddi->guidInstance.Data3 = id; lpddi->guidInstance.Data3 = id;
lpddi->guidProduct = joystick_devices[id].guid_product; lpddi->guidProduct = joystick_devices[id].guid_product;
/* we only support traditional joysticks for now */ lpddi->dwDevType = get_device_type(version, joystick_devices[id].is_joystick);
if (version >= 0x0800)
lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
else
lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
/* Assume the joystick as HID if it is attached to USB bus and has a valid VID/PID */ /* 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 && 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->dwDevType |= DIDEVTYPE_HID;
lpddi->wUsagePage = 0x01; /* Desktop */ lpddi->wUsagePage = 0x01; /* Desktop */
if (lpddi->dwDevType == DI8DEVTYPE_JOYSTICK || lpddi->dwDevType == DIDEVTYPE_JOYSTICK) if (joystick_devices[id].is_joystick)
lpddi->wUsage = 0x04; /* Joystick */ lpddi->wUsage = 0x04; /* Joystick */
else else
lpddi->wUsage = 0x05; /* Game Pad */ lpddi->wUsage = 0x05; /* Game Pad */
@ -372,7 +414,7 @@ static HRESULT joydev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINS
} }
if ((dwDevType == 0) || 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))) { (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800))) {
/* check whether we have a joystick */ /* check whether we have a joystick */
if ((fd = open(joystick_devices[id].device, O_RDONLY)) == -1) 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) || 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))) { (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800))) {
/* check whether we have a joystick */ /* check whether we have a joystick */
if ((fd = open(joystick_devices[id].device, O_RDONLY)) == -1) 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); 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); _dump_DIPROPHEADER(pdiph);
if (!IS_DIPROP(rguid)) return DI_OK; if (!IS_DIPROP(rguid)) return DI_OK;
@ -699,6 +741,29 @@ static HRESULT WINAPI JoystickLinuxWImpl_GetProperty(LPDIRECTINPUTDEVICE8W iface
break; 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: default:
return JoystickWGenericImpl_GetProperty(iface, rguid, pdiph); return JoystickWGenericImpl_GetProperty(iface, rguid, pdiph);
} }
@ -807,10 +872,13 @@ static void joy_polldev(LPDIRECTINPUTDEVICE8A iface)
jse.type,jse.number,jse.value); jse.type,jse.number,jse.value);
if (jse.type & JS_EVENT_BUTTON) if (jse.type & JS_EVENT_BUTTON)
{ {
int button;
if (jse.number >= This->generic.devcaps.dwButtons) return; if (jse.number >= This->generic.devcaps.dwButtons) return;
inst_id = DIDFT_MAKEINSTANCE(jse.number) | DIDFT_PSHBUTTON; button = This->generic.button_map[jse.number];
This->generic.js.rgbButtons[jse.number] = value = jse.value ? 0x80 : 0x00;
inst_id = DIDFT_MAKEINSTANCE(button) | DIDFT_PSHBUTTON;
This->generic.js.rgbButtons[button] = value = jse.value ? 0x80 : 0x00;
} }
else if (jse.type & JS_EVENT_AXIS) else if (jse.type & JS_EVENT_AXIS)
{ {

View file

@ -57,6 +57,7 @@
#include "winbase.h" #include "winbase.h"
#include "winerror.h" #include "winerror.h"
#include "winreg.h" #include "winreg.h"
#include "devguid.h"
#include "dinput.h" #include "dinput.h"
#include "dinput_private.h" #include "dinput_private.h"
@ -83,6 +84,13 @@ struct wine_input_absinfo {
LONG flat; 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 */ /* implemented in effect_linuxinput.c */
HRESULT linuxinput_create_effect(int* fd, REFGUID rguid, struct list *parent_list_entry, LPDIRECTINPUTEFFECT* peff); 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); HRESULT linuxinput_get_info_A(int fd, REFGUID rguid, LPDIEFFECTINFOA info);
@ -100,7 +108,7 @@ struct JoyDev {
GUID guid; GUID guid;
GUID guid_product; GUID guid_product;
BOOL has_ff; BOOL has_ff, is_joystick;
int num_effects; int num_effects;
/* data returned by EVIOCGBIT for caps, EV_ABS, EV_KEY, and EV_FF */ /* data returned by EVIOCGBIT for caps, EV_ABS, EV_KEY, and EV_FF */
@ -122,6 +130,7 @@ struct JoystickImpl
/* joystick private */ /* joystick private */
int joyfd; int joyfd;
enum wine_joystick_linuxinput_fd_state joyfd_state;
int dev_axes_to_di[ABS_MAX]; int dev_axes_to_di[ABS_MAX];
POINTL povs[4]; 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} {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 test_bit(arr,bit) (((BYTE*)(arr))[(bit)>>3]&(1<<((bit)&7)))
#define MAX_JOYDEV 64 #define MAX_JOYDEV 64
@ -211,10 +207,7 @@ static void find_joydevs(void)
} }
if (fd == -1) if (fd == -1)
{
WARN("Failed to open \"%s\": %d %s\n", buf, errno, strerror(errno));
continue; continue;
}
if (ioctl(fd, EVIOCGBIT(0, sizeof(joydev.evbits)), joydev.evbits) == -1) 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 /* A true joystick has at least axis X and Y, and at least 1
* button. copied from linux/drivers/input/joydev.c */ * 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_TRIGGER) ||
test_bit(joydev.keybits, BTN_A) || 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); close(fd);
continue; 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))) if (!(joydev.device = HeapAlloc(GetProcessHeap(), 0, strlen(buf) + 1)))
{ {
close(fd); close(fd);
@ -320,7 +339,7 @@ static void find_joydevs(void)
joydev.bus_type = device_id.bustype; joydev.bus_type = device_id.bustype;
/* Concatenate product_id with vendor_id to mimic Windows behaviour */ /* 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); 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->guidInstance = joydevs[id].guid;
lpddi->guidProduct = joydevs[id].guid_product; lpddi->guidProduct = joydevs[id].guid_product;
lpddi->guidFFDriver = GUID_NULL; lpddi->guidFFDriver = GUID_NULL;
lpddi->dwDevType = get_device_type(version, joydevs[id].is_joystick);
if (version >= 0x0800)
lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
else
lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
/* Assume the joystick as HID if it is attached to USB bus and has a valid VID/PID */ /* 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 && 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->dwDevType |= DIDEVTYPE_HID;
lpddi->wUsagePage = 0x01; /* Desktop */ lpddi->wUsagePage = 0x01; /* Desktop */
if (lpddi->dwDevType == DI8DEVTYPE_JOYSTICK || lpddi->dwDevType == DIDEVTYPE_JOYSTICK) if (joydevs[id].is_joystick)
lpddi->wUsage = 0x04; /* Joystick */ lpddi->wUsage = 0x04; /* Joystick */
else else
lpddi->wUsage = 0x05; /* Game Pad */ lpddi->wUsage = 0x05; /* Game Pad */
@ -391,8 +406,8 @@ static void fill_joystick_dideviceinstanceA(LPDIDEVICEINSTANCEA lpddi, DWORD ver
lpddi->guidInstance = lpddiW.guidInstance; lpddi->guidInstance = lpddiW.guidInstance;
lpddi->guidProduct = lpddiW.guidProduct; lpddi->guidProduct = lpddiW.guidProduct;
lpddi->dwDevType = lpddiW.dwDevType; lpddi->dwDevType = lpddiW.dwDevType;
strcpy(lpddi->tszInstanceName, joydevs[id].name); lstrcpynA(lpddi->tszInstanceName, joydevs[id].name, MAX_PATH);
strcpy(lpddi->tszProductName, joydevs[id].name); lstrcpynA(lpddi->tszProductName, joydevs[id].name, MAX_PATH);
lpddi->guidFFDriver = lpddiW.guidFFDriver; lpddi->guidFFDriver = lpddiW.guidFFDriver;
lpddi->wUsagePage = lpddiW.wUsagePage; lpddi->wUsagePage = lpddiW.wUsagePage;
lpddi->wUsage = lpddiW.wUsage; lpddi->wUsage = lpddiW.wUsage;
@ -407,7 +422,7 @@ static HRESULT joydev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINS
} }
if (!((dwDevType == 0) || 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)))) (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800))))
return S_FALSE; return S_FALSE;
@ -432,7 +447,7 @@ static HRESULT joydev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINS
} }
if (!((dwDevType == 0) || 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)))) (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800))))
return S_FALSE; return S_FALSE;
@ -466,6 +481,7 @@ static JoystickImpl *alloc_device(REFGUID rguid, IDirectInputImpl *dinput, unsig
newDevice->generic.base.dinput = dinput; newDevice->generic.base.dinput = dinput;
newDevice->generic.joy_polldev = joy_polldev; newDevice->generic.joy_polldev = joy_polldev;
newDevice->joyfd = -1; newDevice->joyfd = -1;
newDevice->joyfd_state = WINE_FD_STATE_CLOSED;
newDevice->joydev = &joydevs[index]; newDevice->joydev = &joydevs[index];
newDevice->generic.name = newDevice->joydev->name; newDevice->generic.name = newDevice->joydev->name;
list_init(&newDevice->ff_effects); 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 */ /* Count number of available axes - supported Axis & POVs */
for (i = 0; i < ABS_MAX; i++) 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)) test_bit(newDevice->joydev->absbits, i))
{ {
newDevice->generic.device_axis_count++; newDevice->generic.device_axis_count++;
newDevice->dev_axes_to_di[i] = idx; newDevice->dev_axes_to_di[i] = idx;
newDevice->generic.props[idx].lDevMin = newDevice->joydev->axes[i].minimum; newDevice->generic.props[idx].lDevMin = newDevice->joydev->axes[i].minimum;
newDevice->generic.props[idx].lDevMax = newDevice->joydev->axes[i].maximum; 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++; idx++;
} }
else else
@ -669,6 +689,44 @@ static HRESULT joydev_create_device(IDirectInputImpl *dinput, REFGUID rguid, REF
return DIERR_DEVICENOTREG; return DIERR_DEVICENOTREG;
} }
static int joydev_open_evdev(JoystickImpl *This)
{
int fd;
if ((fd = open(This->joydev->device, O_RDWR)) == -1)
{
if ((fd = open(This->joydev->device, O_RDONLY)) == -1)
{
/* Couldn't open the device at all */
}
else
{
/* Couldn't open in r/w but opened in read-only. */
WARN("Could not open %s in read-write mode. Force feedback will be disabled.\n", This->joydev->device);
}
}
else
{
struct input_event event;
event.type = EV_FF;
event.code = FF_GAIN;
event.value = This->ff_gain;
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(fd, &event, sizeof(event)) == -1)
ERR("Failed disabling autocenter: %d %s\n", errno, strerror(errno));
}
}
return fd;
}
const struct dinput_device joystick_linuxinput_device = { const struct dinput_device joystick_linuxinput_device = {
"Wine Linux-input joystick driver", "Wine Linux-input joystick driver",
@ -693,40 +751,14 @@ static HRESULT WINAPI JoystickWImpl_Acquire(LPDIRECTINPUTDEVICE8W iface)
return res; return res;
} }
if ((This->joyfd = open(This->joydev->device, O_RDWR)) == -1) if ((This->joyfd = joydev_open_evdev(This)) == -1)
{ {
if ((This->joyfd = open(This->joydev->device, O_RDONLY)) == -1) ERR("Failed to open device %s: %d %s\n", This->joydev->device, errno, strerror(errno));
{ IDirectInputDevice2WImpl_Unacquire(iface);
/* Couldn't open the device at all */ return DIERR_NOTFOUND;
ERR("Failed to open device %s: %d %s\n", This->joydev->device, errno, strerror(errno));
IDirectInputDevice2WImpl_Unacquire(iface);
return DIERR_NOTFOUND;
}
else
{
/* Couldn't open in r/w but opened in read-only. */
WARN("Could not open %s in read-write mode. Force feedback will be disabled.\n", This->joydev->device);
}
}
else
{
struct input_event event;
event.type = EV_FF;
event.code = FF_GAIN;
event.value = This->ff_gain;
if (write(This->joyfd, &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)
ERR("Failed disabling autocenter: %d %s\n", errno, strerror(errno));
}
} }
This->joyfd_state = WINE_FD_STATE_OK;
return DI_OK; return DI_OK;
} }
@ -764,6 +796,7 @@ static HRESULT WINAPI JoystickWImpl_Unacquire(LPDIRECTINPUTDEVICE8W iface)
close(This->joyfd); close(This->joyfd);
This->joyfd = -1; This->joyfd = -1;
This->joyfd_state = WINE_FD_STATE_CLOSED;
} }
return res; return res;
} }
@ -808,23 +841,79 @@ static void joy_polldev(LPDIRECTINPUTDEVICE8A iface)
struct input_event ie; struct input_event ie;
JoystickImpl *This = impl_from_IDirectInputDevice8A(iface); JoystickImpl *This = impl_from_IDirectInputDevice8A(iface);
if (This->joyfd==-1) if (This->joyfd == -1)
return; {
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) while (1)
{ {
LONG value = 0; LONG value = 0;
int inst_id = -1; int inst_id = -1;
int result;
plfd.fd = This->joyfd; plfd.fd = This->joyfd;
plfd.events = POLLIN; plfd.events = POLLIN;
if (poll(&plfd,1,0) != 1) result = poll(&plfd,1,0);
return; 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 */ /* we have one event, so we can read */
if (sizeof(ie)!=read(This->joyfd,&ie,sizeof(ie))) result = read(This->joyfd,&ie,sizeof(ie));
return; 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); TRACE("input_event: type %d, code %d, value %d\n",ie.type,ie.code,ie.value);
switch (ie.type) { switch (ie.type) {
@ -836,6 +925,8 @@ static void joy_polldev(LPDIRECTINPUTDEVICE8A iface)
if (btn & 0x80) if (btn & 0x80)
{ {
btn &= 0x7F; btn &= 0x7F;
btn = This->generic.button_map[btn];
inst_id = DIDFT_MAKEINSTANCE(btn) | DIDFT_PSHBUTTON; inst_id = DIDFT_MAKEINSTANCE(btn) | DIDFT_PSHBUTTON;
This->generic.js.rgbButtons[btn] = value = ie.value ? 0x80 : 0x00; 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)) { if (IS_DIPROP(rguid)) {
switch (LOWORD(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: { case (DWORD_PTR)DIPROP_AUTOCENTER: {
LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph; LPCDIPROPDWORD pd = (LPCDIPROPDWORD)ph;
@ -973,7 +1059,7 @@ static HRESULT WINAPI JoystickWImpl_GetProperty(LPDIRECTINPUTDEVICE8W iface, REF
{ {
JoystickImpl *This = impl_from_IDirectInputDevice8W(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); _dump_DIPROPHEADER(pdiph);
if (!IS_DIPROP(rguid)) return DI_OK; if (!IS_DIPROP(rguid)) return DI_OK;
@ -1016,6 +1102,29 @@ static HRESULT WINAPI JoystickWImpl_GetProperty(LPDIRECTINPUTDEVICE8W iface, REF
break; 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: default:
return JoystickWGenericImpl_GetProperty(iface, rguid, pdiph); return JoystickWGenericImpl_GetProperty(iface, rguid, pdiph);
} }

View file

@ -85,6 +85,7 @@
#include "winbase.h" #include "winbase.h"
#include "winerror.h" #include "winerror.h"
#include "winreg.h" #include "winreg.h"
#include "devguid.h"
#include "dinput.h" #include "dinput.h"
#include "dinput_private.h" #include "dinput_private.h"
@ -124,6 +125,11 @@ static inline JoystickImpl *impl_from_IDirectInputDevice8W(IDirectInputDevice8W
JoystickGenericImpl, base), JoystickImpl, generic); JoystickGenericImpl, base), JoystickImpl, generic);
} }
static inline IDirectInputDevice8W *IDirectInputDevice8W_from_impl(JoystickImpl *This)
{
return &This->generic.base.IDirectInputDevice8W_iface;
}
typedef struct _EffectImpl { typedef struct _EffectImpl {
IDirectInputEffect IDirectInputEffect_iface; IDirectInputEffect IDirectInputEffect_iface;
LONG ref; LONG ref;
@ -801,7 +807,11 @@ static void poll_osx_device_state(LPDIRECTINPUTDEVICE8A iface)
TRACE("kIOHIDElementTypeInput_Button\n"); TRACE("kIOHIDElementTypeInput_Button\n");
if(button_idx < 128) 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); val = IOHIDValueGetIntegerValue(valueRef);
newVal = val ? 0x80 : 0x0; newVal = val ? 0x80 : 0x0;
oldVal = device->generic.js.rgbButtons[button_idx]; 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); TRACE("valueRef %s val %d oldVal %d newVal %d\n", debugstr_cf(valueRef), val, oldVal, newVal);
if (oldVal != newVal) if (oldVal != newVal)
{ {
button_idx = device->generic.button_map[button_idx];
inst_id = DIDFT_MAKEINSTANCE(button_idx) | DIDFT_PSHBUTTON; inst_id = DIDFT_MAKEINSTANCE(button_idx) | DIDFT_PSHBUTTON;
queue_event(iface,inst_id,newVal,GetCurrentTime(),device->generic.base.dinput->evsequence++); 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: case kHIDUsage_GD_Hatswitch:
{ {
TRACE("kIOHIDElementTypeInput_Misc / kHIDUsage_GD_Hatswitch\n"); 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); val = IOHIDValueGetIntegerValue(valueRef);
oldVal = device->generic.js.rgdwPOV[pov_idx]; oldVal = device->generic.js.rgdwPOV[pov_idx];
if (val >= 8) if (val >= 8)
@ -850,7 +866,11 @@ static void poll_osx_device_state(LPDIRECTINPUTDEVICE8A iface)
{ {
int wine_obj = -1; 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); val = IOHIDValueGetIntegerValue(valueRef);
newVal = joystick_map_axis(&device->generic.props[idx], val); newVal = joystick_map_axis(&device->generic.props[idx], val);
switch (usage) 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) static HRESULT joydev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, DWORD version, int id)
{ {
IOHIDDeviceRef device; IOHIDDeviceRef device;
BOOL is_joystick;
TRACE("dwDevType %u dwFlags 0x%08x version 0x%04x id %d\n", dwDevType, dwFlags, version, id); 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); device = get_device_ref(id);
if ((dwDevType == 0) || 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))) (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800)))
{ {
if (dwFlags & DIEDFL_FORCEFEEDBACK) { 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) if(get_ff(device, NULL) != S_OK)
return S_FALSE; return S_FALSE;
} }
is_joystick = get_device_property_long(device, CFSTR(kIOHIDDeviceUsageKey)) == kHIDUsage_GD_Joystick;
/* Return joystick */ /* Return joystick */
lpddi->guidInstance = DInput_Wine_OsX_Joystick_GUID; lpddi->guidInstance = DInput_Wine_OsX_Joystick_GUID;
lpddi->guidInstance.Data3 = id; lpddi->guidInstance.Data3 = id;
lpddi->guidProduct = DInput_Wine_OsX_Joystick_GUID; lpddi->guidProduct = DInput_PIDVID_Product_GUID;
lpddi->guidProduct.Data1 = make_vid_pid(device); lpddi->guidProduct.Data1 = make_vid_pid(device);
/* we only support traditional joysticks for now */ lpddi->dwDevType = get_device_type(version, is_joystick);
if (version >= 0x0800) lpddi->dwDevType |= DIDEVTYPE_HID;
lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8); lpddi->wUsagePage = 0x01; /* Desktop */
if (is_joystick)
lpddi->wUsage = 0x04; /* Joystick */
else else
lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8); lpddi->wUsage = 0x05; /* Game Pad */
sprintf(lpddi->tszInstanceName, "Joystick %d", id); sprintf(lpddi->tszInstanceName, "Joystick %d", id);
/* get the device name */ /* get the device name */
@ -989,6 +1013,7 @@ static HRESULT joydev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINS
char name[MAX_PATH]; char name[MAX_PATH];
char friendly[32]; char friendly[32];
IOHIDDeviceRef device; IOHIDDeviceRef device;
BOOL is_joystick;
TRACE("dwDevType %u dwFlags 0x%08x version 0x%04x id %d\n", dwDevType, dwFlags, version, id); 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); device = get_device_ref(id);
if ((dwDevType == 0) || 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))) { (((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800))) {
if (dwFlags & DIEDFL_FORCEFEEDBACK) { 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) if(get_ff(device, NULL) != S_OK)
return S_FALSE; return S_FALSE;
} }
is_joystick = get_device_property_long(device, CFSTR(kIOHIDDeviceUsageKey)) == kHIDUsage_GD_Joystick;
/* Return joystick */ /* Return joystick */
lpddi->guidInstance = DInput_Wine_OsX_Joystick_GUID; lpddi->guidInstance = DInput_Wine_OsX_Joystick_GUID;
lpddi->guidInstance.Data3 = id; lpddi->guidInstance.Data3 = id;
lpddi->guidProduct = DInput_Wine_OsX_Joystick_GUID; lpddi->guidProduct = DInput_PIDVID_Product_GUID;
lpddi->guidProduct.Data1 = make_vid_pid(device); lpddi->guidProduct.Data1 = make_vid_pid(device);
/* we only support traditional joysticks for now */ lpddi->dwDevType = get_device_type(version, is_joystick);
if (version >= 0x0800) lpddi->dwDevType |= DIDEVTYPE_HID;
lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8); lpddi->wUsagePage = 0x01; /* Desktop */
if (is_joystick)
lpddi->wUsage = 0x04; /* Joystick */
else else
lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8); lpddi->wUsage = 0x05; /* Game Pad */
sprintf(friendly, "Joystick %d", id); sprintf(friendly, "Joystick %d", id);
MultiByteToWideChar(CP_ACP, 0, friendly, -1, lpddi->tszInstanceName, MAX_PATH); MultiByteToWideChar(CP_ACP, 0, friendly, -1, lpddi->tszInstanceName, MAX_PATH);
/* get the device name */ /* get the device name */
get_osx_device_name(id, name, MAX_PATH); 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 = DInput_Wine_OsX_Joystick_GUID;
newDevice->generic.guidInstance.Data3 = index; 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.guidProduct.Data1 = make_vid_pid(device);
newDevice->generic.joy_polldev = poll_osx_device_state; 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; 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, static HRESULT osx_set_autocenter(JoystickImpl *This,
const DIPROPDWORD *header) const DIPROPDWORD *header)
{ {
@ -1418,7 +1494,7 @@ static HRESULT WINAPI JoystickWImpl_CreateEffect(IDirectInputDevice8W *iface,
EffectImpl *effect; EffectImpl *effect;
HRESULT hr; 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); dump_DIEFFECT(params, type, 0);
if(!This->ff){ if(!This->ff){
@ -1459,7 +1535,7 @@ static HRESULT WINAPI JoystickAImpl_CreateEffect(IDirectInputDevice8A *iface,
{ {
JoystickImpl *This = impl_from_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, return JoystickWImpl_CreateEffect(&This->generic.base.IDirectInputDevice8W_iface,
type, params, out, outer); type, params, out, outer);
@ -1509,7 +1585,7 @@ static const IDirectInputDevice8AVtbl JoystickAvt =
IDirectInputDevice2AImpl_Release, IDirectInputDevice2AImpl_Release,
JoystickAGenericImpl_GetCapabilities, JoystickAGenericImpl_GetCapabilities,
IDirectInputDevice2AImpl_EnumObjects, IDirectInputDevice2AImpl_EnumObjects,
JoystickAGenericImpl_GetProperty, JoystickAImpl_GetProperty,
JoystickAImpl_SetProperty, JoystickAImpl_SetProperty,
IDirectInputDevice2AImpl_Acquire, IDirectInputDevice2AImpl_Acquire,
IDirectInputDevice2AImpl_Unacquire, IDirectInputDevice2AImpl_Unacquire,
@ -1545,7 +1621,7 @@ static const IDirectInputDevice8WVtbl JoystickWvt =
IDirectInputDevice2WImpl_Release, IDirectInputDevice2WImpl_Release,
JoystickWGenericImpl_GetCapabilities, JoystickWGenericImpl_GetCapabilities,
IDirectInputDevice2WImpl_EnumObjects, IDirectInputDevice2WImpl_EnumObjects,
JoystickWGenericImpl_GetProperty, JoystickWImpl_GetProperty,
JoystickWImpl_SetProperty, JoystickWImpl_SetProperty,
IDirectInputDevice2WImpl_Acquire, IDirectInputDevice2WImpl_Acquire,
IDirectInputDevice2WImpl_Unacquire, IDirectInputDevice2WImpl_Unacquire,

View file

@ -33,6 +33,9 @@
#define MAX_PROPS 164 #define MAX_PROPS 164
struct JoystickGenericImpl; struct JoystickGenericImpl;
/* Number of buttons for which to allow remapping */
#define MAX_MAP_BUTTONS 32
typedef void joy_polldev_handler(LPDIRECTINPUTDEVICE8A iface); typedef void joy_polldev_handler(LPDIRECTINPUTDEVICE8A iface);
typedef struct JoystickGenericImpl typedef struct JoystickGenericImpl
@ -47,6 +50,7 @@ typedef struct JoystickGenericImpl
char *name; char *name;
int device_axis_count; /* Total number of axes in the device */ int device_axis_count; /* Total number of axes in the device */
int *axis_map; /* User axes remapping */ int *axis_map; /* User axes remapping */
int button_map[MAX_MAP_BUTTONS]; /* User button remapping */
LONG deadzone; /* Default dead-zone */ LONG deadzone; /* Default dead-zone */
joy_polldev_handler *joy_polldev; joy_polldev_handler *joy_polldev;
@ -96,5 +100,6 @@ HRESULT WINAPI JoystickWGenericImpl_SetActionMap(LPDIRECTINPUTDEVICE8W iface, LP
DWORD typeFromGUID(REFGUID guid) DECLSPEC_HIDDEN; DWORD typeFromGUID(REFGUID guid) DECLSPEC_HIDDEN;
void dump_DIEFFECT(LPCDIEFFECT eff, REFGUID guid, DWORD dwFlags) 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 */ #endif /* __WINE_DLLS_DINPUT_JOYSTICK_PRIVATE_H */

View file

@ -215,6 +215,9 @@ static HRESULT keyboarddev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVI
if (id != 0) if (id != 0)
return E_FAIL; return E_FAIL;
if (dwFlags & DIEDFL_FORCEFEEDBACK)
return S_FALSE;
if ((dwDevType == 0) || if ((dwDevType == 0) ||
((dwDevType == DIDEVTYPE_KEYBOARD) && (version < 0x0800)) || ((dwDevType == DIDEVTYPE_KEYBOARD) && (version < 0x0800)) ||
(((dwDevType == DI8DEVCLASS_KEYBOARD) || (dwDevType == DI8DEVTYPE_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) if (id != 0)
return E_FAIL; return E_FAIL;
if (dwFlags & DIEDFL_FORCEFEEDBACK)
return S_FALSE;
if ((dwDevType == 0) || if ((dwDevType == 0) ||
((dwDevType == DIDEVTYPE_KEYBOARD) && (version < 0x0800)) || ((dwDevType == DIDEVTYPE_KEYBOARD) && (version < 0x0800)) ||
(((dwDevType == DI8DEVCLASS_KEYBOARD) || (dwDevType == DI8DEVTYPE_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); SysKeyboardImpl *This = impl_from_IDirectInputDevice8A(iface);
TRACE("(this=%p,%p)\n", This, pdidi); 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); fill_keyboard_dideviceinstanceA(pdidi, This->base.dinput->dwVersion, This->subtype);
return DI_OK; return DI_OK;
@ -553,7 +554,7 @@ static HRESULT WINAPI SysKeyboardWImpl_GetProperty(LPDIRECTINPUTDEVICE8W iface,
{ {
SysKeyboardImpl *This = impl_from_IDirectInputDevice8W(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); _dump_DIPROPHEADER(pdiph);
if (!IS_DIPROP(rguid)) return DI_OK; if (!IS_DIPROP(rguid)) return DI_OK;
@ -619,7 +620,8 @@ static HRESULT WINAPI SysKeyboardWImpl_BuildActionMap(LPDIRECTINPUTDEVICE8W ifac
LPCWSTR lpszUserName, LPCWSTR lpszUserName,
DWORD dwFlags) 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); 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, LPCWSTR lpszUserName,
DWORD dwFlags) 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); 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); hr = SysKeyboardWImpl_SetActionMap(&This->base.IDirectInputDevice8W_iface, &diafW, lpszUserNameW, dwFlags);
lpdiaf->dwCRC = diafW.dwCRC;
HeapFree(GetProcessHeap(), 0, diafW.rgoAction); HeapFree(GetProcessHeap(), 0, diafW.rgoAction);
HeapFree(GetProcessHeap(), 0, lpszUserNameW); HeapFree(GetProcessHeap(), 0, lpszUserNameW);

View file

@ -28,6 +28,7 @@
#include "windef.h" #include "windef.h"
#include "winbase.h" #include "winbase.h"
#include "wingdi.h" #include "wingdi.h"
#include "wine/winternl.h"
#include "winuser.h" #include "winuser.h"
#include "winerror.h" #include "winerror.h"
#include "winreg.h" #include "winreg.h"
@ -157,6 +158,9 @@ static HRESULT mousedev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEI
if (id != 0) if (id != 0)
return E_FAIL; return E_FAIL;
if (dwFlags & DIEDFL_FORCEFEEDBACK)
return S_FALSE;
if ((dwDevType == 0) || if ((dwDevType == 0) ||
((dwDevType == DIDEVTYPE_MOUSE) && (version < 0x0800)) || ((dwDevType == DIDEVTYPE_MOUSE) && (version < 0x0800)) ||
(((dwDevType == DI8DEVCLASS_POINTER) || (dwDevType == DI8DEVTYPE_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) if (id != 0)
return E_FAIL; return E_FAIL;
if (dwFlags & DIEDFL_FORCEFEEDBACK)
return S_FALSE;
if ((dwDevType == 0) || if ((dwDevType == 0) ||
((dwDevType == DIDEVTYPE_MOUSE) && (version < 0x0800)) || ((dwDevType == DIDEVTYPE_MOUSE) && (version < 0x0800)) ||
(((dwDevType == DI8DEVCLASS_POINTER) || (dwDevType == DI8DEVTYPE_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); get_app_key(&hkey, &appkey);
if (!get_config_key(hkey, appkey, "MouseWarpOverride", buffer, sizeof(buffer))) if (!get_config_key(hkey, appkey, "MouseWarpOverride", buffer, sizeof(buffer)))
{ {
if (!strcasecmp(buffer, "disable")) if (!_strnicmp(buffer, "disable", -1))
newDevice->warp_override = WARP_DISABLE; newDevice->warp_override = WARP_DISABLE;
else if (!strcasecmp(buffer, "force")) else if (!_strnicmp(buffer, "force", -1))
newDevice->warp_override = WARP_FORCE_ON; newDevice->warp_override = WARP_FORCE_ON;
} }
if (appkey) RegCloseKey(appkey); if (appkey) RegCloseKey(appkey);
@ -723,6 +730,9 @@ static HRESULT WINAPI SysMouseWImpl_GetObjectInfo(LPDIRECTINPUTDEVICE8W iface,
else if (pdidoi->dwType & DIDFT_BUTTON) else if (pdidoi->dwType & DIDFT_BUTTON)
wsprintfW(pdidoi->tszName, buttonW, DIDFT_GETINSTANCE(pdidoi->dwType) - 3); wsprintfW(pdidoi->tszName, buttonW, DIDFT_GETINSTANCE(pdidoi->dwType) - 3);
if(pdidoi->dwType & DIDFT_AXIS)
pdidoi->dwFlags |= DIDOI_ASPECTPOSITION;
_dump_OBJECTINSTANCEW(pdidoi); _dump_OBJECTINSTANCEW(pdidoi);
return res; return res;
} }
@ -758,11 +768,6 @@ static HRESULT WINAPI SysMouseAImpl_GetDeviceInfo(
SysMouseImpl *This = impl_from_IDirectInputDevice8A(iface); SysMouseImpl *This = impl_from_IDirectInputDevice8A(iface);
TRACE("(this=%p,%p)\n", This, pdidi); 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); fill_mouse_dideviceinstanceA(pdidi, This->base.dinput->dwVersion);
return DI_OK; return DI_OK;
@ -828,7 +833,8 @@ static HRESULT WINAPI SysMouseWImpl_SetActionMap(LPDIRECTINPUTDEVICE8W iface,
LPCWSTR lpszUserName, LPCWSTR lpszUserName,
DWORD dwFlags) 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); 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); hr = SysMouseWImpl_SetActionMap(&This->base.IDirectInputDevice8W_iface, &diafW, lpszUserNameW, dwFlags);
lpdiaf->dwCRC = diafW.dwCRC;
HeapFree(GetProcessHeap(), 0, diafW.rgoAction); HeapFree(GetProcessHeap(), 0, diafW.rgoAction);
HeapFree(GetProcessHeap(), 0, lpszUserNameW); HeapFree(GetProcessHeap(), 0, lpszUserNameW);

View file

@ -2,8 +2,6 @@
#ifndef __WINE_DINPUT_PRECOMP_H #ifndef __WINE_DINPUT_PRECOMP_H
#define __WINE_DINPUT_PRECOMP_H #define __WINE_DINPUT_PRECOMP_H
#include <wine/config.h>
#define WIN32_NO_STATUS #define WIN32_NO_STATUS
#define _INC_WINDOWS #define _INC_WINDOWS
#define COM_NO_WINDOWS_H #define COM_NO_WINDOWS_H

View file

@ -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/d3dxof # Synced to WineStaging-3.17
dll/directx/wine/ddraw # Synced to WineStaging-3.3 dll/directx/wine/ddraw # Synced to WineStaging-3.3
dll/directx/wine/devenum # Synced to WineStaging-4.18 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/dinput8 # Synced to WineStaging-3.3
dll/directx/wine/dmusic # Synced to WineStaging-4.0 dll/directx/wine/dmusic # Synced to WineStaging-4.0
dll/directx/wine/dplay # Synced to WineStaging-3.3 dll/directx/wine/dplay # Synced to WineStaging-3.3