HRESULT linuxinput_get_info_A(int fd, REFGUID rguid, LPDIEFFECTINFOA info);
HRESULT linuxinput_get_info_W(int fd, REFGUID rguid, LPDIEFFECTINFOW info);
+static HRESULT WINAPI JoystickWImpl_SendForceFeedbackCommand(LPDIRECTINPUTDEVICE8W iface, DWORD dwFlags);
+
typedef struct JoystickImpl JoystickImpl;
static const IDirectInputDevice8AVtbl JoystickAvt;
static const IDirectInputDevice8WVtbl JoystickWvt;
char *device;
char *name;
GUID guid;
+ GUID guid_product;
BOOL has_ff;
int num_effects;
/* data returned by the EVIOCGABS() ioctl */
struct wine_input_absinfo axes[ABS_MAX];
- WORD vendor_id, product_id;
+ WORD vendor_id, product_id, bus_type;
};
struct JoystickImpl
return CONTAINING_RECORD(CONTAINING_RECORD(CONTAINING_RECORD(iface, IDirectInputDeviceImpl, IDirectInputDevice8W_iface),
JoystickGenericImpl, base), JoystickImpl, generic);
}
-static inline IDirectInputDevice8A *IDirectInputDevice8A_from_impl(JoystickImpl *This)
-{
- return &This->generic.base.IDirectInputDevice8A_iface;
-}
+
static inline IDirectInputDevice8W *IDirectInputDevice8W_from_impl(JoystickImpl *This)
{
return &This->generic.base.IDirectInputDevice8W_iface;
{0x8d, 0x4a, 0x23, 0x90, 0x3f, 0xb6, 0xbd, 0xf7}
};
+/*
+ * Construct the GUID in the same way of Windows doing this.
+ * Data1 is concatenation of productid and vendorid.
+ * Data2 and Data3 are NULL.
+ * Data4 seems to be a constant.
+ */
+static const GUID DInput_Wine_Joystick_Constant_Part_GUID = {
+ 0x000000000,
+ 0x0000,
+ 0x0000,
+ {0x00, 0x00, 0x50, 0x49, 0x44, 0x56, 0x49, 0x44}
+};
+
#define test_bit(arr,bit) (((BYTE*)(arr))[(bit)>>3]&(1<<((bit)&7)))
#define MAX_JOYDEV 64
}
if (ioctl(fd, EVIOCGID, &device_id) == -1)
+ {
WARN("ioctl(EVIOCGID) failed: %d %s\n", errno, strerror(errno));
+ joydev.guid_product = DInput_Wine_Joystick_Base_GUID;
+ }
else
{
joydev.vendor_id = device_id.vendor;
joydev.product_id = device_id.product;
+ joydev.bus_type = device_id.bustype;
+
+ /* Concatenate product_id with vendor_id to mimic Windows behaviour */
+ joydev.guid_product = DInput_Wine_Joystick_Constant_Part_GUID;
+ joydev.guid_product.Data1 = MAKELONG(joydev.vendor_id, joydev.product_id);
}
if (!have_joydevs)
}
}
-static void fill_joystick_dideviceinstanceA(LPDIDEVICEINSTANCEA lpddi, DWORD version, int id)
+static void fill_joystick_dideviceinstanceW(LPDIDEVICEINSTANCEW lpddi, DWORD version, int id)
{
DWORD dwSize = lpddi->dwSize;
lpddi->dwSize = dwSize;
lpddi->guidInstance = joydevs[id].guid;
- lpddi->guidProduct = DInput_Wine_Joystick_Base_GUID;
+ lpddi->guidProduct = joydevs[id].guid_product;
lpddi->guidFFDriver = GUID_NULL;
if (version >= 0x0800)
else
lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
- strcpy(lpddi->tszInstanceName, joydevs[id].name);
- strcpy(lpddi->tszProductName, joydevs[id].name);
+ /* 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 &&
+ joydevs[id].vendor_id && joydevs[id].product_id)
+ {
+ lpddi->dwDevType |= DIDEVTYPE_HID;
+ lpddi->wUsagePage = 0x01; /* Desktop */
+ if (lpddi->dwDevType == DI8DEVTYPE_JOYSTICK || lpddi->dwDevType == DIDEVTYPE_JOYSTICK)
+ lpddi->wUsage = 0x04; /* Joystick */
+ else
+ lpddi->wUsage = 0x05; /* Game Pad */
+ }
+
+ MultiByteToWideChar(CP_ACP, 0, joydevs[id].name, -1, lpddi->tszInstanceName, MAX_PATH);
+ MultiByteToWideChar(CP_ACP, 0, joydevs[id].name, -1, lpddi->tszProductName, MAX_PATH);
}
-static void fill_joystick_dideviceinstanceW(LPDIDEVICEINSTANCEW lpddi, DWORD version, int id)
+static void fill_joystick_dideviceinstanceA(LPDIDEVICEINSTANCEA lpddi, DWORD version, int id)
{
+ DIDEVICEINSTANCEW lpddiW;
DWORD dwSize = lpddi->dwSize;
+ lpddiW.dwSize = sizeof(lpddiW);
+ fill_joystick_dideviceinstanceW(&lpddiW, version, id);
+
TRACE("%d %p\n", dwSize, lpddi);
memset(lpddi, 0, dwSize);
- lpddi->dwSize = dwSize;
- lpddi->guidInstance = joydevs[id].guid;
- lpddi->guidProduct = DInput_Wine_Joystick_Base_GUID;
- lpddi->guidFFDriver = GUID_NULL;
-
- if (version >= 0x0800)
- lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
- else
- lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
-
- MultiByteToWideChar(CP_ACP, 0, joydevs[id].name, -1, lpddi->tszInstanceName, MAX_PATH);
- MultiByteToWideChar(CP_ACP, 0, joydevs[id].name, -1, lpddi->tszProductName, MAX_PATH);
+ /* Convert W->A */
+ lpddi->dwSize = dwSize;
+ lpddi->guidInstance = lpddiW.guidInstance;
+ lpddi->guidProduct = lpddiW.guidProduct;
+ lpddi->dwDevType = lpddiW.dwDevType;
+ strcpy(lpddi->tszInstanceName, joydevs[id].name);
+ strcpy(lpddi->tszProductName, joydevs[id].name);
+ lpddi->guidFFDriver = lpddiW.guidFFDriver;
+ lpddi->wUsagePage = lpddiW.wUsagePage;
+ lpddi->wUsage = lpddiW.wUsage;
}
static HRESULT joydev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, DWORD version, int id)
LPDIDATAFORMAT df = NULL;
int i, idx = 0;
int default_axis_map[WINE_JOYSTICK_MAX_AXES + WINE_JOYSTICK_MAX_POVS*2];
+ DIDEVICEINSTANCEW ddi;
newDevice = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(JoystickImpl));
if (!newDevice) return NULL;
/* Fill the caps */
newDevice->generic.devcaps.dwSize = sizeof(newDevice->generic.devcaps);
newDevice->generic.devcaps.dwFlags = DIDC_ATTACHED;
- if (newDevice->generic.base.dinput->dwVersion >= 0x0800)
- newDevice->generic.devcaps.dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
- else
- newDevice->generic.devcaps.dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
+
+ ddi.dwSize = sizeof(ddi);
+ fill_joystick_dideviceinstanceW(&ddi, newDevice->generic.base.dinput->dwVersion, index);
+ newDevice->generic.devcaps.dwDevType = ddi.dwDevType;
if (newDevice->joydev->has_ff)
newDevice->generic.devcaps.dwFlags |= DIDC_FORCEFEEDBACK;
TRACE("(this=%p)\n",This);
res = IDirectInputDevice2WImpl_Unacquire(iface);
if (res==DI_OK && This->joyfd!=-1) {
- effect_list_item *itr;
struct input_event event;
- /* For each known effect:
- * - stop it
- * - unload it
- * But, unlike DISFFC_RESET, do not release the effect.
- */
- LIST_FOR_EACH_ENTRY(itr, &This->ff_effects, effect_list_item, entry) {
- IDirectInputEffect_Stop(itr->ref);
- IDirectInputEffect_Unload(itr->ref);
- }
+ /* Stop and unload all effects */
+ JoystickWImpl_SendForceFeedbackCommand(iface, DISFFC_RESET);
/* Enable autocenter. */
event.type = EV_FF;
break;
#endif
default:
- FIXME("joystick cannot handle type %d event (code %d)\n",ie.type,ie.code);
+ TRACE("skipping event\n");
break;
}
if (inst_id >= 0)
JoystickImpl* This = impl_from_IDirectInputDevice8W(iface);
TRACE("(this=%p,%p,%p,%p,%p)\n", This, rguid, lpeff, ppdef, pUnkOuter);
-#ifndef HAVE_STRUCT_FF_EFFECT_DIRECTION
- TRACE("not available (compiled w/o ff support)\n");
*ppdef = NULL;
- return DI_OK;
+ if (!This->joydev->has_ff)
+ {
+ TRACE("No force feedback support\n");
+ return DIERR_UNSUPPORTED;
+ }
+
+#ifndef HAVE_STRUCT_FF_EFFECT_DIRECTION
+ TRACE("not available (compiled w/o force feedback support)\n");
+ return DIERR_UNSUPPORTED;
#else
if (!(new_effect = HeapAlloc(GetProcessHeap(), 0, sizeof(*new_effect))))
{
case DISFFC_STOPALL:
{
- /* Stop all effects */
effect_list_item *itr;
+ /* Stop all effects */
LIST_FOR_EACH_ENTRY(itr, &This->ff_effects, effect_list_item, entry)
IDirectInputEffect_Stop(itr->ref);
break;
case DISFFC_RESET:
{
- effect_list_item *itr, *ptr;
+ effect_list_item *itr;
- /* Stop, unload, release and free all effects */
- /* This returns the device to its "bare" state */
- LIST_FOR_EACH_ENTRY_SAFE(itr, ptr, &This->ff_effects, effect_list_item, entry)
- IDirectInputEffect_Release(itr->ref);
+ /* Stop and unload all effects. It is not true that effects are released */
+ LIST_FOR_EACH_ENTRY(itr, &This->ff_effects, effect_list_item, entry)
+ {
+ IDirectInputEffect_Stop(itr->ref);
+ IDirectInputEffect_Unload(itr->ref);
+ }
break;
}
case DISFFC_PAUSE:
case DISFFC_CONTINUE:
- FIXME("No support for Pause or Continue in linux\n");
+ FIXME("No support for Pause or Continue in linux\n");
break;
case DISFFC_SETACTUATORSOFF:
break;
default:
- FIXME("Unknown Force Feedback Command!\n");
- return DIERR_INVALIDPARAM;
+ WARN("Unknown Force Feedback Command %u!\n", dwFlags);
+ return DIERR_INVALIDPARAM;
}
return DI_OK;
#else