Implement new backend methods for haptic and hot plugging on OS X

This commit is contained in:
Edward Rudd 2014-02-04 18:17:16 -05:00
parent c9f6e4ec9f
commit b352698d99
4 changed files with 213 additions and 79 deletions

View File

@ -1083,6 +1083,7 @@
D55A1B7F179F262300625D7C /* SDL_cocoamousetap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_cocoamousetap.h; sourceTree = "<group>"; };
D55A1B80179F262300625D7C /* SDL_cocoamousetap.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDL_cocoamousetap.m; sourceTree = "<group>"; };
DB31407717554B71006C0E22 /* libSDL2.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libSDL2.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
DB89958518A1A5C50092407C /* SDL_syshaptic_c.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDL_syshaptic_c.h; sourceTree = "<group>"; };
F59C70FF00D5CB5801000001 /* ReadMe.txt */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = ReadMe.txt; sourceTree = "<group>"; };
F59C710000D5CB5801000001 /* Welcome.txt */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = Welcome.txt; sourceTree = "<group>"; };
F59C710300D5CB5801000001 /* ReadMe.txt */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = ReadMe.txt; sourceTree = "<group>"; };
@ -1401,6 +1402,7 @@
isa = PBXGroup;
children = (
04BDFDF312E6671700899322 /* SDL_syshaptic.c */,
DB89958518A1A5C50092407C /* SDL_syshaptic_c.h */,
);
path = darwin;
sourceTree = "<group>";

View File

