apple2ix/Apple2Mac/DDHidLib/lib/DDHidJoystick.m

655 lines
18 KiB
Objective-C

/*
* Copyright (c) 2007 Dave Dribin
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use, copy,
* modify, merge, publish, distribute, sublicense, and/or sell copies
* of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#import "DDHidLib.h"
#include <IOKit/hid/IOHIDUsageTables.h>
@interface DDHidJoystick (DDHidJoystickDelegate)
- (void) ddhidJoystick: (DDHidJoystick *) joystick
stick: (unsigned) stick
xChanged: (int) value;
- (void) ddhidJoystick: (DDHidJoystick *) joystick
stick: (unsigned) stick
yChanged: (int) value;
- (void) ddhidJoystick: (DDHidJoystick *) joystick
stick: (unsigned) stick
otherAxis: (unsigned) otherAxis
valueChanged: (int) value;
- (void) ddhidJoystick: (DDHidJoystick *) joystick
stick: (unsigned) stick
povNumber: (unsigned) povNumber
valueChanged: (int) value;
- (void) ddhidJoystick: (DDHidJoystick *) joystick
buttonDown: (unsigned) buttonNumber;
- (void) ddhidJoystick: (DDHidJoystick *) joystick
buttonUp: (unsigned) buttonNumber;
@end
@interface DDHidJoystick (Private)
- (void) initLogicalDeviceElements;
- (void) initJoystickElements: (NSArray *) elements;
- (void) addStick: (NSArray *) stickElements;
- (void) ddhidQueueHasEvents: (DDHidQueue *) hidQueue;
- (int) normalizeValue: (int) value
forElement: (DDHidElement *) element;
- (int) povValue: (int) value
forElement: (DDHidElement *) element;
- (BOOL) findStick: (unsigned *) stick
element: (DDHidElement **) elementOut
withXAxisCookie: (IOHIDElementCookie) cookie;
- (BOOL) findStick: (unsigned *) stick
element: (DDHidElement **) elementOut
withYAxisCookie: (IOHIDElementCookie) cookie;
- (BOOL) findStick: (unsigned *) stickOut
otherAxis: (unsigned *) axisOut
element: (DDHidElement **) elementOut
withCookie: (IOHIDElementCookie) cookie;
- (BOOL) findStick: (unsigned *) stickOut
povNumber: (unsigned *) povNumber
element: (DDHidElement **) elementOut
withCookie: (IOHIDElementCookie) cookie;
@end
@implementation DDHidJoystick
+ (NSArray *) allJoysticks;
{
NSArray * joysticks =
[DDHidDevice allDevicesMatchingUsagePage: kHIDPage_GenericDesktop
usageId: kHIDUsage_GD_Joystick
withClass: self
skipZeroLocations: YES];
NSArray * gamepads =
[DDHidDevice allDevicesMatchingUsagePage: kHIDPage_GenericDesktop
usageId: kHIDUsage_GD_GamePad
withClass: self
skipZeroLocations: YES];
NSMutableArray * allJoysticks = [NSMutableArray arrayWithArray: joysticks];
[allJoysticks addObjectsFromArray: gamepads];
[allJoysticks sortUsingSelector: @selector(compareByLocationId:)];
return allJoysticks;
}
- (id) initLogicalWithDevice: (io_object_t) device
logicalDeviceNumber: (int) logicalDeviceNumber
error: (NSError **) error;
{
self = [super initLogicalWithDevice: device
logicalDeviceNumber: logicalDeviceNumber
error: error];
if (self == nil)
return nil;
mButtonElements = [[NSMutableArray alloc] init];
mSticks = [[NSMutableArray alloc] init];
mLogicalDeviceElements = [[NSMutableArray alloc] init];
[self initLogicalDeviceElements];
int logicalDeviceCount = [mLogicalDeviceElements count];
if (logicalDeviceCount == 0)
{
[self release];
return nil;
}
mLogicalDeviceNumber = logicalDeviceNumber;
if (mLogicalDeviceNumber >= logicalDeviceCount)
mLogicalDeviceNumber = logicalDeviceCount - 1;
[self initJoystickElements:
[mLogicalDeviceElements objectAtIndex: mLogicalDeviceNumber]];
[mButtonElements sortUsingSelector: @selector(compareByUsage:)];
mDelegate = nil;
return self;
}
//===========================================================
// dealloc
//===========================================================
- (void) dealloc
{
[mLogicalDeviceElements release];
[mSticks release];
[mButtonElements release];
mLogicalDeviceElements = nil;
mSticks = nil;
mButtonElements = nil;
[super dealloc];
}
- (int) logicalDeviceCount;
{
return [mLogicalDeviceElements count];
}
#pragma mark -
#pragma mark Joystick Elements
//===========================================================
// - buttonElements
//===========================================================
- (NSArray *) buttonElements;
{
return mButtonElements;
}
- (unsigned) numberOfButtons;
{
return [mButtonElements count];
}
#pragma mark -
#pragma mark Sticks - indexed accessors
- (unsigned int) countOfSticks
{
return [mSticks count];
}
- (DDHidJoystickStick *) objectInSticksAtIndex: (unsigned int)index
{
return [mSticks objectAtIndex: index];
}
- (void) addElementsToQueue: (DDHidQueue *) queue;
{
NSEnumerator * e = [mSticks objectEnumerator];
DDHidJoystickStick * stick;
while (stick = [e nextObject])
{
[queue addElements: [stick allElements]];
}
[queue addElements: mButtonElements];
}
#pragma mark -
#pragma mark Asynchronous Notification
- (void) setDelegate: (id) delegate;
{
mDelegate = delegate;
}
- (void) addElementsToDefaultQueue;
{
[self addElementsToQueue: mDefaultQueue];
}
@end
@implementation DDHidJoystick (Private)
- (void) initLogicalDeviceElements;
{
NSArray * topLevelElements = [self elements];
if ([topLevelElements count] == 0)
{
[mLogicalDeviceElements addObject: topLevelElements];
return;
}
NSEnumerator * e = [topLevelElements objectEnumerator];
DDHidElement * element;
while (element = [e nextObject])
{
unsigned usagePage = [[element usage] usagePage];
unsigned usageId = [[element usage] usageId];
if (usagePage == kHIDPage_GenericDesktop &&
(usageId == kHIDUsage_GD_Joystick || usageId == kHIDUsage_GD_GamePad))
{
[mLogicalDeviceElements addObject: [NSArray arrayWithObject: element]];
}
}
}
- (void) initJoystickElements: (NSArray *) elements;
{
NSEnumerator * e = [elements objectEnumerator];
DDHidElement * element;
DDHidJoystickStick * currentStick = [[[DDHidJoystickStick alloc] init] autorelease];
BOOL stickHasElements = NO;
while (element = [e nextObject])
{
unsigned usagePage = [[element usage] usagePage];
unsigned usageId = [[element usage] usageId];
NSArray * subElements = [element elements];
if ([subElements count] > 0)
{
[self initJoystickElements: subElements];
}
else if ((usagePage == kHIDPage_GenericDesktop) &&
(usageId == kHIDUsage_GD_Pointer))
{
[self addStick: subElements];
}
else if ([currentStick addElement: element])
{
stickHasElements = YES;
}
else if ((usagePage == kHIDPage_Button) &&
(usageId > 0))
{
[mButtonElements addObject: element];
}
}
if (stickHasElements)
{
[mSticks addObject: currentStick];
}
}
- (void) addStick: (NSArray *) elements;
{
NSEnumerator * e = [elements objectEnumerator];
DDHidElement * element;
while (element = [e nextObject])
{
NSLog(@"Stick element: %@", [[element usage] usageName]);
}
}
- (void) ddhidQueueHasEvents: (DDHidQueue *) hidQueue;
{
DDHidEvent * event;
while ((event = [hidQueue nextEvent]))
{
IOHIDElementCookie cookie = [event elementCookie];
SInt32 value = [event value];
DDHidElement * element;
unsigned stick;
unsigned otherAxis;
unsigned povNumber;
if ([self findStick: &stick element: &element withXAxisCookie: cookie])
{
int normalizedValue = [self normalizeValue: value forElement: element];
[self ddhidJoystick: self stick: stick xChanged: normalizedValue];
}
else if ([self findStick: &stick element: &element withYAxisCookie: cookie])
{
int normalizedValue = [self normalizeValue: value forElement: element];
[self ddhidJoystick: self stick: stick yChanged: normalizedValue];
}
else if ([self findStick: &stick otherAxis: &otherAxis element: &element
withCookie: cookie])
{
int normalizedValue = [self normalizeValue: value forElement: element];
[self ddhidJoystick: self stick: stick
otherAxis: otherAxis valueChanged: normalizedValue];
}
else if ([self findStick: &stick povNumber: &povNumber element: &element
withCookie: cookie])
{
int povValue = [self povValue: value forElement: element];
[self ddhidJoystick: self stick: stick
povNumber: povNumber valueChanged: povValue];
}
else
{
unsigned i = 0;
for (i = 0; i < [[self buttonElements] count]; i++)
{
if (cookie == [[[self buttonElements] objectAtIndex: i] cookie])
break;
}
if (value == 1)
{
[self ddhidJoystick: self buttonDown: i];
}
else if (value == 0)
{
[self ddhidJoystick: self buttonUp: i];
}
else
{
DDHidElement * element = [self elementForCookie: [event elementCookie]];
NSLog(@"Element: %@, value: %d", [[element usage] usageName], (int)[event value]);
}
}
}
}
- (int) normalizeValue: (int) value
forElement: (DDHidElement *) element;
{
int normalizedUnits = DDHID_JOYSTICK_VALUE_MAX - DDHID_JOYSTICK_VALUE_MIN;
int elementUnits = [element maxValue] - [element minValue];
int normalizedValue = (((int64_t)(value - [element minValue]) * normalizedUnits) /
elementUnits) + DDHID_JOYSTICK_VALUE_MIN;
return normalizedValue;
}
- (int) povValue: (int) value
forElement: (DDHidElement *) element;
{
long max = [element maxValue];
long min = [element minValue];
// If the value is outside the min/max range, it's probably in a
// centered/NULL state.
if ((value < min) || (value > max))
{
return -1;
}
// Do like DirectInput and express the hatswitch value in hundredths of a
// degree, clockwise from north.
return 36000 / (max - min + 1) * (value - min);
}
- (BOOL) findStick: (unsigned *) stick
element: (DDHidElement **) elementOut
withXAxisCookie: (IOHIDElementCookie) cookie;
{
unsigned i;
for (i = 0; i < [mSticks count]; i++)
{
DDHidElement * element = [[mSticks objectAtIndex: i] xAxisElement];
if ((element != nil) && ([element cookie] == cookie))
{
*stick = i;
*elementOut = element;
return YES;
}
}
return NO;
}
- (BOOL) findStick: (unsigned *) stick
element: (DDHidElement **) elementOut
withYAxisCookie: (IOHIDElementCookie) cookie;
{
unsigned i;
for (i = 0; i < [mSticks count]; i++)
{
DDHidElement * element = [[mSticks objectAtIndex: i] yAxisElement];
if ((element != nil) && ([element cookie] == cookie))
{
*stick = i;
*elementOut = element;
return YES;
}
}
return NO;
}
- (BOOL) findStick: (unsigned *) stickOut
otherAxis: (unsigned *) axisOut
element: (DDHidElement **) elementOut
withCookie: (IOHIDElementCookie) cookie;
{
unsigned i;
for (i = 0; i < [mSticks count]; i++)
{
DDHidJoystickStick * stick = [mSticks objectAtIndex: i];
unsigned j;
for (j = 0; j < [stick countOfStickElements]; j++)
{
DDHidElement * element = [stick objectInStickElementsAtIndex: j];
if ((element != nil) && ([element cookie] == cookie))
{
*stickOut = i;
*axisOut = j;
*elementOut = element;
return YES;
}
}
}
return NO;
}
- (BOOL) findStick: (unsigned *) stickOut
povNumber: (unsigned *) povNumber
element: (DDHidElement **) elementOut
withCookie: (IOHIDElementCookie) cookie;
{
unsigned i;
for (i = 0; i < [mSticks count]; i++)
{
DDHidJoystickStick * stick = [mSticks objectAtIndex: i];
unsigned j;
for (j = 0; j < [stick countOfPovElements]; j++)
{
DDHidElement * element = [stick objectInPovElementsAtIndex: j];
if ((element != nil) && ([element cookie] == cookie))
{
*stickOut = i;
*povNumber = j;
*elementOut = element;
return YES;
}
}
}
return NO;
}
@end
@implementation DDHidJoystick (DDHidJoystickDelegate)
- (void) ddhidJoystick: (DDHidJoystick *) joystick
stick: (unsigned) stick
xChanged: (int) value;
{
if ([mDelegate respondsToSelector: _cmd])
[mDelegate ddhidJoystick: joystick stick: stick xChanged: value];
}
- (void) ddhidJoystick: (DDHidJoystick *) joystick
stick: (unsigned) stick
yChanged: (int) value;
{
if ([mDelegate respondsToSelector: _cmd])
[mDelegate ddhidJoystick: joystick stick: stick yChanged: value];
}
- (void) ddhidJoystick: (DDHidJoystick *) joystick
stick: (unsigned) stick
otherAxis: (unsigned) otherAxis
valueChanged: (int) value;
{
if ([mDelegate respondsToSelector: _cmd])
[mDelegate ddhidJoystick: joystick stick: stick otherAxis: otherAxis
valueChanged: value];
}
- (void) ddhidJoystick: (DDHidJoystick *) joystick
stick: (unsigned) stick
povNumber: (unsigned) povNumber
valueChanged: (int) value;
{
if ([mDelegate respondsToSelector: _cmd])
[mDelegate ddhidJoystick: joystick stick: stick povNumber: povNumber
valueChanged: value];
}
- (void) ddhidJoystick: (DDHidJoystick *) joystick
buttonDown: (unsigned) buttonNumber;
{
if ([mDelegate respondsToSelector: _cmd])
[mDelegate ddhidJoystick: joystick buttonDown: buttonNumber];
}
- (void) ddhidJoystick: (DDHidJoystick *) joystick
buttonUp: (unsigned) buttonNumber;
{
if ([mDelegate respondsToSelector: _cmd])
[mDelegate ddhidJoystick: joystick buttonUp: buttonNumber];
}
@end
@implementation DDHidJoystickStick
- (id) init
{
self = [super init];
if (self == nil)
return nil;
mXAxisElement = nil;
mYAxisElement = nil;
mStickElements = [[NSMutableArray alloc] init];
mPovElements = [[NSMutableArray alloc] init];
return self;
}
//===========================================================
// dealloc
//===========================================================
- (void) dealloc
{
[mXAxisElement release];
[mYAxisElement release];
[mStickElements release];
[mPovElements release];
mXAxisElement = nil;
mYAxisElement = nil;
mStickElements = nil;
mPovElements = nil;
[super dealloc];
}
- (BOOL) addElement: (DDHidElement *) element;
{
DDHidUsage * usage = [element usage];
if ([usage usagePage] != kHIDPage_GenericDesktop)
return NO;
BOOL elementAdded = YES;
switch ([usage usageId])
{
case kHIDUsage_GD_X:
if (mXAxisElement == nil)
mXAxisElement = [element retain];
else
[mStickElements addObject: element];
break;
case kHIDUsage_GD_Y:
if (mYAxisElement == nil)
mYAxisElement = [element retain];
else
[mStickElements addObject: element];
break;
case kHIDUsage_GD_Z:
case kHIDUsage_GD_Rx:
case kHIDUsage_GD_Ry:
case kHIDUsage_GD_Rz:
[mStickElements addObject: element];
break;
case kHIDUsage_GD_Hatswitch:
[mPovElements addObject: element];
break;
default:
elementAdded = NO;
}
return elementAdded;
}
- (NSArray *) allElements;
{
NSMutableArray * elements = [NSMutableArray array];
if (mXAxisElement != nil)
[elements addObject: mXAxisElement];
if (mYAxisElement != nil)
[elements addObject: mYAxisElement];
[elements addObjectsFromArray: mStickElements];
[elements addObjectsFromArray: mPovElements];
return elements;
}
- (DDHidElement *) xAxisElement;
{
return mXAxisElement;
}
- (DDHidElement *) yAxisElement;
{
return mYAxisElement;
}
#pragma mark -
#pragma mark mStickElements - indexed accessors
- (unsigned int) countOfStickElements
{
return [mStickElements count];
}
- (DDHidElement *) objectInStickElementsAtIndex: (unsigned int)index
{
return [mStickElements objectAtIndex: index];
}
#pragma mark -
#pragma mark PovElements - indexed accessors
- (unsigned int) countOfPovElements;
{
return [mPovElements count];
}
- (DDHidElement *) objectInPovElementsAtIndex: (unsigned int)index;
{
return [mPovElements objectAtIndex: index];
}
- (NSString *) description;
{
return [mStickElements description];
}
@end