diff options
| author | Dominik Pich | 2013-03-17 13:33:20 +0100 | 
|---|---|---|
| committer | Dominik Pich | 2013-03-17 13:33:20 +0100 | 
| commit | d4ffd217288cfc0d2798b3df67ab20bc867a7f7e (patch) | |
| tree | ab40c6fb784fbe578713381ea5cf1159934a9c34 /lib/DDHidJoystick.m | |
| parent | 77d2a9f99a289d247c5a8561879489c8f8162055 (diff) | |
| download | DDHidLib-d4ffd217288cfc0d2798b3df67ab20bc867a7f7e.tar.bz2 | |
DDHIDLib 1.1.1
Diffstat (limited to 'lib/DDHidJoystick.m')
| -rw-r--r-- | lib/DDHidJoystick.m | 654 | 
1 files changed, 654 insertions, 0 deletions
| diff --git a/lib/DDHidJoystick.m b/lib/DDHidJoystick.m new file mode 100644 index 0000000..601f9b3 --- /dev/null +++ b/lib/DDHidJoystick.m @@ -0,0 +1,654 @@ +/* + * 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], [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 | 
