wine-wine/dlls/dinput/joystick_osx.c

907 lines
31 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/* DirectInput Joystick device for Mac OS/X
*
* Copyright 1998 Marcus Meissner
* Copyright 1998,1999 Lionel Ulmer
* Copyright 2000-2001 TransGaming Technologies Inc.
* Copyright 2009 CodeWeavers, Aric Stewart
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "config.h"
#include "wine/port.h"
#if defined(HAVE_CARBON_CARBON_H) && defined(HAVE_IOKIT_HID_IOHIDLIB_H)
#define LoadResource __carbon_LoadResource
#define CompareString __carbon_CompareString
#define GetCurrentThread __carbon_GetCurrentThread
#define GetCurrentProcess __carbon_GetCurrentProcess
#define AnimatePalette __carbon_AnimatePalette
#define EqualRgn __carbon_EqualRgn
#define FillRgn __carbon_FillRgn
#define FrameRgn __carbon_FrameRgn
#define GetPixel __carbon_GetPixel
#define InvertRgn __carbon_InvertRgn
#define LineTo __carbon_LineTo
#define OffsetRgn __carbon_OffsetRgn
#define PaintRgn __carbon_PaintRgn
#define Polygon __carbon_Polygon
#define ResizePalette __carbon_ResizePalette
#define SetRectRgn __carbon_SetRectRgn
#define ULONG __carbon_ULONG
#define E_INVALIDARG __carbon_E_INVALIDARG
#define E_OUTOFMEMORY __carbon_E_OUTOFMEMORY
#define E_HANDLE __carbon_E_HANDLE
#define E_ACCESSDENIED __carbon_E_ACCESSDENIED
#define E_UNEXPECTED __carbon_E_UNEXPECTED
#define E_FAIL __carbon_E_FAIL
#define E_ABORT __carbon_E_ABORT
#define E_POINTER __carbon_E_POINTER
#define E_NOINTERFACE __carbon_E_NOINTERFACE
#define E_NOTIMPL __carbon_E_NOTIMPL
#define S_FALSE __carbon_S_FALSE
#define S_OK __carbon_S_OK
#define HRESULT_FACILITY __carbon_HRESULT_FACILITY
#define IS_ERROR __carbon_IS_ERROR
#define FAILED __carbon_FAILED
#define SUCCEEDED __carbon_SUCCEEDED
#define MAKE_HRESULT __carbon_MAKE_HRESULT
#define HRESULT __carbon_HRESULT
#define STDMETHODCALLTYPE __carbon_STDMETHODCALLTYPE
#include <Carbon/Carbon.h>
#include <IOKit/hid/IOHIDLib.h>
#undef LoadResource
#undef CompareString
#undef GetCurrentThread
#undef _CDECL
#undef DPRINTF
#undef GetCurrentProcess
#undef AnimatePalette
#undef EqualRgn
#undef FillRgn
#undef FrameRgn
#undef GetPixel
#undef InvertRgn
#undef LineTo
#undef OffsetRgn
#undef PaintRgn
#undef Polygon
#undef ResizePalette
#undef SetRectRgn
#undef ULONG
#undef E_INVALIDARG
#undef E_OUTOFMEMORY
#undef E_HANDLE
#undef E_ACCESSDENIED
#undef E_UNEXPECTED
#undef E_FAIL
#undef E_ABORT
#undef E_POINTER
#undef E_NOINTERFACE
#undef E_NOTIMPL
#undef S_FALSE
#undef S_OK
#undef HRESULT_FACILITY
#undef IS_ERROR
#undef FAILED
#undef SUCCEEDED
#undef MAKE_HRESULT
#undef HRESULT
#undef STDMETHODCALLTYPE
#endif /* HAVE_CARBON_CARBON_H */
#include "wine/debug.h"
#include "wine/unicode.h"
#include "windef.h"
#include "winbase.h"
#include "winerror.h"
#include "winreg.h"
#include "dinput.h"
#include "dinput_private.h"
#include "device_private.h"
#include "joystick_private.h"
WINE_DEFAULT_DEBUG_CHANNEL(dinput);
#ifdef HAVE_IOHIDMANAGERCREATE
static IOHIDManagerRef gIOHIDManagerRef = NULL;
static CFArrayRef gDevices = NULL;
typedef struct JoystickImpl JoystickImpl;
static const IDirectInputDevice8AVtbl JoystickAvt;
static const IDirectInputDevice8WVtbl JoystickWvt;
struct JoystickImpl
{
struct JoystickGenericImpl generic;
/* osx private */
int id;
CFMutableArrayRef elementCFArrayRef;
ObjProps **propmap;
};
static const GUID DInput_Wine_OsX_Joystick_GUID = { /* 59CAD8F6-E617-41E2-8EB7-47B23EEEDC5A */
0x59CAD8F6, 0xE617, 0x41E2, {0x8E, 0xB7, 0x47, 0xB2, 0x3E, 0xEE, 0xDC, 0x5A}
};
static void CFSetApplierFunctionCopyToCFArray(const void *value, void *context)
{
CFArrayAppendValue( ( CFMutableArrayRef ) context, value );
}
static CFMutableDictionaryRef creates_osx_device_match(int usage)
{
CFMutableDictionaryRef result;
result = CFDictionaryCreateMutable( kCFAllocatorDefault, 0,
&kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks );
if ( result )
{
int number = kHIDPage_GenericDesktop;
CFNumberRef pageCFNumberRef = CFNumberCreate( kCFAllocatorDefault,
kCFNumberIntType, &number);
if ( pageCFNumberRef )
{
CFNumberRef usageCFNumberRef;
CFDictionarySetValue( result, CFSTR( kIOHIDDeviceUsagePageKey ),
pageCFNumberRef );
CFRelease( pageCFNumberRef );
usageCFNumberRef = CFNumberCreate( kCFAllocatorDefault,
kCFNumberIntType, &usage);
if ( usageCFNumberRef )
{
CFDictionarySetValue( result, CFSTR( kIOHIDDeviceUsageKey ),
usageCFNumberRef );
CFRelease( usageCFNumberRef );
}
else
{
ERR("CFNumberCreate() failed.");
return NULL;
}
}
else
{
ERR("CFNumberCreate failed.");
return NULL;
}
}
else
{
ERR("CFDictionaryCreateMutable failed.");
return NULL;
}
return result;
}
static int find_osx_devices(void)
{
IOReturn tIOReturn;
CFMutableDictionaryRef result;
CFSetRef devset;
CFArrayRef matching;
gIOHIDManagerRef = IOHIDManagerCreate( kCFAllocatorDefault, 0L );
tIOReturn = IOHIDManagerOpen( gIOHIDManagerRef, 0L);
if ( kIOReturnSuccess != tIOReturn )
{
ERR("Couldnt open IOHIDManager.");
return 0;
}
matching = CFArrayCreateMutable( kCFAllocatorDefault, 0,
&kCFTypeArrayCallBacks );
/* build matching dictionary */
result = creates_osx_device_match(kHIDPage_Sport);
if (!result)
{
CFRelease(matching);
return 0;
}
CFArrayAppendValue( ( CFMutableArrayRef )matching, result );
result = creates_osx_device_match(kHIDPage_Game);
if (!result)
{
CFRelease(matching);
return 0;
}
CFArrayAppendValue( ( CFMutableArrayRef )matching, result );
IOHIDManagerSetDeviceMatchingMultiple( gIOHIDManagerRef, matching);
devset = IOHIDManagerCopyDevices( gIOHIDManagerRef );
if (devset)
{
CFIndex count;
gDevices = CFArrayCreateMutable( kCFAllocatorDefault, 0,
&kCFTypeArrayCallBacks );
CFSetApplyFunction(devset, CFSetApplierFunctionCopyToCFArray, (void*)gDevices);
count = CFArrayGetCount( gDevices);
CFRelease( devset);
count = CFArrayGetCount( gDevices);
TRACE("found %i device(s)\n",(int)count);
return count;
}
return 0;
}
static int get_osx_device_name(int id, char *name, int length)
{
CFStringRef str;
IOHIDDeviceRef tIOHIDDeviceRef;
if (!gDevices)
return 0;
tIOHIDDeviceRef = ( IOHIDDeviceRef ) CFArrayGetValueAtIndex( gDevices, id );
if (!tIOHIDDeviceRef)
return 0;
if (name)
name[0] = 0;
if (!tIOHIDDeviceRef)
{
ERR("Invalid Device requested %i\n",id);
return 0;
}
str = IOHIDDeviceGetProperty(tIOHIDDeviceRef, CFSTR( kIOHIDProductKey ));
if (str)
{
CFIndex len = CFStringGetLength(str);
if (length >= len)
{
CFStringGetCString(str,name,length,kCFStringEncodingASCII);
return len;
}
else
return (len+1);
}
return 0;
}
static void get_osx_device_elements(JoystickImpl *device, int axis_map[8])
{
IOHIDDeviceRef tIOHIDDeviceRef;
CFArrayRef gElementCFArrayRef;
DWORD axes = 0;
DWORD sliders = 0;
DWORD buttons = 0;
DWORD povs = 0;
device->elementCFArrayRef = NULL;
if (!gDevices)
return;
tIOHIDDeviceRef = ( IOHIDDeviceRef ) CFArrayGetValueAtIndex( gDevices, device->id );
if (!tIOHIDDeviceRef)
return;
gElementCFArrayRef = IOHIDDeviceCopyMatchingElements( tIOHIDDeviceRef,
NULL, 0 );
if (gElementCFArrayRef)
{
CFIndex idx, cnt = CFArrayGetCount( gElementCFArrayRef );
/* build our element array in the order that dinput expects */
device->elementCFArrayRef = CFArrayCreateMutable(NULL,0,NULL);
for ( idx = 0; idx < cnt; idx++ )
{
IOHIDElementRef tIOHIDElementRef = ( IOHIDElementRef ) CFArrayGetValueAtIndex( gElementCFArrayRef, idx );
int eleType = IOHIDElementGetType( tIOHIDElementRef );
switch(eleType)
{
case kIOHIDElementTypeInput_Button:
{
if (buttons < 128)
{
CFArrayInsertValueAtIndex(device->elementCFArrayRef, (axes+povs+buttons), tIOHIDElementRef);
buttons++;
}
break;
}
case kIOHIDElementTypeInput_Axis:
{
CFArrayInsertValueAtIndex(device->elementCFArrayRef, axes, tIOHIDElementRef);
axes++;
break;
}
case kIOHIDElementTypeInput_Misc:
{
uint32_t usage = IOHIDElementGetUsage( tIOHIDElementRef );
switch(usage)
{
case kHIDUsage_GD_Hatswitch:
{
CFArrayInsertValueAtIndex(device->elementCFArrayRef, (axes+povs), tIOHIDElementRef);
povs++;
break;
}
case kHIDUsage_GD_Slider:
sliders ++;
if (sliders > 2)
break;
/* fallthrough, sliders are axis */
case kHIDUsage_GD_X:
case kHIDUsage_GD_Y:
case kHIDUsage_GD_Z:
case kHIDUsage_GD_Rx:
case kHIDUsage_GD_Ry:
case kHIDUsage_GD_Rz:
{
CFArrayInsertValueAtIndex(device->elementCFArrayRef, axes, tIOHIDElementRef);
axis_map[axes]=usage;
axes++;
break;
}
default:
FIXME("Unhandled usage %i\n",usage);
}
break;
}
default:
FIXME("Unhandled type %i\n",eleType);
}
}
}
device->generic.devcaps.dwAxes = axes;
device->generic.devcaps.dwButtons = buttons;
device->generic.devcaps.dwPOVs = povs;
}
static void get_osx_device_elements_props(JoystickImpl *device)
{
CFArrayRef gElementCFArrayRef = device->elementCFArrayRef;
if (gElementCFArrayRef)
{
CFIndex idx, cnt = CFArrayGetCount( gElementCFArrayRef );
for ( idx = 0; idx < cnt; idx++ )
{
IOHIDElementRef tIOHIDElementRef = ( IOHIDElementRef ) CFArrayGetValueAtIndex( gElementCFArrayRef, idx );
device->generic.props[idx].lDevMin = IOHIDElementGetLogicalMin(tIOHIDElementRef);
device->generic.props[idx].lDevMax = IOHIDElementGetLogicalMax(tIOHIDElementRef);
device->generic.props[idx].lMin = 0;
device->generic.props[idx].lMax = 0xffff;
device->generic.props[idx].lDeadZone = 0;
device->generic.props[idx].lSaturation = 0;
}
}
}
static void poll_osx_device_state(JoystickGenericImpl *device_in)
{
JoystickImpl *device = (JoystickImpl*)device_in;
IOHIDDeviceRef tIOHIDDeviceRef;
CFArrayRef gElementCFArrayRef = device->elementCFArrayRef;
TRACE("polling device %i\n",device->id);
if (!gDevices)
return;
tIOHIDDeviceRef = ( IOHIDDeviceRef ) CFArrayGetValueAtIndex( gDevices, device->id );
if (!tIOHIDDeviceRef)
return;
if (gElementCFArrayRef)
{
int button_idx = 0;
int pov_idx = 0;
int slider_idx = 0;
CFIndex idx, cnt = CFArrayGetCount( gElementCFArrayRef );
for ( idx = 0; idx < cnt; idx++ )
{
IOHIDValueRef valueRef;
int val;
IOHIDElementRef tIOHIDElementRef = ( IOHIDElementRef ) CFArrayGetValueAtIndex( gElementCFArrayRef, idx );
int eleType = IOHIDElementGetType( tIOHIDElementRef );
switch(eleType)
{
case kIOHIDElementTypeInput_Button:
if(button_idx < 128)
{
IOHIDDeviceGetValue(tIOHIDDeviceRef, tIOHIDElementRef, &valueRef);
val = IOHIDValueGetIntegerValue(valueRef);
device->generic.js.rgbButtons[button_idx] = val ? 0x80 : 0x00;
button_idx ++;
}
break;
case kIOHIDElementTypeInput_Misc:
{
uint32_t usage = IOHIDElementGetUsage( tIOHIDElementRef );
switch(usage)
{
case kHIDUsage_GD_Hatswitch:
{
IOHIDDeviceGetValue(tIOHIDDeviceRef, tIOHIDElementRef, &valueRef);
val = IOHIDValueGetIntegerValue(valueRef);
if (val >= 8)
device->generic.js.rgdwPOV[pov_idx] = -1;
else
device->generic.js.rgdwPOV[pov_idx] = val * 4500;
pov_idx ++;
break;
}
case kHIDUsage_GD_X:
case kHIDUsage_GD_Y:
case kHIDUsage_GD_Z:
case kHIDUsage_GD_Rx:
case kHIDUsage_GD_Ry:
case kHIDUsage_GD_Rz:
case kHIDUsage_GD_Slider:
{
IOHIDDeviceGetValue(tIOHIDDeviceRef, tIOHIDElementRef, &valueRef);
val = IOHIDValueGetIntegerValue(valueRef);
switch (usage)
{
case kHIDUsage_GD_X:
device->generic.js.lX = joystick_map_axis(&device->generic.props[idx], val);
break;
case kHIDUsage_GD_Y:
device->generic.js.lY = joystick_map_axis(&device->generic.props[idx], val);
break;
case kHIDUsage_GD_Z:
device->generic.js.lZ = joystick_map_axis(&device->generic.props[idx], val);
break;
case kHIDUsage_GD_Rx:
device->generic.js.lRx = joystick_map_axis(&device->generic.props[idx], val);
break;
case kHIDUsage_GD_Ry:
device->generic.js.lRy = joystick_map_axis(&device->generic.props[idx], val);
break;
case kHIDUsage_GD_Rz:
device->generic.js.lRz = joystick_map_axis(&device->generic.props[idx], val);
break;
case kHIDUsage_GD_Slider:
device->generic.js.rglSlider[slider_idx] = joystick_map_axis(&device->generic.props[idx], val);
slider_idx ++;
break;
}
break;
}
default:
FIXME("unhandled usage %i\n",usage);
}
break;
}
default:
FIXME("Unhandled type %i\n",eleType);
}
}
}
}
static INT find_joystick_devices(void)
{
static INT joystick_devices_count = -1;
if (joystick_devices_count != -1) return joystick_devices_count;
joystick_devices_count = find_osx_devices();
return joystick_devices_count;
}
static BOOL joydev_enum_deviceA(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEA lpddi, DWORD version, int id)
{
if (id >= find_joystick_devices()) return FALSE;
if (dwFlags & DIEDFL_FORCEFEEDBACK) {
WARN("force feedback not supported\n");
return FALSE;
}
if ((dwDevType == 0) ||
((dwDevType == DIDEVTYPE_JOYSTICK) && (version > 0x0300 && version < 0x0800)) ||
(((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800)))
{
/* Return joystick */
lpddi->guidInstance = DInput_Wine_OsX_Joystick_GUID;
lpddi->guidInstance.Data3 = id;
lpddi->guidProduct = DInput_Wine_OsX_Joystick_GUID;
/* we only support traditional joysticks for now */
if (version >= 0x0800)
lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
else
lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
sprintf(lpddi->tszInstanceName, "Joystick %d", id);
/* get the device name */
get_osx_device_name(id, lpddi->tszProductName, MAX_PATH);
lpddi->guidFFDriver = GUID_NULL;
return TRUE;
}
return FALSE;
}
static BOOL joydev_enum_deviceW(DWORD dwDevType, DWORD dwFlags, LPDIDEVICEINSTANCEW lpddi, DWORD version, int id)
{
char name[MAX_PATH];
char friendly[32];
if (id >= find_joystick_devices()) return FALSE;
if (dwFlags & DIEDFL_FORCEFEEDBACK) {
WARN("force feedback not supported\n");
return FALSE;
}
if ((dwDevType == 0) ||
((dwDevType == DIDEVTYPE_JOYSTICK) && (version > 0x0300 && version < 0x0800)) ||
(((dwDevType == DI8DEVCLASS_GAMECTRL) || (dwDevType == DI8DEVTYPE_JOYSTICK)) && (version >= 0x0800))) {
/* Return joystick */
lpddi->guidInstance = DInput_Wine_OsX_Joystick_GUID;
lpddi->guidInstance.Data3 = id;
lpddi->guidProduct = DInput_Wine_OsX_Joystick_GUID;
/* we only support traditional joysticks for now */
if (version >= 0x0800)
lpddi->dwDevType = DI8DEVTYPE_JOYSTICK | (DI8DEVTYPEJOYSTICK_STANDARD << 8);
else
lpddi->dwDevType = DIDEVTYPE_JOYSTICK | (DIDEVTYPEJOYSTICK_TRADITIONAL << 8);
sprintf(friendly, "Joystick %d", id);
MultiByteToWideChar(CP_ACP, 0, friendly, -1, lpddi->tszInstanceName, MAX_PATH);
/* get the device name */
get_osx_device_name(id, name, MAX_PATH);
MultiByteToWideChar(CP_ACP, 0, name, -1, lpddi->tszProductName, MAX_PATH);
lpddi->guidFFDriver = GUID_NULL;
return TRUE;
}
return FALSE;
}
static HRESULT alloc_device(REFGUID rguid, const void *jvt, IDirectInputImpl *dinput,
LPDIRECTINPUTDEVICEA* pdev, unsigned short index)
{
DWORD i;
JoystickImpl* newDevice;
char name[MAX_PATH];
HRESULT hr;
LPDIDATAFORMAT df = NULL;
int idx = 0;
int axis_map[8]; /* max axes */
int slider_count = 0;
TRACE("%s %p %p %p %hu\n", debugstr_guid(rguid), jvt, dinput, pdev, index);
newDevice = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(JoystickImpl));
if (newDevice == 0) {
WARN("out of memory\n");
*pdev = 0;
return DIERR_OUTOFMEMORY;
}
newDevice->id = index;
newDevice->generic.guidProduct = DInput_Wine_OsX_Joystick_GUID;
newDevice->generic.joy_polldev = poll_osx_device_state;
/* get the device name */
get_osx_device_name(index, name, MAX_PATH);
TRACE("Name %s\n",name);
/* copy the device name */
newDevice->generic.name = HeapAlloc(GetProcessHeap(),0,strlen(name) + 1);
strcpy(newDevice->generic.name, name);
memset(axis_map, 0, sizeof(axis_map));
get_osx_device_elements(newDevice, axis_map);
TRACE("%i axes %i buttons %i povs\n",newDevice->generic.devcaps.dwAxes,newDevice->generic.devcaps.dwButtons,newDevice->generic.devcaps.dwPOVs);
if (newDevice->generic.devcaps.dwButtons > 128)
{
WARN("Can't support %d buttons. Clamping down to 128\n", newDevice->generic.devcaps.dwButtons);
newDevice->generic.devcaps.dwButtons = 128;
}
newDevice->generic.base.lpVtbl = jvt;
newDevice->generic.base.ref = 1;
newDevice->generic.base.dinput = dinput;
newDevice->generic.base.guid = *rguid;
InitializeCriticalSection(&newDevice->generic.base.crit);
newDevice->generic.base.crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": JoystickImpl*->generic.base.crit");
/* Create copy of default data format */
if (!(df = HeapAlloc(GetProcessHeap(), 0, c_dfDIJoystick2.dwSize))) goto FAILED;
memcpy(df, &c_dfDIJoystick2, c_dfDIJoystick2.dwSize);
df->dwNumObjs = newDevice->generic.devcaps.dwAxes + newDevice->generic.devcaps.dwPOVs + newDevice->generic.devcaps.dwButtons;
if (!(df->rgodf = HeapAlloc(GetProcessHeap(), 0, df->dwNumObjs * df->dwObjSize))) goto FAILED;
for (i = 0; i < newDevice->generic.devcaps.dwAxes; i++)
{
int wine_obj = -1;
switch (axis_map[i])
{
case kHIDUsage_GD_X: wine_obj = 0; break;
case kHIDUsage_GD_Y: wine_obj = 1; break;
case kHIDUsage_GD_Z: wine_obj = 2; break;
case kHIDUsage_GD_Rx: wine_obj = 3; break;
case kHIDUsage_GD_Ry: wine_obj = 4; break;
case kHIDUsage_GD_Rz: wine_obj = 5; break;
case kHIDUsage_GD_Slider:
wine_obj = 6 + slider_count;
slider_count++;
break;
}
if (wine_obj < 0 ) continue;
memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[wine_obj], df->dwObjSize);
df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(wine_obj) | DIDFT_ABSAXIS;
}
for (i = 0; i < newDevice->generic.devcaps.dwPOVs; i++)
{
memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[i + 8], df->dwObjSize);
df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(i) | DIDFT_POV;
}
for (i = 0; i < newDevice->generic.devcaps.dwButtons; i++)
{
memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[i + 12], df->dwObjSize);
df->rgodf[idx ].pguid = &GUID_Button;
df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(i) | DIDFT_PSHBUTTON;
}
newDevice->generic.base.data_format.wine_df = df;
/* create default properties */
newDevice->generic.props = HeapAlloc(GetProcessHeap(),0,c_dfDIJoystick2.dwNumObjs*sizeof(ObjProps));
if (newDevice->generic.props == 0)
goto FAILED;
/* initialize default properties */
get_osx_device_elements_props(newDevice);
IDirectInput_AddRef((LPDIRECTINPUTDEVICE8A)newDevice->generic.base.dinput);
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);
newDevice->generic.devcaps.dwFFSamplePeriod = 0;
newDevice->generic.devcaps.dwFFMinTimeResolution = 0;
newDevice->generic.devcaps.dwFirmwareRevision = 0;
newDevice->generic.devcaps.dwHardwareRevision = 0;
newDevice->generic.devcaps.dwFFDriverVersion = 0;
if (TRACE_ON(dinput)) {
_dump_DIDATAFORMAT(newDevice->generic.base.data_format.wine_df);
_dump_DIDEVCAPS(&newDevice->generic.devcaps);
}
*pdev = (LPDIRECTINPUTDEVICEA)newDevice;
return DI_OK;
FAILED:
hr = DIERR_OUTOFMEMORY;
if (df) HeapFree(GetProcessHeap(), 0, df->rgodf);
HeapFree(GetProcessHeap(), 0, df);
release_DataFormat(&newDevice->generic.base.data_format);
HeapFree(GetProcessHeap(),0,newDevice->generic.name);
HeapFree(GetProcessHeap(),0,newDevice->generic.props);
HeapFree(GetProcessHeap(),0,newDevice);
*pdev = 0;
return hr;
}
/******************************************************************************
* get_joystick_index : Get the joystick index from a given GUID
*/
static unsigned short get_joystick_index(REFGUID guid)
{
GUID wine_joystick = DInput_Wine_OsX_Joystick_GUID;
GUID dev_guid = *guid;
wine_joystick.Data3 = 0;
dev_guid.Data3 = 0;
/* for the standard joystick GUID use index 0 */
if(IsEqualGUID(&GUID_Joystick,guid)) return 0;
/* for the wine joystick GUIDs use the index stored in Data3 */
if(IsEqualGUID(&wine_joystick, &dev_guid)) return guid->Data3;
return 0xffff;
}
static HRESULT joydev_create_deviceA(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEA* pdev)
{
unsigned short index;
int joystick_devices_count;
TRACE("%p %s %p %p\n",dinput, debugstr_guid(rguid), riid, pdev);
*pdev = NULL;
if ((joystick_devices_count = find_joystick_devices()) == 0)
return DIERR_DEVICENOTREG;
if ((index = get_joystick_index(rguid)) < 0xffff &&
joystick_devices_count && index < joystick_devices_count)
{
if ((riid == NULL) ||
IsEqualGUID(&IID_IDirectInputDeviceA, riid) ||
IsEqualGUID(&IID_IDirectInputDevice2A, riid) ||
IsEqualGUID(&IID_IDirectInputDevice7A, riid) ||
IsEqualGUID(&IID_IDirectInputDevice8A, riid))
{
return alloc_device(rguid, &JoystickAvt, dinput, pdev, index);
}
WARN("no interface\n");
return DIERR_NOINTERFACE;
}
return DIERR_DEVICENOTREG;
}
static HRESULT joydev_create_deviceW(IDirectInputImpl *dinput, REFGUID rguid, REFIID riid, LPDIRECTINPUTDEVICEW* pdev)
{
unsigned short index;
int joystick_devices_count;
TRACE("%p %s %p %p\n",dinput, debugstr_guid(rguid), riid, pdev);
*pdev = NULL;
if ((joystick_devices_count = find_joystick_devices()) == 0)
return DIERR_DEVICENOTREG;
if ((index = get_joystick_index(rguid)) < 0xffff &&
joystick_devices_count && index < joystick_devices_count)
{
if ((riid == NULL) ||
IsEqualGUID(&IID_IDirectInputDeviceW, riid) ||
IsEqualGUID(&IID_IDirectInputDevice2W, riid) ||
IsEqualGUID(&IID_IDirectInputDevice7W, riid) ||
IsEqualGUID(&IID_IDirectInputDevice8W, riid))
{
return alloc_device(rguid, &JoystickWvt, dinput, (LPDIRECTINPUTDEVICEA *)pdev, index);
}
WARN("no interface\n");
return DIERR_NOINTERFACE;
}
WARN("invalid device GUID %s\n",debugstr_guid(rguid));
return DIERR_DEVICENOTREG;
}
const struct dinput_device joystick_osx_device = {
"Wine OS X joystick driver",
joydev_enum_deviceA,
joydev_enum_deviceW,
joydev_create_deviceA,
joydev_create_deviceW
};
static const IDirectInputDevice8AVtbl JoystickAvt =
{
IDirectInputDevice2AImpl_QueryInterface,
IDirectInputDevice2AImpl_AddRef,
IDirectInputDevice2AImpl_Release,
JoystickAGenericImpl_GetCapabilities,
IDirectInputDevice2AImpl_EnumObjects,
JoystickAGenericImpl_GetProperty,
JoystickAGenericImpl_SetProperty,
JoystickAGenericImpl_Acquire,
JoystickAGenericImpl_Unacquire,
JoystickAGenericImpl_GetDeviceState,
IDirectInputDevice2AImpl_GetDeviceData,
IDirectInputDevice2AImpl_SetDataFormat,
IDirectInputDevice2AImpl_SetEventNotification,
IDirectInputDevice2AImpl_SetCooperativeLevel,
JoystickAGenericImpl_GetObjectInfo,
JoystickAGenericImpl_GetDeviceInfo,
IDirectInputDevice2AImpl_RunControlPanel,
IDirectInputDevice2AImpl_Initialize,
IDirectInputDevice2AImpl_CreateEffect,
IDirectInputDevice2AImpl_EnumEffects,
IDirectInputDevice2AImpl_GetEffectInfo,
IDirectInputDevice2AImpl_GetForceFeedbackState,
IDirectInputDevice2AImpl_SendForceFeedbackCommand,
IDirectInputDevice2AImpl_EnumCreatedEffectObjects,
IDirectInputDevice2AImpl_Escape,
JoystickAGenericImpl_Poll,
IDirectInputDevice2AImpl_SendDeviceData,
IDirectInputDevice7AImpl_EnumEffectsInFile,
IDirectInputDevice7AImpl_WriteEffectToFile,
IDirectInputDevice8AImpl_BuildActionMap,
IDirectInputDevice8AImpl_SetActionMap,
IDirectInputDevice8AImpl_GetImageInfo
};
#if !defined(__STRICT_ANSI__) && defined(__GNUC__)
# define XCAST(fun) (typeof(JoystickWvt.fun))
#else
# define XCAST(fun) (void*)
#endif
static const IDirectInputDevice8WVtbl JoystickWvt =
{
IDirectInputDevice2WImpl_QueryInterface,
XCAST(AddRef)IDirectInputDevice2AImpl_AddRef,
XCAST(Release)IDirectInputDevice2AImpl_Release,
XCAST(GetCapabilities)JoystickAGenericImpl_GetCapabilities,
IDirectInputDevice2WImpl_EnumObjects,
XCAST(GetProperty)JoystickAGenericImpl_GetProperty,
XCAST(SetProperty)JoystickAGenericImpl_SetProperty,
XCAST(Acquire)JoystickAGenericImpl_Acquire,
XCAST(Unacquire)JoystickAGenericImpl_Unacquire,
XCAST(GetDeviceState)JoystickAGenericImpl_GetDeviceState,
XCAST(GetDeviceData)IDirectInputDevice2AImpl_GetDeviceData,
XCAST(SetDataFormat)IDirectInputDevice2AImpl_SetDataFormat,
XCAST(SetEventNotification)IDirectInputDevice2AImpl_SetEventNotification,
XCAST(SetCooperativeLevel)IDirectInputDevice2AImpl_SetCooperativeLevel,
JoystickWGenericImpl_GetObjectInfo,
JoystickWGenericImpl_GetDeviceInfo,
XCAST(RunControlPanel)IDirectInputDevice2AImpl_RunControlPanel,
XCAST(Initialize)IDirectInputDevice2AImpl_Initialize,
XCAST(CreateEffect)IDirectInputDevice2AImpl_CreateEffect,
IDirectInputDevice2WImpl_EnumEffects,
IDirectInputDevice2WImpl_GetEffectInfo,
XCAST(GetForceFeedbackState)IDirectInputDevice2AImpl_GetForceFeedbackState,
XCAST(SendForceFeedbackCommand)IDirectInputDevice2AImpl_SendForceFeedbackCommand,
XCAST(EnumCreatedEffectObjects)IDirectInputDevice2AImpl_EnumCreatedEffectObjects,
XCAST(Escape)IDirectInputDevice2AImpl_Escape,
XCAST(Poll)JoystickAGenericImpl_Poll,
XCAST(SendDeviceData)IDirectInputDevice2AImpl_SendDeviceData,
IDirectInputDevice7WImpl_EnumEffectsInFile,
IDirectInputDevice7WImpl_WriteEffectToFile,
IDirectInputDevice8WImpl_BuildActionMap,
IDirectInputDevice8WImpl_SetActionMap,
IDirectInputDevice8WImpl_GetImageInfo
};
#undef XCAST
#else /* HAVE_IOHIDMANAGERCREATE */
const struct dinput_device joystick_osx_device = {
"Wine OS X joystick driver",
NULL,
NULL,
NULL,
NULL
};
#endif /* HAVE_IOHIDMANAGERCREATE */