From 7d64531b89057a2beed03af65b8ed6d1e5a1ddce Mon Sep 17 00:00:00 2001 From: Aaron Culliney Date: Sun, 9 Nov 2014 17:08:23 -0800 Subject: [PATCH] Squashed 'Apple2Mac/DDHidLib/' content from commit e6a9848 git-subtree-dir: Apple2Mac/DDHidLib git-subtree-split: e6a9848859fc84e689afb85799658f4980651106 --- .gitignore | 18 + DDHidLib-Info.plist | 22 + DDHidLib.xcodeproj/project.pbxproj | 1109 ++++ Icon.jpg | Bin 0 -> 15141 bytes LICENSE.html | 181 + README.md | 11 + .../EventWatcher.nib/classes.nib | 13 + .../English.lproj/EventWatcher.nib/info.nib | 16 + .../EventWatcher.nib/keyedobjects.nib | Bin 0 -> 9260 bytes browser/English.lproj/InfoPlist.strings | Bin 0 -> 190 bytes .../English.lproj/MainMenu.nib/classes.nib | 19 + browser/English.lproj/MainMenu.nib/info.nib | 22 + .../MainMenu.nib/keyedobjects.nib | Bin 0 -> 31311 bytes browser/HIDBrowser_Prefix.pch | 7 + browser/HexFormatter.h | 34 + browser/HexFormatter.m | 49 + browser/HidBrowserController.h | 42 + browser/HidBrowserController.m | 144 + browser/Info.plist | 30 + browser/WatcherWindowController.h | 57 + browser/WatcherWindowController.m | 269 + browser/main.m | 30 + changelog.yml | 24 + device_test/AppleMikeyPaneController.h | 62 + device_test/AppleMikeyPaneController.m | 160 + device_test/AppleRemote.tiff | Bin 0 -> 90050 bytes device_test/AppleRemotePaneController.h | 51 + device_test/AppleRemotePaneController.m | 145 + device_test/BoolFormatter.h | 35 + device_test/BoolFormatter.m | 82 + device_test/ButtonState.h | 39 + device_test/ButtonState.m | 77 + device_test/DeviceTestController.h | 35 + device_test/DeviceTestController.m | 49 + device_test/English.lproj/InfoPlist.strings | Bin 0 -> 190 bytes .../English.lproj/MainMenu.nib/designable.nib | 5311 +++++++++++++++++ .../MainMenu.nib/keyedobjects.nib | Bin 0 -> 46512 bytes device_test/Info.plist | 26 + device_test/JoystickPaneController.h | 72 + device_test/JoystickPaneController.m | 174 + device_test/KeyboardPaneController.h | 64 + device_test/KeyboardPaneController.m | 179 + device_test/MousePaneController.h | 68 + device_test/MousePaneController.m | 211 + device_test/RemoteFeedbackView.h | 42 + device_test/RemoteFeedbackView.m | 162 + device_test/main.m | 30 + header.c | 23 + lib/DDHidAppleMikey.h | 66 + lib/DDHidAppleMikey.m | 164 + lib/DDHidAppleRemote.h | 84 + lib/DDHidAppleRemote.m | 236 + lib/DDHidDevice.h | 131 + lib/DDHidDevice.m | 595 ++ lib/DDHidElement.h | 65 + lib/DDHidElement.m | 185 + lib/DDHidEvent.h | 45 + lib/DDHidEvent.m | 81 + lib/DDHidJoystick.h | 132 + lib/DDHidJoystick.m | 654 ++ lib/DDHidKeyboard.h | 68 + lib/DDHidKeyboard.m | 173 + lib/DDHidKeyboardBarcodeScanner.h | 74 + lib/DDHidKeyboardBarcodeScanner.m | 222 + lib/DDHidLib.h | 36 + lib/DDHidMouse.h | 78 + lib/DDHidMouse.m | 279 + lib/DDHidQueue.h | 70 + lib/DDHidQueue.m | 174 + lib/DDHidStandardUsages.plist | 2327 ++++++++ lib/DDHidUsage.h | 52 + lib/DDHidUsage.m | 84 + lib/DDHidUsageTables.h | 40 + lib/DDHidUsageTables.m | 85 + lib/NSDictionary+DDHidExtras.h | 46 + lib/NSDictionary+DDHidExtras.m | 81 + usb_hid_usages.txt | 1086 ++++ usb_hid_usages2plist | 46 + .../NSXReturnThrowError/NSXReturnThrowError.h | 103 + .../NSXReturnThrowError/NSXReturnThrowError.m | 106 + versions.xcconfig | 2 + 81 files changed, 16864 insertions(+) create mode 100644 .gitignore create mode 100644 DDHidLib-Info.plist create mode 100644 DDHidLib.xcodeproj/project.pbxproj create mode 100644 Icon.jpg create mode 100644 LICENSE.html create mode 100644 README.md create mode 100644 browser/English.lproj/EventWatcher.nib/classes.nib create mode 100644 browser/English.lproj/EventWatcher.nib/info.nib create mode 100644 browser/English.lproj/EventWatcher.nib/keyedobjects.nib create mode 100644 browser/English.lproj/InfoPlist.strings create mode 100644 browser/English.lproj/MainMenu.nib/classes.nib create mode 100644 browser/English.lproj/MainMenu.nib/info.nib create mode 100644 browser/English.lproj/MainMenu.nib/keyedobjects.nib create mode 100644 browser/HIDBrowser_Prefix.pch create mode 100644 browser/HexFormatter.h create mode 100644 browser/HexFormatter.m create mode 100644 browser/HidBrowserController.h create mode 100644 browser/HidBrowserController.m create mode 100644 browser/Info.plist create mode 100644 browser/WatcherWindowController.h create mode 100644 browser/WatcherWindowController.m create mode 100644 browser/main.m create mode 100644 changelog.yml create mode 100644 device_test/AppleMikeyPaneController.h create mode 100644 device_test/AppleMikeyPaneController.m create mode 100644 device_test/AppleRemote.tiff create mode 100644 device_test/AppleRemotePaneController.h create mode 100644 device_test/AppleRemotePaneController.m create mode 100644 device_test/BoolFormatter.h create mode 100644 device_test/BoolFormatter.m create mode 100644 device_test/ButtonState.h create mode 100644 device_test/ButtonState.m create mode 100644 device_test/DeviceTestController.h create mode 100644 device_test/DeviceTestController.m create mode 100644 device_test/English.lproj/InfoPlist.strings create mode 100644 device_test/English.lproj/MainMenu.nib/designable.nib create mode 100644 device_test/English.lproj/MainMenu.nib/keyedobjects.nib create mode 100644 device_test/Info.plist create mode 100644 device_test/JoystickPaneController.h create mode 100644 device_test/JoystickPaneController.m create mode 100644 device_test/KeyboardPaneController.h create mode 100644 device_test/KeyboardPaneController.m create mode 100644 device_test/MousePaneController.h create mode 100644 device_test/MousePaneController.m create mode 100644 device_test/RemoteFeedbackView.h create mode 100644 device_test/RemoteFeedbackView.m create mode 100644 device_test/main.m create mode 100644 header.c create mode 100644 lib/DDHidAppleMikey.h create mode 100644 lib/DDHidAppleMikey.m create mode 100644 lib/DDHidAppleRemote.h create mode 100644 lib/DDHidAppleRemote.m create mode 100644 lib/DDHidDevice.h create mode 100644 lib/DDHidDevice.m create mode 100644 lib/DDHidElement.h create mode 100644 lib/DDHidElement.m create mode 100644 lib/DDHidEvent.h create mode 100644 lib/DDHidEvent.m create mode 100644 lib/DDHidJoystick.h create mode 100644 lib/DDHidJoystick.m create mode 100644 lib/DDHidKeyboard.h create mode 100644 lib/DDHidKeyboard.m create mode 100644 lib/DDHidKeyboardBarcodeScanner.h create mode 100644 lib/DDHidKeyboardBarcodeScanner.m create mode 100644 lib/DDHidLib.h create mode 100644 lib/DDHidMouse.h create mode 100644 lib/DDHidMouse.m create mode 100644 lib/DDHidQueue.h create mode 100644 lib/DDHidQueue.m create mode 100644 lib/DDHidStandardUsages.plist create mode 100644 lib/DDHidUsage.h create mode 100644 lib/DDHidUsage.m create mode 100644 lib/DDHidUsageTables.h create mode 100644 lib/DDHidUsageTables.m create mode 100644 lib/NSDictionary+DDHidExtras.h create mode 100644 lib/NSDictionary+DDHidExtras.m create mode 100644 usb_hid_usages.txt create mode 100755 usb_hid_usages2plist create mode 100644 vendor/NSXReturnThrowError/NSXReturnThrowError.h create mode 100644 vendor/NSXReturnThrowError/NSXReturnThrowError.m create mode 100644 versions.xcconfig diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..89c499e4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,18 @@ +# Xcode +.DS_Store +build/ +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +*.xcworkspace +!default.xcworkspace +xcuserdata +profile +*.moved-aside +DerivedData +.idea/ diff --git a/DDHidLib-Info.plist b/DDHidLib-Info.plist new file mode 100644 index 00000000..b77aa201 --- /dev/null +++ b/DDHidLib-Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + org.dribin.dave.DDHidLib + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + FMWK + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + CFBundleShortVersionString + ${CURRENT_MARKETING_VERSION} + + diff --git a/DDHidLib.xcodeproj/project.pbxproj b/DDHidLib.xcodeproj/project.pbxproj new file mode 100644 index 00000000..95d0ff96 --- /dev/null +++ b/DDHidLib.xcodeproj/project.pbxproj @@ -0,0 +1,1109 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXAggregateTarget section */ + 551711110B8F41EB00C82155 /* All */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 551711280B8F420E00C82155 /* Build configuration list for PBXAggregateTarget "All" */; + buildPhases = ( + ); + dependencies = ( + 551711130B8F41F500C82155 /* PBXTargetDependency */, + 551711150B8F41F500C82155 /* PBXTargetDependency */, + 55D5935D0BAE3B1E00364849 /* PBXTargetDependency */, + ); + name = All; + productName = All; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 30B1E6A918CBA620004E111E /* DDHidAppleMikey.h in Headers */ = {isa = PBXBuildFile; fileRef = B366F1AE16F5DE9800C0BA49 /* DDHidAppleMikey.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 55170D360B8EC2CE00C82155 /* DDHidAppleRemote.h in Headers */ = {isa = PBXBuildFile; fileRef = 55170D340B8EC2CE00C82155 /* DDHidAppleRemote.h */; }; + 55170D370B8EC2CE00C82155 /* DDHidAppleRemote.m in Sources */ = {isa = PBXBuildFile; fileRef = 55170D350B8EC2CE00C82155 /* DDHidAppleRemote.m */; }; + 55170E0D0B8ECCAC00C82155 /* AppleRemotePaneController.m in Sources */ = {isa = PBXBuildFile; fileRef = 55170E0C0B8ECCAC00C82155 /* AppleRemotePaneController.m */; }; + 55170E650B8ECEF600C82155 /* RemoteFeedbackView.m in Sources */ = {isa = PBXBuildFile; fileRef = 55170E640B8ECEF600C82155 /* RemoteFeedbackView.m */; }; + 55170E670B8ECF0000C82155 /* AppleRemote.tiff in Resources */ = {isa = PBXBuildFile; fileRef = 55170E660B8ECF0000C82155 /* AppleRemote.tiff */; }; + 55193E580B93F31D004C0C98 /* DDHidDevice.h in Headers */ = {isa = PBXBuildFile; fileRef = 55917B4F0B533C82005308AC /* DDHidDevice.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 55193E590B93F31D004C0C98 /* DDHidDevice.m in Sources */ = {isa = PBXBuildFile; fileRef = 55917B500B533C82005308AC /* DDHidDevice.m */; }; + 55193E5A0B93F31D004C0C98 /* DDHidElement.h in Headers */ = {isa = PBXBuildFile; fileRef = 55917E6F0B5413E7005308AC /* DDHidElement.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 55193E5B0B93F31D004C0C98 /* DDHidElement.m in Sources */ = {isa = PBXBuildFile; fileRef = 55917E700B5413E7005308AC /* DDHidElement.m */; }; + 55193E5C0B93F31D004C0C98 /* DDHidUsage.h in Headers */ = {isa = PBXBuildFile; fileRef = 559CB82B0B595B2F00C8FD74 /* DDHidUsage.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 55193E5D0B93F31D004C0C98 /* DDHidUsage.m in Sources */ = {isa = PBXBuildFile; fileRef = 559CB82C0B595B2F00C8FD74 /* DDHidUsage.m */; }; + 55193E5E0B93F31D004C0C98 /* DDHidQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 559180CA0B575698005308AC /* DDHidQueue.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 55193E5F0B93F31D004C0C98 /* DDHidQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = 559180CB0B575698005308AC /* DDHidQueue.m */; }; + 55193E600B93F31D004C0C98 /* DDHidEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 559181A40B576149005308AC /* DDHidEvent.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 55193E610B93F31D004C0C98 /* DDHidEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = 559181A50B576149005308AC /* DDHidEvent.m */; }; + 55193E620B93F31D004C0C98 /* DDHidUsageTables.h in Headers */ = {isa = PBXBuildFile; fileRef = 55917F610B545104005308AC /* DDHidUsageTables.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 55193E630B93F31D004C0C98 /* DDHidUsageTables.m in Sources */ = {isa = PBXBuildFile; fileRef = 55917F620B545104005308AC /* DDHidUsageTables.m */; }; + 55193E640B93F31D004C0C98 /* NSDictionary+DDHidExtras.h in Headers */ = {isa = PBXBuildFile; fileRef = 55917E720B541541005308AC /* NSDictionary+DDHidExtras.h */; settings = {ATTRIBUTES = (); }; }; + 55193E650B93F31D004C0C98 /* NSDictionary+DDHidExtras.m in Sources */ = {isa = PBXBuildFile; fileRef = 55917E730B541541005308AC /* NSDictionary+DDHidExtras.m */; }; + 55193E660B93F31D004C0C98 /* DDHidMouse.h in Headers */ = {isa = PBXBuildFile; fileRef = 559CBC2A0B5B34C300C8FD74 /* DDHidMouse.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 55193E670B93F31D004C0C98 /* DDHidMouse.m in Sources */ = {isa = PBXBuildFile; fileRef = 559CBC2B0B5B34C300C8FD74 /* DDHidMouse.m */; }; + 55193E680B93F31D004C0C98 /* DDHidJoystick.h in Headers */ = {isa = PBXBuildFile; fileRef = 55FD66D30B5DDC3F00325FEF /* DDHidJoystick.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 55193E690B93F31D004C0C98 /* DDHidJoystick.m in Sources */ = {isa = PBXBuildFile; fileRef = 55FD66D40B5DDC3F00325FEF /* DDHidJoystick.m */; }; + 55193E6A0B93F31D004C0C98 /* DDHidAppleRemote.h in Headers */ = {isa = PBXBuildFile; fileRef = 55170D340B8EC2CE00C82155 /* DDHidAppleRemote.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 55193E6B0B93F31D004C0C98 /* DDHidAppleRemote.m in Sources */ = {isa = PBXBuildFile; fileRef = 55170D350B8EC2CE00C82155 /* DDHidAppleRemote.m */; }; + 55193E6C0B93F31D004C0C98 /* DDHidLib.h in Headers */ = {isa = PBXBuildFile; fileRef = 55FD67CB0B5DE18600325FEF /* DDHidLib.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 55193E700B93F35A004C0C98 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 556E1E680B5359F9002F709C /* IOKit.framework */; }; + 55193F110B93F36F004C0C98 /* NSXReturnThrowError.h in Headers */ = {isa = PBXBuildFile; fileRef = 55BE6DCB0B8033010085514D /* NSXReturnThrowError.h */; settings = {ATTRIBUTES = (); }; }; + 55193F120B93F371004C0C98 /* NSXReturnThrowError.m in Sources */ = {isa = PBXBuildFile; fileRef = 55BE6DCC0B8033010085514D /* NSXReturnThrowError.m */; }; + 556E1E690B5359F9002F709C /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 556E1E680B5359F9002F709C /* IOKit.framework */; }; + 55917B640B53408C005308AC /* HidBrowserController.m in Sources */ = {isa = PBXBuildFile; fileRef = 55917B630B53408C005308AC /* HidBrowserController.m */; }; + 55917E1C0B53E454005308AC /* HexFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 55917E1B0B53E454005308AC /* HexFormatter.m */; }; + 559CBAEC0B5B31AB00C8FD74 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 559CBAEA0B5B31AB00C8FD74 /* main.m */; }; + 559CBB930B5B31E300C8FD74 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; }; + 559CBB940B5B31EA00C8FD74 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 556E1E680B5359F9002F709C /* IOKit.framework */; }; + 559CBBD10B5B337600C8FD74 /* DDHidDevice.h in Headers */ = {isa = PBXBuildFile; fileRef = 55917B4F0B533C82005308AC /* DDHidDevice.h */; }; + 559CBBD20B5B337600C8FD74 /* DDHidDevice.m in Sources */ = {isa = PBXBuildFile; fileRef = 55917B500B533C82005308AC /* DDHidDevice.m */; }; + 559CBBD30B5B337600C8FD74 /* DDHidElement.h in Headers */ = {isa = PBXBuildFile; fileRef = 55917E6F0B5413E7005308AC /* DDHidElement.h */; }; + 559CBBD40B5B337600C8FD74 /* DDHidElement.m in Sources */ = {isa = PBXBuildFile; fileRef = 55917E700B5413E7005308AC /* DDHidElement.m */; }; + 559CBBD50B5B337600C8FD74 /* DDHidUsage.h in Headers */ = {isa = PBXBuildFile; fileRef = 559CB82B0B595B2F00C8FD74 /* DDHidUsage.h */; }; + 559CBBD60B5B337600C8FD74 /* DDHidUsage.m in Sources */ = {isa = PBXBuildFile; fileRef = 559CB82C0B595B2F00C8FD74 /* DDHidUsage.m */; }; + 559CBBD70B5B337600C8FD74 /* DDHidQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = 559180CA0B575698005308AC /* DDHidQueue.h */; }; + 559CBBD80B5B337600C8FD74 /* DDHidQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = 559180CB0B575698005308AC /* DDHidQueue.m */; }; + 559CBBD90B5B337600C8FD74 /* DDHidEvent.h in Headers */ = {isa = PBXBuildFile; fileRef = 559181A40B576149005308AC /* DDHidEvent.h */; }; + 559CBBDA0B5B337600C8FD74 /* DDHidEvent.m in Sources */ = {isa = PBXBuildFile; fileRef = 559181A50B576149005308AC /* DDHidEvent.m */; }; + 559CBBDB0B5B337600C8FD74 /* DDHidUsageTables.h in Headers */ = {isa = PBXBuildFile; fileRef = 55917F610B545104005308AC /* DDHidUsageTables.h */; }; + 559CBBDC0B5B337600C8FD74 /* DDHidUsageTables.m in Sources */ = {isa = PBXBuildFile; fileRef = 55917F620B545104005308AC /* DDHidUsageTables.m */; }; + 559CBBDD0B5B337600C8FD74 /* NSDictionary+DDHidExtras.h in Headers */ = {isa = PBXBuildFile; fileRef = 55917E720B541541005308AC /* NSDictionary+DDHidExtras.h */; }; + 559CBC260B5B349100C8FD74 /* NSDictionary+DDHidExtras.m in Sources */ = {isa = PBXBuildFile; fileRef = 55917E730B541541005308AC /* NSDictionary+DDHidExtras.m */; }; + 559CBC2C0B5B34C300C8FD74 /* DDHidMouse.h in Headers */ = {isa = PBXBuildFile; fileRef = 559CBC2A0B5B34C300C8FD74 /* DDHidMouse.h */; }; + 559CBC2D0B5B34C300C8FD74 /* DDHidMouse.m in Sources */ = {isa = PBXBuildFile; fileRef = 559CBC2B0B5B34C300C8FD74 /* DDHidMouse.m */; }; + 559CBCA90B5B3BCE00C8FD74 /* MousePaneController.m in Sources */ = {isa = PBXBuildFile; fileRef = 559CBCA80B5B3BCE00C8FD74 /* MousePaneController.m */; }; + 55A000520B5D7C06001B47E5 /* BoolFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = 55A000500B5D7C06001B47E5 /* BoolFormatter.m */; }; + 55BE6DCD0B8033010085514D /* NSXReturnThrowError.h in Headers */ = {isa = PBXBuildFile; fileRef = 55BE6DCB0B8033010085514D /* NSXReturnThrowError.h */; }; + 55BE6DCE0B8033010085514D /* NSXReturnThrowError.m in Sources */ = {isa = PBXBuildFile; fileRef = 55BE6DCC0B8033010085514D /* NSXReturnThrowError.m */; }; + 55CA60E50BA0F2530012CF7B /* DDHidKeyboard.h in Headers */ = {isa = PBXBuildFile; fileRef = 55CA60E30BA0F2530012CF7B /* DDHidKeyboard.h */; }; + 55CA60E60BA0F2530012CF7B /* DDHidKeyboard.m in Sources */ = {isa = PBXBuildFile; fileRef = 55CA60E40BA0F2530012CF7B /* DDHidKeyboard.m */; }; + 55CA668B0BA38AEF0012CF7B /* KeyboardPaneController.m in Sources */ = {isa = PBXBuildFile; fileRef = 55CA668A0BA38AEF0012CF7B /* KeyboardPaneController.m */; }; + 55D5927D0BAE306E00364849 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 55D5927B0BAE306E00364849 /* InfoPlist.strings */; }; + 55D592940BAE30B600364849 /* MainMenu.nib in Resources */ = {isa = PBXBuildFile; fileRef = 55D592920BAE30B600364849 /* MainMenu.nib */; }; + 55D593290BAE3ABD00364849 /* DDHidLib.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 55193E500B93F2EE004C0C98 /* DDHidLib.framework */; }; + 55D593390BAE3ADF00364849 /* DDHidLib.framework in Copy Files to Frameworks */ = {isa = PBXBuildFile; fileRef = 55193E500B93F2EE004C0C98 /* DDHidLib.framework */; }; + 55D593660BAE3B5D00364849 /* DDHidLib.framework in Copy Files to Frameworks */ = {isa = PBXBuildFile; fileRef = 55193E500B93F2EE004C0C98 /* DDHidLib.framework */; }; + 55D593750BAE3B7500364849 /* DDHidLib.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 55193E500B93F2EE004C0C98 /* DDHidLib.framework */; }; + 55D5937B0BAE3B8800364849 /* DDHidKeyboard.h in Headers */ = {isa = PBXBuildFile; fileRef = 55CA60E30BA0F2530012CF7B /* DDHidKeyboard.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 55D5937C0BAE3B8800364849 /* DDHidKeyboard.m in Sources */ = {isa = PBXBuildFile; fileRef = 55CA60E40BA0F2530012CF7B /* DDHidKeyboard.m */; }; + 55D593870BAE3BB700364849 /* DDHidStandardUsages.plist in Resources */ = {isa = PBXBuildFile; fileRef = 55917F760B54535B005308AC /* DDHidStandardUsages.plist */; }; + 55DCD9C60B55D35D000648E5 /* WatcherWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = 55DCD9C50B55D35D000648E5 /* WatcherWindowController.m */; }; + 55DCD9E00B55D503000648E5 /* EventWatcher.nib in Resources */ = {isa = PBXBuildFile; fileRef = 55DCD9DE0B55D503000648E5 /* EventWatcher.nib */; }; + 55FC9FDB0BB76D8D0095FC7B /* DDHidKeyboardBarcodeScanner.h in Headers */ = {isa = PBXBuildFile; fileRef = 55FC9FD90BB76D8D0095FC7B /* DDHidKeyboardBarcodeScanner.h */; }; + 55FC9FDC0BB76D8D0095FC7B /* DDHidKeyboardBarcodeScanner.m in Sources */ = {isa = PBXBuildFile; fileRef = 55FC9FDA0BB76D8D0095FC7B /* DDHidKeyboardBarcodeScanner.m */; }; + 55FC9FDD0BB76D8D0095FC7B /* DDHidKeyboardBarcodeScanner.h in Headers */ = {isa = PBXBuildFile; fileRef = 55FC9FD90BB76D8D0095FC7B /* DDHidKeyboardBarcodeScanner.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 55FC9FDE0BB76D8D0095FC7B /* DDHidKeyboardBarcodeScanner.m in Sources */ = {isa = PBXBuildFile; fileRef = 55FC9FDA0BB76D8D0095FC7B /* DDHidKeyboardBarcodeScanner.m */; }; + 55FD65CB0B5DD57200325FEF /* DeviceTestController.m in Sources */ = {isa = PBXBuildFile; fileRef = 55FD65CA0B5DD57200325FEF /* DeviceTestController.m */; }; + 55FD66D50B5DDC3F00325FEF /* DDHidJoystick.h in Headers */ = {isa = PBXBuildFile; fileRef = 55FD66D30B5DDC3F00325FEF /* DDHidJoystick.h */; }; + 55FD66D60B5DDC3F00325FEF /* DDHidJoystick.m in Sources */ = {isa = PBXBuildFile; fileRef = 55FD66D40B5DDC3F00325FEF /* DDHidJoystick.m */; }; + 55FD66FD0B5DDD2100325FEF /* JoystickPaneController.m in Sources */ = {isa = PBXBuildFile; fileRef = 55FD66FC0B5DDD2100325FEF /* JoystickPaneController.m */; }; + 55FD67750B5DDF8200325FEF /* ButtonState.m in Sources */ = {isa = PBXBuildFile; fileRef = 55FD67740B5DDF8200325FEF /* ButtonState.m */; }; + 55FD67CC0B5DE18600325FEF /* DDHidLib.h in Headers */ = {isa = PBXBuildFile; fileRef = 55FD67CB0B5DE18600325FEF /* DDHidLib.h */; }; + 8D11072A0486CEB800E47090 /* MainMenu.nib in Resources */ = {isa = PBXBuildFile; fileRef = 29B97318FDCFA39411CA2CEA /* MainMenu.nib */; }; + 8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */; }; + 8D11072D0486CEB800E47090 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; settings = {ATTRIBUTES = (); }; }; + 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; }; + B366F1B016F5DE9800C0BA49 /* DDHidAppleMikey.h in Headers */ = {isa = PBXBuildFile; fileRef = B366F1AE16F5DE9800C0BA49 /* DDHidAppleMikey.h */; }; + B366F1B116F5DE9800C0BA49 /* DDHidAppleMikey.m in Sources */ = {isa = PBXBuildFile; fileRef = B366F1AF16F5DE9800C0BA49 /* DDHidAppleMikey.m */; }; + B366F1B316F5E20800C0BA49 /* DDHidAppleMikey.m in Sources */ = {isa = PBXBuildFile; fileRef = B366F1AF16F5DE9800C0BA49 /* DDHidAppleMikey.m */; }; + B366F1B616F5E64B00C0BA49 /* AppleMikeyPaneController.m in Sources */ = {isa = PBXBuildFile; fileRef = B366F1B516F5E64B00C0BA49 /* AppleMikeyPaneController.m */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 551711120B8F41F500C82155 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */; + proxyType = 1; + remoteGlobalIDString = 8D1107260486CEB800E47090; + remoteInfo = HIDBrowser; + }; + 551711140B8F41F500C82155 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */; + proxyType = 1; + remoteGlobalIDString = 559CBAE00B5B313000C8FD74; + remoteInfo = HIDDeviceTest; + }; + 55D593250BAE3AA800364849 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */; + proxyType = 1; + remoteGlobalIDString = 55193E4F0B93F2EE004C0C98; + remoteInfo = DDHidLib; + }; + 55D5935C0BAE3B1E00364849 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */; + proxyType = 1; + remoteGlobalIDString = 55193E4F0B93F2EE004C0C98; + remoteInfo = DDHidLib; + }; + 55D593600BAE3B3300364849 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */; + proxyType = 1; + remoteGlobalIDString = 55193E4F0B93F2EE004C0C98; + remoteInfo = DDHidLib; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 55D593350BAE3AC800364849 /* Copy Files to Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + 55D593390BAE3ADF00364849 /* DDHidLib.framework in Copy Files to Frameworks */, + ); + name = "Copy Files to Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; + 55D593620BAE3B4B00364849 /* Copy Files to Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + 55D593660BAE3B5D00364849 /* DDHidLib.framework in Copy Files to Frameworks */, + ); + name = "Copy Files to Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 089C165DFE840E0CC02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = ""; }; + 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = ""; }; + 13E42FB307B3F0F600E4EEF1 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = /System/Library/Frameworks/CoreData.framework; sourceTree = ""; }; + 29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 29B97319FDCFA39411CA2CEA /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = English.lproj/MainMenu.nib; sourceTree = ""; }; + 29B97324FDCFA39411CA2CEA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = ""; }; + 29B97325FDCFA39411CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = ""; }; + 32CA4F630368D1EE00C91783 /* HIDBrowser_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HIDBrowser_Prefix.pch; sourceTree = ""; }; + 55170D340B8EC2CE00C82155 /* DDHidAppleRemote.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDHidAppleRemote.h; sourceTree = ""; }; + 55170D350B8EC2CE00C82155 /* DDHidAppleRemote.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDHidAppleRemote.m; sourceTree = ""; }; + 55170E0B0B8ECCAC00C82155 /* AppleRemotePaneController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppleRemotePaneController.h; sourceTree = ""; }; + 55170E0C0B8ECCAC00C82155 /* AppleRemotePaneController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppleRemotePaneController.m; sourceTree = ""; }; + 55170E630B8ECEF600C82155 /* RemoteFeedbackView.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = RemoteFeedbackView.h; sourceTree = ""; }; + 55170E640B8ECEF600C82155 /* RemoteFeedbackView.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = RemoteFeedbackView.m; sourceTree = ""; }; + 55170E660B8ECF0000C82155 /* AppleRemote.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = AppleRemote.tiff; sourceTree = ""; }; + 55193E500B93F2EE004C0C98 /* DDHidLib.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = DDHidLib.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 55193E510B93F2EE004C0C98 /* DDHidLib-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "DDHidLib-Info.plist"; sourceTree = ""; }; + 556E1E680B5359F9002F709C /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = /System/Library/Frameworks/IOKit.framework; sourceTree = ""; }; + 55917B4F0B533C82005308AC /* DDHidDevice.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDHidDevice.h; sourceTree = ""; }; + 55917B500B533C82005308AC /* DDHidDevice.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDHidDevice.m; sourceTree = ""; }; + 55917B620B53408C005308AC /* HidBrowserController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HidBrowserController.h; sourceTree = ""; }; + 55917B630B53408C005308AC /* HidBrowserController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HidBrowserController.m; sourceTree = ""; }; + 55917E1A0B53E454005308AC /* HexFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HexFormatter.h; sourceTree = ""; }; + 55917E1B0B53E454005308AC /* HexFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HexFormatter.m; sourceTree = ""; }; + 55917E6F0B5413E7005308AC /* DDHidElement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDHidElement.h; sourceTree = ""; }; + 55917E700B5413E7005308AC /* DDHidElement.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDHidElement.m; sourceTree = ""; }; + 55917E720B541541005308AC /* NSDictionary+DDHidExtras.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDictionary+DDHidExtras.h"; sourceTree = ""; }; + 55917E730B541541005308AC /* NSDictionary+DDHidExtras.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSDictionary+DDHidExtras.m"; sourceTree = ""; }; + 55917F610B545104005308AC /* DDHidUsageTables.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDHidUsageTables.h; sourceTree = ""; }; + 55917F620B545104005308AC /* DDHidUsageTables.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDHidUsageTables.m; sourceTree = ""; }; + 55917F760B54535B005308AC /* DDHidStandardUsages.plist */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.plist.xml; name = DDHidStandardUsages.plist; path = ../lib/DDHidStandardUsages.plist; sourceTree = ""; }; + 559180CA0B575698005308AC /* DDHidQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDHidQueue.h; sourceTree = ""; }; + 559180CB0B575698005308AC /* DDHidQueue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDHidQueue.m; sourceTree = ""; }; + 559181A40B576149005308AC /* DDHidEvent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDHidEvent.h; sourceTree = ""; }; + 559181A50B576149005308AC /* DDHidEvent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDHidEvent.m; sourceTree = ""; }; + 559CB82B0B595B2F00C8FD74 /* DDHidUsage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDHidUsage.h; sourceTree = ""; }; + 559CB82C0B595B2F00C8FD74 /* DDHidUsage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDHidUsage.m; sourceTree = ""; }; + 559CBAE10B5B313000C8FD74 /* HIDDeviceTest.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = HIDDeviceTest.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 559CBAE90B5B31AB00C8FD74 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 559CBAEA0B5B31AB00C8FD74 /* main.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 559CBBCC0B5B336600C8FD74 /* libddhid.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libddhid.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 559CBC2A0B5B34C300C8FD74 /* DDHidMouse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDHidMouse.h; sourceTree = ""; }; + 559CBC2B0B5B34C300C8FD74 /* DDHidMouse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDHidMouse.m; sourceTree = ""; }; + 559CBCA70B5B3BCE00C8FD74 /* MousePaneController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MousePaneController.h; sourceTree = ""; }; + 559CBCA80B5B3BCE00C8FD74 /* MousePaneController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MousePaneController.m; sourceTree = ""; }; + 55A000500B5D7C06001B47E5 /* BoolFormatter.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = BoolFormatter.m; sourceTree = ""; }; + 55A000510B5D7C06001B47E5 /* BoolFormatter.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = BoolFormatter.h; sourceTree = ""; }; + 55BE6DCB0B8033010085514D /* NSXReturnThrowError.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = NSXReturnThrowError.h; sourceTree = ""; }; + 55BE6DCC0B8033010085514D /* NSXReturnThrowError.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = NSXReturnThrowError.m; sourceTree = ""; }; + 55CA60E30BA0F2530012CF7B /* DDHidKeyboard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDHidKeyboard.h; sourceTree = ""; }; + 55CA60E40BA0F2530012CF7B /* DDHidKeyboard.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDHidKeyboard.m; sourceTree = ""; }; + 55CA66890BA38AEF0012CF7B /* KeyboardPaneController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KeyboardPaneController.h; sourceTree = ""; }; + 55CA668A0BA38AEF0012CF7B /* KeyboardPaneController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KeyboardPaneController.m; sourceTree = ""; }; + 55D592200BAE2E4500364849 /* versions.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = versions.xcconfig; sourceTree = ""; }; + 55D5927C0BAE306E00364849 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = ""; }; + 55D592930BAE30B600364849 /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = English.lproj/MainMenu.nib; sourceTree = ""; }; + 55DCD9C40B55D35D000648E5 /* WatcherWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WatcherWindowController.h; sourceTree = ""; }; + 55DCD9C50B55D35D000648E5 /* WatcherWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WatcherWindowController.m; sourceTree = ""; }; + 55DCD9DF0B55D503000648E5 /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = English.lproj/EventWatcher.nib; sourceTree = ""; }; + 55FC9FD90BB76D8D0095FC7B /* DDHidKeyboardBarcodeScanner.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DDHidKeyboardBarcodeScanner.h; sourceTree = ""; }; + 55FC9FDA0BB76D8D0095FC7B /* DDHidKeyboardBarcodeScanner.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = DDHidKeyboardBarcodeScanner.m; sourceTree = ""; }; + 55FD65C90B5DD57200325FEF /* DeviceTestController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DeviceTestController.h; sourceTree = ""; }; + 55FD65CA0B5DD57200325FEF /* DeviceTestController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DeviceTestController.m; sourceTree = ""; }; + 55FD66D30B5DDC3F00325FEF /* DDHidJoystick.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDHidJoystick.h; sourceTree = ""; }; + 55FD66D40B5DDC3F00325FEF /* DDHidJoystick.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDHidJoystick.m; sourceTree = ""; }; + 55FD66FB0B5DDD2100325FEF /* JoystickPaneController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JoystickPaneController.h; sourceTree = ""; }; + 55FD66FC0B5DDD2100325FEF /* JoystickPaneController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JoystickPaneController.m; sourceTree = ""; }; + 55FD67730B5DDF8200325FEF /* ButtonState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ButtonState.h; sourceTree = ""; }; + 55FD67740B5DDF8200325FEF /* ButtonState.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ButtonState.m; sourceTree = ""; }; + 55FD67CB0B5DE18600325FEF /* DDHidLib.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDHidLib.h; sourceTree = ""; }; + 8D1107310486CEB800E47090 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; + 8D1107320486CEB800E47090 /* HIDBrowser.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = HIDBrowser.app; sourceTree = BUILT_PRODUCTS_DIR; }; + B366F1AE16F5DE9800C0BA49 /* DDHidAppleMikey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DDHidAppleMikey.h; sourceTree = ""; }; + B366F1AF16F5DE9800C0BA49 /* DDHidAppleMikey.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DDHidAppleMikey.m; sourceTree = ""; }; + B366F1B416F5E64A00C0BA49 /* AppleMikeyPaneController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppleMikeyPaneController.h; sourceTree = ""; }; + B366F1B516F5E64B00C0BA49 /* AppleMikeyPaneController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppleMikeyPaneController.m; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 55193E4E0B93F2EE004C0C98 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 55193E700B93F35A004C0C98 /* IOKit.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 559CBADF0B5B313000C8FD74 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 55D593750BAE3B7500364849 /* DDHidLib.framework in Frameworks */, + 559CBB940B5B31EA00C8FD74 /* IOKit.framework in Frameworks */, + 559CBB930B5B31E300C8FD74 /* Cocoa.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 559CBBCA0B5B336600C8FD74 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 8D11072E0486CEB800E47090 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 55D593290BAE3ABD00364849 /* DDHidLib.framework in Frameworks */, + 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */, + 556E1E690B5359F9002F709C /* IOKit.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 080E96DDFE201D6D7F000001 /* Classes */ = { + isa = PBXGroup; + children = ( + 55917B620B53408C005308AC /* HidBrowserController.h */, + 55917B630B53408C005308AC /* HidBrowserController.m */, + 55917E1A0B53E454005308AC /* HexFormatter.h */, + 55917E1B0B53E454005308AC /* HexFormatter.m */, + 55DCD9C40B55D35D000648E5 /* WatcherWindowController.h */, + 55DCD9C50B55D35D000648E5 /* WatcherWindowController.m */, + ); + name = Classes; + sourceTree = ""; + }; + 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */ = { + isa = PBXGroup; + children = ( + 556E1E680B5359F9002F709C /* IOKit.framework */, + 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */, + ); + name = "Linked Frameworks"; + sourceTree = ""; + }; + 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */ = { + isa = PBXGroup; + children = ( + 29B97324FDCFA39411CA2CEA /* AppKit.framework */, + 13E42FB307B3F0F600E4EEF1 /* CoreData.framework */, + 29B97325FDCFA39411CA2CEA /* Foundation.framework */, + ); + name = "Other Frameworks"; + sourceTree = ""; + }; + 19C28FACFE9D520D11CA2CBB /* Products */ = { + isa = PBXGroup; + children = ( + 8D1107320486CEB800E47090 /* HIDBrowser.app */, + 559CBAE10B5B313000C8FD74 /* HIDDeviceTest.app */, + 559CBBCC0B5B336600C8FD74 /* libddhid.a */, + 55193E500B93F2EE004C0C98 /* DDHidLib.framework */, + ); + name = Products; + sourceTree = ""; + }; + 29B97314FDCFA39411CA2CEA /* HIDBrowser */ = { + isa = PBXGroup; + children = ( + 559CBAE80B5B31AB00C8FD74 /* device_test */, + 559CBAA10B5B2F4400C8FD74 /* browser */, + 55917B4C0B533C53005308AC /* lib */, + 55BE6DC90B8033010085514D /* vendor */, + 29B97323FDCFA39411CA2CEA /* Frameworks */, + 19C28FACFE9D520D11CA2CBB /* Products */, + 55193E510B93F2EE004C0C98 /* DDHidLib-Info.plist */, + 55D592200BAE2E4500364849 /* versions.xcconfig */, + ); + name = HIDBrowser; + sourceTree = ""; + }; + 29B97315FDCFA39411CA2CEA /* Other Sources */ = { + isa = PBXGroup; + children = ( + 32CA4F630368D1EE00C91783 /* HIDBrowser_Prefix.pch */, + 29B97316FDCFA39411CA2CEA /* main.m */, + ); + name = "Other Sources"; + sourceTree = ""; + }; + 29B97317FDCFA39411CA2CEA /* Resources */ = { + isa = PBXGroup; + children = ( + 55917F760B54535B005308AC /* DDHidStandardUsages.plist */, + 8D1107310486CEB800E47090 /* Info.plist */, + 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */, + 29B97318FDCFA39411CA2CEA /* MainMenu.nib */, + 55DCD9DE0B55D503000648E5 /* EventWatcher.nib */, + ); + name = Resources; + sourceTree = ""; + }; + 29B97323FDCFA39411CA2CEA /* Frameworks */ = { + isa = PBXGroup; + children = ( + 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */, + 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */, + ); + name = Frameworks; + sourceTree = ""; + }; + 5547B9D20B8E1C02003C6ADE /* Classes */ = { + isa = PBXGroup; + children = ( + B366F1B416F5E64A00C0BA49 /* AppleMikeyPaneController.h */, + B366F1B516F5E64B00C0BA49 /* AppleMikeyPaneController.m */, + 55FD65C90B5DD57200325FEF /* DeviceTestController.h */, + 55FD65CA0B5DD57200325FEF /* DeviceTestController.m */, + 559CBCA70B5B3BCE00C8FD74 /* MousePaneController.h */, + 559CBCA80B5B3BCE00C8FD74 /* MousePaneController.m */, + 55FD66FB0B5DDD2100325FEF /* JoystickPaneController.h */, + 55FD66FC0B5DDD2100325FEF /* JoystickPaneController.m */, + 55CA66890BA38AEF0012CF7B /* KeyboardPaneController.h */, + 55CA668A0BA38AEF0012CF7B /* KeyboardPaneController.m */, + 55170E0B0B8ECCAC00C82155 /* AppleRemotePaneController.h */, + 55170E0C0B8ECCAC00C82155 /* AppleRemotePaneController.m */, + 55170E630B8ECEF600C82155 /* RemoteFeedbackView.h */, + 55170E640B8ECEF600C82155 /* RemoteFeedbackView.m */, + 55A000510B5D7C06001B47E5 /* BoolFormatter.h */, + 55A000500B5D7C06001B47E5 /* BoolFormatter.m */, + 55FD67730B5DDF8200325FEF /* ButtonState.h */, + 55FD67740B5DDF8200325FEF /* ButtonState.m */, + ); + name = Classes; + sourceTree = ""; + }; + 55917B4C0B533C53005308AC /* lib */ = { + isa = PBXGroup; + children = ( + B366F1AE16F5DE9800C0BA49 /* DDHidAppleMikey.h */, + B366F1AF16F5DE9800C0BA49 /* DDHidAppleMikey.m */, + 55917B4F0B533C82005308AC /* DDHidDevice.h */, + 55917B500B533C82005308AC /* DDHidDevice.m */, + 55917E6F0B5413E7005308AC /* DDHidElement.h */, + 55917E700B5413E7005308AC /* DDHidElement.m */, + 559CB82B0B595B2F00C8FD74 /* DDHidUsage.h */, + 559CB82C0B595B2F00C8FD74 /* DDHidUsage.m */, + 559180CA0B575698005308AC /* DDHidQueue.h */, + 559180CB0B575698005308AC /* DDHidQueue.m */, + 559181A40B576149005308AC /* DDHidEvent.h */, + 559181A50B576149005308AC /* DDHidEvent.m */, + 55917F610B545104005308AC /* DDHidUsageTables.h */, + 55917F620B545104005308AC /* DDHidUsageTables.m */, + 55917E720B541541005308AC /* NSDictionary+DDHidExtras.h */, + 55917E730B541541005308AC /* NSDictionary+DDHidExtras.m */, + 559CBC2A0B5B34C300C8FD74 /* DDHidMouse.h */, + 55FD66D30B5DDC3F00325FEF /* DDHidJoystick.h */, + 559CBC2B0B5B34C300C8FD74 /* DDHidMouse.m */, + 55FD66D40B5DDC3F00325FEF /* DDHidJoystick.m */, + 55CA60E30BA0F2530012CF7B /* DDHidKeyboard.h */, + 55CA60E40BA0F2530012CF7B /* DDHidKeyboard.m */, + 55170D340B8EC2CE00C82155 /* DDHidAppleRemote.h */, + 55170D350B8EC2CE00C82155 /* DDHidAppleRemote.m */, + 55FC9FD90BB76D8D0095FC7B /* DDHidKeyboardBarcodeScanner.h */, + 55FC9FDA0BB76D8D0095FC7B /* DDHidKeyboardBarcodeScanner.m */, + 55FD67CB0B5DE18600325FEF /* DDHidLib.h */, + ); + path = lib; + sourceTree = ""; + }; + 559CBAA10B5B2F4400C8FD74 /* browser */ = { + isa = PBXGroup; + children = ( + 080E96DDFE201D6D7F000001 /* Classes */, + 29B97315FDCFA39411CA2CEA /* Other Sources */, + 29B97317FDCFA39411CA2CEA /* Resources */, + ); + path = browser; + sourceTree = ""; + }; + 559CBAE80B5B31AB00C8FD74 /* device_test */ = { + isa = PBXGroup; + children = ( + 5547B9D20B8E1C02003C6ADE /* Classes */, + 559CBAEA0B5B31AB00C8FD74 /* main.m */, + 559CBBA20B5B31FD00C8FD74 /* Resources */, + ); + path = device_test; + sourceTree = ""; + }; + 559CBBA20B5B31FD00C8FD74 /* Resources */ = { + isa = PBXGroup; + children = ( + 55170E660B8ECF0000C82155 /* AppleRemote.tiff */, + 559CBAE90B5B31AB00C8FD74 /* Info.plist */, + 55D5927B0BAE306E00364849 /* InfoPlist.strings */, + 55D592920BAE30B600364849 /* MainMenu.nib */, + ); + name = Resources; + sourceTree = ""; + }; + 55BE6DC90B8033010085514D /* vendor */ = { + isa = PBXGroup; + children = ( + 55BE6DCA0B8033010085514D /* NSXReturnThrowError */, + ); + path = vendor; + sourceTree = ""; + }; + 55BE6DCA0B8033010085514D /* NSXReturnThrowError */ = { + isa = PBXGroup; + children = ( + 55BE6DCB0B8033010085514D /* NSXReturnThrowError.h */, + 55BE6DCC0B8033010085514D /* NSXReturnThrowError.m */, + ); + path = NSXReturnThrowError; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 55193E4B0B93F2EE004C0C98 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 30B1E6A918CBA620004E111E /* DDHidAppleMikey.h in Headers */, + 55193E580B93F31D004C0C98 /* DDHidDevice.h in Headers */, + 55193E5A0B93F31D004C0C98 /* DDHidElement.h in Headers */, + 55193E5C0B93F31D004C0C98 /* DDHidUsage.h in Headers */, + 55193E5E0B93F31D004C0C98 /* DDHidQueue.h in Headers */, + 55193E600B93F31D004C0C98 /* DDHidEvent.h in Headers */, + 55193E620B93F31D004C0C98 /* DDHidUsageTables.h in Headers */, + 55193E640B93F31D004C0C98 /* NSDictionary+DDHidExtras.h in Headers */, + 55193E660B93F31D004C0C98 /* DDHidMouse.h in Headers */, + 55D5937B0BAE3B8800364849 /* DDHidKeyboard.h in Headers */, + 55193E680B93F31D004C0C98 /* DDHidJoystick.h in Headers */, + 55193E6A0B93F31D004C0C98 /* DDHidAppleRemote.h in Headers */, + 55FC9FDD0BB76D8D0095FC7B /* DDHidKeyboardBarcodeScanner.h in Headers */, + 55193E6C0B93F31D004C0C98 /* DDHidLib.h in Headers */, + 55193F110B93F36F004C0C98 /* NSXReturnThrowError.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 559CBBC80B5B336600C8FD74 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 559CBBD10B5B337600C8FD74 /* DDHidDevice.h in Headers */, + 559CBBD30B5B337600C8FD74 /* DDHidElement.h in Headers */, + 559CBBD50B5B337600C8FD74 /* DDHidUsage.h in Headers */, + 559CBBD70B5B337600C8FD74 /* DDHidQueue.h in Headers */, + 559CBBD90B5B337600C8FD74 /* DDHidEvent.h in Headers */, + 559CBBDB0B5B337600C8FD74 /* DDHidUsageTables.h in Headers */, + 559CBBDD0B5B337600C8FD74 /* NSDictionary+DDHidExtras.h in Headers */, + 559CBC2C0B5B34C300C8FD74 /* DDHidMouse.h in Headers */, + 55FD66D50B5DDC3F00325FEF /* DDHidJoystick.h in Headers */, + 55FD67CC0B5DE18600325FEF /* DDHidLib.h in Headers */, + 55BE6DCD0B8033010085514D /* NSXReturnThrowError.h in Headers */, + 55170D360B8EC2CE00C82155 /* DDHidAppleRemote.h in Headers */, + 55CA60E50BA0F2530012CF7B /* DDHidKeyboard.h in Headers */, + 55FC9FDB0BB76D8D0095FC7B /* DDHidKeyboardBarcodeScanner.h in Headers */, + B366F1B016F5DE9800C0BA49 /* DDHidAppleMikey.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 55193E4F0B93F2EE004C0C98 /* DDHidLib */ = { + isa = PBXNativeTarget; + buildConfigurationList = 55193E530B93F2EF004C0C98 /* Build configuration list for PBXNativeTarget "DDHidLib" */; + buildPhases = ( + 55193E4B0B93F2EE004C0C98 /* Headers */, + 55193E4C0B93F2EE004C0C98 /* Resources */, + 55193E4D0B93F2EE004C0C98 /* Sources */, + 55193E4E0B93F2EE004C0C98 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = DDHidLib; + productName = DDHidLib; + productReference = 55193E500B93F2EE004C0C98 /* DDHidLib.framework */; + productType = "com.apple.product-type.framework"; + }; + 559CBAE00B5B313000C8FD74 /* HIDDeviceTest */ = { + isa = PBXNativeTarget; + buildConfigurationList = 559CBAE40B5B313000C8FD74 /* Build configuration list for PBXNativeTarget "HIDDeviceTest" */; + buildPhases = ( + 559CBADD0B5B313000C8FD74 /* Resources */, + 559CBADE0B5B313000C8FD74 /* Sources */, + 559CBADF0B5B313000C8FD74 /* Frameworks */, + 55D593620BAE3B4B00364849 /* Copy Files to Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 55D593610BAE3B3300364849 /* PBXTargetDependency */, + ); + name = HIDDeviceTest; + productName = HIDDeviceTest; + productReference = 559CBAE10B5B313000C8FD74 /* HIDDeviceTest.app */; + productType = "com.apple.product-type.application"; + }; + 559CBBCB0B5B336600C8FD74 /* ddhid */ = { + isa = PBXNativeTarget; + buildConfigurationList = 559CBBE60B5B338B00C8FD74 /* Build configuration list for PBXNativeTarget "ddhid" */; + buildPhases = ( + 559CBBC80B5B336600C8FD74 /* Headers */, + 559CBBC90B5B336600C8FD74 /* Sources */, + 559CBBCA0B5B336600C8FD74 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = ddhid; + productName = ddhid; + productReference = 559CBBCC0B5B336600C8FD74 /* libddhid.a */; + productType = "com.apple.product-type.library.static"; + }; + 8D1107260486CEB800E47090 /* HIDBrowser */ = { + isa = PBXNativeTarget; + buildConfigurationList = C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "HIDBrowser" */; + buildPhases = ( + 8D1107290486CEB800E47090 /* Resources */, + 8D11072C0486CEB800E47090 /* Sources */, + 8D11072E0486CEB800E47090 /* Frameworks */, + 55D593350BAE3AC800364849 /* Copy Files to Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 55D593260BAE3AA800364849 /* PBXTargetDependency */, + ); + name = HIDBrowser; + productInstallPath = "$(HOME)/Applications"; + productName = HIDBrowser; + productReference = 8D1107320486CEB800E47090 /* HIDBrowser.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 29B97313FDCFA39411CA2CEA /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0460; + }; + buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "DDHidLib" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 1; + knownRegions = ( + en, + ); + mainGroup = 29B97314FDCFA39411CA2CEA /* HIDBrowser */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 551711110B8F41EB00C82155 /* All */, + 8D1107260486CEB800E47090 /* HIDBrowser */, + 559CBAE00B5B313000C8FD74 /* HIDDeviceTest */, + 559CBBCB0B5B336600C8FD74 /* ddhid */, + 55193E4F0B93F2EE004C0C98 /* DDHidLib */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 55193E4C0B93F2EE004C0C98 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 55D593870BAE3BB700364849 /* DDHidStandardUsages.plist in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 559CBADD0B5B313000C8FD74 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 55170E670B8ECF0000C82155 /* AppleRemote.tiff in Resources */, + 55D5927D0BAE306E00364849 /* InfoPlist.strings in Resources */, + 55D592940BAE30B600364849 /* MainMenu.nib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 8D1107290486CEB800E47090 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8D11072A0486CEB800E47090 /* MainMenu.nib in Resources */, + 8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */, + 55DCD9E00B55D503000648E5 /* EventWatcher.nib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 55193E4D0B93F2EE004C0C98 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 55193E590B93F31D004C0C98 /* DDHidDevice.m in Sources */, + 55193E5B0B93F31D004C0C98 /* DDHidElement.m in Sources */, + 55193E5D0B93F31D004C0C98 /* DDHidUsage.m in Sources */, + 55193E5F0B93F31D004C0C98 /* DDHidQueue.m in Sources */, + 55193E610B93F31D004C0C98 /* DDHidEvent.m in Sources */, + 55193E630B93F31D004C0C98 /* DDHidUsageTables.m in Sources */, + 55193E650B93F31D004C0C98 /* NSDictionary+DDHidExtras.m in Sources */, + 55193E670B93F31D004C0C98 /* DDHidMouse.m in Sources */, + 55193E690B93F31D004C0C98 /* DDHidJoystick.m in Sources */, + 55193E6B0B93F31D004C0C98 /* DDHidAppleRemote.m in Sources */, + 55193F120B93F371004C0C98 /* NSXReturnThrowError.m in Sources */, + 55D5937C0BAE3B8800364849 /* DDHidKeyboard.m in Sources */, + 55FC9FDE0BB76D8D0095FC7B /* DDHidKeyboardBarcodeScanner.m in Sources */, + B366F1B316F5E20800C0BA49 /* DDHidAppleMikey.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 559CBADE0B5B313000C8FD74 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 559CBAEC0B5B31AB00C8FD74 /* main.m in Sources */, + 559CBCA90B5B3BCE00C8FD74 /* MousePaneController.m in Sources */, + 55A000520B5D7C06001B47E5 /* BoolFormatter.m in Sources */, + 55FD65CB0B5DD57200325FEF /* DeviceTestController.m in Sources */, + 55FD66FD0B5DDD2100325FEF /* JoystickPaneController.m in Sources */, + 55FD67750B5DDF8200325FEF /* ButtonState.m in Sources */, + 55170E0D0B8ECCAC00C82155 /* AppleRemotePaneController.m in Sources */, + 55170E650B8ECEF600C82155 /* RemoteFeedbackView.m in Sources */, + 55CA668B0BA38AEF0012CF7B /* KeyboardPaneController.m in Sources */, + B366F1B616F5E64B00C0BA49 /* AppleMikeyPaneController.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 559CBBC90B5B336600C8FD74 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 559CBBD20B5B337600C8FD74 /* DDHidDevice.m in Sources */, + 559CBBD40B5B337600C8FD74 /* DDHidElement.m in Sources */, + 559CBBD60B5B337600C8FD74 /* DDHidUsage.m in Sources */, + 559CBBD80B5B337600C8FD74 /* DDHidQueue.m in Sources */, + 559CBBDA0B5B337600C8FD74 /* DDHidEvent.m in Sources */, + 559CBBDC0B5B337600C8FD74 /* DDHidUsageTables.m in Sources */, + 559CBC260B5B349100C8FD74 /* NSDictionary+DDHidExtras.m in Sources */, + 559CBC2D0B5B34C300C8FD74 /* DDHidMouse.m in Sources */, + 55FD66D60B5DDC3F00325FEF /* DDHidJoystick.m in Sources */, + 55BE6DCE0B8033010085514D /* NSXReturnThrowError.m in Sources */, + 55170D370B8EC2CE00C82155 /* DDHidAppleRemote.m in Sources */, + 55CA60E60BA0F2530012CF7B /* DDHidKeyboard.m in Sources */, + 55FC9FDC0BB76D8D0095FC7B /* DDHidKeyboardBarcodeScanner.m in Sources */, + B366F1B116F5DE9800C0BA49 /* DDHidAppleMikey.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 8D11072C0486CEB800E47090 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8D11072D0486CEB800E47090 /* main.m in Sources */, + 55917B640B53408C005308AC /* HidBrowserController.m in Sources */, + 55917E1C0B53E454005308AC /* HexFormatter.m in Sources */, + 55DCD9C60B55D35D000648E5 /* WatcherWindowController.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 551711130B8F41F500C82155 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 8D1107260486CEB800E47090 /* HIDBrowser */; + targetProxy = 551711120B8F41F500C82155 /* PBXContainerItemProxy */; + }; + 551711150B8F41F500C82155 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 559CBAE00B5B313000C8FD74 /* HIDDeviceTest */; + targetProxy = 551711140B8F41F500C82155 /* PBXContainerItemProxy */; + }; + 55D593260BAE3AA800364849 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 55193E4F0B93F2EE004C0C98 /* DDHidLib */; + targetProxy = 55D593250BAE3AA800364849 /* PBXContainerItemProxy */; + }; + 55D5935D0BAE3B1E00364849 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 55193E4F0B93F2EE004C0C98 /* DDHidLib */; + targetProxy = 55D5935C0BAE3B1E00364849 /* PBXContainerItemProxy */; + }; + 55D593610BAE3B3300364849 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 55193E4F0B93F2EE004C0C98 /* DDHidLib */; + targetProxy = 55D593600BAE3B3300364849 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + 089C165DFE840E0CC02AAC07 /* English */, + ); + name = InfoPlist.strings; + sourceTree = ""; + }; + 29B97318FDCFA39411CA2CEA /* MainMenu.nib */ = { + isa = PBXVariantGroup; + children = ( + 29B97319FDCFA39411CA2CEA /* English */, + ); + name = MainMenu.nib; + sourceTree = ""; + }; + 55D5927B0BAE306E00364849 /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + 55D5927C0BAE306E00364849 /* English */, + ); + name = InfoPlist.strings; + sourceTree = ""; + }; + 55D592920BAE30B600364849 /* MainMenu.nib */ = { + isa = PBXVariantGroup; + children = ( + 55D592930BAE30B600364849 /* English */, + ); + name = MainMenu.nib; + sourceTree = ""; + }; + 55DCD9DE0B55D503000648E5 /* EventWatcher.nib */ = { + isa = PBXVariantGroup; + children = ( + 55DCD9DF0B55D503000648E5 /* English */, + ); + name = EventWatcher.nib; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 551711290B8F420E00C82155 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + GCC_DYNAMIC_NO_PIC = NO; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + PRODUCT_NAME = All; + }; + name = Debug; + }; + 5517112A0B8F420E00C82155 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = YES; + GCC_GENERATE_DEBUGGING_SYMBOLS = NO; + PRODUCT_NAME = All; + ZERO_LINK = NO; + }; + name = Release; + }; + 55193E540B93F2EF004C0C98 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + FRAMEWORK_VERSION = A; + GCC_DYNAMIC_NO_PIC = NO; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + GCC_MODEL_TUNING = G5; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/AppKit.framework/Headers/AppKit.h"; + INFOPLIST_FILE = "DDHidLib-Info.plist"; + INSTALL_PATH = "@loader_path/../Frameworks"; + OTHER_LDFLAGS = ( + "-framework", + Foundation, + "-framework", + AppKit, + ); + PRODUCT_NAME = DDHidLib; + ZERO_LINK = NO; + }; + name = Debug; + }; + 55193E550B93F2EF004C0C98 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + FRAMEWORK_VERSION = A; + GCC_GENERATE_DEBUGGING_SYMBOLS = NO; + GCC_MODEL_TUNING = G5; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/AppKit.framework/Headers/AppKit.h"; + INFOPLIST_FILE = "DDHidLib-Info.plist"; + INSTALL_PATH = "@loader_path/../Frameworks"; + OTHER_LDFLAGS = ( + "-framework", + Foundation, + "-framework", + AppKit, + ); + PRODUCT_NAME = DDHidLib; + ZERO_LINK = NO; + }; + name = Release; + }; + 559CBAE50B5B313000C8FD74 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 55D592200BAE2E4500364849 /* versions.xcconfig */; + buildSettings = { + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + GCC_DYNAMIC_NO_PIC = NO; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/AppKit.framework/Headers/AppKit.h"; + INFOPLIST_FILE = device_test/Info.plist; + INSTALL_PATH = "$(HOME)/Applications"; + OTHER_LDFLAGS = ( + "-ObjC", + "-framework", + Foundation, + "-framework", + AppKit, + ); + PRODUCT_NAME = HIDDeviceTest; + WRAPPER_EXTENSION = app; + }; + name = Debug; + }; + 559CBAE60B5B313000C8FD74 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 55D592200BAE2E4500364849 /* versions.xcconfig */; + buildSettings = { + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = YES; + GCC_GENERATE_DEBUGGING_SYMBOLS = NO; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/AppKit.framework/Headers/AppKit.h"; + INFOPLIST_FILE = device_test/Info.plist; + INSTALL_PATH = "$(HOME)/Applications"; + OTHER_LDFLAGS = ( + "-ObjC", + "-framework", + Foundation, + "-framework", + AppKit, + ); + PRODUCT_NAME = HIDDeviceTest; + WRAPPER_EXTENSION = app; + }; + name = Release; + }; + 559CBBE70B5B338B00C8FD74 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + GCC_DYNAMIC_NO_PIC = NO; + GCC_GENERATE_DEBUGGING_SYMBOLS = YES; + GCC_MODEL_TUNING = G5; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/AppKit.framework/Headers/AppKit.h"; + INSTALL_PATH = /usr/local/lib; + OTHER_LDFLAGS = ( + "-framework", + Foundation, + "-framework", + AppKit, + ); + PRODUCT_NAME = ddhid; + ZERO_LINK = NO; + }; + name = Debug; + }; + 559CBBE80B5B338B00C8FD74 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = YES; + GCC_GENERATE_DEBUGGING_SYMBOLS = NO; + GCC_MODEL_TUNING = G5; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = "$(SYSTEM_LIBRARY_DIR)/Frameworks/AppKit.framework/Headers/AppKit.h"; + INSTALL_PATH = /usr/local/lib; + OTHER_LDFLAGS = ( + "-framework", + Foundation, + "-framework", + AppKit, + ); + PRODUCT_NAME = ddhid; + ZERO_LINK = NO; + }; + name = Release; + }; + C01FCF4B08A954540054247B /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 55D592200BAE2E4500364849 /* versions.xcconfig */; + buildSettings = { + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + GCC_DYNAMIC_NO_PIC = NO; + GCC_MODEL_TUNING = G5; + GCC_OPTIMIZATION_LEVEL = 0; + INFOPLIST_FILE = browser/Info.plist; + INSTALL_PATH = "$(HOME)/Applications"; + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = HIDBrowser; + WRAPPER_EXTENSION = app; + ZERO_LINK = NO; + }; + name = Debug; + }; + C01FCF4C08A954540054247B /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 55D592200BAE2E4500364849 /* versions.xcconfig */; + buildSettings = { + COMBINE_HIDPI_IMAGES = YES; + GCC_GENERATE_DEBUGGING_SYMBOLS = NO; + GCC_MODEL_TUNING = G5; + INFOPLIST_FILE = browser/Info.plist; + INSTALL_PATH = "$(HOME)/Applications"; + OTHER_LDFLAGS = "-ObjC"; + PRODUCT_NAME = HIDBrowser; + WRAPPER_EXTENSION = app; + ZERO_LINK = NO; + }; + name = Release; + }; + C01FCF4F08A954540054247B /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 55D592200BAE2E4500364849 /* versions.xcconfig */; + buildSettings = { + ARCHS = "$(NATIVE_ARCH_ACTUAL)"; + CLANG_ENABLE_OBJC_ARC = NO; + GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.7; + SDKROOT = macosx; + }; + name = Debug; + }; + C01FCF5008A954540054247B /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 55D592200BAE2E4500364849 /* versions.xcconfig */; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; + CLANG_ENABLE_OBJC_ARC = NO; + GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.7; + SDKROOT = macosx; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 551711280B8F420E00C82155 /* Build configuration list for PBXAggregateTarget "All" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 551711290B8F420E00C82155 /* Debug */, + 5517112A0B8F420E00C82155 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 55193E530B93F2EF004C0C98 /* Build configuration list for PBXNativeTarget "DDHidLib" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 55193E540B93F2EF004C0C98 /* Debug */, + 55193E550B93F2EF004C0C98 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 559CBAE40B5B313000C8FD74 /* Build configuration list for PBXNativeTarget "HIDDeviceTest" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 559CBAE50B5B313000C8FD74 /* Debug */, + 559CBAE60B5B313000C8FD74 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 559CBBE60B5B338B00C8FD74 /* Build configuration list for PBXNativeTarget "ddhid" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 559CBBE70B5B338B00C8FD74 /* Debug */, + 559CBBE80B5B338B00C8FD74 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "HIDBrowser" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C01FCF4B08A954540054247B /* Debug */, + C01FCF4C08A954540054247B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + C01FCF4E08A954540054247B /* Build configuration list for PBXProject "DDHidLib" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C01FCF4F08A954540054247B /* Debug */, + C01FCF5008A954540054247B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 29B97313FDCFA39411CA2CEA /* Project object */; +} diff --git a/Icon.jpg b/Icon.jpg new file mode 100644 index 0000000000000000000000000000000000000000..cd64f416e84998808e8af0a3e87879dda572fe57 GIT binary patch literal 15141 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

