diff options
| author | Dominik Pich | 2013-03-17 13:33:20 +0100 |
|---|---|---|
| committer | Dominik Pich | 2013-03-17 13:33:20 +0100 |
| commit | d4ffd217288cfc0d2798b3df67ab20bc867a7f7e (patch) | |
| tree | ab40c6fb784fbe578713381ea5cf1159934a9c34 /lib | |
| parent | 77d2a9f99a289d247c5a8561879489c8f8162055 (diff) | |
| download | DDHidLib-d4ffd217288cfc0d2798b3df67ab20bc867a7f7e.tar.bz2 | |
DDHIDLib 1.1.1
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 |