@ -22,11 +22,13 @@
#ifdef SDL_HAPTIC_IOKIT
#include "SDL_assert.h"
#include "SDL_haptic.h"
#include "../SDL_syshaptic.h"
#include "SDL_joystick.h"
#include "../../joystick/SDL_sysjoystick.h" /* For the real SDL_Joystick */
#include "../../joystick/darwin/SDL_sysjoystick_c.h" /* For joystick hwdata */
#include "SDL_syshaptic_c.h"
#include <IOKit/IOKitLib.h>
#include <IOKit/hid/IOHIDKeys.h>
@ -38,13 +40,10 @@
#define IO_OBJECT_NULL ((io_service_t)0)
#endif
#define MAX_HAPTICS 32
/*
* List of available haptic devices.
*/
static struct
typedef struct SDL_hapticlist_item
{
char name[256]; /* Name of the device. */
@ -54,7 +53,9 @@ static struct
/* Usage pages for determining if it's a mouse or not. */
long usage;
long usagePage;
} SDL_hapticlist[MAX_HAPTICS];
struct SDL_hapticlist_item *next;
} SDL_hapticlist_item;
/*
@ -82,6 +83,9 @@ struct haptic_hweffect
static void SDL_SYS_HapticFreeFFEFFECT(FFEFFECT * effect, int type);
static int HIDGetDeviceProduct(io_service_t dev, char *name);
static SDL_hapticlist_item *SDL_hapticlist = NULL;
static SDL_hapticlist_item *SDL_hapticlist_tail = NULL;
static int numhaptics = 0;
/*
* Like strerror but for force feedback errors.
@ -146,16 +150,10 @@ FFStrError(HRESULT err)
int
SDL_SYS_HapticInit(void)
{
int numhaptics;
IOReturn result;
io_iterator_t iter;
CFDictionaryRef match;
io_service_t device;
CFMutableDictionaryRef hidProperties;
CFTypeRef refCF;
/* Clear all the memory. */
SDL_memset(SDL_hapticlist, 0, sizeof(SDL_hapticlist));
/* Get HID devices. */
match = IOServiceMatching(kIOHIDDeviceKey);
@ -174,62 +172,150 @@ SDL_SYS_HapticInit(void)
return 0;
}
numhaptics = 0;
while ((device = IOIteratorNext(iter)) != IO_OBJECT_NULL) {
/* Check for force feedback. */
if (FFIsForceFeedback(device) == FF_OK) {
/* Set basic device data. */
HIDGetDeviceProduct(device, SDL_hapticlist[numhaptics].name);
SDL_hapticlist[numhaptics].dev = device;
SDL_hapticlist[numhaptics].haptic = NULL;
/* Set usage pages. */
hidProperties = 0;
refCF = 0;
result = IORegistryEntryCreateCFProperties(device,
&hidProperties,
kCFAllocatorDefault,
kNilOptions);
if ((result == KERN_SUCCESS) && hidProperties) {
refCF =
CFDictionaryGetValue(hidProperties,
CFSTR(kIOHIDPrimaryUsagePageKey));
if (refCF) {
if (!CFNumberGetValue(refCF, kCFNumberLongType,
&SDL_hapticlist[numhaptics].
usagePage))
SDL_SetError
("Haptic: Recieving device's usage page.");
refCF =
CFDictionaryGetValue(hidProperties,
CFSTR(kIOHIDPrimaryUsageKey));
if (refCF) {
if (!CFNumberGetValue(refCF, kCFNumberLongType,
&SDL_hapticlist[numhaptics].
usage))
SDL_SetError("Haptic: Recieving device's usage.");
}
}
CFRelease(hidProperties);
}
/* Device has been added. */
numhaptics++;
} else { /* Free the unused device. */
IOObjectRelease(device);
}
/* Reached haptic limit. */
if (numhaptics >= MAX_HAPTICS)
break;
PRIVATE_MaybeAddDevice(device);
/* always release as the AddDevice will retain IF it's a forcefeedback device */
IOObjectRelease(device);
}
IOObjectRelease(iter);
return numhaptics;
}
int
SDL_SYS_NumHaptics()
{
return numhaptics;
}
static SDL_hapticlist_item *
HapticByDevIndex(int device_index)
{
SDL_hapticlist_item *item = SDL_hapticlist;
if ((device_index < 0) || (device_index >= numhaptics)) {
return NULL;
}
while (device_index > 0) {
SDL_assert(item != NULL);
device_index--;
item = item->next;
}
return item;
}
int
PRIVATE_MaybeAddDevice( io_object_t device )
{
IOReturn result;
CFMutableDictionaryRef hidProperties;
CFTypeRef refCF;
SDL_hapticlist_item *item;
/* Check for force feedback. */
if (FFIsForceFeedback(device) != FF_OK) {
return -1;
}
/* Make sure we don't already have it */
for (item = SDL_hapticlist; item ; item = item->next)
{
if (IOObjectIsEqualTo((io_object_t) item->dev, device)) {
/* Already added */
return -1;
}
}
item = (SDL_hapticlist_item *)SDL_malloc( sizeof(SDL_hapticlist_item));
if (item == NULL) {
return SDL_SetError("Could not allocate haptic storage");
}
/* retain it as we are going to keep it around a while */
IOObjectRetain(device);
/* Set basic device data. */
HIDGetDeviceProduct(device, item->name);
item->dev = device;
item->haptic = NULL;
/* Set usage pages. */
hidProperties = 0;
refCF = 0;
result = IORegistryEntryCreateCFProperties(device,
&hidProperties,
kCFAllocatorDefault,
kNilOptions);
if ((result == KERN_SUCCESS) && hidProperties) {
refCF =
CFDictionaryGetValue(hidProperties,
CFSTR(kIOHIDPrimaryUsagePageKey));
if (refCF) {
if (!CFNumberGetValue(refCF, kCFNumberLongType,
&item->usagePage))
SDL_SetError
("Haptic: Recieving device's usage page.");
refCF =
CFDictionaryGetValue(hidProperties,
CFSTR(kIOHIDPrimaryUsageKey));
if (refCF) {
if (!CFNumberGetValue(refCF, kCFNumberLongType,
&item->usage))
SDL_SetError("Haptic: Recieving device's usage.");
}
}
CFRelease(hidProperties);
}
if (SDL_hapticlist_tail == NULL) {
SDL_hapticlist = SDL_hapticlist_tail = item;
} else {
SDL_hapticlist_tail->next = item;
SDL_hapticlist_tail = item;
}
/* Device has been added. */
++numhaptics;
return numhaptics;
}
int
PRIVATE_MaybeRemoveDevice( io_object_t device )
{
SDL_hapticlist_item *item;
SDL_hapticlist_item *prev = NULL;
for (item = SDL_hapticlist; item != NULL; item = item->next) {
/* found it, remove it. */
if (IOObjectIsEqualTo((io_object_t) item->dev, device)) {
const int retval = item->haptic ? item->haptic->index : -1;
if (prev != NULL) {
prev->next = item->next;
} else {
SDL_assert(SDL_hapticlist == item);
SDL_hapticlist = item->next;
}
if (item == SDL_hapticlist_tail) {
SDL_hapticlist_tail = prev;
}
/* Need to decrement the haptic count */
--numhaptics;
/* !!! TODO: Send a haptic remove event? */
IOObjectRelease(item->dev);
SDL_free(item);
return retval;
}
prev = item;
}
return -1;
}
/*
* Return the name of a haptic device, does not need to be opened.
@ -237,7 +323,9 @@ SDL_SYS_HapticInit(void)
const char *
SDL_SYS_HapticName(int index)
{
return SDL_hapticlist[index].name;
SDL_hapticlist_item *item;
item = HapticByDevIndex(index);
return item->name;
}
/*
@ -470,8 +558,10 @@ SDL_SYS_HapticOpenFromService(SDL_Haptic * haptic, io_service_t service)
int
SDL_SYS_HapticOpen(SDL_Haptic * haptic)
{
return SDL_SYS_HapticOpenFromService(haptic,
SDL_hapticlist[haptic->index].dev);
SDL_hapticlist_item *item;
item = HapticByDevIndex(haptic->index);
return SDL_SYS_HapticOpenFromService(haptic, item->dev);
}
@ -481,12 +571,15 @@ SDL_SYS_HapticOpen(SDL_Haptic * haptic)
int
SDL_SYS_HapticMouse(void)
{
int i;
int device_index = 0;
SDL_hapticlist_item *item;
for (i = 0; i < SDL_numhaptics; i++) {
if ((SDL_hapticlist[i].usagePage == kHIDPage_GenericDesktop) &&
(SDL_hapticlist[i].usage == kHIDUsage_GD_Mouse))
return i;
for (item = SDL_hapticlist; item; item = item->next) {
if ((item->usagePage == kHIDPage_GenericDesktop) &&
(item->usage == kHIDUsage_GD_Mouse))
return device_index;
++device_index;
}
return -1;
@ -524,16 +617,16 @@ SDL_SYS_JoystickSameHaptic(SDL_Haptic * haptic, SDL_Joystick * joystick)
int
SDL_SYS_HapticOpenFromJoystick(SDL_Haptic * haptic, SDL_Joystick * joystick)
{
int i;
for (i=0; i<SDL_numhaptics; i++) {
if (IOObjectIsEqualTo((io_object_t) SDL_hapticlist[i].dev,
int device_index = 0;
SDL_hapticlist_item *item;
for (item = SDL_hapticlist; item; item = item->next) {
if (IOObjectIsEqualTo((io_object_t) item->dev,
joystick->hwdata->ffservice)) {
haptic->index = i;
haptic->index = device_index;
break;
}
}
if (i >= SDL_numhaptics) {
return -1;
}
++device_index;
}
return SDL_SYS_HapticOpenFromService(haptic, joystick->hwdata->ffservice);
@ -569,15 +662,18 @@ SDL_SYS_HapticClose(SDL_Haptic * haptic)
void
SDL_SYS_HapticQuit(void)
{
int i;
SDL_hapticlist_item *item;
SDL_hapticlist_item *next = NULL;
for (i = 0; i < SDL_numhaptics; i++) {
for (item = SDL_hapticlist; item; item = next) {
next = item->next;
/* Opened and not closed haptics are leaked, this is on purpose.
* Close your haptic devices after usage. */
/* Free the io_service_t */
IOObjectRelease(SDL_hapticlist[i].dev);
IOObjectRelease(item->dev);
}
numhaptics = 0;
}