lXFK&#^B0P6-ouXb;TLr`m$2vT}D? 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 F-vH(8v!MV0 literal 0 HcmV?d00001 diff --git a/LICENSE.html b/LICENSE.html new file mode 100644 index 00000000..5831837a --- /dev/null +++ b/LICENSE.html @@ -0,0 +1,181 @@ + + + + + + + + + + The MIT License (MIT) | Open Source Initiative + + + + + + + + + + +

+ +
+
+ + + + + +
+

You are here

+

The MIT License (MIT)

+
+
+
+ + +
+
+ + + + +
+ [OSI Approved License] +

The MIT License (MIT)

+ + + +

Copyright (c) <year> <copyright holders>

+ +

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.

+ + +
+ +
+ + +
+ +
+
+
+
+
+ +
+ + +
+
+ + diff --git a/README.md b/README.md new file mode 100644 index 00000000..5e034a17 --- /dev/null +++ b/README.md @@ -0,0 +1,11 @@ +DDHidLib +===== +###by Dave Dribin + +An Objective-C wrapper around IOHIDLib. + +http://www.dribin.org/dave/software/ + +###Modifications in the repo: +- added experimental support for (apple) mics with built-in keys. +- dropped ppc and added x64 support \ No newline at end of file diff --git a/browser/English.lproj/EventWatcher.nib/classes.nib b/browser/English.lproj/EventWatcher.nib/classes.nib new file mode 100644 index 00000000..8f04df5d --- /dev/null +++ b/browser/English.lproj/EventWatcher.nib/classes.nib @@ -0,0 +1,13 @@ +{ + IBClasses = ( + {CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, + { + ACTIONS = {clearHistory = id; }; + CLASS = WatcherWindowController; + LANGUAGE = ObjC; + OUTLETS = {mEventHistoryController = NSArrayController; }; + SUPERCLASS = NSWindowController; + } + ); + IBVersion = 1; +} \ No newline at end of file diff --git a/browser/English.lproj/EventWatcher.nib/info.nib b/browser/English.lproj/EventWatcher.nib/info.nib new file mode 100644 index 00000000..1c52771a --- /dev/null +++ b/browser/English.lproj/EventWatcher.nib/info.nib @@ -0,0 +1,16 @@ + + + + + IBDocumentLocation + 69 14 356 240 0 0 1440 878 + IBFramework Version + 446.1 + IBOpenObjects + + 5 + + IBSystem Version + 8N1037 + + diff --git a/browser/English.lproj/EventWatcher.nib/keyedobjects.nib b/browser/English.lproj/EventWatcher.nib/keyedobjects.nib new file mode 100644 index 0000000000000000000000000000000000000000..61ebe6c638f298b2d67652d8acb04128acbccec5 GIT binary patch literal 9260 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 PJ?cleL_2nVr%m}EB!cA% literal 0 HcmV?d00001 diff --git a/browser/English.lproj/InfoPlist.strings b/browser/English.lproj/InfoPlist.strings new file mode 100644 index 0000000000000000000000000000000000000000..30cfd962d325cee19affaac7ec096918b385e7dc GIT binary patch literal 190 zcmW-a%?`m(5Ju11Q#6*1sMuJD6$=uv;0an<1h-9#gg5e%IBh0(zWF)x-QPDMCSpy= zo|G$R-sBvdJ=L1VNl8#6wJ@*j3hNps;tCG#q0 ku0!QTt^biz=P}c#&&RxwYyWSnmdJd8f&G|~F_D|{2Yc@!KmY&$ literal 0 HcmV?d00001 diff --git a/browser/English.lproj/MainMenu.nib/classes.nib b/browser/English.lproj/MainMenu.nib/classes.nib new file mode 100644 index 00000000..910a1c9f --- /dev/null +++ b/browser/English.lproj/MainMenu.nib/classes.nib @@ -0,0 +1,19 @@ +{ + IBClasses = ( + {CLASS = DDHidElement; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, + {CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; }, + {CLASS = HexFormatter; LANGUAGE = ObjC; SUPERCLASS = NSFormatter; }, + { + ACTIONS = {exportPlist = id; watchSelected = id; }; + CLASS = HidBrowserController; + LANGUAGE = ObjC; + OUTLETS = { + mDevicesController = NSArrayController; + mElementsController = NSTreeController; + mWindow = NSWindow; + }; + SUPERCLASS = NSObject; + } + ); + IBVersion = 1; +} \ No newline at end of file diff --git a/browser/English.lproj/MainMenu.nib/info.nib b/browser/English.lproj/MainMenu.nib/info.nib new file mode 100644 index 00000000..d20a5cff --- /dev/null +++ b/browser/English.lproj/MainMenu.nib/info.nib @@ -0,0 +1,22 @@ + + + + + IBDocumentLocation + 110 86 356 240 0 0 1440 878 + IBEditorPositions + + 29 + 95 721 310 44 0 0 1440 878 + + IBFramework Version + 446.1 + IBOpenObjects + + 21 + 29 + + IBSystem Version + 8N1037 + + diff --git a/browser/English.lproj/MainMenu.nib/keyedobjects.nib b/browser/English.lproj/MainMenu.nib/keyedobjects.nib new file mode 100644 index 0000000000000000000000000000000000000000..904f45d57bc6d64f34479dd72a41d08c8bc27fa2 GIT binary patch literal 31311 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 literal 0 HcmV?d00001 diff --git a/browser/HIDBrowser_Prefix.pch b/browser/HIDBrowser_Prefix.pch new file mode 100644 index 00000000..5d5ed485 --- /dev/null +++ b/browser/HIDBrowser_Prefix.pch @@ -0,0 +1,7 @@ +// +// Prefix header for all source files of the 'HIDBrowser' target in the 'HIDBrowser' project +// + +#ifdef __OBJC__ + #import +#endif diff --git a/browser/HexFormatter.h b/browser/HexFormatter.h new file mode 100644 index 00000000..e3b28c25 --- /dev/null +++ b/browser/HexFormatter.h @@ -0,0 +1,34 @@ +/* + * 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 + + +@interface HexFormatter : NSFormatter { + +} + ++ (NSString*)format:(long)number; + +@end diff --git a/browser/HexFormatter.m b/browser/HexFormatter.m new file mode 100644 index 00000000..5ac3f6fa --- /dev/null +++ b/browser/HexFormatter.m @@ -0,0 +1,49 @@ +/* + * 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 "HexFormatter.h" + + +@implementation HexFormatter + ++ (NSString*)format:(long)number; +{ + return [NSString stringWithFormat: @"0x%02X", number]; +} + + +- (NSString *)stringForObjectValue:(id)anObject { + return [HexFormatter format:[anObject longValue]]; +} + +- (BOOL)getObjectValue:(id *)anObject forString:(NSString *)string errorDescription:(NSString **)error { + return NO; +} + +- (NSAttributedString *)attributedStringForObjectValue:(id)anObject withDefaultAttributes:(NSDictionary *)attributes { + return [[[NSAttributedString alloc] initWithString:[self stringForObjectValue:anObject]] autorelease]; +} + + +@end diff --git a/browser/HidBrowserController.h b/browser/HidBrowserController.h new file mode 100644 index 00000000..3e7e1160 --- /dev/null +++ b/browser/HidBrowserController.h @@ -0,0 +1,42 @@ +/* + * 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 + + +@interface HidBrowserController : NSObject +{ + IBOutlet NSWindow * mWindow; + IBOutlet NSArrayController * mDevicesController; + IBOutlet NSTreeController * mElementsController; + NSArray * mDevices; +} + +- (NSArray *) devices; + +- (IBAction) watchSelected: (id) sender; + +- (IBAction) exportPlist: (id) sender; + +@end diff --git a/browser/HidBrowserController.m b/browser/HidBrowserController.m new file mode 100644 index 00000000..4b12267d --- /dev/null +++ b/browser/HidBrowserController.m @@ -0,0 +1,144 @@ +/* + * 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 "HidBrowserController.h" +#import "DDHidUsageTables.h" +#import "DDHidDevice.h" +#import "DDHidElement.h" +#import "WatcherWindowController.h" + +@implementation HidBrowserController + +static BOOL sSleepAtExit = NO; + +static void exit_sleeper() +{ + while (sSleepAtExit) sleep(60); +} + +- (void) awakeFromNib +{ + sSleepAtExit = [[NSUserDefaults standardUserDefaults] boolForKey: @"SleepAtExit"]; + atexit(exit_sleeper); + + [self willChangeValueForKey: @"devices"]; + mDevices = [[DDHidDevice allDevices] retain]; + [self didChangeValueForKey: @"devices"]; + + [mWindow center]; + [mWindow makeKeyAndOrderFront: self]; +} + +//=========================================================== +// dealloc +//=========================================================== +- (void) dealloc +{ + [mDevices release]; + + mDevices = nil; + [super dealloc]; +} + +//=========================================================== +// - devices +//=========================================================== +- (NSArray *) devices +{ + return mDevices; +} + +- (DDHidDevice *) selectedDevice; +{ + NSArray * selectedDevices = [mDevicesController selectedObjects]; + if ([selectedDevices count] > 0) + return [selectedDevices objectAtIndex: 0]; + else + return nil; +} + +- (IBAction) watchSelected: (id) sender; +{ + NSArray * selectedElements = [mElementsController selectedObjects]; + if ([selectedElements count] == 0) + return; + + WatcherWindowController * controller = + [[WatcherWindowController alloc] init]; + [controller setDevice: [self selectedDevice]]; + [controller setElements: selectedElements]; + [controller showWindow: self]; +} + +- (IBAction) exportPlist: (id) sender; +{ + DDHidDevice * selectedDevice = [self selectedDevice]; + if (selectedDevice == nil) + return; + + NSSavePanel * panel = [NSSavePanel savePanel]; + + /* set up new attributes */ + [panel setRequiredFileType: @"plist"]; + [panel setAllowsOtherFileTypes: NO]; + [panel setCanSelectHiddenExtension: YES]; + + /* display the NSSavePanel */ + [panel beginSheetForDirectory: NSHomeDirectory() + file: @"" + modalForWindow: [NSApp mainWindow] + modalDelegate: self + didEndSelector: @selector(exportPlistPanelDidEnd:returnCode:contextInfo:) + contextInfo: selectedDevice]; +} + +- (void) exportPlistPanelDidEnd: (NSSavePanel *) panel + returnCode: (int) returnCode + contextInfo: (void *) contextInfo; +{ + DDHidDevice * selectedDevice = contextInfo; + + /* if successful, save file under designated name */ + if (returnCode != NSOKButton) + return; + + NSDictionary * deviceProperties = [selectedDevice properties]; + if (![deviceProperties writeToFile: [panel filename] atomically: YES]) + NSBeep(); +} + +- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication +{ + return YES; +} + +- (void)applicationWillTerminate:(NSNotification *)aNotification +{ + [self willChangeValueForKey: @"devices"]; + [mDevices release]; + mDevices = nil; + [self didChangeValueForKey: @"devices"]; +} + +@end diff --git a/browser/Info.plist b/browser/Info.plist new file mode 100644 index 00000000..feff01cc --- /dev/null +++ b/browser/Info.plist @@ -0,0 +1,30 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIconFile + + CFBundleIdentifier + org.dribin.dave.ddhidlib.HIDBrowser + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + APPL + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + CFBundleShortVersionString + ${CURRENT_MARKETING_VERSION} + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/browser/WatcherWindowController.h b/browser/WatcherWindowController.h new file mode 100644 index 00000000..5cc447a2 --- /dev/null +++ b/browser/WatcherWindowController.h @@ -0,0 +1,57 @@ +/* + * 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 +#import "DDHidDevice.h" +#import "DDHidElement.h" + +@class DDHidQueue; + +@interface WatcherWindowController : NSWindowController +{ + IBOutlet NSArrayController * mEventHistoryController; + DDHidDevice * mDevice; + NSArray * mElements; + DDHidQueue * mQueue; + NSMutableArray * mEventHistory; + int mNextIndex; +} + +- (DDHidDevice *) device; +- (void) setDevice: (DDHidDevice *) newDevice; + +- (NSArray *) elements; +- (void) setElements: (NSArray *) newElements; + +- (NSMutableArray *) eventHistory; +- (void) setEventHistory: (NSMutableArray *) anEventHistory; +- (void) addToEventHistory: (id)mEventHistoryObject; +- (void) removeFromEventHistory: (id)mEventHistoryObject; + +- (BOOL) isWatching; +- (void) setWatching: (BOOL) watching; + +- (IBAction) clearHistory: (id) sender; + +@end diff --git a/browser/WatcherWindowController.m b/browser/WatcherWindowController.m new file mode 100644 index 00000000..a13c9861 --- /dev/null +++ b/browser/WatcherWindowController.m @@ -0,0 +1,269 @@ +/* + * 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 "WatcherWindowController.h" +#import "DDHidQueue.h" +#import "DDHidEvent.h" +#import "DDHidUsage.h" + +@interface WatcherEvent : NSObject +{ + NSString * mUsageDescription; + DDHidEvent * mEvent; + int mIndex; +} + +- (id) initWithUsageDescription: (NSString *) anUsageDecription + event: (DDHidEvent *) anEvent + index: (int) index; + +- (NSString *) usageDescription; +- (DDHidEvent *) event; +- (int) index; + +@end + +@implementation WatcherEvent : NSObject + +- (id) initWithUsageDescription: (NSString *) anUsageDescription + event: (DDHidEvent *) anEvent + index: (int) index +{ + if (self = [super init]) + { + mUsageDescription = [anUsageDescription retain]; + mEvent = [anEvent retain]; + mIndex = index; + } + return self; +} + +//=========================================================== +// dealloc +//=========================================================== +- (void) dealloc +{ + [mUsageDescription release]; + [mEvent release]; + + mUsageDescription = nil; + mEvent = nil; + [super dealloc]; +} + +//=========================================================== +// - usageDescription +//=========================================================== +- (NSString *) usageDescription +{ + return mUsageDescription; +} + +//=========================================================== +// - event +//=========================================================== +- (DDHidEvent *) event +{ + return mEvent; +} + +//=========================================================== +// - index +//=========================================================== +- (int) index +{ + return mIndex; +} + +@end + +@implementation WatcherWindowController + +- (id) init +{ + self = [super initWithWindowNibName: @"EventWatcher" owner: self]; + if (self == nil) + return nil; + + mEventHistory = [[NSMutableArray alloc] init]; + mNextIndex = 1; + + return self; +} + + +//=========================================================== +// dealloc +//=========================================================== +- (void) dealloc +{ + [mQueue release]; + [mDevice release]; + [mElements release]; + [mEventHistory release]; + + mQueue = nil; + mDevice = nil; + mElements = nil; + mEventHistory = nil; + [super dealloc]; +} + +- (void)windowWillClose:(NSNotification *)notification +{ + [mQueue release]; + mQueue = nil; + [mDevice close]; + [self autorelease]; +} + +- (IBAction)showWindow:(id)sender +{ + [super showWindow: sender]; +} + +- (void) ddhidQueueHasEvents: (DDHidQueue *) hidQueue; +{ + WatcherEvent * watcherEvent; + watcherEvent = + [[WatcherEvent alloc] initWithUsageDescription: @"-----------------------------" + event: nil + index: mNextIndex++]; + [watcherEvent autorelease]; + [mEventHistoryController addObject: watcherEvent]; + + NSMutableArray * newEvents = [NSMutableArray array]; + DDHidEvent * event; + while (event = [hidQueue nextEvent]) + { + DDHidElement * element = [mDevice elementForCookie: [event elementCookie]]; + watcherEvent = + [[WatcherEvent alloc] initWithUsageDescription: [[element usage] usageNameWithIds] + event: event + index: mNextIndex++]; + [watcherEvent autorelease]; + [newEvents addObject: watcherEvent]; + } + + [mEventHistoryController addObjects: newEvents]; +} + +- (void) windowDidLoad; +{ + [mDevice open]; + mQueue = [[mDevice createQueueWithSize: 30] retain]; + [mQueue setDelegate: self]; + [mQueue addElements: mElements]; + [self willChangeValueForKey: @"watching"]; + [mQueue startOnCurrentRunLoop]; + [self didChangeValueForKey: @"watching"]; +} + +//=========================================================== +// device +//=========================================================== +- (DDHidDevice *) device +{ + return [[mDevice retain] autorelease]; +} + +- (void) setDevice: (DDHidDevice *) newDevice +{ + if (mDevice != newDevice) + { + [mDevice release]; + mDevice = [newDevice retain]; + } +} + +//=========================================================== +// elements +//=========================================================== +- (NSArray *) elements +{ + return [[mElements retain] autorelease]; +} + +- (void) setElements: (NSArray *) newElements +{ + if (mElements != newElements) + { + [mElements release]; + mElements = [newElements retain]; + } +} + +//=========================================================== +// eventHistory +//=========================================================== +- (NSMutableArray *) eventHistory +{ + return mEventHistory; +} + +- (void) setEventHistory: (NSMutableArray *) anEventHistory +{ + if (mEventHistory != anEventHistory) + { + [mEventHistory release]; + mEventHistory = [anEventHistory retain]; + } +} +- (void) addToEventHistory: (id)mEventHistoryObject +{ + [[self eventHistory] addObject: mEventHistoryObject]; +} +- (void) removeFromEventHistory: (id)mEventHistoryObject +{ + [[self eventHistory] removeObject: mEventHistoryObject]; +} + +- (BOOL) isWatching; +{ + if (mQueue == nil) + return NO; + return [mQueue isStarted]; +} + +- (void) setWatching: (BOOL) watching; +{ + BOOL isStarted = [mQueue isStarted]; + if (isStarted == watching) + return; + + if (watching) + [mQueue startOnCurrentRunLoop]; + else + [mQueue stop]; +} + +- (IBAction) clearHistory: (id) sender; +{ + [self willChangeValueForKey: @"eventHistory"]; + [mEventHistory removeAllObjects]; + mNextIndex = 1; + [self didChangeValueForKey: @"eventHistory"]; +} + +@end diff --git a/browser/main.m b/browser/main.m new file mode 100644 index 00000000..f05b99f0 --- /dev/null +++ b/browser/main.m @@ -0,0 +1,30 @@ +/* + * 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 + +int main(int argc, char *argv[]) +{ + return NSApplicationMain(argc, (const char **) argv); +} diff --git a/changelog.yml b/changelog.yml new file mode 100644 index 00000000..743fff56 --- /dev/null +++ b/changelog.yml @@ -0,0 +1,24 @@ +- version: "1.1" + date: 2008-04-22 + changes: + - Added logical joysticks for devices with multiple top-level elements. + Should allow devices like PS/2 to USB converters to work better. + - Change joystick normalized values to +/- 65536. + - Update Apple Remote codes for Leopard. + - Improved keyboard barcode scanning for certain devices. + - Added internal debugging code to help detect memory leaks. + +- version: "1.0.1" + date: 2007-04-03 + changes: + - "Replace deprecated stringWithCString: with stringWithUTF8String:." + - Make DDHidKeyboard.h public so it gets copied to the framework. + - Plugged some memory leaks. + - Added a class for barcode scanners, thanks to Lucas Newman of Delicious + Monster. + - Add support for point of view hat switches on joysticks. + +- version: "1.0" + date: 2007-03-19 + changes: + - Initial release. diff --git a/device_test/AppleMikeyPaneController.h b/device_test/AppleMikeyPaneController.h new file mode 100644 index 00000000..d72059e4 --- /dev/null +++ b/device_test/AppleMikeyPaneController.h @@ -0,0 +1,62 @@ +/* + * 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 + + +@class DDHidAppleMikey; + +@interface AppleMikeyPaneController : NSObject +{ + IBOutlet NSArrayController * mMikeysController; + IBOutlet NSArrayController * mMikeysEventsController; + + NSArray * mMikeys; + NSUInteger mMikeyIndex; + NSMutableArray * mEvents; + + // Don't retain these + DDHidAppleMikey * mCurrentMikey; +} + +- (NSArray *) mikeys; +- (void) setMikeys: (NSArray *) theMikeys; + +- (NSUInteger) mikeyIndex; +- (void) setMikeyIndex: (NSUInteger) theMikeyIndex; + +- (NSMutableArray *) events; +- (void) setEvents: (NSMutableArray *) theEvents; +- (void) addEvent: (id)theEvent; +- (void) removeEvent: (id)theEvent; + +@end + +@interface AppleMikeyPaneController (DDHidAppleMikeyDelegate) + +- (void) ddhidAppleMikey: (DDHidAppleMikey *) mikey + press: (unsigned) usageId + upOrDown:(BOOL)upOrDown; + +@end diff --git a/device_test/AppleMikeyPaneController.m b/device_test/AppleMikeyPaneController.m new file mode 100644 index 00000000..db0ac189 --- /dev/null +++ b/device_test/AppleMikeyPaneController.m @@ -0,0 +1,160 @@ +/* + * 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 "AppleMikeyPaneController.h" +#import "DDHidLib.h" +#include + +@implementation AppleMikeyPaneController + +- (id) init; +{ + self = [super init]; + if (self == nil) + return nil; + + mEvents = [[NSMutableArray alloc] init]; + + return self; +} + +- (void) awakeFromNib; +{ + NSArray * mikeys = [DDHidAppleMikey allMikeys]; + + [mikeys makeObjectsPerformSelector: @selector(setDelegate:) + withObject: self]; + [self setMikeys: mikeys]; + + if ([mikeys count] > 0) + [self setMikeyIndex: 0]; + else + [self setMikeyIndex: NSNotFound]; +} + +//=========================================================== +// dealloc +//=========================================================== +- (void) dealloc +{ + [mMikeys release]; + [mEvents release]; + + mMikeys = nil; + mEvents = nil; + [super dealloc]; +} + +//=========================================================== +// mikeys +//=========================================================== +- (NSArray *) mikeys +{ + return mMikeys; +} + +- (void) setMikeys: (NSArray *) theMikeys +{ + if (mMikeys != theMikeys) + { + [mMikeys release]; + mMikeys = [theMikeys retain]; + } +} +//=========================================================== +// mikeyIndex +//=========================================================== +- (NSUInteger) mikeyIndex +{ + return mMikeyIndex; +} + +- (void) setMikeyIndex: (NSUInteger) theMikeyIndex +{ + if (mCurrentMikey != nil) + { + [mCurrentMikey stopListening]; + mCurrentMikey = nil; + } + mMikeyIndex = theMikeyIndex; + [mMikeysController setSelectionIndex: mMikeyIndex]; + [self willChangeValueForKey: @"events"]; + [mEvents removeAllObjects]; + [self didChangeValueForKey: @"events"]; + if (mMikeyIndex != NSNotFound) + { + mCurrentMikey = [mMikeys objectAtIndex: mMikeyIndex]; + [mCurrentMikey startListening]; + } +} + +//=========================================================== +// events +//=========================================================== +- (NSMutableArray *) events +{ + return mEvents; +} + +- (void) setEvents: (NSMutableArray *) theEvents +{ + if (mEvents != theEvents) + { + [mEvents release]; + mEvents = [theEvents retain]; + } +} +- (void) addEvent: (id)theEvent +{ + [[self events] addObject: theEvent]; +} +- (void) removeEvent: (id)theEvent +{ + [[self events] removeObject: theEvent]; +} + +@end + +@implementation AppleMikeyPaneController (DDHidAppleMikeyDelegate) + +- (void) ddhidAppleMikey:(DDHidAppleMikey *)mikey press:(unsigned int)usageId upOrDown:(BOOL)upOrDown +{ + NSString *usage = nil; + if(usageId==kHIDUsage_GD_SystemMenuDown) { + usage = @"MenuDown"; + } + else if(usageId == kHIDUsage_GD_SystemMenuUp) { + usage = @"MenuUp"; + } + + if(!usage) + return; + + NSMutableDictionary * row = [[mMikeysEventsController newObject] autorelease]; + [row setObject: upOrDown ? @"Down" : @"Up" forKey: @"event"]; + [row setObject:usage forKey: @"description"]; + [mMikeysEventsController addObject: row]; +} + +@end diff --git a/device_test/AppleRemote.tiff b/device_test/AppleRemote.tiff new file mode 100644 index 0000000000000000000000000000000000000000..7e002ca567e5c56a3c817a87c27ac50cfdf2940e GIT binary patch literal 90050 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 +#import "DDHidLib.h" + +@class DDHidAppleRemote; +@class RemoteFeedbackView; + +@interface AppleRemotePaneController : NSObject +{ + IBOutlet NSButton * mStartStopButton; + IBOutlet RemoteFeedbackView * mFeedbackView; + IBOutlet NSTextField * mFeedbackText; + + DDHidAppleRemote * mRemote; + BOOL mOpenInExclusiveMode; +} + +- (DDHidAppleRemote *) remote; + +- (IBAction) toggleListening: (id) sender; + +- (BOOL) openInExclusiveMode; +- (void) setOpenInExclusiveMode: (BOOL) flag; + +- (void) ddhidAppleRemoteButton: (DDHidAppleRemoteEventIdentifier) buttonIdentifier + pressedDown: (BOOL) pressedDown; + +@end diff --git a/device_test/AppleRemotePaneController.m b/device_test/AppleRemotePaneController.m new file mode 100644 index 00000000..7cbaf526 --- /dev/null +++ b/device_test/AppleRemotePaneController.m @@ -0,0 +1,145 @@ +/* + * 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 "AppleRemotePaneController.h" +#import "RemoteFeedbackView.h" + +@implementation AppleRemotePaneController + +- (void) awakeFromNib; +{ + [self willChangeValueForKey: @"remote"]; + mRemote = [[DDHidAppleRemote firstRemote] retain]; + [self didChangeValueForKey: @"remote"]; + + [mRemote setDelegate: self]; + [self setOpenInExclusiveMode: YES]; +} + +//=========================================================== +// dealloc +//=========================================================== +- (void) dealloc +{ + [mRemote release]; + + mRemote = nil; + [super dealloc]; +} + +- (DDHidAppleRemote *) remote; +{ + return mRemote; +} + +- (IBAction) toggleListening: (id) sender; +{ + NSAssert(mRemote != nil, @"Remote is nil"); + + if ([mRemote isListening]) + { + [mRemote stopListening]; + [mStartStopButton setTitle: @"Start Listening"]; + } + else + { + [mRemote setListenInExclusiveMode: mOpenInExclusiveMode]; + [mRemote startListening]; + [mStartStopButton setTitle: @"Stop Listening"]; + } +} + +//=========================================================== +// openInExclusiveMode +//=========================================================== +- (BOOL) openInExclusiveMode +{ + return mOpenInExclusiveMode; +} + +- (void) setOpenInExclusiveMode: (BOOL) flag +{ + mOpenInExclusiveMode = flag; +} + +- (void) ddhidAppleRemoteButton: (DDHidAppleRemoteEventIdentifier) buttonIdentifier + pressedDown: (BOOL) pressedDown; +{ + NSString * buttonName= nil; + NSString * pressed = @""; + + switch(buttonIdentifier) + { + case kDDHidRemoteButtonVolume_Plus: + buttonName = @"Volume up"; + if (pressedDown) pressed = @"(down)"; else pressed = @"(up)"; + break; + case kDDHidRemoteButtonVolume_Minus: + buttonName = @"Volume down"; + if (pressedDown) pressed = @"(down)"; else pressed = @"(up)"; + break; + case kDDHidRemoteButtonMenu: + buttonName = @"Menu"; + break; + case kDDHidRemoteButtonPlay: + buttonName = @"Play"; + break; + case kDDHidRemoteButtonRight: + buttonName = @"Right"; + break; + case kDDHidRemoteButtonLeft: + buttonName = @"Left"; + break; + case kDDHidRemoteButtonRight_Hold: + buttonName = @"Right holding"; + if (pressedDown) pressed = @"(down)"; else pressed = @"(up)"; + break; + case kDDHidRemoteButtonLeft_Hold: + buttonName = @"Left holding"; + if (pressedDown) pressed = @"(down)"; else pressed = @"(up)"; + break; + case kDDHidRemoteButtonPlay_Sleep: + buttonName = @"Play (sleep mode)"; + break; + case kDDHidRemoteButtonMenu_Hold: + buttonName = @"Menu (long)"; + break; + case kDDHidRemoteControl_Switched: + buttonName = @"Remote Control Switched"; + break; + case kDDHidRemoteControl_Paired: + buttonName = @"Remote Control Paired"; + break; + default: + NSLog(@"Unmapped event for button %d", buttonIdentifier); + break; + } + [mFeedbackText setStringValue:[NSString stringWithFormat:@"%@ %@", + buttonName, pressed]]; + + [mFeedbackView ddhidAppleRemoteButton: buttonIdentifier + pressedDown: pressedDown]; +} + +@end diff --git a/device_test/BoolFormatter.h b/device_test/BoolFormatter.h new file mode 100644 index 00000000..79661cbe --- /dev/null +++ b/device_test/BoolFormatter.h @@ -0,0 +1,35 @@ +/* + * 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 + + +@interface BoolFormatter : NSFormatter +{ + id labels; +} + +- (id)initWithLables:(id)_l; + +@end diff --git a/device_test/BoolFormatter.m b/device_test/BoolFormatter.m new file mode 100644 index 00000000..7f302f97 --- /dev/null +++ b/device_test/BoolFormatter.m @@ -0,0 +1,82 @@ +/* + * 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 "BoolFormatter.h" + + +@implementation BoolFormatter + +- (id)initWithLables:(id)_l { + if ((self = [super init]) != nil) { + self->labels = [_l retain]; + } + return self; +} + +- (void)dealloc { + [self->labels release]; + [super dealloc]; +} + +- (BOOL) boolForObjectValue: (id) object +{ + BOOL result; + if ([object respondsToSelector: @selector(boolValue)]) + result = [object boolValue] ? YES : NO; + else + result = NO; + return result; +} + +- (NSString *)stringForObjectValue:(id)_obj +{ + NSString *str; + + if ([self boolForObjectValue: _obj]) + str = @"Yes"; + else + str = @"No"; + + return (self->labels != nil) + ? (NSString *)[self->labels valueForKey:str] : str; +} + +- (NSAttributedString *)attributedStringForObjectValue:(id)anObject + withDefaultAttributes:(NSDictionary *)defaultAttributes +{ + NSDictionary * yesAttributes = [NSDictionary dictionaryWithObjectsAndKeys: + [NSColor redColor], NSBackgroundColorAttributeName, + nil]; + NSDictionary * attributes = defaultAttributes; + if ([self boolForObjectValue: anObject]) + attributes = yesAttributes; + + NSAttributedString * string = + [[NSAttributedString alloc] initWithString: [self stringForObjectValue: anObject] + attributes: attributes]; + [string autorelease]; + return string; +} + +@end diff --git a/device_test/ButtonState.h b/device_test/ButtonState.h new file mode 100644 index 00000000..d45ada55 --- /dev/null +++ b/device_test/ButtonState.h @@ -0,0 +1,39 @@ +/* + * 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 + +@interface ButtonState : NSObject +{ + NSString * mName; + BOOL mPressed; +} + +- (id) initWithName: (NSString *) name; +- (NSString *) name; + +- (BOOL) pressed; +- (void) setPressed: (BOOL) flag; + +@end diff --git a/device_test/ButtonState.m b/device_test/ButtonState.m new file mode 100644 index 00000000..d093b52b --- /dev/null +++ b/device_test/ButtonState.m @@ -0,0 +1,77 @@ +/* + * 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 "ButtonState.h" + +@implementation ButtonState + +- (id) initWithName: (NSString *) name +{ + self = [super init]; + if (self == nil) + return nil; + + mName = [name retain]; + mPressed = NO; + + return self; +} + +//=========================================================== +// dealloc +//=========================================================== +- (void) dealloc +{ + [mName release]; + + mName = nil; + [super dealloc]; +} + +//=========================================================== +// - name +//=========================================================== +- (NSString *) name +{ + return mName; +} + +//=========================================================== +// - pressed +//=========================================================== +- (BOOL) pressed +{ + return mPressed; +} + +//=========================================================== +// - setPressed: +//=========================================================== +- (void) setPressed: (BOOL) flag +{ + mPressed = flag; +} + +@end + diff --git a/device_test/DeviceTestController.h b/device_test/DeviceTestController.h new file mode 100644 index 00000000..bb03cf12 --- /dev/null +++ b/device_test/DeviceTestController.h @@ -0,0 +1,35 @@ +/* + * 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 + +@class MousePaneController; + +@interface DeviceTestController : NSObject +{ + IBOutlet NSWindow * mWindow; + IBOutlet MousePaneController * mMousePaneController; +} + +@end diff --git a/device_test/DeviceTestController.m b/device_test/DeviceTestController.m new file mode 100644 index 00000000..58d0f91e --- /dev/null +++ b/device_test/DeviceTestController.m @@ -0,0 +1,49 @@ +/* + * 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 "DeviceTestController.h" + +static BOOL sSleepAtExit = NO; + +static void exit_sleeper() +{ + while (sSleepAtExit) sleep(60); +} + +@implementation DeviceTestController + +- (void) awakeFromNib +{ + sSleepAtExit = [[NSUserDefaults standardUserDefaults] boolForKey: @"SleepAtExit"]; + atexit(exit_sleeper); + + [mWindow center]; + [mWindow makeKeyAndOrderFront: self]; +} + +- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication +{ + return YES; +} +@end diff --git a/device_test/English.lproj/InfoPlist.strings b/device_test/English.lproj/InfoPlist.strings new file mode 100644 index 0000000000000000000000000000000000000000..30cfd962d325cee19affaac7ec096918b385e7dc GIT binary patch literal 190 zcmW-a%?`m(5Ju11Q#6*1sMuJD6$=uv;0an<1h-9#gg5e%IBh0(zWF)x-QPDMCSpy= zo|G$R-sBvdJ=L1VNl8#6wJ@*j3hNps;tCG#q0 ku0!QTt^biz=P}c#&&RxwYyWSnmdJd8f&G|~F_D|{2Yc@!KmY&$ literal 0 HcmV?d00001 diff --git a/device_test/English.lproj/MainMenu.nib/designable.nib b/device_test/English.lproj/MainMenu.nib/designable.nib new file mode 100644 index 00000000..fbb8f5ad --- /dev/null +++ b/device_test/English.lproj/MainMenu.nib/designable.nib @@ -0,0 +1,5311 @@ + + + + 1070 + 11G63 + 3084 + 1138.51 + 569.00 + + com.apple.InterfaceBuilder.CocoaPlugin + 3084 + + + NSArrayController + NSBox + NSButton + NSButtonCell + NSCustomObject + NSCustomView + NSLevelIndicator + NSLevelIndicatorCell + NSMenu + NSMenuItem + NSPopUpButton + NSPopUpButtonCell + NSScrollView + NSScroller + NSTabView + NSTabViewItem + NSTableColumn + NSTableHeaderView + NSTableView + NSTextField + NSTextFieldCell + NSView + NSWindowTemplate + + + com.apple.InterfaceBuilder.CocoaPlugin + + + PluginDependencyRecalculationVersion + + + + + + NSApplication + + + + FirstResponder + + + NSApplication + + + 15 + 2 + {{183, 341}, {529, 499}} + 1881669632 + HID Device Test + NSWindow + + View + + + {213, 107} + + + 256 + + + + 274 + {{13, 10}, {503, 483}} + + + + + + + 1 + + + + 256 + + + + 268 + {{17, 399}, {50, 17}} + + + YES + + 67239424 + 272629760 + Mouse: + + LucidaGrande + 13 + 1044 + + + + 6 + System + controlColor + + 3 + MC42NjY2NjY2NjY3AA + + + + 6 + System + controlTextColor + + 3 + MAA + + + + + + + 266 + {{69, 393}, {397, 26}} + + + YES + + -2076049856 + 2048 + + + 109199615 + 1 + + LucidaGrande + 13 + 16 + + + + + + 400 + 75 + + + Item1 + + 1048576 + 2147483647 + 1 + + NSImage + NSMenuCheckmark + + + NSImage + NSMenuMixedState + + _popUpItemAction: + + + YES + + + OtherViews + + + + + + Item2 + + 1048576 + 2147483647 + + + _popUpItemAction: + + + + + Item3 + + 1048576 + 2147483647 + + + _popUpItemAction: + + + + + 3 + YES + YES + 1 + + + + + 268 + {{17, 372}, {93, 17}} + + + YES + + 67239424 + 272629760 + Manufacturer: + + + + + + + + + 266 + {{112, 372}, {354, 17}} + + + YES + + 67239424 + 272629760 + System Font Text + + + + + + + + + 268 + {{48, 338}, {62, 17}} + + + YES + + 67239424 + 272629760 + Mouse X: + + + + + + + + + 266 + {{12, 361}, {459, 5}} + + + {0, 0} + + 67239424 + 0 + Box + + + 6 + System + textBackgroundColor + + 3 + MQA + + + + 3 + MCAwLjgwMDAwMDAxAA + + + 3 + 2 + 0 + NO + + + + 268 + {{46, 312}, {62, 17}} + + + YES + + 67239424 + 272629760 + Mouse Y: + + + + + + + + + 268 + {{17, 286}, {91, 17}} + + + YES + + 67239424 + 272629760 + Mouse Wheel: + + + + + + + + + 266 + {{113, 338}, {350, 16}} + + + YES + + 130560 + 0 + + 5000 + 1 + + + + + 266 + {{113, 312}, {350, 16}} + + + YES + + 130560 + 0 + + 5000 + 1 + + + + + 266 + {{113, 286}, {350, 16}} + + + YES + + 130560 + 0 + + 5 + 1 + + + + + 272 + + + + 2304 + + + + 256 + {157, 240} + + + YES + + + 256 + {157, 17} + + + + + + + 256 + {{158, 0}, {16, 17}} + + + + + + 65 + 40 + 1000 + + 75628096 + 2048 + Button + + LucidaGrande + 11 + 3100 + + + 3 + MC4zMzMzMzI5OQA + + + 6 + System + headerTextColor + + + + + 337772096 + 2048 + + + + 6 + System + controlBackgroundColor + + + + + 3 + YES + YES + + + + 85.97607421875 + 48.97607421875 + 1000 + + 75628096 + 2048 + Pressed + + + + + + 337772032 + 0 + + LucidaGrande + 12 + 16 + + + + + + 3 + YES + YES + + + + 3 + 2 + + + 6 + System + gridColor + + 3 + MC41AA + + + 17 + -700448768 + + + 5 + 15 + 0 + YES + 0 + 1 + + + {{1, 17}, {157, 240}} + + + + + 4 + + + + 256 + {{158, 17}, {15, 240}} + + + + _doScroller: + 0.89473682641983032 + + + + -2147483392 + {{-100, -100}, {131, 15}} + + + 1 + + _doScroller: + 0.99047619104385376 + + + + 2304 + + + + {{1, 0}, {157, 17}} + + + + + 4 + + + + {{113, 20}, {174, 258}} + + + 133138 + + + + + + QSAAAEEgAABBmAAAQZgAAA + + + {{10, 33}, {483, 437}} + + + Mice + + + + + + 2 + + + + 256 + + + + 268 + {{17, 399}, {57, 17}} + + YES + + 67239424 + 272629760 + Joystick: + + + + + + + + + 266 + {{76, 393}, {390, 26}} + + YES + + -2076049856 + 2048 + + + 109199615 + 1 + + + + + + 400 + 75 + + + Item1 + + 1048576 + 2147483647 + 1 + + + _popUpItemAction: + + + YES + + + OtherViews + + + + + + Item2 + + 1048576 + 2147483647 + + + _popUpItemAction: + + + + + Item3 + + 1048576 + 2147483647 + + + _popUpItemAction: + + + + + 3 + YES + YES + 1 + + + + + 268 + {{17, 372}, {93, 17}} + + YES + + 67239424 + 272629760 + Manufacturer: + + + + + + + + + 266 + {{112, 372}, {354, 17}} + + YES + + 69336577 + 272629760 + System Font Text + + + + + + + + + 276 + + + + 2304 + + + + 256 + {177, 267} + + YES + + + 256 + {177, 17} + + + + + + 256 + {{178, 0}, {16, 17}} + + + + + 80 + 40 + 1000 + + 75628096 + 2048 + Button + + + 3 + MC4zMzMzMzI5OQA + + + + + 337772096 + 2048 + + + + + + 3 + YES + + + + 90.97607421875 + 48.97607421875 + 1000 + + 75628096 + 2048 + Pressed + + + + + + 337772032 + 0 + + + + + + 3 + YES + + + + 3 + 2 + + + 17 + -700448768 + + + 5 + 15 + 0 + YES + 0 + 1 + + + {{1, 17}, {177, 267}} + + + + + 4 + + + + 256 + {{178, 17}, {15, 267}} + + + _doScroller: + 0.95789474248886108 + + + + 256 + {{-100, -100}, {177, 15}} + + 1 + + _doScroller: + 0.99047619104385376 + + + + 2304 + + + + {{1, 0}, {177, 17}} + + + + + 4 + + + + {{74, 20}, {194, 285}} + + + 133138 + + + + + QSAAAEEgAABBmAAAQZgAAA + + + + 266 + {{12, 361}, {459, 5}} + + {0, 0} + + 67239424 + 0 + Box + + + + 3 + MCAwLjgwMDAwMDAxAA + + + 3 + 2 + 0 + NO + + + + 266 + {{74, 337}, {389, 16}} + + YES + + 130560 + 0 + + -32768 + 32768 + 1 + + + + + 266 + {{74, 313}, {389, 16}} + + YES + + 130560 + 0 + + -32768 + 32768 + 1 + + + + + 268 + {{17, 337}, {52, 17}} + + YES + + 67239424 + 272629760 + X-Axis: + + + + + + + + + 268 + {{17, 313}, {52, 17}} + + YES + + 67239424 + 272629760 + Y-Axis: + + + + + + + + {{10, 33}, {483, 437}} + + Joysticks + + + + + + + 256 + + + + 266 + {{87, 393}, {379, 26}} + + + YES + + -2076049856 + 2048 + + + 109199615 + 1 + + + + + + 400 + 75 + + + Item1 + + 1048576 + 2147483647 + 1 + + + _popUpItemAction: + + + YES + + + OtherViews + + + + + + Item2 + + 1048576 + 2147483647 + + + _popUpItemAction: + + + + + Item3 + + 1048576 + 2147483647 + + + _popUpItemAction: + + + + + 3 + YES + YES + 1 + + + + + 264 + {{17, 399}, {68, 17}} + + + YES + + 67239424 + 272629760 + Keyboard: + + + + + + + + + 266 + {{112, 372}, {354, 17}} + + + YES + + 67239424 + 272629760 + System Font Text + + + + + + + + + 264 + {{17, 372}, {93, 17}} + + + YES + + 67239424 + 272629760 + Manufacturer: + + + + + + + + + 256 + {{12, 361}, {459, 5}} + + + {0, 0} + + 67239424 + 0 + Box + + + + 3 + MCAwLjgwMDAwMDAxAA + + + 3 + 2 + 0 + NO + + + + 256 + + + + 2304 + + + + 256 + {426, 333} + + + YES + + + 256 + {{427, 0}, {16, 17}} + + + + 94 + 40 + 1000 + + 75628096 + 2048 + + + + 3 + MC4zMzMzMzI5OQA + + + + + 337772096 + 2048 + + + + + + 3 + YES + YES + + + + 326 + 40 + 1000 + + 75628096 + 2048 + + + + + + + 337772096 + 2048 + + + + + + 3 + YES + YES + + + + 3 + 2 + + + 17 + 306184192 + + + 4 + 15 + 0 + YES + 0 + 1 + + + {{1, 1}, {426, 333}} + + + + + 4 + + + + 256 + {{427, 1}, {15, 333}} + + + + _doScroller: + 0.96315789222717285 + + + + -2147483392 + {{-100, -100}, {426, 15}} + + + 1 + + _doScroller: + 0.99047619104385376 + + + {{20, 20}, {443, 335}} + + + 133138 + + + + QSAAAEEgAABBmAAAQZgAAA + + + {{10, 33}, {483, 437}} + + + Keyboards + + + + + + + 256 + + + + 256 + {{188, 137}, {107, 280}} + + + RemoteFeedbackView + NSView + + + + 256 + {{176, 67}, {131, 32}} + + + YES + + 67239424 + 134217728 + Start Listening + + + -2038284033 + 1 + + + + + + 200 + 25 + + + + + 256 + {{165, 39}, {151, 18}} + + YES + + 67239424 + 131072 + Open in exclusive mode + + + 1211912703 + 2 + + NSSwitch + + + + 200 + 25 + + + + + 256 + {{165, 115}, {152, 14}} + + + YES + + 67239424 + 138543104 + - + + + + + + + + + 256 + {{194, 423}, {63, 14}} + + + YES + + 67239424 + 272629760 + Remote ID: + + + + + + + + + 256 + {{259, 423}, {32, 14}} + + + YES + + 67239424 + 272629760 + 9999 + + + + + + + + {{10, 33}, {483, 437}} + + + Remote + + + + + + + 256 + + + + 266 + {{87, 393}, {379, 26}} + + + + YES + + -2076049856 + 2048 + + + 109199615 + 1 + + + + + + 400 + 75 + + + Item1 + + 1048576 + 2147483647 + 1 + + + _popUpItemAction: + + + YES + + + OtherViews + + + + + + Item2 + + 1048576 + 2147483647 + + + _popUpItemAction: + + + + + Item3 + + 1048576 + 2147483647 + + + _popUpItemAction: + + + + + 3 + YES + YES + 1 + + + + + 264 + {{17, 399}, {41, 17}} + + + + YES + + 67239424 + 272629760 + Mikey + + + + + + + + + 266 + {{112, 372}, {354, 17}} + + + + YES + + 67239424 + 272629760 + System Font Text + + + + + + + + + 264 + {{17, 372}, {93, 17}} + + + + YES + + 67239424 + 272629760 + Manufacturer: + + + + + + + + + 256 + {{12, 361}, {459, 5}} + + + + {0, 0} + + 67239424 + 0 + Box + + + + 3 + MCAwLjgwMDAwMDAxAA + + + 3 + 2 + 0 + NO + + + + 256 + + + + 2304 + + + + 256 + {426, 333} + + + + YES + + + 256 + {{427, 0}, {16, 17}} + + + + 94 + 40 + 1000 + + 75628096 + 2048 + + + + 3 + MC4zMzMzMzI5OQA + + + + + 337772096 + 2048 + + + + + + 3 + YES + YES + + + + 326 + 40 + 1000 + + 75628096 + 2048 + + + + + + + 337772096 + 2048 + + + + + + 3 + YES + YES + + + + 3 + 2 + + + 17 + 306184192 + + + 4 + 15 + 0 + YES + 0 + 1 + + + {{1, 1}, {426, 333}} + + + + + + 4 + + + + 256 + {{427, 1}, {15, 333}} + + + + + _doScroller: + 0.96315789222717285 + + + + -2147483392 + {{-100, -100}, {426, 15}} + + + + 1 + + _doScroller: + 0.99047619104385376 + + + {{20, 20}, {443, 335}} + + + + 133138 + + + + QSAAAEEgAABBmAAAQZgAAA + + + {{10, 33}, {483, 437}} + + + + + Mikeys + + + + + + + 0 + YES + YES + + + + + + {529, 499} + + + + + {{0, 0}, {1920, 1178}} + {213, 129} + {10000000000000, 10000000000000} + YES + + + MainMenu + + + + HIDDeviceTest + + 1048576 + 2147483647 + + + submenuAction: + + HIDDeviceTest + + + + About HIDDeviceTest + + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Preferences… + , + 1048576 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Services + + 1048576 + 2147483647 + + + submenuAction: + + + Services + + + _NSServicesMenu + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Hide HIDDeviceTest + h + 1048576 + 2147483647 + + + + + + Hide Others + h + 1572864 + 2147483647 + + + + + + Show All + + 1048576 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Quit HIDDeviceTest + q + 1048576 + 2147483647 + + + + + _NSAppleMenu + + + + + File + + 1048576 + 2147483647 + + + submenuAction: + + + File + + + + + New + n + 1048576 + 2147483647 + + + + + + Open… + o + 1048576 + 2147483647 + + + + + + Open Recent + + 1048576 + 2147483647 + + + submenuAction: + + + Open Recent + + + + + Clear Menu + + 1048576 + 2147483647 + + + + + _NSRecentDocumentsMenu + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Close + w + 1048576 + 2147483647 + + + + + + Save + s + 1048576 + 2147483647 + + + + + + Save As… + S + 1048576 + 2147483647 + + + + + + Revert + + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Page Setup… + P + 1048576 + 2147483647 + + + + + + Print… + p + 1048576 + 2147483647 + + + + + + + + + Edit + + 1048576 + 2147483647 + + + submenuAction: + + + Edit + + + + + Undo + z + 1048576 + 2147483647 + + + + + + Redo + Z + 1048576 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Cut + x + 1048576 + 2147483647 + + + + + + Copy + c + 1048576 + 2147483647 + + + + + + Paste + v + 1048576 + 2147483647 + + + + + + Paste and Match Style + V + 1572864 + 2147483647 + + + + + + Delete + + 1048576 + 2147483647 + + + + + + Select All + a + 1048576 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Find + + 1048576 + 2147483647 + + + submenuAction: + + + Find + + + + + Find… + f + 1048576 + 2147483647 + + + 1 + + + + Find Next + g + 1048576 + 2147483647 + + + 2 + + + + Find Previous + G + 1048576 + 2147483647 + + + 3 + + + + Use Selection for Find + e + 1048576 + 2147483647 + + + 7 + + + + Jump to Selection + j + 1048576 + 2147483647 + + + + + + + + + Spelling + + 1048576 + 2147483647 + + + submenuAction: + + Spelling + + + + Spelling… + : + 1048576 + 2147483647 + + + + + + Check Spelling + ; + 1048576 + 2147483647 + + + + + + Check Spelling as You Type + + 1048576 + 2147483647 + + + + + + + + + Speech + + 1048576 + 2147483647 + + + submenuAction: + + Speech + + + + Start Speaking + + 1048576 + 2147483647 + + + + + + Stop Speaking + + 1048576 + 2147483647 + + + + + + + + + + + + Window + + 1048576 + 2147483647 + + + submenuAction: + + + Window + + + + + Minimize + m + 1048576 + 2147483647 + + + + + + Zoom + + 1048576 + 2147483647 + + + + + + YES + YES + + + 1048576 + 2147483647 + + + + + + Bring All to Front + + 1048576 + 2147483647 + + + + + _NSWindowsMenu + + + + + Help + + 1048576 + 2147483647 + + + submenuAction: + + + Help + + + + + NewApplication Help + ? + 1048576 + 2147483647 + + + + + + + + _NSMainMenu + + + DeviceTestController + + + + productName + manufacturer + + + YES + YES + YES + YES + YES + + + + name + pressed + + + YES + YES + YES + YES + YES + + + BoolFormatter + + + MousePaneController + + + JoystickPaneController + + + + productName + manufacturer + + + YES + YES + YES + YES + YES + + + + name + pressed + + + YES + YES + YES + YES + YES + + + AppleRemotePaneController + + + KeyboardPaneController + + + + productName + manufacturer + + YES + + YES + YES + YES + YES + YES + + + + event + description + + YES + + YES + YES + YES + YES + YES + + + AppleMikeyPaneController + + + + productName + manufacturer + + YES + + YES + YES + YES + YES + YES + + + + event + description + + YES + + YES + YES + YES + YES + YES + + + + 256 + {125, 1} + + + + + + + 256 + {125, 1} + + + + + + + 256 + {125, 1} + + + + + + + + + + terminate: + + + + 139 + + + + orderFrontStandardAboutPanel: + + + + 142 + + + + hideOtherApplications: + + + + 146 + + + + hide: + + + + 152 + + + + unhideAllApplications: + + + + 153 + + + + delegate + + + + 396 + + + + performMiniaturize: + + + + 37 + + + + arrangeInFront: + + + + 39 + + + + print: + + + + 86 + + + + runPageLayout: + + + + 87 + + + + showHelp: + + + + 122 + + + + clearRecentDocuments: + + + + 127 + + + + performClose: + + + + 193 + + + + toggleContinuousSpellChecking: + + + + 222 + + + + undo: + + + + 223 + + + + copy: + + + + 224 + + + + checkSpelling: + + + + 225 + + + + paste: + + + + 226 + + + + stopSpeaking: + + + + 227 + + + + cut: + + + + 228 + + + + showGuessPanel: + + + + 230 + + + + redo: + + + + 231 + + + + selectAll: + + + + 232 + + + + startSpeaking: + + + + 233 + + + + delete: + + + + 235 + + + + performZoom: + + + + 240 + + + + performFindPanelAction: + + + + 241 + + + + performFindPanelAction: + + + + 242 + + + + performFindPanelAction: + + + + 243 + + + + performFindPanelAction: + + + + 244 + + + + centerSelectionInVisibleArea: + + + + 245 + + + + pasteAsPlainText: + + + + 247 + + + + content: arrangedObjects.productName + + + + + + content: arrangedObjects.productName + content + arrangedObjects.productName + + Foo + Bar + No Mice + + 2 + + + 342 + + + + selectedIndex: mouseIndex + + + + + + selectedIndex: mouseIndex + selectedIndex + mouseIndex + + 2 + + + 355 + + + + mMousePaneController + + + + 346 + + + + mWindow + + + + 397 + + + + contentArray: mice + + + + + + contentArray: mice + contentArray + mice + + NSConditionallySetsEditable + + + 2 + + + 354 + + + + value: selection.manufacturer + + + + + + value: selection.manufacturer + value + selection.manufacturer + 2 + + + 267 + + + + maxValue: maxValue + + + + + + maxValue: maxValue + maxValue + maxValue + 2 + + + 347 + + + + value: mouseX + + + + + + value: mouseX + value + mouseX + + 2 + + + 356 + + + + maxValue: maxValue + + + + + + maxValue: maxValue + maxValue + maxValue + 2 + + + 349 + + + + value: mouseY + + + + + + value: mouseY + value + mouseY + + 2 + + + 357 + + + + maxValue: maxValue + + + + + + maxValue: maxValue + maxValue + maxValue + 2 + + + 351 + + + + value: mouseWheel + + + + + + value: mouseWheel + value + mouseWheel + + 2 + + + 358 + + + + value: arrangedObjects.name + + + + + + value: arrangedObjects.name + value + arrangedObjects.name + 2 + + + 316 + + + + value: arrangedObjects.pressed + + + + + + value: arrangedObjects.pressed + value + arrangedObjects.pressed + 2 + + + 317 + + + + contentArray: mouseButtons + + + + + + contentArray: mouseButtons + contentArray + mouseButtons + + NSConditionallySetsEditable + + + 2 + + + 353 + + + + formatter + + + + 323 + + + + mMiceController + + + + 345 + + + + mJoysticksController + + + + 374 + + + + content: arrangedObjects.productName + + + + + + content: arrangedObjects.productName + content + arrangedObjects.productName + + NSNullPlaceholder + No Joysticks + + 2 + + + 394 + + + + selectedIndex: joystickIndex + + + + + + selectedIndex: joystickIndex + selectedIndex + joystickIndex + + 2 + + + 395 + + + + value: selection.manufacturer + + + + + + value: selection.manufacturer + value + selection.manufacturer + + NSNoSelectionPlaceholder + IA + + 2 + + + 393 + + + + contentArray: joysticks + + + + + + contentArray: joysticks + contentArray + joysticks + 2 + + + 369 + + + + value: arrangedObjects.pressed + + + + + + value: arrangedObjects.pressed + value + arrangedObjects.pressed + + NSConditionallySetsEditable + + + 2 + + + 401 + + + + value: arrangedObjects.name + + + + + + value: arrangedObjects.name + value + arrangedObjects.name + 2 + + + 385 + + + + contentArray: joystickButtons + + + + + + contentArray: joystickButtons + contentArray + joystickButtons + 2 + + + 383 + + + + formatter + + + + 388 + + + + value: xAxis + + + + + + value: xAxis + value + xAxis + 2 + + + 404 + + + + value: yAxis + + + + + + value: yAxis + value + yAxis + 2 + + + 405 + + + + toggleListening: + + + + 412 + + + + mStartStopButton + + + + 414 + + + + mFeedbackView + + + + 415 + + + + mFeedbackText + + + + 419 + + + + value: openInExclusiveMode + + + + + + value: openInExclusiveMode + value + openInExclusiveMode + 2 + + + 413 + + + + value: remote.remoteId + + + + + + value: remote.remoteId + value + remote.remoteId + 2 + + + 422 + + + + mKeyboardsController + + + + 454 + + + + mKeyboardEventsController + + + + 457 + + + + content: arrangedObjects.productName + + + + + + content: arrangedObjects.productName + content + arrangedObjects.productName + + NSNullPlaceholder + No Joysticks + + 2 + + + 440 + + + + selectedIndex: keyboardIndex + + + + + + selectedIndex: keyboardIndex + selectedIndex + keyboardIndex + + 2 + + + 441 + + + + value: selection.manufacturer + + + + + + value: selection.manufacturer + value + selection.manufacturer + 2 + + + 439 + + + + contentArray: keyboards + + + + + + contentArray: keyboards + contentArray + keyboards + 2 + + + 433 + + + + value: arrangedObjects.event + + + + + + value: arrangedObjects.event + value + arrangedObjects.event + 2 + + + 459 + + + + value: arrangedObjects.description + + + + + + value: arrangedObjects.description + value + arrangedObjects.description + 2 + + + 460 + + + + contentArray: events + + + + + + contentArray: events + contentArray + events + 2 + + + 456 + + + + mMikeysController + + + + 504 + + + + mMikeysEventsController + + + + 505 + + + + contentArray: mikeys + + + + + + contentArray: mikeys + contentArray + mikeys + 2 + + + 538 + + + + contentArray: events + + + + + + contentArray: events + contentArray + events + 2 + + + 540 + + + + value: selection.manufacturer + + + + + + value: selection.manufacturer + value + selection.manufacturer + 2 + + + 544 + + + + content: arrangedObjects.productName + + + + + + content: arrangedObjects.productName + content + arrangedObjects.productName + + NSNullPlaceholder + No Mikeys + + 2 + + + 541 + + + + selectedIndex: mikeyIndex + + + + + + selectedIndex: mikeyIndex + selectedIndex + mikeyIndex + + 2 + + + 542 + + + + value: arrangedObjects.description + + + + + + value: arrangedObjects.description + value + arrangedObjects.description + 2 + + + 536 + + + + value: arrangedObjects.event + + + + + + value: arrangedObjects.event + value + arrangedObjects.event + 2 + + + 535 + + + + + + 0 + + + + + + -2 + + + File's Owner + + + -1 + + + First Responder + + + 21 + + + + + + Window + + + 2 + + + + + + + + 248 + + + + + + + + + + + + 249 + + + + + + + + 250 + + + + + + + + + + + + + + + + + 360 + + + + + + + + 361 + + + + + + + + 366 + + + + + + + + 367 + + + + + + + + 376 + + + + + + + + + + + 377 + + + + + + + + + 378 + + + + + + + + 387 + + + + + 379 + + + + + + + + 380 + + + + + + 398 + + + + + + + + 399 + + + + + + + + 402 + + + + + + + + 403 + + + + + + + + 251 + + + + + + + + 252 + + + + + + + + + + + + + + + + + + + 255 + + + + + + + + 256 + + + + + + + + 265 + + + + + + + + 266 + + + + + + + + 270 + + + + + + + + 271 + + + + + + 273 + + + + + + + + 274 + + + + + + + + 281 + + + + + + + + 288 + + + + + + + + 294 + + + + + + + + 310 + + + + + + + + + + + 311 + + + + + + + + + 312 + + + + + + + + 313 + + + + + + + + 321 + + + + + 253 + + + + + + + + 254 + + + + + + + + + + + + + 424 + + + + + + + + 429 + + + + + + + + 430 + + + + + + + + 431 + + + + + + + + 448 + + + + + + 450 + + + + + + + + + + 451 + + + + + + + + + 452 + + + + + + + + 453 + + + + + + + + 407 + + + + + + + + 408 + + + + + + + + + + + + + 409 + + + + + 410 + + + + + + + + 411 + + + + + + + + 416 + + + + + + + + 420 + + + + + + + + 421 + + + + + + + + 29 + + + + + + + + + + MainMenu + + + 19 + + + + + + + + 24 + + + + + + + + + + + 5 + + + + + 23 + + + + + 92 + + + + + 239 + + + + + 56 + + + + + + + + 57 + + + + + + + + + + + + + + + + + + 58 + + + + + 129 + + + + + 131 + + + + + + + + 130 + + + + + 134 + + + + + 136 + + + + + 143 + + + + + 144 + + + + + 145 + + + + + 149 + + + + + 150 + + + + + 236 + + + + + 83 + + + + + + + + 81 + + + + + + + + + + + + + + + + + + 72 + + + + + 73 + + + + + 74 + + + + + 75 + + + + + 77 + + + + + 78 + + + + + 79 + + + + + 80 + + + + + 82 + + + + + 112 + + + + + 124 + + + + + + + + 125 + + + + + + + + 126 + + + + + 103 + + + + + + + + 106 + + + + + + + + 111 + + + + + 217 + + + + + + + + 205 + + + + + + + + + + + + + + + + + + + + 197 + + + + + 198 + + + + + 199 + + + + + 202 + + + + + 203 + + + + + 206 + + + + + 207 + + + + + 211 + + + + + + + + 212 + + + + + + + + + 195 + + + + + 196 + + + + + 214 + + + + + 215 + + + + + 216 + + + + + + + + 200 + + + + + + + + + + 201 + + + + + 204 + + + + + 219 + + + + + 218 + + + + + + + + 220 + + + + + + + + + + + + 208 + + + + + 209 + + + + + 210 + + + + + 213 + + + + + 221 + + + + + 246 + + + + + 261 + + + DeviceTestController + + + 262 + + + Mice + + + 314 + + + MouseButtons + + + 322 + + + BoolFormatter + + + 344 + + + MousePaneController + + + 359 + + + JoystickPaneController + + + 368 + + + Joysticks + + + 382 + + + JoystickButtons + + + 406 + + + AppleRemotePaneController + + + 423 + + + KeyboardPaneController + + + 432 + + + Keyboards + + + 455 + + + KeyboardEvents + + + 462 + + + + + 463 + + + + + + + + 464 + + + + + 465 + + + + + 466 + + + + + 467 + + + + + 468 + + + + + 469 + + + + + 470 + + + + + 471 + + + + + + + + 472 + + + + + 473 + + + + + 474 + + + + + 475 + + + + + 476 + + + + + 477 + + + + + 478 + + + + + 479 + + + + + 480 + + + + + + + + 481 + + + + + 482 + + + + + 483 + + + + + 484 + + + + + 485 + + + + + 486 + + + + + 487 + + + + + 488 + + + + + 489 + + + + + 490 + + + + + 491 + + + + + 492 + + + + + 362 + + + + + + + + + + 365 + + + + + 364 + + + + + 363 + + + + + 257 + + + + + + + + + + 260 + + + + + 259 + + + + + 258 + + + + + 425 + + + + + + + + + + 428 + + + + + 427 + + + + + 426 + + + + + 493 + + + + + 494 + + + + + 495 + + + + + 496 + + + + + 497 + + + + + 498 + + + + + 499 + + + + + 500 + + + + + -3 + + + Application + + + 381 + + + + + 272 + + + + + 449 + + + + + 501 + + + AppleMikeyPaneController + + + 502 + + + mikeys + + + 503 + + + mikeyEvents + + + 506 + + + + + + + + 507 + + + + + + + + + + + + + 513 + + + + + + + + 512 + + + + + + + + 509 + + + + + 508 + + + + + + + + + + 524 + + + + + + + + + 523 + + + + + 522 + + + + + 526 + + + + + + + + 525 + + + + + + + + 528 + + + + + 527 + + + + + 519 + + + + + 514 + + + + + + + + 515 + + + + + + + + + + 518 + + + + + 517 + + + + + 516 + + + + + 510 + + + + + + + + 521 + + + + + 511 + + + + + + + + 520 + + + + + + + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + + + + + + 544 + + + + + AppleMikeyPaneController + NSObject + + NSArrayController + NSArrayController + + + + mMikeysController + NSArrayController + + + mMikeysEventsController + NSArrayController + + + + IBProjectSource + ./Classes/AppleMikeyPaneController.h + + + + AppleRemotePaneController + NSObject + + toggleListening: + id + + + toggleListening: + + toggleListening: + id + + + + NSTextField + RemoteFeedbackView + NSButton + + + + mFeedbackText + NSTextField + + + mFeedbackView + RemoteFeedbackView + + + mStartStopButton + NSButton + + + + IBProjectSource + ./Classes/AppleRemotePaneController.h + + + + BoolFormatter + NSFormatter + + IBProjectSource + ./Classes/BoolFormatter.h + + + + DeviceTestController + NSObject + + MousePaneController + NSWindow + + + + mMousePaneController + MousePaneController + + + mWindow + NSWindow + + + + IBProjectSource + ./Classes/DeviceTestController.h + + + + JoystickPaneController + NSObject + + mJoysticksController + NSArrayController + + + mJoysticksController + + mJoysticksController + NSArrayController + + + + IBProjectSource + ./Classes/JoystickPaneController.h + + + + KeyboardPaneController + NSObject + + NSArrayController + NSArrayController + + + + mKeyboardEventsController + NSArrayController + + + mKeyboardsController + NSArrayController + + + + IBProjectSource + ./Classes/KeyboardPaneController.h + + + + MousePaneController + NSObject + + mMiceController + NSArrayController + + + mMiceController + + mMiceController + NSArrayController + + + + IBProjectSource + ./Classes/MousePaneController.h + + + + RemoteFeedbackView + NSView + + IBProjectSource + ./Classes/RemoteFeedbackView.h + + + + + 0 + IBCocoaFramework + + com.apple.InterfaceBuilder.CocoaPlugin.macosx + + + YES + 3 + + {11, 11} + {10, 3} + + + diff --git a/device_test/English.lproj/MainMenu.nib/keyedobjects.nib b/device_test/English.lproj/MainMenu.nib/keyedobjects.nib new file mode 100644 index 0000000000000000000000000000000000000000..8158386c7245da11ea73d6cf4a6c0a103e05c76e GIT binary patch literal 46512 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 Pe>-;S|Ly<(4%hzx{KEy1 literal 0 HcmV?d00001 diff --git a/device_test/Info.plist b/device_test/Info.plist new file mode 100644 index 00000000..db90f929 --- /dev/null +++ b/device_test/Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + org.dribin.dave.ddhidlib.HIDDeviceTest + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + APPL + CFBundleSignature + ???? + CFBundleVersion + ${CURRENT_PROJECT_VERSION} + CFBundleShortVersionString + ${CURRENT_MARKETING_VERSION} + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/device_test/JoystickPaneController.h b/device_test/JoystickPaneController.h new file mode 100644 index 00000000..8126ffbc --- /dev/null +++ b/device_test/JoystickPaneController.h @@ -0,0 +1,72 @@ +/* + * 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 +#import "DDHidLib.h" + + +@interface JoystickPaneController : NSObject +{ + IBOutlet NSArrayController * mJoysticksController; + + NSArray * mJoysticks; + NSMutableArray * mJoystickButtons; + int mXAxis; + int mYAxis; + NSUInteger mJoystickIndex; + + // Don't retain these + DDHidJoystick * mCurrentJoystick; +} + +- (NSArray *) joysticks; + +- (NSArray *) joystickButtons; + +- (NSUInteger) joystickIndex; +- (void) setJoystickIndex: (NSUInteger) theJoystickIndex; + +- (int) xAxis; +- (int) yAxis; + +- (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 + buttonDown: (unsigned) buttonNumber; + +- (void) ddhidJoystick: (DDHidJoystick *) joystick + buttonUp: (unsigned) buttonNumber; + +@end diff --git a/device_test/JoystickPaneController.m b/device_test/JoystickPaneController.m new file mode 100644 index 00000000..12beff8e --- /dev/null +++ b/device_test/JoystickPaneController.m @@ -0,0 +1,174 @@ +/* + * 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 "JoystickPaneController.h" +#import "DDHidJoystick.h" +#import "ButtonState.h" + +@interface JoystickPaneController (Private) + +- (void) setJoysticks: (NSArray *) theJoysticks; + +@end + +@implementation JoystickPaneController + +- (void) awakeFromNib; +{ + NSArray * joysticks = [DDHidJoystick allJoysticks]; + + mJoystickButtons = [[NSMutableArray alloc] init]; + [joysticks makeObjectsPerformSelector: @selector(setDelegate:) + withObject: self]; + [self setJoysticks: joysticks]; + if ([mJoysticks count] > 0) + [self setJoystickIndex: 0]; + else + [self setJoystickIndex: NSNotFound]; +} + +//=========================================================== +// joysticks +//=========================================================== +- (NSArray *) joysticks +{ + return mJoysticks; +} + +- (NSArray *) joystickButtons; +{ + return mJoystickButtons; +} + +//=========================================================== +// joystickIndex +//=========================================================== +- (NSUInteger) joystickIndex +{ + return mJoystickIndex; +} + +- (void) setJoystickIndex: (NSUInteger) theJoystickIndex +{ + if (mCurrentJoystick != nil) + { + [mCurrentJoystick stopListening]; + mCurrentJoystick = nil; + } + mJoystickIndex = theJoystickIndex; + [mJoysticksController setSelectionIndex: mJoystickIndex]; + if (mJoystickIndex != NSNotFound) + { + mCurrentJoystick = [mJoysticks objectAtIndex: mJoystickIndex]; + [mCurrentJoystick startListening]; + + [self willChangeValueForKey: @"joystickButtons"]; + [mJoystickButtons removeAllObjects]; + NSArray * buttons = [mCurrentJoystick buttonElements]; + NSEnumerator * e = [buttons objectEnumerator]; + DDHidElement * element; + while (element = [e nextObject]) + { + ButtonState * state = [[ButtonState alloc] initWithName: [[element usage] usageName]]; + [state autorelease]; + [mJoystickButtons addObject: state]; + } + [self didChangeValueForKey: @"joystickButtons"]; + } +} + +- (int) xAxis; +{ + return mXAxis; +} + +- (int) yAxis; +{ + return mYAxis; +} + +- (void) ddhidJoystick: (DDHidJoystick *) joystick + stick: (unsigned) stick + xChanged: (int) value; +{ + [self willChangeValueForKey: @"xAxis"]; + mXAxis = value; + [self didChangeValueForKey: @"xAxis"]; +} + +- (void) ddhidJoystick: (DDHidJoystick *) joystick + stick: (unsigned) stick + yChanged: (int) value; +{ + [self willChangeValueForKey: @"yAxis"]; + mYAxis = value; + [self didChangeValueForKey: @"yAxis"]; +} + +- (void) ddhidJoystick: (DDHidJoystick *) joystick + stick: (unsigned) stick + otherAxis: (unsigned) otherAxis + valueChanged: (int) value; +{ + // Somehow display values here + NSLog(@"Stick: %d, other axis: %d, changed: %d", stick, otherAxis, value); +} + +- (void) ddhidJoystick: (DDHidJoystick *) joystick + stick: (unsigned) stick + povNumber: (unsigned) povNumber + valueChanged: (int) value; +{ + // Somehow display values here + NSLog(@"Stick: %d, POV number: %d, changed: %d", stick, povNumber, value); +} + +- (void) ddhidJoystick: (DDHidJoystick *) joystick + buttonDown: (unsigned) buttonNumber; +{ + ButtonState * state = [mJoystickButtons objectAtIndex: buttonNumber]; + [state setPressed: YES]; +} + +- (void) ddhidJoystick: (DDHidJoystick *) joystick + buttonUp: (unsigned) buttonNumber; +{ + ButtonState * state = [mJoystickButtons objectAtIndex: buttonNumber]; + [state setPressed: NO]; +} + +@end + +@implementation JoystickPaneController (Private) + +- (void) setJoysticks: (NSArray *) theJoysticks +{ + if (mJoysticks != theJoysticks) + { + [mJoysticks release]; + mJoysticks = [theJoysticks retain]; + } +} + +@end diff --git a/device_test/KeyboardPaneController.h b/device_test/KeyboardPaneController.h new file mode 100644 index 00000000..f134d2d0 --- /dev/null +++ b/device_test/KeyboardPaneController.h @@ -0,0 +1,64 @@ +/* + * 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 + + +@class DDHidKeyboard; + +@interface KeyboardPaneController : NSObject +{ + IBOutlet NSArrayController * mKeyboardsController; + IBOutlet NSArrayController * mKeyboardEventsController; + + NSArray * mKeyboards; + NSUInteger mKeyboardIndex; + NSMutableArray * mEvents; + + // Don't retain these + DDHidKeyboard * mCurrentKeyboard; +} + +- (NSArray *) keyboards; +- (void) setKeyboards: (NSArray *) theKeyboards; + +- (NSUInteger) keyboardIndex; +- (void) setKeyboardIndex: (NSUInteger) theKeyboardIndex; + +- (NSMutableArray *) events; +- (void) setEvents: (NSMutableArray *) theEvents; +- (void) addEvent: (id)theEvent; +- (void) removeEvent: (id)theEvent; + +@end + +@interface KeyboardPaneController (DDHidKeyboardDelegate) + +- (void) ddhidKeyboard: (DDHidKeyboard *) keyboard + keyDown: (unsigned) usageId; + +- (void) ddhidKeyboard: (DDHidKeyboard *) keyboard + keyUp: (unsigned) usageId; + +@end diff --git a/device_test/KeyboardPaneController.m b/device_test/KeyboardPaneController.m new file mode 100644 index 00000000..160577f6 --- /dev/null +++ b/device_test/KeyboardPaneController.m @@ -0,0 +1,179 @@ +/* + * 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 "KeyboardPaneController.h" +#import "DDHidLib.h" +#include + +@interface KeyboardPaneController (Private) + +- (void) addEvent: (NSString *) event usageId: (unsigned) usageId; + +@end + +@implementation KeyboardPaneController + +- (id) init; +{ + self = [super init]; + if (self == nil) + return nil; + + mEvents = [[NSMutableArray alloc] init]; + + return self; +} + +- (void) awakeFromNib; +{ + NSArray * keyboards = [DDHidKeyboard allKeyboards]; + + [keyboards makeObjectsPerformSelector: @selector(setDelegate:) + withObject: self]; + [self setKeyboards: keyboards]; + + if ([keyboards count] > 0) + [self setKeyboardIndex: 0]; + else + [self setKeyboardIndex: NSNotFound]; +} + +//=========================================================== +// dealloc +//=========================================================== +- (void) dealloc +{ + [mKeyboards release]; + [mEvents release]; + + mKeyboards = nil; + mEvents = nil; + [super dealloc]; +} + +//=========================================================== +// keyboards +//=========================================================== +- (NSArray *) keyboards +{ + return mKeyboards; +} + +- (void) setKeyboards: (NSArray *) theKeyboards +{ + if (mKeyboards != theKeyboards) + { + [mKeyboards release]; + mKeyboards = [theKeyboards retain]; + } +} +//=========================================================== +// keyboardIndex +//=========================================================== +- (NSUInteger) keyboardIndex +{ + return mKeyboardIndex; +} + +- (void) setKeyboardIndex: (NSUInteger) theKeyboardIndex +{ + if (mCurrentKeyboard != nil) + { + [mCurrentKeyboard stopListening]; + mCurrentKeyboard = nil; + } + mKeyboardIndex = theKeyboardIndex; + [mKeyboardsController setSelectionIndex: mKeyboardIndex]; + [self willChangeValueForKey: @"events"]; + [mEvents removeAllObjects]; + [self didChangeValueForKey: @"events"]; + if (mKeyboardIndex != NSNotFound) + { + mCurrentKeyboard = [mKeyboards objectAtIndex: mKeyboardIndex]; + [mCurrentKeyboard startListening]; + } +} + +//=========================================================== +// events +//=========================================================== +- (NSMutableArray *) events +{ + return mEvents; +} + +- (void) setEvents: (NSMutableArray *) theEvents +{ + if (mEvents != theEvents) + { + [mEvents release]; + mEvents = [theEvents retain]; + } +} +- (void) addEvent: (id)theEvent +{ + [[self events] addObject: theEvent]; +} +- (void) removeEvent: (id)theEvent +{ + [[self events] removeObject: theEvent]; +} + + +@end + +@implementation KeyboardPaneController (DDHidKeyboardDelegate) + +- (void) ddhidKeyboard: (DDHidKeyboard *) keyboard + keyDown: (unsigned) usageId; +{ + [self addEvent: @"Key Down" usageId: usageId]; +} + +- (void) ddhidKeyboard: (DDHidKeyboard *) keyboard + keyUp: (unsigned) usageId; +{ + [self addEvent: @"Key Up" usageId: usageId]; +} + +@end + +@implementation KeyboardPaneController (Private) + +- (void) addEvent: (NSString *) event usageId: (unsigned) usageId; +{ + DDHidUsageTables * usageTables = [DDHidUsageTables standardUsageTables]; + NSString * description = [NSString stringWithFormat: @"%@ (0x%04X)", + [usageTables descriptionForUsagePage: kHIDPage_KeyboardOrKeypad + usage: usageId], + usageId]; + + NSMutableDictionary * row = [[mKeyboardEventsController newObject] autorelease]; + [row setObject: event forKey: @"event"]; + [row setObject: description forKey: @"description"]; + [mKeyboardEventsController addObject: row]; +} + +@end + diff --git a/device_test/MousePaneController.h b/device_test/MousePaneController.h new file mode 100644 index 00000000..40d3c090 --- /dev/null +++ b/device_test/MousePaneController.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 + +@class DDHidQueue; +@class DDHidMouse; + +@interface MousePaneController : NSObject +{ + IBOutlet NSArrayController * mMiceController; + NSArray * mMice; + DDHidMouse * mCurrentMouse; + + NSUInteger mMouseIndex; + int mMouseX; + int mMouseY; + int mMouseWheel; + NSMutableArray * mMouseButtons; +} + +- (BOOL) no; + +- (NSArray *) mice; +- (void) setMice: (NSArray *) newMice; + +- (NSArray *) mouseButtons; + +- (NSUInteger) mouseIndex; +- (void) setMouseIndex: (NSUInteger) theMouseIndex; + +- (int) maxValue; + +- (int) mouseX; + +- (int) mouseY; + +- (int) mouseWheel; + +- (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/device_test/MousePaneController.m b/device_test/MousePaneController.m new file mode 100644 index 00000000..27ad49bf --- /dev/null +++ b/device_test/MousePaneController.m @@ -0,0 +1,211 @@ +/* + * 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 "MousePaneController.h" +#import "DDHidLib.h" +#import "ButtonState.h" + + +@interface MousePaneController (Private) + +- (void) setMouseX: (int) mouseX; +- (void) setMouseY: (int) mouseY; +- (void) setMouseWheel: (int) mouseWheel; + +@end + +@implementation MousePaneController + +static int sMaxValue = 2500; + +static int applyDelta(int current, int delta) +{ + int newValue = (current + delta) % sMaxValue; + if (newValue < 0) + newValue = sMaxValue + newValue; + return newValue; +} + +- (void) awakeFromNib; +{ + mCurrentMouse = 0; + mMouseButtons = [[NSMutableArray alloc] init]; + + NSArray * mice = [DDHidMouse allMice]; + [mice makeObjectsPerformSelector: @selector(setDelegate:) + withObject: self]; + [self setMice: mice]; + [self setMouseIndex: 0]; +} + +//=========================================================== +// mice +//=========================================================== +- (NSArray *) mice +{ + return mMice; +} + +- (void) setMice: (NSArray *) theMice +{ + if (mMice != theMice) + { + [mMice release]; + mMice = [theMice retain]; + } +} + +- (NSArray *) mouseButtons; +{ + return mMouseButtons; +} + +- (BOOL) no; +{ + return NO; +} + +//=========================================================== +// - mouseIndex +//=========================================================== +- (NSUInteger) mouseIndex +{ + return mMouseIndex; +} + +//=========================================================== +// - setMouseIndex: +//=========================================================== +- (void) setMouseIndex: (NSUInteger) theMouseIndex +{ + if (mCurrentMouse != nil) + { + [mCurrentMouse stopListening]; + mCurrentMouse = nil; + } + mMouseIndex = theMouseIndex; + [mMiceController setSelectionIndex: mMouseIndex]; + if (mMouseIndex != NSNotFound) + { + mCurrentMouse = [mMice objectAtIndex: mMouseIndex]; + [mCurrentMouse startListening]; + [self setMouseX: sMaxValue/2]; + [self setMouseY: sMaxValue/2]; + [self setMouseWheel: sMaxValue/2]; + + [self willChangeValueForKey: @"mouseButtons"]; + [mMouseButtons removeAllObjects]; + NSArray * buttons = [mCurrentMouse buttonElements]; + NSEnumerator * e = [buttons objectEnumerator]; + DDHidElement * element; + while (element = [e nextObject]) + { + ButtonState * state = [[ButtonState alloc] initWithName: [[element usage] usageName]]; + [state autorelease]; + [mMouseButtons addObject: state]; + } + [self didChangeValueForKey: @"mouseButtons"]; + } +} + +- (int) maxValue; +{ + return sMaxValue; +} + +//=========================================================== +// - mouseX +//=========================================================== +- (int) mouseX +{ + return mMouseX; +} + +//=========================================================== +// - mouseY +//=========================================================== +- (int) mouseY +{ + return mMouseY; +} + +//=========================================================== +// - mouseWheel +//=========================================================== +- (int) mouseWheel +{ + return mMouseWheel; +} + +- (void) ddhidMouse: (DDHidMouse *) mouse xChanged: (SInt32) deltaX; +{ + [self setMouseX: applyDelta(mMouseX, deltaX)]; +} + +- (void) ddhidMouse: (DDHidMouse *) mouse yChanged: (SInt32) deltaY; +{ + [self setMouseY: applyDelta(mMouseY, deltaY)]; +} + +- (void) ddhidMouse: (DDHidMouse *) mouse wheelChanged: (SInt32) deltaWheel; +{ + // Some wheels only output -1 or +1, some output a more analog value. + // Normalize wheel to -1%/+1% movement. + deltaWheel = (deltaWheel/abs(deltaWheel))*(sMaxValue/100); + [self setMouseWheel: applyDelta(mMouseWheel, deltaWheel)]; +} + +- (void) ddhidMouse: (DDHidMouse *) mouse buttonDown: (unsigned) buttonNumber; +{ + ButtonState * state = [mMouseButtons objectAtIndex: buttonNumber]; + [state setPressed: YES]; +} + +- (void) ddhidMouse: (DDHidMouse *) mouse buttonUp: (unsigned) buttonNumber; +{ + ButtonState * state = [mMouseButtons objectAtIndex: buttonNumber]; + [state setPressed: NO]; +} + +@end + +@implementation MousePaneController (Private) + +- (void) setMouseX: (int) mouseX; +{ + mMouseX = mouseX; +} + +- (void) setMouseY: (int) mouseY; +{ + mMouseY = mouseY; +} + +- (void) setMouseWheel: (int) mouseWheel; +{ + mMouseWheel = mouseWheel; +} + +@end + diff --git a/device_test/RemoteFeedbackView.h b/device_test/RemoteFeedbackView.h new file mode 100644 index 00000000..767e5d60 --- /dev/null +++ b/device_test/RemoteFeedbackView.h @@ -0,0 +1,42 @@ +/* + * 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 +#import "DDHidAppleRemote.h" + +@interface RemoteFeedbackView : NSView +{ + NSImage* remoteImage; + DDHidAppleRemoteEventIdentifier lastButtonIdentifier; + BOOL drawn; + BOOL clearAfterDraw; +} + +- (void) ddhidAppleRemoteButton: (DDHidAppleRemoteEventIdentifier)buttonIdentifier + pressedDown: (BOOL) pressedDown; + +@end diff --git a/device_test/RemoteFeedbackView.m b/device_test/RemoteFeedbackView.m new file mode 100644 index 00000000..3afa0672 --- /dev/null +++ b/device_test/RemoteFeedbackView.m @@ -0,0 +1,162 @@ +/* + * 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 "RemoteFeedbackView.h" + +@implementation RemoteFeedbackView + +- (id)initWithFrame:(NSRect)frameRect +{ + if ((self = [super initWithFrame:frameRect]) != nil) { + remoteImage = [[NSImage imageNamed:@"AppleRemote"] retain]; + lastButtonIdentifier = -1; + } + return self; +} + +- (void) dealloc { + + [remoteImage release]; + [super dealloc]; +} + +- (void) clearAfterRedraw: (id) sender +{ + clearAfterDraw = NO; + [self ddhidAppleRemoteButton: lastButtonIdentifier pressedDown: NO]; +} + +- (void) ddhidAppleRemoteButton: (DDHidAppleRemoteEventIdentifier)buttonIdentifier + pressedDown: (BOOL) pressedDown; +{ + + clearAfterDraw = NO; + + if (pressedDown) { + lastButtonIdentifier = buttonIdentifier; + } else { + if (drawn) + lastButtonIdentifier = -1; + else { + lastButtonIdentifier = buttonIdentifier; + clearAfterDraw = YES; + } + } + + drawn = NO; + [self setNeedsDisplay:YES]; +} + +- (void)drawRect:(NSRect)rect +{ + drawn = YES; + NSRect imageRect; + NSRect drawingRect; + imageRect.origin = NSZeroPoint; + imageRect.size = [remoteImage size]; + + int x = ([self bounds].size.width - [remoteImage size].width)/2; + int y = ([self bounds].size.height - [remoteImage size].height)/2; + + drawingRect.origin = NSMakePoint(x, y); + drawingRect.size = imageRect.size; + + [remoteImage drawInRect: drawingRect + fromRect: imageRect + operation: NSCompositeSourceOver + fraction: 1.0]; + + + if (lastButtonIdentifier == -1) { + return; + } + + DDHidAppleRemoteEventIdentifier buttonToSelect = lastButtonIdentifier; + + NSPoint buttonPos = NSZeroPoint; + float opacity = 0.5; + + switch(buttonToSelect) { + case kDDHidRemoteButtonVolume_Plus: + buttonPos.x = 53; + buttonPos.y = 240; + break; + case kDDHidRemoteButtonVolume_Minus: + buttonPos.x = 53; + buttonPos.y = 180; + break; + case kDDHidRemoteButtonMenu_Hold: + opacity = 0.8; + case kDDHidRemoteButtonMenu: + buttonPos.x = 53; + buttonPos.y = 137; + clearAfterDraw = YES; + break; + case kDDHidRemoteButtonPlay_Sleep: + opacity = 0.8; + case kDDHidRemoteButtonPlay: + buttonPos.x = 53; + buttonPos.y = 210; + clearAfterDraw = YES; + break; + case kDDHidRemoteButtonRight_Hold: + opacity = 0.8; + buttonPos.x = 83; + buttonPos.y = 210; + break; + case kDDHidRemoteButtonRight: + buttonPos.x = 83; + buttonPos.y = 210; + clearAfterDraw = YES; + break; + case kDDHidRemoteButtonLeft_Hold: + opacity = 0.8; + buttonPos.x = 23; + buttonPos.y = 210; + break; + case kDDHidRemoteButtonLeft: + buttonPos.x = 23; + buttonPos.y = 210; + clearAfterDraw = YES; + break; + default: + break; + } + + float width = 20.0; + float height= 20.0; + NSRect r = NSMakeRect(buttonPos.x + x - (width/2), buttonPos.y + y - (height/2), width, height); + NSBezierPath* bp = [NSBezierPath bezierPathWithOvalInRect:r]; + + [[NSColor colorWithCalibratedRed:1.0 green:0.0 blue:0.0 alpha:opacity] set]; + [bp fill]; + if (clearAfterDraw) { + [self performSelector:@selector(clearAfterRedraw:) withObject:self afterDelay:0.1]; + } +} + +@end diff --git a/device_test/main.m b/device_test/main.m new file mode 100644 index 00000000..f05b99f0 --- /dev/null +++ b/device_test/main.m @@ -0,0 +1,30 @@ +/* + * 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 + +int main(int argc, char *argv[]) +{ + return NSApplicationMain(argc, (const char **) argv); +} diff --git a/header.c b/header.c new file mode 100644 index 00000000..ddd2f75d --- /dev/null +++ b/header.c @@ -0,0 +1,23 @@ +/* + * 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. + */ diff --git a/lib/DDHidAppleMikey.h b/lib/DDHidAppleMikey.h new file mode 100644 index 00000000..c6bea0d3 --- /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 +#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 00000000..1460e57a --- /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 + +#define APPLE_MIC_ONLY 1 + +@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 mikeys + id a2 = [self allDevicesMatchingUsagePage:12 usageId:1 withClass:self skipZeroLocations:NO]; +#if APPLE_MIC_ONLY + a2 = [a2 filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"productName == \"Apple Mikey HID Driver\""]]; +#endif + + 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 00000000..f6bc8ef3 --- /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 + +#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 00000000..265db457 --- /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 00000000..40b9fdb3 --- /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 +#include +#include +#include +#include + +@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 00000000..387a1e5e --- /dev/null +++ b/lib/DDHidDevice.m @@ -0,0 +1,595 @@ +/* + * 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 + +@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); + id retVal = nil; + if(hidMatchDictionary) { + retVal = [self allDevicesMatchingCFDictionary: hidMatchDictionary + withClass: [DDHidDevice class] + skipZeroLocations: NO]; + //CFRelease(hidMatchDictionary);//dont free, it is freed by IOServiceGetMatchingServices + } + return retVal; +} + ++ (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); + id retVal = nil; + if(hidMatchDictionary) { + NSMutableDictionary * objcMatchDictionary = + (NSMutableDictionary *) hidMatchDictionary; + [objcMatchDictionary ddhid_setObject: [NSNumber numberWithUnsignedInt: usagePage] + forString: kIOHIDDeviceUsagePageKey]; + [objcMatchDictionary ddhid_setObject: [NSNumber numberWithUnsignedInt: usageId] + forString: kIOHIDDeviceUsageKey]; + retVal = [self allDevicesMatchingCFDictionary: hidMatchDictionary + withClass: hidClass + skipZeroLocations: skipZeroLocations]; + //CFRelease(hidMatchDictionary);//dont free, it is freed by IOServiceGetMatchingServices + } +return retVal; +} + ++ (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 00000000..4e9577cd --- /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 +#include + +@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 00000000..5a00095b --- /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 + +@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 00000000..0861cfd2 --- /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 +#include + +@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 00000000..8b2ab5fb --- /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 00000000..ebf20ccb --- /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 +#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 00000000..986ea280 --- /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 + +@interface DDHidJoystick (DDHidJoystickDelegate) + +- (void) ddhidJoystick: (DDHidJoystick *) joystick + stick: (unsigned) stick + xChanged: (int) value; + +- (void) ddhidJoystick: (DDHidJoystick *) joystick + stick: (unsigned) stick + yChanged: (int) value; + +- (void) ddhidJoystick: (DDHidJoystick *) joystick + stick: (unsigned) stick + otherAxis: (unsigned) otherAxis + valueChanged: (int) value; + +- (void) ddhidJoystick: (DDHidJoystick *) joystick + stick: (unsigned) stick + povNumber: (unsigned) povNumber + valueChanged: (int) value; + +- (void) ddhidJoystick: (DDHidJoystick *) joystick + buttonDown: (unsigned) buttonNumber; + +- (void) ddhidJoystick: (DDHidJoystick *) joystick + buttonUp: (unsigned) buttonNumber; + +@end + +@interface DDHidJoystick (Private) + +- (void) initLogicalDeviceElements; +- (void) initJoystickElements: (NSArray *) elements; +- (void) addStick: (NSArray *) stickElements; +- (void) ddhidQueueHasEvents: (DDHidQueue *) hidQueue; + +- (int) normalizeValue: (int) value + forElement: (DDHidElement *) element; + +- (int) povValue: (int) value + forElement: (DDHidElement *) element; + +- (BOOL) findStick: (unsigned *) stick + element: (DDHidElement **) elementOut + withXAxisCookie: (IOHIDElementCookie) cookie; + +- (BOOL) findStick: (unsigned *) stick + element: (DDHidElement **) elementOut + withYAxisCookie: (IOHIDElementCookie) cookie; + +- (BOOL) findStick: (unsigned *) stickOut + otherAxis: (unsigned *) axisOut + element: (DDHidElement **) elementOut + withCookie: (IOHIDElementCookie) cookie; + +- (BOOL) findStick: (unsigned *) stickOut + povNumber: (unsigned *) povNumber + element: (DDHidElement **) elementOut + withCookie: (IOHIDElementCookie) cookie; + +@end + +@implementation DDHidJoystick + ++ (NSArray *) allJoysticks; +{ + NSArray * joysticks = + [DDHidDevice allDevicesMatchingUsagePage: kHIDPage_GenericDesktop + usageId: kHIDUsage_GD_Joystick + withClass: self + skipZeroLocations: YES]; + NSArray * gamepads = + [DDHidDevice allDevicesMatchingUsagePage: kHIDPage_GenericDesktop + usageId: kHIDUsage_GD_GamePad + withClass: self + skipZeroLocations: YES]; + + NSMutableArray * allJoysticks = [NSMutableArray arrayWithArray: joysticks]; + [allJoysticks addObjectsFromArray: gamepads]; + [allJoysticks sortUsingSelector: @selector(compareByLocationId:)]; + return allJoysticks; +} + +- (id) initLogicalWithDevice: (io_object_t) device + logicalDeviceNumber: (int) logicalDeviceNumber + error: (NSError **) error; +{ + self = [super initLogicalWithDevice: device + logicalDeviceNumber: logicalDeviceNumber + error: error]; + if (self == nil) + return nil; + + mButtonElements = [[NSMutableArray alloc] init]; + mSticks = [[NSMutableArray alloc] init]; + mLogicalDeviceElements = [[NSMutableArray alloc] init]; + + [self initLogicalDeviceElements]; + int logicalDeviceCount = [mLogicalDeviceElements count]; + if (logicalDeviceCount == 0) + { + [self release]; + return nil; + } + + mLogicalDeviceNumber = logicalDeviceNumber; + if (mLogicalDeviceNumber >= logicalDeviceCount) + mLogicalDeviceNumber = logicalDeviceCount - 1; + + [self initJoystickElements: + [mLogicalDeviceElements objectAtIndex: mLogicalDeviceNumber]]; + [mButtonElements sortUsingSelector: @selector(compareByUsage:)]; + mDelegate = nil; + + return self; +} + +//=========================================================== +// dealloc +//=========================================================== +- (void) dealloc +{ + [mLogicalDeviceElements release]; + [mSticks release]; + [mButtonElements release]; + + mLogicalDeviceElements = nil; + mSticks = nil; + mButtonElements = nil; + [super dealloc]; +} + +- (int) logicalDeviceCount; +{ + return [mLogicalDeviceElements count]; +} + +#pragma mark - +#pragma mark Joystick Elements + +//=========================================================== +// - buttonElements +//=========================================================== +- (NSArray *) buttonElements; +{ + return mButtonElements; +} + +- (unsigned) numberOfButtons; +{ + return [mButtonElements count]; +} + +#pragma mark - +#pragma mark Sticks - indexed accessors + +- (unsigned int) countOfSticks +{ + return [mSticks count]; +} + +- (DDHidJoystickStick *) objectInSticksAtIndex: (unsigned int)index +{ + return [mSticks objectAtIndex: index]; +} + +- (void) addElementsToQueue: (DDHidQueue *) queue; +{ + NSEnumerator * e = [mSticks objectEnumerator]; + DDHidJoystickStick * stick; + while (stick = [e nextObject]) + { + [queue addElements: [stick allElements]]; + } + + [queue addElements: mButtonElements]; +} + + +#pragma mark - +#pragma mark Asynchronous Notification + +- (void) setDelegate: (id) delegate; +{ + mDelegate = delegate; +} + +- (void) addElementsToDefaultQueue; +{ + [self addElementsToQueue: mDefaultQueue]; +} + +@end + +@implementation DDHidJoystick (Private) + +- (void) initLogicalDeviceElements; +{ + NSArray * topLevelElements = [self elements]; + if ([topLevelElements count] == 0) + { + [mLogicalDeviceElements addObject: topLevelElements]; + return; + } + + NSEnumerator * e = [topLevelElements objectEnumerator]; + DDHidElement * element; + while (element = [e nextObject]) + { + unsigned usagePage = [[element usage] usagePage]; + unsigned usageId = [[element usage] usageId]; + if (usagePage == kHIDPage_GenericDesktop && + (usageId == kHIDUsage_GD_Joystick || usageId == kHIDUsage_GD_GamePad)) + { + [mLogicalDeviceElements addObject: [NSArray arrayWithObject: element]]; + } + } +} + +- (void) initJoystickElements: (NSArray *) elements; +{ + NSEnumerator * e = [elements objectEnumerator]; + DDHidElement * element; + DDHidJoystickStick * currentStick = [[[DDHidJoystickStick alloc] init] autorelease]; + BOOL stickHasElements = NO; + + while (element = [e nextObject]) + { + unsigned usagePage = [[element usage] usagePage]; + unsigned usageId = [[element usage] usageId]; + NSArray * subElements = [element elements]; + + if ([subElements count] > 0) + { + [self initJoystickElements: subElements]; + } + else if ((usagePage == kHIDPage_GenericDesktop) && + (usageId == kHIDUsage_GD_Pointer)) + { + [self addStick: subElements]; + } + else if ([currentStick addElement: element]) + { + stickHasElements = YES; + } + else if ((usagePage == kHIDPage_Button) && + (usageId > 0)) + { + [mButtonElements addObject: element]; + } + } + if (stickHasElements) + { + [mSticks addObject: currentStick]; + } +} + +- (void) addStick: (NSArray *) elements; +{ + NSEnumerator * e = [elements objectEnumerator]; + DDHidElement * element; + while (element = [e nextObject]) + { + NSLog(@"Stick element: %@", [[element usage] usageName]); + } +} + +- (void) ddhidQueueHasEvents: (DDHidQueue *) hidQueue; +{ + DDHidEvent * event; + while ((event = [hidQueue nextEvent])) + { + IOHIDElementCookie cookie = [event elementCookie]; + SInt32 value = [event value]; + DDHidElement * element; + unsigned stick; + unsigned otherAxis; + unsigned povNumber; + if ([self findStick: &stick element: &element withXAxisCookie: cookie]) + { + int normalizedValue = [self normalizeValue: value forElement: element]; + [self ddhidJoystick: self stick: stick xChanged: normalizedValue]; + } + else if ([self findStick: &stick element: &element withYAxisCookie: cookie]) + { + int normalizedValue = [self normalizeValue: value forElement: element]; + [self ddhidJoystick: self stick: stick yChanged: normalizedValue]; + } + else if ([self findStick: &stick otherAxis: &otherAxis element: &element + withCookie: cookie]) + { + int normalizedValue = [self normalizeValue: value forElement: element]; + [self ddhidJoystick: self stick: stick + otherAxis: otherAxis valueChanged: normalizedValue]; + } + else if ([self findStick: &stick povNumber: &povNumber element: &element + withCookie: cookie]) + { + int povValue = [self povValue: value forElement: element]; + [self ddhidJoystick: self stick: stick + povNumber: povNumber valueChanged: povValue]; + } + else + { + unsigned i = 0; + for (i = 0; i < [[self buttonElements] count]; i++) + { + if (cookie == [[[self buttonElements] objectAtIndex: i] cookie]) + break; + } + + if (value == 1) + { + [self ddhidJoystick: self buttonDown: i]; + } + else if (value == 0) + { + [self ddhidJoystick: self buttonUp: i]; + } + else + { + DDHidElement * element = [self elementForCookie: [event elementCookie]]; + NSLog(@"Element: %@, value: %d", [[element usage] usageName], (int)[event value]); + } + } + } +} + +- (int) normalizeValue: (int) value + forElement: (DDHidElement *) element; +{ + int normalizedUnits = DDHID_JOYSTICK_VALUE_MAX - DDHID_JOYSTICK_VALUE_MIN; + int elementUnits = [element maxValue] - [element minValue]; + + int normalizedValue = (((int64_t)(value - [element minValue]) * normalizedUnits) / + elementUnits) + DDHID_JOYSTICK_VALUE_MIN; + return normalizedValue; +} + +- (int) povValue: (int) value + forElement: (DDHidElement *) element; +{ + long max = [element maxValue]; + long min = [element minValue]; + + // If the value is outside the min/max range, it's probably in a + // centered/NULL state. + if ((value < min) || (value > max)) + { + return -1; + } + + // Do like DirectInput and express the hatswitch value in hundredths of a + // degree, clockwise from north. + return 36000 / (max - min + 1) * (value - min); +} + +- (BOOL) findStick: (unsigned *) stick + element: (DDHidElement **) elementOut + withXAxisCookie: (IOHIDElementCookie) cookie; +{ + unsigned i; + for (i = 0; i < [mSticks count]; i++) + { + DDHidElement * element = [[mSticks objectAtIndex: i] xAxisElement]; + if ((element != nil) && ([element cookie] == cookie)) + { + *stick = i; + *elementOut = element; + return YES; + } + } + return NO; +} + +- (BOOL) findStick: (unsigned *) stick + element: (DDHidElement **) elementOut + withYAxisCookie: (IOHIDElementCookie) cookie; +{ + unsigned i; + for (i = 0; i < [mSticks count]; i++) + { + DDHidElement * element = [[mSticks objectAtIndex: i] yAxisElement]; + if ((element != nil) && ([element cookie] == cookie)) + { + *stick = i; + *elementOut = element; + return YES; + } + } + return NO; +} + +- (BOOL) findStick: (unsigned *) stickOut + otherAxis: (unsigned *) axisOut + element: (DDHidElement **) elementOut + withCookie: (IOHIDElementCookie) cookie; +{ + unsigned i; + for (i = 0; i < [mSticks count]; i++) + { + DDHidJoystickStick * stick = [mSticks objectAtIndex: i]; + unsigned j; + for (j = 0; j < [stick countOfStickElements]; j++) + { + DDHidElement * element = [stick objectInStickElementsAtIndex: j]; + if ((element != nil) && ([element cookie] == cookie)) + { + *stickOut = i; + *axisOut = j; + *elementOut = element; + return YES; + } + } + } + return NO; +} + +- (BOOL) findStick: (unsigned *) stickOut + povNumber: (unsigned *) povNumber + element: (DDHidElement **) elementOut + withCookie: (IOHIDElementCookie) cookie; +{ + unsigned i; + for (i = 0; i < [mSticks count]; i++) + { + DDHidJoystickStick * stick = [mSticks objectAtIndex: i]; + unsigned j; + for (j = 0; j < [stick countOfPovElements]; j++) + { + DDHidElement * element = [stick objectInPovElementsAtIndex: j]; + if ((element != nil) && ([element cookie] == cookie)) + { + *stickOut = i; + *povNumber = j; + *elementOut = element; + return YES; + } + } + } + return NO; +} + +@end + +@implementation DDHidJoystick (DDHidJoystickDelegate) + +- (void) ddhidJoystick: (DDHidJoystick *) joystick + stick: (unsigned) stick + xChanged: (int) value; +{ + if ([mDelegate respondsToSelector: _cmd]) + [mDelegate ddhidJoystick: joystick stick: stick xChanged: value]; +} + +- (void) ddhidJoystick: (DDHidJoystick *) joystick + stick: (unsigned) stick + yChanged: (int) value; +{ + if ([mDelegate respondsToSelector: _cmd]) + [mDelegate ddhidJoystick: joystick stick: stick yChanged: value]; +} + +- (void) ddhidJoystick: (DDHidJoystick *) joystick + stick: (unsigned) stick + otherAxis: (unsigned) otherAxis + valueChanged: (int) value; +{ + if ([mDelegate respondsToSelector: _cmd]) + [mDelegate ddhidJoystick: joystick stick: stick otherAxis: otherAxis + valueChanged: value]; +} + +- (void) ddhidJoystick: (DDHidJoystick *) joystick + stick: (unsigned) stick + povNumber: (unsigned) povNumber + valueChanged: (int) value; +{ + if ([mDelegate respondsToSelector: _cmd]) + [mDelegate ddhidJoystick: joystick stick: stick povNumber: povNumber + valueChanged: value]; +} + +- (void) ddhidJoystick: (DDHidJoystick *) joystick + buttonDown: (unsigned) buttonNumber; +{ + if ([mDelegate respondsToSelector: _cmd]) + [mDelegate ddhidJoystick: joystick buttonDown: buttonNumber]; +} + +- (void) ddhidJoystick: (DDHidJoystick *) joystick + buttonUp: (unsigned) buttonNumber; +{ + if ([mDelegate respondsToSelector: _cmd]) + [mDelegate ddhidJoystick: joystick buttonUp: buttonNumber]; +} + +@end + +@implementation DDHidJoystickStick + +- (id) init +{ + self = [super init]; + if (self == nil) + return nil; + + mXAxisElement = nil; + mYAxisElement = nil; + mStickElements = [[NSMutableArray alloc] init]; + mPovElements = [[NSMutableArray alloc] init]; + + return self; +} + +//=========================================================== +// dealloc +//=========================================================== +- (void) dealloc +{ + [mXAxisElement release]; + [mYAxisElement release]; + [mStickElements release]; + [mPovElements release]; + + mXAxisElement = nil; + mYAxisElement = nil; + mStickElements = nil; + mPovElements = nil; + [super dealloc]; +} + +- (BOOL) addElement: (DDHidElement *) element; +{ + DDHidUsage * usage = [element usage]; + if ([usage usagePage] != kHIDPage_GenericDesktop) + return NO; + + BOOL elementAdded = YES; + switch ([usage usageId]) + { + case kHIDUsage_GD_X: + if (mXAxisElement == nil) + mXAxisElement = [element retain]; + else + [mStickElements addObject: element]; + break; + + case kHIDUsage_GD_Y: + if (mYAxisElement == nil) + mYAxisElement = [element retain]; + else + [mStickElements addObject: element]; + break; + + case kHIDUsage_GD_Z: + case kHIDUsage_GD_Rx: + case kHIDUsage_GD_Ry: + case kHIDUsage_GD_Rz: + [mStickElements addObject: element]; + break; + + case kHIDUsage_GD_Hatswitch: + [mPovElements addObject: element]; + break; + + default: + elementAdded = NO; + + } + + return elementAdded; +} + +- (NSArray *) allElements; +{ + NSMutableArray * elements = [NSMutableArray array]; + if (mXAxisElement != nil) + [elements addObject: mXAxisElement]; + if (mYAxisElement != nil) + [elements addObject: mYAxisElement]; + [elements addObjectsFromArray: mStickElements]; + [elements addObjectsFromArray: mPovElements]; + return elements; +} + +- (DDHidElement *) xAxisElement; +{ + return mXAxisElement; +} + +- (DDHidElement *) yAxisElement; +{ + return mYAxisElement; +} + +#pragma mark - +#pragma mark mStickElements - indexed accessors + +- (unsigned int) countOfStickElements +{ + return [mStickElements count]; +} + +- (DDHidElement *) objectInStickElementsAtIndex: (unsigned int)index +{ + return [mStickElements objectAtIndex: index]; +} + +#pragma mark - +#pragma mark PovElements - indexed accessors + +- (unsigned int) countOfPovElements; +{ + return [mPovElements count]; +} + +- (DDHidElement *) objectInPovElementsAtIndex: (unsigned int)index; +{ + return [mPovElements objectAtIndex: index]; +} + +- (NSString *) description; +{ + return [mStickElements description]; +} + +@end diff --git a/lib/DDHidKeyboard.h b/lib/DDHidKeyboard.h new file mode 100644 index 00000000..fd9200d2 --- /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 +#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 00000000..5b0db354 --- /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 + +@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 00000000..6573b016 --- /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 +#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; + +- (NSUInteger) 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 00000000..a6c434fe --- /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 + +@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; +} + +- (NSUInteger) 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 00000000..20d86817 --- /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 00000000..d396aba0 --- /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 +#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 00000000..ab478a3a --- /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 + + +// 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], (int)[event value]); + } + } + } +} + +@end + diff --git a/lib/DDHidQueue.h b/lib/DDHidQueue.h new file mode 100644 index 00000000..315d0031 --- /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 +#include + +@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 00000000..4575dff0 --- /dev/null +++ b/lib/DDHidQueue.m @@ -0,0 +1,174 @@ +/* + * 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]; + CFRelease(mEventSource); + + 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 00000000..84eb663f --- /dev/null +++ b/lib/DDHidStandardUsages.plist @@ -0,0 +1,2327 @@ + + + + + 1 + + description + Generic Desktop + ranges + + + usages + + 0 + Undefined + 1 + Pointer + 2 + Mouse + 3 + Reserved + 4 + Joystick + 5 + Game Pad + 6 + Keyboard + 7 + Keypad + 8 + Multi-axis Controller + 48 + X + 49 + Y + 50 + Z + 51 + Rx + 52 + Ry + 53 + Rz + 54 + Slider + 55 + Dial + 56 + Wheel + 57 + Hat Switch + 58 + Counted Buffer + 59 + Byte Count + 60 + Motion Wakeup + 64 + Vx + 65 + Vy + 66 + Vz + 67 + Vbrx + 68 + Vbry + 69 + Vbrx + 70 + Vno + 128 + System Control + 129 + System Power Down + 130 + System Sleep + 131 + System Wake Up + 132 + System Context Menu + 133 + System Main Menu + 134 + System App Menu + 135 + System Menu Help + 136 + System Menu Exit + 137 + System Menu Select + 138 + System Menu Right + 139 + System Menu Left + 140 + System Menu Up + 141 + System Menu Down + 144 + D-pad Up + 145 + D-pad Down + 146 + D-pad Right + 147 + D-pad Left + + + 2 + + description + Simulation Controls + ranges + + + usages + + 0 + Undefined + 1 + Flight Simulation Device + 2 + Automobile Simulation Device + 3 + Tank Simulation Device + 4 + Spaceship Simulation Device + 5 + Submarine Simulation Device + 6 + Sailing Simulation Device + 7 + Motorcycle Simulation Device + 8 + Sports Simulation Device + 9 + Airplane Simulation Device + 10 + Helicopter Simulation Device + 11 + Magic Carpet Simulation Device + 12 + Bicycle + 32 + Flight Control Stick + 33 + Flight Stick + 34 + Cyclic Control + 35 + Cyclic Trim + 36 + Flight Yoke + 37 + Track Control + 38 + Driving Control + 176 + Aileron + 177 + Aileron Trim + 178 + Anti-Torque Control + 179 + Auto-pilot Enable + 180 + Chaff Release + 181 + Collective Control + 182 + Dive Brake + 183 + Electronic Counter Measures + 184 + Elevator + 185 + Elevator Trim + 186 + Rudder + 187 + Throttle + 188 + Flight Communication + 189 + Flare Release + 190 + Landing Gear + 191 + Toe Brake + 192 + Trigger + 193 + Weapons Arm + 194 + Weapons Select + 195 + Wing Flaps + 196 + Accelerator + 197 + Brake + 198 + Clutch + 199 + Shifter + 200 + Steering + 201 + Turret Direction + 202 + Barrel Elevation + 203 + Dive Plane + 204 + Ballast + 205 + Bicycle Crank + 206 + Handle Bars + 207 + Front Brake + 208 + Rear Brake + + + 3 + + description + VR Controls + ranges + + + usages + + 0 + Unidentified + 1 + Belt + 2 + Body Suit + 3 + Flexor + 4 + Glove + 5 + Head Tracker + 6 + Head Mounted Display + 7 + Hand Tracker + 8 + Oculometer + 9 + Vest + 10 + Animatronic Device + 32 + Stereo Enable + 33 + Display Enable + + + 4 + + description + Sports Controls + ranges + + + usages + + 0 + Unidentified + 1 + Baseball Bat + 2 + Golf Club + 3 + Rowing Machine + 4 + Treadmill + 48 + Oar + 49 + Slope + 50 + Rate + 51 + Stick Speed + 52 + Stick Face Angle + 53 + Stick Heel/Toe + 54 + Stick Follow Through + 55 + Stick Tempo + 56 + Stick Type + 57 + Stick Height + 80 + Putter + 81 + 1 Iron + 82 + 2 Iron + 83 + 3 Iron + 84 + 4 Iron + 85 + 5 Iron + 86 + 6 Iron + 87 + 7 Iron + 88 + 8 Iron + 89 + 9 Iron + 90 + 10 Iron + 91 + 11 Iron + 92 + Sand Wedge + 93 + Loft Wedge + 94 + Power Wedge + 95 + 1 Wood + 96 + 3 Wood + 97 + 5 Wood + 98 + 7 Wood + 99 + 9 Wood + + + 5 + + description + Game Controls + ranges + + + usages + + 0 + Undefined + 1 + 3D Game Controller + 2 + Pinball Device + 3 + Gun Device + 32 + Point of View + 33 + Turn Right/Left + 34 + Pitch Right/Left + 35 + Roll Forward/Backward + 36 + Move Right/Left + 37 + Move Forward/Backward + 38 + Move Up/Down + 39 + Lean Right/Left + 40 + Lean Forward/Backward + 41 + Height of POV + 42 + Flipper + 43 + Secondary Flipper + 44 + Bump + 45 + New Game + 46 + Shoot Ball + 47 + Player + 48 + Gun Bolt + 49 + Gun Clip + 50 + Gun Selector + 51 + Gun Single Shot + 52 + Gun Burst + 53 + Gun Automatic + 54 + Gun Safety + 55 + Gamepad Fire/Jump + 57 + Gamepad Trigger + + + 7 + + description + Keyboard + ranges + + + usages + + 0 + No Event + 1 + Keyboard ErrorRollOver + 2 + Keyboard POSTFail + 3 + Keyboard ErrorUndefined + 4 + Keyboard a and A + 5 + Keyboard b and B + 6 + Keyboard c and C + 7 + Keyboard d and D + 8 + Keyboard e and E + 9 + Keyboard f and F + 10 + Keyboard g and G + 11 + Keyboard h and H + 12 + Keyboard i and I + 13 + Keyboard j and J + 14 + Keyboard k and K + 15 + Keyboard l and L + 16 + Keyboard m and M + 17 + Keyboard n and N + 18 + Keyboard o and O + 19 + Keyboard p and P + 20 + Keyboard q and Q + 21 + Keyboard r and R + 22 + Keyboard s and S + 23 + Keyboard t and T + 24 + Keyboard u and U + 25 + Keyboard v and V + 26 + Keyboard w and W + 27 + Keyboard x and X + 28 + Keyboard y and Y + 29 + Keyboard z and Z + 30 + Keyboard 1 and ! + 31 + Keyboard 2 and @ + 32 + Keyboard 3 and # + 33 + Keyboard 4 and $ + 34 + Keyboard 5 and % + 35 + Keyboard 6 and ^ + 36 + Keyboard 7 and & + 37 + Keyboard 8 and * + 38 + Keyboard 9 and ( + 39 + Keyboard 0 and ) + 40 + Keyboard Return (ENTER) + 41 + Keyboard ESCAPE + 42 + Keyboard DELETE (Backspace) + 43 + Keyboard Tab + 44 + Keyboard Spacebar + 45 + Keyboard - and (underscore) + 46 + Keyboard = and + + 47 + Keyboard [ and { + 48 + Keyboard ] and } + 49 + Keyboard \ and | + 50 + Keyboard Non-US # and ~ + 51 + Keyboard ; and : + 52 + Keyboard ' and " + 53 + Keyboard Grave Accent and Tilde + 54 + Keyboard, and < + 55 + Keyboard . and > + 56 + Keyboard / and ? + 57 + Keyboard Caps Lock + 58 + Keyboard F1 + 59 + Keyboard F2 + 60 + Keyboard F3 + 61 + Keyboard F4 + 62 + Keyboard F5 + 63 + Keyboard F6 + 64 + Keyboard F7 + 65 + Keyboard F8 + 66 + Keyboard F9 + 67 + Keyboard F10 + 68 + Keyboard F11 + 69 + Keyboard F12 + 70 + Keyboard PrintScreen + 71 + Keyboard Scroll Lock + 72 + Keyboard Pause + 73 + Keyboard Insert + 74 + Keyboard Home + 75 + Keyboard PageUp + 76 + Keyboard Delete Forward + 77 + Keyboard End + 78 + Keyboard PageDown + 79 + Keyboard RightArrow + 80 + Keyboard LeftArrow + 81 + Keyboard DownArrow + 82 + Keyboard UpArrow + 83 + Keypad Num Lock and Clear + 84 + Keypad / + 85 + Keypad * + 86 + Keypad - + 87 + Keypad + + 88 + Keypad ENTER + 89 + Keypad 1 and End + 90 + Keypad 2 and Down Arrow + 91 + Keypad 3 and PageDn + 92 + Keypad 4 and Left Arrow + 93 + Keypad 5 + 94 + Keypad 6 and Right Arrow + 95 + Keypad 7 and Home + 96 + Keypad 8 and Up Arrow + 97 + Keypad 9 and PageUp + 98 + Keypad 0 and Insert + 99 + Keypad . and Delete + 100 + Keyboard Non-US \ and | + 101 + Keyboard Application + 102 + Keyboard Power + 103 + Keypad = + 104 + Keyboard F13 + 105 + Keyboard F14 + 106 + Keyboard F15 + 107 + Keyboard F16 + 108 + Keyboard F17 + 109 + Keyboard F18 + 110 + Keyboard F19 + 111 + Keyboard F20 + 112 + Keyboard F21 + 113 + Keyboard F22 + 114 + Keyboard F23 + 115 + Keyboard F24 + 116 + Keyboard Execute + 117 + Keyboard Help + 118 + Keyboard Menu + 119 + Keyboard Select + 120 + Keyboard Stop + 121 + Keyboard Again + 122 + Keyboard Undo + 123 + Keyboard Cut + 124 + Keyboard Copy + 125 + Keyboard Paste + 126 + Keyboard Find + 127 + Keyboard Mute + 128 + Keyboard Volume Up + 129 + Keyboard Volume Down + 130 + Keyboard Locking Caps Lock + 131 + Keyboard Locking Num Lock + 132 + Keyboard Locking Scroll Lock + 133 + Keypad Comma + 134 + Keypad Equal Sign + 135 + Keyboard International1 + 136 + Keyboard International2 + 137 + Keyboard International3 + 138 + Keyboard International4 + 139 + Keyboard International5 + 140 + Keyboard International6 + 141 + Keyboard International7 + 142 + Keyboard International8 + 143 + Keyboard International9 + 144 + Keyboard LANG1 + 145 + Keyboard LANG2 + 146 + Keyboard LANG3 + 147 + Keyboard LANG4 + 148 + Keyboard LANG5 + 149 + Keyboard LANG6 + 150 + Keyboard LANG7 + 151 + Keyboard LANG8 + 152 + Keyboard LANG9 + 153 + Keyboard Alternate Erase + 154 + Keyboard SysReq/Attention + 155 + Keyboard Cancel + 156 + Keyboard Clear + 157 + Keyboard Prior + 158 + Keyboard Return + 159 + Keyboard Separator + 160 + Keyboard Out + 161 + Keyboard Oper + 162 + Keyboard Clear/Again + 163 + Keyboard CrSel/Props + 164 + Keyboard ExSel + 224 + Keyboard LeftControl + 225 + Keyboard LeftShift + 226 + Keyboard LeftAlt + 227 + Keyboard Left GUI + 228 + Keyboard RightControl + 229 + Keyboard RightShift + 230 + Keyboard RightAlt + 231 + Keyboard Right GUI + + + 8 + + description + LEDs + ranges + + {76, 65535} + Reserved + + usages + + 0 + Undefined + 1 + Num Lock + 2 + Caps Lock + 3 + Scroll Lock + 4 + Compose + 5 + Kana + 6 + Power + 7 + Shift + 8 + Do Not Disturb + 9 + Mute + 10 + Tone Enable + 11 + High Cut Filter + 12 + Low Cut Filter + 13 + Equalizer Enable + 14 + Sound Field On + 15 + Surround Field On + 16 + Repeat + 17 + Stereo + 18 + Sampling Rate Detect + 19 + Spinning + 20 + CAV + 21 + CLV + 22 + Recording Format Detect + 23 + Off-Hook + 24 + Ring + 25 + Message Waiting + 26 + Data Mode + 27 + Battery Operation + 28 + Battery OK + 29 + Battery Low + 30 + Speaker + 31 + Head Set + 32 + Hold + 33 + Microphone + 34 + Coverage + 35 + Night Mode + 36 + Send Calls + 37 + Call Pickup + 38 + Conference + 39 + Stand-by + 40 + Camera On + 41 + Camera Off + 42 + On-Line + 43 + Off-Line + 44 + Busy + 45 + Ready + 46 + Paper-Out + 47 + Paper-Jam + 48 + Remote + 49 + Forward + 50 + Reverse + 51 + Stop + 52 + Rewind + 53 + Fast Forward + 54 + Play + 55 + Pause + 56 + Record + 57 + Error + 58 + Usage Selected Indicator + 59 + Usage In Use Indicator + 60 + Usage Multi Mode Indicator + 61 + Indicator On + 62 + Indicator Flash + 63 + Indicator Slow Blink + 64 + Indicator Fast Blink + 65 + Indicator Off + 66 + Flash On Time + 67 + Slow Blink On Time + 68 + Slow Blink Off Time + 69 + Fast Blink On Time + 70 + Fast Blink Off Time + 71 + Usage Indicator Color + 72 + Red + 73 + Green + 74 + Amber + 75 + Generic Indicator + 76 + System Suspend + 77 + External Power Connected + + + 9 + + default + Button %d + description + Button + ranges + + + usages + + 0 + No Button Pressed + + + 10 + + default + Instance %d + description + Ordinal + ranges + + + usages + + 0 + Unused + + + 11 + + description + Telephony + ranges + + + usages + + 0 + Unassigned + 1 + Phone + 2 + Answering Machine + 3 + Message Controls + 4 + Handset + 5 + Headset + 6 + Telephony Key Pad + 7 + Programmable Button + 32 + Hook Switch + 33 + Flash + 34 + Feature + 35 + Hold + 36 + Redial + 37 + Transfer + 38 + Drop + 39 + Park + 40 + Forward Calls + 41 + Alternate Function + 42 + Line + 43 + Speaker Phone + 44 + Conference + 45 + Ring Enable + 46 + Ring Select + 47 + Phone Mute + 48 + Caller ID + 80 + Speed Dial + 81 + Store Number + 82 + Recall Number + 83 + Phone Directory + 112 + Voice Mail + 113 + Screen Calls + 114 + Do Not Disturb + 115 + Message + 116 + Answer On/Off + 144 + Inside Dial Tone + 145 + Outside Dial Tone + 146 + Inside Ring Tone + 147 + Outside Ring Tone + 148 + Priority Ring Tone + 149 + Inside Ringback + 150 + Priority Ringback + 151 + Line Busy Tone + 152 + Reorder Tone + 153 + Call Waiting Tone + 154 + Confirmation Tone 1 + 155 + Confirmation Tone 2 + 156 + Tones Off + 176 + Phone Key 0 + 177 + Phone Key 1 + 178 + Phone Key 2 + 179 + Phone Key 3 + 180 + Phone Key 4 + 181 + Phone Key 5 + 182 + Phone Key 6 + 183 + Phone Key 7 + 184 + Phone Key 8 + 185 + Phone Key 9 + 186 + Phone Key Star + 187 + Phone Key Pound + 188 + Phone Key A + 189 + Phone Key B + 190 + Phone Key C + 191 + Phone Key D + + + 12 + + description + Consumer + ranges + + + usages + + 0 + Unassigned + 1 + Consumer Control + 2 + Numeric Key Pad + 3 + Programmable Buttons + 32 + +10 + 33 + +100 + 34 + AM/PM + 48 + Power + 49 + Reset + 50 + Sleep + 51 + Sleep After + 52 + Sleep Mode + 53 + Illumination + 54 + Function Buttons + 64 + Menu + 65 + Menu Pick + 66 + Menu Up + 67 + Menu Down + 68 + Menu Left + 69 + Menu Right + 70 + Menu Escape + 71 + Menu Value Increase + 72 + Menu Value Decrease + 96 + Data On Screen + 97 + Closed Caption + 98 + Closed Caption Select + 99 + VCR/TV + 100 + Broadcast Mode + 101 + Snapshot + 102 + Still + 128 + Selection + 129 + Assign Selection + 130 + Mode Step + 131 + Recall Last + 132 + Enter Channel + 133 + Order Movie + 134 + Channel + 135 + Media Selection + 136 + Media Select Computer + 137 + Media Select TV + 138 + Media Select WWW + 139 + Media Select DVD + 140 + Media Select Telephone + 141 + Media Select Program Guide + 142 + Media Select Video Phone + 143 + Media Select Games + 144 + Media Select Messages + 145 + Media Select CD + 146 + Media Select VCR + 147 + Media Select Tuner + 148 + Quit + 149 + Help + 150 + Media Select Tape + 151 + Media Select Cable + 152 + Media Select Satellite + 153 + Media Select Security + 154 + Media Select Home + 155 + Media Select Call + 156 + Channel Increment + 157 + Channel Decrement + 158 + Media Select SAP + 160 + VCR Plus + 161 + Once + 162 + Daily + 163 + Weekly + 164 + Monthly + 176 + Play + 177 + Pause + 178 + Record + 179 + Fast Forward + 180 + Rewind + 181 + Scan Next Track + 182 + Scan Previous Track + 183 + Stop + 184 + Eject + 185 + Random Play + 186 + Select DisC + 187 + Enter Disc + 188 + Repeat + 189 + Tracking + 190 + Track Normal + 191 + Slow Tracking + 192 + Frame Forward + 193 + Frame Back + 194 + Mark + 195 + Clear Mark + 196 + Repeat From Mark + 197 + Return To Mark + 198 + Search Mark Forward + 199 + Search Mark Backwards + 200 + Counter Reset + 201 + Show Counter + 202 + Tracking Increment + 203 + Tracking Decrement + 205 + Pause/Play + 224 + Volume + 225 + Balance + 226 + Mute + 227 + Bass + 228 + Treble + 229 + Bass Boost + 230 + Surround Mode + 231 + Loudness + 232 + MPX + 233 + Volume Up + 234 + Volume Down + 240 + Speed Select + 241 + Playback Speed + 242 + Standard Play + 243 + Long Play + 244 + Extended Play + 245 + Slow + 256 + Fan Enable + 257 + Fan Speed + 258 + Light + 259 + Light Illumination Level + 260 + Climate Control Enable + 261 + Room Temperature + 262 + Security Enable + 263 + Fire Alarm + 264 + Police Alarm + 336 + Balance Right + 337 + Balance Left + 338 + Bass Increment + 339 + Bass Decrement + 340 + Treble Increment + 341 + Treble Decrement + 352 + Speaker System + 353 + Channel Left + 354 + Channel Right + 355 + Channel Center + 356 + Channel Front + 357 + Channel Center Front + 358 + Channel Side + 359 + Channel Surround + 360 + Channel Low Frequency Enhancement + 361 + Channel Top + 362 + Channel Unknown + 368 + Sub-channel + 369 + Sub-channel Increment + 370 + Sub-channel Decrement + 371 + Alternate Audio Increment + 372 + Alternate Audio Decrement + 384 + Application Launch Buttons + 385 + AL Launch Button Configuration Tool + 386 + AL Programmable Button Configuration + 387 + AL Consumer Control Configuration + 388 + AL Word Processor + 389 + AL Text Editor + 390 + AL Spreadsheet + 391 + AL Graphics Editor + 392 + AL Presentation App + 393 + AL Database App + 394 + AL Email Reader + 395 + AL Newsreader + 396 + AL Voicemail + 397 + AL Contacts/Address Book + 398 + AL Calendar/Schedule + 399 + AL Task/Project Manager + 400 + AL Log/Journal/Timecard + 401 + AL Checkbook/Finance + 402 + AL Calculator + 403 + AL A/V Capture/Playback + 404 + AL Local Machine Browser + 405 + AL LAN/WAN Browser + 406 + AL Internet Browser + 407 + AL Remote Networking/ISP Connect + 408 + AL Network Conference + 409 + AL Network Chat + 410 + AL Telephony/Dialer + 411 + AL Logon + 412 + AL Logoff + 413 + AL Logon/Logoff + 414 + AL Terminal Lock/Screensaver + 415 + AL Control Panel + 416 + AL Command Line Processor/Run + 417 + AL Process/Task Manager + 418 + AL Select Tast/Application + 419 + AL Next Task/Application + 420 + AL Previous Task/Application + 421 + AL Preemptive Halt Task/Application + 423 + AL My Documents + 427 + AC Spell + 438 + AL My Pictures + 439 + AL My Music + 512 + Generic GUI Application Controls + 513 + AC New + 514 + AC Open + 515 + AC Close + 516 + AC Exit + 517 + AC Maximize + 518 + AC Minimize + 519 + AC Save + 520 + AC Print + 521 + AC Properties + 538 + AC Undo + 539 + AC Copy + 540 + AC Cut + 541 + AC Paste + 542 + AC Select All + 543 + AC Find + 544 + AC Find and Replace + 545 + AC Search + 546 + AC Go To + 547 + AC Home + 548 + AC Back + 549 + AC Forward + 550 + AC Stop + 551 + AC Refresh + 552 + AC Previous Link + 553 + AC Next Link + 554 + AC Bookmarks + 555 + AC History + 556 + AC Subscriptions + 557 + AC Zoom In + 558 + AC Zoom Out + 559 + AC Zoom + 560 + AC Full Screen View + 561 + AC Normal View + 562 + AC View Toggle + 563 + AC Scroll Up + 564 + AC Scroll Down + 565 + AC Scroll + 566 + AC Pan Left + 567 + AC Pan Right + 568 + AC Pan + 569 + AC New Window + 570 + AC Tile Horizontally + 571 + AC Tile Vertically + 572 + AC Format + 633 + AC Redo + 649 + AC Reply + 651 + AC Fwd + 652 + AC Send + + + 13 + + description + Digitizer + ranges + + + usages + + 0 + Undefined + 1 + Digitizer + 2 + Pen + 3 + Light Pen + 4 + Touch Screen + 5 + Touch Pad + 6 + White Board + 7 + Coordinate Measuring Machine + 8 + 3-D Digitizer + 9 + Stereo Plotter + 10 + Articulated Arm + 11 + Armature + 12 + Multiple Point Digitizer + 13 + Free Space Wand + 32 + Stylus + 33 + Puck + 34 + Finger + 48 + Tip Pressure + 49 + Barrel Pressure + 50 + In Range + 51 + Touch + 52 + Untouch + 53 + Tap + 54 + Quality + 55 + Data Valid + 56 + Transducer Index + 57 + Tablet Function Keys + 58 + Program Change Keys + 59 + Battery Strength + 60 + Invert + 61 + X Tilt + 62 + Y Tilt + 63 + Azimuth + 64 + Altitude + 65 + Twist + 66 + Tip Switch + 67 + Secondary Tip Switch + 68 + Barrel Switch + 69 + Eraser + 70 + Tablet Pick + + + 15 + + description + Physical Interface Device + ranges + + + usages + + + + 16 + + default + Unicode Char u%04x + description + Unicode + ranges + + + usages + + + + 20 + + description + Alphnumeric Display + ranges + + + usages + + 0 + Undefined + 1 + Alphanumeric Display + 32 + Display Attributes Report + 33 + ASCII Character Set + 34 + Data Read Back + 35 + Font Read Back + 36 + Display Control Report + 37 + Clear Display + 38 + Display Enable + 39 + Screen Saver Delay + 40 + Screen Saver Enable + 41 + Vertical Scroll + 42 + Horizontal Scroll + 43 + Character Report + 44 + Display Data + 45 + Display Status + 46 + Stat Not Ready + 47 + Stat Ready + 48 + Err Not a loadable character + 49 + Err Font data cannot be read + 50 + Cursor Position Report + 51 + Row + 52 + Column + 53 + Rows + 54 + Columns + 55 + Cursor Pixel Positioning + 56 + Cursor Mode + 57 + Cursor Enable + 58 + Cursor Blink + 59 + Font Report + 60 + Font Data + 61 + Character Width + 62 + Character Height + 63 + Character Spacing Horizontal + 64 + Character Spacing Vertical + 65 + Unicode Character Set + + + 128 + + description + Monitor + ranges + + + usages + + 0 + Undefined + 1 + Monitor Control + 2 + EDID Information + 3 + VDIF Information + 4 + VESA Version + 5 + On Screen Display + 6 + Auto Size Center + 7 + Polarity Horz Synch + 8 + Polarity Vert Synch + 9 + Sync Type + 10 + Screen Position + 11 + Horizontal Frequency + 12 + Vertical Frequency + + + 129 + + default + ENUM %d + description + Monitor Enumerated Values + ranges + + + usages + + 0 + unassigned + + + 130 + + description + VESA Virtual Controls + ranges + + + usages + + 16 + Brightness + 18 + Contrast + 22 + Video Gain Red + 24 + Video Gain Green + 26 + Video Gain Blue + 28 + Focus + 32 + Horizontal Position + 34 + Horizontal Size + 36 + Horizontal Pincushion + 38 + Horizontal Pincushion Balance + 40 + Horizontal Misconvergence + 42 + Horizontal Linearity + 44 + Horizontal Linearity Balance + 48 + Vertical Position + 50 + Vertical Size + 52 + Vertical Pincushion + 54 + Vertical Pincushion Balance + 56 + Vertical Misconvergence + 58 + Vertical Linearity + 60 + Vertical Linearity Balance + 64 + Parallelogram Distortion + 66 + Trapezoidal Distortion + 68 + Tilt + 70 + Top Corner Distortion Control + 72 + Top Corner Distortion Balance + 74 + Bottom Corner Distortion Control + 76 + Bottom Corner Distortion Balance + 86 + MoirHorizontal + 88 + MoirVertical + 94 + Input Level Select + 96 + Input Source Select + 98 + Stereo Mode + 108 + Video Black Level Red + 110 + Video Black Level Green + 112 + Video Black Level Blue + + + 131 + + description + VESA Command + ranges + + + usages + + 0 + Undefined + 1 + Settings + 2 + Degauss + + + 132 + + description + Power Device + ranges + + + usages + + 0 + Undefined + 1 + iName + 2 + PresentStatus + 3 + ChangedStatus + 4 + UPS + 5 + PowerSupply + 16 + BatterySystem + 17 + BatterySystemID + 18 + Battery + 19 + BatteryID + 20 + Charger + 21 + ChargerID + 22 + PowerConverter + 23 + PowerConverterID + 24 + OutletSystem + 25 + OutletSystemID + 26 + Input + 27 + InputID + 28 + Output + 29 + OutputID + 30 + Flow + 31 + FlowID + 32 + Outlet + 33 + OutletID + 34 + Gang + 35 + GangID + 36 + Sink + 37 + SinkID + 48 + Voltage + 49 + Current + 50 + Frequency + 51 + ApparentPower + 52 + ActivePower + 53 + PercentLoad + 54 + Temperature + 55 + Humidity + 64 + ConfigVoltage + 65 + ConfigCurrent + 66 + ConfigFrequency + 67 + ConfigApparentPower + 68 + ConfigActivePower + 69 + ConfigPercentLoad + 70 + ConfigTemperature + 71 + ConfigHumidity + 80 + SwitchOnControl + 81 + SwitchOffControl + 82 + ToggleControl + 83 + LowVoltageTransfer + 84 + HighVoltageTransfer + 85 + DelayBeforeReboot + 86 + DelayBeforeStartup + 87 + DelayBeforeShutdown + 88 + Test + 89 + Vendorspecificcommand + 96 + Present + 97 + Good + 98 + InternalFailure + 99 + VoltageOutOfRange + 100 + FrequencyOutOfRange + 101 + Overload + 102 + OverCharged + 103 + OverTemperature + 104 + ShutdownRequested + 105 + ShutdownImminent + 106 + VendorSpecificAnswerValid + 107 + SwitchOn/Off + 108 + Switcheble + 109 + Used + 110 + Boost + 111 + Buck + 112 + Initialized + 113 + Tested + + + 133 + + description + Battery System + ranges + + + usages + + 0 + Undefined + 1 + SMBBatteryMode + 2 + SMBBatteryStatus + 3 + SMBAlarmWarning + 4 + SMBChargerMode + 5 + SMBChargerStatus + 6 + SMBChargerSpecInfo + 7 + SMBSelectorState + 8 + SMBSelectorPreset + 9 + SMBSelectorInfo + 16 + OptionalMfgFunction1 + 17 + OptionalMfgFunction2 + 18 + OptionalMfgFunction3 + 19 + OptionalMfgFunction4 + 20 + OptionalMfgFunction5 + 21 + ConnectionToSMBus + 22 + OutputConnection + 23 + ChargerConnection + 24 + BatteryInsertion + 25 + Usenext + 26 + OKToUse + 40 + ManufacturerAccess + 41 + RemainingCapacityLimit + 42 + RemainingTimeLimit + 43 + AtRate + 44 + CapacityMode + 45 + BroadcastToCharger + 46 + PrimaryBattery + 47 + ChargeController + 64 + TerminateCharge + 65 + TermminateDischarge + 66 + BelowRemainingCapacityLimit + 67 + RemainingTimeLimitExpired + 68 + Charging + 69 + Discharging + 70 + FullyCharged + 71 + FullyDischarged + 72 + ConditionningFlag + 73 + AtRateOK + 74 + SMBErrorCode + 75 + NeedReplacement + 96 + AtRateTimeToFull + 97 + AtRateTimeToEmpty + 98 + AverageCurrent + 99 + Maxerror + 100 + RelativeStateOfCharge + 101 + AbsoluteStateOfCharge + 102 + RemainingCapacity + 103 + FullChargeCapacity + 104 + RunTimeToEmpty + 105 + AverageTimeToEmpty + 106 + AverageTimeToFull + 107 + CycleCount + 128 + BattPackModelLevel + 129 + InternalChargeController + 130 + PrimaryBatterySupport + 131 + DesignCapacity + 132 + SpecificationInfo + 133 + ManufacturerDate + 134 + SerialNumber + 135 + iManufacturerName + 136 + iDevicename + 137 + iDeviceChemistery + 138 + iManufacturerData + 139 + Rechargeable + 140 + WarningCapacityLimit + 141 + CapacityGranularity1 + 142 + CapacityGranularity2 + 192 + InhibitCharge + 193 + EnablePolling + 194 + ResetToZero + 208 + ACPresent + 209 + BatteryPresent + 210 + PowerFail + 211 + AlarmInhibited + 212 + ThermistorUnderRange + 213 + ThermistorHot + 214 + ThermistorCold + 215 + ThermistorOverRange + 216 + VoltageOutOfRange + 217 + CurrentOutOfRange + 218 + CurrentNotRegulated + 219 + VoltageNotRegulated + 220 + MasterMode + 221 + ChargerBattery/HostControlled + 240 + ChargerSpecInfo + 241 + ChargerSpecRef + 242 + Level2 + 243 + Level3 + + + 140 + + description + Bar Code Scanner + ranges + + + usages + + + + 141 + + description + Scale Device + ranges + + + usages + + + + 144 + + description + Camera Control + ranges + + + usages + + + + 145 + + description + Arcade Device + ranges + + + usages + + 233 + Base Up + 234 + Base Down + + + + diff --git a/lib/DDHidUsage.h b/lib/DDHidUsage.h new file mode 100644 index 00000000..8dc5654c --- /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 + + +@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 00000000..8fe2c117 --- /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 00000000..be8d46ed --- /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 + + +@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 00000000..9e7703a8 --- /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 00000000..750d0d40 --- /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 + + +@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 00000000..4864a489 --- /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 diff --git a/usb_hid_usages.txt b/usb_hid_usages.txt new file mode 100644 index 00000000..93ae0ed4 --- /dev/null +++ b/usb_hid_usages.txt @@ -0,0 +1,1086 @@ +# $NetBSD: usb_hid_usages,v 1.2 2004/05/16 13:22:23 lukem Exp $ +# +# USB HID usage table +# Syntax: +# - lines that do not start with a white space give the number and name of +# a usage page. +# - lines that start with a white space give the number and name of +# a usage with the last given page. +# If the number is * then the line matches all usages and the name +# is a printf formatting string that will be given the usage number. +# +1 Generic Desktop + 0x00 Undefined + 0x01 Pointer + 0x02 Mouse + 0x03 Reserved + 0x04 Joystick + 0x05 Game Pad + 0x06 Keyboard + 0x07 Keypad + 0x08 Multi-axis Controller + 0x30 X + 0x31 Y + 0x32 Z + 0x33 Rx + 0x34 Ry + 0x35 Rz + 0x36 Slider + 0x37 Dial + 0x38 Wheel + 0x39 Hat Switch + 0x3A Counted Buffer + 0x3B Byte Count + 0x3C Motion Wakeup + 0x40 Vx + 0x41 Vy + 0x42 Vz + 0x43 Vbrx + 0x44 Vbry + 0x45 Vbrx + 0x46 Vno + 0x80 System Control + 0x81 System Power Down + 0x82 System Sleep + 0x83 System Wake Up + 0x84 System Context Menu + 0x85 System Main Menu + 0x86 System App Menu + 0x87 System Menu Help + 0x88 System Menu Exit + 0x89 System Menu Select + 0x8A System Menu Right + 0x8B System Menu Left + 0x8C System Menu Up + 0x8D System Menu Down + 0x90 D-pad Up + 0x91 D-pad Down + 0x92 D-pad Right + 0x93 D-pad Left + +2 Simulation Controls + 0x00 Undefined + 0x01 Flight Simulation Device + 0x02 Automobile Simulation Device + 0x03 Tank Simulation Device + 0x04 Spaceship Simulation Device + 0x05 Submarine Simulation Device + 0x06 Sailing Simulation Device + 0x07 Motorcycle Simulation Device + 0x08 Sports Simulation Device + 0x09 Airplane Simulation Device + 0x0A Helicopter Simulation Device + 0x0B Magic Carpet Simulation Device + 0x0C Bicycle + 0x20 Flight Control Stick + 0x21 Flight Stick + 0x22 Cyclic Control + 0x23 Cyclic Trim + 0x24 Flight Yoke + 0x25 Track Control + 0x26 Driving Control + 0xB0 Aileron + 0xB1 Aileron Trim + 0xB2 Anti-Torque Control + 0xB3 Auto-pilot Enable + 0xB4 Chaff Release + 0xB5 Collective Control + 0xB6 Dive Brake + 0xB7 Electronic Counter Measures + 0xB8 Elevator + 0xB9 Elevator Trim + 0xBA Rudder + 0xBB Throttle + 0xBC Flight Communication + 0xBD Flare Release + 0xBE Landing Gear + 0xBF Toe Brake + 0xC0 Trigger + 0xC1 Weapons Arm + 0xC2 Weapons Select + 0xC3 Wing Flaps + 0xC4 Accelerator + 0xC5 Brake + 0xC6 Clutch + 0xC7 Shifter + 0xC8 Steering + 0xC9 Turret Direction + 0xCA Barrel Elevation + 0xCB Dive Plane + 0xCC Ballast + 0xCD Bicycle Crank + 0xCE Handle Bars + 0xCF Front Brake + 0xD0 Rear Brake + +3 VR Controls + 0x00 Unidentified + 0x01 Belt + 0x02 Body Suit + 0x03 Flexor + 0x04 Glove + 0x05 Head Tracker + 0x06 Head Mounted Display + 0x07 Hand Tracker + 0x08 Oculometer + 0x09 Vest + 0x0A Animatronic Device + 0x20 Stereo Enable + 0x21 Display Enable + +4 Sports Controls + 0x00 Unidentified + 0x01 Baseball Bat + 0x02 Golf Club + 0x03 Rowing Machine + 0x04 Treadmill + 0x30 Oar + 0x31 Slope + 0x32 Rate + 0x33 Stick Speed + 0x34 Stick Face Angle + 0x35 Stick Heel/Toe + 0x36 Stick Follow Through + 0x37 Stick Tempo + 0x38 Stick Type + 0x39 Stick Height + 0x50 Putter + 0x51 1 Iron + 0x52 2 Iron + 0x53 3 Iron + 0x54 4 Iron + 0x55 5 Iron + 0x56 6 Iron + 0x57 7 Iron + 0x58 8 Iron + 0x59 9 Iron + 0x5A 10 Iron + 0x5B 11 Iron + 0x5C Sand Wedge + 0x5D Loft Wedge + 0x5E Power Wedge + 0x5F 1 Wood + 0x60 3 Wood + 0x61 5 Wood + 0x62 7 Wood + 0x63 9 Wood + +5 Game Controls + 0x00 Undefined + 0x01 3D Game Controller + 0x02 Pinball Device + 0x03 Gun Device + 0x20 Point of View + 0x21 Turn Right/Left + 0x22 Pitch Right/Left + 0x23 Roll Forward/Backward + 0x24 Move Right/Left + 0x25 Move Forward/Backward + 0x26 Move Up/Down + 0x27 Lean Right/Left + 0x28 Lean Forward/Backward + 0x29 Height of POV + 0x2A Flipper + 0x2B Secondary Flipper + 0x2C Bump + 0x2D New Game + 0x2E Shoot Ball + 0x2F Player + 0x30 Gun Bolt + 0x31 Gun Clip + 0x32 Gun Selector + 0x33 Gun Single Shot + 0x34 Gun Burst + 0x35 Gun Automatic + 0x36 Gun Safety + 0x37 Gamepad Fire/Jump + 0x39 Gamepad Trigger + +7 Keyboard + 0x00 No Event + 0x01 Keyboard ErrorRollOver + 0x02 Keyboard POSTFail + 0x03 Keyboard ErrorUndefined + 0x04 Keyboard a and A + 0x05 Keyboard b and B + 0x06 Keyboard c and C + 0x07 Keyboard d and D + 0x08 Keyboard e and E + 0x09 Keyboard f and F + 0x0A Keyboard g and G + 0x0B Keyboard h and H + 0x0C Keyboard i and I + 0x0D Keyboard j and J + 0x0E Keyboard k and K + 0x0F Keyboard l and L + 0x10 Keyboard m and M + 0x11 Keyboard n and N + 0x12 Keyboard o and O + 0x13 Keyboard p and P + 0x14 Keyboard q and Q + 0x15 Keyboard r and R + 0x16 Keyboard s and S + 0x17 Keyboard t and T + 0x18 Keyboard u and U + 0x19 Keyboard v and V + 0x1A Keyboard w and W + 0x1B Keyboard x and X + 0x1C Keyboard y and Y + 0x1D Keyboard z and Z + 0x1E Keyboard 1 and ! + 0x1F Keyboard 2 and @ + 0x20 Keyboard 3 and # + 0x21 Keyboard 4 and $ + 0x22 Keyboard 5 and % + 0x23 Keyboard 6 and ^ + 0x24 Keyboard 7 and & + 0x25 Keyboard 8 and * + 0x26 Keyboard 9 and ( + 0x27 Keyboard 0 and ) + 0x28 Keyboard Return (ENTER) + 0x29 Keyboard ESCAPE + 0x2A Keyboard DELETE (Backspace) + 0x2B Keyboard Tab + 0x2C Keyboard Spacebar + 0x2D Keyboard - and (underscore) + 0x2E Keyboard = and + + 0x2F Keyboard [ and { + 0x30 Keyboard ] and } + 0x31 Keyboard \ and | + 0x32 Keyboard Non-US # and ~ + 0x33 Keyboard ; and : + 0x34 Keyboard ' and " + 0x35 Keyboard Grave Accent and Tilde + 0x36 Keyboard, and < + 0x37 Keyboard . and > + 0x38 Keyboard / and ? + 0x39 Keyboard Caps Lock + 0x3A Keyboard F1 + 0x3B Keyboard F2 + 0x3C Keyboard F3 + 0x3D Keyboard F4 + 0x3E Keyboard F5 + 0x3F Keyboard F6 + 0x40 Keyboard F7 + 0x41 Keyboard F8 + 0x42 Keyboard F9 + 0x43 Keyboard F10 + 0x44 Keyboard F11 + 0x45 Keyboard F12 + 0x46 Keyboard PrintScreen + 0x47 Keyboard Scroll Lock + 0x48 Keyboard Pause + 0x49 Keyboard Insert + 0x4A Keyboard Home + 0x4B Keyboard PageUp + 0x4C Keyboard Delete Forward + 0x4D Keyboard End + 0x4E Keyboard PageDown + 0x4F Keyboard RightArrow + 0x50 Keyboard LeftArrow + 0x51 Keyboard DownArrow + 0x52 Keyboard UpArrow + 0x53 Keypad Num Lock and Clear + 0x54 Keypad / + 0x55 Keypad * + 0x56 Keypad - + 0x57 Keypad + + 0x58 Keypad ENTER + 0x59 Keypad 1 and End + 0x5A Keypad 2 and Down Arrow + 0x5B Keypad 3 and PageDn + 0x5C Keypad 4 and Left Arrow + 0x5D Keypad 5 + 0x5E Keypad 6 and Right Arrow + 0x5F Keypad 7 and Home + 0x60 Keypad 8 and Up Arrow + 0x61 Keypad 9 and PageUp + 0x62 Keypad 0 and Insert + 0x63 Keypad . and Delete + 0x64 Keyboard Non-US \ and | + 0x65 Keyboard Application + 0x66 Keyboard Power + 0x67 Keypad = + 0x68 Keyboard F13 + 0x69 Keyboard F14 + 0x6A Keyboard F15 + 0x6B Keyboard F16 + 0x6C Keyboard F17 + 0x6D Keyboard F18 + 0x6E Keyboard F19 + 0x6F Keyboard F20 + 0x70 Keyboard F21 + 0x71 Keyboard F22 + 0x72 Keyboard F23 + 0x73 Keyboard F24 + 0x74 Keyboard Execute + 0x75 Keyboard Help + 0x76 Keyboard Menu + 0x77 Keyboard Select + 0x78 Keyboard Stop + 0x79 Keyboard Again + 0x7A Keyboard Undo + 0x7B Keyboard Cut + 0x7C Keyboard Copy + 0x7D Keyboard Paste + 0x7E Keyboard Find + 0x7F Keyboard Mute + 0x80 Keyboard Volume Up + 0x81 Keyboard Volume Down + 0x82 Keyboard Locking Caps Lock + 0x83 Keyboard Locking Num Lock + 0x84 Keyboard Locking Scroll Lock + 0x85 Keypad Comma + 0x86 Keypad Equal Sign + 0x87 Keyboard International1 + 0x88 Keyboard International2 + 0x89 Keyboard International3 + 0x8A Keyboard International4 + 0x8B Keyboard International5 + 0x8C Keyboard International6 + 0x8D Keyboard International7 + 0x8E Keyboard International8 + 0x8F Keyboard International9 + 0x90 Keyboard LANG1 + 0x91 Keyboard LANG2 + 0x92 Keyboard LANG3 + 0x93 Keyboard LANG4 + 0x94 Keyboard LANG5 + 0x95 Keyboard LANG6 + 0x96 Keyboard LANG7 + 0x97 Keyboard LANG8 + 0x98 Keyboard LANG9 + 0x99 Keyboard Alternate Erase + 0x9A Keyboard SysReq/Attention + 0x9B Keyboard Cancel + 0x9C Keyboard Clear + 0x9D Keyboard Prior + 0x9E Keyboard Return + 0x9F Keyboard Separator + 0xA0 Keyboard Out + 0xA1 Keyboard Oper + 0xA2 Keyboard Clear/Again + 0xA3 Keyboard CrSel/Props + 0xA4 Keyboard ExSel + 0xE0 Keyboard LeftControl + 0xE1 Keyboard LeftShift + 0xE2 Keyboard LeftAlt + 0xE3 Keyboard Left GUI + 0xE4 Keyboard RightControl + 0xE5 Keyboard RightShift + 0xE6 Keyboard RightAlt + 0xE7 Keyboard Right GUI + +8 LEDs + 0x00 Undefined + 0x01 Num Lock + 0x02 Caps Lock + 0x03 Scroll Lock + 0x04 Compose + 0x05 Kana + 0x06 Power + 0x07 Shift + 0x08 Do Not Disturb + 0x09 Mute + 0x0A Tone Enable + 0x0B High Cut Filter + 0x0C Low Cut Filter + 0x0D Equalizer Enable + 0x0E Sound Field On + 0x0F Surround Field On + 0x10 Repeat + 0x11 Stereo + 0x12 Sampling Rate Detect + 0x13 Spinning + 0x14 CAV + 0x15 CLV + 0x16 Recording Format Detect + 0x17 Off-Hook + 0x18 Ring + 0x19 Message Waiting + 0x1A Data Mode + 0x1B Battery Operation + 0x1C Battery OK + 0x1D Battery Low + 0x1E Speaker + 0x1F Head Set + 0x20 Hold + 0x21 Microphone + 0x22 Coverage + 0x23 Night Mode + 0x24 Send Calls + 0x25 Call Pickup + 0x26 Conference + 0x27 Stand-by + 0x28 Camera On + 0x29 Camera Off + 0x2A On-Line + 0x2B Off-Line + 0x2C Busy + 0x2D Ready + 0x2E Paper-Out + 0x2F Paper-Jam + 0x30 Remote + 0x31 Forward + 0x32 Reverse + 0x33 Stop + 0x34 Rewind + 0x35 Fast Forward + 0x36 Play + 0x37 Pause + 0x38 Record + 0x39 Error + 0x3A Usage Selected Indicator + 0x3B Usage In Use Indicator + 0x3C Usage Multi Mode Indicator + 0x3D Indicator On + 0x3E Indicator Flash + 0x3F Indicator Slow Blink + 0x40 Indicator Fast Blink + 0x41 Indicator Off + 0x42 Flash On Time + 0x43 Slow Blink On Time + 0x44 Slow Blink Off Time + 0x45 Fast Blink On Time + 0x46 Fast Blink Off Time + 0x47 Usage Indicator Color + 0x48 Red + 0x49 Green + 0x4A Amber + 0x4B Generic Indicator + 0x4C System Suspend + 0x4D External Power Connected + 0x4C-FFFF Reserved + +9 Button + 0x00 No Button Pressed + * Button %d + +10 Ordinal + 0x00 Unused + * Instance %d + +11 Telephony + 0x00 Unassigned + 0x01 Phone + 0x02 Answering Machine + 0x03 Message Controls + 0x04 Handset + 0x05 Headset + 0x06 Telephony Key Pad + 0x07 Programmable Button + 0x20 Hook Switch + 0x21 Flash + 0x22 Feature + 0x23 Hold + 0x24 Redial + 0x25 Transfer + 0x26 Drop + 0x27 Park + 0x28 Forward Calls + 0x29 Alternate Function + 0x2A Line + 0x2B Speaker Phone + 0x2C Conference + 0x2D Ring Enable + 0x2E Ring Select + 0x2F Phone Mute + 0x30 Caller ID + 0x50 Speed Dial + 0x51 Store Number + 0x52 Recall Number + 0x53 Phone Directory + 0x70 Voice Mail + 0x71 Screen Calls + 0x72 Do Not Disturb + 0x73 Message + 0x74 Answer On/Off + 0x90 Inside Dial Tone + 0x91 Outside Dial Tone + 0x92 Inside Ring Tone + 0x93 Outside Ring Tone + 0x94 Priority Ring Tone + 0x95 Inside Ringback + 0x96 Priority Ringback + 0x97 Line Busy Tone + 0x98 Reorder Tone + 0x99 Call Waiting Tone + 0x9A Confirmation Tone 1 + 0x9B Confirmation Tone 2 + 0x9C Tones Off + 0xB0 Phone Key 0 + 0xB1 Phone Key 1 + 0xB2 Phone Key 2 + 0xB3 Phone Key 3 + 0xB4 Phone Key 4 + 0xB5 Phone Key 5 + 0xB6 Phone Key 6 + 0xB7 Phone Key 7 + 0xB8 Phone Key 8 + 0xB9 Phone Key 9 + 0xBA Phone Key Star + 0xBB Phone Key Pound + 0xBC Phone Key A + 0xBD Phone Key B + 0xBE Phone Key C + 0xBF Phone Key D + +12 Consumer + 0x00 Unassigned + 0x01 Consumer Control + 0x02 Numeric Key Pad + 0x03 Programmable Buttons + 0x20 +10 + 0x21 +100 + 0x22 AM/PM + 0x30 Power + 0x31 Reset + 0x32 Sleep + 0x33 Sleep After + 0x34 Sleep Mode + 0x35 Illumination + 0x36 Function Buttons + 0x40 Menu + 0x41 Menu Pick + 0x42 Menu Up + 0x43 Menu Down + 0x44 Menu Left + 0x45 Menu Right + 0x46 Menu Escape + 0x47 Menu Value Increase + 0x48 Menu Value Decrease + 0x60 Data On Screen + 0x61 Closed Caption + 0x62 Closed Caption Select + 0x63 VCR/TV + 0x64 Broadcast Mode + 0x65 Snapshot + 0x66 Still + 0x80 Selection + 0x81 Assign Selection + 0x82 Mode Step + 0x83 Recall Last + 0x84 Enter Channel + 0x85 Order Movie + 0x86 Channel + 0x87 Media Selection + 0x88 Media Select Computer + 0x89 Media Select TV + 0x8A Media Select WWW + 0x8B Media Select DVD + 0x8C Media Select Telephone + 0x8D Media Select Program Guide + 0x8E Media Select Video Phone + 0x8F Media Select Games + 0x90 Media Select Messages + 0x91 Media Select CD + 0x92 Media Select VCR + 0x93 Media Select Tuner + 0x94 Quit + 0x95 Help + 0x96 Media Select Tape + 0x97 Media Select Cable + 0x98 Media Select Satellite + 0x99 Media Select Security + 0x9A Media Select Home + 0x9B Media Select Call + 0x9C Channel Increment + 0x9D Channel Decrement + 0x9E Media Select SAP + 0xA0 VCR Plus + 0xA1 Once + 0xA2 Daily + 0xA3 Weekly + 0xA4 Monthly + 0xB0 Play + 0xB1 Pause + 0xB2 Record + 0xB3 Fast Forward + 0xB4 Rewind + 0xB5 Scan Next Track + 0xB6 Scan Previous Track + 0xB7 Stop + 0xB8 Eject + 0xB9 Random Play + 0xBA Select DisC + 0xBB Enter Disc + 0xBC Repeat + 0xBD Tracking + 0xBE Track Normal + 0xBF Slow Tracking + 0xC0 Frame Forward + 0xC1 Frame Back + 0xC2 Mark + 0xC3 Clear Mark + 0xC4 Repeat From Mark + 0xC5 Return To Mark + 0xC6 Search Mark Forward + 0xC7 Search Mark Backwards + 0xC8 Counter Reset + 0xC9 Show Counter + 0xCA Tracking Increment + 0xCB Tracking Decrement + 0xCD Pause/Play + 0xE0 Volume + 0xE1 Balance + 0xE2 Mute + 0xE3 Bass + 0xE4 Treble + 0xE5 Bass Boost + 0xE6 Surround Mode + 0xE7 Loudness + 0xE8 MPX + 0xE9 Volume Up + 0xEA Volume Down + 0xF0 Speed Select + 0xF1 Playback Speed + 0xF2 Standard Play + 0xF3 Long Play + 0xF4 Extended Play + 0xF5 Slow + 0x100 Fan Enable + 0x101 Fan Speed + 0x102 Light + 0x103 Light Illumination Level + 0x104 Climate Control Enable + 0x105 Room Temperature + 0x106 Security Enable + 0x107 Fire Alarm + 0x108 Police Alarm + 0x150 Balance Right + 0x151 Balance Left + 0x152 Bass Increment + 0x153 Bass Decrement + 0x154 Treble Increment + 0x155 Treble Decrement + 0x160 Speaker System + 0x161 Channel Left + 0x162 Channel Right + 0x163 Channel Center + 0x164 Channel Front + 0x165 Channel Center Front + 0x166 Channel Side + 0x167 Channel Surround + 0x168 Channel Low Frequency Enhancement + 0x169 Channel Top + 0x16A Channel Unknown + 0x170 Sub-channel + 0x171 Sub-channel Increment + 0x172 Sub-channel Decrement + 0x173 Alternate Audio Increment + 0x174 Alternate Audio Decrement + 0x180 Application Launch Buttons + 0x181 AL Launch Button Configuration Tool + 0x182 AL Programmable Button Configuration + 0x183 AL Consumer Control Configuration + 0x184 AL Word Processor + 0x185 AL Text Editor + 0x186 AL Spreadsheet + 0x187 AL Graphics Editor + 0x188 AL Presentation App + 0x189 AL Database App + 0x18A AL Email Reader + 0x18B AL Newsreader + 0x18C AL Voicemail + 0x18D AL Contacts/Address Book + 0x18E AL Calendar/Schedule + 0x18F AL Task/Project Manager + 0x190 AL Log/Journal/Timecard + 0x191 AL Checkbook/Finance + 0x192 AL Calculator + 0x193 AL A/V Capture/Playback + 0x194 AL Local Machine Browser + 0x195 AL LAN/WAN Browser + 0x196 AL Internet Browser + 0x197 AL Remote Networking/ISP Connect + 0x198 AL Network Conference + 0x199 AL Network Chat + 0x19A AL Telephony/Dialer + 0x19B AL Logon + 0x19C AL Logoff + 0x19D AL Logon/Logoff + 0x19E AL Terminal Lock/Screensaver + 0x19F AL Control Panel + 0x1A0 AL Command Line Processor/Run + 0x1A1 AL Process/Task Manager + 0x1A2 AL Select Tast/Application + 0x1A3 AL Next Task/Application + 0x1A4 AL Previous Task/Application + 0x1A5 AL Preemptive Halt Task/Application + 0x1A7 AL My Documents + 0x1AB AC Spell + 0x1B6 AL My Pictures + 0x1B7 AL My Music + 0x200 Generic GUI Application Controls + 0x201 AC New + 0x202 AC Open + 0x203 AC Close + 0x204 AC Exit + 0x205 AC Maximize + 0x206 AC Minimize + 0x207 AC Save + 0x208 AC Print + 0x209 AC Properties + 0x21A AC Undo + 0x21B AC Copy + 0x21C AC Cut + 0x21D AC Paste + 0x21E AC Select All + 0x21F AC Find + 0x220 AC Find and Replace + 0x221 AC Search + 0x222 AC Go To + 0x223 AC Home + 0x224 AC Back + 0x225 AC Forward + 0x226 AC Stop + 0x227 AC Refresh + 0x228 AC Previous Link + 0x229 AC Next Link + 0x22A AC Bookmarks + 0x22B AC History + 0x22C AC Subscriptions + 0x22D AC Zoom In + 0x22E AC Zoom Out + 0x22F AC Zoom + 0x230 AC Full Screen View + 0x231 AC Normal View + 0x232 AC View Toggle + 0x233 AC Scroll Up + 0x234 AC Scroll Down + 0x235 AC Scroll + 0x236 AC Pan Left + 0x237 AC Pan Right + 0x238 AC Pan + 0x239 AC New Window + 0x23A AC Tile Horizontally + 0x23B AC Tile Vertically + 0x23C AC Format + 0x279 AC Redo + 0x289 AC Reply + 0x28B AC Fwd + 0x28C AC Send + +13 Digitizer + 0x00 Undefined + 0x01 Digitizer + 0x02 Pen + 0x03 Light Pen + 0x04 Touch Screen + 0x05 Touch Pad + 0x06 White Board + 0x07 Coordinate Measuring Machine + 0x08 3-D Digitizer + 0x09 Stereo Plotter + 0x0A Articulated Arm + 0x0B Armature + 0x0C Multiple Point Digitizer + 0x0D Free Space Wand + 0x20 Stylus + 0x21 Puck + 0x22 Finger + 0x30 Tip Pressure + 0x31 Barrel Pressure + 0x32 In Range + 0x33 Touch + 0x34 Untouch + 0x35 Tap + 0x36 Quality + 0x37 Data Valid + 0x38 Transducer Index + 0x39 Tablet Function Keys + 0x3A Program Change Keys + 0x3B Battery Strength + 0x3C Invert + 0x3D X Tilt + 0x3E Y Tilt + 0x3F Azimuth + 0x40 Altitude + 0x41 Twist + 0x42 Tip Switch + 0x43 Secondary Tip Switch + 0x44 Barrel Switch + 0x45 Eraser + 0x46 Tablet Pick + +15 Physical Interface Device + +16 Unicode + * Unicode Char u%04x + +20 Alphnumeric Display + 0x00 Undefined + 0x01 Alphanumeric Display + 0x20 Display Attributes Report + 0x21 ASCII Character Set + 0x22 Data Read Back + 0x23 Font Read Back + 0x24 Display Control Report + 0x25 Clear Display + 0x26 Display Enable + 0x27 Screen Saver Delay + 0x28 Screen Saver Enable + 0x29 Vertical Scroll + 0x2A Horizontal Scroll + 0x2B Character Report + 0x2C Display Data + 0x2D Display Status + 0x2E Stat Not Ready + 0x2F Stat Ready + 0x30 Err Not a loadable character + 0x31 Err Font data cannot be read + 0x32 Cursor Position Report + 0x33 Row + 0x34 Column + 0x35 Rows + 0x36 Columns + 0x37 Cursor Pixel Positioning + 0x38 Cursor Mode + 0x39 Cursor Enable + 0x3A Cursor Blink + 0x3B Font Report + 0x3C Font Data + 0x3D Character Width + 0x3E Character Height + 0x3F Character Spacing Horizontal + 0x40 Character Spacing Vertical + 0x41 Unicode Character Set + +128 Monitor + 0x00 Undefined + 0x01 Monitor Control + 0x02 EDID Information + 0x03 VDIF Information + 0x04 VESA Version + 0x05 On Screen Display + 0x06 Auto Size Center + 0x07 Polarity Horz Synch + 0x08 Polarity Vert Synch + 0x09 Sync Type + 0x0A Screen Position + 0x0B Horizontal Frequency + 0x0C Vertical Frequency + +129 Monitor Enumerated Values + 0x00 unassigned + * ENUM %d + +130 VESA Virtual Controls + 0x10 Brightness + 0x12 Contrast + 0x16 Video Gain Red + 0x18 Video Gain Green + 0x1A Video Gain Blue + 0x1C Focus + 0x20 Horizontal Position + 0x22 Horizontal Size + 0x24 Horizontal Pincushion + 0x26 Horizontal Pincushion Balance + 0x28 Horizontal Misconvergence + 0x2A Horizontal Linearity + 0x2C Horizontal Linearity Balance + 0x30 Vertical Position + 0x32 Vertical Size + 0x34 Vertical Pincushion + 0x36 Vertical Pincushion Balance + 0x38 Vertical Misconvergence + 0x3A Vertical Linearity + 0x3C Vertical Linearity Balance + 0x40 Parallelogram Distortion + 0x42 Trapezoidal Distortion + 0x44 Tilt + 0x46 Top Corner Distortion Control + 0x48 Top Corner Distortion Balance + 0x4A Bottom Corner Distortion Control + 0x4C Bottom Corner Distortion Balance + 0x56 MoirHorizontal + 0x58 MoirVertical + 0x5E Input Level Select + 0x60 Input Source Select + 0x62 Stereo Mode + 0x6C Video Black Level Red + 0x6E Video Black Level Green + 0x70 Video Black Level Blue + +131 VESA Command + 0x00 Undefined + 0x01 Settings + 0x02 Degauss + +132 Power Device + 0x00 Undefined + 0x01 iName + 0x02 PresentStatus + 0x03 ChangedStatus + 0x04 UPS + 0x05 PowerSupply + 0x10 BatterySystem + 0x11 BatterySystemID + 0x12 Battery + 0x13 BatteryID + 0x14 Charger + 0x15 ChargerID + 0x16 PowerConverter + 0x17 PowerConverterID + 0x18 OutletSystem + 0x19 OutletSystemID + 0x1A Input + 0x1B InputID + 0x1C Output + 0x1D OutputID + 0x1E Flow + 0x1F FlowID + 0x20 Outlet + 0x21 OutletID + 0x22 Gang + 0x23 GangID + 0x24 Sink + 0x25 SinkID + 0x30 Voltage + 0x31 Current + 0x32 Frequency + 0x33 ApparentPower + 0x34 ActivePower + 0x35 PercentLoad + 0x36 Temperature + 0x37 Humidity + 0x40 ConfigVoltage + 0x41 ConfigCurrent + 0x42 ConfigFrequency + 0x43 ConfigApparentPower + 0x44 ConfigActivePower + 0x45 ConfigPercentLoad + 0x46 ConfigTemperature + 0x47 ConfigHumidity + 0x50 SwitchOnControl + 0x51 SwitchOffControl + 0x52 ToggleControl + 0x53 LowVoltageTransfer + 0x54 HighVoltageTransfer + 0x55 DelayBeforeReboot + 0x56 DelayBeforeStartup + 0x57 DelayBeforeShutdown + 0x58 Test + 0x59 Vendorspecificcommand + 0x60 Present + 0x61 Good + 0x62 InternalFailure + 0x63 VoltageOutOfRange + 0x64 FrequencyOutOfRange + 0x65 Overload + 0x66 OverCharged + 0x67 OverTemperature + 0x68 ShutdownRequested + 0x69 ShutdownImminent + 0x6A VendorSpecificAnswerValid + 0x6B SwitchOn/Off + 0x6C Switcheble + 0x6D Used + 0x6E Boost + 0x6F Buck + 0x70 Initialized + 0x71 Tested + +133 Battery System + 0x00 Undefined + 0x01 SMBBatteryMode + 0x02 SMBBatteryStatus + 0x03 SMBAlarmWarning + 0x04 SMBChargerMode + 0x05 SMBChargerStatus + 0x06 SMBChargerSpecInfo + 0x07 SMBSelectorState + 0x08 SMBSelectorPreset + 0x09 SMBSelectorInfo + 0x10 OptionalMfgFunction1 + 0x11 OptionalMfgFunction2 + 0x12 OptionalMfgFunction3 + 0x13 OptionalMfgFunction4 + 0x14 OptionalMfgFunction5 + 0x15 ConnectionToSMBus + 0x16 OutputConnection + 0x17 ChargerConnection + 0x18 BatteryInsertion + 0x19 Usenext + 0x1A OKToUse + 0x28 ManufacturerAccess + 0x29 RemainingCapacityLimit + 0x2A RemainingTimeLimit + 0x2B AtRate + 0x2C CapacityMode + 0x2D BroadcastToCharger + 0x2E PrimaryBattery + 0x2F ChargeController + 0x40 TerminateCharge + 0x41 TermminateDischarge + 0x42 BelowRemainingCapacityLimit + 0x43 RemainingTimeLimitExpired + 0x44 Charging + 0x45 Discharging + 0x46 FullyCharged + 0x47 FullyDischarged + 0x48 ConditionningFlag + 0x49 AtRateOK + 0x4A SMBErrorCode + 0x4B NeedReplacement + 0x60 AtRateTimeToFull + 0x61 AtRateTimeToEmpty + 0x62 AverageCurrent + 0x63 Maxerror + 0x64 RelativeStateOfCharge + 0x65 AbsoluteStateOfCharge + 0x66 RemainingCapacity + 0x67 FullChargeCapacity + 0x68 RunTimeToEmpty + 0x69 AverageTimeToEmpty + 0x6A AverageTimeToFull + 0x6B CycleCount + 0x80 BattPackModelLevel + 0x81 InternalChargeController + 0x82 PrimaryBatterySupport + 0x83 DesignCapacity + 0x84 SpecificationInfo + 0x85 ManufacturerDate + 0x86 SerialNumber + 0x87 iManufacturerName + 0x88 iDevicename + 0x89 iDeviceChemistery + 0x8A iManufacturerData + 0x8B Rechargeable + 0x8C WarningCapacityLimit + 0x8D CapacityGranularity1 + 0x8E CapacityGranularity2 + 0xC0 InhibitCharge + 0xC1 EnablePolling + 0xC2 ResetToZero + 0xD0 ACPresent + 0xD1 BatteryPresent + 0xD2 PowerFail + 0xD3 AlarmInhibited + 0xD4 ThermistorUnderRange + 0xD5 ThermistorHot + 0xD6 ThermistorCold + 0xD7 ThermistorOverRange + 0xD8 VoltageOutOfRange + 0xD9 CurrentOutOfRange + 0xDA CurrentNotRegulated + 0xDB VoltageNotRegulated + 0xDC MasterMode + 0xDD ChargerBattery/HostControlled + 0xF0 ChargerSpecInfo + 0xF1 ChargerSpecRef + 0xF2 Level2 + 0xF3 Level3 + +140 Bar Code Scanner + +141 Scale Device + +144 Camera Control + +145 Arcade Device + +# Some Microsoft non-standard extensions +0xff00 Microsoft + 0xe9 Base Up + 0xea Base Down diff --git a/usb_hid_usages2plist b/usb_hid_usages2plist new file mode 100755 index 00000000..f50c5b97 --- /dev/null +++ b/usb_hid_usages2plist @@ -0,0 +1,46 @@ +#!/usr/bin/env ruby + +$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "vendor")) +$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "lib")) + +require 'pp' +require 'plist' + +usb_hid_usages = ARGV[0] + +usage_tables = {} +current_usage = 0; +current_usage_table = nil + +File.open(usb_hid_usages).each_line do |line| + next if line =~ /^\s*#/ + next if line =~ /^\s*$/ + + if (line =~ /^(\d+)\s+(.*)\s*$/) + current_usage = $1.to_i + usage_description = $2 + current_usage_table = {'usages' => {}, 'ranges' => {}} + current_usage_table['description'] = usage_description + usage_tables[current_usage] = current_usage_table + elsif (line =~ /^\s+(\S+)\s+(.*)\s*$/) + usage_page = $1 + usage_page_description = $2 + + if (usage_page =~ /^0x((?:\d|[a-fA-F])+)$/) + usage_page = $1.hex + current_usage_table['usages'][usage_page] = usage_page_description + elsif (usage_page =~ /^0x((?:\d|[a-fA-F])+)-((?:\d|[a-fA-F])+)$/) + range_start = $1.hex + range_end = $2.hex + range = "{#{range_start}, #{range_end}}"; + current_usage_table['ranges'][range] = usage_page_description + elsif (usage_page == '*') + current_usage_table['default'] = usage_page_description + else + puts "Uknown page: #{usage_page}" + end + + end +end + +puts Plist.dump(usage_tables) \ No newline at end of file diff --git a/vendor/NSXReturnThrowError/NSXReturnThrowError.h b/vendor/NSXReturnThrowError/NSXReturnThrowError.h new file mode 100644 index 00000000..b8aa11a3 --- /dev/null +++ b/vendor/NSXReturnThrowError/NSXReturnThrowError.h @@ -0,0 +1,103 @@ +/***************************************************************************//** + NSXReturnThrowError.h + Copyright (c) 2007 Jonathan 'Wolf' Rentzsch: + Some rights reserved: + + @section Overview + + NSXReturnThrowError does two things: + + 1. Eases wrapping error codes into NSError objects. + + 2. Enhances NSError by adding origin information to the error instance. + Origin information includes the actual line of code that returned + the error, as well as the file+line+function/method name. + + A big NSXReturnThrowError feature is that it deduces the correct NSError + error domain based on the wrapped code's return type+value. Bonus: it + does so without requiring ObjC++, relying on \@encode acrobatics + instead. + + NSXReturnThrowError was coded against 10.4, but should be compatible + with 10.3 as well. However that's currently untested. + + @section Usage + + NSXReturnThrowError handles both types of error handling: explicit + returning of NSError objects and raising NSExceptions. + + Use NSXReturnError() if you're returning NSError objects explicitly: + + @code + - (id)demoReturnError:(NSError**)error_ { + id result = nil; + NSError *error = nil; + + NSXReturnError(SomeCarbonFunction()); + if (!error) + NSXReturnError(someposixfunction()); + if (!error) + NSXReturnError(some_mach_function()); + if (!error) + NSXReturnError([SomeCocoaClass sharedInstance]); + + if (error_) *error_ = error; + return result; + } + @endcode + + Use NSXThrowError() if you'd prefer to raise NSException objects: + + @code + - (id)demo { + id result = nil; + + NSXThrowError(SomeCarbonFunction()); + NSXThrowError(someposixfunction()); + NSXThrowError(some_mach_function()); + NSXThrowError([SomeCocoaClass newObject]); + + return result; + } + @endcode + + The current structure of the raised NSException object is that it's a + normal NSException whose name is "NSError". The actual error object is + hung off the exception's userInfo dictionary with the key of @"error". + + @mainpage NSXReturnThrowError + @todo Add a compile-time flag for whether to stuff __FILE__+friends + info into the generated NSError or not. + + + ***************************************************************************/ + +#import + +extern NSString *NSXErrorExceptionName; +extern NSString *NULLPointerErrorDomain; +extern NSString *BOOLErrorDomain; + +void NSXMakeErrorImp(const char *objCType_, intptr_t result_, const char *file_, unsigned line_, const char *function_, const char *code_, NSError **error_); + +#define NSXMakeError(ERROR, CODE) \ + do{ \ + typeof(CODE) codeResult = (CODE); \ + NSXMakeErrorImp(@encode(typeof(CODE)), (intptr_t)codeResult, __FILE__, __LINE__, __PRETTY_FUNCTION__, #CODE, &ERROR); \ + }while(0) + +#define NSXReturnError(CODE) NSXMakeError(error, CODE) + +#define NSXRaiseError(ERROR) \ + [[NSException exceptionWithName:NSXErrorExceptionName \ + reason:[error description] \ + userInfo:[NSDictionary dictionaryWithObject:error forKey:@"error"]] raise]; + +#define NSXThrowError(CODE) \ + do{ \ + NSError *error = nil; \ + NSXReturnError(CODE); \ + if (error) { \ + NSXRaiseError(ERROR); \ + } \ + }while(0) diff --git a/vendor/NSXReturnThrowError/NSXReturnThrowError.m b/vendor/NSXReturnThrowError/NSXReturnThrowError.m new file mode 100644 index 00000000..bb1f0d7c --- /dev/null +++ b/vendor/NSXReturnThrowError/NSXReturnThrowError.m @@ -0,0 +1,106 @@ +/******************************************************************************* + NSXReturnThrowError.m + Copyright (c) 2007 Jonathan 'Wolf' Rentzsch: + Some rights reserved: + + ***************************************************************************/ + +#import "NSXReturnThrowError.h" + +NSString *NSXErrorExceptionName = @"NSXError"; +NSString *NULLPointerErrorDomain = @"NULLPointerErrorDomain"; +NSString *BOOLErrorDomain = @"BOOLErrorDomain"; + +typedef enum { + NSXErrorCodeType_Unknown, + NSXErrorCodeType_Cocoa, // "@" + NSXErrorCodeType_PosixOrMach, // "i" (-1 == posix+errno, otherwise mach) + NSXErrorCodeType_Carbon, // "s" || "l" + NSXErrorCodeType_ptr, // "r*" || "*" || "^" + NSXErrorCodeType_BOOL // "c" +} NSXErrorCodeType; + +static NSXErrorCodeType NSXErrorCodeTypeFromObjCType(const char *objCType) { + switch (objCType[0]) { + case 's': + case 'l': + return NSXErrorCodeType_Carbon; + case 'i': + return NSXErrorCodeType_PosixOrMach; + case '@': + return NSXErrorCodeType_Cocoa; + case '^': + case '*': + return NSXErrorCodeType_ptr; + case 'r': + return '*' == objCType[1] ? NSXErrorCodeType_ptr : NSXErrorCodeType_Unknown; + case 'c': + return NSXErrorCodeType_BOOL; + default: + return NSXErrorCodeType_Unknown; + } +} + +void NSXMakeErrorImp(const char *objCType_, intptr_t result_, const char *file_, unsigned line_, const char *function_, const char *code_, NSError **error_) { + NSString *errorDomain = nil; + int errorCode = (int)result_; + + switch (NSXErrorCodeTypeFromObjCType(objCType_)) { + case NSXErrorCodeType_Cocoa: + // codeResult's type is an id/NSObject* pointer. 0 == nil == failure. + if (0 == result_) { + errorDomain = @"NSCocoaErrorDomain"; // Could use NSCocoaErrorDomain symbol, but that would force us to 10.4. + errorCode = -1; + } + break; + case NSXErrorCodeType_Carbon: + // codeResult's type is OSErr (short) or OSStatus (long). 0 == noErr == success. + if (0 != result_) { + errorDomain = NSOSStatusErrorDomain; + } + break; + case NSXErrorCodeType_PosixOrMach: + // codeResult's type is int, which is used for both posix error codes and mach_error_t/kern_return_t. + // 0 means success for both, and we can differentiate posix error codes since they're always -1 (the + // actual posix code stored in errno). + if (0 != result_) { + if (-1 == result_) { + // Posix error code. + errorDomain = NSPOSIXErrorDomain; + errorCode = errno; + } else { + // Mach error code. + errorDomain = NSMachErrorDomain; + } + } + break; + case NSXErrorCodeType_ptr: + // codeResult's type is some sort of non-id/non-NSObject* pointer. 0 == NULL == failure. + if (0 == result_) { + errorDomain = NULLPointerErrorDomain; + errorCode = -1; + } + break; + case NSXErrorCodeType_BOOL: + // codeResult's type is a BOOL. 0 == NO == failure. + if (0 == result_) { + errorDomain = BOOLErrorDomain; + errorCode = -1; + } + break; + default: + NSCAssert1(NO, @"NSXErrorCodeType_Unknown: \"%s\"", objCType_); + break; + } + + if (errorDomain && error_) { + *error_ = [NSError errorWithDomain:errorDomain + code:errorCode + userInfo:[NSDictionary dictionaryWithObjectsAndKeys: + [NSString stringWithUTF8String:file_], @"reportingFile", + [NSNumber numberWithInt:line_], @"reportingLine", + [NSString stringWithUTF8String:function_], @"reportingMethod", + [NSString stringWithUTF8String:code_], @"origin", + nil]]; + } +} diff --git a/versions.xcconfig b/versions.xcconfig new file mode 100644 index 00000000..1a5dc2ff --- /dev/null +++ b/versions.xcconfig @@ -0,0 +1,2 @@ +CURRENT_MARKETING_VERSION = 1.1.1 +CURRENT_PROJECT_VERSION = 1010.9.0