winejoystick: Add WinMM joystick support for OS X.
This commit is contained in:
parent
01227ab267
commit
65711634ce
|
@ -13684,7 +13684,7 @@ fi
|
|||
test -n "$ALSA_LIBS" || enable_winealsa_drv=${enable_winealsa_drv:-no}
|
||||
test -n "$COREAUDIO_LIBS" || enable_winecoreaudio_drv=${enable_winecoreaudio_drv:-no}
|
||||
test "x$ac_cv_member_oss_sysinfo_numaudioengines" = xyes || enable_wineoss_drv=${enable_wineoss_drv:-no}
|
||||
test "$ac_cv_header_linux_joystick_h" = "yes" || enable_winejoystick_drv=${enable_winejoystick_drv:-no}
|
||||
test "$ac_cv_header_linux_joystick_h" = "yes" -o "$ac_cv_header_IOKit_hid_IOHIDLib_h" = "yes" || enable_winejoystick_drv=${enable_winejoystick_drv:-no}
|
||||
|
||||
if test "x$ALSA_LIBS$COREAUDIO_LIBS" = "x" -a \
|
||||
"x$ac_cv_member_oss_sysinfo_numaudioengines" != xyes -a \
|
||||
|
|
|
@ -1767,7 +1767,7 @@ dnl **** Disable unsupported winmm drivers ****
|
|||
test -n "$ALSA_LIBS" || enable_winealsa_drv=${enable_winealsa_drv:-no}
|
||||
test -n "$COREAUDIO_LIBS" || enable_winecoreaudio_drv=${enable_winecoreaudio_drv:-no}
|
||||
test "x$ac_cv_member_oss_sysinfo_numaudioengines" = xyes || enable_wineoss_drv=${enable_wineoss_drv:-no}
|
||||
test "$ac_cv_header_linux_joystick_h" = "yes" || enable_winejoystick_drv=${enable_winejoystick_drv:-no}
|
||||
test "$ac_cv_header_linux_joystick_h" = "yes" -o "$ac_cv_header_IOKit_hid_IOHIDLib_h" = "yes" || enable_winejoystick_drv=${enable_winejoystick_drv:-no}
|
||||
|
||||
dnl **** Check for any sound system ****
|
||||
if test "x$ALSA_LIBS$COREAUDIO_LIBS" = "x" -a \
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
MODULE = winejoystick.drv
|
||||
IMPORTS = winmm user32
|
||||
EXTRALIBS = $(IOKIT_LIBS)
|
||||
|
||||
C_SRCS = \
|
||||
joystick.c \
|
||||
joystick_linux.c
|
||||
joystick_linux.c \
|
||||
joystick_osx.c
|
||||
|
|
|
@ -0,0 +1,754 @@
|
|||
/*
|
||||
* WinMM joystick driver OS X implementation
|
||||
*
|
||||
* Copyright 1997 Andreas Mohr
|
||||
* Copyright 1998 Marcus Meissner
|
||||
* Copyright 1998,1999 Lionel Ulmer
|
||||
* Copyright 2000 Wolfgang Schwotzer
|
||||
* Copyright 2000-2001 TransGaming Technologies Inc.
|
||||
* Copyright 2002 David Hagood
|
||||
* Copyright 2009 CodeWeavers, Aric Stewart
|
||||
* Copyright 2015 Ken Thomases for CodeWeavers Inc.
|
||||
*
|
||||
* 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"
|
||||
|
||||
#if defined(HAVE_IOKIT_HID_IOHIDLIB_H)
|
||||
|
||||
#define DWORD UInt32
|
||||
#define LPDWORD UInt32*
|
||||
#define LONG SInt32
|
||||
#define LPLONG SInt32*
|
||||
#define E_PENDING __carbon_E_PENDING
|
||||
#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 <IOKit/IOKitLib.h>
|
||||
#include <IOKit/hid/IOHIDLib.h>
|
||||
#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
|
||||
#undef DWORD
|
||||
#undef LPDWORD
|
||||
#undef LONG
|
||||
#undef LPLONG
|
||||
#undef E_PENDING
|
||||
|
||||
#include "joystick.h"
|
||||
|
||||
#include "wine/debug.h"
|
||||
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(joystick);
|
||||
|
||||
|
||||
#define MAXJOYSTICK (JOYSTICKID2 + 30)
|
||||
|
||||
|
||||
enum {
|
||||
AXIS_X,
|
||||
AXIS_Y,
|
||||
AXIS_Z,
|
||||
AXIS_RX,
|
||||
AXIS_RY,
|
||||
AXIS_RZ,
|
||||
NUM_AXES
|
||||
};
|
||||
|
||||
struct axis {
|
||||
IOHIDElementRef element;
|
||||
CFIndex min_value, max_value;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
BOOL in_use;
|
||||
IOHIDElementRef element;
|
||||
struct axis axes[NUM_AXES];
|
||||
CFMutableArrayRef buttons;
|
||||
IOHIDElementRef hatswitch;
|
||||
} joystick_t;
|
||||
|
||||
|
||||
static joystick_t joysticks[MAXJOYSTICK];
|
||||
static CFMutableArrayRef device_main_elements = NULL;
|
||||
|
||||
|
||||
static const char* debugstr_cf(CFTypeRef t)
|
||||
{
|
||||
CFStringRef s;
|
||||
const char* ret;
|
||||
|
||||
if (!t) return "(null)";
|
||||
|
||||
if (CFGetTypeID(t) == CFStringGetTypeID())
|
||||
s = t;
|
||||
else
|
||||
s = CFCopyDescription(t);
|
||||
ret = CFStringGetCStringPtr(s, kCFStringEncodingUTF8);
|
||||
if (ret) ret = debugstr_a(ret);
|
||||
if (!ret)
|
||||
{
|
||||
const UniChar* u = CFStringGetCharactersPtr(s);
|
||||
if (u)
|
||||
ret = debugstr_wn((const WCHAR*)u, CFStringGetLength(s));
|
||||
}
|
||||
if (!ret)
|
||||
{
|
||||
UniChar buf[200];
|
||||
int len = min(CFStringGetLength(s), sizeof(buf)/sizeof(buf[0]));
|
||||
CFStringGetCharacters(s, CFRangeMake(0, len), buf);
|
||||
ret = debugstr_wn(buf, len);
|
||||
}
|
||||
if (s != t) CFRelease(s);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const char* debugstr_device(IOHIDDeviceRef device)
|
||||
{
|
||||
return wine_dbg_sprintf("<IOHIDDevice %p product %s>", device,
|
||||
debugstr_cf(IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductKey))));
|
||||
}
|
||||
|
||||
static const char* debugstr_element(IOHIDElementRef element)
|
||||
{
|
||||
return wine_dbg_sprintf("<IOHIDElement %p type %d usage %u/%u device %p>", element,
|
||||
IOHIDElementGetType(element), IOHIDElementGetUsagePage(element),
|
||||
IOHIDElementGetUsage(element), IOHIDElementGetDevice(element));
|
||||
}
|
||||
|
||||
|
||||
static int axis_for_usage(int usage)
|
||||
{
|
||||
switch (usage)
|
||||
{
|
||||
case kHIDUsage_GD_X: return AXIS_X;
|
||||
case kHIDUsage_GD_Y: return AXIS_Y;
|
||||
case kHIDUsage_GD_Z: return AXIS_Z;
|
||||
case kHIDUsage_GD_Rx: return AXIS_RX;
|
||||
case kHIDUsage_GD_Ry: return AXIS_RY;
|
||||
case kHIDUsage_GD_Rz: return AXIS_RZ;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* joystick_from_id
|
||||
*/
|
||||
static joystick_t* joystick_from_id(DWORD_PTR device_id)
|
||||
{
|
||||
int index;
|
||||
|
||||
if ((device_id - (DWORD_PTR)joysticks) % sizeof(joysticks[0]) != 0)
|
||||
return NULL;
|
||||
index = (device_id - (DWORD_PTR)joysticks) / sizeof(joysticks[0]);
|
||||
if (index < 0 || index >= MAXJOYSTICK || !((joystick_t*)device_id)->in_use)
|
||||
return NULL;
|
||||
|
||||
return (joystick_t*)device_id;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* create_osx_device_match
|
||||
*/
|
||||
static CFDictionaryRef create_osx_device_match(int usage)
|
||||
{
|
||||
CFDictionaryRef result = NULL;
|
||||
int number;
|
||||
CFStringRef keys[] = { CFSTR(kIOHIDDeviceUsagePageKey), CFSTR(kIOHIDDeviceUsageKey) };
|
||||
CFNumberRef values[2];
|
||||
int i;
|
||||
|
||||
TRACE("usage %d\n", usage);
|
||||
|
||||
number = kHIDPage_GenericDesktop;
|
||||
values[0] = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &number);
|
||||
values[1] = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &usage);
|
||||
|
||||
if (values[0] && values[1])
|
||||
{
|
||||
result = CFDictionaryCreate(NULL, (const void**)keys, (const void**)values, sizeof(values) / sizeof(values[0]),
|
||||
&kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
|
||||
|
||||
if (!result)
|
||||
ERR("CFDictionaryCreate failed.\n");
|
||||
}
|
||||
else
|
||||
ERR("CFNumberCreate failed.\n");
|
||||
|
||||
for (i = 0; i < sizeof(values) / sizeof(values[0]); i++)
|
||||
if (values[i]) CFRelease(values[i]);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* find_top_level
|
||||
*/
|
||||
static CFIndex find_top_level(IOHIDDeviceRef hid_device, CFMutableArrayRef main_elements)
|
||||
{
|
||||
CFArrayRef elements;
|
||||
CFIndex total = 0;
|
||||
|
||||
TRACE("hid_device %s\n", debugstr_device(hid_device));
|
||||
|
||||
if (!hid_device)
|
||||
return 0;
|
||||
|
||||
elements = IOHIDDeviceCopyMatchingElements(hid_device, NULL, 0);
|
||||
|
||||
if (elements)
|
||||
{
|
||||
CFIndex i, count = CFArrayGetCount(elements);
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
IOHIDElementRef element = (IOHIDElementRef)CFArrayGetValueAtIndex(elements, i);
|
||||
int type = IOHIDElementGetType(element);
|
||||
|
||||
TRACE("element %s\n", debugstr_element(element));
|
||||
|
||||
/* Check for top-level gaming device collections */
|
||||
if (type == kIOHIDElementTypeCollection && IOHIDElementGetParent(element) == 0)
|
||||
{
|
||||
int usage_page = IOHIDElementGetUsagePage(element);
|
||||
int usage = IOHIDElementGetUsage(element);
|
||||
|
||||
if (usage_page == kHIDPage_GenericDesktop &&
|
||||
(usage == kHIDUsage_GD_Joystick || usage == kHIDUsage_GD_GamePad))
|
||||
{
|
||||
CFArrayAppendValue(main_elements, element);
|
||||
total++;
|
||||
}
|
||||
}
|
||||
}
|
||||
CFRelease(elements);
|
||||
}
|
||||
|
||||
TRACE("-> total %d\n", (int)total);
|
||||
return total;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* find_osx_devices
|
||||
*/
|
||||
static int find_osx_devices(void)
|
||||
{
|
||||
IOHIDManagerRef hid_manager;
|
||||
int usages[] = { kHIDUsage_GD_Joystick, kHIDUsage_GD_GamePad };
|
||||
int i;
|
||||
CFDictionaryRef matching_dicts[sizeof(usages) / sizeof(usages[0])];
|
||||
CFArrayRef matching;
|
||||
CFSetRef devset;
|
||||
|
||||
TRACE("()\n");
|
||||
|
||||
hid_manager = IOHIDManagerCreate(kCFAllocatorDefault, 0L);
|
||||
if (IOHIDManagerOpen(hid_manager, 0) != kIOReturnSuccess)
|
||||
{
|
||||
ERR("Couldn't open IOHIDManager.\n");
|
||||
CFRelease(hid_manager);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < sizeof(matching_dicts) / sizeof(matching_dicts[0]); i++)
|
||||
{
|
||||
matching_dicts[i] = create_osx_device_match(usages[i]);
|
||||
if (!matching_dicts[i])
|
||||
{
|
||||
while (i > 0)
|
||||
CFRelease(matching_dicts[--i]);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
matching = CFArrayCreate(NULL, (const void**)matching_dicts, sizeof(matching_dicts) / sizeof(matching_dicts[0]),
|
||||
&kCFTypeArrayCallBacks);
|
||||
|
||||
for (i = 0; i < sizeof(matching_dicts) / sizeof(matching_dicts[0]); i++)
|
||||
CFRelease(matching_dicts[i]);
|
||||
|
||||
IOHIDManagerSetDeviceMatchingMultiple(hid_manager, matching);
|
||||
CFRelease(matching);
|
||||
devset = IOHIDManagerCopyDevices(hid_manager);
|
||||
if (devset)
|
||||
{
|
||||
CFIndex num_devices, num_main_elements;
|
||||
const void** refs;
|
||||
CFArrayRef devices;
|
||||
|
||||
num_devices = CFSetGetCount(devset);
|
||||
refs = HeapAlloc(GetProcessHeap(), 0, num_devices * sizeof(*refs));
|
||||
if (!refs)
|
||||
{
|
||||
CFRelease(devset);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
CFSetGetValues(devset, refs);
|
||||
devices = CFArrayCreate(NULL, refs, num_devices, &kCFTypeArrayCallBacks);
|
||||
HeapFree(GetProcessHeap(), 0, refs);
|
||||
CFRelease(devset);
|
||||
if (!devices)
|
||||
goto fail;
|
||||
|
||||
device_main_elements = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
|
||||
if (!device_main_elements)
|
||||
{
|
||||
CFRelease(devices);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
num_main_elements = 0;
|
||||
for (i = 0; i < num_devices; i++)
|
||||
{
|
||||
IOHIDDeviceRef hid_device = (IOHIDDeviceRef)CFArrayGetValueAtIndex(devices, i);
|
||||
TRACE("hid_device %s\n", debugstr_device(hid_device));
|
||||
num_main_elements += find_top_level(hid_device, device_main_elements);
|
||||
}
|
||||
|
||||
CFRelease(devices);
|
||||
|
||||
TRACE("found %i device(s), %i collection(s)\n",(int)num_devices,(int)num_main_elements);
|
||||
return (int)num_main_elements;
|
||||
}
|
||||
|
||||
fail:
|
||||
IOHIDManagerClose(hid_manager, 0);
|
||||
CFRelease(hid_manager);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* collect_joystick_elements
|
||||
*/
|
||||
static void collect_joystick_elements(joystick_t* joystick, IOHIDElementRef collection)
|
||||
{
|
||||
CFIndex i, count;
|
||||
CFArrayRef children = IOHIDElementGetChildren(collection);
|
||||
|
||||
TRACE("collection %s\n", debugstr_element(collection));
|
||||
|
||||
count = CFArrayGetCount(children);
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
IOHIDElementRef child;
|
||||
int type;
|
||||
|
||||
child = (IOHIDElementRef)CFArrayGetValueAtIndex(children, i);
|
||||
TRACE("child %s\n", debugstr_element(child));
|
||||
type = IOHIDElementGetType(child);
|
||||
switch (type)
|
||||
{
|
||||
case kIOHIDElementTypeCollection:
|
||||
collect_joystick_elements(joystick, child);
|
||||
break;
|
||||
case kIOHIDElementTypeInput_Button:
|
||||
{
|
||||
int usage_page = IOHIDElementGetUsagePage(child);
|
||||
|
||||
TRACE("kIOHIDElementTypeInput_Button usage_page %d\n", usage_page);
|
||||
|
||||
/* avoid strange elements found on the 360 controller */
|
||||
if (usage_page == kHIDPage_Button)
|
||||
CFArrayAppendValue(joystick->buttons, child);
|
||||
break;
|
||||
}
|
||||
case kIOHIDElementTypeInput_Axis:
|
||||
{
|
||||
TRACE("kIOHIDElementTypeInput_Axis; ignoring\n");
|
||||
break;
|
||||
}
|
||||
case kIOHIDElementTypeInput_Misc:
|
||||
{
|
||||
uint32_t usage = IOHIDElementGetUsage( child );
|
||||
switch(usage)
|
||||
{
|
||||
case kHIDUsage_GD_Hatswitch:
|
||||
{
|
||||
TRACE("kIOHIDElementTypeInput_Misc / kHIDUsage_GD_Hatswitch\n");
|
||||
if (joystick->hatswitch)
|
||||
TRACE(" ignoring additional hatswitch\n");
|
||||
else
|
||||
joystick->hatswitch = (IOHIDElementRef)CFRetain(child);
|
||||
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:
|
||||
{
|
||||
int axis = axis_for_usage(usage);
|
||||
TRACE("kIOHIDElementTypeInput_Misc / kHIDUsage_GD_<axis> (%d) axis %d\n", usage, axis);
|
||||
if (axis < 0 || joystick->axes[axis].element)
|
||||
TRACE(" ignoring\n");
|
||||
else
|
||||
{
|
||||
joystick->axes[axis].element = (IOHIDElementRef)CFRetain(child);
|
||||
joystick->axes[axis].min_value = IOHIDElementGetLogicalMin(child);
|
||||
joystick->axes[axis].max_value = IOHIDElementGetLogicalMax(child);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kHIDUsage_GD_Slider:
|
||||
TRACE("kIOHIDElementTypeInput_Misc / kHIDUsage_GD_Slider; ignoring\n");
|
||||
break;
|
||||
default:
|
||||
FIXME("kIOHIDElementTypeInput_Misc / Unhandled usage %d\n", usage);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
FIXME("Unhandled type %i\n",type);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* button_usage_comparator
|
||||
*/
|
||||
static CFComparisonResult button_usage_comparator(const void *val1, const void *val2, void *context)
|
||||
{
|
||||
IOHIDElementRef element1 = (IOHIDElementRef)val1, element2 = (IOHIDElementRef)val2;
|
||||
int usage1 = IOHIDElementGetUsage(element1), usage2 = IOHIDElementGetUsage(element2);
|
||||
|
||||
if (usage1 < usage2)
|
||||
return kCFCompareLessThan;
|
||||
if (usage1 > usage2)
|
||||
return kCFCompareGreaterThan;
|
||||
return kCFCompareEqualTo;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* driver_open
|
||||
*/
|
||||
LRESULT driver_open(LPSTR str, DWORD index)
|
||||
{
|
||||
if (index >= MAXJOYSTICK || joysticks[index].in_use)
|
||||
return 0;
|
||||
|
||||
joysticks[index].in_use = TRUE;
|
||||
return (LRESULT)&joysticks[index];
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* driver_close
|
||||
*/
|
||||
LRESULT driver_close(DWORD_PTR device_id)
|
||||
{
|
||||
joystick_t* joystick = joystick_from_id(device_id);
|
||||
int i;
|
||||
|
||||
if (joystick == NULL)
|
||||
return 0;
|
||||
|
||||
CFRelease(joystick->element);
|
||||
for (i = 0; i < NUM_AXES; i++)
|
||||
{
|
||||
if (joystick->axes[i].element)
|
||||
CFRelease(joystick->axes[i].element);
|
||||
}
|
||||
if (joystick->buttons)
|
||||
CFRelease(joystick->buttons);
|
||||
if (joystick->hatswitch)
|
||||
CFRelease(joystick->hatswitch);
|
||||
|
||||
memset(joystick, 0, sizeof(*joystick));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* open_joystick
|
||||
*/
|
||||
static BOOL open_joystick(joystick_t* joystick)
|
||||
{
|
||||
CFIndex index;
|
||||
CFRange range;
|
||||
|
||||
if (joystick->element)
|
||||
return TRUE;
|
||||
|
||||
if (!device_main_elements)
|
||||
{
|
||||
find_osx_devices();
|
||||
if (!device_main_elements)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
index = joystick - joysticks;
|
||||
if (index > CFArrayGetCount(device_main_elements))
|
||||
return FALSE;
|
||||
|
||||
joystick->element = (IOHIDElementRef)CFArrayGetValueAtIndex(device_main_elements, index);
|
||||
joystick->buttons = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
|
||||
collect_joystick_elements(joystick, joystick->element);
|
||||
|
||||
/* Sort buttons into correct order */
|
||||
range.location = 0;
|
||||
range.length = CFArrayGetCount(joystick->buttons);
|
||||
CFArraySortValues(joystick->buttons, range, button_usage_comparator, NULL);
|
||||
if (range.length > 32)
|
||||
{
|
||||
/* Delete any buttons beyond the first 32 */
|
||||
range.location = 32;
|
||||
range.length -= 32;
|
||||
CFArrayReplaceValues(joystick->buttons, range, NULL, 0);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* driver_joyGetDevCaps
|
||||
*/
|
||||
LRESULT driver_joyGetDevCaps(DWORD_PTR device_id, JOYCAPSW* caps, DWORD size)
|
||||
{
|
||||
joystick_t* joystick;
|
||||
IOHIDDeviceRef device;
|
||||
|
||||
if ((joystick = joystick_from_id(device_id)) == NULL)
|
||||
return MMSYSERR_NODRIVER;
|
||||
|
||||
if (!open_joystick(joystick))
|
||||
return JOYERR_PARMS;
|
||||
|
||||
caps->szPname[0] = 0;
|
||||
|
||||
device = IOHIDElementGetDevice(joystick->element);
|
||||
if (device)
|
||||
{
|
||||
CFStringRef product_name = IOHIDDeviceGetProperty(device, CFSTR(kIOHIDProductKey));
|
||||
if (product_name)
|
||||
{
|
||||
CFRange range;
|
||||
|
||||
range.location = 0;
|
||||
range.length = min(MAXPNAMELEN - 1, CFStringGetLength(product_name));
|
||||
CFStringGetCharacters(product_name, range, (UniChar*)caps->szPname);
|
||||
caps->szPname[range.length] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
caps->wMid = MM_MICROSOFT;
|
||||
caps->wPid = MM_PC_JOYSTICK;
|
||||
caps->wXmin = 0;
|
||||
caps->wXmax = 0xFFFF;
|
||||
caps->wYmin = 0;
|
||||
caps->wYmax = 0xFFFF;
|
||||
caps->wZmin = 0;
|
||||
caps->wZmax = joystick->axes[AXIS_Z].element ? 0xFFFF : 0;
|
||||
caps->wNumButtons = CFArrayGetCount(joystick->buttons);
|
||||
if (size == sizeof(JOYCAPSW))
|
||||
{
|
||||
int i;
|
||||
|
||||
/* complete 95 structure */
|
||||
caps->wRmin = 0;
|
||||
caps->wRmax = 0xFFFF;
|
||||
caps->wUmin = 0;
|
||||
caps->wUmax = 0xFFFF;
|
||||
caps->wVmin = 0;
|
||||
caps->wVmax = 0xFFFF;
|
||||
caps->wMaxAxes = 6; /* same as MS Joystick Driver */
|
||||
caps->wNumAxes = 0;
|
||||
caps->wMaxButtons = 32; /* same as MS Joystick Driver */
|
||||
caps->szRegKey[0] = 0;
|
||||
caps->szOEMVxD[0] = 0;
|
||||
caps->wCaps = 0;
|
||||
|
||||
for (i = 0; i < NUM_AXES; i++)
|
||||
{
|
||||
if (joystick->axes[i].element)
|
||||
{
|
||||
caps->wNumAxes++;
|
||||
switch (i)
|
||||
{
|
||||
case AXIS_Z: caps->wCaps |= JOYCAPS_HASZ; break;
|
||||
case AXIS_RX: caps->wCaps |= JOYCAPS_HASU; break;
|
||||
case AXIS_RY: caps->wCaps |= JOYCAPS_HASV; break;
|
||||
case AXIS_RZ: caps->wCaps |= JOYCAPS_HASR; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (joystick->hatswitch)
|
||||
caps->wCaps |= JOYCAPS_HASPOV | JOYCAPS_POV4DIR;
|
||||
}
|
||||
|
||||
TRACE("name %s buttons %u axes %d caps 0x%08x\n", debugstr_w(caps->szPname), caps->wNumButtons, caps->wNumAxes, caps->wCaps);
|
||||
|
||||
return JOYERR_NOERROR;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* driver_joyGetPosEx
|
||||
*/
|
||||
LRESULT driver_joyGetPosEx(DWORD_PTR device_id, JOYINFOEX* info)
|
||||
{
|
||||
static const struct {
|
||||
DWORD flag;
|
||||
off_t offset;
|
||||
} axis_map[NUM_AXES] = {
|
||||
{ JOY_RETURNX, FIELD_OFFSET(JOYINFOEX, dwXpos) },
|
||||
{ JOY_RETURNY, FIELD_OFFSET(JOYINFOEX, dwYpos) },
|
||||
{ JOY_RETURNZ, FIELD_OFFSET(JOYINFOEX, dwZpos) },
|
||||
{ JOY_RETURNU, FIELD_OFFSET(JOYINFOEX, dwUpos) },
|
||||
{ JOY_RETURNV, FIELD_OFFSET(JOYINFOEX, dwVpos) },
|
||||
{ JOY_RETURNR, FIELD_OFFSET(JOYINFOEX, dwRpos) },
|
||||
};
|
||||
|
||||
joystick_t* joystick;
|
||||
IOHIDDeviceRef device;
|
||||
CFIndex i, count;
|
||||
IOHIDValueRef valueRef;
|
||||
long value;
|
||||
|
||||
if ((joystick = joystick_from_id(device_id)) == NULL)
|
||||
return MMSYSERR_NODRIVER;
|
||||
|
||||
if (!open_joystick(joystick))
|
||||
return JOYERR_PARMS;
|
||||
|
||||
device = IOHIDElementGetDevice(joystick->element);
|
||||
|
||||
if (info->dwFlags & JOY_RETURNBUTTONS)
|
||||
{
|
||||
info->dwButtons = 0;
|
||||
info->dwButtonNumber = 0;
|
||||
|
||||
count = CFArrayGetCount(joystick->buttons);
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
IOHIDElementRef button = (IOHIDElementRef)CFArrayGetValueAtIndex(joystick->buttons, i);
|
||||
IOHIDDeviceGetValue(device, button, &valueRef);
|
||||
value = IOHIDValueGetIntegerValue(valueRef);
|
||||
if (value)
|
||||
{
|
||||
info->dwButtons |= 1 << i;
|
||||
if (!info->dwButtonNumber)
|
||||
info->dwButtonNumber = i + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < NUM_AXES; i++)
|
||||
{
|
||||
if (info->dwFlags & axis_map[i].flag)
|
||||
{
|
||||
DWORD* field = (DWORD*)((char*)info + axis_map[i].offset);
|
||||
if (joystick->axes[i].element)
|
||||
{
|
||||
IOHIDDeviceGetValue(device, joystick->axes[i].element, &valueRef);
|
||||
value = IOHIDValueGetIntegerValue(valueRef) - joystick->axes[i].min_value;
|
||||
*field = MulDiv(value, 0xFFFF, joystick->axes[i].max_value - joystick->axes[i].min_value);
|
||||
}
|
||||
else
|
||||
{
|
||||
*field = 0;
|
||||
info->dwFlags &= ~axis_map[i].flag;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (info->dwFlags & JOY_RETURNPOV)
|
||||
{
|
||||
if (joystick->hatswitch)
|
||||
{
|
||||
IOHIDDeviceGetValue(device, joystick->hatswitch, &valueRef);
|
||||
value = IOHIDValueGetIntegerValue(valueRef);
|
||||
if (value >= 8)
|
||||
info->dwPOV = JOY_POVCENTERED;
|
||||
else
|
||||
info->dwPOV = value * 4500;
|
||||
}
|
||||
else
|
||||
{
|
||||
info->dwPOV = 0;
|
||||
info->dwFlags &= ~JOY_RETURNPOV;
|
||||
}
|
||||
}
|
||||
|
||||
TRACE("x: %d, y: %d, z: %d, r: %d, u: %d, v: %d, buttons: 0x%04x, pov %d, flags: 0x%04x\n",
|
||||
info->dwXpos, info->dwYpos, info->dwZpos, info->dwRpos, info->dwUpos, info->dwVpos, info->dwButtons, info->dwPOV, info->dwFlags);
|
||||
|
||||
return JOYERR_NOERROR;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* driver_joyGetPos
|
||||
*/
|
||||
LRESULT driver_joyGetPos(DWORD_PTR device_id, JOYINFO* info)
|
||||
{
|
||||
JOYINFOEX ji;
|
||||
LONG ret;
|
||||
|
||||
memset(&ji, 0, sizeof(ji));
|
||||
|
||||
ji.dwSize = sizeof(ji);
|
||||
ji.dwFlags = JOY_RETURNX | JOY_RETURNY | JOY_RETURNZ | JOY_RETURNBUTTONS;
|
||||
ret = driver_joyGetPosEx(device_id, &ji);
|
||||
if (ret == JOYERR_NOERROR)
|
||||
{
|
||||
info->wXpos = ji.dwXpos;
|
||||
info->wYpos = ji.dwYpos;
|
||||
info->wZpos = ji.dwZpos;
|
||||
info->wButtons = ji.dwButtons;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* HAVE_IOKIT_HID_IOHIDLIB_H */
|
Loading…
Reference in New Issue