diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/DDHidAppleMikey.h | 66 | ||||
| -rw-r--r-- | lib/DDHidAppleMikey.m | 164 | ||||
| -rw-r--r-- | lib/DDHidAppleRemote.h | 84 | ||||
| -rw-r--r-- | lib/DDHidAppleRemote.m | 236 | ||||
| -rw-r--r-- | lib/DDHidDevice.h | 131 | ||||
| -rw-r--r-- | lib/DDHidDevice.m | 585 | ||||
| -rw-r--r-- | lib/DDHidElement.h | 65 | ||||
| -rw-r--r-- | lib/DDHidElement.m | 185 | ||||
| -rw-r--r-- | lib/DDHidEvent.h | 45 | ||||
| -rw-r--r-- | lib/DDHidEvent.m | 81 | ||||
| -rw-r--r-- | lib/DDHidJoystick.h | 132 | ||||
| -rw-r--r-- | lib/DDHidJoystick.m | 654 | ||||
| -rw-r--r-- | lib/DDHidKeyboard.h | 68 | ||||
| -rw-r--r-- | lib/DDHidKeyboard.m | 173 | ||||
| -rw-r--r-- | lib/DDHidKeyboardBarcodeScanner.h | 74 | ||||
| -rw-r--r-- | lib/DDHidKeyboardBarcodeScanner.m | 222 | ||||
| -rw-r--r-- | lib/DDHidLib.h | 36 | ||||
| -rw-r--r-- | lib/DDHidMouse.h | 78 | ||||
| -rw-r--r-- | lib/DDHidMouse.m | 279 | ||||
| -rw-r--r-- | lib/DDHidQueue.h | 70 | ||||
| -rw-r--r-- | lib/DDHidQueue.m | 172 | ||||
| -rw-r--r-- | lib/DDHidStandardUsages.plist | 2327 | ||||
| -rw-r--r-- | lib/DDHidUsage.h | 52 | ||||
| -rw-r--r-- | lib/DDHidUsage.m | 84 | ||||
| -rw-r--r-- | lib/DDHidUsageTables.h | 40 | ||||
| -rw-r--r-- | lib/DDHidUsageTables.m | 85 | ||||
| -rw-r--r-- | lib/NSDictionary+DDHidExtras.h | 46 | ||||
| -rw-r--r-- | lib/NSDictionary+DDHidExtras.m | 81 | 
28 files changed, 6315 insertions, 0 deletions
| diff --git a/lib/DDHidAppleMikey.h b/lib/DDHidAppleMikey.h new file mode 100644 index 0000000..c6bea0d --- /dev/null +++ b/lib/DDHidAppleMikey.h @@ -0,0 +1,66 @@ +/* + * 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 <Cocoa/Cocoa.h> +#import "DDHidDevice.h" + +@class DDHidElement; +@class DDHidQueue; + +@interface DDHidAppleMikey : DDHidDevice +{ +    NSMutableArray * mPressElements; +     +    id mDelegate; +} + ++ (NSArray *) allMikeys; + +- (id) initWithDevice: (io_object_t) device error: (NSError **) error_; + +#pragma mark - +#pragma mark Elements + +- (NSArray *) pressElements; + +- (unsigned) numberOfKeys; + +- (void) addElementsToQueue: (DDHidQueue *) queue; + +#pragma mark - +#pragma mark Asynchronous Notification + +- (void) setDelegate: (id) delegate; + +- (void) addElementsToDefaultQueue; + +@end + +@interface NSObject (DDHidAppleMikeyDelegate) + +- (void) ddhidAppleMikey: (DDHidAppleMikey *) mikey +                   press: (unsigned) usageId +                upOrDown:(BOOL)upOrDown; + +@end diff --git a/lib/DDHidAppleMikey.m b/lib/DDHidAppleMikey.m new file mode 100644 index 0000000..b0da05f --- /dev/null +++ b/lib/DDHidAppleMikey.m @@ -0,0 +1,164 @@ +/* + * 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 "DDHidAppleMikey.h" +#import "DDHidElement.h" +#import "DDHidUsage.h" +#import "DDHidQueue.h" +#import "DDHidEvent.h" +#include <IOKit/hid/IOHIDUsageTables.h> + +@interface DDHidAppleMikey (DDHidAppleMikeyDelegate) + +- (void) ddhidAppleMikey: (DDHidAppleMikey *) mikey +               press: (unsigned) usageId +                upOrDown:(BOOL)upOrDown; + +@end + +@interface DDHidAppleMikey (Private) + +- (void) initPressElements: (NSArray *) elements; +- (void) ddhidQueueHasEvents: (DDHidQueue *) hidQueue; + +@end + +@implementation DDHidAppleMikey + ++ (NSArray *) allMikeys; +{ +    //add mikey +    CFMutableDictionaryRef hidMatchDictionary = +    IOServiceMatching(kIOHIDDeviceKey); +    id a2 = [self allDevicesMatchingCFDictionary: hidMatchDictionary +                                      withClass: self +                              skipZeroLocations: NO]; +    a2 = [a2 filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"productName == \"Apple Mikey HID Driver\""]]; + +    return a2; +} + +- (id) initWithDevice: (io_object_t) device error: (NSError **) error_; +{ +    self = [super initWithDevice: device error: error_]; +    if (self == nil) +        return nil; +     +    mPressElements = [[NSMutableArray alloc] init]; +    [self initPressElements: [self elements]]; +     +    return self; +} + +//===========================================================  +// dealloc +//===========================================================  +- (void) dealloc +{ +    [mPressElements release]; +     +    mPressElements = nil; +    [super dealloc]; +} + +#pragma mark - +#pragma mark Elements + +- (NSArray *) pressElements; +{ +    return mPressElements; +} + +- (unsigned) numberOfKeys; +{ +    return [mPressElements count]; +} + +- (void) addElementsToQueue: (DDHidQueue *) queue; +{ +    [queue addElements: mPressElements]; +} + +#pragma mark - +#pragma mark Asynchronous Notification + +- (void) setDelegate: (id) delegate; +{ +    mDelegate = delegate; +} + +- (void) addElementsToDefaultQueue; +{ +    [self addElementsToQueue: mDefaultQueue]; +} + +@end + +@implementation DDHidAppleMikey (DDHidAppleMikeyDelegate) + +- (void) ddhidAppleMikey:(DDHidAppleMikey *)mikey press:(unsigned int)usageId upOrDown:(BOOL)upOrDown +{ +    if ([mDelegate respondsToSelector: _cmd]) +        [mDelegate ddhidAppleMikey: mikey press: usageId upOrDown:(BOOL)upOrDown]; +} + +@end + +@implementation DDHidAppleMikey (Private) + +- (void) initPressElements: (NSArray *) elements; +{ +    NSEnumerator * e = [elements objectEnumerator]; +    DDHidElement * element; +    while (element = [e nextObject]) +    { +//        unsigned usagePage = [[element usage] usagePage]; +//        unsigned usageId = [[element usage] usageId]; +//        if (usagePage == kHIDPage_KeyboardOrKeypad) +//        { +//            if ((usageId >= 0x04) && (usageId <= 0xA4) || +//                (usageId >= 0xE0) && (usageId <= 0xE7)) +            { +                [mPressElements addObject: element]; +            } +//        } +        NSArray * subElements = [element elements]; +        if (subElements != nil) +            [self initPressElements: subElements]; +    } +} + +- (void) ddhidQueueHasEvents: (DDHidQueue *) hidQueue; +{ +    DDHidEvent * event; +    while (event = [hidQueue nextEvent]) +    { +        DDHidElement * element = [self elementForCookie: [event elementCookie]]; +        unsigned usageId = [[element usage] usageId]; +        SInt32 value = [event value]; +        [self ddhidAppleMikey:self press:usageId upOrDown:value==1]; +    } +} + +@end diff --git a/lib/DDHidAppleRemote.h b/lib/DDHidAppleRemote.h new file mode 100644 index 0000000..f6bc8ef --- /dev/null +++ b/lib/DDHidAppleRemote.h @@ -0,0 +1,84 @@ +/* + * 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 <Cocoa/Cocoa.h> + +#import "DDHidDevice.h" + +@class DDHidElement; + +enum DDHidAppleRemoteEventIdentifier +{ +	kDDHidRemoteButtonVolume_Plus=0, +	kDDHidRemoteButtonVolume_Minus, +	kDDHidRemoteButtonMenu, +	kDDHidRemoteButtonPlay, +	kDDHidRemoteButtonRight,	 +	kDDHidRemoteButtonLeft,	 +	kDDHidRemoteButtonRight_Hold,	 +	kDDHidRemoteButtonLeft_Hold, +	kDDHidRemoteButtonMenu_Hold, +	kDDHidRemoteButtonPlay_Sleep, +	kDDHidRemoteControl_Switched, +    kDDHidRemoteControl_Paired, +}; +typedef enum DDHidAppleRemoteEventIdentifier DDHidAppleRemoteEventIdentifier; + +@interface DDHidAppleRemote : DDHidDevice +{ +    NSMutableDictionary * mCookieToButtonMapping; +    NSArray * mButtonElements; +    DDHidElement * mIdElement; +    int mRemoteId; + +    id mDelegate; +} + ++ (NSArray *) allRemotes; + ++ (DDHidAppleRemote *) firstRemote; + +- (id) initWithDevice: (io_object_t) device error: (NSError **) error_; + +#pragma mark - +#pragma mark Asynchronous Notification + +- (void) setDelegate: (id) delegate; + +- (void) addElementsToDefaultQueue; + +#pragma mark - +#pragma mark Properties + +- (int) remoteId; +- (void) setRemoteId: (int) theRemoteId; + +@end + +@interface NSObject (DDHidAppleRemoteDelegate) + +- (void) ddhidAppleRemoteButton: (DDHidAppleRemoteEventIdentifier) buttonIdentifier +                    pressedDown: (BOOL) pressedDown; + +@end diff --git a/lib/DDHidAppleRemote.m b/lib/DDHidAppleRemote.m new file mode 100644 index 0000000..e8b31b2 --- /dev/null +++ b/lib/DDHidAppleRemote.m @@ -0,0 +1,236 @@ +/* + * 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. + */ + +// Based on Martin Kahr's Apple Remote wrapper +// http://www.martinkahr.com/source-code/ + +#import "DDHidAppleRemote.h" +#import "DDHidElement.h" +#import "DDHidUsage.h" +#import "DDHidQueue.h" +#import "DDHidEvent.h" +#import "NSDictionary+DDHidExtras.h" + +@interface DDHidAppleRemote (Private) + +- (void) initRemoteElements: (NSArray *) elements; + +- (void) ddhidQueueHasEvents: (DDHidQueue *) hidQueue; + +- (void) handleEventWithCookieString: (NSString*) cookieString +                         sumOfValues: (SInt32) sumOfValues; + +@end + +@implementation DDHidAppleRemote + ++ (NSArray *) allRemotes; +{ +    CFMutableDictionaryRef hidMatchDictionary = +        IOServiceMatching("AppleIRController"); +     +    return +        [DDHidDevice allDevicesMatchingCFDictionary: hidMatchDictionary +                                          withClass: self +                                  skipZeroLocations: YES]; +} + ++ (DDHidAppleRemote *) firstRemote; +{ +    NSArray * allRemotes = [self allRemotes]; +    if ([allRemotes count] > 0) +        return [allRemotes objectAtIndex: 0]; +    else +        return nil; +} + +- (id) initWithDevice: (io_object_t) device error: (NSError **) error_; +{ +    self = [super initWithDevice: device error: error_]; +    if (self == nil) +        return nil; +     +    mCookieToButtonMapping = [[NSMutableDictionary alloc] init]; +     +    [mCookieToButtonMapping ddhid_setInt: kDDHidRemoteButtonVolume_Plus +                                  forKey: @"14_12_11_6_5_"]; +    [mCookieToButtonMapping ddhid_setInt: kDDHidRemoteButtonVolume_Plus +                                  forKey: @"31_29_28_19_18_"]; +    [mCookieToButtonMapping ddhid_setInt: kDDHidRemoteButtonVolume_Minus +                                  forKey: @"14_13_11_6_5_"]; +    [mCookieToButtonMapping ddhid_setInt: kDDHidRemoteButtonVolume_Minus +                                  forKey: @"31_30_28_19_18_"]; +    [mCookieToButtonMapping ddhid_setInt: kDDHidRemoteButtonMenu +                                  forKey: @"14_7_6_5_14_7_6_5_"]; +    [mCookieToButtonMapping ddhid_setInt: kDDHidRemoteButtonMenu +                                  forKey: @"31_20_19_18_31_20_19_18_"]; +    [mCookieToButtonMapping ddhid_setInt: kDDHidRemoteButtonPlay +                                  forKey: @"14_8_6_5_14_8_6_5_"]; +    [mCookieToButtonMapping ddhid_setInt: kDDHidRemoteButtonPlay +                                  forKey: @"31_21_19_18_31_21_19_18_"]; +    [mCookieToButtonMapping ddhid_setInt: kDDHidRemoteButtonRight +                                  forKey: @"14_9_6_5_14_9_6_5_"]; +    [mCookieToButtonMapping ddhid_setInt: kDDHidRemoteButtonRight +                                  forKey: @"31_22_19_18_31_22_19_18_"]; +    [mCookieToButtonMapping ddhid_setInt: kDDHidRemoteButtonLeft +                                  forKey: @"14_10_6_5_14_10_6_5_"]; +    [mCookieToButtonMapping ddhid_setInt: kDDHidRemoteButtonLeft +                                  forKey: @"31_23_19_18_31_23_19_18_"]; +    [mCookieToButtonMapping ddhid_setInt: kDDHidRemoteButtonRight_Hold +                                  forKey: @"14_6_5_4_2_"]; +    [mCookieToButtonMapping ddhid_setInt: kDDHidRemoteButtonRight_Hold +                                  forKey: @"31_19_18_4_2_"]; +    [mCookieToButtonMapping ddhid_setInt: kDDHidRemoteButtonLeft_Hold +                                  forKey: @"14_6_5_3_2_"]; +    [mCookieToButtonMapping ddhid_setInt: kDDHidRemoteButtonLeft_Hold +                                  forKey: @"31_19_18_3_2_"]; +    [mCookieToButtonMapping ddhid_setInt: kDDHidRemoteButtonMenu_Hold +                                  forKey: @"14_6_5_14_6_5_"]; +    [mCookieToButtonMapping ddhid_setInt: kDDHidRemoteButtonMenu_Hold +                                  forKey: @"31_19_18_31_19_18_"]; +    [mCookieToButtonMapping ddhid_setInt: kDDHidRemoteButtonPlay_Sleep +                                  forKey: @"18_14_6_5_18_14_6_5_"]; +    [mCookieToButtonMapping ddhid_setInt: kDDHidRemoteButtonPlay_Sleep +                                  forKey: @"35_31_19_18_35_31_19_18_"]; +    [mCookieToButtonMapping ddhid_setInt: kDDHidRemoteControl_Switched +                                  forKey: @"19_"]; +    //[mCookieToButtonMapping ddhid_setInt: kDDHidRemoteControl_Switched +    //                              forKey: @"??_"]; // unknown for 10.5 +    [mCookieToButtonMapping ddhid_setInt: kDDHidRemoteControl_Paired +                                  forKey: @"15_14_6_5_15_14_6_5_"]; +    [mCookieToButtonMapping ddhid_setInt: kDDHidRemoteControl_Paired +                                  forKey: @"32_31_19_18_32_31_19_18_"]; +     +    [self initRemoteElements: [self elements]]; +     +     +    return self; +} + +//===========================================================  +// dealloc +//===========================================================  +- (void) dealloc +{ +    [mCookieToButtonMapping release]; +    [mButtonElements release]; +    [mIdElement release]; +     +    mCookieToButtonMapping = nil; +    mButtonElements = nil; +    mIdElement = nil; +    [super dealloc]; +} + +#pragma mark - +#pragma mark Asynchronous Notification + +- (void) setDelegate: (id) delegate; +{ +    mDelegate = delegate; +} + +- (void) addElementsToDefaultQueue; +{ +    [mDefaultQueue addElements: mButtonElements]; +} + +#pragma mark - +#pragma mark Properties + +//===========================================================  +//  remoteId  +//===========================================================  +- (int) remoteId +{ +    return mRemoteId; +} + +- (void) setRemoteId: (int) theRemoteId +{ +    mRemoteId = theRemoteId; +} + +@end + +@implementation DDHidAppleRemote (Private) + +- (void) initRemoteElements: (NSArray *) elements; +{ +    NSAssert([elements count] == 1, @"Assume only 1 top level remote element"); +    DDHidElement * consumerControlsElement = [elements objectAtIndex: 0]; +    mButtonElements = [[consumerControlsElement elements] retain]; +    DDHidElement * element; +    NSEnumerator * e = [mButtonElements objectEnumerator]; +    while (element = [e nextObject]) +    { +        if ([[element usage] isEqualToUsagePage: 0x0006 +                                        usageId: 0x0022]) +        { +            mIdElement = [element retain]; +        } +    } +} + +- (void) ddhidQueueHasEvents: (DDHidQueue *) hidQueue; +{ +	NSMutableString * cookieString = [NSMutableString string]; +	SInt32 sumOfValues = 0; + +    DDHidEvent * event; +    while (event = [hidQueue nextEvent]) +    { +        if ([event elementCookie] == [mIdElement cookie]) +        { +            [self setRemoteId: [event value]]; +        } +        else +        { +            sumOfValues += [event value]; +            [cookieString appendString: +                [NSString stringWithFormat: @"%u_", [event elementCookieAsUnsigned]]]; +        } +    } +    [self handleEventWithCookieString: cookieString sumOfValues: sumOfValues];	 +} + +- (void) handleEventWithCookieString: (NSString*) cookieString +                         sumOfValues: (SInt32) sumOfValues; +{ +	NSNumber* buttonId = [mCookieToButtonMapping objectForKey: cookieString]; +	if (buttonId != nil) +    { +		if ([mDelegate respondsToSelector: @selector(ddhidAppleRemoteButton:pressedDown:)]) +        { +			[mDelegate ddhidAppleRemoteButton: [buttonId intValue] +                                 pressedDown: (sumOfValues>0)]; +		} +	} +    else +		NSLog(@"Unknown button for cookiestring %@", cookieString); + +} + +@end + diff --git a/lib/DDHidDevice.h b/lib/DDHidDevice.h new file mode 100644 index 0000000..40b9fdb --- /dev/null +++ b/lib/DDHidDevice.h @@ -0,0 +1,131 @@ +/* + * 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 <Cocoa/Cocoa.h> +#include <IOKit/IOKitLib.h> +#include <IOKit/IOCFPlugIn.h> +#include <IOKit/hid/IOHIDLib.h> +#include <IOKit/hid/IOHIDKeys.h> + +@class DDHidUsage; +@class DDHidElement; +@class DDHidQueue; + +@interface DDHidDevice : NSObject +{ +    io_object_t mHidDevice; +	IOHIDDeviceInterface122** mDeviceInterface; + +    NSMutableDictionary * mProperties; +    DDHidUsage * mPrimaryUsage; +    NSMutableArray * mUsages; +    NSArray * mElements; +    NSMutableDictionary * mElementsByCookie; +    BOOL mListenInExclusiveMode; +    DDHidQueue * mDefaultQueue; +    int mTag; +    int mLogicalDeviceNumber; +} + +- (id) initWithDevice: (io_object_t) device error: (NSError **) error; +- (id) initLogicalWithDevice: (io_object_t) device +         logicalDeviceNumber: (int) logicalDeviceNumber +                       error: (NSError **) error; +- (int) logicalDeviceCount; + +#pragma mark - +#pragma mark Finding Devices + ++ (NSArray *) allDevices; + ++ (NSArray *) allDevicesMatchingUsagePage: (unsigned) usagePage +                                  usageId: (unsigned) usageId +                                withClass: (Class) hidClass +                        skipZeroLocations: (BOOL) emptyLocation; + ++ (NSArray *) allDevicesMatchingCFDictionary: (CFDictionaryRef) matchDictionary +                                   withClass: (Class) hidClass +                           skipZeroLocations: (BOOL) emptyLocation; + +#pragma mark - +#pragma mark I/O Kit Objects + +- (io_object_t) ioDevice; +- (IOHIDDeviceInterface122**) deviceInterface; + +#pragma mark - +#pragma mark Operations + +- (void) open; +- (void) openWithOptions: (UInt32) options; +- (void) close; +- (DDHidQueue *) createQueueWithSize: (unsigned) size; +- (long) getElementValue: (DDHidElement *) element; + +#pragma mark - +#pragma mark Asynchronous Notification + +- (BOOL) listenInExclusiveMode; +- (void) setListenInExclusiveMode: (BOOL) flag; + +- (void) startListening; + +- (void) stopListening; + +- (BOOL) isListening; + +#pragma mark - +#pragma mark Properties + +- (NSDictionary *) properties; + +- (NSArray *) elements; +- (DDHidElement *) elementForCookie: (IOHIDElementCookie) cookie; + +- (NSString *) productName; +- (NSString *) manufacturer; +- (NSString *) serialNumber; +- (NSString *) transport; +- (long) vendorId; +- (long) productId; +- (long) version; +- (long) locationId; +- (long) usagePage; +- (long) usage; +- (DDHidUsage *) primaryUsage; +- (NSArray *) usages; + +- (NSComparisonResult) compareByLocationId: (DDHidDevice *) device; + +- (int) tag; +- (void) setTag: (int) theTag; + +@end + +@interface DDHidDevice (Protected) + +- (unsigned) sizeOfDefaultQueue; +- (void) addElementsToDefaultQueue; + +@end diff --git a/lib/DDHidDevice.m b/lib/DDHidDevice.m new file mode 100644 index 0000000..8000185 --- /dev/null +++ b/lib/DDHidDevice.m @@ -0,0 +1,585 @@ +/* + * 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 "DDHidDevice.h" +#import "DDHidUsage.h" +#import "DDHidElement.h" +#import "DDHidQueue.h" +#import "NSDictionary+DDHidExtras.h" +#import "NSXReturnThrowError.h" + +#include <IOKit/hid/IOHIDUsageTables.h> + +@interface DDHidDevice (Private) + ++ (void) addDevice: (io_object_t) hidDevice +         withClass: (Class) hidClass + skipZeroLocations: (BOOL) skipZeroLocations +      toDeviceList: (NSMutableArray *) devices; + +- (BOOL) initPropertiesWithError: (NSError **) error_; +- (BOOL) createDeviceInterfaceWithError: (NSError **) error_; + +@end + +@implementation DDHidDevice + +- (id) initWithDevice: (io_object_t) device error: (NSError **) error; +{ +    return [self initLogicalWithDevice: device +                   logicalDeviceNumber: 0 +                                 error: error]; +} + +- (id) initLogicalWithDevice: (io_object_t) device +         logicalDeviceNumber: (int) logicalDeviceNumber +                       error: (NSError **) error; +{ +    self = [super init]; +    if (self == nil) +        return nil; +     +    mHidDevice = device; +    IOObjectRetain(mHidDevice); +  +    if (![self initPropertiesWithError: error]) +    { +        [self release]; +        return nil; +    } +     +    if (![self createDeviceInterfaceWithError: error]) +    { +        [self release]; +        return nil; +    } +     +    mLogicalDeviceNumber = logicalDeviceNumber; +    mListenInExclusiveMode = NO; +    mDefaultQueue = nil; +    mTag = 0; +	 +    return self; +} + +//===========================================================  +// dealloc +//===========================================================  +- (void) dealloc +{ +    [mDefaultQueue release]; +    if (mDeviceInterface != NULL) +    { +        (*mDeviceInterface)->close(mDeviceInterface); +        (*mDeviceInterface)->Release(mDeviceInterface); +    } +    [mElementsByCookie release]; +    [mElements release]; +    [mUsages release]; +    [mPrimaryUsage release]; +    [mProperties release]; +    IOObjectRelease(mHidDevice); +     +    mProperties = nil; +    mDeviceInterface = NULL; +    [super dealloc]; +} + +#pragma mark - +#pragma mark Finding Devices + ++ (NSArray *) allDevices; +{ +	// Set up a matching dictionary to search the I/O Registry by class +	// name for all HID class devices +	CFMutableDictionaryRef hidMatchDictionary = +        IOServiceMatching(kIOHIDDeviceKey); +    return [self allDevicesMatchingCFDictionary: hidMatchDictionary +                                      withClass: [DDHidDevice class] +                              skipZeroLocations: NO]; +} + ++ (NSArray *) allDevicesMatchingUsagePage: (unsigned) usagePage +                                  usageId: (unsigned) usageId +                                withClass: (Class) hidClass +                        skipZeroLocations: (BOOL) skipZeroLocations; +{ +	// Set up a matching dictionary to search the I/O Registry by class +	// name for all HID class devices +	CFMutableDictionaryRef hidMatchDictionary = +        IOServiceMatching(kIOHIDDeviceKey); +    NSMutableDictionary * objcMatchDictionary = +        (NSMutableDictionary *) hidMatchDictionary; +    [objcMatchDictionary ddhid_setObject: [NSNumber numberWithUnsignedInt: usagePage] +                               forString: kIOHIDDeviceUsagePageKey]; +    [objcMatchDictionary ddhid_setObject: [NSNumber numberWithUnsignedInt: usageId] +                               forString: kIOHIDDeviceUsageKey]; +    return [self allDevicesMatchingCFDictionary: hidMatchDictionary +                                      withClass: hidClass +                              skipZeroLocations: skipZeroLocations]; +} + ++ (NSArray *) allDevicesMatchingCFDictionary: (CFDictionaryRef) matchDictionary +                                   withClass: (Class) hidClass +                           skipZeroLocations: (BOOL) skipZeroLocations; +{ +	// Now search I/O Registry for matching devices. +	io_iterator_t hidObjectIterator = MACH_PORT_NULL; +    NSMutableArray * devices = [NSMutableArray array]; +    @try +    { +        NSXThrowError(IOServiceGetMatchingServices(kIOMasterPortDefault, +                                                   matchDictionary, +                                                   &hidObjectIterator)); +         +        if (hidObjectIterator == 0) +            return [NSArray array]; +         +        io_object_t hidDevice; +        while (hidDevice = IOIteratorNext(hidObjectIterator)) +        { +            [self addDevice: hidDevice +                  withClass: hidClass +          skipZeroLocations: skipZeroLocations +               toDeviceList: devices]; +        } +         +        // This makes sure the array return is consistent from run to run,  +        // assuming no new devices were added. +        [devices sortUsingSelector: @selector(compareByLocationId:)]; +    } +    @finally +    { +        if (hidObjectIterator != MACH_PORT_NULL) +            IOObjectRelease(hidObjectIterator); +    } +     +    return devices; +} + +- (int) logicalDeviceCount; +{ +    return 1; +} + +#pragma mark - +#pragma mark I/O Kit Objects + +- (io_object_t) ioDevice; +{ +    return mHidDevice; +} + +- (IOHIDDeviceInterface122**) deviceInterface; +{ +    return mDeviceInterface; +} + +#pragma mark - +#pragma mark Operations + +- (void) open; +{ +    [self openWithOptions: kIOHIDOptionsTypeNone]; +} + +- (void) openWithOptions: (UInt32) options; +{ +    NSXThrowError((*mDeviceInterface)->open(mDeviceInterface, options)); +} + +- (void) close; +{ +    NSXThrowError((*mDeviceInterface)->close(mDeviceInterface)); +} + +- (DDHidQueue *) createQueueWithSize: (unsigned) size; +{ +    IOHIDQueueInterface ** queue = +    (*mDeviceInterface)->allocQueue(mDeviceInterface); +    if (queue == NULL) +        return nil; +    return [[[DDHidQueue alloc] initWithHIDQueue: queue +                                            size: size] autorelease]; +} + +- (long) getElementValue: (DDHidElement *) element; +{ +    IOHIDEventStruct event; +    NSXThrowError((*mDeviceInterface)->getElementValue(mDeviceInterface, +                                                       [element cookie], +                                                       &event)); +    return event.value; +} + +#pragma mark - +#pragma mark Asynchronous Notification + +//===========================================================  +//  listenInExclusiveMode  +//===========================================================  +- (BOOL) listenInExclusiveMode +{ +    return mListenInExclusiveMode; +} + +- (void) setListenInExclusiveMode: (BOOL) flag +{ +    mListenInExclusiveMode = flag; +} + +- (void) startListening; +{ +    if ([self isListening]) +        return; +     +    UInt32 options = kIOHIDOptionsTypeNone; +    if (mListenInExclusiveMode) +        options = kIOHIDOptionsTypeSeizeDevice; +    [self openWithOptions: options]; +    mDefaultQueue = [[self createQueueWithSize: [self sizeOfDefaultQueue]] retain]; +    [mDefaultQueue setDelegate: self]; +    [self addElementsToDefaultQueue]; +    [mDefaultQueue startOnCurrentRunLoop]; +} + +- (void) stopListening; +{ +    if (![self isListening]) +        return; +     +    [mDefaultQueue stop]; +    [mDefaultQueue release]; +    mDefaultQueue = nil; +    [self close]; +} + +- (BOOL) isListening; +{ +    return (mDefaultQueue != nil); +} + +#pragma mark - +#pragma mark Properties + +- (NSDictionary *) properties; +{ +    return mProperties; +} + +//===========================================================  +// - productName +//===========================================================  +- (NSString *) productName +{ +    NSString * productName = [mProperties ddhid_stringForString: kIOHIDProductKey]; +    if ([self logicalDeviceCount] > 1) +    { +        productName = [productName stringByAppendingString: +                       [NSString stringWithFormat:@" #%d", mLogicalDeviceNumber + 1]]; +    } +    return productName; +} + +//===========================================================  +// - manufacturer +//===========================================================  +- (NSString *) manufacturer +{ +    return [mProperties ddhid_stringForString: kIOHIDManufacturerKey]; +} + +//===========================================================  +// - serialNumber +//===========================================================  +- (NSString *) serialNumber +{ +    return [mProperties ddhid_stringForString: kIOHIDSerialNumberKey]; +} + +//===========================================================  +// - transport +//===========================================================  +- (NSString *) transport +{ +    return [mProperties ddhid_stringForString: kIOHIDTransportKey]; +} + +//===========================================================  +// - vendorId +//===========================================================  +- (long) vendorId +{ +    return [mProperties ddhid_longForString: kIOHIDVendorIDKey]; +} + +//===========================================================  +// - productId +//===========================================================  +- (long) productId +{ +    return [mProperties ddhid_longForString: kIOHIDProductIDKey]; +} + +//===========================================================  +// - version +//===========================================================  +- (long) version +{ +    return [mProperties ddhid_longForString: kIOHIDVersionNumberKey]; +} + +//===========================================================  +// - locationId +//===========================================================  +- (long) locationId +{ +    return [mProperties ddhid_longForString: kIOHIDLocationIDKey]; +} + +//===========================================================  +// - usagePage +//===========================================================  +- (long) usagePage +{ +    return [mProperties ddhid_longForString: kIOHIDPrimaryUsagePageKey]; +} + +//===========================================================  +// - usage +//===========================================================  +- (long) usage +{ +    return [mProperties ddhid_longForString: kIOHIDPrimaryUsageKey]; +} + +- (NSArray *) elements; +{ +    return mElements; +} + +- (DDHidElement *) elementForCookie: (IOHIDElementCookie) cookie; +{ +    NSNumber * n = [NSNumber numberWithUnsignedInt: (unsigned) cookie]; +    return [mElementsByCookie objectForKey: n]; +} + +- (DDHidUsage *) primaryUsage; +{ +    return mPrimaryUsage; +} + +- (NSArray *) usages; +{ +    return mUsages; +} + +- (NSComparisonResult) compareByLocationId: (DDHidDevice *) device; +{ +    long myLocationId = [self locationId]; +    long otherLocationId = [device locationId]; +    if (myLocationId < otherLocationId) +        return NSOrderedAscending; +    else if (myLocationId > otherLocationId) +        return NSOrderedDescending; +    else +        return NSOrderedSame; +} + +//===========================================================  +//  tag  +//===========================================================  +- (int) tag +{ +    return mTag; +} + +- (void) setTag: (int) theTag +{ +    mTag = theTag; +} + +@end + +@implementation DDHidDevice (Protected) + +- (unsigned) sizeOfDefaultQueue; +{ +    return 10; +} + +- (void) addElementsToDefaultQueue; +{ +    [mDefaultQueue addElements: [self elements] recursively: YES]; +} + +@end + +@implementation DDHidDevice (Private) + ++ (void) addDevice: (io_object_t) hidDevice +         withClass: (Class) hidClass + skipZeroLocations: (BOOL) skipZeroLocations +      toDeviceList: (NSMutableArray *) devices; +{ +    @try +    { +        NSError * error = nil; +        DDHidDevice * device = [[hidClass alloc] initWithDevice: hidDevice +                                                          error: &error]; +        if (device == nil) +        { +            NSXRaiseError(error); +        } +        [device autorelease]; +         +        if (([device locationId] == 0) && skipZeroLocations) +            return; +         +        [devices addObject: device]; + +        // Add remainnig logical devices +        int i; +        for (i = 1; i < [device logicalDeviceCount]; i++) +        { +            device = [[hidClass alloc] initLogicalWithDevice: hidDevice +                                         logicalDeviceNumber: i +                                                       error: &error]; +             +            if (device == nil) +            { +                NSXRaiseError(error); +            } +            [device autorelease]; +             +            [devices addObject: device]; +        } +    } +    @finally +    { +        IOObjectRelease(hidDevice); +    } +} + +- (void) indexElements: (NSArray *) elements; +{ +    NSEnumerator * e = [elements objectEnumerator]; +    DDHidElement * element; +    while (element = [e nextObject]) +    { +        NSNumber * n = [NSNumber numberWithUnsignedInt: [element cookieAsUnsigned]]; +        [mElementsByCookie setObject: element +                              forKey: n]; +        NSArray * children = [element elements]; +        if (children != nil) +            [self indexElements: children]; +    } +} + +- (BOOL) initPropertiesWithError: (NSError **) error_; +{ +    NSError * error = nil; +    BOOL result = NO; +     +    CFMutableDictionaryRef properties; +    NSXReturnError(IORegistryEntryCreateCFProperties(mHidDevice, &properties, +                                                     kCFAllocatorDefault, kNilOptions)); +    if (error) +        goto done; +     +    mProperties = (NSMutableDictionary *) properties; +    NSArray * elementProperties = [mProperties ddhid_objectForString: kIOHIDElementKey]; +    mElements = [DDHidElement elementsWithPropertiesArray: elementProperties]; +    [mElements retain]; +     +    unsigned usagePage = [mProperties ddhid_unsignedIntForString: kIOHIDPrimaryUsagePageKey]; +    unsigned usageId = [mProperties ddhid_unsignedIntForString: kIOHIDPrimaryUsageKey]; +     +    mPrimaryUsage = [[DDHidUsage alloc] initWithUsagePage: usagePage +                                                  usageId: usageId]; +    mUsages = [[NSMutableArray alloc] init]; +     +    NSArray * usagePairs = [mProperties ddhid_objectForString: kIOHIDDeviceUsagePairsKey]; +    NSEnumerator * e = [usagePairs objectEnumerator]; +    NSDictionary * usagePair; +    while (usagePair = [e nextObject]) +    { +        usagePage = [usagePair ddhid_unsignedIntForString: kIOHIDDeviceUsagePageKey]; +        usageId = [usagePair ddhid_unsignedIntForString: kIOHIDDeviceUsageKey]; +        DDHidUsage * usage = [DDHidUsage usageWithUsagePage: usagePage +                                                    usageId: usageId]; +        [mUsages addObject: usage]; +    } +     +    mElementsByCookie = [[NSMutableDictionary alloc] init]; +    [self indexElements: mElements]; +    result = YES; +     +done: +        if (error_) +            *error_ = error; +    return result; +} + +- (BOOL) createDeviceInterfaceWithError: (NSError **) error_; +{ +	io_name_t className; +	IOCFPlugInInterface ** plugInInterface = NULL; +	SInt32 score = 0; +    NSError * error = nil; +    BOOL result = NO; +	 +	mDeviceInterface = NULL; +	 +	NSXReturnError(IOObjectGetClass(mHidDevice, className)); +    if (error) +        goto done; +	 +	NSXReturnError(IOCreatePlugInInterfaceForService(mHidDevice, +                                                     kIOHIDDeviceUserClientTypeID, +                                                     kIOCFPlugInInterfaceID, +													 &plugInInterface, +													 &score)); +    if (error) +        goto done; +     +    //Call a method of the intermediate plug-in to create the device interface +    NSXReturnError((*plugInInterface)->QueryInterface(plugInInterface, CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID), (LPVOID) &mDeviceInterface)); +    if (error) +        goto done; +     +    result = YES; +     +done: +    if (plugInInterface != NULL) +    { +        (*plugInInterface)->Release(plugInInterface); +    } +    if (error_) +        *error_ = error; +	return result; +} + +@end + diff --git a/lib/DDHidElement.h b/lib/DDHidElement.h new file mode 100644 index 0000000..4e9577c --- /dev/null +++ b/lib/DDHidElement.h @@ -0,0 +1,65 @@ +/* + * 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 <Cocoa/Cocoa.h> +#include <IOKit/hid/IOHIDKeys.h> + +@class DDHidUsage; + +@interface DDHidElement : NSObject +{ +    NSDictionary * mProperties; +    DDHidUsage * mUsage; +    NSArray * mElements; +} + ++ (NSArray *) elementsWithPropertiesArray: (NSArray *) propertiesArray; + ++ (DDHidElement *) elementWithProperties: (NSDictionary *) properties; + +- (id) initWithProperties: (NSDictionary *) properties; + +- (NSDictionary *) properties; + +- (NSString *) stringForKey: (NSString *) key; + +- (NSString *) description; + +- (IOHIDElementCookie) cookie; +- (unsigned) cookieAsUnsigned; + +- (NSArray *) elements; +- (DDHidUsage *) usage; +- (NSString *) name; +- (BOOL) hasNullState; +- (BOOL) hasPreferredState; +- (BOOL) isArray; +- (BOOL) isRelative; +- (BOOL) isWrapping; +- (long) maxValue; +- (long) minValue; + +- (NSComparisonResult) compareByUsage: (DDHidElement *) device; + +@end diff --git a/lib/DDHidElement.m b/lib/DDHidElement.m new file mode 100644 index 0000000..5a00095 --- /dev/null +++ b/lib/DDHidElement.m @@ -0,0 +1,185 @@ +/* + * 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 "DDHidElement.h" +#import "DDHidUsage.h" +#import "NSDictionary+DDHidExtras.h" +#include <IOKit/hid/IOHIDKeys.h> + +@implementation DDHidElement + ++ (NSArray *) elementsWithPropertiesArray: (NSArray *) propertiesArray; +{ +    NSMutableArray * elements = [NSMutableArray array]; +     +    NSDictionary * properties; +    NSEnumerator * e = [propertiesArray objectEnumerator]; +    while (properties = [e nextObject]) +    { +        DDHidElement * element = [DDHidElement elementWithProperties: properties]; +        [elements addObject: element]; +    } +     +    return elements; +} + ++ (DDHidElement *) elementWithProperties: (NSDictionary *) properties; +{ +    DDHidElement * element = [[DDHidElement alloc] initWithProperties: properties]; +    return [element autorelease]; +} + +- (id) initWithProperties: (NSDictionary *) properties; +{ +    self = [super init]; +    if (self == nil) +        return nil; +     +    mProperties = [properties retain]; +    unsigned usagePage = [mProperties ddhid_unsignedIntForString: kIOHIDElementUsagePageKey]; +    unsigned usageId = [mProperties ddhid_unsignedIntForString: kIOHIDElementUsageKey]; +    mUsage = [[DDHidUsage alloc] initWithUsagePage: usagePage +                                           usageId: usageId]; +     +    NSArray * elementsProperties = +        [mProperties ddhid_objectForString: kIOHIDElementKey]; +    mElements = [[DDHidElement elementsWithPropertiesArray: elementsProperties] +        retain]; + +    return self; +} + +//===========================================================  +// dealloc +//===========================================================  +- (void) dealloc +{ +    [mProperties release]; +    [mUsage release]; +    [mElements release]; +     +    mProperties = nil; +    mUsage = nil; +    mElements = nil; +    [super dealloc]; +} + +- (NSDictionary *) properties; +{ +    return mProperties; +} + +- (NSString *) stringForKey: (NSString *) key; +{ +    return [mProperties objectForKey: key]; +} + +- (NSString *) description; +{ +    return [[self usage] usageNameWithIds]; +} + +- (IOHIDElementCookie) cookie; +{ +    return (IOHIDElementCookie) +    [mProperties ddhid_unsignedIntForString: kIOHIDElementCookieKey]; +} + +- (unsigned) cookieAsUnsigned; +{ +    return [mProperties ddhid_unsignedIntForString: kIOHIDElementCookieKey]; +} + +- (DDHidUsage *) usage; +{ +    return mUsage; +} + +- (NSArray *) elements; +{ +    return mElements; +} + +- (NSString *) name; +{ +    return [mProperties ddhid_objectForString: kIOHIDElementNameKey]; +} + +- (BOOL) hasNullState; +{ +    return [mProperties ddhid_boolForString: kIOHIDElementHasNullStateKey]; +} + +- (BOOL) hasPreferredState; +{ +    return [mProperties ddhid_boolForString: kIOHIDElementHasNullStateKey]; +} + +- (BOOL) isArray; +{ +    return [mProperties ddhid_boolForString: kIOHIDElementIsArrayKey]; +} + +- (BOOL) isRelative; +{ +    return [mProperties ddhid_boolForString: kIOHIDElementIsRelativeKey]; +} + +- (BOOL) isWrapping; +{ +    return [mProperties ddhid_boolForString: kIOHIDElementIsWrappingKey]; +} + +- (long) maxValue; +{ +    return [mProperties ddhid_longForString: kIOHIDElementMaxKey]; +} + +- (long) minValue; +{ +    return [mProperties ddhid_longForString: kIOHIDElementMinKey]; +} + +- (NSComparisonResult) compareByUsage: (DDHidElement *) device; +{ +    unsigned myUsagePage = [[self usage] usagePage]; +    unsigned myUsageId = [[self usage] usageId]; + +    unsigned otherUsagePage = [[device usage] usagePage]; +    unsigned otherUsageId = [[device usage] usageId]; + +    if (myUsagePage < otherUsagePage) +        return NSOrderedAscending; +    else if (myUsagePage > otherUsagePage) +        return NSOrderedDescending; +     +    if (myUsageId < otherUsageId) +        return NSOrderedAscending; +    else if (myUsageId > otherUsageId) +        return NSOrderedDescending; + +    return NSOrderedSame; +} + +@end diff --git a/lib/DDHidEvent.h b/lib/DDHidEvent.h new file mode 100644 index 0000000..0861cfd --- /dev/null +++ b/lib/DDHidEvent.h @@ -0,0 +1,45 @@ +/* + * 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 <Cocoa/Cocoa.h> +#include <IOKit/hid/IOHIDLib.h> + +@interface DDHidEvent : NSObject +{ +    IOHIDEventStruct mEvent; +} + ++ (DDHidEvent *) eventWithIOHIDEvent: (IOHIDEventStruct *) event; + +- (id) initWithIOHIDEvent: (IOHIDEventStruct *) event; + +- (IOHIDElementType) type; +- (IOHIDElementCookie) elementCookie; +- (unsigned) elementCookieAsUnsigned; +- (SInt32) value; +- (AbsoluteTime) timestamp; +- (UInt32) longValueSize; +- (void *) longValue; + +@end diff --git a/lib/DDHidEvent.m b/lib/DDHidEvent.m new file mode 100644 index 0000000..8b2ab5f --- /dev/null +++ b/lib/DDHidEvent.m @@ -0,0 +1,81 @@ +/* + * 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 "DDHidEvent.h" + + +@implementation DDHidEvent + ++ (DDHidEvent *) eventWithIOHIDEvent: (IOHIDEventStruct *) event; +{ +    return [[[self alloc] initWithIOHIDEvent: event] autorelease]; +} + +- (id) initWithIOHIDEvent: (IOHIDEventStruct *) event; +{ +    self = [super init]; +    if (self == nil) +        return nil; +     +    mEvent = *event; +     +    return self; +} + +- (IOHIDElementType) type; +{ +    return mEvent.type; +} + +- (IOHIDElementCookie) elementCookie; +{ +    return mEvent.elementCookie; +} + +- (unsigned) elementCookieAsUnsigned; +{ +    return (unsigned) mEvent.elementCookie; +} + +- (SInt32) value; +{ +    return mEvent.value; +} + +- (AbsoluteTime) timestamp; +{ +    return mEvent.timestamp; +} + +- (UInt32) longValueSize; +{ +    return mEvent.longValueSize; +} + +- (void *) longValue; +{ +    return mEvent.longValue; +} + +@end diff --git a/lib/DDHidJoystick.h b/lib/DDHidJoystick.h new file mode 100644 index 0000000..ebf20cc --- /dev/null +++ b/lib/DDHidJoystick.h @@ -0,0 +1,132 @@ +/* + * 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 <Cocoa/Cocoa.h> +#import "DDHidDevice.h" + +@class DDHidElement; +@class DDHidQueue; + +@interface DDHidJoystickStick : NSObject +{ +    DDHidElement * mXAxisElement; +    DDHidElement * mYAxisElement; +    NSMutableArray * mStickElements; +    // Point of view elements (i.e. hat switches) +    NSMutableArray * mPovElements; +} + +- (DDHidElement *) xAxisElement; + +- (DDHidElement *) yAxisElement; + +#pragma mark - +#pragma mark StickElements - indexed accessors + +- (unsigned int) countOfStickElements; +- (DDHidElement *) objectInStickElementsAtIndex: (unsigned int)index; + +#pragma mark - +#pragma mark PovElements - indexed accessors + +- (unsigned int) countOfPovElements; +- (DDHidElement *) objectInPovElementsAtIndex: (unsigned int)index; + +- (NSArray *) allElements; + +-  (BOOL) addElement: (DDHidElement *) element; + +@end + +@interface DDHidJoystick : DDHidDevice +{ +    NSMutableArray * mSticks; +    NSMutableArray * mButtonElements; +    NSMutableArray * mLogicalDeviceElements; + +    id mDelegate; +} + ++ (NSArray *) allJoysticks; + +- (id) initLogicalWithDevice: (io_object_t) device  +         logicalDeviceNumber: (int) logicalDeviceNumber  +                       error: (NSError **) error; + +- (int) logicalDeviceCount; + +#pragma mark - +#pragma mark Joystick Elements + +- (unsigned) numberOfButtons; + +- (NSArray *) buttonElements; + +#pragma mark - +#pragma mark Sticks - indexed accessors + +- (unsigned int) countOfSticks; +- (DDHidJoystickStick *) objectInSticksAtIndex: (unsigned int)index; + +- (void) addElementsToQueue: (DDHidQueue *) queue; + +#pragma mark - +#pragma mark Asynchronous Notification + +- (void) setDelegate: (id) delegate; + +- (void) addElementsToDefaultQueue; + +@end + +#define DDHID_JOYSTICK_VALUE_MIN -65536 +#define DDHID_JOYSTICK_VALUE_MAX 65536 + +@interface NSObject (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 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 diff --git a/lib/DDHidKeyboard.h b/lib/DDHidKeyboard.h new file mode 100644 index 0000000..fd9200d --- /dev/null +++ b/lib/DDHidKeyboard.h @@ -0,0 +1,68 @@ +/* + * 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 <Cocoa/Cocoa.h> +#import "DDHidDevice.h" + +@class DDHidElement; +@class DDHidQueue; + +@interface DDHidKeyboard : DDHidDevice +{ +    NSMutableArray * mKeyElements; +     +    id mDelegate; +} + ++ (NSArray *) allKeyboards; + +- (id) initWithDevice: (io_object_t) device error: (NSError **) error_; + +#pragma mark - +#pragma mark Keyboards Elements + +- (NSArray *) keyElements; + +- (unsigned) numberOfKeys; + +- (void) addElementsToQueue: (DDHidQueue *) queue; + +#pragma mark - +#pragma mark Asynchronous Notification + +- (void) setDelegate: (id) delegate; + +- (void) addElementsToDefaultQueue; + +@end + +@interface NSObject (DDHidKeyboardDelegate) + +- (void) ddhidKeyboard: (DDHidKeyboard *) keyboard +               keyDown: (unsigned) usageId; + +- (void) ddhidKeyboard: (DDHidKeyboard *) keyboard +                 keyUp: (unsigned) usageId; + +@end diff --git a/lib/DDHidKeyboard.m b/lib/DDHidKeyboard.m new file mode 100644 index 0000000..7e37264 --- /dev/null +++ b/lib/DDHidKeyboard.m @@ -0,0 +1,173 @@ +/* + * 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 "DDHidKeyboard.h" +#import "DDHidElement.h" +#import "DDHidUsage.h" +#import "DDHidQueue.h" +#import "DDHidEvent.h" +#include <IOKit/hid/IOHIDUsageTables.h> + +@interface DDHidKeyboard (DDHidKeyboardDelegate) + +- (void) ddhidKeyboard: (DDHidKeyboard *) keyboard +               keyDown: (unsigned) usageId; + +- (void) ddhidKeyboard: (DDHidKeyboard *) keyboard +                 keyUp: (unsigned) usageId; + +@end + +@interface DDHidKeyboard (Private) + +- (void) initKeyboardElements: (NSArray *) elements; +- (void) ddhidQueueHasEvents: (DDHidQueue *) hidQueue; + +@end + +@implementation DDHidKeyboard + ++ (NSArray *) allKeyboards; +{ +    return +        [DDHidDevice allDevicesMatchingUsagePage: kHIDPage_GenericDesktop +                                         usageId: kHIDUsage_GD_Keyboard +                                       withClass: self +                               skipZeroLocations: YES]; +} + +- (id) initWithDevice: (io_object_t) device error: (NSError **) error_; +{ +    self = [super initWithDevice: device error: error_]; +    if (self == nil) +        return nil; +     +    mKeyElements = [[NSMutableArray alloc] init]; +    [self initKeyboardElements: [self elements]]; +     +    return self; +} + +//===========================================================  +// dealloc +//===========================================================  +- (void) dealloc +{ +    [mKeyElements release]; +     +    mKeyElements = nil; +    [super dealloc]; +} + +#pragma mark - +#pragma mark Keyboards Elements + +- (NSArray *) keyElements; +{ +    return mKeyElements; +} + +- (unsigned) numberOfKeys; +{ +    return [mKeyElements count]; +} + +- (void) addElementsToQueue: (DDHidQueue *) queue; +{ +    [queue addElements: mKeyElements]; +} + +#pragma mark - +#pragma mark Asynchronous Notification + +- (void) setDelegate: (id) delegate; +{ +    mDelegate = delegate; +} + +- (void) addElementsToDefaultQueue; +{ +    [self addElementsToQueue: mDefaultQueue]; +} + +@end + +@implementation DDHidKeyboard (DDHidKeyboardDelegate) + +- (void) ddhidKeyboard: (DDHidKeyboard *) keyboard +               keyDown: (unsigned) usageId; +{ +    if ([mDelegate respondsToSelector: _cmd]) +        [mDelegate ddhidKeyboard: keyboard keyDown: usageId]; +} + +- (void) ddhidKeyboard: (DDHidKeyboard *) keyboard +                 keyUp: (unsigned) usageId; +{ +    if ([mDelegate respondsToSelector: _cmd]) +        [mDelegate ddhidKeyboard: keyboard keyUp: usageId]; +} + +@end + +@implementation DDHidKeyboard (Private) + +- (void) initKeyboardElements: (NSArray *) elements; +{ +    NSEnumerator * e = [elements objectEnumerator]; +    DDHidElement * element; +    while (element = [e nextObject]) +    { +        unsigned usagePage = [[element usage] usagePage]; +        unsigned usageId = [[element usage] usageId]; +        if (usagePage == kHIDPage_KeyboardOrKeypad) +        { +            if ((usageId >= 0x04) && (usageId <= 0xA4) || +                (usageId >= 0xE0) && (usageId <= 0xE7)) +            { +                [mKeyElements addObject: element]; +            } +        } +        NSArray * subElements = [element elements]; +        if (subElements != nil) +            [self initKeyboardElements: subElements]; +    } +} + +- (void) ddhidQueueHasEvents: (DDHidQueue *) hidQueue; +{ +    DDHidEvent * event; +    while (event = [hidQueue nextEvent]) +    { +        DDHidElement * element = [self elementForCookie: [event elementCookie]]; +        unsigned usageId = [[element usage] usageId]; +        SInt32 value = [event value]; +        if (value == 1) +            [self ddhidKeyboard: self keyDown: usageId]; +        else +            [self ddhidKeyboard: self keyUp: usageId]; +    } +} + +@end diff --git a/lib/DDHidKeyboardBarcodeScanner.h b/lib/DDHidKeyboardBarcodeScanner.h new file mode 100644 index 0000000..8504343 --- /dev/null +++ b/lib/DDHidKeyboardBarcodeScanner.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2007 Dave Dribin, Lucas Newman + *  + * 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 <Cocoa/Cocoa.h> +#import "DDHidDevice.h" + +@class DDHidElement; +@class DDHidQueue; + +@interface DDHidKeyboardBarcodeScanner : DDHidDevice +{ +    NSMutableArray * mKeyElements; +     +    NSMutableString * mAccumulatedDigits; +    NSTimer *mBarcodeInputTimer; +    BOOL mIsLikelyKeyboardBarcodeScanner; +     +    id mDelegate; +} + ++ (NSArray *) allPossibleKeyboardBarcodeScanners; + +- (id) initWithDevice: (io_object_t) device error: (NSError **) error_; + +#pragma mark - +#pragma mark Keyboard Elements + +- (NSArray *) keyElements; + +- (unsigned) numberOfKeys; + +- (void) addElementsToQueue: (DDHidQueue *) queue; + +#pragma mark - +#pragma mark Asynchronous Notification + +- (void) setDelegate: (id) delegate; + +- (void) addElementsToDefaultQueue; + +#pragma mark - +#pragma mark Properties + +- (BOOL) isLikelyKeyboardBarcodeScanner; + +@end + +@interface NSObject (DDHidKeyboardBarcodeScannerDelegate) + +- (void) ddhidKeyboardBarcodeScanner: (DDHidKeyboardBarcodeScanner *) keyboardBarcodeScanner +                          gotBarcode: (NSString *) barcode; + +@end diff --git a/lib/DDHidKeyboardBarcodeScanner.m b/lib/DDHidKeyboardBarcodeScanner.m new file mode 100644 index 0000000..8705cf3 --- /dev/null +++ b/lib/DDHidKeyboardBarcodeScanner.m @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2007 Dave Dribin, Lucas Newman + *  + * 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 "DDHidKeyboardBarcodeScanner.h" +#import "DDHidElement.h" +#import "DDHidUsage.h" +#import "DDHidQueue.h" +#import "DDHidEvent.h" +#include <IOKit/hid/IOHIDUsageTables.h> + +@interface DDHidKeyboardBarcodeScanner (DDHidKeyboardBarcodeDelegate) + +- (void) ddhidKeyboardBarcodeScanner: (DDHidKeyboardBarcodeScanner *) keyboardBarcodeScanner +                          gotBarcode: (NSString *) barcode; + +@end + +@interface DDHidKeyboardBarcodeScanner (Private) + +- (void) initKeyboardElements: (NSArray *) elements; +- (void) ddhidQueueHasEvents: (DDHidQueue *) hidQueue; +- (void) processBarcodeDigit: (unsigned) usageId; +- (void) clearAccumulatedInput; +- (void) invalidateBarcodeInputTimer; + +@end + +@implementation DDHidKeyboardBarcodeScanner + ++ (NSArray *) allPossibleKeyboardBarcodeScanners; +{ +    return [DDHidDevice allDevicesMatchingUsagePage: kHIDPage_GenericDesktop +                                            usageId: kHIDUsage_GD_Keyboard +                                          withClass: self +                                  skipZeroLocations: YES]; +} + +- (id) initWithDevice: (io_object_t) device error: (NSError **) error_; +{ +    self = [super initWithDevice: device error: error_]; +    if (self == nil) +        return nil; +     +    mKeyElements = [[NSMutableArray alloc] init]; +    mAccumulatedDigits = [[NSMutableString alloc] init]; +    mBarcodeInputTimer = nil; +     +    if ([[self productName] rangeOfString:@"Apple"].location != NSNotFound || [[self productName] rangeOfString:@"Internal"].location != NSNotFound) +        mIsLikelyKeyboardBarcodeScanner = NO; +    else +        mIsLikelyKeyboardBarcodeScanner = YES; // if we see invalid barcodes, we can change our mind +     +    [self initKeyboardElements: [self elements]]; +     +    return self; +} + +//===========================================================  +// dealloc +//===========================================================  +- (void) dealloc +{ +    [self invalidateBarcodeInputTimer]; +    [mKeyElements release]; +    [mAccumulatedDigits release]; +     +    mKeyElements = nil; +    mAccumulatedDigits = nil; +    [super dealloc]; +} + +#pragma mark - +#pragma mark Keyboard Elements + +- (NSArray *) keyElements; +{ +    return mKeyElements; +} + +- (unsigned) numberOfKeys; +{ +    return [mKeyElements count]; +} + +- (void) addElementsToQueue: (DDHidQueue *) queue; +{ +    [queue addElements: mKeyElements]; +} + +#pragma mark - +#pragma mark Asynchronous Notification + +- (void) setDelegate: (id) delegate; +{ +    mDelegate = delegate; +} + +- (void) addElementsToDefaultQueue; +{ +    [self addElementsToQueue: mDefaultQueue]; +} + +#pragma mark - +#pragma mark Properties + +- (BOOL) isLikelyKeyboardBarcodeScanner; +{ +    return mIsLikelyKeyboardBarcodeScanner; +} + +@end + +@implementation DDHidKeyboardBarcodeScanner (DDHidKeyboardDelegate) + +- (void) ddhidKeyboardBarcodeScanner: (DDHidKeyboardBarcodeScanner *) keyboardBarcodeScanner +                          gotBarcode: (NSString *) barcode; +{ +    if ([mDelegate respondsToSelector: _cmd]) +        [mDelegate ddhidKeyboardBarcodeScanner: keyboardBarcodeScanner gotBarcode: barcode]; +} + +@end + +@implementation DDHidKeyboardBarcodeScanner (Private) + +- (void) initKeyboardElements: (NSArray *) elements; +{ +    NSEnumerator * e = [elements objectEnumerator]; +    DDHidElement * element; +    while ((element = [e nextObject])) +    { +        unsigned usagePage = [[element usage] usagePage]; +        unsigned usageId = [[element usage] usageId]; +        if (usagePage == kHIDPage_KeyboardOrKeypad) +        { +            if ((usageId >= kHIDUsage_KeyboardA) && (usageId <= kHIDUsage_Keyboard0)) +            { +                [mKeyElements addObject: element]; +            } +        } +        NSArray * subElements = [element elements]; +        if (subElements != nil) +            [self initKeyboardElements: subElements]; +    } +} + +- (void) ddhidQueueHasEvents: (DDHidQueue *) hidQueue; +{ +    DDHidEvent * event; +    while ((event = [hidQueue nextEvent])) +    { +        DDHidElement * element = [self elementForCookie: [event elementCookie]]; +        unsigned usageId = [[element usage] usageId]; +        SInt32 value = [event value]; +        if (value == 1) // key down +            [self processBarcodeDigit: usageId]; +    } +} + +#define UPC_A_BARCODE_LENGTH (12) +#define BARCODE_INPUT_TIMEOUT (0.5) +    +- (void) processBarcodeDigit: (unsigned) usageId; +{ +    if (usageId <= kHIDUsage_KeyboardZ || usageId >= kHIDUsage_KeyboardCapsLock) { // an alphabetic key was pressed => probably not a barcode scanner +        [self willChangeValueForKey:@"isLikelyKeyboardBarcodeScanner"]; +        mIsLikelyKeyboardBarcodeScanner = NO; +        [self didChangeValueForKey:@"isLikelyKeyboardBarcodeScanner"]; +         +        [self clearAccumulatedInput]; +        return; +    } +     +    if (!mBarcodeInputTimer) // schedule a timer to make sure we get the rest of the digits in a timely manner +        mBarcodeInputTimer = [[NSTimer scheduledTimerWithTimeInterval:BARCODE_INPUT_TIMEOUT target:self selector:@selector(fireBarcodeInputTimeout:) userInfo:nil repeats:NO] retain]; +     +    [mAccumulatedDigits appendString:[NSString stringWithFormat:@"%d", (usageId + 1) % 10]]; +} + +- (void) fireBarcodeInputTimeout: (NSTimer *) timer; +{ +    if ([mAccumulatedDigits length] >= UPC_A_BARCODE_LENGTH) +        [self ddhidKeyboardBarcodeScanner: self gotBarcode: [[mAccumulatedDigits copy] autorelease]]; +    [self clearAccumulatedInput]; +} + +- (void) clearAccumulatedInput; +{ +    [mAccumulatedDigits deleteCharactersInRange:NSMakeRange(0, [mAccumulatedDigits length])]; +     +    [self invalidateBarcodeInputTimer]; +} + +- (void) invalidateBarcodeInputTimer; +{ +    [mBarcodeInputTimer invalidate]; +    [mBarcodeInputTimer release]; +    mBarcodeInputTimer = nil; +} + +@end diff --git a/lib/DDHidLib.h b/lib/DDHidLib.h new file mode 100644 index 0000000..20d8681 --- /dev/null +++ b/lib/DDHidLib.h @@ -0,0 +1,36 @@ +/* + * 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 "DDHidDevice.h" +#import "DDHidElement.h" +#import "DDHidUsage.h" +#import "DDHidQueue.h" +#import "DDHidEvent.h" +#import "DDHidUsageTables.h" +#import "DDHidMouse.h" +#import "DDHidJoystick.h" +#import "DDHidKeyboard.h" +#import "DDHidAppleRemote.h" +#import "DDHidAppleMikey.h" +#import "DDHidKeyboardBarcodeScanner.h" diff --git a/lib/DDHidMouse.h b/lib/DDHidMouse.h new file mode 100644 index 0000000..d396aba --- /dev/null +++ b/lib/DDHidMouse.h @@ -0,0 +1,78 @@ +/* + * 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 <Cocoa/Cocoa.h> +#import "DDHidDevice.h" + +@class DDHidElement; +@class DDHidQueue; + +@interface DDHidMouse : DDHidDevice +{ +    DDHidElement * mXElement; +    DDHidElement * mYElement; +    DDHidElement * mWheelElement; +    NSMutableArray * mButtonElements; +     +    id mDelegate; +} + ++ (NSArray *) allMice; + +- (id) initWithDevice: (io_object_t) device error: (NSError **) error_; + +#pragma mark - +#pragma mark Mouse Elements + +- (DDHidElement *) xElement; + +- (DDHidElement *) yElement; + +- (DDHidElement *) wheelElement; + +- (NSArray *) buttonElements; + +- (unsigned) numberOfButtons; + +- (void) addElementsToQueue: (DDHidQueue *) queue; + +#pragma mark - +#pragma mark Asynchronous Notification + +- (void) setDelegate: (id) delegate; + +- (void) addElementsToDefaultQueue; + +@end + +@interface NSObject (DDHidMouseDelegate) + +- (void) ddhidMouse: (DDHidMouse *) mouse xChanged: (SInt32) deltaX; +- (void) ddhidMouse: (DDHidMouse *) mouse yChanged: (SInt32) deltaY; +- (void) ddhidMouse: (DDHidMouse *) mouse wheelChanged: (SInt32) deltaWheel; +- (void) ddhidMouse: (DDHidMouse *) mouse buttonDown: (unsigned) buttonNumber; +- (void) ddhidMouse: (DDHidMouse *) mouse buttonUp: (unsigned) buttonNumber; + +@end + diff --git a/lib/DDHidMouse.m b/lib/DDHidMouse.m new file mode 100644 index 0000000..7eeb5b3 --- /dev/null +++ b/lib/DDHidMouse.m @@ -0,0 +1,279 @@ +/* + * 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 "DDHidMouse.h" +#import "DDHidUsage.h" +#import "DDHidElement.h" +#import "DDHidQueue.h" +#import "DDHidEvent.h" +#include <IOKit/hid/IOHIDUsageTables.h> + + +// Implement our own delegate methods + +@interface DDHidMouse (DDHidMouseDelegate) + +- (void) ddhidMouse: (DDHidMouse *) mouse xChanged: (SInt32) deltaX; +- (void) ddhidMouse: (DDHidMouse *) mouse yChanged: (SInt32) deltaY; +- (void) ddhidMouse: (DDHidMouse *) mouse wheelChanged: (SInt32) deltaWheel; +- (void) ddhidMouse: (DDHidMouse *) mouse buttonDown: (unsigned) buttonNumber; +- (void) ddhidMouse: (DDHidMouse *) mouse buttonUp: (unsigned) buttonNumber; + +@end + +@interface DDHidMouse (Private) + +- (void) initMouseElements: (NSArray *) elements; +- (void) ddhidQueueHasEvents: (DDHidQueue *) hidQueue; + +@end + +@implementation DDHidMouse + ++ (NSArray *) allMice; +{ +    return +        [DDHidDevice allDevicesMatchingUsagePage: kHIDPage_GenericDesktop +                                         usageId: kHIDUsage_GD_Mouse +                                       withClass: self +                               skipZeroLocations: YES]; +} + +- (id) initWithDevice: (io_object_t) device error: (NSError **) error_; +{ +    self = [super initWithDevice: device error: error_]; +    if (self == nil) +        return nil; +     +    mXElement = mYElement = mWheelElement = nil; +    mButtonElements = [[NSMutableArray alloc] init]; +    [self initMouseElements: [self elements]]; +     +    return self; +} + +//===========================================================  +// dealloc +//===========================================================  +- (void) dealloc +{ +    [mXElement release]; +    [mYElement release]; +    [mWheelElement release]; +    [mButtonElements release]; +     +    mXElement = nil; +    mYElement = nil; +    mWheelElement = nil; +    mButtonElements = nil; +    [super dealloc]; +} + +#pragma mark - +#pragma mark Mouse Elements + +//===========================================================  +// - xElement +//===========================================================  +- (DDHidElement *) xElement +{ +    return mXElement;  +} + +//===========================================================  +// - yElement +//===========================================================  +- (DDHidElement *) yElement +{ +    return mYElement;  +} + +- (DDHidElement *) wheelElement; +{ +    return mWheelElement; +} + +//===========================================================  +// - buttonElements +//===========================================================  +- (NSArray *) buttonElements; +{ +    return mButtonElements;  +} + +- (unsigned) numberOfButtons; +{ +    return [mButtonElements count]; +} + +- (void) addElementsToQueue: (DDHidQueue *) queue; +{ +    [queue addElement: mXElement]; +    [queue addElement: mYElement]; +    [queue addElement: mWheelElement]; +    [queue addElements: mButtonElements]; +} + + +#pragma mark - +#pragma mark Asynchronous Notification + +- (void) setDelegate: (id) delegate; +{ +    mDelegate = delegate; +} + +- (void) addElementsToDefaultQueue; +{ +    [self addElementsToQueue: mDefaultQueue]; +} + +@end + +@implementation DDHidMouse (DDHidMouseDelegate) + +- (void) ddhidMouse: (DDHidMouse *) mouse xChanged: (SInt32) deltaX; +{ +    if ([mDelegate respondsToSelector: _cmd]) +        [mDelegate ddhidMouse: mouse xChanged: deltaX]; +} + +- (void) ddhidMouse: (DDHidMouse *) mouse yChanged: (SInt32) deltaY; +{ +    if ([mDelegate respondsToSelector: _cmd]) +        [mDelegate ddhidMouse: mouse yChanged: deltaY]; +} + +- (void) ddhidMouse: (DDHidMouse *) mouse wheelChanged: (SInt32) deltaWheel; +{ +    if ([mDelegate respondsToSelector: _cmd]) +        [mDelegate ddhidMouse: mouse wheelChanged: deltaWheel]; +} + +- (void) ddhidMouse: (DDHidMouse *) mouse buttonDown: (unsigned) buttonNumber; +{ +    if ([mDelegate respondsToSelector: _cmd]) +        [mDelegate ddhidMouse: mouse buttonDown: buttonNumber]; +} + +- (void) ddhidMouse: (DDHidMouse *) mouse buttonUp: (unsigned) buttonNumber; +{ +    if ([mDelegate respondsToSelector: _cmd]) +        [mDelegate ddhidMouse: mouse buttonUp: buttonNumber]; +} + +@end + +@implementation DDHidMouse (Private) + +- (void) initMouseElements: (NSArray *) elements; +{ +    NSEnumerator * e = [elements objectEnumerator]; +    DDHidElement * element; +    while (element = [e nextObject]) +    { +        unsigned usagePage = [[element usage] usagePage]; +        unsigned usageId = [[element usage] usageId]; +        if ((usagePage == kHIDPage_GenericDesktop) && +            (usageId == kHIDUsage_GD_X)) +        { +            mXElement = [element retain]; +        } +        else if ((usagePage == kHIDPage_GenericDesktop) && +                 (usageId == kHIDUsage_GD_Y)) +        { +            mYElement = [element retain]; +        } +        else if ((usagePage == kHIDPage_GenericDesktop) && +                 (usageId == kHIDUsage_GD_Wheel)) +        { +            mWheelElement = [element retain]; +        } +        else if ((usagePage == kHIDPage_Button) && +                 (usageId > 0)) +        { +            [mButtonElements addObject: element]; +        } +        NSArray * subElements = [element elements]; +        if (subElements != nil) +            [self initMouseElements: subElements]; +    } +} + +- (void) ddhidQueueHasEvents: (DDHidQueue *) hidQueue; +{ +    DDHidEvent * event; +    while (event = [hidQueue nextEvent]) +    { +        IOHIDElementCookie cookie = [event elementCookie]; +        SInt32 value = [event value]; +        if (cookie == [[self xElement] cookie]) +        { +            if (value != 0) +            { +                [self ddhidMouse: self xChanged: value]; +            } +        } +        else if (cookie == [[self yElement] cookie]) +        { +            if (value != 0) +            { +                [self ddhidMouse: self yChanged: value]; +            } +        } +        else if (cookie == [[self wheelElement] cookie]) +        { +            if (value != 0) +            { +                [self ddhidMouse: self wheelChanged: value]; +            } +        } +        else +        { +            unsigned i = 0; +            for (i = 0; i < [[self buttonElements] count]; i++) +            { +                if (cookie == [[[self buttonElements] objectAtIndex: i] cookie]) +                    break; +            } +             +            if (value == 1) +            { +                [self ddhidMouse: self buttonDown: i]; +            } +            else if (value == 0) +            { +                [self ddhidMouse: self buttonUp: i]; +            } +            else +            { +                DDHidElement * element = [self elementForCookie: [event elementCookie]]; +                NSLog(@"Element: %@, value: %d", [[element usage] usageName], [event value]); +            } +        } +    } +} + +@end + diff --git a/lib/DDHidQueue.h b/lib/DDHidQueue.h new file mode 100644 index 0000000..315d003 --- /dev/null +++ b/lib/DDHidQueue.h @@ -0,0 +1,70 @@ +/* + * 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 <Cocoa/Cocoa.h> +#include <IOKit/hid/IOHIDLib.h> + +@class DDHidElement; +@class DDHidEvent; + +@interface DDHidQueue : NSObject +{ +    IOHIDQueueInterface ** mQueue; +    NSRunLoop * mRunLoop; +    BOOL mStarted; +     +    id mDelegate; +    CFRunLoopSourceRef mEventSource; +} + +- (id) initWithHIDQueue: (IOHIDQueueInterface **) queue +                   size: (unsigned) size; + +- (void) addElement: (DDHidElement *) element; + +- (void) addElements: (NSArray *) elements; + +- (void) addElements: (NSArray *) elements recursively: (BOOL) recursively; + +- (void) setDelegate: (id) delegate; + +- (void) startOnCurrentRunLoop; + +- (void) startOnRunLoop: (NSRunLoop *) runLoop; + +- (void) stop; + +- (BOOL) isStarted; + +- (BOOL) getNextEvent: (IOHIDEventStruct *) event; + +- (DDHidEvent *) nextEvent; + +@end + +@interface NSObject (DDHidQueueDelegate) + +- (void) ddhidQueueHasEvents: (DDHidQueue *) hidQueue; + +@end diff --git a/lib/DDHidQueue.m b/lib/DDHidQueue.m new file mode 100644 index 0000000..8f44698 --- /dev/null +++ b/lib/DDHidQueue.m @@ -0,0 +1,172 @@ +/* + * 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 "DDHidQueue.h" +#import "DDHidElement.h" +#import "DDHIdEvent.h" +#import "NSXReturnThrowError.h" + +static void queueCallbackFunction(void* target,  IOReturn result, void* refcon, +                                  void* sender); + +@interface DDHidQueue (Private) + +- (void) handleQueueCallback; + +@end + +@implementation DDHidQueue + +- (id) initWithHIDQueue: (IOHIDQueueInterface **) queue +                   size: (unsigned) size; +{ +    self = [super init]; +    if (self == nil) +        return nil; +     +    mQueue = queue; +    IOReturn result = (*mQueue)->create(mQueue, 0, size); +    if (result != kIOReturnSuccess) +    { +        [self release]; +        return nil; +    } +      +    return self; +} + +- (void) dealloc; +{ +    [self stop]; +    (*mQueue)->dispose(mQueue); +    (*mQueue)->Release(mQueue); +    [super dealloc]; +} + +- (void) addElement: (DDHidElement *) element; +{ +    IOHIDElementCookie cookie = [element cookie]; +    (*mQueue)->addElement(mQueue, cookie, 0); +} + +- (void) addElements: (NSArray *) elements; +{ +    return [self addElements: elements recursively: NO]; +} + +- (void) addElements: (NSArray *) elements recursively: (BOOL) recursively; +{ +    NSEnumerator * e = [elements objectEnumerator]; +    DDHidElement * element; +    while (element = [e nextObject]) +    { +        [self addElement: element]; +        if (recursively) +            [self addElements: [element elements]]; +    } +} + +- (void) setDelegate: (id) delegate; +{ +    mDelegate = delegate; +} + +- (void) startOnCurrentRunLoop; +{ +    [self startOnRunLoop: [NSRunLoop currentRunLoop]]; +} + +- (void) startOnRunLoop: (NSRunLoop *) runLoop; +{ +    if (mStarted) +        return; +     +    mRunLoop = [runLoop retain]; +     +    NSXThrowError((*mQueue)->createAsyncEventSource(mQueue, &mEventSource)); +    NSXThrowError((*mQueue)->setEventCallout(mQueue, queueCallbackFunction, self, NULL)); +    CFRunLoopAddSource([mRunLoop getCFRunLoop], mEventSource, +                       kCFRunLoopDefaultMode); +    (*mQueue)->start(mQueue); +    mStarted = YES; +} + +- (void) stop; +{ +    if (!mStarted) +        return; +     +    CFRunLoopRemoveSource([mRunLoop getCFRunLoop], mEventSource, kCFRunLoopDefaultMode); +    (*mQueue)->stop(mQueue); +    [mRunLoop release]; +    mRunLoop = nil; +    mStarted = NO; +} + +- (BOOL) isStarted; +{ +    return mStarted; +} + +- (BOOL) getNextEvent: (IOHIDEventStruct *) event; +{ +    AbsoluteTime zeroTime = {0, 0}; +    IOReturn result = (*mQueue)->getNextEvent(mQueue, event, zeroTime, 0); +    return (result == kIOReturnSuccess); +} + +- (DDHidEvent *) nextEvent; +{ +    AbsoluteTime zeroTime = {0, 0}; +    IOHIDEventStruct event; +    IOReturn result = (*mQueue)->getNextEvent(mQueue, &event, zeroTime, 0); +    if (result != kIOReturnSuccess) +        return nil; +    else +        return [DDHidEvent eventWithIOHIDEvent: &event]; +} + +@end + +@implementation DDHidQueue (Private) + +- (void) handleQueueCallback; +{ +    if ([mDelegate respondsToSelector: @selector(ddhidQueueHasEvents:)]) +    { +        [mDelegate ddhidQueueHasEvents: self]; +    } +} + +@end + +static void queueCallbackFunction(void* target,  IOReturn result, void* refcon, +                                  void* sender) +{ +    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; +    DDHidQueue * queue = (DDHidQueue *) target; +    [queue handleQueueCallback]; +    [pool release]; +     +} diff --git a/lib/DDHidStandardUsages.plist b/lib/DDHidStandardUsages.plist new file mode 100644 index 0000000..84eb663 --- /dev/null +++ b/lib/DDHidStandardUsages.plist @@ -0,0 +1,2327 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> +<plist version="1.0"> +  <dict> +    <key>1</key> +    <dict> +      <key>description</key> +      <string>Generic Desktop</string> +      <key>ranges</key> +      <dict> +      </dict> +      <key>usages</key> +      <dict> +        <key>0</key> +        <string>Undefined</string> +        <key>1</key> +        <string>Pointer</string> +        <key>2</key> +        <string>Mouse</string> +        <key>3</key> +        <string>Reserved</string> +        <key>4</key> +        <string>Joystick</string> +        <key>5</key> +        <string>Game Pad</string> +        <key>6</key> +        <string>Keyboard</string> +        <key>7</key> +        <string>Keypad</string> +        <key>8</key> +        <string>Multi-axis Controller</string> +        <key>48</key> +        <string>X</string> +        <key>49</key> +        <string>Y</string> +        <key>50</key> +        <string>Z</string> +        <key>51</key> +        <string>Rx</string> +        <key>52</key> +        <string>Ry</string> +        <key>53</key> +        <string>Rz</string> +        <key>54</key> +        <string>Slider</string> +        <key>55</key> +        <string>Dial</string> +        <key>56</key> +        <string>Wheel</string> +        <key>57</key> +        <string>Hat Switch</string> +        <key>58</key> +        <string>Counted Buffer</string> +        <key>59</key> +        <string>Byte Count</string> +        <key>60</key> +        <string>Motion Wakeup</string> +        <key>64</key> +        <string>Vx</string> +        <key>65</key> +        <string>Vy</string> +        <key>66</key> +        <string>Vz</string> +        <key>67</key> +        <string>Vbrx</string> +        <key>68</key> +        <string>Vbry</string> +        <key>69</key> +        <string>Vbrx</string> +        <key>70</key> +        <string>Vno</string> +        <key>128</key> +        <string>System Control</string> +        <key>129</key> +        <string>System Power Down</string> +        <key>130</key> +        <string>System Sleep</string> +        <key>131</key> +        <string>System Wake Up</string> +        <key>132</key> +        <string>System Context Menu</string> +        <key>133</key> +        <string>System Main Menu</string> +        <key>134</key> +        <string>System App Menu</string> +        <key>135</key> +        <string>System Menu Help</string> +        <key>136</key> +        <string>System Menu Exit</string> +        <key>137</key> +        <string>System Menu Select</string> +        <key>138</key> +        <string>System Menu Right</string> +        <key>139</key> +        <string>System Menu Left</string> +        <key>140</key> +        <string>System Menu Up</string> +        <key>141</key> +        <string>System Menu Down</string> +        <key>144</key> +        <string>D-pad Up</string> +        <key>145</key> +        <string>D-pad Down</string> +        <key>146</key> +        <string>D-pad Right</string> +        <key>147</key> +        <string>D-pad Left</string> +      </dict> +    </dict> +    <key>2</key> +    <dict> +      <key>description</key> +      <string>Simulation Controls</string> +      <key>ranges</key> +      <dict> +      </dict> +      <key>usages</key> +      <dict> +        <key>0</key> +        <string>Undefined</string> +        <key>1</key> +        <string>Flight Simulation Device</string> +        <key>2</key> +        <string>Automobile Simulation Device</string> +        <key>3</key> +        <string>Tank Simulation Device</string> +        <key>4</key> +        <string>Spaceship Simulation Device</string> +        <key>5</key> +        <string>Submarine Simulation Device</string> +        <key>6</key> +        <string>Sailing Simulation Device</string> +        <key>7</key> +        <string>Motorcycle Simulation Device</string> +        <key>8</key> +        <string>Sports Simulation Device</string> +        <key>9</key> +        <string>Airplane Simulation Device</string> +        <key>10</key> +        <string>Helicopter Simulation Device</string> +        <key>11</key> +        <string>Magic Carpet Simulation Device</string> +        <key>12</key> +        <string>Bicycle</string> +        <key>32</key> +        <string>Flight Control Stick</string> +        <key>33</key> +        <string>Flight Stick</string> +        <key>34</key> +        <string>Cyclic Control</string> +        <key>35</key> +        <string>Cyclic Trim</string> +        <key>36</key> +        <string>Flight Yoke</string> +        <key>37</key> +        <string>Track Control</string> +        <key>38</key> +        <string>Driving Control</string> +        <key>176</key> +        <string>Aileron</string> +        <key>177</key> +        <string>Aileron Trim</string> +        <key>178</key> +        <string>Anti-Torque Control</string> +        <key>179</key> +        <string>Auto-pilot Enable</string> +        <key>180</key> +        <string>Chaff Release</string> +        <key>181</key> +        <string>Collective Control</string> +        <key>182</key> +        <string>Dive Brake</string> +        <key>183</key> +        <string>Electronic Counter Measures</string> +        <key>184</key> +        <string>Elevator</string> +        <key>185</key> +        <string>Elevator Trim</string> +        <key>186</key> +        <string>Rudder</string> +        <key>187</key> +        <string>Throttle</string> +        <key>188</key> +        <string>Flight Communication</string> +        <key>189</key> +        <string>Flare Release</string> +        <key>190</key> +        <string>Landing Gear</string> +        <key>191</key> +        <string>Toe Brake</string> +        <key>192</key> +        <string>Trigger</string> +        <key>193</key> +        <string>Weapons Arm</string> +        <key>194</key> +        <string>Weapons Select</string> +        <key>195</key> +        <string>Wing Flaps</string> +        <key>196</key> +        <string>Accelerator</string> +        <key>197</key> +        <string>Brake</string> +        <key>198</key> +        <string>Clutch</string> +        <key>199</key> +        <string>Shifter</string> +        <key>200</key> +        <string>Steering</string> +        <key>201</key> +        <string>Turret Direction</string> +        <key>202</key> +        <string>Barrel Elevation</string> +        <key>203</key> +        <string>Dive Plane</string> +        <key>204</key> +        <string>Ballast</string> +        <key>205</key> +        <string>Bicycle Crank</string> +        <key>206</key> +        <string>Handle Bars</string> +        <key>207</key> +        <string>Front Brake</string> +        <key>208</key> +        <string>Rear Brake</string> +      </dict> +    </dict> +    <key>3</key> +    <dict> +      <key>description</key> +      <string>VR Controls</string> +      <key>ranges</key> +      <dict> +      </dict> +      <key>usages</key> +      <dict> +        <key>0</key> +        <string>Unidentified</string> +        <key>1</key> +        <string>Belt</string> +        <key>2</key> +        <string>Body Suit</string> +        <key>3</key> +        <string>Flexor</string> +        <key>4</key> +        <string>Glove</string> +        <key>5</key> +        <string>Head Tracker</string> +        <key>6</key> +        <string>Head Mounted Display</string> +        <key>7</key> +        <string>Hand Tracker</string> +        <key>8</key> +        <string>Oculometer</string> +        <key>9</key> +        <string>Vest</string> +        <key>10</key> +        <string>Animatronic Device</string> +        <key>32</key> +        <string>Stereo Enable</string> +        <key>33</key> +        <string>Display Enable</string> +      </dict> +    </dict> +    <key>4</key> +    <dict> +      <key>description</key> +      <string>Sports Controls</string> +      <key>ranges</key> +      <dict> +      </dict> +      <key>usages</key> +      <dict> +        <key>0</key> +        <string>Unidentified</string> +        <key>1</key> +        <string>Baseball Bat</string> +        <key>2</key> +        <string>Golf Club</string> +        <key>3</key> +        <string>Rowing Machine</string> +        <key>4</key> +        <string>Treadmill</string> +        <key>48</key> +        <string>Oar</string> +        <key>49</key> +        <string>Slope</string> +        <key>50</key> +        <string>Rate</string> +        <key>51</key> +        <string>Stick Speed</string> +        <key>52</key> +        <string>Stick Face Angle</string> +        <key>53</key> +        <string>Stick Heel/Toe</string> +        <key>54</key> +        <string>Stick Follow Through</string> +        <key>55</key> +        <string>Stick Tempo</string> +        <key>56</key> +        <string>Stick Type</string> +        <key>57</key> +        <string>Stick Height</string> +        <key>80</key> +        <string>Putter</string> +        <key>81</key> +        <string>1 Iron</string> +        <key>82</key> +        <string>2 Iron</string> +        <key>83</key> +        <string>3 Iron</string> +        <key>84</key> +        <string>4 Iron</string> +        <key>85</key> +        <string>5 Iron</string> +        <key>86</key> +        <string>6 Iron</string> +        <key>87</key> +        <string>7 Iron</string> +        <key>88</key> +        <string>8 Iron</string> +        <key>89</key> +        <string>9 Iron</string> +        <key>90</key> +        <string>10 Iron</string> +        <key>91</key> +        <string>11 Iron</string> +        <key>92</key> +        <string>Sand Wedge</string> +        <key>93</key> +        <string>Loft Wedge</string> +        <key>94</key> +        <string>Power Wedge</string> +        <key>95</key> +        <string>1 Wood</string> +        <key>96</key> +        <string>3 Wood</string> +        <key>97</key> +        <string>5 Wood</string> +        <key>98</key> +        <string>7 Wood</string> +        <key>99</key> +        <string>9 Wood</string> +      </dict> +    </dict> +    <key>5</key> +    <dict> +      <key>description</key> +      <string>Game Controls</string> +      <key>ranges</key> +      <dict> +      </dict> +      <key>usages</key> +      <dict> +        <key>0</key> +        <string>Undefined</string> +        <key>1</key> +        <string>3D Game Controller</string> +        <key>2</key> +        <string>Pinball Device</string> +        <key>3</key> +        <string>Gun Device</string> +        <key>32</key> +        <string>Point of View</string> +        <key>33</key> +        <string>Turn Right/Left</string> +        <key>34</key> +        <string>Pitch Right/Left</string> +        <key>35</key> +        <string>Roll Forward/Backward</string> +        <key>36</key> +        <string>Move Right/Left</string> +        <key>37</key> +        <string>Move Forward/Backward</string> +        <key>38</key> +        <string>Move Up/Down</string> +        <key>39</key> +        <string>Lean Right/Left</string> +        <key>40</key> +        <string>Lean Forward/Backward</string> +        <key>41</key> +        <string>Height of POV</string> +        <key>42</key> +        <string>Flipper</string> +        <key>43</key> +        <string>Secondary Flipper</string> +        <key>44</key> +        <string>Bump</string> +        <key>45</key> +        <string>New Game</string> +        <key>46</key> +        <string>Shoot Ball</string> +        <key>47</key> +        <string>Player</string> +        <key>48</key> +        <string>Gun Bolt</string> +        <key>49</key> +        <string>Gun Clip</string> +        <key>50</key> +        <string>Gun Selector</string> +        <key>51</key> +        <string>Gun Single Shot</string> +        <key>52</key> +        <string>Gun Burst</string> +        <key>53</key> +        <string>Gun Automatic</string> +        <key>54</key> +        <string>Gun Safety</string> +        <key>55</key> +        <string>Gamepad Fire/Jump</string> +        <key>57</key> +        <string>Gamepad Trigger</string> +      </dict> +    </dict> +    <key>7</key> +    <dict> +      <key>description</key> +      <string>Keyboard</string> +      <key>ranges</key> +      <dict> +      </dict> +      <key>usages</key> +      <dict> +        <key>0</key> +        <string>No Event</string> +        <key>1</key> +        <string>Keyboard ErrorRollOver</string> +        <key>2</key> +        <string>Keyboard POSTFail</string> +        <key>3</key> +        <string>Keyboard ErrorUndefined</string> +        <key>4</key> +        <string>Keyboard a and A</string> +        <key>5</key> +        <string>Keyboard b and B</string> +        <key>6</key> +        <string>Keyboard c and C</string> +        <key>7</key> +        <string>Keyboard d and D</string> +        <key>8</key> +        <string>Keyboard e and E</string> +        <key>9</key> +        <string>Keyboard f and F</string> +        <key>10</key> +        <string>Keyboard g and G</string> +        <key>11</key> +        <string>Keyboard h and H</string> +        <key>12</key> +        <string>Keyboard i and I</string> +        <key>13</key> +        <string>Keyboard j and J</string> +        <key>14</key> +        <string>Keyboard k and K</string> +        <key>15</key> +        <string>Keyboard l and L</string> +        <key>16</key> +        <string>Keyboard m and M</string> +        <key>17</key> +        <string>Keyboard n and N</string> +        <key>18</key> +        <string>Keyboard o and O</string> +        <key>19</key> +        <string>Keyboard p and P</string> +        <key>20</key> +        <string>Keyboard q and Q</string> +        <key>21</key> +        <string>Keyboard r and R</string> +        <key>22</key> +        <string>Keyboard s and S</string> +        <key>23</key> +        <string>Keyboard t and T</string> +        <key>24</key> +        <string>Keyboard u and U</string> +        <key>25</key> +        <string>Keyboard v and V</string> +        <key>26</key> +        <string>Keyboard w and W</string> +        <key>27</key> +        <string>Keyboard x and X</string> +        <key>28</key> +        <string>Keyboard y and Y</string> +        <key>29</key> +        <string>Keyboard z and Z</string> +        <key>30</key> +        <string>Keyboard 1 and !</string> +        <key>31</key> +        <string>Keyboard 2 and @</string> +        <key>32</key> +        <string>Keyboard 3 and #</string> +        <key>33</key> +        <string>Keyboard 4 and $</string> +        <key>34</key> +        <string>Keyboard 5 and %</string> +        <key>35</key> +        <string>Keyboard 6 and ^</string> +        <key>36</key> +        <string>Keyboard 7 and &</string> +        <key>37</key> +        <string>Keyboard 8 and *</string> +        <key>38</key> +        <string>Keyboard 9 and (</string> +        <key>39</key> +        <string>Keyboard 0 and )</string> +        <key>40</key> +        <string>Keyboard Return (ENTER)</string> +        <key>41</key> +        <string>Keyboard ESCAPE</string> +        <key>42</key> +        <string>Keyboard DELETE (Backspace)</string> +        <key>43</key> +        <string>Keyboard Tab</string> +        <key>44</key> +        <string>Keyboard Spacebar</string> +        <key>45</key> +        <string>Keyboard - and (underscore)</string> +        <key>46</key> +        <string>Keyboard = and +</string> +        <key>47</key> +        <string>Keyboard [ and {</string> +        <key>48</key> +        <string>Keyboard ] and }</string> +        <key>49</key> +        <string>Keyboard \ and |</string> +        <key>50</key> +        <string>Keyboard Non-US # and ~</string> +        <key>51</key> +        <string>Keyboard ; and :</string> +        <key>52</key> +        <string>Keyboard ' and "</string> +        <key>53</key> +        <string>Keyboard Grave Accent and Tilde</string> +        <key>54</key> +        <string>Keyboard, and <</string> +        <key>55</key> +        <string>Keyboard . and ></string> +        <key>56</key> +        <string>Keyboard / and ?</string> +        <key>57</key> +        <string>Keyboard Caps Lock</string> +        <key>58</key> +        <string>Keyboard F1</string> +        <key>59</key> +        <string>Keyboard F2</string> +        <key>60</key> +        <string>Keyboard F3</string> +        <key>61</key> +        <string>Keyboard F4</string> +        <key>62</key> +        <string>Keyboard F5</string> +        <key>63</key> +        <string>Keyboard F6</string> +        <key>64</key> +        <string>Keyboard F7</string> +        <key>65</key> +        <string>Keyboard F8</string> +        <key>66</key> +        <string>Keyboard F9</string> +        <key>67</key> +        <string>Keyboard F10</string> +        <key>68</key> +        <string>Keyboard F11</string> +        <key>69</key> +        <string>Keyboard F12</string> +        <key>70</key> +        <string>Keyboard PrintScreen</string> +        <key>71</key> +        <string>Keyboard Scroll Lock</string> +        <key>72</key> +        <string>Keyboard Pause</string> +        <key>73</key> +        <string>Keyboard Insert</string> +        <key>74</key> +        <string>Keyboard Home</string> +        <key>75</key> +        <string>Keyboard PageUp</string> +        <key>76</key> +        <string>Keyboard Delete Forward</string> +        <key>77</key> +        <string>Keyboard End</string> +        <key>78</key> +        <string>Keyboard PageDown</string> +        <key>79</key> +        <string>Keyboard RightArrow</string> +        <key>80</key> +        <string>Keyboard LeftArrow</string> +        <key>81</key> +        <string>Keyboard DownArrow</string> +        <key>82</key> +        <string>Keyboard UpArrow</string> +        <key>83</key> +        <string>Keypad Num Lock and Clear</string> +        <key>84</key> +        <string>Keypad /</string> +        <key>85</key> +        <string>Keypad *</string> +        <key>86</key> +        <string>Keypad -</string> +        <key>87</key> +        <string>Keypad +</string> +        <key>88</key> +        <string>Keypad ENTER</string> +        <key>89</key> +        <string>Keypad 1 and End</string> +        <key>90</key> +        <string>Keypad 2 and Down Arrow</string> +        <key>91</key> +        <string>Keypad 3 and PageDn</string> +        <key>92</key> +        <string>Keypad 4 and Left Arrow</string> +        <key>93</key> +        <string>Keypad 5</string> +        <key>94</key> +        <string>Keypad 6 and Right Arrow</string> +        <key>95</key> +        <string>Keypad 7 and Home</string> +        <key>96</key> +        <string>Keypad 8 and Up Arrow</string> +        <key>97</key> +        <string>Keypad 9 and PageUp</string> +        <key>98</key> +        <string>Keypad 0 and Insert</string> +        <key>99</key> +        <string>Keypad . and Delete</string> +        <key>100</key> +        <string>Keyboard Non-US \ and |</string> +        <key>101</key> +        <string>Keyboard Application</string> +        <key>102</key> +        <string>Keyboard Power</string> +        <key>103</key> +        <string>Keypad =</string> +        <key>104</key> +        <string>Keyboard F13</string> +        <key>105</key> +        <string>Keyboard F14</string> +        <key>106</key> +        <string>Keyboard F15</string> +        <key>107</key> +        <string>Keyboard F16</string> +        <key>108</key> +        <string>Keyboard F17</string> +        <key>109</key> +        <string>Keyboard F18</string> +        <key>110</key> +        <string>Keyboard F19</string> +        <key>111</key> +        <string>Keyboard F20</string> +        <key>112</key> +        <string>Keyboard F21</string> +        <key>113</key> +        <string>Keyboard F22</string> +        <key>114</key> +        <string>Keyboard F23</string> +        <key>115</key> +        <string>Keyboard F24</string> +        <key>116</key> +        <string>Keyboard Execute</string> +        <key>117</key> +        <string>Keyboard Help</string> +        <key>118</key> +        <string>Keyboard Menu</string> +        <key>119</key> +        <string>Keyboard Select</string> +        <key>120</key> +        <string>Keyboard Stop</string> +        <key>121</key> +        <string>Keyboard Again</string> +        <key>122</key> +        <string>Keyboard Undo</string> +        <key>123</key> +        <string>Keyboard Cut</string> +        <key>124</key> +        <string>Keyboard Copy</string> +        <key>125</key> +        <string>Keyboard Paste</string> +        <key>126</key> +        <string>Keyboard Find</string> +        <key>127</key> +        <string>Keyboard Mute</string> +        <key>128</key> +        <string>Keyboard Volume Up</string> +        <key>129</key> +        <string>Keyboard Volume Down</string> +        <key>130</key> +        <string>Keyboard Locking Caps Lock</string> +        <key>131</key> +        <string>Keyboard Locking Num Lock</string> +        <key>132</key> +        <string>Keyboard Locking Scroll Lock</string> +        <key>133</key> +        <string>Keypad Comma</string> +        <key>134</key> +        <string>Keypad Equal Sign</string> +        <key>135</key> +        <string>Keyboard International1</string> +        <key>136</key> +        <string>Keyboard International2</string> +        <key>137</key> +        <string>Keyboard International3</string> +        <key>138</key> +        <string>Keyboard International4</string> +        <key>139</key> +        <string>Keyboard International5</string> +        <key>140</key> +        <string>Keyboard International6</string> +        <key>141</key> +        <string>Keyboard International7</string> +        <key>142</key> +        <string>Keyboard International8</string> +        <key>143</key> +        <string>Keyboard International9</string> +        <key>144</key> +        <string>Keyboard LANG1</string> +        <key>145</key> +        <string>Keyboard LANG2</string> +        <key>146</key> +        <string>Keyboard LANG3</string> +        <key>147</key> +        <string>Keyboard LANG4</string> +        <key>148</key> +        <string>Keyboard LANG5</string> +        <key>149</key> +        <string>Keyboard LANG6</string> +        <key>150</key> +        <string>Keyboard LANG7</string> +        <key>151</key> +        <string>Keyboard LANG8</string> +        <key>152</key> +        <string>Keyboard LANG9</string> +        <key>153</key> +        <string>Keyboard Alternate Erase</string> +        <key>154</key> +        <string>Keyboard SysReq/Attention</string> +        <key>155</key> +        <string>Keyboard Cancel</string> +        <key>156</key> +        <string>Keyboard Clear</string> +        <key>157</key> +        <string>Keyboard Prior</string> +        <key>158</key> +        <string>Keyboard Return</string> +        <key>159</key> +        <string>Keyboard Separator</string> +        <key>160</key> +        <string>Keyboard Out</string> +        <key>161</key> +        <string>Keyboard Oper</string> +        <key>162</key> +        <string>Keyboard Clear/Again</string> +        <key>163</key> +        <string>Keyboard CrSel/Props</string> +        <key>164</key> +        <string>Keyboard ExSel</string> +        <key>224</key> +        <string>Keyboard LeftControl</string> +        <key>225</key> +        <string>Keyboard LeftShift</string> +        <key>226</key> +        <string>Keyboard LeftAlt</string> +        <key>227</key> +        <string>Keyboard Left GUI</string> +        <key>228</key> +        <string>Keyboard RightControl</string> +        <key>229</key> +        <string>Keyboard RightShift</string> +        <key>230</key> +        <string>Keyboard RightAlt</string> +        <key>231</key> +        <string>Keyboard Right GUI</string> +      </dict> +    </dict> +    <key>8</key> +    <dict> +      <key>description</key> +      <string>LEDs</string> +      <key>ranges</key> +      <dict> +        <key>{76, 65535}</key> +        <string>Reserved</string> +      </dict> +      <key>usages</key> +      <dict> +        <key>0</key> +        <string>Undefined</string> +        <key>1</key> +        <string>Num Lock</string> +        <key>2</key> +        <string>Caps Lock</string> +        <key>3</key> +        <string>Scroll Lock</string> +        <key>4</key> +        <string>Compose</string> +        <key>5</key> +        <string>Kana</string> +        <key>6</key> +        <string>Power</string> +        <key>7</key> +        <string>Shift</string> +        <key>8</key> +        <string>Do Not Disturb</string> +        <key>9</key> +        <string>Mute</string> +        <key>10</key> +        <string>Tone Enable</string> +        <key>11</key> +        <string>High Cut Filter</string> +        <key>12</key> +        <string>Low Cut Filter</string> +        <key>13</key> +        <string>Equalizer Enable</string> +        <key>14</key> +        <string>Sound Field On</string> +        <key>15</key> +        <string>Surround Field On</string> +        <key>16</key> +        <string>Repeat</string> +        <key>17</key> +        <string>Stereo</string> +        <key>18</key> +        <string>Sampling Rate Detect</string> +        <key>19</key> +        <string>Spinning</string> +        <key>20</key> +        <string>CAV</string> +        <key>21</key> +        <string>CLV</string> +        <key>22</key> +        <string>Recording Format Detect</string> +        <key>23</key> +        <string>Off-Hook</string> +        <key>24</key> +        <string>Ring</string> +        <key>25</key> +        <string>Message Waiting</string> +        <key>26</key> +        <string>Data Mode</string> +        <key>27</key> +        <string>Battery Operation</string> +        <key>28</key> +        <string>Battery OK</string> +        <key>29</key> +        <string>Battery Low</string> +        <key>30</key> +        <string>Speaker</string> +        <key>31</key> +        <string>Head Set</string> +        <key>32</key> +        <string>Hold</string> +        <key>33</key> +        <string>Microphone</string> +        <key>34</key> +        <string>Coverage</string> +        <key>35</key> +        <string>Night Mode</string> +        <key>36</key> +        <string>Send Calls</string> +        <key>37</key> +        <string>Call Pickup</string> +        <key>38</key> +        <string>Conference</string> +        <key>39</key> +        <string>Stand-by</string> +        <key>40</key> +        <string>Camera On</string> +        <key>41</key> +        <string>Camera Off</string> +        <key>42</key> +        <string>On-Line</string> +        <key>43</key> +        <string>Off-Line</string> +        <key>44</key> +        <string>Busy</string> +        <key>45</key> +        <string>Ready</string> +        <key>46</key> +        <string>Paper-Out</string> +        <key>47</key> +        <string>Paper-Jam</string> +        <key>48</key> +        <string>Remote</string> +        <key>49</key> +        <string>Forward</string> +        <key>50</key> +        <string>Reverse</string> +        <key>51</key> +        <string>Stop</string> +        <key>52</key> +        <string>Rewind</string> +        <key>53</key> +        <string>Fast Forward</string> +        <key>54</key> +        <string>Play</string> +        <key>55</key> +        <string>Pause</string> +        <key>56</key> +        <string>Record</string> +        <key>57</key> +        <string>Error</string> +        <key>58</key> +        <string>Usage Selected Indicator</string> +        <key>59</key> +        <string>Usage In Use Indicator</string> +        <key>60</key> +        <string>Usage Multi Mode Indicator</string> +        <key>61</key> +        <string>Indicator On</string> +        <key>62</key> +        <string>Indicator Flash</string> +        <key>63</key> +        <string>Indicator Slow Blink</string> +        <key>64</key> +        <string>Indicator Fast Blink</string> +        <key>65</key> +        <string>Indicator Off</string> +        <key>66</key> +        <string>Flash On Time</string> +        <key>67</key> +        <string>Slow Blink On Time</string> +        <key>68</key> +        <string>Slow Blink Off Time</string> +        <key>69</key> +        <string>Fast Blink On Time</string> +        <key>70</key> +        <string>Fast Blink Off Time</string> +        <key>71</key> +        <string>Usage Indicator Color</string> +        <key>72</key> +        <string>Red</string> +        <key>73</key> +        <string>Green</string> +        <key>74</key> +        <string>Amber</string> +        <key>75</key> +        <string>Generic Indicator</string> +        <key>76</key> +        <string>System Suspend</string> +        <key>77</key> +        <string>External Power Connected</string> +      </dict> +    </dict> +    <key>9</key> +    <dict> +      <key>default</key> +      <string>Button %d</string> +      <key>description</key> +      <string>Button</string> +      <key>ranges</key> +      <dict> +      </dict> +      <key>usages</key> +      <dict> +        <key>0</key> +        <string>No Button Pressed</string> +      </dict> +    </dict> +    <key>10</key> +    <dict> +      <key>default</key> +      <string>Instance %d</string> +      <key>description</key> +      <string>Ordinal</string> +      <key>ranges</key> +      <dict> +      </dict> +      <key>usages</key> +      <dict> +        <key>0</key> +        <string>Unused</string> +      </dict> +    </dict> +    <key>11</key> +    <dict> +      <key>description</key> +      <string>Telephony</string> +      <key>ranges</key> +      <dict> +      </dict> +      <key>usages</key> +      <dict> +        <key>0</key> +        <string>Unassigned</string> +        <key>1</key> +        <string>Phone</string> +        <key>2</key> +        <string>Answering Machine</string> +        <key>3</key> +        <string>Message Controls</string> +        <key>4</key> +        <string>Handset</string> +        <key>5</key> +        <string>Headset</string> +        <key>6</key> +        <string>Telephony Key Pad</string> +        <key>7</key> +        <string>Programmable Button</string> +        <key>32</key> +        <string>Hook Switch</string> +        <key>33</key> +        <string>Flash</string> +        <key>34</key> +        <string>Feature</string> +        <key>35</key> +        <string>Hold</string> +        <key>36</key> +        <string>Redial</string> +        <key>37</key> +        <string>Transfer</string> +        <key>38</key> +        <string>Drop</string> +        <key>39</key> +        <string>Park</string> +        <key>40</key> +        <string>Forward Calls</string> +        <key>41</key> +        <string>Alternate Function</string> +        <key>42</key> +        <string>Line</string> +        <key>43</key> +        <string>Speaker Phone</string> +        <key>44</key> +        <string>Conference</string> +        <key>45</key> +        <string>Ring Enable</string> +        <key>46</key> +        <string>Ring Select</string> +        <key>47</key> +        <string>Phone Mute</string> +        <key>48</key> +        <string>Caller ID</string> +        <key>80</key> +        <string>Speed Dial</string> +        <key>81</key> +        <string>Store Number</string> +        <key>82</key> +        <string>Recall Number</string> +        <key>83</key> +        <string>Phone Directory</string> +        <key>112</key> +        <string>Voice Mail</string> +        <key>113</key> +        <string>Screen Calls</string> +        <key>114</key> +        <string>Do Not Disturb</string> +        <key>115</key> +        <string>Message</string> +        <key>116</key> +        <string>Answer On/Off</string> +        <key>144</key> +        <string>Inside Dial Tone</string> +        <key>145</key> +        <string>Outside Dial Tone</string> +        <key>146</key> +        <string>Inside Ring Tone</string> +        <key>147</key> +        <string>Outside Ring Tone</string> +        <key>148</key> +        <string>Priority Ring Tone</string> +        <key>149</key> +        <string>Inside Ringback</string> +        <key>150</key> +        <string>Priority Ringback</string> +        <key>151</key> +        <string>Line Busy Tone</string> +        <key>152</key> +        <string>Reorder Tone</string> +        <key>153</key> +        <string>Call Waiting Tone</string> +        <key>154</key> +        <string>Confirmation Tone 1</string> +        <key>155</key> +        <string>Confirmation Tone 2</string> +        <key>156</key> +        <string>Tones Off</string> +        <key>176</key> +        <string>Phone Key 0</string> +        <key>177</key> +        <string>Phone Key 1</string> +        <key>178</key> +        <string>Phone Key 2</string> +        <key>179</key> +        <string>Phone Key 3</string> +        <key>180</key> +        <string>Phone Key 4</string> +        <key>181</key> +        <string>Phone Key 5</string> +        <key>182</key> +        <string>Phone Key 6</string> +        <key>183</key> +        <string>Phone Key 7</string> +        <key>184</key> +        <string>Phone Key 8</string> +        <key>185</key> +        <string>Phone Key 9</string> +        <key>186</key> +        <string>Phone Key Star</string> +        <key>187</key> +        <string>Phone Key Pound</string> +        <key>188</key> +        <string>Phone Key A</string> +        <key>189</key> +        <string>Phone Key B</string> +        <key>190</key> +        <string>Phone Key C</string> +        <key>191</key> +        <string>Phone Key D</string> +      </dict> +    </dict> +    <key>12</key> +    <dict> +      <key>description</key> +      <string>Consumer</string> +      <key>ranges</key> +      <dict> +      </dict> +      <key>usages</key> +      <dict> +        <key>0</key> +        <string>Unassigned</string> +        <key>1</key> +        <string>Consumer Control</string> +        <key>2</key> +        <string>Numeric Key Pad</string> +        <key>3</key> +        <string>Programmable Buttons</string> +        <key>32</key> +        <string>+10</string> +        <key>33</key> +        <string>+100</string> +        <key>34</key> +        <string>AM/PM</string> +        <key>48</key> +        <string>Power</string> +        <key>49</key> +        <string>Reset</string> +        <key>50</key> +        <string>Sleep</string> +        <key>51</key> +        <string>Sleep After</string> +        <key>52</key> +        <string>Sleep Mode</string> +        <key>53</key> +        <string>Illumination</string> +        <key>54</key> +        <string>Function Buttons</string> +        <key>64</key> +        <string>Menu</string> +        <key>65</key> +        <string>Menu  Pick</string> +        <key>66</key> +        <string>Menu Up</string> +        <key>67</key> +        <string>Menu Down</string> +        <key>68</key> +        <string>Menu Left</string> +        <key>69</key> +        <string>Menu Right</string> +        <key>70</key> +        <string>Menu Escape</string> +        <key>71</key> +        <string>Menu Value Increase</string> +        <key>72</key> +        <string>Menu Value Decrease</string> +        <key>96</key> +        <string>Data On Screen</string> +        <key>97</key> +        <string>Closed Caption</string> +        <key>98</key> +        <string>Closed Caption Select</string> +        <key>99</key> +        <string>VCR/TV</string> +        <key>100</key> +        <string>Broadcast Mode</string> +        <key>101</key> +        <string>Snapshot</string> +        <key>102</key> +        <string>Still</string> +        <key>128</key> +        <string>Selection</string> +        <key>129</key> +        <string>Assign Selection</string> +        <key>130</key> +        <string>Mode Step</string> +        <key>131</key> +        <string>Recall Last</string> +        <key>132</key> +        <string>Enter Channel</string> +        <key>133</key> +        <string>Order Movie</string> +        <key>134</key> +        <string>Channel</string> +        <key>135</key> +        <string>Media Selection</string> +        <key>136</key> +        <string>Media Select Computer</string> +        <key>137</key> +        <string>Media Select TV</string> +        <key>138</key> +        <string>Media Select WWW</string> +        <key>139</key> +        <string>Media Select DVD</string> +        <key>140</key> +        <string>Media Select Telephone</string> +        <key>141</key> +        <string>Media Select Program Guide</string> +        <key>142</key> +        <string>Media Select Video Phone</string> +        <key>143</key> +        <string>Media Select Games</string> +        <key>144</key> +        <string>Media Select Messages</string> +        <key>145</key> +        <string>Media Select CD</string> +        <key>146</key> +        <string>Media Select VCR</string> +        <key>147</key> +        <string>Media Select Tuner</string> +        <key>148</key> +        <string>Quit</string> +        <key>149</key> +        <string>Help</string> +        <key>150</key> +        <string>Media Select Tape</string> +        <key>151</key> +        <string>Media Select Cable</string> +        <key>152</key> +        <string>Media Select Satellite</string> +        <key>153</key> +        <string>Media Select Security</string> +        <key>154</key> +        <string>Media Select Home</string> +        <key>155</key> +        <string>Media Select Call</string> +        <key>156</key> +        <string>Channel Increment</string> +        <key>157</key> +        <string>Channel Decrement</string> +        <key>158</key> +        <string>Media Select SAP</string> +        <key>160</key> +        <string>VCR Plus</string> +        <key>161</key> +        <string>Once</string> +        <key>162</key> +        <string>Daily</string> +        <key>163</key> +        <string>Weekly</string> +        <key>164</key> +        <string>Monthly</string> +        <key>176</key> +        <string>Play</string> +        <key>177</key> +        <string>Pause</string> +        <key>178</key> +        <string>Record</string> +        <key>179</key> +        <string>Fast Forward</string> +        <key>180</key> +        <string>Rewind</string> +        <key>181</key> +        <string>Scan Next Track</string> +        <key>182</key> +        <string>Scan Previous Track</string> +        <key>183</key> +        <string>Stop</string> +        <key>184</key> +        <string>Eject</string> +        <key>185</key> +        <string>Random Play</string> +        <key>186</key> +        <string>Select DisC</string> +        <key>187</key> +        <string>Enter Disc</string> +        <key>188</key> +        <string>Repeat</string> +        <key>189</key> +        <string>Tracking</string> +        <key>190</key> +        <string>Track Normal</string> +        <key>191</key> +        <string>Slow Tracking</string> +        <key>192</key> +        <string>Frame Forward</string> +        <key>193</key> +        <string>Frame Back</string> +        <key>194</key> +        <string>Mark</string> +        <key>195</key> +        <string>Clear Mark</string> +        <key>196</key> +        <string>Repeat From Mark</string> +        <key>197</key> +        <string>Return To Mark</string> +        <key>198</key> +        <string>Search Mark Forward</string> +        <key>199</key> +        <string>Search Mark Backwards</string> +        <key>200</key> +        <string>Counter Reset</string> +        <key>201</key> +        <string>Show Counter</string> +        <key>202</key> +        <string>Tracking Increment</string> +        <key>203</key> +        <string>Tracking Decrement</string> +        <key>205</key> +        <string>Pause/Play</string> +        <key>224</key> +        <string>Volume</string> +        <key>225</key> +        <string>Balance</string> +        <key>226</key> +        <string>Mute</string> +        <key>227</key> +        <string>Bass</string> +        <key>228</key> +        <string>Treble</string> +        <key>229</key> +        <string>Bass Boost</string> +        <key>230</key> +        <string>Surround Mode</string> +        <key>231</key> +        <string>Loudness</string> +        <key>232</key> +        <string>MPX</string> +        <key>233</key> +        <string>Volume Up</string> +        <key>234</key> +        <string>Volume Down</string> +        <key>240</key> +        <string>Speed Select</string> +        <key>241</key> +        <string>Playback Speed</string> +        <key>242</key> +        <string>Standard Play</string> +        <key>243</key> +        <string>Long Play</string> +        <key>244</key> +        <string>Extended Play</string> +        <key>245</key> +        <string>Slow</string> +        <key>256</key> +        <string>Fan Enable</string> +        <key>257</key> +        <string>Fan Speed</string> +        <key>258</key> +        <string>Light</string> +        <key>259</key> +        <string>Light Illumination Level</string> +        <key>260</key> +        <string>Climate Control Enable</string> +        <key>261</key> +        <string>Room Temperature</string> +        <key>262</key> +        <string>Security Enable</string> +        <key>263</key> +        <string>Fire Alarm</string> +        <key>264</key> +        <string>Police Alarm</string> +        <key>336</key> +        <string>Balance Right</string> +        <key>337</key> +        <string>Balance Left</string> +        <key>338</key> +        <string>Bass Increment</string> +        <key>339</key> +        <string>Bass Decrement</string> +        <key>340</key> +        <string>Treble Increment</string> +        <key>341</key> +        <string>Treble Decrement</string> +        <key>352</key> +        <string>Speaker System</string> +        <key>353</key> +        <string>Channel Left</string> +        <key>354</key> +        <string>Channel Right</string> +        <key>355</key> +        <string>Channel Center</string> +        <key>356</key> +        <string>Channel Front</string> +        <key>357</key> +        <string>Channel Center Front</string> +        <key>358</key> +        <string>Channel Side</string> +        <key>359</key> +        <string>Channel Surround</string> +        <key>360</key> +        <string>Channel Low Frequency Enhancement</string> +        <key>361</key> +        <string>Channel Top</string> +        <key>362</key> +        <string>Channel Unknown</string> +        <key>368</key> +        <string>Sub-channel</string> +        <key>369</key> +        <string>Sub-channel Increment</string> +        <key>370</key> +        <string>Sub-channel Decrement</string> +        <key>371</key> +        <string>Alternate Audio Increment</string> +        <key>372</key> +        <string>Alternate Audio Decrement</string> +        <key>384</key> +        <string>Application Launch Buttons</string> +        <key>385</key> +        <string>AL Launch Button Configuration Tool</string> +        <key>386</key> +        <string>AL Programmable Button Configuration</string> +        <key>387</key> +        <string>AL Consumer Control Configuration</string> +        <key>388</key> +        <string>AL Word Processor</string> +        <key>389</key> +        <string>AL Text Editor</string> +        <key>390</key> +        <string>AL Spreadsheet</string> +        <key>391</key> +        <string>AL Graphics Editor</string> +        <key>392</key> +        <string>AL Presentation App</string> +        <key>393</key> +        <string>AL Database App</string> +        <key>394</key> +        <string>AL Email Reader</string> +        <key>395</key> +        <string>AL Newsreader</string> +        <key>396</key> +        <string>AL Voicemail</string> +        <key>397</key> +        <string>AL Contacts/Address Book</string> +        <key>398</key> +        <string>AL Calendar/Schedule</string> +        <key>399</key> +        <string>AL Task/Project Manager</string> +        <key>400</key> +        <string>AL Log/Journal/Timecard</string> +        <key>401</key> +        <string>AL Checkbook/Finance</string> +        <key>402</key> +        <string>AL Calculator</string> +        <key>403</key> +        <string>AL A/V Capture/Playback</string> +        <key>404</key> +        <string>AL Local Machine Browser</string> +        <key>405</key> +        <string>AL LAN/WAN Browser</string> +        <key>406</key> +        <string>AL Internet Browser</string> +        <key>407</key> +        <string>AL Remote Networking/ISP Connect</string> +        <key>408</key> +        <string>AL Network Conference</string> +        <key>409</key> +        <string>AL Network Chat</string> +        <key>410</key> +        <string>AL Telephony/Dialer</string> +        <key>411</key> +        <string>AL Logon</string> +        <key>412</key> +        <string>AL Logoff</string> +        <key>413</key> +        <string>AL Logon/Logoff</string> +        <key>414</key> +        <string>AL Terminal Lock/Screensaver</string> +        <key>415</key> +        <string>AL Control Panel</string> +        <key>416</key> +        <string>AL Command Line Processor/Run</string> +        <key>417</key> +        <string>AL Process/Task Manager</string> +        <key>418</key> +        <string>AL Select Tast/Application</string> +        <key>419</key> +        <string>AL Next Task/Application</string> +        <key>420</key> +        <string>AL Previous Task/Application</string> +        <key>421</key> +        <string>AL Preemptive Halt Task/Application</string> +        <key>423</key> +        <string>AL My Documents</string> +        <key>427</key> +        <string>AC Spell</string> +        <key>438</key> +        <string>AL My Pictures</string> +        <key>439</key> +        <string>AL My Music</string> +        <key>512</key> +        <string>Generic GUI Application Controls</string> +        <key>513</key> +        <string>AC New</string> +        <key>514</key> +        <string>AC Open</string> +        <key>515</key> +        <string>AC Close</string> +        <key>516</key> +        <string>AC Exit</string> +        <key>517</key> +        <string>AC Maximize</string> +        <key>518</key> +        <string>AC Minimize</string> +        <key>519</key> +        <string>AC Save</string> +        <key>520</key> +        <string>AC Print</string> +        <key>521</key> +        <string>AC Properties</string> +        <key>538</key> +        <string>AC Undo</string> +        <key>539</key> +        <string>AC Copy</string> +        <key>540</key> +        <string>AC Cut</string> +        <key>541</key> +        <string>AC Paste</string> +        <key>542</key> +        <string>AC Select All</string> +        <key>543</key> +        <string>AC Find</string> +        <key>544</key> +        <string>AC Find and Replace</string> +        <key>545</key> +        <string>AC Search</string> +        <key>546</key> +        <string>AC Go To</string> +        <key>547</key> +        <string>AC Home</string> +        <key>548</key> +        <string>AC Back</string> +        <key>549</key> +        <string>AC Forward</string> +        <key>550</key> +        <string>AC Stop</string> +        <key>551</key> +        <string>AC Refresh</string> +        <key>552</key> +        <string>AC Previous Link</string> +        <key>553</key> +        <string>AC Next Link</string> +        <key>554</key> +        <string>AC Bookmarks</string> +        <key>555</key> +        <string>AC History</string> +        <key>556</key> +        <string>AC Subscriptions</string> +        <key>557</key> +        <string>AC Zoom In</string> +        <key>558</key> +        <string>AC Zoom Out</string> +        <key>559</key> +        <string>AC Zoom</string> +        <key>560</key> +        <string>AC Full Screen View</string> +        <key>561</key> +        <string>AC Normal View</string> +        <key>562</key> +        <string>AC View Toggle</string> +        <key>563</key> +        <string>AC Scroll Up</string> +        <key>564</key> +        <string>AC Scroll Down</string> +        <key>565</key> +        <string>AC Scroll</string> +        <key>566</key> +        <string>AC Pan Left</string> +        <key>567</key> +        <string>AC Pan Right</string> +        <key>568</key> +        <string>AC Pan</string> +        <key>569</key> +        <string>AC New Window</string> +        <key>570</key> +        <string>AC Tile Horizontally</string> +        <key>571</key> +        <string>AC Tile Vertically</string> +        <key>572</key> +        <string>AC Format</string> +        <key>633</key> +        <string>AC Redo</string> +        <key>649</key> +        <string>AC Reply</string> +        <key>651</key> +        <string>AC Fwd</string> +        <key>652</key> +        <string>AC Send</string> +      </dict> +    </dict> +    <key>13</key> +    <dict> +      <key>description</key> +      <string>Digitizer</string> +      <key>ranges</key> +      <dict> +      </dict> +      <key>usages</key> +      <dict> +        <key>0</key> +        <string>Undefined</string> +        <key>1</key> +        <string>Digitizer</string> +        <key>2</key> +        <string>Pen</string> +        <key>3</key> +        <string>Light Pen</string> +        <key>4</key> +        <string>Touch Screen</string> +        <key>5</key> +        <string>Touch Pad</string> +        <key>6</key> +        <string>White Board</string> +        <key>7</key> +        <string>Coordinate Measuring Machine</string> +        <key>8</key> +        <string>3-D Digitizer</string> +        <key>9</key> +        <string>Stereo Plotter</string> +        <key>10</key> +        <string>Articulated Arm</string> +        <key>11</key> +        <string>Armature</string> +        <key>12</key> +        <string>Multiple Point Digitizer</string> +        <key>13</key> +        <string>Free Space Wand</string> +        <key>32</key> +        <string>Stylus</string> +        <key>33</key> +        <string>Puck</string> +        <key>34</key> +        <string>Finger</string> +        <key>48</key> +        <string>Tip Pressure</string> +        <key>49</key> +        <string>Barrel Pressure</string> +        <key>50</key> +        <string>In Range</string> +        <key>51</key> +        <string>Touch</string> +        <key>52</key> +        <string>Untouch</string> +        <key>53</key> +        <string>Tap</string> +        <key>54</key> +        <string>Quality</string> +        <key>55</key> +        <string>Data Valid</string> +        <key>56</key> +        <string>Transducer Index</string> +        <key>57</key> +        <string>Tablet Function Keys</string> +        <key>58</key> +        <string>Program Change Keys</string> +        <key>59</key> +        <string>Battery Strength</string> +        <key>60</key> +        <string>Invert</string> +        <key>61</key> +        <string>X Tilt</string> +        <key>62</key> +        <string>Y Tilt</string> +        <key>63</key> +        <string>Azimuth</string> +        <key>64</key> +        <string>Altitude</string> +        <key>65</key> +        <string>Twist</string> +        <key>66</key> +        <string>Tip Switch</string> +        <key>67</key> +        <string>Secondary Tip Switch</string> +        <key>68</key> +        <string>Barrel Switch</string> +        <key>69</key> +        <string>Eraser</string> +        <key>70</key> +        <string>Tablet Pick</string> +      </dict> +    </dict> +    <key>15</key> +    <dict> +      <key>description</key> +      <string>Physical Interface Device</string> +      <key>ranges</key> +      <dict> +      </dict> +      <key>usages</key> +      <dict> +      </dict> +    </dict> +    <key>16</key> +    <dict> +      <key>default</key> +      <string>Unicode Char u%04x</string> +      <key>description</key> +      <string>Unicode</string> +      <key>ranges</key> +      <dict> +      </dict> +      <key>usages</key> +      <dict> +      </dict> +    </dict> +    <key>20</key> +    <dict> +      <key>description</key> +      <string>Alphnumeric Display</string> +      <key>ranges</key> +      <dict> +      </dict> +      <key>usages</key> +      <dict> +        <key>0</key> +        <string>Undefined</string> +        <key>1</key> +        <string>Alphanumeric Display</string> +        <key>32</key> +        <string>Display Attributes Report</string> +        <key>33</key> +        <string>ASCII Character Set</string> +        <key>34</key> +        <string>Data Read Back</string> +        <key>35</key> +        <string>Font Read Back</string> +        <key>36</key> +        <string>Display Control Report</string> +        <key>37</key> +        <string>Clear Display</string> +        <key>38</key> +        <string>Display Enable</string> +        <key>39</key> +        <string>Screen Saver Delay</string> +        <key>40</key> +        <string>Screen Saver Enable</string> +        <key>41</key> +        <string>Vertical Scroll</string> +        <key>42</key> +        <string>Horizontal Scroll</string> +        <key>43</key> +        <string>Character Report</string> +        <key>44</key> +        <string>Display Data</string> +        <key>45</key> +        <string>Display Status</string> +        <key>46</key> +        <string>Stat Not Ready</string> +        <key>47</key> +        <string>Stat Ready</string> +        <key>48</key> +        <string>Err Not a loadable character</string> +        <key>49</key> +        <string>Err Font data cannot be read</string> +        <key>50</key> +        <string>Cursor Position Report</string> +        <key>51</key> +        <string>Row</string> +        <key>52</key> +        <string>Column</string> +        <key>53</key> +        <string>Rows</string> +        <key>54</key> +        <string>Columns</string> +        <key>55</key> +        <string>Cursor Pixel Positioning</string> +        <key>56</key> +        <string>Cursor Mode</string> +        <key>57</key> +        <string>Cursor Enable</string> +        <key>58</key> +        <string>Cursor Blink</string> +        <key>59</key> +        <string>Font Report</string> +        <key>60</key> +        <string>Font Data</string> +        <key>61</key> +        <string>Character Width</string> +        <key>62</key> +        <string>Character Height</string> +        <key>63</key> +        <string>Character Spacing Horizontal</string> +        <key>64</key> +        <string>Character Spacing Vertical</string> +        <key>65</key> +        <string>Unicode Character Set</string> +      </dict> +    </dict> +    <key>128</key> +    <dict> +      <key>description</key> +      <string>Monitor</string> +      <key>ranges</key> +      <dict> +      </dict> +      <key>usages</key> +      <dict> +        <key>0</key> +        <string>Undefined</string> +        <key>1</key> +        <string>Monitor Control</string> +        <key>2</key> +        <string>EDID Information</string> +        <key>3</key> +        <string>VDIF Information</string> +        <key>4</key> +        <string>VESA Version</string> +        <key>5</key> +        <string>On Screen Display</string> +        <key>6</key> +        <string>Auto Size Center</string> +        <key>7</key> +        <string>Polarity Horz Synch</string> +        <key>8</key> +        <string>Polarity Vert Synch</string> +        <key>9</key> +        <string>Sync Type</string> +        <key>10</key> +        <string>Screen Position</string> +        <key>11</key> +        <string>Horizontal Frequency</string> +        <key>12</key> +        <string>Vertical Frequency</string> +      </dict> +    </dict> +    <key>129</key> +    <dict> +      <key>default</key> +      <string>ENUM %d</string> +      <key>description</key> +      <string>Monitor Enumerated Values</string> +      <key>ranges</key> +      <dict> +      </dict> +      <key>usages</key> +      <dict> +        <key>0</key> +        <string>unassigned</string> +      </dict> +    </dict> +    <key>130</key> +    <dict> +      <key>description</key> +      <string>VESA Virtual Controls</string> +      <key>ranges</key> +      <dict> +      </dict> +      <key>usages</key> +      <dict> +        <key>16</key> +        <string>Brightness</string> +        <key>18</key> +        <string>Contrast</string> +        <key>22</key> +        <string>Video Gain Red</string> +        <key>24</key> +        <string>Video Gain Green</string> +        <key>26</key> +        <string>Video Gain Blue</string> +        <key>28</key> +        <string>Focus</string> +        <key>32</key> +        <string>Horizontal Position</string> +        <key>34</key> +        <string>Horizontal Size</string> +        <key>36</key> +        <string>Horizontal Pincushion</string> +        <key>38</key> +        <string>Horizontal Pincushion Balance</string> +        <key>40</key> +        <string>Horizontal Misconvergence</string> +        <key>42</key> +        <string>Horizontal Linearity</string> +        <key>44</key> +        <string>Horizontal Linearity Balance</string> +        <key>48</key> +        <string>Vertical Position</string> +        <key>50</key> +        <string>Vertical Size</string> +        <key>52</key> +        <string>Vertical Pincushion</string> +        <key>54</key> +        <string>Vertical Pincushion Balance</string> +        <key>56</key> +        <string>Vertical Misconvergence</string> +        <key>58</key> +        <string>Vertical Linearity</string> +        <key>60</key> +        <string>Vertical Linearity Balance</string> +        <key>64</key> +        <string>Parallelogram Distortion</string> +        <key>66</key> +        <string>Trapezoidal Distortion</string> +        <key>68</key> +        <string>Tilt</string> +        <key>70</key> +        <string>Top Corner Distortion Control</string> +        <key>72</key> +        <string>Top Corner Distortion Balance</string> +        <key>74</key> +        <string>Bottom Corner Distortion Control</string> +        <key>76</key> +        <string>Bottom Corner Distortion Balance</string> +        <key>86</key> +        <string>MoirHorizontal</string> +        <key>88</key> +        <string>MoirVertical</string> +        <key>94</key> +        <string>Input Level Select</string> +        <key>96</key> +        <string>Input Source Select</string> +        <key>98</key> +        <string>Stereo Mode</string> +        <key>108</key> +        <string>Video Black Level Red</string> +        <key>110</key> +        <string>Video Black Level Green</string> +        <key>112</key> +        <string>Video Black Level Blue</string> +      </dict> +    </dict> +    <key>131</key> +    <dict> +      <key>description</key> +      <string>VESA Command</string> +      <key>ranges</key> +      <dict> +      </dict> +      <key>usages</key> +      <dict> +        <key>0</key> +        <string>Undefined</string> +        <key>1</key> +        <string>Settings</string> +        <key>2</key> +        <string>Degauss</string> +      </dict> +    </dict> +    <key>132</key> +    <dict> +      <key>description</key> +      <string>Power Device</string> +      <key>ranges</key> +      <dict> +      </dict> +      <key>usages</key> +      <dict> +        <key>0</key> +        <string>Undefined</string> +        <key>1</key> +        <string>iName</string> +        <key>2</key> +        <string>PresentStatus</string> +        <key>3</key> +        <string>ChangedStatus</string> +        <key>4</key> +        <string>UPS</string> +        <key>5</key> +        <string>PowerSupply</string> +        <key>16</key> +        <string>BatterySystem</string> +        <key>17</key> +        <string>BatterySystemID</string> +        <key>18</key> +        <string>Battery</string> +        <key>19</key> +        <string>BatteryID</string> +        <key>20</key> +        <string>Charger</string> +        <key>21</key> +        <string>ChargerID</string> +        <key>22</key> +        <string>PowerConverter</string> +        <key>23</key> +        <string>PowerConverterID</string> +        <key>24</key> +        <string>OutletSystem</string> +        <key>25</key> +        <string>OutletSystemID</string> +        <key>26</key> +        <string>Input</string> +        <key>27</key> +        <string>InputID</string> +        <key>28</key> +        <string>Output</string> +        <key>29</key> +        <string>OutputID</string> +        <key>30</key> +        <string>Flow</string> +        <key>31</key> +        <string>FlowID</string> +        <key>32</key> +        <string>Outlet</string> +        <key>33</key> +        <string>OutletID</string> +        <key>34</key> +        <string>Gang</string> +        <key>35</key> +        <string>GangID</string> +        <key>36</key> +        <string>Sink</string> +        <key>37</key> +        <string>SinkID</string> +        <key>48</key> +        <string>Voltage</string> +        <key>49</key> +        <string>Current</string> +        <key>50</key> +        <string>Frequency</string> +        <key>51</key> +        <string>ApparentPower</string> +        <key>52</key> +        <string>ActivePower</string> +        <key>53</key> +        <string>PercentLoad</string> +        <key>54</key> +        <string>Temperature</string> +        <key>55</key> +        <string>Humidity</string> +        <key>64</key> +        <string>ConfigVoltage</string> +        <key>65</key> +        <string>ConfigCurrent</string> +        <key>66</key> +        <string>ConfigFrequency</string> +        <key>67</key> +        <string>ConfigApparentPower</string> +        <key>68</key> +        <string>ConfigActivePower</string> +        <key>69</key> +        <string>ConfigPercentLoad</string> +        <key>70</key> +        <string>ConfigTemperature</string> +        <key>71</key> +        <string>ConfigHumidity</string> +        <key>80</key> +        <string>SwitchOnControl</string> +        <key>81</key> +        <string>SwitchOffControl</string> +        <key>82</key> +        <string>ToggleControl</string> +        <key>83</key> +        <string>LowVoltageTransfer</string> +        <key>84</key> +        <string>HighVoltageTransfer</string> +        <key>85</key> +        <string>DelayBeforeReboot</string> +        <key>86</key> +        <string>DelayBeforeStartup</string> +        <key>87</key> +        <string>DelayBeforeShutdown</string> +        <key>88</key> +        <string>Test</string> +        <key>89</key> +        <string>Vendorspecificcommand</string> +        <key>96</key> +        <string>Present</string> +        <key>97</key> +        <string>Good</string> +        <key>98</key> +        <string>InternalFailure</string> +        <key>99</key> +        <string>VoltageOutOfRange</string> +        <key>100</key> +        <string>FrequencyOutOfRange</string> +        <key>101</key> +        <string>Overload</string> +        <key>102</key> +        <string>OverCharged</string> +        <key>103</key> +        <string>OverTemperature</string> +        <key>104</key> +        <string>ShutdownRequested</string> +        <key>105</key> +        <string>ShutdownImminent</string> +        <key>106</key> +        <string>VendorSpecificAnswerValid</string> +        <key>107</key> +        <string>SwitchOn/Off</string> +        <key>108</key> +        <string>Switcheble</string> +        <key>109</key> +        <string>Used</string> +        <key>110</key> +        <string>Boost</string> +        <key>111</key> +        <string>Buck</string> +        <key>112</key> +        <string>Initialized</string> +        <key>113</key> +        <string>Tested</string> +      </dict> +    </dict> +    <key>133</key> +    <dict> +      <key>description</key> +      <string>Battery System</string> +      <key>ranges</key> +      <dict> +      </dict> +      <key>usages</key> +      <dict> +        <key>0</key> +        <string>Undefined</string> +        <key>1</key> +        <string>SMBBatteryMode</string> +        <key>2</key> +        <string>SMBBatteryStatus</string> +        <key>3</key> +        <string>SMBAlarmWarning</string> +        <key>4</key> +        <string>SMBChargerMode</string> +        <key>5</key> +        <string>SMBChargerStatus</string> +        <key>6</key> +        <string>SMBChargerSpecInfo</string> +        <key>7</key> +        <string>SMBSelectorState</string> +        <key>8</key> +        <string>SMBSelectorPreset</string> +        <key>9</key> +        <string>SMBSelectorInfo</string> +        <key>16</key> +        <string>OptionalMfgFunction1</string> +        <key>17</key> +        <string>OptionalMfgFunction2</string> +        <key>18</key> +        <string>OptionalMfgFunction3</string> +        <key>19</key> +        <string>OptionalMfgFunction4</string> +        <key>20</key> +        <string>OptionalMfgFunction5</string> +        <key>21</key> +        <string>ConnectionToSMBus</string> +        <key>22</key> +        <string>OutputConnection</string> +        <key>23</key> +        <string>ChargerConnection</string> +        <key>24</key> +        <string>BatteryInsertion</string> +        <key>25</key> +        <string>Usenext</string> +        <key>26</key> +        <string>OKToUse</string> +        <key>40</key> +        <string>ManufacturerAccess</string> +        <key>41</key> +        <string>RemainingCapacityLimit</string> +        <key>42</key> +        <string>RemainingTimeLimit</string> +        <key>43</key> +        <string>AtRate</string> +        <key>44</key> +        <string>CapacityMode</string> +        <key>45</key> +        <string>BroadcastToCharger</string> +        <key>46</key> +        <string>PrimaryBattery</string> +        <key>47</key> +        <string>ChargeController</string> +        <key>64</key> +        <string>TerminateCharge</string> +        <key>65</key> +        <string>TermminateDischarge</string> +        <key>66</key> +        <string>BelowRemainingCapacityLimit</string> +        <key>67</key> +        <string>RemainingTimeLimitExpired</string> +        <key>68</key> +        <string>Charging</string> +        <key>69</key> +        <string>Discharging</string> +        <key>70</key> +        <string>FullyCharged</string> +        <key>71</key> +        <string>FullyDischarged</string> +        <key>72</key> +        <string>ConditionningFlag</string> +        <key>73</key> +        <string>AtRateOK</string> +        <key>74</key> +        <string>SMBErrorCode</string> +        <key>75</key> +        <string>NeedReplacement</string> +        <key>96</key> +        <string>AtRateTimeToFull</string> +        <key>97</key> +        <string>AtRateTimeToEmpty</string> +        <key>98</key> +        <string>AverageCurrent</string> +        <key>99</key> +        <string>Maxerror</string> +        <key>100</key> +        <string>RelativeStateOfCharge</string> +        <key>101</key> +        <string>AbsoluteStateOfCharge</string> +        <key>102</key> +        <string>RemainingCapacity</string> +        <key>103</key> +        <string>FullChargeCapacity</string> +        <key>104</key> +        <string>RunTimeToEmpty</string> +        <key>105</key> +        <string>AverageTimeToEmpty</string> +        <key>106</key> +        <string>AverageTimeToFull</string> +        <key>107</key> +        <string>CycleCount</string> +        <key>128</key> +        <string>BattPackModelLevel</string> +        <key>129</key> +        <string>InternalChargeController</string> +        <key>130</key> +        <string>PrimaryBatterySupport</string> +        <key>131</key> +        <string>DesignCapacity</string> +        <key>132</key> +        <string>SpecificationInfo</string> +        <key>133</key> +        <string>ManufacturerDate</string> +        <key>134</key> +        <string>SerialNumber</string> +        <key>135</key> +        <string>iManufacturerName</string> +        <key>136</key> +        <string>iDevicename</string> +        <key>137</key> +        <string>iDeviceChemistery</string> +        <key>138</key> +        <string>iManufacturerData</string> +        <key>139</key> +        <string>Rechargeable</string> +        <key>140</key> +        <string>WarningCapacityLimit</string> +        <key>141</key> +        <string>CapacityGranularity1</string> +        <key>142</key> +        <string>CapacityGranularity2</string> +        <key>192</key> +        <string>InhibitCharge</string> +        <key>193</key> +        <string>EnablePolling</string> +        <key>194</key> +        <string>ResetToZero</string> +        <key>208</key> +        <string>ACPresent</string> +        <key>209</key> +        <string>BatteryPresent</string> +        <key>210</key> +        <string>PowerFail</string> +        <key>211</key> +        <string>AlarmInhibited</string> +        <key>212</key> +        <string>ThermistorUnderRange</string> +        <key>213</key> +        <string>ThermistorHot</string> +        <key>214</key> +        <string>ThermistorCold</string> +        <key>215</key> +        <string>ThermistorOverRange</string> +        <key>216</key> +        <string>VoltageOutOfRange</string> +        <key>217</key> +        <string>CurrentOutOfRange</string> +        <key>218</key> +        <string>CurrentNotRegulated</string> +        <key>219</key> +        <string>VoltageNotRegulated</string> +        <key>220</key> +        <string>MasterMode</string> +        <key>221</key> +        <string>ChargerBattery/HostControlled</string> +        <key>240</key> +        <string>ChargerSpecInfo</string> +        <key>241</key> +        <string>ChargerSpecRef</string> +        <key>242</key> +        <string>Level2</string> +        <key>243</key> +        <string>Level3</string> +      </dict> +    </dict> +    <key>140</key> +    <dict> +      <key>description</key> +      <string>Bar Code Scanner</string> +      <key>ranges</key> +      <dict> +      </dict> +      <key>usages</key> +      <dict> +      </dict> +    </dict> +    <key>141</key> +    <dict> +      <key>description</key> +      <string>Scale Device</string> +      <key>ranges</key> +      <dict> +      </dict> +      <key>usages</key> +      <dict> +      </dict> +    </dict> +    <key>144</key> +    <dict> +      <key>description</key> +      <string>Camera Control</string> +      <key>ranges</key> +      <dict> +      </dict> +      <key>usages</key> +      <dict> +      </dict> +    </dict> +    <key>145</key> +    <dict> +      <key>description</key> +      <string>Arcade Device</string> +      <key>ranges</key> +      <dict> +      </dict> +      <key>usages</key> +      <dict> +        <key>233</key> +        <string>Base Up</string> +        <key>234</key> +        <string>Base Down</string> +      </dict> +    </dict> +  </dict> +</plist> diff --git a/lib/DDHidUsage.h b/lib/DDHidUsage.h new file mode 100644 index 0000000..8dc5654 --- /dev/null +++ b/lib/DDHidUsage.h @@ -0,0 +1,52 @@ +/* + * 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 <Cocoa/Cocoa.h> + + +@interface DDHidUsage : NSObject +{ +    unsigned mUsagePage; +    unsigned mUsageId; +} + ++ (DDHidUsage *) usageWithUsagePage: (unsigned) usagePage +                            usageId: (unsigned) usageId; + +- (id) initWithUsagePage: (unsigned) usagePage +                 usageId: (unsigned) usageId; + +- (unsigned) usagePage; + +- (unsigned) usageId; + +- (NSString *) usageName; + +- (NSString *) usageNameWithIds; + +- (NSString *) description; + +- (BOOL) isEqualToUsagePage: (unsigned) usagePage usageId: (unsigned) usageId; + +@end diff --git a/lib/DDHidUsage.m b/lib/DDHidUsage.m new file mode 100644 index 0000000..8fe2c11 --- /dev/null +++ b/lib/DDHidUsage.m @@ -0,0 +1,84 @@ +/* + * 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 "DDHidUsage.h" +#import "DDHidUsageTables.h" + +@implementation DDHidUsage + ++ (DDHidUsage *) usageWithUsagePage: (unsigned) usagePage +                            usageId: (unsigned) usageId; +{ +    return [[[self alloc] initWithUsagePage: usagePage usageId: usageId] +        autorelease]; +} + +- (id) initWithUsagePage: (unsigned) usagePage +                 usageId: (unsigned) usageId; +{ +    self = [super init]; +    if (self == nil) +        return nil; +     +    mUsagePage = usagePage; +    mUsageId = usageId; +     +    return self; +} + +- (unsigned) usagePage; +{ +    return mUsagePage; +} + +- (unsigned) usageId; +{ +    return mUsageId; +} + +- (NSString *) usageName; +{ +    DDHidUsageTables * usageTables = [DDHidUsageTables standardUsageTables]; +    return +        [usageTables descriptionForUsagePage: mUsagePage +                                       usage: mUsageId]; +} + +- (NSString *) usageNameWithIds; +{ +    return [NSString stringWithFormat: @"%@ (0x%04x : 0x%04x)", +        [self usageName], mUsagePage, mUsageId]; +} + +- (NSString *) description; +{ +    return [NSString stringWithFormat: @"HID Usage: %@", [self usageName]]; +} + +- (BOOL) isEqualToUsagePage: (unsigned) usagePage usageId: (unsigned) usageId; +{ +    return ((mUsagePage == usagePage) && (mUsageId == usageId)); +} + +@end diff --git a/lib/DDHidUsageTables.h b/lib/DDHidUsageTables.h new file mode 100644 index 0000000..be8d46e --- /dev/null +++ b/lib/DDHidUsageTables.h @@ -0,0 +1,40 @@ +/* + * 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 <Cocoa/Cocoa.h> + + +@interface DDHidUsageTables : NSObject +{ +    NSDictionary * mLookupTables; +} + ++ (DDHidUsageTables *) standardUsageTables; + +- (id) initWithLookupTables: (NSDictionary *) lookupTables; + +- (NSString *) descriptionForUsagePage: (unsigned) usagePage +                                 usage: (unsigned) usage; + +@end diff --git a/lib/DDHidUsageTables.m b/lib/DDHidUsageTables.m new file mode 100644 index 0000000..9e7703a --- /dev/null +++ b/lib/DDHidUsageTables.m @@ -0,0 +1,85 @@ +/* + * 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 "DDHidUsageTables.h" + +@implementation DDHidUsageTables + +static DDHidUsageTables * sStandardUsageTables = nil; + ++ (DDHidUsageTables *) standardUsageTables; +{ +    if (sStandardUsageTables == nil) +    { +        NSBundle * myBundle = [NSBundle bundleForClass: self]; +        NSString * usageTablesPath = +            [myBundle pathForResource: @"DDHidStandardUsages" ofType: @"plist"]; +        NSDictionary * lookupTables = +            [NSDictionary dictionaryWithContentsOfFile: usageTablesPath]; +        sStandardUsageTables = +            [[DDHidUsageTables alloc] initWithLookupTables: lookupTables]; +        [sStandardUsageTables retain]; +    } +     +    return sStandardUsageTables; +} + +- (id) initWithLookupTables: (NSDictionary *) lookupTables; +{ +    self = [super init]; +    if (self == nil) +        return nil; +     +    mLookupTables = [lookupTables retain]; +     +    return self; +} + +- (NSString *) descriptionForUsagePage: (unsigned) usagePage +                                usage: (unsigned) usage +{ +    NSString * usagePageString = [NSString stringWithFormat: @"%u", usagePage]; +    NSString * usageString = [NSString stringWithFormat: @"%u", usage]; +    // NSNumber * usagePageNumber = [NSNumber numberWithUnsignedInt: usagePage]; +     +    NSDictionary * usagePageLookup = [mLookupTables objectForKey: usagePageString]; +    if (usagePageLookup == nil) +        return @"Unknown usage page"; +     +    NSDictionary * usageLookup = [usagePageLookup objectForKey: @"usages"]; +    NSString * description = [usageLookup objectForKey: usageString]; +    if (description != nil) +        return description; +     +    NSString * defaultUsage = [usagePageLookup objectForKey: @"default"]; +    if (defaultUsage != nil) +    { +        description = [NSString stringWithFormat: defaultUsage, usage]; +        return description; +    } +     +    return @"Unknown usage"; +} + +@end diff --git a/lib/NSDictionary+DDHidExtras.h b/lib/NSDictionary+DDHidExtras.h new file mode 100644 index 0000000..750d0d4 --- /dev/null +++ b/lib/NSDictionary+DDHidExtras.h @@ -0,0 +1,46 @@ +/* + * 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 <Cocoa/Cocoa.h> + + +@interface NSDictionary (DDHidExtras) + +- (unsigned) ddhid_unsignedForKey: (NSString *) key; + +- (id) ddhid_objectForString: (const char *) key; + +- (NSString *) ddhid_stringForString: (const char *) key; +- (long) ddhid_longForString: (const char *) key; +- (unsigned int) ddhid_unsignedIntForString: (const char *) key; +- (BOOL) ddhid_boolForString: (const char *) key; + +@end + +@interface NSMutableDictionary (DDHidExtras) + +- (void) ddhid_setObject: (id) object forString: (const char *) key; +- (void) ddhid_setInt: (int) i forKey: (id) key; + +@end diff --git a/lib/NSDictionary+DDHidExtras.m b/lib/NSDictionary+DDHidExtras.m new file mode 100644 index 0000000..4864a48 --- /dev/null +++ b/lib/NSDictionary+DDHidExtras.m @@ -0,0 +1,81 @@ +/* + * 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 "NSDictionary+DDHidExtras.h" + + +@implementation NSDictionary (DDHidExtras) + +- (unsigned) ddhid_unsignedForKey: (NSString *) key; +{ +    NSNumber * number = [self objectForKey: key]; +    return [number unsignedIntValue]; +} + +- (id) ddhid_objectForString: (const char *) key; +{ +    NSString * objcKey = [NSString stringWithUTF8String: key]; +    return [self objectForKey: objcKey]; +} + +- (NSString *) ddhid_stringForString: (const char *) key; +{ +    return [self ddhid_objectForString: key]; +} + +- (long) ddhid_longForString: (const char *) key; +{ +    NSNumber * number =  [self ddhid_objectForString: key]; +    return [number longValue]; +} + +- (unsigned int) ddhid_unsignedIntForString: (const char *) key; +{ +    NSNumber * number =  [self ddhid_objectForString: key]; +    return [number unsignedIntValue]; +} + +- (BOOL) ddhid_boolForString: (const char *) key; +{ +    NSNumber * number =  [self ddhid_objectForString: key]; +    return [number boolValue]; +} + +@end + +@implementation NSMutableDictionary (DDHidExtras) + +- (void) ddhid_setObject: (id) object forString: (const char *) key; +{ +    NSString * objcKey = [NSString stringWithUTF8String: key]; +    [self setObject: object forKey: objcKey]; +} + +- (void) ddhid_setInt: (int) i forKey: (id) key; +{ +    NSNumber * number = [NSNumber numberWithInt: i]; +    [self setObject: number forKey: key]; +} + +@end | 
