├── .gitignore ├── LICENSE ├── PTHotKeyTest.xcodeproj └── project.pbxproj ├── PTHotKeyTest ├── KSAppDelegate.h ├── KSAppDelegate.m ├── PTHotKey.h ├── PTHotKey.m ├── PTHotKeyCenter.h ├── PTHotKeyCenter.m ├── PTHotKeyTest-Info.plist ├── PTHotKeyTest-Prefix.pch ├── PTHotKeyTest.entitlements ├── PTKeyBroadcaster.h ├── PTKeyBroadcaster.m ├── PTKeyCodes.plist ├── PTKeyCombo.h ├── PTKeyCombo.m ├── PTKeyComboPanel.h ├── PTKeyComboPanel.m ├── PTKeyComboPanel.xib ├── en.lproj │ ├── Credits.rtf │ ├── InfoPlist.strings │ └── MainMenu.xib └── main.m └── readme.md /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | # Xcode 3 | build/* 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | *.xcworkspace 13 | !default.xcworkspace 14 | xcuserdata 15 | profile 16 | *.moved-aside 17 | DerivedData -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2019 Keith Smiley (http://keith.so) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the 'Software'), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software is furnished to do so, 8 | subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 15 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 16 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 17 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 18 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 19 | -------------------------------------------------------------------------------- /PTHotKeyTest.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | C280FB6A1586176E009E412F /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C280FB691586176E009E412F /* Cocoa.framework */; }; 11 | C280FB741586176E009E412F /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = C280FB721586176E009E412F /* InfoPlist.strings */; }; 12 | C280FB761586176E009E412F /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = C280FB751586176E009E412F /* main.m */; }; 13 | C280FB7A1586176E009E412F /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = C280FB781586176E009E412F /* Credits.rtf */; }; 14 | C280FB7D1586176E009E412F /* KSAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = C280FB7C1586176E009E412F /* KSAppDelegate.m */; }; 15 | C280FB801586176F009E412F /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = C280FB7E1586176F009E412F /* MainMenu.xib */; }; 16 | C280FB911586177C009E412F /* PTHotKey.m in Sources */ = {isa = PBXBuildFile; fileRef = C280FB871586177C009E412F /* PTHotKey.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 17 | C280FB921586177C009E412F /* PTHotKeyCenter.m in Sources */ = {isa = PBXBuildFile; fileRef = C280FB891586177C009E412F /* PTHotKeyCenter.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 18 | C280FB931586177C009E412F /* PTKeyBroadcaster.m in Sources */ = {isa = PBXBuildFile; fileRef = C280FB8B1586177C009E412F /* PTKeyBroadcaster.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 19 | C280FB941586177C009E412F /* PTKeyCodes.plist in Resources */ = {isa = PBXBuildFile; fileRef = C280FB8C1586177C009E412F /* PTKeyCodes.plist */; }; 20 | C280FB951586177C009E412F /* PTKeyCombo.m in Sources */ = {isa = PBXBuildFile; fileRef = C280FB8E1586177C009E412F /* PTKeyCombo.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 21 | C280FB961586177C009E412F /* PTKeyComboPanel.m in Sources */ = {isa = PBXBuildFile; fileRef = C280FB901586177C009E412F /* PTKeyComboPanel.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 22 | C280FB981586193A009E412F /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C280FB971586193A009E412F /* Carbon.framework */; }; 23 | C280FB9B15861FFF009E412F /* PTKeyComboPanel.xib in Resources */ = {isa = PBXBuildFile; fileRef = C280FB9A15861FFF009E412F /* PTKeyComboPanel.xib */; }; 24 | /* End PBXBuildFile section */ 25 | 26 | /* Begin PBXFileReference section */ 27 | C280FB651586176E009E412F /* PTHotKeyTest.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = PTHotKeyTest.app; sourceTree = BUILT_PRODUCTS_DIR; }; 28 | C280FB691586176E009E412F /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; 29 | C280FB6C1586176E009E412F /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; }; 30 | C280FB6D1586176E009E412F /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; }; 31 | C280FB6E1586176E009E412F /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 32 | C280FB711586176E009E412F /* PTHotKeyTest-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "PTHotKeyTest-Info.plist"; sourceTree = ""; }; 33 | C280FB731586176E009E412F /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 34 | C280FB751586176E009E412F /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 35 | C280FB771586176E009E412F /* PTHotKeyTest-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "PTHotKeyTest-Prefix.pch"; sourceTree = ""; }; 36 | C280FB791586176E009E412F /* en */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; name = en; path = en.lproj/Credits.rtf; sourceTree = ""; }; 37 | C280FB7B1586176E009E412F /* KSAppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KSAppDelegate.h; sourceTree = ""; }; 38 | C280FB7C1586176E009E412F /* KSAppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KSAppDelegate.m; sourceTree = ""; }; 39 | C280FB7F1586176F009E412F /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/MainMenu.xib; sourceTree = ""; }; 40 | C280FB861586177C009E412F /* PTHotKey.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PTHotKey.h; sourceTree = ""; }; 41 | C280FB871586177C009E412F /* PTHotKey.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PTHotKey.m; sourceTree = ""; }; 42 | C280FB881586177C009E412F /* PTHotKeyCenter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PTHotKeyCenter.h; sourceTree = ""; }; 43 | C280FB891586177C009E412F /* PTHotKeyCenter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PTHotKeyCenter.m; sourceTree = ""; }; 44 | C280FB8A1586177C009E412F /* PTKeyBroadcaster.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PTKeyBroadcaster.h; sourceTree = ""; }; 45 | C280FB8B1586177C009E412F /* PTKeyBroadcaster.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PTKeyBroadcaster.m; sourceTree = ""; }; 46 | C280FB8C1586177C009E412F /* PTKeyCodes.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = PTKeyCodes.plist; sourceTree = ""; }; 47 | C280FB8D1586177C009E412F /* PTKeyCombo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PTKeyCombo.h; sourceTree = ""; }; 48 | C280FB8E1586177C009E412F /* PTKeyCombo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PTKeyCombo.m; sourceTree = ""; }; 49 | C280FB8F1586177C009E412F /* PTKeyComboPanel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PTKeyComboPanel.h; sourceTree = ""; }; 50 | C280FB901586177C009E412F /* PTKeyComboPanel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PTKeyComboPanel.m; sourceTree = ""; }; 51 | C280FB971586193A009E412F /* Carbon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = System/Library/Frameworks/Carbon.framework; sourceTree = SDKROOT; }; 52 | C280FB9A15861FFF009E412F /* PTKeyComboPanel.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = PTKeyComboPanel.xib; sourceTree = ""; }; 53 | C280FBA115863802009E412F /* PTHotKeyTest.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = PTHotKeyTest.entitlements; sourceTree = ""; }; 54 | /* End PBXFileReference section */ 55 | 56 | /* Begin PBXFrameworksBuildPhase section */ 57 | C280FB621586176E009E412F /* Frameworks */ = { 58 | isa = PBXFrameworksBuildPhase; 59 | buildActionMask = 2147483647; 60 | files = ( 61 | C280FB981586193A009E412F /* Carbon.framework in Frameworks */, 62 | C280FB6A1586176E009E412F /* Cocoa.framework in Frameworks */, 63 | ); 64 | runOnlyForDeploymentPostprocessing = 0; 65 | }; 66 | /* End PBXFrameworksBuildPhase section */ 67 | 68 | /* Begin PBXGroup section */ 69 | C280FB5A1586176E009E412F = { 70 | isa = PBXGroup; 71 | children = ( 72 | C280FB6F1586176E009E412F /* PTHotKeyTest */, 73 | C280FB681586176E009E412F /* Frameworks */, 74 | C280FB661586176E009E412F /* Products */, 75 | ); 76 | sourceTree = ""; 77 | }; 78 | C280FB661586176E009E412F /* Products */ = { 79 | isa = PBXGroup; 80 | children = ( 81 | C280FB651586176E009E412F /* PTHotKeyTest.app */, 82 | ); 83 | name = Products; 84 | sourceTree = ""; 85 | }; 86 | C280FB681586176E009E412F /* Frameworks */ = { 87 | isa = PBXGroup; 88 | children = ( 89 | C280FB691586176E009E412F /* Cocoa.framework */, 90 | C280FB971586193A009E412F /* Carbon.framework */, 91 | C280FB6B1586176E009E412F /* Other Frameworks */, 92 | ); 93 | name = Frameworks; 94 | sourceTree = ""; 95 | }; 96 | C280FB6B1586176E009E412F /* Other Frameworks */ = { 97 | isa = PBXGroup; 98 | children = ( 99 | C280FB6C1586176E009E412F /* AppKit.framework */, 100 | C280FB6D1586176E009E412F /* CoreData.framework */, 101 | C280FB6E1586176E009E412F /* Foundation.framework */, 102 | ); 103 | name = "Other Frameworks"; 104 | sourceTree = ""; 105 | }; 106 | C280FB6F1586176E009E412F /* PTHotKeyTest */ = { 107 | isa = PBXGroup; 108 | children = ( 109 | C280FBA115863802009E412F /* PTHotKeyTest.entitlements */, 110 | C280FB7B1586176E009E412F /* KSAppDelegate.h */, 111 | C280FB7C1586176E009E412F /* KSAppDelegate.m */, 112 | C280FB7E1586176F009E412F /* MainMenu.xib */, 113 | C280FB9A15861FFF009E412F /* PTKeyComboPanel.xib */, 114 | C280FB9915861D39009E412F /* PTHotKey */, 115 | C280FB701586176E009E412F /* Supporting Files */, 116 | ); 117 | path = PTHotKeyTest; 118 | sourceTree = ""; 119 | }; 120 | C280FB701586176E009E412F /* Supporting Files */ = { 121 | isa = PBXGroup; 122 | children = ( 123 | C280FB711586176E009E412F /* PTHotKeyTest-Info.plist */, 124 | C280FB721586176E009E412F /* InfoPlist.strings */, 125 | C280FB751586176E009E412F /* main.m */, 126 | C280FB771586176E009E412F /* PTHotKeyTest-Prefix.pch */, 127 | C280FB781586176E009E412F /* Credits.rtf */, 128 | ); 129 | name = "Supporting Files"; 130 | sourceTree = ""; 131 | }; 132 | C280FB9915861D39009E412F /* PTHotKey */ = { 133 | isa = PBXGroup; 134 | children = ( 135 | C280FB861586177C009E412F /* PTHotKey.h */, 136 | C280FB871586177C009E412F /* PTHotKey.m */, 137 | C280FB881586177C009E412F /* PTHotKeyCenter.h */, 138 | C280FB891586177C009E412F /* PTHotKeyCenter.m */, 139 | C280FB8A1586177C009E412F /* PTKeyBroadcaster.h */, 140 | C280FB8B1586177C009E412F /* PTKeyBroadcaster.m */, 141 | C280FB8C1586177C009E412F /* PTKeyCodes.plist */, 142 | C280FB8D1586177C009E412F /* PTKeyCombo.h */, 143 | C280FB8E1586177C009E412F /* PTKeyCombo.m */, 144 | C280FB8F1586177C009E412F /* PTKeyComboPanel.h */, 145 | C280FB901586177C009E412F /* PTKeyComboPanel.m */, 146 | ); 147 | name = PTHotKey; 148 | sourceTree = ""; 149 | }; 150 | /* End PBXGroup section */ 151 | 152 | /* Begin PBXNativeTarget section */ 153 | C280FB641586176E009E412F /* PTHotKeyTest */ = { 154 | isa = PBXNativeTarget; 155 | buildConfigurationList = C280FB831586176F009E412F /* Build configuration list for PBXNativeTarget "PTHotKeyTest" */; 156 | buildPhases = ( 157 | C280FB611586176E009E412F /* Sources */, 158 | C280FB621586176E009E412F /* Frameworks */, 159 | C280FB631586176E009E412F /* Resources */, 160 | ); 161 | buildRules = ( 162 | ); 163 | dependencies = ( 164 | ); 165 | name = PTHotKeyTest; 166 | productName = PTHotKeyTest; 167 | productReference = C280FB651586176E009E412F /* PTHotKeyTest.app */; 168 | productType = "com.apple.product-type.application"; 169 | }; 170 | /* End PBXNativeTarget section */ 171 | 172 | /* Begin PBXProject section */ 173 | C280FB5C1586176E009E412F /* Project object */ = { 174 | isa = PBXProject; 175 | attributes = { 176 | CLASSPREFIX = KS; 177 | LastUpgradeCheck = 0430; 178 | }; 179 | buildConfigurationList = C280FB5F1586176E009E412F /* Build configuration list for PBXProject "PTHotKeyTest" */; 180 | compatibilityVersion = "Xcode 3.2"; 181 | developmentRegion = English; 182 | hasScannedForEncodings = 0; 183 | knownRegions = ( 184 | en, 185 | ); 186 | mainGroup = C280FB5A1586176E009E412F; 187 | productRefGroup = C280FB661586176E009E412F /* Products */; 188 | projectDirPath = ""; 189 | projectRoot = ""; 190 | targets = ( 191 | C280FB641586176E009E412F /* PTHotKeyTest */, 192 | ); 193 | }; 194 | /* End PBXProject section */ 195 | 196 | /* Begin PBXResourcesBuildPhase section */ 197 | C280FB631586176E009E412F /* Resources */ = { 198 | isa = PBXResourcesBuildPhase; 199 | buildActionMask = 2147483647; 200 | files = ( 201 | C280FB741586176E009E412F /* InfoPlist.strings in Resources */, 202 | C280FB7A1586176E009E412F /* Credits.rtf in Resources */, 203 | C280FB801586176F009E412F /* MainMenu.xib in Resources */, 204 | C280FB941586177C009E412F /* PTKeyCodes.plist in Resources */, 205 | C280FB9B15861FFF009E412F /* PTKeyComboPanel.xib in Resources */, 206 | ); 207 | runOnlyForDeploymentPostprocessing = 0; 208 | }; 209 | /* End PBXResourcesBuildPhase section */ 210 | 211 | /* Begin PBXSourcesBuildPhase section */ 212 | C280FB611586176E009E412F /* Sources */ = { 213 | isa = PBXSourcesBuildPhase; 214 | buildActionMask = 2147483647; 215 | files = ( 216 | C280FB761586176E009E412F /* main.m in Sources */, 217 | C280FB7D1586176E009E412F /* KSAppDelegate.m in Sources */, 218 | C280FB911586177C009E412F /* PTHotKey.m in Sources */, 219 | C280FB921586177C009E412F /* PTHotKeyCenter.m in Sources */, 220 | C280FB931586177C009E412F /* PTKeyBroadcaster.m in Sources */, 221 | C280FB951586177C009E412F /* PTKeyCombo.m in Sources */, 222 | C280FB961586177C009E412F /* PTKeyComboPanel.m in Sources */, 223 | ); 224 | runOnlyForDeploymentPostprocessing = 0; 225 | }; 226 | /* End PBXSourcesBuildPhase section */ 227 | 228 | /* Begin PBXVariantGroup section */ 229 | C280FB721586176E009E412F /* InfoPlist.strings */ = { 230 | isa = PBXVariantGroup; 231 | children = ( 232 | C280FB731586176E009E412F /* en */, 233 | ); 234 | name = InfoPlist.strings; 235 | sourceTree = ""; 236 | }; 237 | C280FB781586176E009E412F /* Credits.rtf */ = { 238 | isa = PBXVariantGroup; 239 | children = ( 240 | C280FB791586176E009E412F /* en */, 241 | ); 242 | name = Credits.rtf; 243 | sourceTree = ""; 244 | }; 245 | C280FB7E1586176F009E412F /* MainMenu.xib */ = { 246 | isa = PBXVariantGroup; 247 | children = ( 248 | C280FB7F1586176F009E412F /* en */, 249 | ); 250 | name = MainMenu.xib; 251 | sourceTree = ""; 252 | }; 253 | /* End PBXVariantGroup section */ 254 | 255 | /* Begin XCBuildConfiguration section */ 256 | C280FB811586176F009E412F /* Debug */ = { 257 | isa = XCBuildConfiguration; 258 | buildSettings = { 259 | ALWAYS_SEARCH_USER_PATHS = NO; 260 | ARCHS = "$(ARCHS_STANDARD_64_BIT)"; 261 | CLANG_ENABLE_OBJC_ARC = YES; 262 | COPY_PHASE_STRIP = NO; 263 | GCC_C_LANGUAGE_STANDARD = gnu99; 264 | GCC_DYNAMIC_NO_PIC = NO; 265 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 266 | GCC_OPTIMIZATION_LEVEL = 0; 267 | GCC_PREPROCESSOR_DEFINITIONS = ( 268 | "DEBUG=1", 269 | "$(inherited)", 270 | ); 271 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 272 | GCC_VERSION = com.apple.compilers.llvm.clang.1_0; 273 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 274 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 275 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 276 | GCC_WARN_UNUSED_VARIABLE = YES; 277 | MACOSX_DEPLOYMENT_TARGET = 10.7; 278 | ONLY_ACTIVE_ARCH = YES; 279 | OTHER_LDFLAGS = ""; 280 | SDKROOT = macosx; 281 | }; 282 | name = Debug; 283 | }; 284 | C280FB821586176F009E412F /* Release */ = { 285 | isa = XCBuildConfiguration; 286 | buildSettings = { 287 | ALWAYS_SEARCH_USER_PATHS = NO; 288 | ARCHS = "$(ARCHS_STANDARD_64_BIT)"; 289 | CLANG_ENABLE_OBJC_ARC = YES; 290 | COPY_PHASE_STRIP = YES; 291 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 292 | GCC_C_LANGUAGE_STANDARD = gnu99; 293 | GCC_ENABLE_OBJC_EXCEPTIONS = YES; 294 | GCC_VERSION = com.apple.compilers.llvm.clang.1_0; 295 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 296 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 297 | GCC_WARN_UNINITIALIZED_AUTOS = YES; 298 | GCC_WARN_UNUSED_VARIABLE = YES; 299 | MACOSX_DEPLOYMENT_TARGET = 10.7; 300 | OTHER_LDFLAGS = ""; 301 | SDKROOT = macosx; 302 | }; 303 | name = Release; 304 | }; 305 | C280FB841586176F009E412F /* Debug */ = { 306 | isa = XCBuildConfiguration; 307 | buildSettings = { 308 | CODE_SIGN_ENTITLEMENTS = PTHotKeyTest/PTHotKeyTest.entitlements; 309 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 310 | GCC_PREFIX_HEADER = "PTHotKeyTest/PTHotKeyTest-Prefix.pch"; 311 | INFOPLIST_FILE = "PTHotKeyTest/PTHotKeyTest-Info.plist"; 312 | OTHER_LDFLAGS = "-all_load"; 313 | PRODUCT_NAME = "$(TARGET_NAME)"; 314 | WRAPPER_EXTENSION = app; 315 | }; 316 | name = Debug; 317 | }; 318 | C280FB851586176F009E412F /* Release */ = { 319 | isa = XCBuildConfiguration; 320 | buildSettings = { 321 | CODE_SIGN_ENTITLEMENTS = PTHotKeyTest/PTHotKeyTest.entitlements; 322 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 323 | GCC_PREFIX_HEADER = "PTHotKeyTest/PTHotKeyTest-Prefix.pch"; 324 | INFOPLIST_FILE = "PTHotKeyTest/PTHotKeyTest-Info.plist"; 325 | OTHER_LDFLAGS = "-all_load"; 326 | PRODUCT_NAME = "$(TARGET_NAME)"; 327 | WRAPPER_EXTENSION = app; 328 | }; 329 | name = Release; 330 | }; 331 | /* End XCBuildConfiguration section */ 332 | 333 | /* Begin XCConfigurationList section */ 334 | C280FB5F1586176E009E412F /* Build configuration list for PBXProject "PTHotKeyTest" */ = { 335 | isa = XCConfigurationList; 336 | buildConfigurations = ( 337 | C280FB811586176F009E412F /* Debug */, 338 | C280FB821586176F009E412F /* Release */, 339 | ); 340 | defaultConfigurationIsVisible = 0; 341 | defaultConfigurationName = Release; 342 | }; 343 | C280FB831586176F009E412F /* Build configuration list for PBXNativeTarget "PTHotKeyTest" */ = { 344 | isa = XCConfigurationList; 345 | buildConfigurations = ( 346 | C280FB841586176F009E412F /* Debug */, 347 | C280FB851586176F009E412F /* Release */, 348 | ); 349 | defaultConfigurationIsVisible = 0; 350 | defaultConfigurationName = Release; 351 | }; 352 | /* End XCConfigurationList section */ 353 | }; 354 | rootObject = C280FB5C1586176E009E412F /* Project object */; 355 | } 356 | -------------------------------------------------------------------------------- /PTHotKeyTest/KSAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // KSAppDelegate.h 3 | // PTHotKeyTest 4 | // 5 | // Created by Keith Smiley on 6/11/12. 6 | // Copyright (c) 2012 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "PTKeyComboPanel.h" 11 | #import "PTKeyCombo.h" 12 | #import "PTHotKeyCenter.h" 13 | #import "PTHotKey.h" 14 | 15 | //@class PTKeyCombo; // Not sure why these were used. 16 | //@class PTHotKey; 17 | 18 | @interface KSAppDelegate : NSObject { 19 | IBOutlet NSWindow *hotkey; 20 | IBOutlet NSTextField *appShortcutField; 21 | PTHotKey *appActivationHotKey; 22 | PTKeyCombo *appActivationKeyCombo; 23 | } 24 | 25 | @property (assign) IBOutlet NSWindow *window; 26 | 27 | - (IBAction)setAppShortcut:(id)sender; 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /PTHotKeyTest/KSAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // KSAppDelegate.m 3 | // PTHotKeyTest 4 | // 5 | // Created by Keith Smiley on 6/11/12. 6 | // Copyright (c) 2012 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import "KSAppDelegate.h" 10 | 11 | 12 | @implementation KSAppDelegate 13 | 14 | @synthesize window = _window; 15 | 16 | NSString *HotKeyAppToFrontName = @"application to foreground"; 17 | static NSString *AppActivationKeyCodeKey = @"AppActivationKeyCode"; 18 | static NSString *AppActivationModifiersKey = @"AppActivationModifiers"; 19 | 20 | - (void)applicationDidFinishLaunching:(NSNotification *)aNotification 21 | { 22 | [self registerAppActivationKeystrokeWithTarget:self selector:@selector(toggle:)]; 23 | [appShortcutField setStringValue:[[self appActivationKeyCombo] description]]; 24 | } 25 | 26 | - (BOOL)applicationShouldHandleReopen:(NSApplication *)theApplication hasVisibleWindows:(BOOL)flag { 27 | [NSApp activateIgnoringOtherApps:YES]; 28 | [_window makeKeyAndOrderFront:nil]; 29 | return YES; 30 | } 31 | 32 | - (IBAction)setAppShortcut:(id)sender { 33 | [[PTKeyComboPanel sharedPanel] showSheetForHotkey:[self appActivationHotKey] forWindow:[NSApp mainWindow] modalDelegate:self]; // Change [NSApp mainWindow] if you want to be more specific 34 | } 35 | 36 | - (void)keyComboPanelEnded:(PTKeyComboPanel*)panel { 37 | PTKeyCombo *oldKeyCombo = [self appActivationKeyCombo]; 38 | [self setAppActivationKeyCombo:[panel keyCombo] sender:self]; 39 | 40 | [appShortcutField setStringValue:[[self appActivationKeyCombo] description]]; 41 | 42 | if (![self registerAppActivationKeystrokeWithTarget:[NSApp delegate] selector:@selector(toggle:)]) { 43 | [self setAppActivationKeyCombo:oldKeyCombo sender:self]; 44 | NSLog(@"reverting to old (hopefully working key combo"); 45 | } 46 | 47 | } 48 | 49 | - (IBAction)toggle:(id)sender { 50 | if ([_window isKeyWindow]) { 51 | [_window close]; 52 | } else { 53 | [NSApp activateIgnoringOtherApps:YES]; 54 | [_window makeKeyAndOrderFront:nil]; 55 | } 56 | } 57 | 58 | - (void)setAppActivationKeyCombo:(PTKeyCombo*)aCombo sender:(id)sender { 59 | if (aCombo) { 60 | appActivationKeyCombo = nil; 61 | appActivationKeyCombo = aCombo; 62 | 63 | [[self appActivationHotKey] setKeyCombo:appActivationKeyCombo]; 64 | 65 | [[NSUserDefaults standardUserDefaults] setInteger:[aCombo keyCode] forKey:AppActivationKeyCodeKey]; 66 | [[NSUserDefaults standardUserDefaults] setInteger:[aCombo modifiers] forKey:AppActivationModifiersKey]; 67 | } 68 | } 69 | 70 | - (PTHotKey*)appActivationHotKey { 71 | if (!appActivationHotKey) { 72 | appActivationHotKey = [[PTHotKey alloc] init]; 73 | [appActivationHotKey setName:HotKeyAppToFrontName]; 74 | [appActivationHotKey setKeyCombo:[self appActivationKeyCombo]]; 75 | } 76 | 77 | return appActivationHotKey; 78 | } 79 | 80 | - (PTKeyCombo*)appActivationKeyCombo { 81 | NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; 82 | if (!appActivationKeyCombo) { 83 | appActivationKeyCombo = [[PTKeyCombo alloc] initWithKeyCode:[[defaults objectForKey:AppActivationKeyCodeKey] intValue] 84 | modifiers:[[defaults objectForKey:AppActivationModifiersKey] intValue]]; 85 | } 86 | return appActivationKeyCombo; 87 | } 88 | 89 | - (BOOL)registerAppActivationKeystrokeWithTarget:(id)target selector:(SEL)selector { 90 | PTHotKey *hotKey = [self appActivationHotKey]; 91 | 92 | [hotKey setTarget:target]; 93 | [hotKey setAction:selector]; 94 | 95 | [[PTHotKeyCenter sharedCenter] unregisterHotKeyForName:HotKeyAppToFrontName]; 96 | 97 | return [[PTHotKeyCenter sharedCenter] registerHotKey:hotKey]; 98 | } 99 | 100 | @end 101 | -------------------------------------------------------------------------------- /PTHotKeyTest/PTHotKey.h: -------------------------------------------------------------------------------- 1 | // 2 | // PTHotKey.h 3 | // Protein 4 | // 5 | // Created by Quentin Carnicelli on Sat Aug 02 2003. 6 | // Copyright (c) 2003 Quentin D. Carnicelli. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | #import "PTKeyCombo.h" 12 | 13 | @interface PTHotKey : NSObject { 14 | NSString* mName; 15 | PTKeyCombo* mKeyCombo; 16 | id mTarget; 17 | SEL mAction; 18 | EventHotKeyRef carbonHotKey; 19 | } 20 | 21 | - (id)init; 22 | 23 | - (void)setName: (NSString*)name; 24 | - (NSString*)name; 25 | 26 | - (EventHotKeyRef)carbonHotKey; 27 | - (void)setCarbonHotKey:(EventHotKeyRef)hotKey; 28 | 29 | - (void)setKeyCombo: (PTKeyCombo*)combo; 30 | - (PTKeyCombo*)keyCombo; 31 | 32 | - (void)setTarget: (id)target; 33 | - (id)target; 34 | - (void)setAction: (SEL)action; 35 | - (SEL)action; 36 | 37 | - (void)invoke; 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /PTHotKeyTest/PTHotKey.m: -------------------------------------------------------------------------------- 1 | // 2 | // PTHotKey.m 3 | // Protein 4 | // 5 | // Created by Quentin Carnicelli on Sat Aug 02 2003. 6 | // Copyright (c) 2003 Quentin D. Carnicelli. All rights reserved. 7 | // 8 | 9 | #import "PTHotKey.h" 10 | 11 | #import "PTHotKeyCenter.h" 12 | #import "PTKeyCombo.h" 13 | 14 | @implementation PTHotKey 15 | 16 | - (id)init 17 | { 18 | self = [super init]; 19 | 20 | if( self ) 21 | { 22 | [self setKeyCombo: [PTKeyCombo clearKeyCombo]]; 23 | } 24 | 25 | return self; 26 | } 27 | 28 | - (void)dealloc 29 | { 30 | [mName release]; 31 | [mKeyCombo release]; 32 | 33 | [super dealloc]; 34 | } 35 | 36 | - (NSString*)description 37 | { 38 | return [NSString stringWithFormat: @"<%@: %@>", NSStringFromClass( [self class] ), [self keyCombo]]; 39 | } 40 | 41 | #pragma mark - 42 | 43 | - (EventHotKeyRef)carbonHotKey { 44 | return carbonHotKey; 45 | } 46 | 47 | - (void)setCarbonHotKey:(EventHotKeyRef)hotKey { 48 | carbonHotKey = hotKey; 49 | } 50 | 51 | - (void)setKeyCombo: (PTKeyCombo*)combo 52 | { 53 | [combo retain]; 54 | [mKeyCombo release]; 55 | mKeyCombo = combo; 56 | } 57 | 58 | - (PTKeyCombo*)keyCombo 59 | { 60 | return mKeyCombo; 61 | } 62 | 63 | - (void)setName: (NSString*)name 64 | { 65 | [name retain]; 66 | [mName release]; 67 | mName = name; 68 | } 69 | 70 | - (NSString*)name 71 | { 72 | return mName; 73 | } 74 | 75 | - (void)setTarget: (id)target 76 | { 77 | mTarget = target; 78 | } 79 | 80 | - (id)target 81 | { 82 | return mTarget; 83 | } 84 | 85 | - (void)setAction: (SEL)action 86 | { 87 | mAction = action; 88 | } 89 | 90 | - (SEL)action 91 | { 92 | return mAction; 93 | } 94 | 95 | - (void)invoke 96 | { 97 | [mTarget performSelector: mAction withObject: self]; 98 | } 99 | 100 | @end 101 | -------------------------------------------------------------------------------- /PTHotKeyTest/PTHotKeyCenter.h: -------------------------------------------------------------------------------- 1 | // 2 | // PTHotKeyCenter.h 3 | // Protein 4 | // 5 | // Created by Quentin Carnicelli on Sat Aug 02 2003. 6 | // Copyright (c) 2003 Quentin D. Carnicelli. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class PTHotKey; 12 | 13 | @interface PTHotKeyCenter : NSObject 14 | { 15 | NSMutableDictionary* mHotKeys; //Keys are NSValue of EventHotKeyRef 16 | NSMutableDictionary* mHotKeyMap; 17 | u_int32_t mNextKeyID; 18 | BOOL mEventHandlerInstalled; 19 | } 20 | 21 | + (id)sharedCenter; 22 | 23 | //- (void) enterHotKeyWithName:(NSString *)name enable:(BOOL)ena; 24 | - (BOOL)registerHotKey: (PTHotKey*)hotKey; 25 | - (void)unregisterHotKey: (PTHotKey*)hotKey; 26 | - (void) unregisterHotKeyForName:(NSString *)name; 27 | - (void) unregisterAllHotKeys; 28 | - (void) setHotKeyRegistrationForName:(NSString *)name enable:(BOOL)ena; 29 | - (PTHotKey *) hotKeyForName:(NSString *)name; 30 | - (void) updateHotKey:(PTHotKey *)hk; 31 | 32 | - (NSArray*)allHotKeys; 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /PTHotKeyTest/PTHotKeyCenter.m: -------------------------------------------------------------------------------- 1 | // 2 | // PTHotKeyCenter.m 3 | // Protein 4 | // 5 | // Created by Quentin Carnicelli on Sat Aug 02 2003. 6 | // Copyright (c) 2003 Quentin D. Carnicelli. All rights reserved. 7 | // 8 | 9 | #import "PTHotKeyCenter.h" 10 | #import "PTHotKey.h" 11 | #import "PTKeyCombo.h" 12 | #import 13 | 14 | @interface PTHotKeyCenter (Private) 15 | - (void)_updateEventHandler; 16 | - (void)_hotKeyDown: (PTHotKey*)hotKey; 17 | - (void)_hotKeyUp: (PTHotKey*)hotKey; 18 | static OSStatus hotKeyEventHandler(EventHandlerCallRef inHandlerRef, EventRef inEvent, void* refCon ); 19 | @end 20 | 21 | @implementation PTHotKeyCenter 22 | 23 | static id _sharedHotKeyCenter = nil; 24 | 25 | + (id)sharedCenter 26 | { 27 | if( _sharedHotKeyCenter == nil ) 28 | { 29 | _sharedHotKeyCenter = [[self alloc] init]; 30 | } 31 | 32 | return _sharedHotKeyCenter; 33 | } 34 | 35 | - (id)init 36 | { 37 | self = [super init]; 38 | 39 | if( self ) 40 | { 41 | mHotKeys = [[NSMutableDictionary alloc] init]; 42 | mHotKeyMap = [[NSMutableDictionary alloc] init]; 43 | mNextKeyID = 1; 44 | } 45 | 46 | return self; 47 | } 48 | 49 | - (void)dealloc 50 | { 51 | [mHotKeys release]; 52 | [super dealloc]; 53 | } 54 | 55 | #pragma mark - 56 | 57 | - (BOOL)registerHotKey: (PTHotKey*)hotKey 58 | { 59 | //NSLog(@"registerHotKey: %@", hotKey); 60 | OSStatus err; 61 | EventHotKeyID hotKeyID; 62 | EventHotKeyRef carbonHotKey; 63 | /* 64 | if([mHotKeys objectForKey:[hotKey name]]) 65 | [self unregisterHotKey: hotKey]; 66 | */ 67 | if( [[hotKey keyCombo] isValidHotKeyCombo] == NO ) 68 | { 69 | //NSLog(@"not valid keycombo:"); 70 | return YES; 71 | } 72 | 73 | 74 | hotKeyID.signature = UTGetOSTypeFromString(CFSTR("PTHk")); 75 | hotKeyID.id = mNextKeyID; 76 | 77 | //NSLog(@"registering..."); 78 | err = RegisterEventHotKey( [[hotKey keyCombo] keyCode], 79 | [[hotKey keyCombo] modifiers], 80 | hotKeyID, 81 | GetEventDispatcherTarget(), 82 | 0, 83 | &carbonHotKey ); 84 | 85 | if( err ) 86 | { 87 | //NSLog(@"error --"); 88 | return NO; 89 | } 90 | 91 | NSNumber *kid = [NSNumber numberWithUnsignedInt:mNextKeyID]; 92 | [mHotKeyMap setObject:hotKey forKey:kid]; 93 | mNextKeyID += 1; 94 | 95 | 96 | [hotKey setCarbonHotKey:carbonHotKey]; 97 | [mHotKeys setObject: hotKey forKey: [hotKey name]]; 98 | 99 | [self _updateEventHandler]; 100 | //NSLog(@"Eo registerHotKey:"); 101 | return YES; 102 | } 103 | 104 | - (void)unregisterHotKey: (PTHotKey*)hotKey 105 | { 106 | //NSLog(@"unregisterHotKey: %@", hotKey); 107 | EventHotKeyRef carbonHotKey; 108 | 109 | if(![mHotKeys objectForKey:[hotKey name]]) 110 | return; 111 | 112 | carbonHotKey = [hotKey carbonHotKey]; 113 | NSAssert( carbonHotKey != nil, @"" ); 114 | 115 | (void)UnregisterEventHotKey( carbonHotKey ); 116 | //Watch as we ignore 'err': 117 | 118 | [mHotKeys removeObjectForKey: [hotKey name]]; 119 | NSArray *remKeys = [mHotKeyMap allKeysForObject:hotKey]; 120 | if (remKeys && [remKeys count] > 0) 121 | [mHotKeyMap removeObjectsForKeys:remKeys]; 122 | 123 | [self _updateEventHandler]; 124 | //NSLog(@"Eo unregisterHotKey:"); 125 | //See that? Completely ignored 126 | } 127 | 128 | - (void) unregisterHotKeyForName:(NSString *)name 129 | { 130 | [self unregisterHotKey:[mHotKeys objectForKey:name]]; 131 | } 132 | 133 | - (void) unregisterAllHotKeys; 134 | { 135 | NSEnumerator *enumerator = [mHotKeys objectEnumerator]; 136 | id thing; 137 | while ((thing = [enumerator nextObject])) 138 | { 139 | [self unregisterHotKey:thing]; 140 | } 141 | } 142 | 143 | - (void) setHotKeyRegistrationForName:(NSString *)name enable:(BOOL)ena 144 | { 145 | if (ena) 146 | { 147 | [self registerHotKey:[mHotKeys objectForKey:name]]; 148 | } else 149 | { 150 | [self unregisterHotKey:[mHotKeys objectForKey:name]]; 151 | } 152 | } 153 | 154 | - (void) updateHotKey:(PTHotKey *)hk 155 | { 156 | [hk retain]; 157 | //NSLog(@"updateHotKey: %@", hk); 158 | [self unregisterHotKey:[mHotKeys objectForKey:[hk name]]]; 159 | //NSLog(@"unreg'd: %@", hk); 160 | [self registerHotKey:hk]; 161 | //NSLog(@"Eo updateHotKey:"); 162 | } 163 | 164 | - (PTHotKey *) hotKeyForName:(NSString *)name 165 | { 166 | return [mHotKeys objectForKey:name]; 167 | } 168 | 169 | - (NSArray*)allHotKeys 170 | { 171 | return [mHotKeys allValues]; 172 | } 173 | 174 | #pragma mark - 175 | - (void)_updateEventHandler 176 | { 177 | if( [mHotKeys count] && mEventHandlerInstalled == NO ) 178 | { 179 | EventTypeSpec eventSpec[2] = { 180 | { kEventClassKeyboard, kEventHotKeyPressed }, 181 | { kEventClassKeyboard, kEventHotKeyReleased } 182 | }; 183 | 184 | InstallEventHandler( GetEventDispatcherTarget(), 185 | (EventHandlerProcPtr)hotKeyEventHandler, 186 | 2, eventSpec, nil, nil); 187 | 188 | mEventHandlerInstalled = YES; 189 | } 190 | } 191 | 192 | - (void)_hotKeyDown: (PTHotKey*)hotKey 193 | { 194 | [hotKey invoke]; 195 | } 196 | 197 | - (void)_hotKeyUp: (PTHotKey*)hotKey 198 | { 199 | //[hotKey uninvoke]; 200 | } 201 | 202 | - (OSStatus)sendCarbonEvent: (EventRef)event 203 | { 204 | OSStatus err; 205 | EventHotKeyID hotKeyID; 206 | PTHotKey* hotKey; 207 | 208 | NSAssert( GetEventClass( event ) == kEventClassKeyboard, @"Unknown event class" ); 209 | 210 | err = GetEventParameter( event, 211 | kEventParamDirectObject, 212 | typeEventHotKeyID, 213 | nil, 214 | sizeof(EventHotKeyID), 215 | nil, 216 | &hotKeyID ); 217 | if( err ) 218 | return err; 219 | 220 | 221 | NSAssert( hotKeyID.signature == UTGetOSTypeFromString(CFSTR("PTHk")), @"Invalid hot key id" ); 222 | 223 | NSNumber *kid = [NSNumber numberWithUnsignedInt:hotKeyID.id]; 224 | hotKey = [mHotKeyMap objectForKey:kid]; 225 | 226 | NSAssert( hotKey != nil, @"Invalid hot key id" ); 227 | 228 | switch( GetEventKind( event ) ) 229 | { 230 | case kEventHotKeyPressed: 231 | [self _hotKeyDown: hotKey]; 232 | break; 233 | 234 | case kEventHotKeyReleased: 235 | [self _hotKeyUp: hotKey]; 236 | break; 237 | 238 | default: 239 | NSAssert( 0, @"Unknown event kind" ); 240 | } 241 | 242 | return noErr; 243 | } 244 | 245 | static OSStatus hotKeyEventHandler(EventHandlerCallRef inHandlerRef, EventRef inEvent, void* refCon ) 246 | { 247 | return [[PTHotKeyCenter sharedCenter] sendCarbonEvent: inEvent]; 248 | } 249 | 250 | @end 251 | -------------------------------------------------------------------------------- /PTHotKeyTest/PTHotKeyTest-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | com.ks.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | LSMinimumSystemVersion 26 | ${MACOSX_DEPLOYMENT_TARGET} 27 | NSHumanReadableCopyright 28 | Copyright © 2012 __MyCompanyName__. All rights reserved. 29 | NSMainNibFile 30 | MainMenu 31 | NSPrincipalClass 32 | NSApplication 33 | 34 | 35 | -------------------------------------------------------------------------------- /PTHotKeyTest/PTHotKeyTest-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'PTHotKeyTest' target in the 'PTHotKeyTest' project 3 | // 4 | 5 | #ifdef __OBJC__ 6 | #import 7 | #endif 8 | -------------------------------------------------------------------------------- /PTHotKeyTest/PTHotKeyTest.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.app-sandbox 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /PTHotKeyTest/PTKeyBroadcaster.h: -------------------------------------------------------------------------------- 1 | // 2 | // PTKeyBroadcaster.h 3 | // Protein 4 | // 5 | // Created by Quentin Carnicelli on Sun Aug 03 2003. 6 | // Copyright (c) 2003 Quentin D. Carnicelli. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | @interface PTKeyBroadcaster : NSButton 13 | { 14 | } 15 | 16 | + (long)cocoaModifiersAsCarbonModifiers: (long)cocoaModifiers; 17 | 18 | @end 19 | 20 | __private_extern__ NSString* PTKeyBroadcasterKeyEvent; //keys: keyCombo as PTKeyCombo 21 | -------------------------------------------------------------------------------- /PTHotKeyTest/PTKeyBroadcaster.m: -------------------------------------------------------------------------------- 1 | // 2 | // PTKeyBroadcaster.m 3 | // Protein 4 | // 5 | // Created by Quentin Carnicelli on Sun Aug 03 2003. 6 | // Copyright (c) 2003 Quentin D. Carnicelli. All rights reserved. 7 | // 8 | 9 | #import "PTKeyBroadcaster.h" 10 | #import "PTKeyCombo.h" 11 | #import 12 | 13 | NSString* PTKeyBroadcasterKeyEvent = @"PTKeyBroadcasterKeyEvent"; 14 | 15 | @implementation PTKeyBroadcaster 16 | 17 | - (void)_bcastKeyCode: (short)keyCode modifiers: (long)modifiers 18 | { 19 | PTKeyCombo* keyCombo = [PTKeyCombo keyComboWithKeyCode: keyCode modifiers: modifiers]; 20 | NSDictionary* userInfo = [NSDictionary dictionaryWithObject: keyCombo forKey:@"keyCombo"]; 21 | 22 | [[NSNotificationCenter defaultCenter] 23 | postNotificationName: PTKeyBroadcasterKeyEvent 24 | object: self 25 | userInfo: userInfo]; 26 | } 27 | 28 | - (void)_bcastEvent: (NSEvent*)event 29 | { 30 | short keyCode; 31 | long modifiers; 32 | 33 | keyCode = [event keyCode]; 34 | modifiers = [event modifierFlags]; 35 | modifiers = [[self class] cocoaModifiersAsCarbonModifiers: modifiers]; 36 | 37 | [self _bcastKeyCode: keyCode modifiers: modifiers]; 38 | } 39 | 40 | - (BOOL)resignFirstResponder { 41 | return NO; 42 | } 43 | 44 | - (void)keyDown: (NSEvent*)event 45 | { 46 | [self _bcastEvent: event]; 47 | } 48 | 49 | - (BOOL)performKeyEquivalent: (NSEvent*)event 50 | { 51 | [self _bcastEvent: event]; 52 | return YES; 53 | } 54 | 55 | + (long)cocoaModifiersAsCarbonModifiers: (long)cocoaModifiers 56 | { 57 | static long cocoaToCarbon[6][2] = 58 | { 59 | { NSCommandKeyMask, cmdKey}, 60 | { NSAlternateKeyMask, optionKey}, 61 | { NSControlKeyMask, controlKey}, 62 | { NSShiftKeyMask, shiftKey}, 63 | { NSFunctionKeyMask, rightControlKey}, 64 | //{ NSAlphaShiftKeyMask, alphaLock }, //Ignore this? 65 | }; 66 | 67 | long carbonModifiers = 0; 68 | int i; 69 | 70 | for( i = 0 ; i < 6; i++ ) 71 | if( cocoaModifiers & cocoaToCarbon[i][0] ) 72 | carbonModifiers += cocoaToCarbon[i][1]; 73 | 74 | return carbonModifiers; 75 | } 76 | 77 | 78 | @end 79 | -------------------------------------------------------------------------------- /PTHotKeyTest/PTKeyCodes.plist: -------------------------------------------------------------------------------- 1 | { 2 | 0 = "A"; 3 | 1 = "S"; 4 | 2 = "D"; 5 | 3 = "F"; 6 | 4 = "H"; 7 | 5 = "G"; 8 | 6 = "Z"; 9 | 7 = "X"; 10 | 8 = "C"; 11 | 9 = "V"; 12 | 10 = "$"; 13 | 11 = "B"; 14 | 12 = "Q"; 15 | 13 = "W"; 16 | 14 = "E"; 17 | 15 = "R"; 18 | 16 = "Y"; 19 | 17 = "T"; 20 | 18 = "1"; 21 | 19 = "2"; 22 | 20 = "3"; 23 | 21 = "4"; 24 | 22 = "6"; 25 | 23 = "5"; 26 | 24 = "="; 27 | 25 = "9"; 28 | 26 = "7"; 29 | 27 = "-"; 30 | 28 = "8"; 31 | 29 = "0"; 32 | 30 = "\]"; 33 | 31 = "O"; 34 | 32 = "U"; 35 | 33 = "\["; 36 | 34 = "I"; 37 | 35 = "P"; 38 | 36 = "Return"; 39 | 37 = "L"; 40 | 38 = "J"; 41 | 39 = "\'"; 42 | 40 = "K"; 43 | 41 = ";"; 44 | 42 = "\\"; 45 | 43 = ","; 46 | 44 = "\/"; 47 | 45 = "N"; 48 | 46 = "M"; 49 | 47 = "."; 50 | 48 = "Tab"; 51 | 49 = "Space"; 52 | 50 = "\`"; 53 | 51 = "Delete"; 54 | 53 = "ESC"; 55 | 55 = "Command"; 56 | 56 = "Shift"; 57 | 57 = "Caps Lock"; 58 | 58 = "Option"; 59 | 59 = "Control"; 60 | 65 = "Pad ."; 61 | 67 = "Pad *"; 62 | 69 = "Pad +"; 63 | 71 = "Clear"; 64 | 75 = "Pad /"; 65 | 76 = "Pad Enter"; 66 | 78 = "Pad -"; 67 | 81 = "Pad ="; 68 | 82 = "Pad 0"; 69 | 83 = "Pad 1"; 70 | 84 = "Pad 2"; 71 | 85 = "Pad 3"; 72 | 86 = "Pad 4"; 73 | 87 = "Pad 5"; 74 | 88 = "Pad 6"; 75 | 89 = "Pad 7"; 76 | 91 = "Pad 8"; 77 | 92 = "Pad 9"; 78 | 96 = "F5"; 79 | 97 = "F6"; 80 | 98 = "F7"; 81 | 99 = "F3"; 82 | 100 = "F8"; 83 | 101 = "F9"; 84 | 103 = "F11"; 85 | 105 = "F13"; 86 | 107 = "F14"; 87 | 109 = "F10"; 88 | 111 = "F12"; 89 | 113 = "F15"; 90 | 114 = "Ins"; 91 | 115 = "Home"; 92 | 116 = "Page Up"; 93 | 117 = "Del"; 94 | 118 = "F4"; 95 | 119 = "End"; 96 | 120 = "F2"; 97 | 121 = "Page Down"; 98 | 122 = "F1"; 99 | 123 = "Left Arrow"; 100 | 124 = "Right Arrow"; 101 | 125 = "Down Arrow"; 102 | 126 = "Up Arrow"; 103 | } -------------------------------------------------------------------------------- /PTHotKeyTest/PTKeyCombo.h: -------------------------------------------------------------------------------- 1 | // 2 | // PTKeyCombo.h 3 | // Protein 4 | // 5 | // Created by Quentin Carnicelli on Sat Aug 02 2003. 6 | // Copyright (c) 2003 Quentin D. Carnicelli. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | @interface PTKeyCombo : NSObject 13 | { 14 | int mKeyCode; 15 | int mModifiers; 16 | } 17 | 18 | + (id)clearKeyCombo; 19 | + (id)keyComboWithKeyCode: (int)keyCode modifiers: (int)modifiers; 20 | - (id)initWithKeyCode: (int)keyCode modifiers: (int)modifiers; 21 | 22 | - (id)initWithPlistRepresentation: (id)plist; 23 | - (id)plistRepresentation; 24 | 25 | - (BOOL)isEqual: (PTKeyCombo*)combo; 26 | 27 | - (int)keyCode; 28 | - (int)modifiers; 29 | 30 | - (BOOL)isClearCombo; 31 | - (BOOL)isValidHotKeyCombo; 32 | 33 | @end 34 | 35 | @interface PTKeyCombo (UserDisplayAdditions) 36 | 37 | - (NSString*)description; 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /PTHotKeyTest/PTKeyCombo.m: -------------------------------------------------------------------------------- 1 | // 2 | // PTKeyCombo.m 3 | // Protein 4 | // 5 | // Created by Quentin Carnicelli on Sat Aug 02 2003. 6 | // Copyright (c) 2003 Quentin D. Carnicelli. All rights reserved. 7 | // 8 | 9 | #import "PTKeyCombo.h" 10 | 11 | #import 12 | 13 | @implementation PTKeyCombo 14 | 15 | + (id)clearKeyCombo 16 | { 17 | return [self keyComboWithKeyCode: -1 modifiers: -1]; 18 | } 19 | 20 | + (id)keyComboWithKeyCode: (int)keyCode modifiers: (int)modifiers 21 | { 22 | return [[[self alloc] initWithKeyCode: keyCode modifiers: modifiers] autorelease]; 23 | } 24 | 25 | - (id)initWithKeyCode: (int)keyCode modifiers: (int)modifiers 26 | { 27 | self = [super init]; 28 | 29 | if( self ) 30 | { 31 | mKeyCode = keyCode; 32 | mModifiers = modifiers; 33 | } 34 | 35 | return self; 36 | } 37 | 38 | - (id)initWithPlistRepresentation: (id)plist 39 | { 40 | int keyCode, modifiers; 41 | 42 | keyCode = [[plist objectForKey: @"keyCode"] intValue]; 43 | if( keyCode <= 0 ) keyCode = -1; 44 | 45 | modifiers = [[plist objectForKey: @"modifiers"] intValue]; 46 | if( modifiers <= 0 ) modifiers = -1; 47 | 48 | return [self initWithKeyCode: keyCode modifiers: modifiers]; 49 | } 50 | 51 | - (id)plistRepresentation 52 | { 53 | return [NSDictionary dictionaryWithObjectsAndKeys: 54 | [NSNumber numberWithInt: [self keyCode]], @"keyCode", 55 | [NSNumber numberWithInt: [self modifiers]], @"modifiers", 56 | nil]; 57 | } 58 | 59 | - (id)copyWithZone:(NSZone*)zone; 60 | { 61 | return [self retain]; 62 | } 63 | 64 | - (BOOL)isEqual: (PTKeyCombo*)combo 65 | { 66 | return [self keyCode] == [combo keyCode] && 67 | [self modifiers] == [combo modifiers]; 68 | } 69 | 70 | #pragma mark - 71 | 72 | - (int)keyCode 73 | { 74 | return mKeyCode; 75 | } 76 | 77 | - (int)modifiers 78 | { 79 | return mModifiers; 80 | } 81 | 82 | - (BOOL)isValidHotKeyCombo 83 | { 84 | return mKeyCode >= 0 && mModifiers > 0; 85 | } 86 | 87 | - (BOOL)isClearCombo 88 | { 89 | return mKeyCode == -1 && mModifiers == -1; 90 | } 91 | 92 | @end 93 | 94 | #pragma mark - 95 | 96 | @implementation PTKeyCombo (UserDisplayAdditions) 97 | 98 | + (NSDictionary*)_keyCodesDictionary 99 | { 100 | static NSDictionary* keyCodes = nil; 101 | if( keyCodes == nil ) { 102 | keyCodes = [[NSDictionary dictionaryWithContentsOfFile:[[NSBundle bundleForClass: self] pathForResource: @"PTKeyCodes" ofType: @"plist"]] retain]; 103 | } 104 | 105 | return keyCodes; 106 | } 107 | 108 | + (NSString*)_stringForModifiers: (long)modifiers 109 | { 110 | static long modToChar[4][2] = 111 | { 112 | #ifdef __BIG_ENDIAN__ 113 | { cmdKey, 0x23180000 }, 114 | { optionKey, 0x23250000 }, 115 | { controlKey, 0x005E0000 }, 116 | { shiftKey, 0x21e70000 } 117 | #else 118 | { cmdKey, 0x00002318 }, 119 | { optionKey, 0x00002325 }, 120 | { controlKey, 0x0000005E }, 121 | { shiftKey, 0x000021e7 } 122 | #endif 123 | }; 124 | 125 | NSString* str = nil; 126 | NSString* charStr; 127 | long i; 128 | 129 | str = [NSString string]; 130 | 131 | for( i = 0; i < 4; i++ ) 132 | { 133 | if( modifiers & modToChar[i][0] ) 134 | { 135 | charStr = [NSString stringWithCharacters: (const unichar*)&modToChar[i][1] length: 1]; 136 | str = [str stringByAppendingString: charStr]; 137 | } 138 | } 139 | 140 | if( !str ) 141 | str = @""; 142 | 143 | return str; 144 | } 145 | 146 | + (NSString*)_stringForKeyCode: (short)keyCode 147 | { 148 | NSDictionary* dict; 149 | id key; 150 | NSString* str; 151 | 152 | dict = [self _keyCodesDictionary]; 153 | key = [NSString stringWithFormat: @"%d", keyCode]; 154 | str = [dict objectForKey: key]; 155 | 156 | if( !str ) 157 | str = [NSString stringWithFormat: @"%X", keyCode]; 158 | 159 | return str; 160 | } 161 | 162 | - (NSString*)description 163 | { 164 | NSString* desc; 165 | 166 | if( [self isValidHotKeyCombo] ) //This might have to change 167 | { 168 | desc = [NSString stringWithFormat: @"%@%@", 169 | [[self class] _stringForModifiers: [self modifiers]], 170 | [[self class] _stringForKeyCode: [self keyCode]]]; 171 | } 172 | else 173 | desc = NSLocalizedString(@"(None)", @"description for no key combination"); 174 | 175 | return desc; 176 | } 177 | 178 | @end 179 | -------------------------------------------------------------------------------- /PTHotKeyTest/PTKeyComboPanel.h: -------------------------------------------------------------------------------- 1 | // 2 | // PTKeyComboPanel.h 3 | // Protein 4 | // 5 | // Created by Quentin Carnicelli on Sun Aug 03 2003. 6 | // Copyright (c) 2003 Quentin D. Carnicelli. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class PTKeyBroadcaster; 12 | @class PTKeyCombo; 13 | @class PTHotKey; 14 | 15 | @interface PTKeyComboPanel : NSWindowController 16 | { 17 | IBOutlet NSTextField* mTitleField; 18 | IBOutlet NSTextField* mComboField; 19 | IBOutlet PTKeyBroadcaster* mKeyBcaster; 20 | 21 | id currentModalDelegate; 22 | 23 | NSString* mTitleFormat; 24 | NSString* mKeyName; 25 | PTKeyCombo* mKeyCombo; 26 | } 27 | 28 | + (id)sharedPanel; 29 | 30 | - (void)showSheetForHotkey:(PTHotKey*)hotKey forWindow:(NSWindow*)mainWindow modalDelegate:(id)target; 31 | 32 | - (void)runModalForHotKey: (PTHotKey*)hotKey; 33 | 34 | - (void)setKeyCombo: (PTKeyCombo*)combo; 35 | - (PTKeyCombo*)keyCombo; 36 | 37 | - (void)setKeyBindingName: (NSString*)name; 38 | - (NSString*)keyBindingName; 39 | 40 | - (IBAction)ok: (id)sender; 41 | - (IBAction)cancel: (id)sender; 42 | - (IBAction)clear: (id)sender; 43 | @end 44 | 45 | 46 | @interface PTKeyComboPanel (ModalDelegate) 47 | - (void)keyComboPanelEnded:(PTKeyComboPanel*)panel; 48 | @end 49 | -------------------------------------------------------------------------------- /PTHotKeyTest/PTKeyComboPanel.m: -------------------------------------------------------------------------------- 1 | // 2 | // PTKeyComboPanel.m 3 | // Protein 4 | // 5 | // Created by Quentin Carnicelli on Sun Aug 03 2003. 6 | // Copyright (c) 2003 Quentin D. Carnicelli. All rights reserved. 7 | // 8 | 9 | #import "PTKeyComboPanel.h" 10 | 11 | #import "PTHotKey.h" 12 | #import "PTKeyCombo.h" 13 | #import "PTKeyBroadcaster.h" 14 | #import "PTHotKeyCenter.h" 15 | 16 | @implementation PTKeyComboPanel 17 | 18 | static id _sharedKeyComboPanel = nil; 19 | 20 | + (id)sharedPanel 21 | { 22 | if( _sharedKeyComboPanel == nil ) 23 | { 24 | _sharedKeyComboPanel = [[self alloc] init]; 25 | } 26 | 27 | return _sharedKeyComboPanel; 28 | } 29 | 30 | - (id)init 31 | { 32 | mTitleFormat = @"empty"; 33 | mKeyName = @"empty"; 34 | return [self initWithWindowNibName: @"PTKeyComboPanel"]; 35 | } 36 | 37 | - (void)dealloc 38 | { 39 | [[NSNotificationCenter defaultCenter] removeObserver: self]; 40 | [mKeyName release]; 41 | [mTitleFormat release]; 42 | 43 | [super dealloc]; 44 | } 45 | 46 | - (void)windowDidLoad 47 | { 48 | mTitleFormat = [[mTitleField stringValue] retain]; 49 | 50 | [[NSNotificationCenter defaultCenter] 51 | addObserver: self 52 | selector: @selector( noteKeyBroadcast: ) 53 | name: PTKeyBroadcasterKeyEvent 54 | object: mKeyBcaster]; 55 | } 56 | 57 | - (void)_refreshContents 58 | { 59 | if( mComboField) 60 | [mComboField setStringValue: [mKeyCombo description]]; 61 | 62 | 63 | if( mTitleField ) 64 | [mTitleField setStringValue: [NSString stringWithFormat: mTitleFormat, mKeyName]]; 65 | 66 | } 67 | 68 | - (void)chooseHotKeyDidEnd:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo { 69 | PTHotKey *hotKey = (PTHotKey *)contextInfo; 70 | 71 | [[self window] close]; 72 | 73 | if (hotKey && returnCode == NSOKButton) { 74 | [hotKey setKeyCombo: [self keyCombo]]; 75 | [[PTHotKeyCenter sharedCenter] updateHotKey: hotKey]; 76 | if ([currentModalDelegate respondsToSelector:@selector(keyComboPanelEnded:)]) 77 | [currentModalDelegate keyComboPanelEnded:self]; 78 | else 79 | NSLog(@"currentModalDelegate doesn't respond to keyComboPanelEnded:!"); 80 | } 81 | 82 | [hotKey release]; 83 | [currentModalDelegate release]; 84 | } 85 | 86 | - (void)showSheetForHotkey:(PTHotKey*)hotKey forWindow:(NSWindow*)mainWindow modalDelegate:(id)target { 87 | [[self window] makeFirstResponder:mKeyBcaster]; 88 | 89 | [self setKeyCombo: [hotKey keyCombo]]; 90 | [self setKeyBindingName: [hotKey name]]; 91 | 92 | currentModalDelegate = [target retain]; 93 | [hotKey retain]; 94 | 95 | [NSApp beginSheet:[self window] modalForWindow:mainWindow modalDelegate:self 96 | didEndSelector:@selector(chooseHotKeyDidEnd:returnCode:contextInfo:) contextInfo:hotKey]; 97 | } 98 | 99 | - (void)runModalForHotKey: (PTHotKey*)hotKey { 100 | int resultCode; 101 | 102 | [self setKeyCombo: [hotKey keyCombo]]; 103 | [self setKeyBindingName: [hotKey name]]; 104 | 105 | resultCode = [NSApp runModalForWindow: [self window]]; 106 | [[self window] orderOut:self]; 107 | 108 | if (resultCode == NSOKButton) { 109 | [hotKey setKeyCombo: [self keyCombo]]; 110 | [[PTHotKeyCenter sharedCenter] updateHotKey: hotKey]; 111 | } 112 | } 113 | 114 | #pragma mark - 115 | 116 | - (void)setKeyCombo: (PTKeyCombo*)combo 117 | { 118 | if (combo == nil) 119 | combo = [PTKeyCombo clearKeyCombo]; 120 | else 121 | [combo retain]; 122 | 123 | [mKeyCombo release]; 124 | mKeyCombo = combo; 125 | [self _refreshContents]; 126 | } 127 | 128 | - (PTKeyCombo*)keyCombo 129 | { 130 | return mKeyCombo; 131 | } 132 | 133 | - (void)setKeyBindingName: (NSString*)name 134 | { 135 | [name retain]; 136 | [mKeyName release]; 137 | mKeyName = name; 138 | [self _refreshContents]; 139 | } 140 | 141 | - (NSString*)keyBindingName 142 | { 143 | return mKeyName; 144 | } 145 | 146 | #pragma mark - 147 | 148 | - (IBAction)ok: (id)sender { 149 | if ([[self window] isModalPanel]) 150 | [NSApp stopModalWithCode:NSOKButton]; 151 | else 152 | [NSApp endSheet:[self window] returnCode:NSOKButton]; 153 | 154 | } 155 | 156 | - (IBAction)cancel: (id)sender { 157 | if ([[self window] isModalPanel]) 158 | [NSApp stopModalWithCode:NSCancelButton]; 159 | else 160 | [NSApp endSheet:[self window] returnCode:NSCancelButton]; 161 | } 162 | 163 | - (IBAction)clear: (id)sender 164 | { 165 | [self setKeyCombo: [PTKeyCombo clearKeyCombo]]; 166 | if ([[self window] isModalPanel]) 167 | [NSApp stopModalWithCode:NSOKButton]; 168 | } 169 | 170 | - (void)noteKeyBroadcast: (NSNotification*)note 171 | { 172 | PTKeyCombo* keyCombo = [[note userInfo] objectForKey: @"keyCombo"]; 173 | 174 | [self setKeyCombo: keyCombo]; 175 | } 176 | 177 | @end 178 | -------------------------------------------------------------------------------- /PTHotKeyTest/PTKeyComboPanel.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1070 5 | 11E53 6 | 2182 7 | 1138.47 8 | 569.00 9 | 10 | com.apple.InterfaceBuilder.CocoaPlugin 11 | 2182 12 | 13 | 14 | NSTextField 15 | NSView 16 | NSWindowTemplate 17 | NSTextFieldCell 18 | NSImageCell 19 | IBNSLayoutConstraint 20 | NSButtonCell 21 | NSButton 22 | NSImageView 23 | NSCustomObject 24 | 25 | 26 | com.apple.InterfaceBuilder.CocoaPlugin 27 | 28 | 29 | PluginDependencyRecalculationVersion 30 | 31 | 32 | 33 | 34 | PTKeyComboPanel 35 | 36 | 37 | FirstResponder 38 | 39 | 40 | NSApplication 41 | 42 | 43 | 1 44 | 2 45 | {{290, 345}, {394, 165}} 46 | 1886912512 47 | 48 | NSWindow 49 | 50 | View 51 | 52 | 53 | {213, 107} 54 | 55 | 56 | 256 57 | 58 | 59 | 60 | 256 61 | {{152, 60}, {173, 22}} 62 | 63 | 64 | 65 | YES 66 | 67 | -2072904127 68 | 138413056 69 | 70 | 71 | LucidaGrande 72 | 13 73 | 1044 74 | 75 | none 76 | 77 | YES 78 | 79 | 6 80 | System 81 | textBackgroundColor 82 | 83 | 3 84 | MQA 85 | 86 | 87 | 88 | 6 89 | System 90 | textColor 91 | 92 | 3 93 | MAA 94 | 95 | 96 | 97 | 98 | 99 | 100 | 256 101 | {{130, 12}, {84, 32}} 102 | 103 | 104 | 105 | YES 106 | 107 | 67239424 108 | 137887744 109 | None 110 | 111 | 112 | -2038284033 113 | 1 114 | 115 | Helvetica 116 | 13 117 | 16 118 | 119 | 120 | 121 | 122 | 123 | 200 124 | 25 125 | 126 | 127 | 128 | 129 | 256 130 | {{214, 12}, {82, 32}} 131 | 132 | 133 | 134 | YES 135 | 136 | 67239424 137 | 137887744 138 | Cancel 139 | 140 | 141 | -2038284033 142 | 1 143 | 144 | 145 | 146 | 200 147 | 25 148 | 149 | 150 | 151 | 152 | 256 153 | {{69, 90}, {308, 55}} 154 | 155 | 156 | 157 | YES 158 | 159 | 67239424 160 | 4194304 161 | Press a key combination to %@. 162 | 163 | LucidaGrande-Bold 164 | 13 165 | 2072 166 | 167 | 168 | 169 | 6 170 | System 171 | controlColor 172 | 173 | 3 174 | MC42NjY2NjY2NjY3AA 175 | 176 | 177 | 178 | 6 179 | System 180 | controlTextColor 181 | 182 | 183 | 184 | 185 | 186 | 187 | 256 188 | {{69, 62}, {81, 17}} 189 | 190 | 191 | 192 | YES 193 | 194 | 67239424 195 | 71303168 196 | Keystroke: 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 256 206 | {{296, 12}, {84, 32}} 207 | 208 | 209 | 210 | YES 211 | 212 | 67239424 213 | 134217728 214 | OK 215 | 216 | 217 | -2038284033 218 | 1 219 | 220 | 221 | 222 | 200 223 | 25 224 | 225 | 226 | 227 | 228 | 256 229 | {{44, 60}, {22, 20}} 230 | 231 | 232 | 233 | YES 234 | 235 | 67239424 236 | 0 237 | 238 | 239 | 240 | 1211945471 241 | 2 242 | 243 | NSRadioButton 244 | 245 | 246 | 247 | 248 | 249 | 200 250 | 25 251 | 252 | 253 | 254 | 255 | 256 256 | 257 | Apple PDF pasteboard type 258 | Apple PICT pasteboard type 259 | Apple PNG pasteboard type 260 | NSFilenamesPboardType 261 | NeXT Encapsulated PostScript v1.2 pasteboard type 262 | NeXT TIFF v4.0 pasteboard type 263 | 264 | {{20, 113}, {32, 32}} 265 | 266 | 267 | YES 268 | 269 | 130560 270 | 33554432 271 | 272 | NSImage 273 | NSAdvanced 274 | 275 | 0 276 | 0 277 | 0 278 | YES 279 | 280 | YES 281 | 282 | 283 | {394, 165} 284 | 285 | 286 | 287 | 288 | {{0, 0}, {1280, 778}} 289 | {213, 129} 290 | {10000000000000, 10000000000000} 291 | YES 292 | 293 | 294 | 295 | 296 | 297 | 298 | window 299 | 300 | 301 | 302 | 41 303 | 304 | 305 | 306 | ok: 307 | 308 | 309 | 310 | 42 311 | 312 | 313 | 314 | clear: 315 | 316 | 317 | 318 | 43 319 | 320 | 321 | 322 | cancel: 323 | 324 | 325 | 326 | 44 327 | 328 | 329 | 330 | mComboField 331 | 332 | 333 | 334 | 45 335 | 336 | 337 | 338 | mKeyBcaster 339 | 340 | 341 | 342 | 46 343 | 344 | 345 | 346 | mTitleField 347 | 348 | 349 | 350 | 47 351 | 352 | 353 | 354 | initialFirstResponder 355 | 356 | 357 | 358 | 40 359 | 360 | 361 | 362 | 363 | 364 | 0 365 | 366 | 367 | 368 | 369 | 370 | -2 371 | 372 | 373 | File's Owner 374 | 375 | 376 | -1 377 | 378 | 379 | First Responder 380 | 381 | 382 | -3 383 | 384 | 385 | Application 386 | 387 | 388 | 3 389 | 390 | 391 | 392 | 393 | 394 | Panel 395 | 396 | 397 | 4 398 | 399 | 400 | 401 | 402 | 4 403 | 0 404 | 405 | 4 406 | 1 407 | 408 | 20 409 | 410 | 1000 411 | 8 412 | 29 413 | 3 414 | 415 | 416 | 417 | 418 | 3 419 | 0 420 | 421 | 4 422 | 1 423 | 424 | 8 425 | 426 | 1000 427 | 6 428 | 24 429 | 3 430 | 431 | 432 | 433 | 434 | 3 435 | 0 436 | 437 | 3 438 | 1 439 | 440 | 20 441 | 442 | 1000 443 | 8 444 | 29 445 | 3 446 | 447 | 448 | 449 | 450 | 5 451 | 0 452 | 453 | 6 454 | 1 455 | 456 | 12 457 | 458 | 1000 459 | 6 460 | 24 461 | 3 462 | 463 | 464 | 465 | 466 | 5 467 | 0 468 | 469 | 5 470 | 1 471 | 472 | 46 473 | 474 | 1000 475 | 3 476 | 9 477 | 3 478 | 479 | 480 | 481 | 482 | 5 483 | 0 484 | 485 | 5 486 | 1 487 | 488 | 0.0 489 | 490 | 1000 491 | 6 492 | 24 493 | 2 494 | 495 | 496 | 497 | 498 | 5 499 | 0 500 | 501 | 6 502 | 1 503 | 504 | 12 505 | 506 | 1000 507 | 6 508 | 24 509 | 3 510 | 511 | 512 | 513 | 514 | 4 515 | 0 516 | 517 | 4 518 | 1 519 | 520 | 20 521 | 522 | 1000 523 | 8 524 | 29 525 | 3 526 | 527 | 528 | 529 | 530 | 4 531 | 0 532 | 533 | 4 534 | 1 535 | 536 | 62 537 | 538 | 1000 539 | 3 540 | 9 541 | 3 542 | 543 | 544 | 545 | 546 | 3 547 | 0 548 | 549 | 3 550 | 1 551 | 552 | 0.0 553 | 554 | 1000 555 | 6 556 | 24 557 | 2 558 | 559 | 560 | 561 | 562 | 4 563 | 0 564 | 565 | 4 566 | 1 567 | 568 | 20 569 | 570 | 1000 571 | 8 572 | 29 573 | 3 574 | 575 | 576 | 577 | 578 | 6 579 | 0 580 | 581 | 6 582 | 1 583 | 584 | 20 585 | 586 | 1000 587 | 8 588 | 29 589 | 3 590 | 591 | 592 | 593 | 594 | 5 595 | 0 596 | 597 | 5 598 | 1 599 | 600 | 152 601 | 602 | 1000 603 | 3 604 | 9 605 | 3 606 | 607 | 608 | 609 | 610 | 6 611 | 0 612 | 613 | 6 614 | 1 615 | 616 | 20 617 | 618 | 1000 619 | 8 620 | 29 621 | 3 622 | 623 | 624 | 625 | 626 | 4 627 | 0 628 | 629 | 4 630 | 1 631 | 632 | 0.0 633 | 634 | 1000 635 | 6 636 | 24 637 | 2 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 5 651 | 0 652 | 653 | 5 654 | 1 655 | 656 | 20 657 | 658 | 1000 659 | 8 660 | 29 661 | 3 662 | 663 | 664 | 665 | 666 | 3 667 | 0 668 | 669 | 3 670 | 1 671 | 672 | 20 673 | 674 | 1000 675 | 8 676 | 29 677 | 3 678 | 679 | 680 | 681 | 682 | 683 | 684 | 5 685 | 686 | 687 | 688 | 689 | 6 690 | 691 | 692 | 693 | 694 | 7 695 | 696 | 697 | 698 | 699 | 8 700 | 701 | 702 | 703 | 704 | 9 705 | 706 | 707 | 708 | 709 | 10 710 | 711 | 712 | 713 | 714 | 11 715 | 716 | 717 | 718 | 719 | 12 720 | 721 | 722 | 723 | 724 | 13 725 | 726 | 727 | 728 | 729 | 14 730 | 731 | 732 | 733 | 734 | 15 735 | 736 | 737 | 738 | 739 | 16 740 | 741 | 742 | 743 | 744 | 17 745 | 746 | 747 | 748 | 749 | 18 750 | 751 | 752 | 753 | 754 | 19 755 | 756 | 757 | 758 | 759 | 20 760 | 761 | 762 | 763 | 764 | 7 765 | 0 766 | 767 | 0 768 | 1 769 | 770 | 173 771 | 772 | 1000 773 | 3 774 | 9 775 | 1 776 | 777 | 778 | 779 | 780 | 781 | 782 | 783 | 21 784 | 785 | 786 | 787 | 788 | 7 789 | 0 790 | 791 | 0 792 | 1 793 | 794 | 72 795 | 796 | 1000 797 | 3 798 | 9 799 | 1 800 | 801 | 802 | 803 | 804 | 805 | 806 | 807 | 22 808 | 809 | 810 | 811 | 812 | 813 | 814 | 815 | 23 816 | 817 | 818 | 819 | 820 | 7 821 | 0 822 | 823 | 0 824 | 1 825 | 826 | 302 827 | 828 | 1000 829 | 3 830 | 9 831 | 1 832 | 833 | 834 | 835 | 836 | 8 837 | 0 838 | 839 | 0 840 | 1 841 | 842 | 55 843 | 844 | 1000 845 | 3 846 | 9 847 | 1 848 | 849 | 850 | 851 | 852 | 853 | 854 | 855 | 24 856 | 857 | 858 | 859 | 860 | 7 861 | 0 862 | 863 | 0 864 | 1 865 | 866 | 75 867 | 868 | 1000 869 | 3 870 | 9 871 | 1 872 | 873 | 874 | 875 | 876 | 877 | 878 | 879 | 25 880 | 881 | 882 | 883 | 884 | 7 885 | 0 886 | 887 | 0 888 | 1 889 | 890 | 72 891 | 892 | 1000 893 | 3 894 | 9 895 | 1 896 | 897 | 898 | 899 | 900 | 901 | 902 | 903 | 26 904 | 905 | 906 | 907 | 908 | 909 | 910 | 911 | 27 912 | 913 | 914 | 915 | 916 | 28 917 | 918 | 919 | 920 | 921 | 29 922 | 923 | 924 | 925 | 926 | 30 927 | 928 | 929 | 930 | 931 | 31 932 | 933 | 934 | 935 | 936 | 32 937 | 938 | 939 | 940 | 941 | 33 942 | 943 | 944 | 945 | 946 | 34 947 | 948 | 949 | 950 | 951 | 35 952 | 953 | 954 | 955 | 956 | 36 957 | 958 | 959 | 960 | 961 | 37 962 | 963 | 964 | 965 | 966 | 38 967 | 968 | 969 | 970 | 971 | 39 972 | 973 | 974 | 975 | 976 | 48 977 | 978 | 979 | 980 | 981 | 982 | 983 | 984 | 49 985 | 986 | 987 | 988 | 989 | 52 990 | 991 | 992 | 993 | 994 | 53 995 | 996 | 997 | 998 | 999 | 1000 | 1001 | com.apple.InterfaceBuilder.CocoaPlugin 1002 | com.apple.InterfaceBuilder.CocoaPlugin 1003 | com.apple.InterfaceBuilder.CocoaPlugin 1004 | com.apple.InterfaceBuilder.CocoaPlugin 1005 | com.apple.InterfaceBuilder.CocoaPlugin 1006 | com.apple.InterfaceBuilder.CocoaPlugin 1007 | com.apple.InterfaceBuilder.CocoaPlugin 1008 | com.apple.InterfaceBuilder.CocoaPlugin 1009 | com.apple.InterfaceBuilder.CocoaPlugin 1010 | com.apple.InterfaceBuilder.CocoaPlugin 1011 | com.apple.InterfaceBuilder.CocoaPlugin 1012 | com.apple.InterfaceBuilder.CocoaPlugin 1013 | com.apple.InterfaceBuilder.CocoaPlugin 1014 | 1015 | 1016 | 1017 | 1018 | com.apple.InterfaceBuilder.CocoaPlugin 1019 | 1020 | 1021 | 1022 | 1023 | com.apple.InterfaceBuilder.CocoaPlugin 1024 | 1025 | com.apple.InterfaceBuilder.CocoaPlugin 1026 | 1027 | 1028 | 1029 | 1030 | 1031 | com.apple.InterfaceBuilder.CocoaPlugin 1032 | 1033 | 1034 | 1035 | 1036 | com.apple.InterfaceBuilder.CocoaPlugin 1037 | 1038 | 1039 | 1040 | 1041 | com.apple.InterfaceBuilder.CocoaPlugin 1042 | PTKeyBroadcaster 1043 | 1044 | ToolTip 1045 | 1046 | ToolTip 1047 | 1048 | CkJhc2VkIG9uIENvY29hSG90S2V5TGliCmh0dHA6Ly93d3cucm9ndWVhbW9lYmEuY29tLwo 1049 | 1050 | 1051 | 1052 | com.apple.InterfaceBuilder.CocoaPlugin 1053 | com.apple.InterfaceBuilder.CocoaPlugin 1054 | com.apple.InterfaceBuilder.CocoaPlugin 1055 | com.apple.InterfaceBuilder.CocoaPlugin 1056 | com.apple.InterfaceBuilder.CocoaPlugin 1057 | com.apple.InterfaceBuilder.CocoaPlugin 1058 | com.apple.InterfaceBuilder.CocoaPlugin 1059 | com.apple.InterfaceBuilder.CocoaPlugin 1060 | com.apple.InterfaceBuilder.CocoaPlugin 1061 | com.apple.InterfaceBuilder.CocoaPlugin 1062 | com.apple.InterfaceBuilder.CocoaPlugin 1063 | com.apple.InterfaceBuilder.CocoaPlugin 1064 | com.apple.InterfaceBuilder.CocoaPlugin 1065 | com.apple.InterfaceBuilder.CocoaPlugin 1066 | com.apple.InterfaceBuilder.CocoaPlugin 1067 | 1068 | 1069 | 1070 | 1071 | 1072 | 1073 | 1074 | 1075 | 1076 | 1077 | 1078 | 1079 | 1080 | 1081 | 1082 | 1083 | 1084 | 1085 | 1086 | com.apple.InterfaceBuilder.CocoaPlugin 1087 | 1088 | com.apple.InterfaceBuilder.CocoaPlugin 1089 | com.apple.InterfaceBuilder.CocoaPlugin 1090 | com.apple.InterfaceBuilder.CocoaPlugin 1091 | com.apple.InterfaceBuilder.CocoaPlugin 1092 | com.apple.InterfaceBuilder.CocoaPlugin 1093 | com.apple.InterfaceBuilder.CocoaPlugin 1094 | com.apple.InterfaceBuilder.CocoaPlugin 1095 | com.apple.InterfaceBuilder.CocoaPlugin 1096 | com.apple.InterfaceBuilder.CocoaPlugin 1097 | 1098 | 1099 | 1100 | 1101 | 1102 | 53 1103 | 1104 | 1105 | 1106 | 1107 | NSLayoutConstraint 1108 | NSObject 1109 | 1110 | IBProjectSource 1111 | ./Classes/NSLayoutConstraint.h 1112 | 1113 | 1114 | 1115 | PTKeyBroadcaster 1116 | NSButton 1117 | 1118 | IBProjectSource 1119 | ./Classes/PTKeyBroadcaster.h 1120 | 1121 | 1122 | 1123 | PTKeyComboPanel 1124 | NSWindowController 1125 | 1126 | id 1127 | id 1128 | id 1129 | 1130 | 1131 | 1132 | cancel: 1133 | id 1134 | 1135 | 1136 | clear: 1137 | id 1138 | 1139 | 1140 | ok: 1141 | id 1142 | 1143 | 1144 | 1145 | NSTextField 1146 | PTKeyBroadcaster 1147 | NSTextField 1148 | 1149 | 1150 | 1151 | mComboField 1152 | NSTextField 1153 | 1154 | 1155 | mKeyBcaster 1156 | PTKeyBroadcaster 1157 | 1158 | 1159 | mTitleField 1160 | NSTextField 1161 | 1162 | 1163 | 1164 | IBProjectSource 1165 | ./Classes/PTKeyComboPanel.h 1166 | 1167 | 1168 | 1169 | 1170 | 0 1171 | IBCocoaFramework 1172 | YES 1173 | 3 1174 | 1175 | NSAdvanced 1176 | {32, 32} 1177 | 1178 | YES 1179 | 1180 | 1181 | -------------------------------------------------------------------------------- /PTHotKeyTest/en.lproj/Credits.rtf: -------------------------------------------------------------------------------- 1 | {\rtf0\ansi{\fonttbl\f0\fswiss Helvetica;} 2 | {\colortbl;\red255\green255\blue255;} 3 | \paperw9840\paperh8400 4 | \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural 5 | 6 | \f0\b\fs24 \cf0 Engineering: 7 | \b0 \ 8 | Some people\ 9 | \ 10 | 11 | \b Human Interface Design: 12 | \b0 \ 13 | Some other people\ 14 | \ 15 | 16 | \b Testing: 17 | \b0 \ 18 | Hopefully not nobody\ 19 | \ 20 | 21 | \b Documentation: 22 | \b0 \ 23 | Whoever\ 24 | \ 25 | 26 | \b With special thanks to: 27 | \b0 \ 28 | Mom\ 29 | } 30 | -------------------------------------------------------------------------------- /PTHotKeyTest/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /PTHotKeyTest/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // PTHotKeyTest 4 | // 5 | // Created by Keith Smiley on 6/11/12. 6 | // Copyright (c) 2012 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | int main(int argc, char *argv[]) 12 | { 13 | return NSApplicationMain(argc, (const char **)argv); 14 | } 15 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | ## How to use 2 | 3 | Feel free to download and decode this project in order to implement it in your own projects. Or follow these loose instructions to configure it. 4 | 5 | ## Instructions for other implementations 6 | 7 | Configure your project as necessary this project is using ARC and sandboxed with no entitlements. 8 | 9 | 1. Import Carbon.framework into your project if it's not already. 10 | 2. Import the PTHotKey files into your project. I like to group them to stay organized. 11 | 3. **If you are using ARC** be sure to add `-fno-objc-arc` under the compiler flags for each of the PTHotKey m files. (This is found by clicking on your Target's settings -> Build Phases -> Compile Sources) 12 | 4. Import the PTHotKey header files into your controlling header file. 13 | 14 | #import "PTKeyComboPanel.h" 15 | #import "PTKeyCombo.h" 16 | #import "PTHotKeyCenter.h" 17 | #import "PTHotKey.h" 18 | 19 | *I found that the project worked correctly with these import statements. Your implementation may vary.* 20 | 21 | 5. Create another view named `PTKeyComboPanel.xib` (the naming matters) file with a single window and change the File Owner's custom class to `PTKeyComboPanel` 22 | 6. Add the rest of the controls to the window dependent on what you want. See the view in this project for the "typical" implementation. **I would recommend copying the window in this project and pasting it into yours. If you choose to configure it yourself there is a hidden element that needs to be bound to the File's Owner.** 23 | 7. Bind your controls to the File Owner. 24 | 8. Implement the controlling code in your m file. See this project for other details. The key is configuring the `@selector` argument being passed to `registerAppActivationKeystrokeWithTarget` with the action you want the shortcut the execute when pressed. In this example it toggles the main window. 25 | 9. ??? 26 | 10. Profit! 27 | 28 | ## Notes 29 | 30 | - This configuration is not perfectly coded there are some things I would change it before implementing this method to be more efficient. *Use it wisely.* 31 | - This configuration saves the hotkey information to `[NSUserDefaults standardUserDefaults]` if you'd like to save it to a different controller or plist you'll need to change those settings. 32 | - The statements in `applicationDidFinishLaunching` register the hotkeys when the application is launched. Be sure to edit that statement's `@selector` as you did before. 33 | - I have yet to configure this example to work with multiple hotkey instances. It would require some sort of configuration to use separate sets of shortcuts for different functions. 34 | - If you would like to configure 1 shortcut to be user customizable for different options use a NSPopupButton with something like this configuration. (This can also be done with an NSArrayController) 35 | 36 | SEL customSelector = NSSelectorFromString([[[button selectedItem] title] stringByAppendingString:@":"]); 37 | Then implement `customSelector` in place of the `@selector` **Be sure to append the colon so it can function correctly.** 38 | 39 | 40 | ## Attributions 41 | 42 | This implementation came from [Brett Terpstra's](http://brettterpstra.com/) fork [nvALT](https://github.com/ttscoff/nv) when searching for a dynamic global shortcut solution. Thank's for being awesome Brett. --------------------------------------------------------------------------------