From 225a494d663add0d3c25296e2c4ed5f5ab64c9d8 Mon Sep 17 00:00:00 2001 From: Aric Stewart Date: Tue, 10 Mar 2009 14:59:20 -0500 Subject: [PATCH] dinput: Add Mac OS/X joystick support. --- configure | 2 + configure.ac | 1 + dlls/dinput/Makefile.in | 2 + dlls/dinput/dinput_main.c | 3 +- dlls/dinput/dinput_private.h | 1 + dlls/dinput/joystick_osx.c | 787 +++++++++++++++++++++++++++++++++++ include/config.h.in | 3 + 7 files changed, 798 insertions(+), 1 deletion(-) create mode 100644 dlls/dinput/joystick_osx.c diff --git a/configure b/configure index c254f1086da..8bf88e1981d 100755 --- a/configure +++ b/configure @@ -6076,6 +6076,7 @@ done + for ac_header in \ @@ -6084,6 +6085,7 @@ for ac_header in \ CoreAudio/CoreAudio.h \ DiskArbitration/DiskArbitration.h \ IOKit/IOKitLib.h \ + IOKit/hid/IOHIDLib.h \ alias.h \ alsa/asoundlib.h \ arpa/inet.h \ diff --git a/configure.ac b/configure.ac index b1c3c125f60..0930f5c75c1 100644 --- a/configure.ac +++ b/configure.ac @@ -263,6 +263,7 @@ AC_CHECK_HEADERS(\ CoreAudio/CoreAudio.h \ DiskArbitration/DiskArbitration.h \ IOKit/IOKitLib.h \ + IOKit/hid/IOHIDLib.h \ alias.h \ alsa/asoundlib.h \ arpa/inet.h \ diff --git a/dlls/dinput/Makefile.in b/dlls/dinput/Makefile.in index 79c81d82e84..16142efb8a2 100644 --- a/dlls/dinput/Makefile.in +++ b/dlls/dinput/Makefile.in @@ -5,6 +5,7 @@ VPATH = @srcdir@ MODULE = dinput.dll IMPORTLIB = dinput IMPORTS = dxguid uuid ole32 user32 advapi32 kernel32 +EXTRALIBS = @CARBONLIB@ @IOKITLIB@ C_SRCS = \ data_formats.c \ @@ -14,6 +15,7 @@ C_SRCS = \ joystick.c \ joystick_linux.c \ joystick_linuxinput.c \ + joystick_osx.c \ keyboard.c \ mouse.c \ regsvr.c diff --git a/dlls/dinput/dinput_main.c b/dlls/dinput/dinput_main.c index f89d5f060ef..f9ba1c650fa 100644 --- a/dlls/dinput/dinput_main.c +++ b/dlls/dinput/dinput_main.c @@ -79,7 +79,8 @@ static const struct dinput_device *dinput_devices[] = &mouse_device, &keyboard_device, &joystick_linuxinput_device, - &joystick_linux_device + &joystick_linux_device, + &joystick_osx_device }; #define NB_DINPUT_DEVICES (sizeof(dinput_devices)/sizeof(dinput_devices[0])) diff --git a/dlls/dinput/dinput_private.h b/dlls/dinput/dinput_private.h index 24fffb8e2ec..ddb9aa06bd1 100644 --- a/dlls/dinput/dinput_private.h +++ b/dlls/dinput/dinput_private.h @@ -58,6 +58,7 @@ extern const struct dinput_device mouse_device; extern const struct dinput_device keyboard_device; extern const struct dinput_device joystick_linux_device; extern const struct dinput_device joystick_linuxinput_device; +extern const struct dinput_device joystick_osx_device; extern void check_dinput_hooks(LPDIRECTINPUTDEVICE8A); typedef int (*DI_EVENT_PROC)(LPDIRECTINPUTDEVICE8A, WPARAM, LPARAM); diff --git a/dlls/dinput/joystick_osx.c b/dlls/dinput/joystick_osx.c new file mode 100644 index 00000000000..04af1e55042 --- /dev/null +++ b/dlls/dinput/joystick_osx.c @@ -0,0 +1,787 @@ +/* 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 +#include +#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_IOKIT_HID_IOHIDLIB_H + +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("Couldn’t 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) +{ + IOHIDDeviceRef tIOHIDDeviceRef; + CFArrayRef gElementCFArrayRef; + DWORD axes = 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; + } + 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; + 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; + 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; + + 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); + + get_osx_device_elements(newDevice); + + 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++) + { + memcpy(&df->rgodf[idx], &c_dfDIJoystick2.rgodf[i], df->dwObjSize); + df->rgodf[idx++].dwType = DIDFT_MAKEINSTANCE(i) | 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_IOKIT_HID_IOHIDLIB_H */ + +const struct dinput_device joystick_osx_device = { + "Wine OS X joystick driver", + NULL, + NULL, + NULL, + NULL +}; + +#endif /* HAVE_IOKIT_HID_IOHIDLIB_H */ diff --git a/include/config.h.in b/include/config.h.in index 2b7c655e4a9..3dec61e9150 100644 --- a/include/config.h.in +++ b/include/config.h.in @@ -255,6 +255,9 @@ /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H +/* Define to 1 if you have the header file. */ +#undef HAVE_IOKIT_HID_IOHIDLIB_H + /* Define to 1 if you have the header file. */ #undef HAVE_IOKIT_IOKITLIB_H