View File

@ -0,0 +1,26 @@
/*
Simple DirectMedia Layer
Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
int
PRIVATE_MaybeAddDevice( io_object_t device );
int
PRIVATE_MaybeRemoveDevice( io_object_t device );

View File

@ -48,6 +48,7 @@
#include "../SDL_joystick_c.h"
#include "SDL_sysjoystick_c.h"
#include "SDL_events.h"
#include "../../haptic/darwin/SDL_syshaptic_c.h" /* For haptic hot plugging */
#if !SDL_EVENTS_DISABLED
#include "../../events/SDL_events_c.h"
#endif
@ -122,6 +123,9 @@ HIDRemovalCallback(void *target, IOReturn result, void *refcon, void *sender)
{
recDevice *device = (recDevice *) refcon;
device->removed = 1;
#if SDL_HAPTIC_IOKIT
PRIVATE_MaybeRemoveDevice(device->ffservice);
#endif
s_bDeviceRemoved = SDL_TRUE;
}
@ -134,6 +138,9 @@ void JoystickDeviceWasRemovedCallback( void * refcon, io_service_t service, natu
{
recDevice *device = (recDevice *) refcon;
device->removed = 1;
#if SDL_HAPTIC_IOKIT
PRIVATE_MaybeRemoveDevice(device->ffservice);
#endif
s_bDeviceRemoved = SDL_TRUE;
}
}
@ -679,6 +686,9 @@ AddDeviceHelper( io_object_t ioHIDDeviceObject )
* SDL_HapticOpenFromJoystick */
if (FFIsForceFeedback(ioHIDDeviceObject) == FF_OK) {
device->ffservice = ioHIDDeviceObject;
#if SDL_HAPTIC_IOKIT
PRIVATE_MaybeAddDevice(ioHIDDeviceObject);
#endif
} else {
device->ffservice = 0;
}