@ -0,0 +1,30 @@ |
|||||||
|
{ |
||||||
|
"DVTSourceControlWorkspaceBlueprintPrimaryRemoteRepositoryKey" : "79BC31FA35C73FAE9D63749994DC7D1D9E35A66B", |
||||||
|
"DVTSourceControlWorkspaceBlueprintWorkingCopyRepositoryLocationsKey" : { |
||||||
|
|
||||||
|
}, |
||||||
|
"DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : { |
||||||
|
"79BC31FA35C73FAE9D63749994DC7D1D9E35A66B" : 0, |
||||||
|
"F2FE0AAE95F0B87896F2BEE0B176D4FC32D691A3" : 0 |
||||||
|
}, |
||||||
|
"DVTSourceControlWorkspaceBlueprintIdentifierKey" : "FE3C46F0-59C9-4F38-8281-63F46BD16224", |
||||||
|
"DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : { |
||||||
|
"79BC31FA35C73FAE9D63749994DC7D1D9E35A66B" : "Clocker\/", |
||||||
|
"F2FE0AAE95F0B87896F2BEE0B176D4FC32D691A3" : "Clocker\/Clocker\/pop\/" |
||||||
|
}, |
||||||
|
"DVTSourceControlWorkspaceBlueprintNameKey" : "Clocker", |
||||||
|
"DVTSourceControlWorkspaceBlueprintVersion" : 204, |
||||||
|
"DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "Clocker.xcodeproj", |
||||||
|
"DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [ |
||||||
|
{ |
||||||
|
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/Abhishaker17\/Clocker.git", |
||||||
|
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git", |
||||||
|
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "79BC31FA35C73FAE9D63749994DC7D1D9E35A66B" |
||||||
|
}, |
||||||
|
{ |
||||||
|
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "https:\/\/github.com\/facebook\/pop.git", |
||||||
|
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git", |
||||||
|
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "F2FE0AAE95F0B87896F2BEE0B176D4FC32D691A3" |
||||||
|
} |
||||||
|
] |
||||||
|
} |
@ -0,0 +1,18 @@ |
|||||||
|
# Xcode |
||||||
|
build/* |
||||||
|
*.pbxuser |
||||||
|
!default.pbxuser |
||||||
|
*.mode1v3 |
||||||
|
!default.mode1v3 |
||||||
|
*.mode2v3 |
||||||
|
!default.mode2v3 |
||||||
|
*.perspectivev3 |
||||||
|
!default.perspectivev3 |
||||||
|
*.xcworkspace |
||||||
|
!default.xcworkspace |
||||||
|
xcuserdata |
||||||
|
profile |
||||||
|
*.moved-aside |
||||||
|
|
||||||
|
## Ignore incredibly annoying .DS_Store files |
||||||
|
.DS_Store |
@ -0,0 +1,28 @@ |
|||||||
|
//
|
||||||
|
// IKAppDelegate.h
|
||||||
|
// ShortcutRecorderDemo
|
||||||
|
//
|
||||||
|
// Created by ILya Kulakov on 18.01.13.
|
||||||
|
// Copyright (c) 2013 Ilya Kulakov. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h> |
||||||
|
|
||||||
|
|
||||||
|
@interface IKAppDelegate : NSObject <NSApplicationDelegate> |
||||||
|
|
||||||
|
@property (assign) IBOutlet NSWindow *window; |
||||||
|
|
||||||
|
@property (assign) IBOutlet NSButton *pingButton; |
||||||
|
|
||||||
|
@property (assign) IBOutlet NSMenuItem *pingItem; |
||||||
|
|
||||||
|
- (IBAction)showIBAutoLayout:(id)aSender; |
||||||
|
|
||||||
|
- (IBAction)showCodeAutoLayout:(id)aSender; |
||||||
|
|
||||||
|
- (IBAction)showAutoresizingMasks:(id)aSender; |
||||||
|
|
||||||
|
- (IBAction)ping:(id)aSender; |
||||||
|
|
||||||
|
@end |
@ -0,0 +1,130 @@ |
|||||||
|
// |
||||||
|
// IKAppDelegate.m |
||||||
|
// ShortcutRecorderDemo |
||||||
|
// |
||||||
|
// Created by Ilya Kulakov on 18.01.13. |
||||||
|
// Copyright (c) 2013 Ilya Kulakov. All rights reserved. |
||||||
|
// |
||||||
|
|
||||||
|
#import <ShortcutRecorder/ShortcutRecorder.h> |
||||||
|
#import <PTHotKey/PTHotKeyCenter.h> |
||||||
|
#import <PTHotKey/PTHotKey+ShortcutRecorder.h> |
||||||
|
#import "IKAppDelegate.h" |
||||||
|
#import "IKIBAutoLayoutWindowController.h" |
||||||
|
#import "IKCodeAutoLayoutWindowController.h" |
||||||
|
#import "IKIBAutoresizingMasksWindowController.h" |
||||||
|
|
||||||
|
|
||||||
|
@implementation IKAppDelegate |
||||||
|
{ |
||||||
|
IKIBAutoLayoutWindowController *_ibAutoLayoutWindowController; |
||||||
|
IKCodeAutoLayoutWindowController *_codeAutoLayoutWindowController; |
||||||
|
IKIBAutoresizingMasksWindowController *_ibAutoresizingMasksWindowController; |
||||||
|
} |
||||||
|
|
||||||
|
- (void)dealloc |
||||||
|
{ |
||||||
|
[[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.globalPing"]; |
||||||
|
} |
||||||
|
|
||||||
|
#pragma mark Methods |
||||||
|
|
||||||
|
- (IBAction)showIBAutoLayout:(id)aSender |
||||||
|
{ |
||||||
|
if (!_ibAutoLayoutWindowController) |
||||||
|
_ibAutoLayoutWindowController = [[IKIBAutoLayoutWindowController alloc] initWithWindowNibName:@"IKIBAutoLayoutWindowController"]; |
||||||
|
|
||||||
|
[_ibAutoLayoutWindowController showWindow:aSender]; |
||||||
|
} |
||||||
|
|
||||||
|
- (void)showCodeAutoLayout:(id)aSender |
||||||
|
{ |
||||||
|
if (!_codeAutoLayoutWindowController) |
||||||
|
_codeAutoLayoutWindowController = [[IKCodeAutoLayoutWindowController alloc] initWithWindowNibName:@"IKCodeAutoLayoutWindowController"]; |
||||||
|
|
||||||
|
[_codeAutoLayoutWindowController showWindow:aSender]; |
||||||
|
} |
||||||
|
|
||||||
|
- (void)showAutoresizingMasks:(id)aSender |
||||||
|
{ |
||||||
|
if (!_ibAutoresizingMasksWindowController) |
||||||
|
_ibAutoresizingMasksWindowController = [[IKIBAutoresizingMasksWindowController alloc] initWithWindowNibName:@"IKIBAutoresizingMasksWindowController"]; |
||||||
|
|
||||||
|
[_ibAutoresizingMasksWindowController showWindow:aSender]; |
||||||
|
} |
||||||
|
|
||||||
|
- (IBAction)ping:(id)aSender |
||||||
|
{ |
||||||
|
[[NSSound soundNamed:@"Ping"] play]; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
#pragma mark NSApplicationDelegate |
||||||
|
|
||||||
|
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender |
||||||
|
{ |
||||||
|
return YES; |
||||||
|
} |
||||||
|
|
||||||
|
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification |
||||||
|
{ |
||||||
|
// Insert code here to initialize your application |
||||||
|
} |
||||||
|
|
||||||
|
- (void)applicationDidBecomeActive:(NSNotification *)aNotification |
||||||
|
{ |
||||||
|
[self.window makeKeyAndOrderFront:self]; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
#pragma mark NSObject |
||||||
|
|
||||||
|
- (void)awakeFromNib |
||||||
|
{ |
||||||
|
NSUserDefaultsController *defaults = [NSUserDefaultsController sharedUserDefaultsController]; |
||||||
|
|
||||||
|
[self.pingButton bind:@"keyEquivalent" |
||||||
|
toObject:defaults |
||||||
|
withKeyPath:@"values.ping" |
||||||
|
options:@{NSValueTransformerBindingOption: [SRKeyEquivalentTransformer new]}]; |
||||||
|
[self.pingButton bind:@"keyEquivalentModifierMask" |
||||||
|
toObject:defaults |
||||||
|
withKeyPath:@"values.ping" |
||||||
|
options:@{NSValueTransformerBindingOption: [SRKeyEquivalentModifierMaskTransformer new]}]; |
||||||
|
|
||||||
|
[self.pingItem bind:@"keyEquivalent" |
||||||
|
toObject:defaults |
||||||
|
withKeyPath:@"values.pingItem" |
||||||
|
options:@{NSValueTransformerBindingOption: [SRKeyEquivalentTransformer new]}]; |
||||||
|
[self.pingItem bind:@"keyEquivalentModifierMask" |
||||||
|
toObject:defaults |
||||||
|
withKeyPath:@"values.pingItem" |
||||||
|
options:@{NSValueTransformerBindingOption: [SRKeyEquivalentModifierMaskTransformer new]}]; |
||||||
|
|
||||||
|
[defaults addObserver:self forKeyPath:@"values.globalPing" options:NSKeyValueObservingOptionInitial context:NULL]; |
||||||
|
} |
||||||
|
|
||||||
|
- (void)observeValueForKeyPath:(NSString *)aKeyPath ofObject:(id)anObject change:(NSDictionary *)aChange context:(void *)aContext |
||||||
|
{ |
||||||
|
if ([aKeyPath isEqualToString:@"values.globalPing"]) |
||||||
|
{ |
||||||
|
PTHotKeyCenter *hotKeyCenter = [PTHotKeyCenter sharedCenter]; |
||||||
|
PTHotKey *oldHotKey = [hotKeyCenter hotKeyWithIdentifier:aKeyPath]; |
||||||
|
[hotKeyCenter unregisterHotKey:oldHotKey]; |
||||||
|
|
||||||
|
NSDictionary *newShortcut = [anObject valueForKeyPath:aKeyPath]; |
||||||
|
|
||||||
|
if (newShortcut && (NSNull *)newShortcut != [NSNull null]) |
||||||
|
{ |
||||||
|
PTHotKey *newHotKey = [PTHotKey hotKeyWithIdentifier:aKeyPath |
||||||
|
keyCombo:newShortcut |
||||||
|
target:self |
||||||
|
action:@selector(ping:)]; |
||||||
|
[hotKeyCenter registerHotKey:newHotKey]; |
||||||
|
} |
||||||
|
} |
||||||
|
else |
||||||
|
[super observeValueForKeyPath:aKeyPath ofObject:anObject change:aChange context:aContext]; |
||||||
|
} |
||||||
|
|
||||||
|
@end |
@ -0,0 +1,15 @@ |
|||||||
|
//
|
||||||
|
// IKCodeAutoLayoutWindowController.h
|
||||||
|
// ShortcutRecorderDemo
|
||||||
|
//
|
||||||
|
// Created by Ilya Kulakov on 21.01.13.
|
||||||
|
// Copyright (c) 2013 Ilya Kulakov. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h> |
||||||
|
#import "IKDemoWindowController.h" |
||||||
|
|
||||||
|
|
||||||
|
@interface IKCodeAutoLayoutWindowController : IKDemoWindowController |
||||||
|
|
||||||
|
@end |
@ -0,0 +1,114 @@ |
|||||||
|
// |
||||||
|
// IKCodeAutoLayoutWindowController.m |
||||||
|
// ShortcutRecorderDemo |
||||||
|
// |
||||||
|
// Created by Ilya Kulakov on 21.01.13. |
||||||
|
// Copyright (c) 2013 Ilya Kulakov. All rights reserved. |
||||||
|
// |
||||||
|
|
||||||
|
#import "IKCodeAutoLayoutWindowController.h" |
||||||
|
|
||||||
|
|
||||||
|
@implementation IKCodeAutoLayoutWindowController |
||||||
|
|
||||||
|
#pragma mark NSWindowController |
||||||
|
|
||||||
|
- (void)awakeFromNib |
||||||
|
{ |
||||||
|
[super awakeFromNib]; |
||||||
|
|
||||||
|
SRRecorderControl *pingShortcutRecorder = [[SRRecorderControl alloc] initWithFrame:NSZeroRect]; |
||||||
|
pingShortcutRecorder.delegate = self; |
||||||
|
pingShortcutRecorder.enabled = NO; |
||||||
|
[pingShortcutRecorder setAllowedModifierFlags:NSShiftKeyMask | NSAlternateKeyMask | NSCommandKeyMask |
||||||
|
requiredModifierFlags:0 |
||||||
|
allowsEmptyModifierFlags:NO]; |
||||||
|
SRRecorderControl *globalPingShortcutRecorder = [[SRRecorderControl alloc] initWithFrame:NSZeroRect]; |
||||||
|
globalPingShortcutRecorder.delegate = self; |
||||||
|
SRRecorderControl *pingItemShortcutRecorder = [[SRRecorderControl alloc] initWithFrame:NSZeroRect]; |
||||||
|
pingItemShortcutRecorder.delegate = self; |
||||||
|
NSTextField *pingLabel = [[NSTextField alloc] initWithFrame:NSZeroRect]; |
||||||
|
pingLabel.translatesAutoresizingMaskIntoConstraints = NO; |
||||||
|
pingLabel.font = [NSFont systemFontOfSize:13]; |
||||||
|
pingLabel.editable = NO; |
||||||
|
pingLabel.selectable = NO; |
||||||
|
pingLabel.bezeled = NO; |
||||||
|
pingLabel.alignment = NSRightTextAlignment; |
||||||
|
pingLabel.stringValue = @"Ping Button:"; |
||||||
|
pingLabel.drawsBackground = NO; |
||||||
|
[pingLabel setContentHuggingPriority:NSLayoutPriorityDefaultHigh forOrientation:NSLayoutConstraintOrientationHorizontal]; |
||||||
|
NSTextField *globalPingLabel = [[NSTextField alloc] initWithFrame:NSZeroRect]; |
||||||
|
globalPingLabel.translatesAutoresizingMaskIntoConstraints = NO; |
||||||
|
globalPingLabel.font = [NSFont systemFontOfSize:13]; |
||||||
|
globalPingLabel.editable = NO; |
||||||
|
globalPingLabel.selectable = NO; |
||||||
|
globalPingLabel.bezeled = NO; |
||||||
|
globalPingLabel.alignment = NSRightTextAlignment; |
||||||
|
globalPingLabel.stringValue = @"Global Ping:"; |
||||||
|
globalPingLabel.drawsBackground = NO; |
||||||
|
[globalPingLabel setContentHuggingPriority:NSLayoutPriorityDefaultHigh forOrientation:NSLayoutConstraintOrientationHorizontal]; |
||||||
|
NSTextField *pingItemLabel = [[NSTextField alloc] initWithFrame:NSZeroRect]; |
||||||
|
pingItemLabel.translatesAutoresizingMaskIntoConstraints = NO; |
||||||
|
pingItemLabel.font = [NSFont systemFontOfSize:13]; |
||||||
|
pingItemLabel.editable = NO; |
||||||
|
pingItemLabel.selectable = NO; |
||||||
|
pingItemLabel.bezeled = NO; |
||||||
|
pingItemLabel.alignment = NSRightTextAlignment; |
||||||
|
pingItemLabel.stringValue = @"Ping Item:"; |
||||||
|
pingItemLabel.drawsBackground = NO; |
||||||
|
[pingItemLabel setContentHuggingPriority:NSLayoutPriorityDefaultHigh forOrientation:NSLayoutConstraintOrientationHorizontal]; |
||||||
|
|
||||||
|
NSView *v = self.window.contentView; |
||||||
|
[v addSubview:pingShortcutRecorder]; |
||||||
|
[v addSubview:globalPingShortcutRecorder]; |
||||||
|
[v addSubview:pingItemShortcutRecorder]; |
||||||
|
[v addSubview:pingLabel]; |
||||||
|
[v addSubview:globalPingLabel]; |
||||||
|
[v addSubview:pingItemLabel]; |
||||||
|
|
||||||
|
NSDictionary *views = NSDictionaryOfVariableBindings(pingShortcutRecorder, |
||||||
|
globalPingShortcutRecorder, |
||||||
|
pingItemShortcutRecorder, |
||||||
|
pingLabel, |
||||||
|
globalPingLabel, |
||||||
|
pingItemLabel); |
||||||
|
[v addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[pingLabel(==80)]-[pingShortcutRecorder(>=100)]-|" |
||||||
|
options:NSLayoutFormatAlignAllBaseline |
||||||
|
metrics:nil |
||||||
|
views:views]]; |
||||||
|
[v addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[globalPingLabel(==pingLabel)]-[globalPingShortcutRecorder(==pingShortcutRecorder)]-|" |
||||||
|
options:NSLayoutFormatAlignAllBaseline |
||||||
|
metrics:nil |
||||||
|
views:views]]; |
||||||
|
[v addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[pingItemLabel(==pingLabel)]-[pingItemShortcutRecorder(==pingShortcutRecorder)]-|" |
||||||
|
options:NSLayoutFormatAlignAllBaseline |
||||||
|
metrics:nil |
||||||
|
views:views]]; |
||||||
|
[v addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[pingShortcutRecorder(==25)]-[globalPingShortcutRecorder(==25)]-[pingItemShortcutRecorder(==25)]-|" |
||||||
|
options:0 |
||||||
|
metrics:nil |
||||||
|
views:views]]; |
||||||
|
|
||||||
|
NSUserDefaultsController *defaults = [NSUserDefaultsController sharedUserDefaultsController]; |
||||||
|
self.pingShortcutRecorder = pingShortcutRecorder; |
||||||
|
[self.pingShortcutRecorder bind:NSValueBinding |
||||||
|
toObject:defaults |
||||||
|
withKeyPath:@"values.ping" |
||||||
|
options:nil]; |
||||||
|
[self.pingShortcutRecorder bind:NSEnabledBinding |
||||||
|
toObject:defaults |
||||||
|
withKeyPath:@"values.isPingItemEnabled" |
||||||
|
options:nil]; |
||||||
|
self.globalPingShortcutRecorder = globalPingShortcutRecorder; |
||||||
|
[self.globalPingShortcutRecorder bind:NSValueBinding |
||||||
|
toObject:defaults |
||||||
|
withKeyPath:@"values.globalPing" |
||||||
|
options:nil]; |
||||||
|
self.pingItemShortcutRecorder = pingItemShortcutRecorder; |
||||||
|
[self.pingItemShortcutRecorder bind:NSValueBinding |
||||||
|
toObject:defaults |
||||||
|
withKeyPath:@"values.pingItem" |
||||||
|
options:nil]; |
||||||
|
} |
||||||
|
|
||||||
|
@end |
@ -0,0 +1,21 @@ |
|||||||
|
//
|
||||||
|
// IKDemoWindowController.h
|
||||||
|
// ShortcutRecorderDemo
|
||||||
|
//
|
||||||
|
// Created by Ilya Kulakov on 18.01.13.
|
||||||
|
// Copyright (c) 2013 Ilya Kulakov. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h> |
||||||
|
#import <ShortcutRecorder/ShortcutRecorder.h> |
||||||
|
|
||||||
|
|
||||||
|
@interface IKDemoWindowController : NSWindowController <SRRecorderControlDelegate, SRValidatorDelegate> |
||||||
|
|
||||||
|
@property (weak) IBOutlet SRRecorderControl *pingShortcutRecorder; |
||||||
|
|
||||||
|
@property (weak) IBOutlet SRRecorderControl *globalPingShortcutRecorder; |
||||||
|
|
||||||
|
@property (weak) IBOutlet SRRecorderControl *pingItemShortcutRecorder; |
||||||
|
|
||||||
|
@end |
@ -0,0 +1,126 @@ |
|||||||
|
// |
||||||
|
// IKDemoWindowController.m |
||||||
|
// ShortcutRecorderDemo |
||||||
|
// |
||||||
|
// Created by Ilya Kulakov on 18.01.13. |
||||||
|
// Copyright (c) 2013 Ilya Kulakov. All rights reserved. |
||||||
|
// |
||||||
|
|
||||||
|
#import <PTHotKey/PTHotKeyCenter.h> |
||||||
|
#import "IKDemoWindowController.h" |
||||||
|
|
||||||
|
|
||||||
|
@implementation IKDemoWindowController |
||||||
|
{ |
||||||
|
SRValidator *_validator; |
||||||
|
} |
||||||
|
|
||||||
|
#pragma mark SRRecorderControlDelegate |
||||||
|
|
||||||
|
- (BOOL)shortcutRecorder:(SRRecorderControl *)aRecorder canRecordShortcut:(NSDictionary *)aShortcut |
||||||
|
{ |
||||||
|
__autoreleasing NSError *error = nil; |
||||||
|
BOOL isTaken = [_validator isKeyCode:[aShortcut[SRShortcutKeyCode] unsignedShortValue] andFlagsTaken:[aShortcut[SRShortcutModifierFlagsKey] unsignedIntegerValue] error:&error]; |
||||||
|
|
||||||
|
if (isTaken) |
||||||
|
{ |
||||||
|
NSBeep(); |
||||||
|
[self presentError:error |
||||||
|
modalForWindow:self.window |
||||||
|
delegate:nil |
||||||
|
didPresentSelector:NULL |
||||||
|
contextInfo:NULL]; |
||||||
|
} |
||||||
|
|
||||||
|
return !isTaken; |
||||||
|
} |
||||||
|
|
||||||
|
- (BOOL)shortcutRecorderShouldBeginRecording:(SRRecorderControl *)aRecorder |
||||||
|
{ |
||||||
|
[[PTHotKeyCenter sharedCenter] pause]; |
||||||
|
return YES; |
||||||
|
} |
||||||
|
|
||||||
|
- (void)shortcutRecorderDidEndRecording:(SRRecorderControl *)aRecorder |
||||||
|
{ |
||||||
|
[[PTHotKeyCenter sharedCenter] resume]; |
||||||
|
} |
||||||
|
|
||||||
|
- (BOOL)shortcutRecorder:(SRRecorderControl *)aRecorder shouldUnconditionallyAllowModifierFlags:(NSEventModifierFlags)aModifierFlags forKeyCode:(unsigned short)aKeyCode |
||||||
|
{ |
||||||
|
// Keep required flags required. |
||||||
|
if ((aModifierFlags & aRecorder.requiredModifierFlags) != aRecorder.requiredModifierFlags) |
||||||
|
return NO; |
||||||
|
|
||||||
|
// Don't allow disallowed flags. |
||||||
|
if ((aModifierFlags & aRecorder.allowedModifierFlags) != aModifierFlags) |
||||||
|
return NO; |
||||||
|
|
||||||
|
switch (aKeyCode) |
||||||
|
{ |
||||||
|
case kVK_F1: |
||||||
|
case kVK_F2: |
||||||
|
case kVK_F3: |
||||||
|
case kVK_F4: |
||||||
|
case kVK_F5: |
||||||
|
case kVK_F6: |
||||||
|
case kVK_F7: |
||||||
|
case kVK_F8: |
||||||
|
case kVK_F9: |
||||||
|
case kVK_F10: |
||||||
|
case kVK_F11: |
||||||
|
case kVK_F12: |
||||||
|
case kVK_F13: |
||||||
|
case kVK_F14: |
||||||
|
case kVK_F15: |
||||||
|
case kVK_F16: |
||||||
|
case kVK_F17: |
||||||
|
case kVK_F18: |
||||||
|
case kVK_F19: |
||||||
|
case kVK_F20: |
||||||
|
return YES; |
||||||
|
default: |
||||||
|
return NO; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
#pragma mark SRValidatorDelegate |
||||||
|
|
||||||
|
- (BOOL)shortcutValidator:(SRValidator *)aValidator isKeyCode:(unsigned short)aKeyCode andFlagsTaken:(NSEventModifierFlags)aFlags reason:(NSString **)outReason |
||||||
|
{ |
||||||
|
#define IS_TAKEN(aRecorder) (recorder != (aRecorder) && SRShortcutEqualToShortcut(shortcut, [(aRecorder) objectValue])) |
||||||
|
SRRecorderControl *recorder = (SRRecorderControl *)self.window.firstResponder; |
||||||
|
|
||||||
|
if (![recorder isKindOfClass:[SRRecorderControl class]]) |
||||||
|
return NO; |
||||||
|
|
||||||
|
NSDictionary *shortcut = SRShortcutWithCocoaModifierFlagsAndKeyCode(aFlags, aKeyCode); |
||||||
|
|
||||||
|
if (IS_TAKEN(_pingShortcutRecorder) || |
||||||
|
IS_TAKEN(_globalPingShortcutRecorder) || |
||||||
|
IS_TAKEN(_pingItemShortcutRecorder)) |
||||||
|
{ |
||||||
|
*outReason = @"it's already used. To use this shortcut, first remove or change the other shortcut"; |
||||||
|
return YES; |
||||||
|
} |
||||||
|
else |
||||||
|
return NO; |
||||||
|
#undef IS_TAKEN |
||||||
|
} |
||||||
|
|
||||||
|
- (BOOL)shortcutValidatorShouldCheckMenu:(SRValidator *)aValidator |
||||||
|
{ |
||||||
|
return YES; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
#pragma mark NSObject |
||||||
|
|
||||||
|
- (void)awakeFromNib |
||||||
|
{ |
||||||
|
[super awakeFromNib]; |
||||||
|
_validator = [[SRValidator alloc] initWithDelegate:self]; |
||||||
|
} |
||||||
|
|
||||||
|
@end |
@ -0,0 +1,15 @@ |
|||||||
|
//
|
||||||
|
// IKIBAutoLayoutWindowController.h
|
||||||
|
// ShortcutRecorderDemo
|
||||||
|
//
|
||||||
|
// Created by Ilya Kulakov on 18.01.13.
|
||||||
|
// Copyright (c) 2013 Ilya Kulakov. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h> |
||||||
|
#import "IKDemoWindowController.h" |
||||||
|
|
||||||
|
|
||||||
|
@interface IKIBAutoLayoutWindowController : IKDemoWindowController |
||||||
|
|
||||||
|
@end |
@ -0,0 +1,43 @@ |
|||||||
|
// |
||||||
|
// IKIBAutoLayoutWindowController.m |
||||||
|
// ShortcutRecorderDemo |
||||||
|
// |
||||||
|
// Created by Ilya Kulakov on 18.01.13. |
||||||
|
// Copyright (c) 2013 Ilya Kulakov. All rights reserved. |
||||||
|
// |
||||||
|
|
||||||
|
#import "IKIBAutoLayoutWindowController.h" |
||||||
|
|
||||||
|
|
||||||
|
@implementation IKIBAutoLayoutWindowController |
||||||
|
|
||||||
|
#pragma mark NSObject |
||||||
|
|
||||||
|
- (void)awakeFromNib |
||||||
|
{ |
||||||
|
[super awakeFromNib]; |
||||||
|
|
||||||
|
NSUserDefaultsController *defaults = [NSUserDefaultsController sharedUserDefaultsController]; |
||||||
|
|
||||||
|
[self.pingShortcutRecorder bind:NSValueBinding |
||||||
|
toObject:defaults |
||||||
|
withKeyPath:@"values.ping" |
||||||
|
options:nil]; |
||||||
|
[self.pingShortcutRecorder bind:NSEnabledBinding |
||||||
|
toObject:defaults |
||||||
|
withKeyPath:@"values.isPingItemEnabled" |
||||||
|
options:nil]; |
||||||
|
[self.pingShortcutRecorder setAllowedModifierFlags:NSShiftKeyMask | NSAlternateKeyMask | NSCommandKeyMask |
||||||
|
requiredModifierFlags:0 |
||||||
|
allowsEmptyModifierFlags:NO]; |
||||||
|
[self.globalPingShortcutRecorder bind:NSValueBinding |
||||||
|
toObject:defaults |
||||||
|
withKeyPath:@"values.globalPing" |
||||||
|
options:nil]; |
||||||
|
[self.pingItemShortcutRecorder bind:NSValueBinding |
||||||
|
toObject:defaults |
||||||
|
withKeyPath:@"values.pingItem" |
||||||
|
options:nil]; |
||||||
|
} |
||||||
|
|
||||||
|
@end |
@ -0,0 +1,15 @@ |
|||||||
|
//
|
||||||
|
// IKIBAutoresizingMasksWindowController.h
|
||||||
|
// ShortcutRecorderDemo
|
||||||
|
//
|
||||||
|
// Created by Ilya Kulakov on 20.01.13.
|
||||||
|
// Copyright (c) 2013 Ilya Kulakov. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h> |
||||||
|
#import "IKDemoWindowController.h" |
||||||
|
|
||||||
|
|
||||||
|
@interface IKIBAutoresizingMasksWindowController : IKDemoWindowController |
||||||
|
|
||||||
|
@end |
@ -0,0 +1,67 @@ |
|||||||
|
// |
||||||
|
// IKIBAutoresizingMasksWindowController.m |
||||||
|
// ShortcutRecorderDemo |
||||||
|
// |
||||||
|
// Created by Ilya Kulakov on 20.01.13. |
||||||
|
// Copyright (c) 2013 Ilya Kulakov. All rights reserved. |
||||||
|
// |
||||||
|
|
||||||
|
#import "IKIBAutoresizingMasksWindowController.h" |
||||||
|
|
||||||
|
|
||||||
|
@implementation IKIBAutoresizingMasksWindowController |
||||||
|
|
||||||
|
- (void)dealloc |
||||||
|
{ |
||||||
|
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; |
||||||
|
[defaults removeObserver:self forKeyPath:@"ping"]; |
||||||
|
[defaults removeObserver:self forKeyPath:@"globalPing"]; |
||||||
|
[defaults removeObserver:self forKeyPath:@"pingItem"]; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
#pragma mark SRRecorderControlDelegate |
||||||
|
|
||||||
|
- (void)shortcutRecorderDidEndRecording:(SRRecorderControl *)aRecorder |
||||||
|
{ |
||||||
|
if (aRecorder == self.pingShortcutRecorder) |
||||||
|
[[NSUserDefaults standardUserDefaults] setValue:aRecorder.objectValue forKey:@"ping"]; |
||||||
|
else if (aRecorder == self.globalPingShortcutRecorder) |
||||||
|
[[NSUserDefaults standardUserDefaults] setValue:aRecorder.objectValue forKey:@"globalPing"]; |
||||||
|
else if (aRecorder == self.pingItemShortcutRecorder) |
||||||
|
[[NSUserDefaults standardUserDefaults] setValue:aRecorder.objectValue forKey:@"pingItem"]; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
#pragma mark NSObject |
||||||
|
|
||||||
|
- (void)awakeFromNib |
||||||
|
{ |
||||||
|
[super awakeFromNib]; |
||||||
|
|
||||||
|
[self.pingShortcutRecorder setAllowedModifierFlags:NSShiftKeyMask | NSAlternateKeyMask | NSCommandKeyMask |
||||||
|
requiredModifierFlags:0 |
||||||
|
allowsEmptyModifierFlags:NO]; |
||||||
|
|
||||||
|
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; |
||||||
|
[defaults addObserver:self forKeyPath:@"ping" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionInitial context:NULL]; |
||||||
|
[defaults addObserver:self forKeyPath:@"globalPing" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionInitial context:NULL]; |
||||||
|
[defaults addObserver:self forKeyPath:@"pingItem" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionInitial context:NULL]; |
||||||
|
[defaults addObserver:self forKeyPath:@"isPingItemEnabled" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionInitial context:NULL]; |
||||||
|
} |
||||||
|
|
||||||
|
- (void)observeValueForKeyPath:(NSString *)aKeyPath ofObject:(id)anObject change:(NSDictionary *)aChange context:(void *)aContext |
||||||
|
{ |
||||||
|
if ([aKeyPath isEqualToString:@"ping"]) |
||||||
|
self.pingShortcutRecorder.objectValue = aChange[NSKeyValueChangeNewKey]; |
||||||
|
else if ([aKeyPath isEqualToString:@"globalPing"]) |
||||||
|
self.globalPingShortcutRecorder.objectValue = aChange[NSKeyValueChangeNewKey]; |
||||||
|
else if ([aKeyPath isEqualToString:@"pingItem"]) |
||||||
|
self.pingItemShortcutRecorder.objectValue = aChange[NSKeyValueChangeNewKey]; |
||||||
|
else if ([aKeyPath isEqualToString:@"isPingItemEnabled"]) |
||||||
|
self.pingShortcutRecorder.enabled = ((id)aChange[NSKeyValueChangeNewKey] != [NSNull null]) && [aChange[NSKeyValueChangeNewKey] boolValue]; |
||||||
|
else |
||||||
|
[super observeValueForKeyPath:aKeyPath ofObject:anObject change:aChange context:aContext]; |
||||||
|
} |
||||||
|
|
||||||
|
@end |
@ -0,0 +1,36 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> |
||||||
|
<plist version="1.0"> |
||||||
|
<dict> |
||||||
|
<key>CFBundleDevelopmentRegion</key> |
||||||
|
<string>en</string> |
||||||
|
<key>CFBundleExecutable</key> |
||||||
|
<string>${EXECUTABLE_NAME}</string> |
||||||
|
<key>CFBundleIconFile</key> |
||||||
|
<string></string> |
||||||
|
<key>CFBundleIdentifier</key> |
||||||
|
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> |
||||||
|
<key>CFBundleInfoDictionaryVersion</key> |
||||||
|
<string>6.0</string> |
||||||
|
<key>CFBundleName</key> |
||||||
|
<string>${PRODUCT_NAME}</string> |
||||||
|
<key>CFBundlePackageType</key> |
||||||
|
<string>APPL</string> |
||||||
|
<key>CFBundleShortVersionString</key> |
||||||
|
<string>1.0</string> |
||||||
|
<key>CFBundleSignature</key> |
||||||
|
<string>????</string> |
||||||
|
<key>CFBundleVersion</key> |
||||||
|
<string>1</string> |
||||||
|
<key>LSApplicationCategoryType</key> |
||||||
|
<string>public.app-category.developer-tools</string> |
||||||
|
<key>LSMinimumSystemVersion</key> |
||||||
|
<string>${MACOSX_DEPLOYMENT_TARGET}</string> |
||||||
|
<key>NSHumanReadableCopyright</key> |
||||||
|
<string>Copyright © 2013 Ilya Kulakov. All rights reserved.</string> |
||||||
|
<key>NSMainNibFile</key> |
||||||
|
<string>MainMenu</string> |
||||||
|
<key>NSPrincipalClass</key> |
||||||
|
<string>NSApplication</string> |
||||||
|
</dict> |
||||||
|
</plist> |
@ -0,0 +1,7 @@ |
|||||||
|
// |
||||||
|
// Prefix header for all source files of the 'ShortcutRecorderDemo' target in the 'ShortcutRecorderDemo' project |
||||||
|
// |
||||||
|
|
||||||
|
#ifdef __OBJC__ |
||||||
|
#import <Cocoa/Cocoa.h> |
||||||
|
#endif |
@ -0,0 +1,29 @@ |
|||||||
|
{\rtf0\ansi{\fonttbl\f0\fswiss Helvetica;} |
||||||
|
{\colortbl;\red255\green255\blue255;} |
||||||
|
\paperw9840\paperh8400 |
||||||
|
\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural |
||||||
|
|
||||||
|
\f0\b\fs24 \cf0 Engineering: |
||||||
|
\b0 \ |
||||||
|
Some people\ |
||||||
|
\ |
||||||
|
|
||||||
|
\b Human Interface Design: |
||||||
|
\b0 \ |
||||||
|
Some other people\ |
||||||
|
\ |
||||||
|
|
||||||
|
\b Testing: |
||||||
|
\b0 \ |
||||||
|
Hopefully not nobody\ |
||||||
|
\ |
||||||
|
|
||||||
|
\b Documentation: |
||||||
|
\b0 \ |
||||||
|
Whoever\ |
||||||
|
\ |
||||||
|
|
||||||
|
\b With special thanks to: |
||||||
|
\b0 \ |
||||||
|
Mom\ |
||||||
|
} |
@ -0,0 +1,26 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?> |
||||||
|
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="6250" systemVersion="14A389" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES"> |
||||||
|
<dependencies> |
||||||
|
<deployment identifier="macosx"/> |
||||||
|
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="6250"/> |
||||||
|
</dependencies> |
||||||
|
<objects> |
||||||
|
<customObject id="-2" userLabel="File's Owner" customClass="IKCodeAutoLayoutWindowController"> |
||||||
|
<connections> |
||||||
|
<outlet property="window" destination="3" id="26"/> |
||||||
|
</connections> |
||||||
|
</customObject> |
||||||
|
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/> |
||||||
|
<customObject id="-3" userLabel="Application" customClass="NSObject"/> |
||||||
|
<window title="Code Auto Layout Demo" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" hidesOnDeactivate="YES" oneShot="NO" showsToolbarButton="NO" frameAutosaveName="Code Auto Layout Demo" animationBehavior="default" id="3" customClass="NSPanel"> |
||||||
|
<windowStyleMask key="styleMask" titled="YES" closable="YES" resizable="YES" utility="YES"/> |
||||||
|
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/> |
||||||
|
<rect key="contentRect" x="196" y="112" width="327" height="98"/> |
||||||
|
<rect key="screenRect" x="0.0" y="0.0" width="1366" height="745"/> |
||||||
|
<view key="contentView" id="4"> |
||||||
|
<rect key="frame" x="0.0" y="0.0" width="327" height="98"/> |
||||||
|
<autoresizingMask key="autoresizingMask"/> |
||||||
|
</view> |
||||||
|
</window> |
||||||
|
</objects> |
||||||
|
</document> |
@ -0,0 +1,116 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?> |
||||||
|
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="9532" systemVersion="15D21" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES"> |
||||||
|
<dependencies> |
||||||
|
<deployment identifier="macosx"/> |
||||||
|
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="9532"/> |
||||||
|
</dependencies> |
||||||
|
<objects> |
||||||
|
<customObject id="-2" userLabel="File's Owner" customClass="IKIBAutoLayoutWindowController"> |
||||||
|
<connections> |
||||||
|
<outlet property="globalPingShortcutRecorder" destination="13" id="90"/> |
||||||
|
<outlet property="pingItemShortcutRecorder" destination="141" id="162"/> |
||||||
|
<outlet property="pingShortcutRecorder" destination="8" id="89"/> |
||||||
|
<outlet property="window" destination="5" id="7"/> |
||||||
|
</connections> |
||||||
|
</customObject> |
||||||
|
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/> |
||||||
|
<customObject id="-3" userLabel="Application" customClass="NSObject"/> |
||||||
|
<window title="Interface Builder Auto Layout Demo" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" hidesOnDeactivate="YES" oneShot="NO" showsToolbarButton="NO" frameAutosaveName="Interface Builder Auto Layout Demo" animationBehavior="default" id="5" customClass="NSPanel"> |
||||||
|
<windowStyleMask key="styleMask" titled="YES" closable="YES" resizable="YES" utility="YES"/> |
||||||
|
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/> |
||||||
|
<rect key="contentRect" x="196" y="112" width="411" height="131"/> |
||||||
|
<rect key="screenRect" x="0.0" y="0.0" width="2560" height="1417"/> |
||||||
|
<view key="contentView" wantsLayer="YES" id="6"> |
||||||
|
<rect key="frame" x="0.0" y="0.0" width="411" height="131"/> |
||||||
|
<autoresizingMask key="autoresizingMask"/> |
||||||
|
<subviews> |
||||||
|
<customView translatesAutoresizingMaskIntoConstraints="NO" id="8" customClass="SRRecorderControl"> |
||||||
|
<rect key="frame" x="109" y="86" width="282" height="25"/> |
||||||
|
<constraints> |
||||||
|
<constraint firstAttribute="height" constant="25" id="44v-Ku-Fxy"/> |
||||||
|
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="100" id="pw5-ZW-h0a"/> |
||||||
|
</constraints> |
||||||
|
<userDefinedRuntimeAttributes> |
||||||
|
<userDefinedRuntimeAttribute type="number" keyPath="allowedModifierFlags"> |
||||||
|
<integer key="value" value="2"/> |
||||||
|
</userDefinedRuntimeAttribute> |
||||||
|
</userDefinedRuntimeAttributes> |
||||||
|
<connections> |
||||||
|
<accessibilityConnection property="title" destination="18" id="129"/> |
||||||
|
<outlet property="delegate" destination="-2" id="131"/> |
||||||
|
</connections> |
||||||
|
</customView> |
||||||
|
<customView translatesAutoresizingMaskIntoConstraints="NO" id="13" customClass="SRRecorderControl"> |
||||||
|
<rect key="frame" x="109" y="53" width="282" height="25"/> |
||||||
|
<connections> |
||||||
|
<accessibilityConnection property="title" destination="23" id="130"/> |
||||||
|
<outlet property="delegate" destination="-2" id="132"/> |
||||||
|
</connections> |
||||||
|
</customView> |
||||||
|
<textField horizontalHuggingPriority="750" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="18" userLabel="Ping Button Label"> |
||||||
|
<rect key="frame" x="18" y="83" width="85" height="17"/> |
||||||
|
<constraints> |
||||||
|
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="81" id="eoT-cc-Swt"/> |
||||||
|
</constraints> |
||||||
|
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Ping Button:" id="19"> |
||||||
|
<font key="font" metaFont="system"/> |
||||||
|
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/> |
||||||
|
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/> |
||||||
|
</textFieldCell> |
||||||
|
</textField> |
||||||
|
<textField horizontalHuggingPriority="750" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="23" userLabel="Global Ping Label"> |
||||||
|
<rect key="frame" x="18" y="50" width="85" height="17"/> |
||||||
|
<constraints> |
||||||
|
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="80" id="116"/> |
||||||
|
</constraints> |
||||||
|
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Global Ping:" id="24"> |
||||||
|
<font key="font" metaFont="system"/> |
||||||
|
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/> |
||||||
|
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/> |
||||||
|
</textFieldCell> |
||||||
|
</textField> |
||||||
|
<customView translatesAutoresizingMaskIntoConstraints="NO" id="141" customClass="SRRecorderControl"> |
||||||
|
<rect key="frame" x="109" y="20" width="282" height="25"/> |
||||||
|
<connections> |
||||||
|
<accessibilityConnection property="title" destination="137" id="160"/> |
||||||
|
<outlet property="delegate" destination="-2" id="161"/> |
||||||
|
</connections> |
||||||
|
</customView> |
||||||
|
<textField horizontalHuggingPriority="750" verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="137" userLabel="Ping Item Label"> |
||||||
|
<rect key="frame" x="18" y="17" width="85" height="17"/> |
||||||
|
<constraints> |
||||||
|
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="67" id="158"/> |
||||||
|
</constraints> |
||||||
|
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Ping Item:" id="138"> |
||||||
|
<font key="font" metaFont="system"/> |
||||||
|
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/> |
||||||
|
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/> |
||||||
|
</textFieldCell> |
||||||
|
</textField> |
||||||
|
</subviews> |
||||||
|
<constraints> |
||||||
|
<constraint firstItem="13" firstAttribute="trailing" secondItem="8" secondAttribute="trailing" id="1L0-EV-0eS"/> |
||||||
|
<constraint firstItem="141" firstAttribute="baseline" secondItem="137" secondAttribute="baseline" id="1by-4m-cQM"/> |
||||||
|
<constraint firstItem="13" firstAttribute="top" secondItem="8" secondAttribute="bottom" constant="8" symbolic="YES" id="4Eq-Jg-m83"/> |
||||||
|
<constraint firstItem="141" firstAttribute="leading" secondItem="13" secondAttribute="leading" id="4xF-rl-sl4"/> |
||||||
|
<constraint firstItem="141" firstAttribute="top" secondItem="13" secondAttribute="bottom" constant="8" symbolic="YES" id="Jtg-9U-w2u"/> |
||||||
|
<constraint firstItem="141" firstAttribute="height" secondItem="13" secondAttribute="height" id="LE9-R3-sDy"/> |
||||||
|
<constraint firstItem="141" firstAttribute="trailing" secondItem="13" secondAttribute="trailing" id="RAz-3I-dQg"/> |
||||||
|
<constraint firstItem="13" firstAttribute="height" secondItem="8" secondAttribute="height" id="Ta6-p0-KrZ"/> |
||||||
|
<constraint firstItem="137" firstAttribute="trailing" secondItem="23" secondAttribute="trailing" id="Uy1-V9-aOf"/> |
||||||
|
<constraint firstItem="23" firstAttribute="leading" secondItem="6" secondAttribute="leading" constant="20" symbolic="YES" id="by8-Mj-2uE"/> |
||||||
|
<constraint firstAttribute="trailing" secondItem="8" secondAttribute="trailing" constant="20" symbolic="YES" id="eLg-WV-Qtu"/> |
||||||
|
<constraint firstItem="8" firstAttribute="leading" secondItem="18" secondAttribute="trailing" constant="8" symbolic="YES" id="eQT-vu-0s6"/> |
||||||
|
<constraint firstItem="23" firstAttribute="trailing" secondItem="18" secondAttribute="trailing" id="iWl-MD-Fkk"/> |
||||||
|
<constraint firstItem="18" firstAttribute="baseline" secondItem="8" secondAttribute="baseline" id="kFr-fB-U4P"/> |
||||||
|
<constraint firstItem="8" firstAttribute="top" secondItem="6" secondAttribute="top" constant="20" symbolic="YES" id="kaZ-QD-cXD"/> |
||||||
|
<constraint firstItem="13" firstAttribute="leading" secondItem="8" secondAttribute="leading" id="l0u-R5-hvE"/> |
||||||
|
<constraint firstItem="18" firstAttribute="leading" secondItem="6" secondAttribute="leading" constant="20" symbolic="YES" id="rCD-cF-OEo"/> |
||||||
|
<constraint firstItem="137" firstAttribute="leading" secondItem="6" secondAttribute="leading" constant="20" symbolic="YES" id="tWc-F4-7fR"/> |
||||||
|
<constraint firstItem="13" firstAttribute="baseline" secondItem="23" secondAttribute="baseline" id="zoV-Ng-bmL"/> |
||||||
|
</constraints> |
||||||
|
</view> |
||||||
|
<point key="canvasLocation" x="318.5" y="603.5"/> |
||||||
|
</window> |
||||||
|
</objects> |
||||||
|
</document> |
@ -0,0 +1,466 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="8.00"> |
||||||
|
<data> |
||||||
|
<int key="IBDocument.SystemTarget">1080</int> |
||||||
|
<string key="IBDocument.SystemVersion">12C60</string> |
||||||
|
<string key="IBDocument.InterfaceBuilderVersion">3084</string> |
||||||
|
<string key="IBDocument.AppKitVersion">1187.34</string> |
||||||
|
<string key="IBDocument.HIToolboxVersion">625.00</string> |
||||||
|
<object class="NSMutableDictionary" key="IBDocument.PluginVersions"> |
||||||
|
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string> |
||||||
|
<string key="NS.object.0">3084</string> |
||||||
|
</object> |
||||||
|
<array key="IBDocument.IntegratedClassDependencies"> |
||||||
|
<string>NSCustomObject</string> |
||||||
|
<string>NSCustomView</string> |
||||||
|
<string>NSTextField</string> |
||||||
|
<string>NSTextFieldCell</string> |
||||||
|
<string>NSView</string> |
||||||
|
<string>NSWindowTemplate</string> |
||||||
|
</array> |
||||||
|
<array key="IBDocument.PluginDependencies"> |
||||||
|
<string>com.apple.InterfaceBuilder.CocoaPlugin</string> |
||||||
|
</array> |
||||||
|
<object class="NSMutableDictionary" key="IBDocument.Metadata"> |
||||||
|
<string key="NS.key.0">PluginDependencyRecalculationVersion</string> |
||||||
|
<integer value="1" key="NS.object.0"/> |
||||||
|
</object> |
||||||
|
<array class="NSMutableArray" key="IBDocument.RootObjects" id="1000"> |
||||||
|
<object class="NSCustomObject" id="1001"> |
||||||
|
<string key="NSClassName">IKIBAutoresizingMasksWindowController</string> |
||||||
|
</object> |
||||||
|
<object class="NSCustomObject" id="1003"> |
||||||
|
<string key="NSClassName">FirstResponder</string> |
||||||
|
</object> |
||||||
|
<object class="NSCustomObject" id="1004"> |
||||||
|
<string key="NSClassName">NSApplication</string> |
||||||
|
</object> |
||||||
|
<object class="NSWindowTemplate" id="80070142"> |
||||||
|
<int key="NSWindowStyleMask">27</int> |
||||||
|
<int key="NSWindowBacking">2</int> |
||||||
|
<string key="NSWindowRect">{{196, 112}, {327, 131}}</string> |
||||||
|
<int key="NSWTFlags">-1535638528</int> |
||||||
|
<string key="NSWindowTitle">Interface Builder Autoresizing Masks Demo</string> |
||||||
|
<string key="NSWindowClass">NSPanel</string> |
||||||
|
<nil key="NSViewClass"/> |
||||||
|
<nil key="NSUserInterfaceItemIdentifier"/> |
||||||
|
<string key="NSWindowContentMaxSize">{600, 131}</string> |
||||||
|
<string key="NSWindowContentMinSize">{200, 131}</string> |
||||||
|
<object class="NSView" key="NSWindowView" id="45375859"> |
||||||
|
<reference key="NSNextResponder"/> |
||||||
|
<int key="NSvFlags">256</int> |
||||||
|
<array class="NSMutableArray" key="NSSubviews"> |
||||||
|
<object class="NSCustomView" id="162563404"> |
||||||
|
<reference key="NSNextResponder" ref="45375859"/> |
||||||
|
<int key="NSvFlags">266</int> |
||||||
|
<string key="NSFrame">{{105, 86}, {202, 25}}</string> |
||||||
|
<reference key="NSSuperview" ref="45375859"/> |
||||||
|
<reference key="NSWindow"/> |
||||||
|
<reference key="NSNextKeyView" ref="932723322"/> |
||||||
|
<string key="NSReuseIdentifierKey">_NS:9</string> |
||||||
|
<string key="NSClassName">SRRecorderControl</string> |
||||||
|
</object> |
||||||
|
<object class="NSCustomView" id="188754340"> |
||||||
|
<reference key="NSNextResponder" ref="45375859"/> |
||||||
|
<int key="NSvFlags">266</int> |
||||||
|
<string key="NSFrame">{{105, 53}, {202, 25}}</string> |
||||||
|
<reference key="NSSuperview" ref="45375859"/> |
||||||
|
<reference key="NSWindow"/> |
||||||
|
<reference key="NSNextKeyView" ref="622910158"/> |
||||||
|
<string key="NSReuseIdentifierKey">_NS:9</string> |
||||||
|
<string key="NSClassName">SRRecorderControl</string> |
||||||
|
</object> |
||||||
|
<object class="NSTextField" id="292773233"> |
||||||
|
<reference key="NSNextResponder" ref="45375859"/> |
||||||
|
<int key="NSvFlags">268</int> |
||||||
|
<string key="NSFrame">{{19, 91}, {81, 17}}</string> |
||||||
|
<reference key="NSSuperview" ref="45375859"/> |
||||||
|
<reference key="NSWindow"/> |
||||||
|
<reference key="NSNextKeyView" ref="162563404"/> |
||||||
|
<string key="NSReuseIdentifierKey">_NS:1535</string> |
||||||
|
<bool key="NSEnabled">YES</bool> |
||||||
|
<object class="NSTextFieldCell" key="NSCell" id="779379804"> |
||||||
|
<int key="NSCellFlags">68157504</int> |
||||||
|
<int key="NSCellFlags2">71304192</int> |
||||||
|
<string key="NSContents">Ping Button:</string> |
||||||
|
<object class="NSFont" key="NSSupport" id="280059051"> |
||||||
|
<string key="NSName">LucidaGrande</string> |
||||||
|
<double key="NSSize">13</double> |
||||||
|
<int key="NSfFlags">1044</int> |
||||||
|
</object> |
||||||
|
<string key="NSCellIdentifier">_NS:1535</string> |
||||||
|
<reference key="NSControlView" ref="292773233"/> |
||||||
|
<object class="NSColor" key="NSBackgroundColor" id="394644910"> |
||||||
|
<int key="NSColorSpace">6</int> |
||||||
|
<string key="NSCatalogName">System</string> |
||||||
|
<string key="NSColorName">controlColor</string> |
||||||
|
<object class="NSColor" key="NSColor"> |
||||||
|
<int key="NSColorSpace">3</int> |
||||||
|
<bytes key="NSWhite">MC42NjY2NjY2NjY3AA</bytes> |
||||||
|
</object> |
||||||
|
</object> |
||||||
|
<object class="NSColor" key="NSTextColor" id="445556250"> |
||||||
|
<int key="NSColorSpace">6</int> |
||||||
|
<string key="NSCatalogName">System</string> |
||||||
|
<string key="NSColorName">controlTextColor</string> |
||||||
|
<object class="NSColor" key="NSColor"> |
||||||
|
<int key="NSColorSpace">3</int> |
||||||
|
<bytes key="NSWhite">MAA</bytes> |
||||||
|
</object> |
||||||
|
</object> |
||||||
|
</object> |
||||||
|
<bool key="NSAllowsLogicalLayoutDirection">NO</bool> |
||||||
|
</object> |
||||||
|
<object class="NSTextField" id="932723322"> |
||||||
|
<reference key="NSNextResponder" ref="45375859"/> |
||||||
|
<int key="NSvFlags">268</int> |
||||||
|
<string key="NSFrame">{{17, 58}, {83, 17}}</string> |
||||||
|
<reference key="NSSuperview" ref="45375859"/> |
||||||
|
<reference key="NSWindow"/> |
||||||
|
<reference key="NSNextKeyView" ref="188754340"/> |
||||||
|
<string key="NSReuseIdentifierKey">_NS:1535</string> |
||||||
|
<bool key="NSEnabled">YES</bool> |
||||||
|
<object class="NSTextFieldCell" key="NSCell" id="14029865"> |
||||||
|
<int key="NSCellFlags">68157504</int> |
||||||
|
<int key="NSCellFlags2">71304192</int> |
||||||
|
<string key="NSContents">Global Ping:</string> |
||||||
|
<reference key="NSSupport" ref="280059051"/> |
||||||
|
<string key="NSCellIdentifier">_NS:1535</string> |
||||||
|
<reference key="NSControlView" ref="932723322"/> |
||||||
|
<reference key="NSBackgroundColor" ref="394644910"/> |
||||||
|
<reference key="NSTextColor" ref="445556250"/> |
||||||
|
</object> |
||||||
|
<bool key="NSAllowsLogicalLayoutDirection">NO</bool> |
||||||
|
</object> |
||||||
|
<object class="NSTextField" id="622910158"> |
||||||
|
<reference key="NSNextResponder" ref="45375859"/> |
||||||
|
<int key="NSvFlags">268</int> |
||||||
|
<string key="NSFrame">{{32, 25}, {68, 17}}</string> |
||||||
|
<reference key="NSSuperview" ref="45375859"/> |
||||||
|
<reference key="NSWindow"/> |
||||||
|
<reference key="NSNextKeyView" ref="494005960"/> |
||||||
|
<string key="NSReuseIdentifierKey">_NS:1535</string> |
||||||
|
<bool key="NSEnabled">YES</bool> |
||||||
|
<object class="NSTextFieldCell" key="NSCell" id="708003864"> |
||||||
|
<int key="NSCellFlags">68157504</int> |
||||||
|
<int key="NSCellFlags2">272630784</int> |
||||||
|
<string key="NSContents">Ping Item:</string> |
||||||
|
<reference key="NSSupport" ref="280059051"/> |
||||||
|
<string key="NSCellIdentifier">_NS:1535</string> |
||||||
|
<reference key="NSControlView" ref="622910158"/> |
||||||
|
<reference key="NSBackgroundColor" ref="394644910"/> |
||||||
|
<reference key="NSTextColor" ref="445556250"/> |
||||||
|
</object> |
||||||
|
<bool key="NSAllowsLogicalLayoutDirection">NO</bool> |
||||||
|
</object> |
||||||
|
<object class="NSCustomView" id="494005960"> |
||||||
|
<reference key="NSNextResponder" ref="45375859"/> |
||||||
|
<int key="NSvFlags">266</int> |
||||||
|
<string key="NSFrame">{{105, 20}, {202, 25}}</string> |
||||||
|
<reference key="NSSuperview" ref="45375859"/> |
||||||
|
<reference key="NSWindow"/> |
||||||
|
<reference key="NSNextKeyView"/> |
||||||
|
<string key="NSReuseIdentifierKey">_NS:9</string> |
||||||
|
<string key="NSClassName">SRRecorderControl</string> |
||||||
|
</object> |
||||||
|
</array> |
||||||
|
<string key="NSFrameSize">{327, 131}</string> |
||||||
|
<reference key="NSSuperview"/> |
||||||
|
<reference key="NSWindow"/> |
||||||
|
<reference key="NSNextKeyView" ref="292773233"/> |
||||||
|
<bool key="NSViewIsLayerTreeHost">YES</bool> |
||||||
|
<array key="NSViewContentFilters"> |
||||||
|
<object class="CIVortexDistortion"> |
||||||
|
<object class="CIVector" key="CI_inputCenter"> |
||||||
|
<int key="CICount">2</int> |
||||||
|
<string key="CIVector">{{150, 180}, {0, 0}}</string> |
||||||
|
</object> |
||||||
|
<real value="300" key="CI_inputRadius"/> |
||||||
|
<real value="56.548667764616276" key="CI_inputAngle"/> |
||||||
|
<bool key="CIEnabled">YES</bool> |
||||||
|
</object> |
||||||
|
</array> |
||||||
|
<string key="NSReuseIdentifierKey">_NS:21</string> |
||||||
|
</object> |
||||||
|
<string key="NSScreenRect">{{0, 0}, {1366, 746}}</string> |
||||||
|
<string key="NSMinSize">{200, 147}</string> |
||||||
|
<string key="NSMaxSize">{600, 147}</string> |
||||||
|
<string key="NSFrameAutosaveName">Interface Builder Autoresizing Masks Demo</string> |
||||||
|
<bool key="NSWindowIsRestorable">YES</bool> |
||||||
|
</object> |
||||||
|
</array> |
||||||
|
<object class="IBObjectContainer" key="IBDocument.Objects"> |
||||||
|
<array class="NSMutableArray" key="connectionRecords"> |
||||||
|
<object class="IBConnectionRecord"> |
||||||
|
<object class="IBOutletConnection" key="connection"> |
||||||
|
<string key="label">pingShortcutRecorder</string> |
||||||
|
<reference key="source" ref="1001"/> |
||||||
|
<reference key="destination" ref="162563404"/> |
||||||
|
</object> |
||||||
|
<int key="connectionID">31</int> |
||||||
|
</object> |
||||||
|
<object class="IBConnectionRecord"> |
||||||
|
<object class="IBOutletConnection" key="connection"> |
||||||
|
<string key="label">globalPingShortcutRecorder</string> |
||||||
|
<reference key="source" ref="1001"/> |
||||||
|
<reference key="destination" ref="188754340"/> |
||||||
|
</object> |
||||||
|
<int key="connectionID">32</int> |
||||||
|
</object> |
||||||
|
<object class="IBConnectionRecord"> |
||||||
|
<object class="IBOutletConnection" key="connection"> |
||||||
|
<string key="label">window</string> |
||||||
|
<reference key="source" ref="1001"/> |
||||||
|
<reference key="destination" ref="80070142"/> |
||||||
|
</object> |
||||||
|
<int key="connectionID">33</int> |
||||||
|
</object> |
||||||
|
<object class="IBConnectionRecord"> |
||||||
|
<object class="IBOutletConnection" key="connection"> |
||||||
|
<string key="label">pingItemShortcutRecorder</string> |
||||||
|
<reference key="source" ref="1001"/> |
||||||
|
<reference key="destination" ref="494005960"/> |
||||||
|
</object> |
||||||
|
<int key="connectionID">42</int> |
||||||
|
</object> |
||||||
|
<object class="IBConnectionRecord"> |
||||||
|
<object class="IBAccessibilityConnection" key="connection"> |
||||||
|
<string key="label">title</string> |
||||||
|
<reference key="source" ref="188754340"/> |
||||||
|
<reference key="destination" ref="932723322"/> |
||||||
|
</object> |
||||||
|
<int key="connectionID">35</int> |
||||||
|
</object> |
||||||
|
<object class="IBConnectionRecord"> |
||||||
|
<object class="IBOutletConnection" key="connection"> |
||||||
|
<string key="label">delegate</string> |
||||||
|
<reference key="source" ref="188754340"/> |
||||||
|
<reference key="destination" ref="1001"/> |
||||||
|
</object> |
||||||
|
<int key="connectionID">37</int> |
||||||
|
</object> |
||||||
|
<object class="IBConnectionRecord"> |
||||||
|
<object class="IBAccessibilityConnection" key="connection"> |
||||||
|
<string key="label">title</string> |
||||||
|
<reference key="source" ref="162563404"/> |
||||||
|
<reference key="destination" ref="292773233"/> |
||||||
|
</object> |
||||||
|
<int key="connectionID">34</int> |
||||||
|
</object> |
||||||
|
<object class="IBConnectionRecord"> |
||||||
|
<object class="IBOutletConnection" key="connection"> |
||||||
|
<string key="label">delegate</string> |
||||||
|
<reference key="source" ref="162563404"/> |
||||||
|
<reference key="destination" ref="1001"/> |
||||||
|
</object> |
||||||
|
<int key="connectionID">36</int> |
||||||
|
</object> |
||||||
|
<object class="IBConnectionRecord"> |
||||||
|
<object class="IBOutletConnection" key="connection"> |
||||||
|
<string key="label">delegate</string> |
||||||
|
<reference key="source" ref="494005960"/> |
||||||
|
<reference key="destination" ref="1001"/> |
||||||
|
</object> |
||||||
|
<int key="connectionID">41</int> |
||||||
|
</object> |
||||||
|
<object class="IBConnectionRecord"> |
||||||
|
<object class="IBAccessibilityConnection" key="connection"> |
||||||
|
<string key="label">title</string> |
||||||
|
<reference key="source" ref="494005960"/> |
||||||
|
<reference key="destination" ref="622910158"/> |
||||||
|
</object> |
||||||
|
<int key="connectionID">43</int> |
||||||
|
</object> |
||||||
|
</array> |
||||||
|
<object class="IBMutableOrderedSet" key="objectRecords"> |
||||||
|
<array key="orderedObjects"> |
||||||
|
<object class="IBObjectRecord"> |
||||||
|
<int key="objectID">0</int> |
||||||
|
<array key="object" id="0"/> |
||||||
|
<reference key="children" ref="1000"/> |
||||||
|
<nil key="parent"/> |
||||||
|
</object> |
||||||
|
<object class="IBObjectRecord"> |
||||||
|
<int key="objectID">-2</int> |
||||||
|
<reference key="object" ref="1001"/> |
||||||
|
<reference key="parent" ref="0"/> |
||||||
|
<string key="objectName">File's Owner</string> |
||||||
|
</object> |
||||||
|
<object class="IBObjectRecord"> |
||||||
|
<int key="objectID">-1</int> |
||||||
|
<reference key="object" ref="1003"/> |
||||||
|
<reference key="parent" ref="0"/> |
||||||
|
<string key="objectName">First Responder</string> |
||||||
|
</object> |
||||||
|
<object class="IBObjectRecord"> |
||||||
|
<int key="objectID">-3</int> |
||||||
|
<reference key="object" ref="1004"/> |
||||||
|
<reference key="parent" ref="0"/> |
||||||
|
<string key="objectName">Application</string> |
||||||
|
</object> |
||||||
|
<object class="IBObjectRecord"> |
||||||
|
<int key="objectID">7</int> |
||||||
|
<reference key="object" ref="80070142"/> |
||||||
|
<array class="NSMutableArray" key="children"> |
||||||
|
<reference ref="45375859"/> |
||||||
|
</array> |
||||||
|
<reference key="parent" ref="0"/> |
||||||
|
</object> |
||||||
|
<object class="IBObjectRecord"> |
||||||
|
<int key="objectID">8</int> |
||||||
|
<reference key="object" ref="45375859"/> |
||||||
|
<array class="NSMutableArray" key="children"> |
||||||
|
<reference ref="292773233"/> |
||||||
|
<reference ref="932723322"/> |
||||||
|
<reference ref="188754340"/> |
||||||
|
<reference ref="162563404"/> |
||||||
|
<reference ref="494005960"/> |
||||||
|
<reference ref="622910158"/> |
||||||
|
</array> |
||||||
|
<reference key="parent" ref="80070142"/> |
||||||
|
</object> |
||||||
|
<object class="IBObjectRecord"> |
||||||
|
<int key="objectID">9</int> |
||||||
|
<reference key="object" ref="292773233"/> |
||||||
|
<array class="NSMutableArray" key="children"> |
||||||
|
<reference ref="779379804"/> |
||||||
|
</array> |
||||||
|
<reference key="parent" ref="45375859"/> |
||||||
|
</object> |
||||||
|
<object class="IBObjectRecord"> |
||||||
|
<int key="objectID">10</int> |
||||||
|
<reference key="object" ref="932723322"/> |
||||||
|
<array class="NSMutableArray" key="children"> |
||||||
|
<reference ref="14029865"/> |
||||||
|
</array> |
||||||
|
<reference key="parent" ref="45375859"/> |
||||||
|
</object> |
||||||
|
<object class="IBObjectRecord"> |
||||||
|
<int key="objectID">11</int> |
||||||
|
<reference key="object" ref="188754340"/> |
||||||
|
<array class="NSMutableArray" key="children"/> |
||||||
|
<reference key="parent" ref="45375859"/> |
||||||
|
</object> |
||||||
|
<object class="IBObjectRecord"> |
||||||
|
<int key="objectID">12</int> |
||||||
|
<reference key="object" ref="162563404"/> |
||||||
|
<array class="NSMutableArray" key="children"/> |
||||||
|
<reference key="parent" ref="45375859"/> |
||||||
|
</object> |
||||||
|
<object class="IBObjectRecord"> |
||||||
|
<int key="objectID">27</int> |
||||||
|
<reference key="object" ref="14029865"/> |
||||||
|
<reference key="parent" ref="932723322"/> |
||||||
|
</object> |
||||||
|
<object class="IBObjectRecord"> |
||||||
|
<int key="objectID">29</int> |
||||||
|
<reference key="object" ref="779379804"/> |
||||||
|
<reference key="parent" ref="292773233"/> |
||||||
|
</object> |
||||||
|
<object class="IBObjectRecord"> |
||||||
|
<int key="objectID">38</int> |
||||||
|
<reference key="object" ref="622910158"/> |
||||||
|
<array class="NSMutableArray" key="children"> |
||||||
|
<reference ref="708003864"/> |
||||||
|
</array> |
||||||
|
<reference key="parent" ref="45375859"/> |
||||||
|
</object> |
||||||
|
<object class="IBObjectRecord"> |
||||||
|
<int key="objectID">39</int> |
||||||
|
<reference key="object" ref="708003864"/> |
||||||
|
<reference key="parent" ref="622910158"/> |
||||||
|
</object> |
||||||
|
<object class="IBObjectRecord"> |
||||||
|
<int key="objectID">40</int> |
||||||
|
<reference key="object" ref="494005960"/> |
||||||
|
<reference key="parent" ref="45375859"/> |
||||||
|
</object> |
||||||
|
</array> |
||||||
|
</object> |
||||||
|
<dictionary class="NSMutableDictionary" key="flattenedProperties"> |
||||||
|
<string key="-1.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> |
||||||
|
<string key="-2.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> |
||||||
|
<string key="-3.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> |
||||||
|
<string key="10.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> |
||||||
|
<string key="11.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> |
||||||
|
<string key="12.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> |
||||||
|
<string key="27.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> |
||||||
|
<string key="29.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> |
||||||
|
<string key="38.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> |
||||||
|
<string key="39.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> |
||||||
|
<string key="40.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> |
||||||
|
<string key="7.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> |
||||||
|
<boolean value="YES" key="7.NSWindowTemplate.visibleAtLaunch"/> |
||||||
|
<string key="8.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> |
||||||
|
<string key="9.IBPluginDependency">com.apple.InterfaceBuilder.CocoaPlugin</string> |
||||||
|
</dictionary> |
||||||
|
<dictionary class="NSMutableDictionary" key="unlocalizedProperties"/> |
||||||
|
<nil key="activeLocalization"/> |
||||||
|
<dictionary class="NSMutableDictionary" key="localizations"/> |
||||||
|
<nil key="sourceID"/> |
||||||
|
<int key="maxID">43</int> |
||||||
|
</object> |
||||||
|
<object class="IBClassDescriber" key="IBDocument.Classes"> |
||||||
|
<array class="NSMutableArray" key="referencedPartialClassDescriptions"> |
||||||
|
<object class="IBPartialClassDescription"> |
||||||
|
<string key="className">IKDemoWindowController</string> |
||||||
|
<string key="superclassName">NSWindowController</string> |
||||||
|
<dictionary class="NSMutableDictionary" key="outlets"> |
||||||
|
<string key="globalPingShortcutRecorder">SRRecorderControl</string> |
||||||
|
<string key="pingItemShortcutRecorder">SRRecorderControl</string> |
||||||
|
<string key="pingShortcutRecorder">SRRecorderControl</string> |
||||||
|
</dictionary> |
||||||
|
<dictionary class="NSMutableDictionary" key="toOneOutletInfosByName"> |
||||||
|
<object class="IBToOneOutletInfo" key="globalPingShortcutRecorder"> |
||||||
|
<string key="name">globalPingShortcutRecorder</string> |
||||||
|
<string key="candidateClassName">SRRecorderControl</string> |
||||||
|
</object> |
||||||
|
<object class="IBToOneOutletInfo" key="pingItemShortcutRecorder"> |
||||||
|
<string key="name">pingItemShortcutRecorder</string> |
||||||
|
<string key="candidateClassName">SRRecorderControl</string> |
||||||
|
</object> |
||||||
|
<object class="IBToOneOutletInfo" key="pingShortcutRecorder"> |
||||||
|
<string key="name">pingShortcutRecorder</string> |
||||||
|
<string key="candidateClassName">SRRecorderControl</string> |
||||||
|
</object> |
||||||
|
</dictionary> |
||||||
|
<object class="IBClassDescriptionSource" key="sourceIdentifier"> |
||||||
|
<string key="majorKey">IBProjectSource</string> |
||||||
|
<string key="minorKey">./Classes/IKDemoWindowController.h</string> |
||||||
|
</object> |
||||||
|
</object> |
||||||
|
<object class="IBPartialClassDescription"> |
||||||
|
<string key="className">IKIBAutoresizingMasksWindowController</string> |
||||||
|
<string key="superclassName">IKDemoWindowController</string> |
||||||
|
<object class="IBClassDescriptionSource" key="sourceIdentifier"> |
||||||
|
<string key="majorKey">IBProjectSource</string> |
||||||
|
<string key="minorKey">./Classes/IKIBAutoresizingMasksWindowController.h</string> |
||||||
|
</object> |
||||||
|
</object> |
||||||
|
<object class="IBPartialClassDescription"> |
||||||
|
<string key="className">SRRecorderControl</string> |
||||||
|
<string key="superclassName">NSView</string> |
||||||
|
<object class="NSMutableDictionary" key="outlets"> |
||||||
|
<string key="NS.key.0">delegate</string> |
||||||
|
<string key="NS.object.0">NSObject</string> |
||||||
|
</object> |
||||||
|
<object class="NSMutableDictionary" key="toOneOutletInfosByName"> |
||||||
|
<string key="NS.key.0">delegate</string> |
||||||
|
<object class="IBToOneOutletInfo" key="NS.object.0"> |
||||||
|
<string key="name">delegate</string> |
||||||
|
<string key="candidateClassName">NSObject</string> |
||||||
|
</object> |
||||||
|
</object> |
||||||
|
<object class="IBClassDescriptionSource" key="sourceIdentifier"> |
||||||
|
<string key="majorKey">IBProjectSource</string> |
||||||
|
<string key="minorKey">./Classes/SRRecorderControl.h</string> |
||||||
|
</object> |
||||||
|
</object> |
||||||
|
</array> |
||||||
|
</object> |
||||||
|
<int key="IBDocument.localizationMode">0</int> |
||||||
|
<string key="IBDocument.TargetRuntimeIdentifier">IBCocoaFramework</string> |
||||||
|
<bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool> |
||||||
|
<int key="IBDocument.defaultPropertyAccessControl">3</int> |
||||||
|
</data> |
||||||
|
</archive> |
@ -0,0 +1,2 @@ |
|||||||
|
/* Localized versions of Info.plist keys */ |
||||||
|
|
@ -0,0 +1,168 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?> |
||||||
|
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="4510" systemVersion="12F37" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES"> |
||||||
|
<dependencies> |
||||||
|
<deployment defaultVersion="1080" identifier="macosx"/> |
||||||
|
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="4510"/> |
||||||
|
</dependencies> |
||||||
|
<objects> |
||||||
|
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication"> |
||||||
|
<connections> |
||||||
|
<outlet property="delegate" destination="494" id="495"/> |
||||||
|
</connections> |
||||||
|
</customObject> |
||||||
|
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/> |
||||||
|
<customObject id="-3" userLabel="Application"/> |
||||||
|
<menu title="AMainMenu" systemMenu="main" id="29"> |
||||||
|
<items> |
||||||
|
<menuItem title="ShortcutRecorderDemo" id="56"> |
||||||
|
<menu key="submenu" title="ShortcutRecorderDemo" systemMenu="apple" id="57"> |
||||||
|
<items> |
||||||
|
<menuItem title="Ping" id="627"> |
||||||
|
<modifierMask key="keyEquivalentModifierMask"/> |
||||||
|
<connections> |
||||||
|
<action selector="ping:" target="494" id="630"/> |
||||||
|
</connections> |
||||||
|
</menuItem> |
||||||
|
<menuItem isSeparatorItem="YES" id="628"/> |
||||||
|
<menuItem title="Hide ShortcutRecorderDemo" keyEquivalent="h" id="134"> |
||||||
|
<connections> |
||||||
|
<action selector="hide:" target="-1" id="367"/> |
||||||
|
</connections> |
||||||
|
</menuItem> |
||||||
|
<menuItem title="Hide Others" keyEquivalent="h" id="145"> |
||||||
|
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/> |
||||||
|
<connections> |
||||||
|
<action selector="hideOtherApplications:" target="-1" id="368"/> |
||||||
|
</connections> |
||||||
|
</menuItem> |
||||||
|
<menuItem title="Show All" id="150"> |
||||||
|
<connections> |
||||||
|
<action selector="unhideAllApplications:" target="-1" id="370"/> |
||||||
|
</connections> |
||||||
|
</menuItem> |
||||||
|
<menuItem isSeparatorItem="YES" id="149"> |
||||||
|
<modifierMask key="keyEquivalentModifierMask" command="YES"/> |
||||||
|
</menuItem> |
||||||
|
<menuItem title="Quit ShortcutRecorderDemo" keyEquivalent="q" id="136"> |
||||||
|
<connections> |
||||||
|
<action selector="terminate:" target="-3" id="449"/> |
||||||
|
</connections> |
||||||
|
</menuItem> |
||||||
|
</items> |
||||||
|
</menu> |
||||||
|
</menuItem> |
||||||
|
<menuItem title="File" id="83"/> |
||||||
|
<menuItem title="Edit" id="217"/> |
||||||
|
<menuItem title="Format" id="375"> |
||||||
|
<modifierMask key="keyEquivalentModifierMask"/> |
||||||
|
</menuItem> |
||||||
|
<menuItem title="Window" id="19"/> |
||||||
|
<menuItem title="Help" id="490"> |
||||||
|
<modifierMask key="keyEquivalentModifierMask"/> |
||||||
|
</menuItem> |
||||||
|
</items> |
||||||
|
</menu> |
||||||
|
<window title="Demo" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" animationBehavior="default" id="371"> |
||||||
|
<windowStyleMask key="styleMask" titled="YES" closable="YES"/> |
||||||
|
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/> |
||||||
|
<rect key="contentRect" x="335" y="390" width="387" height="211"/> |
||||||
|
<rect key="screenRect" x="0.0" y="0.0" width="1366" height="746"/> |
||||||
|
<view key="contentView" id="372"> |
||||||
|
<rect key="frame" x="0.0" y="0.0" width="387" height="211"/> |
||||||
|
<autoresizingMask key="autoresizingMask"/> |
||||||
|
<subviews> |
||||||
|
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="565"> |
||||||
|
<rect key="frame" x="14" y="163" width="359" height="32"/> |
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> |
||||||
|
<buttonCell key="cell" type="push" title="Show "Interface Builder Auto Layout" Demo" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="566"> |
||||||
|
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> |
||||||
|
<font key="font" metaFont="system"/> |
||||||
|
</buttonCell> |
||||||
|
<connections> |
||||||
|
<action selector="showIBAutoLayout:" target="494" id="598"/> |
||||||
|
</connections> |
||||||
|
</button> |
||||||
|
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="570"> |
||||||
|
<rect key="frame" x="14" y="97" width="359" height="32"/> |
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> |
||||||
|
<buttonCell key="cell" type="push" title="Show "Interface Builder Autoresizing Masks" Demo" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="571"> |
||||||
|
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> |
||||||
|
<font key="font" metaFont="system"/> |
||||||
|
</buttonCell> |
||||||
|
<connections> |
||||||
|
<action selector="showAutoresizingMasks:" target="494" id="626"/> |
||||||
|
</connections> |
||||||
|
</button> |
||||||
|
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="578"> |
||||||
|
<rect key="frame" x="14" y="130" width="359" height="32"/> |
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> |
||||||
|
<buttonCell key="cell" type="push" title="Show "Code Auto Layout" Demo" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="579"> |
||||||
|
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> |
||||||
|
<font key="font" metaFont="system"/> |
||||||
|
</buttonCell> |
||||||
|
<connections> |
||||||
|
<action selector="showCodeAutoLayout:" target="494" id="599"/> |
||||||
|
</connections> |
||||||
|
</button> |
||||||
|
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="603"> |
||||||
|
<rect key="frame" x="160" y="13" width="67" height="32"/> |
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> |
||||||
|
<buttonCell key="cell" type="push" title="Ping" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="604"> |
||||||
|
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> |
||||||
|
<font key="font" metaFont="system"/> |
||||||
|
</buttonCell> |
||||||
|
<connections> |
||||||
|
<action selector="ping:" target="494" id="624"/> |
||||||
|
</connections> |
||||||
|
</button> |
||||||
|
<box autoresizesSubviews="NO" verticalHuggingPriority="750" title="Box" boxType="separator" titlePosition="noTitle" translatesAutoresizingMaskIntoConstraints="NO" id="609"> |
||||||
|
<rect key="frame" x="12" y="59" width="363" height="5"/> |
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> |
||||||
|
<color key="borderColor" white="0.0" alpha="0.41999999999999998" colorSpace="calibratedWhite"/> |
||||||
|
<color key="fillColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/> |
||||||
|
<font key="titleFont" metaFont="system"/> |
||||||
|
</box> |
||||||
|
<button ambiguous="YES" misplaced="YES" translatesAutoresizingMaskIntoConstraints="NO" id="OcL-7V-pmg"> |
||||||
|
<rect key="frame" x="18" y="68" width="281" height="18"/> |
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> |
||||||
|
<buttonCell key="cell" type="check" title="Enable the "Ping Button" recorder control" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="k7N-bO-eJf"> |
||||||
|
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/> |
||||||
|
<font key="font" metaFont="system"/> |
||||||
|
</buttonCell> |
||||||
|
<connections> |
||||||
|
<binding destination="zMM-8O-7w9" name="value" keyPath="values.isPingItemEnabled" id="i4u-VA-wXP"> |
||||||
|
<dictionary key="options"> |
||||||
|
<integer key="NSNullPlaceholder" value="0"/> |
||||||
|
</dictionary> |
||||||
|
</binding> |
||||||
|
</connections> |
||||||
|
</button> |
||||||
|
</subviews> |
||||||
|
<constraints> |
||||||
|
<constraint firstItem="565" firstAttribute="top" secondItem="372" secondAttribute="top" constant="20" symbolic="YES" id="567"/> |
||||||
|
<constraint firstItem="565" firstAttribute="leading" secondItem="372" secondAttribute="leading" constant="20" symbolic="YES" id="568"/> |
||||||
|
<constraint firstItem="570" firstAttribute="leading" secondItem="372" secondAttribute="leading" constant="20" symbolic="YES" id="573"/> |
||||||
|
<constraint firstItem="578" firstAttribute="top" secondItem="565" secondAttribute="bottom" constant="12" symbolic="YES" id="584"/> |
||||||
|
<constraint firstItem="578" firstAttribute="leading" secondItem="372" secondAttribute="leading" constant="20" symbolic="YES" id="592"/> |
||||||
|
<constraint firstAttribute="trailing" secondItem="578" secondAttribute="trailing" constant="20" symbolic="YES" id="593"/> |
||||||
|
<constraint firstItem="570" firstAttribute="top" secondItem="578" secondAttribute="bottom" constant="12" id="596"/> |
||||||
|
<constraint firstAttribute="trailing" secondItem="565" secondAttribute="trailing" constant="20" id="597"/> |
||||||
|
<constraint firstItem="609" firstAttribute="leading" secondItem="372" secondAttribute="leading" constant="12" symbolic="YES" id="617"/> |
||||||
|
<constraint firstAttribute="trailing" secondItem="609" secondAttribute="trailing" constant="12" symbolic="YES" id="618"/> |
||||||
|
<constraint firstItem="609" firstAttribute="centerX" secondItem="603" secondAttribute="centerX" id="619"/> |
||||||
|
<constraint firstAttribute="bottom" secondItem="603" secondAttribute="bottom" constant="20" symbolic="YES" id="623"/> |
||||||
|
<constraint firstAttribute="bottom" secondItem="609" secondAttribute="bottom" constant="61" id="TT4-tb-fdZ"/> |
||||||
|
<constraint firstItem="609" firstAttribute="top" secondItem="OcL-7V-pmg" secondAttribute="bottom" constant="8" id="h06-vZ-ACJ"/> |
||||||
|
</constraints> |
||||||
|
</view> |
||||||
|
</window> |
||||||
|
<customObject id="494" customClass="IKAppDelegate"> |
||||||
|
<connections> |
||||||
|
<outlet property="pingButton" destination="603" id="625"/> |
||||||
|
<outlet property="pingItem" destination="627" id="629"/> |
||||||
|
<outlet property="window" destination="371" id="532"/> |
||||||
|
</connections> |
||||||
|
</customObject> |
||||||
|
<userDefaultsController representsSharedInstance="YES" id="zMM-8O-7w9"/> |
||||||
|
</objects> |
||||||
|
</document> |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 29 KiB |
@ -0,0 +1,14 @@ |
|||||||
|
// |
||||||
|
// main.m |
||||||
|
// ShortcutRecorderDemo |
||||||
|
// |
||||||
|
// Created by Ilya Kulakov on 18.01.13. |
||||||
|
// Copyright (c) 2013 Ilya Kulakov. All rights reserved. |
||||||
|
// |
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h> |
||||||
|
|
||||||
|
int main(int argc, char *argv[]) |
||||||
|
{ |
||||||
|
return NSApplicationMain(argc, (const char **)argv); |
||||||
|
} |
@ -0,0 +1,31 @@ |
|||||||
|
# ShortcutRecorder |
||||||
|
|
||||||
|
Copyright (c) 2006, Contributors |
||||||
|
All rights reserved. |
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without |
||||||
|
modification, are permitted provided that the following conditions are met: |
||||||
|
* Redistributions of source code must retain the above copyright |
||||||
|
notice, this list of conditions and the following disclaimer. |
||||||
|
* Redistributions in binary form must reproduce the above copyright |
||||||
|
notice, this list of conditions and the following disclaimer in the |
||||||
|
documentation and/or other materials provided with the distribution. |
||||||
|
* Neither the name of the organization nor the |
||||||
|
names of its contributors may be used to endorse or promote products |
||||||
|
derived from this software without specific prior written permission. |
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND |
||||||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
||||||
|
DISCLAIMED. IN NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY |
||||||
|
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
||||||
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
||||||
|
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
|
||||||
|
# PTHotKey |
||||||
|
|
||||||
|
Copyright (c) 2003 Quentin D. Carnicelli. |
||||||
|
All rights reserved. |
@ -0,0 +1,22 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> |
||||||
|
<plist version="1.0"> |
||||||
|
<dict> |
||||||
|
<key>CFBundleDevelopmentRegion</key> |
||||||
|
<string>English</string> |
||||||
|
<key>CFBundleExecutable</key> |
||||||
|
<string>ShortcutRecorder</string> |
||||||
|
<key>CFBundleIdentifier</key> |
||||||
|
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> |
||||||
|
<key>CFBundleInfoDictionaryVersion</key> |
||||||
|
<string>6.0</string> |
||||||
|
<key>CFBundlePackageType</key> |
||||||
|
<string>FMWK</string> |
||||||
|
<key>CFBundleShortVersionString</key> |
||||||
|
<string>2.17</string> |
||||||
|
<key>CFBundleSignature</key> |
||||||
|
<string>????</string> |
||||||
|
<key>CFBundleVersion</key> |
||||||
|
<string>2.17</string> |
||||||
|
</dict> |
||||||
|
</plist> |
@ -0,0 +1,8 @@ |
|||||||
|
// |
||||||
|
// Prefix header for all source files of the 'ShortcutRecorder' target in the 'ShortcutRecorder' project |
||||||
|
// |
||||||
|
|
||||||
|
#ifdef __OBJC__ |
||||||
|
#import <Cocoa/Cocoa.h> |
||||||
|
#import <Carbon/Carbon.h> |
||||||
|
#endif |
@ -0,0 +1,116 @@ |
|||||||
|
//
|
||||||
|
// SRCommon.h
|
||||||
|
// ShortcutRecorder
|
||||||
|
//
|
||||||
|
// Copyright 2006-2012 Contributors. All rights reserved.
|
||||||
|
//
|
||||||
|
// License: BSD
|
||||||
|
//
|
||||||
|
// Contributors:
|
||||||
|
// David Dauer
|
||||||
|
// Jesper
|
||||||
|
// Jamie Kirkpatrick
|
||||||
|
// Andy Kim
|
||||||
|
// Ilya Kulakov
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h> |
||||||
|
#import <Carbon/Carbon.h> |
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Mask representing subset of Cocoa modifier flags suitable for shortcuts. |
||||||
|
*/ |
||||||
|
static const NSEventModifierFlags SRCocoaModifierFlagsMask = NSCommandKeyMask | NSAlternateKeyMask | NSShiftKeyMask | NSControlKeyMask; |
||||||
|
|
||||||
|
/*!
|
||||||
|
Mask representing subset of Carbon modifier flags suitable for shortcuts. |
||||||
|
*/ |
||||||
|
static const NSUInteger SRCarbonModifierFlagsMask = cmdKey | optionKey | shiftKey | controlKey; |
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Converts carbon modifier flags to cocoa. |
||||||
|
*/ |
||||||
|
FOUNDATION_STATIC_INLINE NSEventModifierFlags SRCarbonToCocoaFlags(UInt32 aCarbonFlags) |
||||||
|
{ |
||||||
|
NSEventModifierFlags cocoaFlags = 0; |
||||||
|
|
||||||
|
if (aCarbonFlags & cmdKey) |
||||||
|
cocoaFlags |= NSCommandKeyMask; |
||||||
|
|
||||||
|
if (aCarbonFlags & optionKey) |
||||||
|
cocoaFlags |= NSAlternateKeyMask; |
||||||
|
|
||||||
|
if (aCarbonFlags & controlKey) |
||||||
|
cocoaFlags |= NSControlKeyMask; |
||||||
|
|
||||||
|
if (aCarbonFlags & shiftKey) |
||||||
|
cocoaFlags |= NSShiftKeyMask; |
||||||
|
|
||||||
|
return cocoaFlags; |
||||||
|
} |
||||||
|
|
||||||
|
/*!
|
||||||
|
Converts cocoa modifier flags to carbon. |
||||||
|
*/ |
||||||
|
FOUNDATION_STATIC_INLINE UInt32 SRCocoaToCarbonFlags(NSEventModifierFlags aCocoaFlags) |
||||||
|
{ |
||||||
|
UInt32 carbonFlags = 0; |
||||||
|
|
||||||
|
if (aCocoaFlags & NSCommandKeyMask) |
||||||
|
carbonFlags |= cmdKey; |
||||||
|
|
||||||
|
if (aCocoaFlags & NSAlternateKeyMask) |
||||||
|
carbonFlags |= optionKey; |
||||||
|
|
||||||
|
if (aCocoaFlags & NSControlKeyMask) |
||||||
|
carbonFlags |= controlKey; |
||||||
|
|
||||||
|
if (aCocoaFlags & NSShiftKeyMask) |
||||||
|
carbonFlags |= shiftKey; |
||||||
|
|
||||||
|
return carbonFlags; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Return Bundle where resources can be found. |
||||||
|
|
||||||
|
@discussion Throws NSInternalInconsistencyException if bundle cannot be found. |
||||||
|
*/ |
||||||
|
NSBundle *SRBundle(); |
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Convenient method to get localized string from the framework bundle. |
||||||
|
*/ |
||||||
|
NSString *SRLoc(NSString *aKey); |
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Convenient method to get image from the framework bundle. |
||||||
|
*/ |
||||||
|
NSImage *SRImage(NSString *anImageName); |
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns string representation of shortcut with modifier flags replaced with their localized |
||||||
|
readable equivalents (e.g. ? -> Option). |
||||||
|
*/ |
||||||
|
NSString *SRReadableStringForCocoaModifierFlagsAndKeyCode(NSEventModifierFlags aModifierFlags, unsigned short aKeyCode); |
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns string representation of shortcut with modifier flags replaced with their localized |
||||||
|
readable equivalents (e.g. ? -> Option) and ASCII character for key code. |
||||||
|
*/ |
||||||
|
NSString *SRReadableASCIIStringForCocoaModifierFlagsAndKeyCode(NSEventModifierFlags aModifierFlags, unsigned short aKeyCode); |
||||||
|
|
||||||
|
/*!
|
||||||
|
Determines if given key code with flags is equal to key equivalent and flags |
||||||
|
(usually taken from NSButton or NSMenu). |
||||||
|
|
||||||
|
@discussion On Mac OS X some key combinations can have "alternates". E.g. option-A can be represented both as option-A and as Œ. |
||||||
|
*/ |
||||||
|
BOOL SRKeyCodeWithFlagsEqualToKeyEquivalentWithFlags(unsigned short aKeyCode, |
||||||
|
NSEventModifierFlags aKeyCodeFlags, |
||||||
|
NSString *aKeyEquivalent, |
||||||
|
NSEventModifierFlags aKeyEquivalentModifierFlags); |
@ -0,0 +1,175 @@ |
|||||||
|
// |
||||||
|
// SRCommon.m |
||||||
|
// ShortcutRecorder |
||||||
|
// |
||||||
|
// Copyright 2006-2012 Contributors. All rights reserved. |
||||||
|
// |
||||||
|
// License: BSD |
||||||
|
// |
||||||
|
// Contributors: |
||||||
|
// David Dauer |
||||||
|
// Jesper |
||||||
|
// Jamie Kirkpatrick |
||||||
|
// Andy Kim |
||||||
|
// Ilya Kulakov |
||||||
|
|
||||||
|
#import "SRCommon.h" |
||||||
|
#import "SRKeyCodeTransformer.h" |
||||||
|
|
||||||
|
|
||||||
|
NSBundle *SRBundle() |
||||||
|
{ |
||||||
|
static dispatch_once_t onceToken; |
||||||
|
static NSBundle *Bundle = nil; |
||||||
|
dispatch_once(&onceToken, ^{ |
||||||
|
Bundle = [NSBundle bundleWithIdentifier:@"com.kulakov.ShortcutRecorder"]; |
||||||
|
|
||||||
|
if (!Bundle) |
||||||
|
{ |
||||||
|
// Could be a CocoaPods framework with embedded resources bundle. |
||||||
|
// Look up "use_frameworks!" and "resources_bundle" in CocoaPods documentation. |
||||||
|
Bundle = [NSBundle bundleWithIdentifier:@"org.cocoapods.ShortcutRecorder"]; |
||||||
|
|
||||||
|
if (!Bundle) |
||||||
|
{ |
||||||
|
Class c = NSClassFromString(@"SRRecorderControl"); |
||||||
|
|
||||||
|
if (c) |
||||||
|
{ |
||||||
|
Bundle = [NSBundle bundleForClass:c]; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (Bundle) |
||||||
|
{ |
||||||
|
Bundle = [NSBundle bundleWithPath:[Bundle pathForResource:@"ShortcutRecorder" ofType:@"bundle"]]; |
||||||
|
} |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
if (!Bundle) |
||||||
|
{ |
||||||
|
@throw [NSException exceptionWithName:NSInternalInconsistencyException |
||||||
|
reason:@"Unable to find bundle with resources." |
||||||
|
userInfo:nil]; |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
return Bundle; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
NSString *SRLoc(NSString *aKey) |
||||||
|
{ |
||||||
|
return NSLocalizedStringFromTableInBundle(aKey, @"ShortcutRecorder", SRBundle(), nil); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
NSImage *SRImage(NSString *anImageName) |
||||||
|
{ |
||||||
|
if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_6) |
||||||
|
return [[NSImage alloc] initByReferencingURL:[SRBundle() URLForImageResource:anImageName]]; |
||||||
|
else |
||||||
|
return [SRBundle() imageForResource:anImageName]; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
NSString *SRReadableStringForCocoaModifierFlagsAndKeyCode(NSEventModifierFlags aModifierFlags, unsigned short aKeyCode) |
||||||
|
{ |
||||||
|
SRKeyCodeTransformer *t = [SRKeyCodeTransformer sharedPlainTransformer]; |
||||||
|
NSString *c = [t transformedValue:@(aKeyCode)]; |
||||||
|
|
||||||
|
return [NSString stringWithFormat:@"%@%@%@%@%@", |
||||||
|
(aModifierFlags & NSCommandKeyMask ? SRLoc(@"Command-") : @""), |
||||||
|
(aModifierFlags & NSAlternateKeyMask ? SRLoc(@"Option-") : @""), |
||||||
|
(aModifierFlags & NSControlKeyMask ? SRLoc(@"Control-") : @""), |
||||||
|
(aModifierFlags & NSShiftKeyMask ? SRLoc(@"Shift-") : @""), |
||||||
|
c]; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
NSString *SRReadableASCIIStringForCocoaModifierFlagsAndKeyCode(NSEventModifierFlags aModifierFlags, unsigned short aKeyCode) |
||||||
|
{ |
||||||
|
SRKeyCodeTransformer *t = [SRKeyCodeTransformer sharedPlainASCIITransformer]; |
||||||
|
NSString *c = [t transformedValue:@(aKeyCode)]; |
||||||
|
|
||||||
|
return [NSString stringWithFormat:@"%@%@%@%@%@", |
||||||
|
(aModifierFlags & NSCommandKeyMask ? SRLoc(@"Command-") : @""), |
||||||
|
(aModifierFlags & NSAlternateKeyMask ? SRLoc(@"Option-") : @""), |
||||||
|
(aModifierFlags & NSControlKeyMask ? SRLoc(@"Control-") : @""), |
||||||
|
(aModifierFlags & NSShiftKeyMask ? SRLoc(@"Shift-") : @""), |
||||||
|
c]; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
static BOOL _SRKeyCodeWithFlagsEqualToKeyEquivalentWithFlags(unsigned short aKeyCode, |
||||||
|
NSEventModifierFlags aKeyCodeFlags, |
||||||
|
NSString *aKeyEquivalent, |
||||||
|
NSEventModifierFlags aKeyEquivalentModifierFlags, |
||||||
|
SRKeyCodeTransformer *aTransformer) |
||||||
|
{ |
||||||
|
if (!aKeyEquivalent) |
||||||
|
return NO; |
||||||
|
|
||||||
|
aKeyCodeFlags &= SRCocoaModifierFlagsMask; |
||||||
|
aKeyEquivalentModifierFlags &= SRCocoaModifierFlagsMask; |
||||||
|
|
||||||
|
if (aKeyCodeFlags == aKeyEquivalentModifierFlags) |
||||||
|
{ |
||||||
|
NSString *keyCodeRepresentation = [aTransformer transformedValue:@(aKeyCode) |
||||||
|
withImplicitModifierFlags:nil |
||||||
|
explicitModifierFlags:@(aKeyCodeFlags)]; |
||||||
|
return [keyCodeRepresentation isEqual:aKeyEquivalent]; |
||||||
|
} |
||||||
|
else if (!aKeyEquivalentModifierFlags || |
||||||
|
(aKeyCodeFlags & aKeyEquivalentModifierFlags) == aKeyEquivalentModifierFlags) |
||||||
|
{ |
||||||
|
// Some key equivalent modifier flags can be implicitly set by using special unicode characters. E.g. Œ insetead of opt-a. |
||||||
|
// However all modifier flags explictily set in key equivalent MUST be also set in key code flags. |
||||||
|
// E.g. ctrl-Œ/ctrl-opt-a and Œ/opt-a match this condition, but cmd-Œ/ctrl-opt-a doesn't. |
||||||
|
NSString *keyCodeRepresentation = [aTransformer transformedValue:@(aKeyCode) |
||||||
|
withImplicitModifierFlags:nil |
||||||
|
explicitModifierFlags:@(aKeyCodeFlags)]; |
||||||
|
|
||||||
|
if ([keyCodeRepresentation isEqual:aKeyEquivalent]) |
||||||
|
{ |
||||||
|
// Key code and key equivalent are not equal key code representation matches key equivalent, but modifier flags are not. |
||||||
|
return NO; |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
NSEventModifierFlags possiblyImplicitFlags = aKeyCodeFlags & ~aKeyEquivalentModifierFlags; |
||||||
|
keyCodeRepresentation = [aTransformer transformedValue:@(aKeyCode) |
||||||
|
withImplicitModifierFlags:@(possiblyImplicitFlags) |
||||||
|
explicitModifierFlags:@(aKeyEquivalentModifierFlags)]; |
||||||
|
return [keyCodeRepresentation isEqual:aKeyEquivalent]; |
||||||
|
} |
||||||
|
} |
||||||
|
else |
||||||
|
return NO; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
BOOL SRKeyCodeWithFlagsEqualToKeyEquivalentWithFlags(unsigned short aKeyCode, |
||||||
|
NSEventModifierFlags aKeyCodeFlags, |
||||||
|
NSString *aKeyEquivalent, |
||||||
|
NSEventModifierFlags aKeyEquivalentModifierFlags) |
||||||
|
{ |
||||||
|
BOOL isEqual = _SRKeyCodeWithFlagsEqualToKeyEquivalentWithFlags(aKeyCode, |
||||||
|
aKeyCodeFlags, |
||||||
|
aKeyEquivalent, |
||||||
|
aKeyEquivalentModifierFlags, |
||||||
|
[SRKeyCodeTransformer sharedASCIITransformer]); |
||||||
|
|
||||||
|
if (!isEqual) |
||||||
|
{ |
||||||
|
isEqual = _SRKeyCodeWithFlagsEqualToKeyEquivalentWithFlags(aKeyCode, |
||||||
|
aKeyCodeFlags, |
||||||
|
aKeyEquivalent, |
||||||
|
aKeyEquivalentModifierFlags, |
||||||
|
[SRKeyCodeTransformer sharedTransformer]); |
||||||
|
} |
||||||
|
|
||||||
|
return isEqual; |
||||||
|
} |
@ -0,0 +1,139 @@ |
|||||||
|
//
|
||||||
|
// SRKeyCodeTransformer.h
|
||||||
|
// ShortcutRecorder
|
||||||
|
//
|
||||||
|
// Copyright 2006-2012 Contributors. All rights reserved.
|
||||||
|
//
|
||||||
|
// License: BSD
|
||||||
|
//
|
||||||
|
// Contributors:
|
||||||
|
// David Dauer
|
||||||
|
// Jesper
|
||||||
|
// Jamie Kirkpatrick
|
||||||
|
// Ilya Kulakov
|
||||||
|
// Silvio Rizzi
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h> |
||||||
|
#import <Carbon/Carbon.h> |
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Transforms key code into unicode character or plain string. |
||||||
|
*/ |
||||||
|
@interface SRKeyCodeTransformer : NSValueTransformer |
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns initialized key code transformer. |
||||||
|
|
||||||
|
@param aUsesASCII Determines whether transformer uses only ASCII capable keyboard input source. |
||||||
|
|
||||||
|
@param aUsesPlainStrings Determines whether key codes without readable glyphs (e.g. F1...F19) are transformed to |
||||||
|
to unicode characters (NSF1FunctionKey...NSF19FunctionKey) suitable for setting key equivalents |
||||||
|
of Cocoa controls or to plain strings (@"F1"...@"F19") suitable for drawing, logging and accessibility. |
||||||
|
|
||||||
|
@discussion This method is the designated initializer for SRKeyCodeTransformer. |
||||||
|
*/ |
||||||
|
- (instancetype)initWithASCIICapableKeyboardInputSource:(BOOL)aUsesASCII plainStrings:(BOOL)aUsesPlainStrings; |
||||||
|
|
||||||
|
/*!
|
||||||
|
Determines whether transformer uses ASCII capable keyboard input source. |
||||||
|
*/ |
||||||
|
@property (readonly) BOOL usesASCIICapableKeyboardInputSource; |
||||||
|
|
||||||
|
/*!
|
||||||
|
Determines whether key codes without readable glyphs are transformed to unicode characters |
||||||
|
suitable for setting keqEquivalents or to plain strings suitable for drawing, logging and accessibility. |
||||||
|
*/ |
||||||
|
@property (readonly) BOOL usesPlainStrings; |
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns the shared transformer. |
||||||
|
*/ |
||||||
|
+ (instancetype)sharedTransformer; |
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns the shared transformer configured to use only ASCII capable keyboard input source. |
||||||
|
*/ |
||||||
|
+ (instancetype)sharedASCIITransformer; |
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns the shared transformer configured to transform key codes to plain strings. |
||||||
|
*/ |
||||||
|
+ (SRKeyCodeTransformer *)sharedPlainTransformer; |
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns the shared transformer configured to use only ASCII capable keyboard input source |
||||||
|
and to transform key codes to plain strings. |
||||||
|
*/ |
||||||
|
+ (SRKeyCodeTransformer *)sharedPlainASCIITransformer; |
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns mapping from special key codes to unicode characters. |
||||||
|
*/ |
||||||
|
+ (NSDictionary *)specialKeyCodesToUnicodeCharactersMapping; |
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns mapping from special key codes to plain strings. |
||||||
|
*/ |
||||||
|
+ (NSDictionary *)specialKeyCodesToPlainStringsMapping; |
||||||
|
|
||||||
|
/*!
|
||||||
|
Determines whether key code is special. |
||||||
|
|
||||||
|
@param aKeyCode Key code to be checked. |
||||||
|
*/ |
||||||
|
- (BOOL)isKeyCodeSpecial:(unsigned short)aKeyCode; |
||||||
|
|
||||||
|
/*!
|
||||||
|
Transforms given special key code into unicode character by taking into account modifier flags. |
||||||
|
|
||||||
|
@discussion E.g. the key code 0x30 is transformed to ⇥. But if shift is pressed, it is transformed to ⇤. |
||||||
|
|
||||||
|
@result Unicode character or plain string. nil if not a special key code. |
||||||
|
*/ |
||||||
|
- (NSString *)transformedSpecialKeyCode:(NSNumber *)aKeyCode withExplicitModifierFlags:(NSNumber *)aModifierFlags; |
||||||
|
|
||||||
|
/*!
|
||||||
|
Shorcut to [self transformedValue:aValue withImplicitModifierFlags:aModifierFlags explicitModifierFlags:0] |
||||||
|
*/ |
||||||
|
- (NSString *)transformedValue:(NSNumber *)aValue withModifierFlags:(NSNumber *)aModifierFlags; |
||||||
|
|
||||||
|
/*!
|
||||||
|
Transfroms given key code into unicode character by taking into account modifier flags. |
||||||
|
|
||||||
|
@param aValue An instance of NSNumber (unsigned short) that represents key code. |
||||||
|
|
||||||
|
@param anImplicitModifierFlags An instance of NSNumber (NSEventModifierFlags) that represents implicit modifier flags like opt in å. |
||||||
|
|
||||||
|
@param anExplicitModifierFlags An instance of NSNumber (NSEventModifierFlags) that represents explicit modifier flags like shift in shift-⇤. |
||||||
|
*/ |
||||||
|
- (NSString *)transformedValue:(NSNumber *)aValue withImplicitModifierFlags:(NSNumber *)anImplicitModifierFlags explicitModifierFlags:(NSNumber *)anExplicitModifierFlags; |
||||||
|
|
||||||
|
@end |
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
These constants represents drawable unicode characters for key codes that do not have |
||||||
|
appropriate constants in Carbon and Cocoa. |
||||||
|
*/ |
||||||
|
typedef NS_ENUM(unichar, SRKeyCodeGlyph) |
||||||
|
{ |
||||||
|
SRKeyCodeGlyphTabRight = 0x21E5, // ⇥
|
||||||
|
SRKeyCodeGlyphTabLeft = 0x21E4, // ⇤
|
||||||
|
SRKeyCodeGlyphReturn = 0x2305, // ⌅
|
||||||
|
SRKeyCodeGlyphReturnR2L = 0x21A9, // ↩
|
||||||
|
SRKeyCodeGlyphDeleteLeft = 0x232B, // ⌫
|
||||||
|
SRKeyCodeGlyphDeleteRight = 0x2326, // ⌦
|
||||||
|
SRKeyCodeGlyphPadClear = 0x2327, // ⌧
|
||||||
|
SRKeyCodeGlyphLeftArrow = 0x2190, // ←
|
||||||
|
SRKeyCodeGlyphRightArrow = 0x2192, // →
|
||||||
|
SRKeyCodeGlyphUpArrow = 0x2191, // ↑
|
||||||
|
SRKeyCodeGlyphDownArrow = 0x2193, // ↓
|
||||||
|
SRKeyCodeGlyphPageDown = 0x21DF, // ⇟
|
||||||
|
SRKeyCodeGlyphPageUp = 0x21DE, // ⇞
|
||||||
|
SRKeyCodeGlyphNorthwestArrow = 0x2196, // ↖
|
||||||
|
SRKeyCodeGlyphSoutheastArrow = 0x2198, // ↘
|
||||||
|
SRKeyCodeGlyphEscape = 0x238B, // ⎋
|
||||||
|
SRKeyCodeGlyphSpace = 0x0020, // ' '
|
||||||
|
}; |
@ -0,0 +1,21 @@ |
|||||||
|
//
|
||||||
|
// SRKeyEquivalentModifierMaskTransformer.h
|
||||||
|
// ShortcutRecorder
|
||||||
|
//
|
||||||
|
// Copyright 2012 Contributors. All rights reserved.
|
||||||
|
//
|
||||||
|
// License: BSD
|
||||||
|
//
|
||||||
|
// Contributors to this file:
|
||||||
|
// Ilya Kulakov
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h> |
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Transform dictionary representation of shortcut into string suitable |
||||||
|
for -setKeyEquivalentModifierMask: of NSButton and NSMenuItem. |
||||||
|
*/ |
||||||
|
@interface SRKeyEquivalentModifierMaskTransformer : NSValueTransformer |
||||||
|
|
||||||
|
@end |
@ -0,0 +1,44 @@ |
|||||||
|
// |
||||||
|
// SRKeyEquivalentModifierMaskTransformer.m |
||||||
|
// ShortcutRecorder |
||||||
|
// |
||||||
|
// Copyright 2012 Contributors. All rights reserved. |
||||||
|
// |
||||||
|
// License: BSD |
||||||
|
// |
||||||
|
// Contributors: |
||||||
|
// Ilya Kulakov |
||||||
|
|
||||||
|
#import "SRKeyEquivalentModifierMaskTransformer.h" |
||||||
|
#import "SRKeyCodeTransformer.h" |
||||||
|
#import "SRRecorderControl.h" |
||||||
|
|
||||||
|
|
||||||
|
@implementation SRKeyEquivalentModifierMaskTransformer |
||||||
|
|
||||||
|
#pragma mark NSValueTransformer |
||||||
|
|
||||||
|
+ (BOOL)allowsReverseTransformation |
||||||
|
{ |
||||||
|
return NO; |
||||||
|
} |
||||||
|
|
||||||
|
+ (Class)transformedValueClass |
||||||
|
{ |
||||||
|
return [NSNumber class]; |
||||||
|
} |
||||||
|
|
||||||
|
- (NSNumber *)transformedValue:(NSDictionary *)aValue |
||||||
|
{ |
||||||
|
if (![aValue isKindOfClass:[NSDictionary class]]) |
||||||
|
return @(0); |
||||||
|
|
||||||
|
NSNumber *modifierFlags = aValue[SRShortcutModifierFlagsKey]; |
||||||
|
|
||||||
|
if (![modifierFlags isKindOfClass:[NSNumber class]]) |
||||||
|
return @(0); |
||||||
|
|
||||||
|
return modifierFlags; |
||||||
|
} |
||||||
|
|
||||||
|
@end |
@ -0,0 +1,21 @@ |
|||||||
|
//
|
||||||
|
// SRKeyEquivalentTransformer.h
|
||||||
|
// ShortcutRecorder
|
||||||
|
//
|
||||||
|
// Copyright 2012 Contributors. All rights reserved.
|
||||||
|
//
|
||||||
|
// License: BSD
|
||||||
|
//
|
||||||
|
// Contributors to this file:
|
||||||
|
// Ilya Kulakov
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h> |
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Transform dictionary representation of shortcut into string suitable |
||||||
|
for -setKeyEquivalent: of NSButton and NSMenuItem. |
||||||
|
*/ |
||||||
|
@interface SRKeyEquivalentTransformer : NSValueTransformer |
||||||
|
|
||||||
|
@end |
@ -0,0 +1,53 @@ |
|||||||
|
// |
||||||
|
// SRKeyEquivalentTransformer.m |
||||||
|
// ShortcutRecorder |
||||||
|
// |
||||||
|
// Copyright 2012 Contributors. All rights reserved. |
||||||
|
// |
||||||
|
// License: BSD |
||||||
|
// |
||||||
|
// Contributors: |
||||||
|
// Ilya Kulakov |
||||||
|
|
||||||
|
#import "SRKeyEquivalentTransformer.h" |
||||||
|
#import "SRKeyCodeTransformer.h" |
||||||
|
#import "SRRecorderControl.h" |
||||||
|
|
||||||
|
|
||||||
|
@implementation SRKeyEquivalentTransformer |
||||||
|
|
||||||
|
#pragma mark NSValueTransformer |
||||||
|
|
||||||
|
+ (BOOL)allowsReverseTransformation |
||||||
|
{ |
||||||
|
return NO; |
||||||
|
} |
||||||
|
|
||||||
|
+ (Class)transformedValueClass |
||||||
|
{ |
||||||
|
return [NSString class]; |
||||||
|
} |
||||||
|
|
||||||
|
- (NSString *)transformedValue:(NSDictionary *)aValue |
||||||
|
{ |
||||||
|
if (![aValue isKindOfClass:[NSDictionary class]]) |
||||||
|
return @""; |
||||||
|
|
||||||
|
NSNumber *keyCode = aValue[SRShortcutKeyCode]; |
||||||
|
|
||||||
|
if (![keyCode isKindOfClass:[NSNumber class]]) |
||||||
|
return @""; |
||||||
|
|
||||||
|
NSNumber *modifierFlags = aValue[SRShortcutModifierFlagsKey]; |
||||||
|
|
||||||
|
if (![modifierFlags isKindOfClass:[NSNumber class]]) |
||||||
|
modifierFlags = @(0); |
||||||
|
|
||||||
|
SRKeyCodeTransformer *t = [SRKeyCodeTransformer sharedASCIITransformer]; |
||||||
|
|
||||||
|
return [t transformedValue:keyCode |
||||||
|
withImplicitModifierFlags:nil |
||||||
|
explicitModifierFlags:modifierFlags]; |
||||||
|
} |
||||||
|
|
||||||
|
@end |
@ -0,0 +1,37 @@ |
|||||||
|
//
|
||||||
|
// SRModifierFlagsTransformer.h
|
||||||
|
// ShortcutRecorder
|
||||||
|
//
|
||||||
|
// Copyright 2006-2012 Contributors. All rights reserved.
|
||||||
|
//
|
||||||
|
// License: BSD
|
||||||
|
//
|
||||||
|
// Contributors:
|
||||||
|
// Ilya Kulakov
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h> |
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Transforms mask of Cocoa modifier flags to string of unicode characters. |
||||||
|
*/ |
||||||
|
@interface SRModifierFlagsTransformer : NSValueTransformer |
||||||
|
|
||||||
|
- (instancetype)initWithPlainStrings:(BOOL)aUsesPlainStrings; |
||||||
|
|
||||||
|
/*!
|
||||||
|
Determines whether modifier flags are transformed to unicode characters or to plain strings. |
||||||
|
*/ |
||||||
|
@property (readonly) BOOL usesPlainStrings; |
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns the shared transformer. |
||||||
|
*/ |
||||||
|
+ (instancetype)sharedTransformer; |
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns the shared plain transformer. |
||||||
|
*/ |
||||||
|
+ (instancetype)sharedPlainTransformer; |
||||||
|
|
||||||
|
@end |
@ -0,0 +1,108 @@ |
|||||||
|
// |
||||||
|
// SRModifierFlagsTransformer.m |
||||||
|
// ShortcutRecorder |
||||||
|
// |
||||||
|
// Copyright 2006-2012 Contributors. All rights reserved. |
||||||
|
// |
||||||
|
// License: BSD |
||||||
|
// |
||||||
|
// Contributors: |
||||||
|
// Ilya Kulakov |
||||||
|
|
||||||
|
#import "SRModifierFlagsTransformer.h" |
||||||
|
#import "SRCommon.h" |
||||||
|
|
||||||
|
|
||||||
|
@implementation SRModifierFlagsTransformer |
||||||
|
|
||||||
|
- (instancetype)initWithPlainStrings:(BOOL)aUsesPlainStrings |
||||||
|
{ |
||||||
|
self = [super init]; |
||||||
|
|
||||||
|
if (self) |
||||||
|
{ |
||||||
|
_usesPlainStrings = aUsesPlainStrings; |
||||||
|
} |
||||||
|
|
||||||
|
return self; |
||||||
|
} |
||||||
|
|
||||||
|
- (instancetype)init |
||||||
|
{ |
||||||
|
return [self initWithPlainStrings:NO]; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
#pragma mark Methods |
||||||
|
|
||||||
|
+ (instancetype)sharedTransformer |
||||||
|
{ |
||||||
|
static dispatch_once_t OnceToken; |
||||||
|
static SRModifierFlagsTransformer *Transformer = nil; |
||||||
|
dispatch_once(&OnceToken, ^{ |
||||||
|
Transformer = [[self alloc] initWithPlainStrings:NO]; |
||||||
|
}); |
||||||
|
return Transformer; |
||||||
|
} |
||||||
|
|
||||||
|
+ (instancetype)sharedPlainTransformer |
||||||
|
{ |
||||||
|
static dispatch_once_t OnceToken; |
||||||
|
static SRModifierFlagsTransformer *Transformer = nil; |
||||||
|
dispatch_once(&OnceToken, ^{ |
||||||
|
Transformer = [[self alloc] initWithPlainStrings:YES]; |
||||||
|
}); |
||||||
|
return Transformer; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
#pragma mark NSValueTransformer |
||||||
|
|
||||||
|
+ (Class)transformedValueClass |
||||||
|
{ |
||||||
|
return [NSString class]; |
||||||
|
} |
||||||
|
|
||||||
|
+ (BOOL)allowsReverseTransformation |
||||||
|
{ |
||||||
|
return NO; |
||||||
|
} |
||||||
|
|
||||||
|
- (NSString *)transformedValue:(NSNumber *)aValue |
||||||
|
{ |
||||||
|
if (![aValue isKindOfClass:[NSNumber class]]) |
||||||
|
return nil; |
||||||
|
else if (self.usesPlainStrings) |
||||||
|
{ |
||||||
|
NSEventModifierFlags modifierFlags = [aValue unsignedIntegerValue]; |
||||||
|
NSMutableString *s = [NSMutableString string]; |
||||||
|
|
||||||
|
if (modifierFlags & NSControlKeyMask) |
||||||
|
[s appendString:SRLoc(@"Control-")]; |
||||||
|
|
||||||
|
if (modifierFlags & NSAlternateKeyMask) |
||||||
|
[s appendString:SRLoc(@"Option-")]; |
||||||
|
|
||||||
|
if (modifierFlags & NSShiftKeyMask) |
||||||
|
[s appendString:SRLoc(@"Shift-")]; |
||||||
|
|
||||||
|
if (modifierFlags & NSCommandKeyMask) |
||||||
|
[s appendString:SRLoc(@"Command-")]; |
||||||
|
|
||||||
|
if (s.length > 0) |
||||||
|
[s deleteCharactersInRange:NSMakeRange(s.length - 1, 1)]; |
||||||
|
|
||||||
|
return s; |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
NSEventModifierFlags f = [aValue unsignedIntegerValue]; |
||||||
|
return [NSString stringWithFormat:@"%@%@%@%@", |
||||||
|
(f & NSControlKeyMask ? @"⌃" : @""), |
||||||
|
(f & NSAlternateKeyMask ? @"⌥" : @""), |
||||||
|
(f & NSShiftKeyMask ? @"⇧" : @""), |
||||||
|
(f & NSCommandKeyMask ? @"⌘" : @"")]; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@end |
@ -0,0 +1,436 @@ |
|||||||
|
//
|
||||||
|
// SRRecorderControl.h
|
||||||
|
// ShortcutRecorder
|
||||||
|
//
|
||||||
|
// Copyright 2006-2012 Contributors. All rights reserved.
|
||||||
|
//
|
||||||
|
// License: BSD
|
||||||
|
//
|
||||||
|
// Contributors:
|
||||||
|
// David Dauer
|
||||||
|
// Jesper
|
||||||
|
// Jamie Kirkpatrick
|
||||||
|
// Ilya Kulakov
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h> |
||||||
|
#import <ShortcutRecorder/SRCommon.h> |
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Key code. |
||||||
|
|
||||||
|
@discussion NSNumber representation of unsigned short. |
||||||
|
Required key of SRRecorderControl's objectValue. |
||||||
|
*/ |
||||||
|
extern NSString *const SRShortcutKeyCode; |
||||||
|
|
||||||
|
/*!
|
||||||
|
Modifier flags. |
||||||
|
|
||||||
|
@discussion NSNumber representation of NSEventModifierFlags. |
||||||
|
Optional key of SRRecorderControl's objectValue. |
||||||
|
*/ |
||||||
|
extern NSString *const SRShortcutModifierFlagsKey; |
||||||
|
|
||||||
|
/*!
|
||||||
|
Interpretation of key code and modifier flags depending on system locale and input source |
||||||
|
used when shortcut was taken. |
||||||
|
|
||||||
|
@discussion NSString. |
||||||
|
Optional key of SRRecorderControl's objectValue. |
||||||
|
*/ |
||||||
|
extern NSString *const SRShortcutCharacters; |
||||||
|
|
||||||
|
/*!
|
||||||
|
Interpretation of key code without modifier flags depending on system locale and input source |
||||||
|
used when shortcut was taken. |
||||||
|
|
||||||
|
@discussion NSString. |
||||||
|
Optional key of SRRecorderControl's objectValue. |
||||||
|
*/ |
||||||
|
extern NSString *const SRShortcutCharactersIgnoringModifiers; |
||||||
|
|
||||||
|
|
||||||
|
@protocol SRRecorderControlDelegate; |
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
An SRRecorderControl object is a control (but not a subclass of NSControl) that allows you to record shortcuts. |
||||||
|
|
||||||
|
@discussion In addition to NSView bindings, exposes: |
||||||
|
NSValueBinding. This binding supports 2 options: |
||||||
|
- NSValueTransformerBindingOption |
||||||
|
- NSValueTransformerNameBindingOption |
||||||
|
NSEnabledBinding. This binding supports 2 options: |
||||||
|
- NSValueTransformerBindingOption |
||||||
|
- NSValueTransformerNameBindingOption |
||||||
|
Note that at that moment, this binding _is not_ multivalue. |
||||||
|
|
||||||
|
Required height: 25 points |
||||||
|
Recommended min width: 100 points |
||||||
|
*/ |
||||||
|
IB_DESIGNABLE |
||||||
|
@interface SRRecorderControl : NSView /* <NSAccessibility, NSKeyValueBindingCreation, NSToolTipOwner, NSNibAwaking> */ |
||||||
|
|
||||||
|
/*!
|
||||||
|
The receiver’s delegate. |
||||||
|
|
||||||
|
@discussion A recorder control delegate responds to editing-related messages. You can use to to prevent editing |
||||||
|
in some cases or to validate typed shortcuts. |
||||||
|
*/ |
||||||
|
@property (assign) IBOutlet NSObject<SRRecorderControlDelegate> *delegate; |
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns an integer bit field indicating allowed modifier flags. |
||||||
|
|
||||||
|
@discussion Defaults to SRCocoaModifierFlagsMask. |
||||||
|
*/ |
||||||
|
@property (readonly) IBInspectable NSEventModifierFlags allowedModifierFlags; |
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns an integer bit field indicating required modifier flags. |
||||||
|
|
||||||
|
@discussion Defaults to 0. |
||||||
|
*/ |
||||||
|
@property (readonly) IBInspectable NSEventModifierFlags requiredModifierFlags; |
||||||
|
|
||||||
|
/*!
|
||||||
|
Determines whether shortcuts without modifier flags are allowed. |
||||||
|
|
||||||
|
@discussion Defaults to NO. |
||||||
|
*/ |
||||||
|
@property (readonly) IBInspectable BOOL allowsEmptyModifierFlags; |
||||||
|
|
||||||
|
/*!
|
||||||
|
Determines whether the control reinterpret key code and modifier flags |
||||||
|
using ASCII capable input source. |
||||||
|
|
||||||
|
@discussion Defaults to YES. |
||||||
|
If not set, the same key code may be draw differently depending on current input source. |
||||||
|
E.g. with US English input source key code 0x0 is interpreted as "a", |
||||||
|
however with Russian input source, it's interpreted as "ф". |
||||||
|
*/ |
||||||
|
@property IBInspectable BOOL drawsASCIIEquivalentOfShortcut; |
||||||
|
|
||||||
|
/*!
|
||||||
|
Determines whether Escape is used to cancel recording. |
||||||
|
|
||||||
|
@discussion Defaults to YES. |
||||||
|
If set, Escape without modifier flags cannot be recorded as shortcut. |
||||||
|
*/ |
||||||
|
@property IBInspectable BOOL allowsEscapeToCancelRecording; |
||||||
|
|
||||||
|
/*!
|
||||||
|
Determines whether delete (or forward delete) is used to remove current shortcut and end recording. |
||||||
|
|
||||||
|
@discussion Defaults to YES. |
||||||
|
If set, neither Delete nor Forward Delete without modifier flags can be recorded as shortcut. |
||||||
|
*/ |
||||||
|
@property IBInspectable BOOL allowsDeleteToClearShortcutAndEndRecording; |
||||||
|
|
||||||
|
/*!
|
||||||
|
Determines whether control enabled and can be edited or not. |
||||||
|
|
||||||
|
@discussion Defaults to YES. |
||||||
|
*/ |
||||||
|
@property (nonatomic, getter=isEnabled) IBInspectable BOOL enabled; |
||||||
|
|
||||||
|
/*!
|
||||||
|
Determines whether recording is in process. |
||||||
|
*/ |
||||||
|
@property (nonatomic, readonly) BOOL isRecording; |
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns dictionary representation of receiver's shortcut. |
||||||
|
*/ |
||||||
|
@property (nonatomic, copy) NSDictionary *objectValue; |
||||||
|
|
||||||
|
/*!
|
||||||
|
Configures recording behavior of the control. |
||||||
|
|
||||||
|
@param newAllowedModifierFlags New allowed modifier flags. |
||||||
|
|
||||||
|
@param newRequiredModifierFlags New required modifier flags. |
||||||
|
|
||||||
|
@param newAllowsEmptyModifierFlags Determines whether empty modifier flags are allowed. |
||||||
|
|
||||||
|
@discussion Flags are filtered using SRCocoaModifierFlagsMask. Flags does not affect object values set manually. |
||||||
|
|
||||||
|
These restrictions can be ignored if delegate implements shortcutRecorder:shouldUnconditionallyAllowModifierFlags:forKeyCode: and returns YES for given modifier flags and key code. |
||||||
|
|
||||||
|
Throws NSInvalidArgumentException if either required flags are not allowed |
||||||
|
or required flags are not empty and no modifier flags are allowed. |
||||||
|
|
||||||
|
@see SRRecorderControlDelegate |
||||||
|
*/ |
||||||
|
- (void)setAllowedModifierFlags:(NSEventModifierFlags)newAllowedModifierFlags |
||||||
|
requiredModifierFlags:(NSEventModifierFlags)newRequiredModifierFlags |
||||||
|
allowsEmptyModifierFlags:(BOOL)newAllowsEmptyModifierFlags; |
||||||
|
|
||||||
|
/*!
|
||||||
|
Called to initialize internal state after either initWithFrame or awakeFromNib is called. |
||||||
|
*/ |
||||||
|
- (void)_initInternalState; |
||||||
|
|
||||||
|
/*!
|
||||||
|
Turns on the recording mode. |
||||||
|
|
||||||
|
@discussion You SHOULD not call this method directly. |
||||||
|
*/ |
||||||
|
- (BOOL)beginRecording; |
||||||
|
|
||||||
|
/*!
|
||||||
|
Turns off the recording mode. Current object value is preserved. |
||||||
|
|
||||||
|
@discussion You SHOULD not call this method directly. |
||||||
|
*/ |
||||||
|
- (void)endRecording; |
||||||
|
|
||||||
|
/*!
|
||||||
|
Clears object value and turns off the recording mode. |
||||||
|
|
||||||
|
@discussion You SHOULD not call this method directly. |
||||||
|
*/ |
||||||
|
- (void)clearAndEndRecording; |
||||||
|
|
||||||
|
/*!
|
||||||
|
Designated method to end recording. Sets a given object value, updates bindings and turns off the recording mode. |
||||||
|
|
||||||
|
@discussion You SHOULD not call this method directly. |
||||||
|
*/ |
||||||
|
- (void)endRecordingWithObjectValue:(NSDictionary *)anObjectValue; |
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns shape of the control. |
||||||
|
|
||||||
|
@discussion Primarily used to draw appropriate focus ring. |
||||||
|
*/ |
||||||
|
- (NSBezierPath *)controlShape; |
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns rect for label with given attributes. |
||||||
|
|
||||||
|
@param aLabel Label for drawing. |
||||||
|
|
||||||
|
@param anAttributes A dictionary of NSAttributedString text attributes to be applied to the string. |
||||||
|
*/ |
||||||
|
- (NSRect)rectForLabel:(NSString *)aLabel withAttributes:(NSDictionary *)anAttributes; |
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns rect of the snap back button in the receiver coordinates. |
||||||
|
*/ |
||||||
|
- (NSRect)snapBackButtonRect; |
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns rect of the clear button in the receiver coordinates. |
||||||
|
|
||||||
|
@discussion Returned rect will have empty width (other values will be valid) if button should not be drawn. |
||||||
|
*/ |
||||||
|
- (NSRect)clearButtonRect; |
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns label to be displayed by the receiver. |
||||||
|
|
||||||
|
@discussion Returned value depends on isRecording state objectValue and currenlty pressed keys and modifier flags. |
||||||
|
*/ |
||||||
|
- (NSString *)label; |
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns label for accessibility. |
||||||
|
|
||||||
|
@discussion Returned value depends on isRecording state objectValue and currenlty pressed keys and modifier flags. |
||||||
|
*/ |
||||||
|
- (NSString *)accessibilityLabel; |
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns string representation of object value. |
||||||
|
*/ |
||||||
|
- (NSString *)stringValue; |
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns string representation of object value for accessibility. |
||||||
|
*/ |
||||||
|
- (NSString *)accessibilityStringValue; |
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns attirbutes of label to be displayed by the receiver according to current state. |
||||||
|
|
||||||
|
@see normalLabelAttributes |
||||||
|
|
||||||
|
@see recordingLabelAttributes |
||||||
|
|
||||||
|
@see disabledLabelAttributes |
||||||
|
*/ |
||||||
|
- (NSDictionary *)labelAttributes; |
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns attributes of label to be displayed by the receiver in normal mode. |
||||||
|
*/ |
||||||
|
- (NSDictionary *)normalLabelAttributes; |
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns attributes of label to be displayed by the receiver in recording mode. |
||||||
|
*/ |
||||||
|
- (NSDictionary *)recordingLabelAttributes; |
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns attributes of label to be displayed by the receiver in disabled mode. |
||||||
|
*/ |
||||||
|
- (NSDictionary *)disabledLabelAttributes; |
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Draws background of the receiver into current graphics context. |
||||||
|
*/ |
||||||
|
- (void)drawBackground:(NSRect)aDirtyRect; |
||||||
|
|
||||||
|
/*!
|
||||||
|
Draws interior of the receiver into current graphics context. |
||||||
|
*/ |
||||||
|
- (void)drawInterior:(NSRect)aDirtyRect; |
||||||
|
|
||||||
|
/*!
|
||||||
|
Draws label of the receiver into current graphics context. |
||||||
|
*/ |
||||||
|
- (void)drawLabel:(NSRect)aDirtyRect; |
||||||
|
|
||||||
|
/*!
|
||||||
|
Draws snap back button of the receiver into current graphics context. |
||||||
|
*/ |
||||||
|
- (void)drawSnapBackButton:(NSRect)aDirtyRect; |
||||||
|
|
||||||
|
/*!
|
||||||
|
Draws clear button of the receiver into current graphics context. |
||||||
|
*/ |
||||||
|
- (void)drawClearButton:(NSRect)aDirtyRect; |
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Determines whether main button (representation of the receiver in normal mode) is highlighted. |
||||||
|
*/ |
||||||
|
- (BOOL)isMainButtonHighlighted; |
||||||
|
|
||||||
|
/*!
|
||||||
|
Determines whether snap back button is highlighted. |
||||||
|
*/ |
||||||
|
- (BOOL)isSnapBackButtonHighlighted; |
||||||
|
|
||||||
|
/*!
|
||||||
|
Determines whetehr clear button is highlighted. |
||||||
|
*/ |
||||||
|
- (BOOL)isClearButtonHighlighted; |
||||||
|
|
||||||
|
/*!
|
||||||
|
Determines whether modifier flags are valid for key code according to the receiver settings. |
||||||
|
|
||||||
|
@param aModifierFlags Proposed modifier flags. |
||||||
|
|
||||||
|
@param aKeyCode Code of the pressed key. |
||||||
|
|
||||||
|
@see allowedModifierFlags |
||||||
|
|
||||||
|
@see allowsEmptyModifierFlags |
||||||
|
|
||||||
|
@see requiredModifierFlags |
||||||
|
*/ |
||||||
|
- (BOOL)areModifierFlagsValid:(NSEventModifierFlags)aModifierFlags forKeyCode:(unsigned short)aKeyCode; |
||||||
|
|
||||||
|
/*!
|
||||||
|
A helper method to propagate view-driven changes back to model. |
||||||
|
|
||||||
|
@discussion This method makes it easier to propagate changes from a view |
||||||
|
back to the model without overriding bind:toObject:withKeyPath:options: |
||||||
|
|
||||||
|
@see http://tomdalling.com/blog/cocoa/implementing-your-own-cocoa-bindings/
|
||||||
|
*/ |
||||||
|
- (void)propagateValue:(id)aValue forBinding:(NSString *)aBinding; |
||||||
|
|
||||||
|
@end |
||||||
|
|
||||||
|
|
||||||
|
@protocol SRRecorderControlDelegate <NSObject> |
||||||
|
|
||||||
|
@optional |
||||||
|
|
||||||
|
/*!
|
||||||
|
Asks the delegate if editing should begin in the specified shortcut recorder. |
||||||
|
|
||||||
|
@param aRecorder The shortcut recorder which editing is about to begin. |
||||||
|
|
||||||
|
@result YES if an editing session should be initiated; otherwise, NO to disallow editing. |
||||||
|
|
||||||
|
@discussion Implementation of this method by the delegate is optional. If it is not present, editing proceeds as if this method had returned YES. |
||||||
|
*/ |
||||||
|
- (BOOL)shortcutRecorderShouldBeginRecording:(SRRecorderControl *)aRecorder; |
||||||
|
|
||||||
|
/*!
|
||||||
|
Gives a delegate opportunity to bypass rules specified by allowed and required modifier flags. |
||||||
|
|
||||||
|
@param aRecorder The shortcut recorder for which editing ended. |
||||||
|
|
||||||
|
@param aModifierFlags Proposed modifier flags. |
||||||
|
|
||||||
|
@param aKeyCode Code of the pressed key. |
||||||
|
|
||||||
|
@result YES if recorder should bypass key code with given modifier flags despite settings like required modifier flags, allowed modifier flags. |
||||||
|
|
||||||
|
@discussion Implementation of this method by the delegate is optional. |
||||||
|
Normally, you wouldn't allow a user to record shourcut without modifier flags set: disallow 'a', but allow cmd-'a'. |
||||||
|
However, some keys were designed to be key shortcuts by itself. E.g. Functional keys. By implementing this method a delegate can allow |
||||||
|
these special keys to be set without modifier flags even when the control is configured to disallow empty modifier flags. |
||||||
|
|
||||||
|
@see allowedModifierFlags |
||||||
|
|
||||||
|
@see allowsEmptyModifierFlags |
||||||
|
|
||||||
|
@see requiredModifierFlags |
||||||
|
*/ |
||||||
|
- (BOOL)shortcutRecorder:(SRRecorderControl *)aRecorder shouldUnconditionallyAllowModifierFlags:(NSEventModifierFlags)aModifierFlags forKeyCode:(unsigned short)aKeyCode; |
||||||
|
|
||||||
|
/*!
|
||||||
|
Asks the delegate if the shortcut can be set by the specified shortcut recorder. |
||||||
|
|
||||||
|
@param aRecorder The shortcut recorder which shortcut is beign to be recordered. |
||||||
|
|
||||||
|
@param aShortcut The Shortcut user typed. |
||||||
|
|
||||||
|
@result YES if shortcut can be recordered. Otherwise NO. |
||||||
|
|
||||||
|
@discussion Implementation of this method by the delegate is optional. If it is not present, shortcut is recordered as if this method had returned YES. |
||||||
|
You may implement this method to filter shortcuts that were already set by other recorders. |
||||||
|
|
||||||
|
@see SRValidator |
||||||
|
*/ |
||||||
|
- (BOOL)shortcutRecorder:(SRRecorderControl *)aRecorder canRecordShortcut:(NSDictionary *)aShortcut; |
||||||
|
|
||||||
|
/*!
|
||||||
|
Tells the delegate that editing stopped for the specified shortcut recorder. |
||||||
|
|
||||||
|
@param aRecorder The shortcut recorder for which editing ended. |
||||||
|
|
||||||
|
@discussion Implementation of this method by the delegate is optional. |
||||||
|
*/ |
||||||
|
- (void)shortcutRecorderDidEndRecording:(SRRecorderControl *)aRecorder; |
||||||
|
|
||||||
|
@end |
||||||
|
|
||||||
|
|
||||||
|
FOUNDATION_STATIC_INLINE BOOL SRShortcutEqualToShortcut(NSDictionary *a, NSDictionary *b) |
||||||
|
{ |
||||||
|
if (a == b) |
||||||
|
return YES; |
||||||
|
else if (a && !b) |
||||||
|
return NO; |
||||||
|
else if (!a && b) |
||||||
|
return NO; |
||||||
|
else |
||||||
|
return ([a[SRShortcutKeyCode] isEqual:b[SRShortcutKeyCode]] && [a[SRShortcutModifierFlagsKey] isEqual:b[SRShortcutModifierFlagsKey]]); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
FOUNDATION_STATIC_INLINE NSDictionary *SRShortcutWithCocoaModifierFlagsAndKeyCode(NSEventModifierFlags aModifierFlags, unsigned short aKeyCode) |
||||||
|
{ |
||||||
|
return @{SRShortcutKeyCode: @(aKeyCode), SRShortcutModifierFlagsKey: @(aModifierFlags)}; |
||||||
|
} |
@ -0,0 +1,131 @@ |
|||||||
|
//
|
||||||
|
// SRValidator.h
|
||||||
|
// ShortcutRecorder
|
||||||
|
//
|
||||||
|
// Copyright 2006-2012 Contributors. All rights reserved.
|
||||||
|
//
|
||||||
|
// License: BSD
|
||||||
|
//
|
||||||
|
// Contributors:
|
||||||
|
// David Dauer
|
||||||
|
// Jesper
|
||||||
|
// Jamie Kirkpatrick
|
||||||
|
// Andy Kim
|
||||||
|
// Silvio Rizzi
|
||||||
|
// Ilya Kulakov
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h> |
||||||
|
|
||||||
|
|
||||||
|
@protocol SRValidatorDelegate; |
||||||
|
|
||||||
|
/*!
|
||||||
|
Implements logic to check whether shortcut is taken by other parts of the application and system. |
||||||
|
*/ |
||||||
|
@interface SRValidator : NSObject |
||||||
|
|
||||||
|
@property (assign) NSObject<SRValidatorDelegate> *delegate; |
||||||
|
|
||||||
|
- (instancetype)initWithDelegate:(NSObject<SRValidatorDelegate> *)aDelegate; |
||||||
|
|
||||||
|
/*!
|
||||||
|
Determines whether shortcut is taken. |
||||||
|
|
||||||
|
@discussion Key is checked in the following order: |
||||||
|
1. If delegate implements shortcutValidator:isKeyCode:andFlagsTaken:reason: |
||||||
|
2. If delegate allows system-wide shortcuts are checked |
||||||
|
3. If delegate allows application menu it checked |
||||||
|
|
||||||
|
@see SRValidatorDelegate |
||||||
|
*/ |
||||||
|
- (BOOL)isKeyCode:(unsigned short)aKeyCode andFlagsTaken:(NSEventModifierFlags)aFlags error:(NSError **)outError; |
||||||
|
|
||||||
|
/*!
|
||||||
|
Determines whether shortcut is taken in delegate. |
||||||
|
|
||||||
|
@discussion If delegate does not implement appropriate method, returns immediately. |
||||||
|
*/ |
||||||
|
- (BOOL)isKeyCode:(unsigned short)aKeyCode andFlagTakenInDelegate:(NSEventModifierFlags)aFlags error:(NSError **)outError; |
||||||
|
|
||||||
|
/*!
|
||||||
|
Determines whether shortcut is taken by system-wide shortcuts. |
||||||
|
|
||||||
|
@discussion Does not check whether delegate allows or disallows checking in system shortcuts. |
||||||
|
*/ |
||||||
|
- (BOOL)isKeyCode:(unsigned short)aKeyCode andFlagsTakenInSystemShortcuts:(NSEventModifierFlags)aFlags error:(NSError **)outError; |
||||||
|
|
||||||
|
/*!
|
||||||
|
Determines whether shortcut is taken by application menu item. |
||||||
|
|
||||||
|
@discussion Does not check whether delegate allows or disallows checking in application menu. |
||||||
|
*/ |
||||||
|
- (BOOL)isKeyCode:(unsigned short)aKeyCode andFlags:(NSEventModifierFlags)aFlags takenInMenu:(NSMenu *)aMenu error:(NSError **)outError; |
||||||
|
|
||||||
|
@end |
||||||
|
|
||||||
|
|
||||||
|
@protocol SRValidatorDelegate |
||||||
|
|
||||||
|
@optional |
||||||
|
|
||||||
|
/*!
|
||||||
|
Asks the delegate if aKeyCode and aFlags are valid. |
||||||
|
|
||||||
|
@param aValidator The validator that validates key code and flags. |
||||||
|
|
||||||
|
@param aKeyCode Key code to validate. |
||||||
|
|
||||||
|
@param aFlags Flags to validate. |
||||||
|
|
||||||
|
@param outReason If delegate decides that shortcut is invalid, it may pass here an error message. |
||||||
|
|
||||||
|
@result YES if shortcut is valid. Otherwise NO. |
||||||
|
|
||||||
|
@discussion Implementation of this method by the delegate is optional. If it is not present, checking proceeds as if this method had returned YES. |
||||||
|
*/ |
||||||
|
- (BOOL)shortcutValidator:(SRValidator *)aValidator isKeyCode:(unsigned short)aKeyCode andFlagsTaken:(NSEventModifierFlags)aFlags reason:(NSString **)outReason; |
||||||
|
|
||||||
|
/*!
|
||||||
|
Asks the delegate whether validator should check key equivalents of app's menu items. |
||||||
|
|
||||||
|
@param aValidator The validator that going to check app's menu items. |
||||||
|
|
||||||
|
@result YES if validator should check key equivalents of app's menu items. Otherwise NO. |
||||||
|
|
||||||
|
@discussion Implementation of this method by the delegate is optional. If it is not present, checking proceeds as if this method had returned YES. |
||||||
|
*/ |
||||||
|
- (BOOL)shortcutValidatorShouldCheckMenu:(SRValidator *)aValidator; |
||||||
|
|
||||||
|
/*!
|
||||||
|
Asks the delegate whether it should check system shortcuts. |
||||||
|
|
||||||
|
@param aValidator The validator that going to check system shortcuts. |
||||||
|
|
||||||
|
@result YES if validator should check system shortcuts. Otherwise NO. |
||||||
|
|
||||||
|
@discussion Implementation of this method by the delegate is optional. If it is not present, checking proceeds as if this method had returned YES. |
||||||
|
*/ |
||||||
|
- (BOOL)shortcutValidatorShouldCheckSystemShortcuts:(SRValidator *)aValidator; |
||||||
|
|
||||||
|
/*!
|
||||||
|
Asks the delegate whether it should use ASCII representation of key code when making error messages. |
||||||
|
|
||||||
|
@param aValidator The validator that is about to make an error message. |
||||||
|
|
||||||
|
@result YES if validator should use ASCII representation. Otherwise NO. |
||||||
|
|
||||||
|
@discussion Implementation of this method by the delegate is optional. If it is not present, ASCII representation of key code is used. |
||||||
|
*/ |
||||||
|
- (BOOL)shortcutValidatorShouldUseASCIIStringForKeyCodes:(SRValidator *)aValidator; |
||||||
|
|
||||||
|
@end |
||||||
|
|
||||||
|
|
||||||
|
@interface NSMenuItem (SRValidator) |
||||||
|
|
||||||
|
/*!
|
||||||
|
Returns full path to the menu item. E.g. "Window ➝ Zoom" |
||||||
|
*/ |
||||||
|
- (NSString *)SR_path; |
||||||
|
|
||||||
|
@end |
@ -0,0 +1,233 @@ |
|||||||
|
// |
||||||
|
// SRValidator.h |
||||||
|
// ShortcutRecorder |
||||||
|
// |
||||||
|
// Copyright 2006-2012 Contributors. All rights reserved. |
||||||
|
// |
||||||
|
// License: BSD |
||||||
|
// |
||||||
|
// Contributors: |
||||||
|
// David Dauer |
||||||
|
// Jesper |
||||||
|
// Jamie Kirkpatrick |
||||||
|
// Andy Kim |
||||||
|
// Silvio Rizzi |
||||||
|
// Ilya Kulakov |
||||||
|
|
||||||
|
#import "SRValidator.h" |
||||||
|
#import "SRCommon.h" |
||||||
|
#import "SRKeyCodeTransformer.h" |
||||||
|
|
||||||
|
|
||||||
|
@implementation SRValidator |
||||||
|
|
||||||
|
- (instancetype)initWithDelegate:(NSObject<SRValidatorDelegate> *)aDelegate; |
||||||
|
{ |
||||||
|
self = [super init]; |
||||||
|
|
||||||
|
if (self) |
||||||
|
{ |
||||||
|
_delegate = aDelegate; |
||||||
|
} |
||||||
|
|
||||||
|
return self; |
||||||
|
} |
||||||
|
|
||||||
|
- (instancetype)init |
||||||
|
{ |
||||||
|
return [self initWithDelegate:nil]; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
#pragma mark Methods |
||||||
|
|
||||||
|
- (BOOL)isKeyCode:(unsigned short)aKeyCode andFlagsTaken:(NSEventModifierFlags)aFlags error:(NSError **)outError; |
||||||
|
{ |
||||||
|
if ([self isKeyCode:aKeyCode andFlagTakenInDelegate:aFlags error:outError]) |
||||||
|
return YES; |
||||||
|
|
||||||
|
if ((![self.delegate respondsToSelector:@selector(shortcutValidatorShouldCheckSystemShortcuts:)] || |
||||||
|
[self.delegate shortcutValidatorShouldCheckSystemShortcuts:self]) && |
||||||
|
[self isKeyCode:aKeyCode andFlagsTakenInSystemShortcuts:aFlags error:outError]) |
||||||
|
{ |
||||||
|
return YES; |
||||||
|
} |
||||||
|
|
||||||
|
if ((![self.delegate respondsToSelector:@selector(shortcutValidatorShouldCheckMenu:)] || |
||||||
|
[self.delegate shortcutValidatorShouldCheckMenu:self]) && |
||||||
|
[self isKeyCode:aKeyCode andFlags:aFlags takenInMenu:[NSApp mainMenu] error:outError]) |
||||||
|
{ |
||||||
|
return YES; |
||||||
|
} |
||||||
|
|
||||||
|
return NO; |
||||||
|
} |
||||||
|
|
||||||
|
- (BOOL)isKeyCode:(unsigned short)aKeyCode andFlagTakenInDelegate:(NSEventModifierFlags)aFlags error:(NSError **)outError |
||||||
|
{ |
||||||
|
if (self.delegate) |
||||||
|
{ |
||||||
|
NSString *delegateReason = nil; |
||||||
|
if ([self.delegate respondsToSelector:@selector(shortcutValidator:isKeyCode:andFlagsTaken:reason:)] && |
||||||
|
[self.delegate shortcutValidator:self |
||||||
|
isKeyCode:aKeyCode |
||||||
|
andFlagsTaken:aFlags |
||||||
|
reason:&delegateReason]) |
||||||
|
{ |
||||||
|
if (outError) |
||||||
|
{ |
||||||
|
BOOL isASCIIOnly = YES; |
||||||
|
|
||||||
|
if ([self.delegate respondsToSelector:@selector(shortcutValidatorShouldUseASCIIStringForKeyCodes:)]) |
||||||
|
isASCIIOnly = [self.delegate shortcutValidatorShouldUseASCIIStringForKeyCodes:self]; |
||||||
|
|
||||||
|
NSString *shortcut = isASCIIOnly ? SRReadableASCIIStringForCocoaModifierFlagsAndKeyCode(aFlags, aKeyCode) : SRReadableStringForCocoaModifierFlagsAndKeyCode(aFlags, aKeyCode); |
||||||
|
NSString *failureReason = [NSString stringWithFormat: |
||||||
|
SRLoc(@"The key combination \"%@\" can't be used!"), |
||||||
|
shortcut]; |
||||||
|
NSString *description = [NSString stringWithFormat: |
||||||
|
SRLoc(@"The key combination \"%@\" can't be used because %@."), |
||||||
|
shortcut, |
||||||
|
[delegateReason length] ? delegateReason : @"it's already used"]; |
||||||
|
NSDictionary *userInfo = @{ |
||||||
|
NSLocalizedFailureReasonErrorKey : failureReason, |
||||||
|
NSLocalizedDescriptionKey: description |
||||||
|
}; |
||||||
|
*outError = [NSError errorWithDomain:NSCocoaErrorDomain code:0 userInfo:userInfo]; |
||||||
|
} |
||||||
|
|
||||||
|
return YES; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return NO; |
||||||
|
} |
||||||
|
|
||||||
|
- (BOOL)isKeyCode:(unsigned short)aKeyCode andFlagsTakenInSystemShortcuts:(NSEventModifierFlags)aFlags error:(NSError **)outError |
||||||
|
{ |
||||||
|
CFArrayRef s = NULL; |
||||||
|
OSStatus err = CopySymbolicHotKeys(&s); |
||||||
|
|
||||||
|
if (err != noErr) |
||||||
|
return YES; |
||||||
|
|
||||||
|
NSArray *symbolicHotKeys = (NSArray *)CFBridgingRelease(s); |
||||||
|
aFlags &= SRCocoaModifierFlagsMask; |
||||||
|
|
||||||
|
for (NSDictionary *symbolicHotKey in symbolicHotKeys) |
||||||
|
{ |
||||||
|
if ((__bridge CFBooleanRef)symbolicHotKey[(__bridge NSString *)kHISymbolicHotKeyEnabled] != kCFBooleanTrue) |
||||||
|
continue; |
||||||
|
|
||||||
|
unsigned short symbolicHotKeyCode = [symbolicHotKey[(__bridge NSString *)kHISymbolicHotKeyCode] integerValue]; |
||||||
|
|
||||||
|
if (symbolicHotKeyCode == aKeyCode) |
||||||
|
{ |
||||||
|
UInt32 symbolicHotKeyFlags = [symbolicHotKey[(__bridge NSString *)kHISymbolicHotKeyModifiers] unsignedIntValue]; |
||||||
|
symbolicHotKeyFlags &= SRCarbonModifierFlagsMask; |
||||||
|
|
||||||
|
if (SRCarbonToCocoaFlags(symbolicHotKeyFlags) == aFlags) |
||||||
|
{ |
||||||
|
if (outError) |
||||||
|
{ |
||||||
|
BOOL isASCIIOnly = YES; |
||||||
|
|
||||||
|
if ([self.delegate respondsToSelector:@selector(shortcutValidatorShouldUseASCIIStringForKeyCodes:)]) |
||||||
|
isASCIIOnly = [self.delegate shortcutValidatorShouldUseASCIIStringForKeyCodes:self]; |
||||||
|
|
||||||
|
NSString *shortcut = isASCIIOnly ? SRReadableASCIIStringForCocoaModifierFlagsAndKeyCode(aFlags, aKeyCode) : SRReadableStringForCocoaModifierFlagsAndKeyCode(aFlags, aKeyCode); |
||||||
|
NSString *failureReason = [NSString stringWithFormat: |
||||||
|
SRLoc(@"The key combination \"%@\" can't be used!"), |
||||||
|
shortcut]; |
||||||
|
NSString *description = [NSString stringWithFormat: |
||||||
|
SRLoc(@"The key combination \"%@\" can't be used because it's already used by a system-wide keyboard shortcut. If you really want to use this key combination, most shortcuts can be changed in the Keyboard panel in System Preferences."), |
||||||
|
shortcut]; |
||||||
|
NSDictionary *userInfo = @{ |
||||||
|
NSLocalizedFailureReasonErrorKey: failureReason, |
||||||
|
NSLocalizedDescriptionKey: description |
||||||
|
}; |
||||||
|
*outError = [NSError errorWithDomain:NSCocoaErrorDomain code:0 userInfo:userInfo]; |
||||||
|
} |
||||||
|
|
||||||
|
return YES; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return NO; |
||||||
|
} |
||||||
|
|
||||||
|
- (BOOL)isKeyCode:(unsigned short)aKeyCode andFlags:(NSEventModifierFlags)aFlags takenInMenu:(NSMenu *)aMenu error:(NSError **)outError |
||||||
|
{ |
||||||
|
aFlags &= SRCocoaModifierFlagsMask; |
||||||
|
|
||||||
|
for (NSMenuItem *menuItem in [aMenu itemArray]) |
||||||
|
{ |
||||||
|
if (menuItem.hasSubmenu && [self isKeyCode:aKeyCode andFlags:aFlags takenInMenu:menuItem.submenu error:outError]) |
||||||
|
return YES; |
||||||
|
|
||||||
|
NSString *keyEquivalent = menuItem.keyEquivalent; |
||||||
|
|
||||||
|
if (![keyEquivalent length]) |
||||||
|
continue; |
||||||
|
|
||||||
|
NSEventModifierFlags keyEquivalentModifierMask = menuItem.keyEquivalentModifierMask; |
||||||
|
|
||||||
|
if (SRKeyCodeWithFlagsEqualToKeyEquivalentWithFlags(aKeyCode, aFlags, keyEquivalent, keyEquivalentModifierMask)) |
||||||
|
{ |
||||||
|
if (outError) |
||||||
|
{ |
||||||
|
BOOL isASCIIOnly = YES; |
||||||
|
|
||||||
|
if ([self.delegate respondsToSelector:@selector(shortcutValidatorShouldUseASCIIStringForKeyCodes:)]) |
||||||
|
isASCIIOnly = [self.delegate shortcutValidatorShouldUseASCIIStringForKeyCodes:self]; |
||||||
|
|
||||||
|
NSString *shortcut = isASCIIOnly ? SRReadableASCIIStringForCocoaModifierFlagsAndKeyCode(aFlags, aKeyCode) : SRReadableStringForCocoaModifierFlagsAndKeyCode(aFlags, aKeyCode); |
||||||
|
NSString *failureReason = [NSString stringWithFormat:SRLoc(@"The key combination \"%@\" can't be used!"), shortcut]; |
||||||
|
NSString *description = [NSString stringWithFormat:SRLoc(@"The key combination \"%@\" can't be used because it's already used by the menu item \"%@\"."), shortcut, menuItem.SR_path]; |
||||||
|
NSDictionary *userInfo = @{ |
||||||
|
NSLocalizedFailureReasonErrorKey: failureReason, |
||||||
|
NSLocalizedDescriptionKey: description |
||||||
|
}; |
||||||
|
*outError = [NSError errorWithDomain:NSCocoaErrorDomain code:0 userInfo:userInfo]; |
||||||
|
} |
||||||
|
|
||||||
|
return YES; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return NO; |
||||||
|
} |
||||||
|
|
||||||
|
@end |
||||||
|
|
||||||
|
|
||||||
|
@implementation NSMenuItem (SRValidator) |
||||||
|
|
||||||
|
- (NSString *)SR_path |
||||||
|
{ |
||||||
|
NSMutableArray *items = [NSMutableArray array]; |
||||||
|
static const NSUInteger Limit = 1000; |
||||||
|
NSMenuItem *currentMenuItem = self; |
||||||
|
NSUInteger i = 0; |
||||||
|
|
||||||
|
do |
||||||
|
{ |
||||||
|
[items insertObject:currentMenuItem atIndex:0]; |
||||||
|
currentMenuItem = currentMenuItem.parentItem; |
||||||
|
++i; |
||||||
|
} |
||||||
|
while (currentMenuItem && i < Limit); |
||||||
|
|
||||||
|
NSMutableString *path = [NSMutableString string]; |
||||||
|
|
||||||
|
for (NSMenuItem *menuItem in items) |
||||||
|
[path appendFormat:@"%@➝", menuItem.title]; |
||||||
|
|
||||||
|
if ([path length] > 1) |
||||||
|
[path deleteCharactersInRange:NSMakeRange([path length] - 1, 1)]; |
||||||
|
|
||||||
|
return path; |
||||||
|
} |
||||||
|
|
||||||
|
@end |
@ -0,0 +1,54 @@ |
|||||||
|
//
|
||||||
|
// ShortcutRecorder.h
|
||||||
|
// ShortcutRecorder
|
||||||
|
// Copyright 2012 Contributors. All rights reserved.
|
||||||
|
//
|
||||||
|
// License: BSD
|
||||||
|
//
|
||||||
|
// Contributors to this file:
|
||||||
|
// Jesper
|
||||||
|
// Ilya Kulakov
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h> |
||||||
|
#import <ShortcutRecorder/SRCommon.h> |
||||||
|
#import <ShortcutRecorder/SRKeyCodeTransformer.h> |
||||||
|
#import <ShortcutRecorder/SRModifierFlagsTransformer.h> |
||||||
|
#import <ShortcutRecorder/SRKeyEquivalentTransformer.h> |
||||||
|
#import <ShortcutRecorder/SRKeyEquivalentModifierMaskTransformer.h> |
||||||
|
#import <ShortcutRecorder/SRValidator.h> |
||||||
|
#import <ShortcutRecorder/SRRecorderControl.h> |
||||||
|
|
||||||
|
|
||||||
|
#ifndef IBInspectable |
||||||
|
#define IBInspectable |
||||||
|
#endif |
||||||
|
|
||||||
|
#ifndef IB_DESIGNABLE |
||||||
|
#define IB_DESIGNABLE |
||||||
|
#endif |
||||||
|
|
||||||
|
#ifndef NSAppKitVersionNumber10_6 |
||||||
|
#define NSAppKitVersionNumber10_6 1038 |
||||||
|
#endif |
||||||
|
|
||||||
|
#ifndef NSAppKitVersionNumber10_9 |
||||||
|
#define NSAppKitVersionNumber10_9 1265 |
||||||
|
#endif |
||||||
|
|
||||||
|
#ifndef NSEDGEINSETS_DEFINED |
||||||
|
typedef struct NSEdgeInsets { |
||||||
|
CGFloat top; |
||||||
|
CGFloat left; |
||||||
|
CGFloat bottom; |
||||||
|
CGFloat right; |
||||||
|
} NSEdgeInsets; |
||||||
|
|
||||||
|
NS_INLINE NSEdgeInsets NSEdgeInsetsMake(CGFloat top, CGFloat left, CGFloat bottom, CGFloat right) { |
||||||
|
NSEdgeInsets e; |
||||||
|
e.top = top; |
||||||
|
e.left = left; |
||||||
|
e.bottom = bottom; |
||||||
|
e.right = right; |
||||||
|
return e; |
||||||
|
} |
||||||
|
#endif |
@ -0,0 +1,22 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> |
||||||
|
<plist version="1.0"> |
||||||
|
<dict> |
||||||
|
<key>CFBundleDevelopmentRegion</key> |
||||||
|
<string>English</string> |
||||||
|
<key>CFBundleExecutable</key> |
||||||
|
<string>${EXECUTABLE_NAME}</string> |
||||||
|
<key>CFBundleIdentifier</key> |
||||||
|
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> |
||||||
|
<key>CFBundleInfoDictionaryVersion</key> |
||||||
|
<string>6.0</string> |
||||||
|
<key>CFBundlePackageType</key> |
||||||
|
<string>FMWK</string> |
||||||
|
<key>CFBundleShortVersionString</key> |
||||||
|
<string>1.5</string> |
||||||
|
<key>CFBundleSignature</key> |
||||||
|
<string>????</string> |
||||||
|
<key>CFBundleVersion</key> |
||||||
|
<string>1.5</string> |
||||||
|
</dict> |
||||||
|
</plist> |
@ -0,0 +1,31 @@ |
|||||||
|
//
|
||||||
|
// PTHotKey+ShortcutRecorder.h
|
||||||
|
// ShortcutRecorder
|
||||||
|
//
|
||||||
|
// Created by Ilya Kulakov on 27.02.11.
|
||||||
|
// Copyright 2011 Wireload. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h> |
||||||
|
#import "PTHotKey.h" |
||||||
|
|
||||||
|
|
||||||
|
@interface PTHotKey (ShortcutRecorder) |
||||||
|
|
||||||
|
+ (PTHotKey *)hotKeyWithIdentifier:(id)anIdentifier |
||||||
|
keyCombo:(NSDictionary *)aKeyCombo |
||||||
|
target:(id)aTarget |
||||||
|
action:(SEL)anAction; |
||||||
|
|
||||||
|
+ (PTHotKey *)hotKeyWithIdentifier:(id)anIdentifier |
||||||
|
keyCombo:(NSDictionary *)aKeyCombo |
||||||
|
target:(id)aTarget |
||||||
|
action:(SEL)anAction |
||||||
|
keyUpAction:(SEL)aKeyUpAction; |
||||||
|
|
||||||
|
+ (PTHotKey *)hotKeyWithIdentifier:(id)anIdentifier |
||||||
|
keyCombo:(NSDictionary *)aKeyCombo |
||||||
|
target:(id)aTarget |
||||||
|
action:(SEL)anAction |
||||||
|
withObject:(id)anObject; |
||||||
|
@end |
@ -0,0 +1,53 @@ |
|||||||
|
// |
||||||
|
// PTHotKey+ShortcutRecorder.m |
||||||
|
// ShortcutRecorder |
||||||
|
// |
||||||
|
// Created by Ilya Kulakov on 27.02.11. |
||||||
|
// Copyright 2011 Wireload. All rights reserved. |
||||||
|
// |
||||||
|
|
||||||
|
#import "PTHotKey+ShortcutRecorder.h" |
||||||
|
#import "SRRecorderControl.h" |
||||||
|
|
||||||
|
|
||||||
|
@implementation PTHotKey (ShortcutRecorder) |
||||||
|
|
||||||
|
+ (PTHotKey *)hotKeyWithIdentifier:(id)anIdentifier |
||||||
|
keyCombo:(NSDictionary *)aKeyCombo |
||||||
|
target:(id)aTarget |
||||||
|
action:(SEL)anAction |
||||||
|
{ |
||||||
|
return [PTHotKey hotKeyWithIdentifier:anIdentifier keyCombo:aKeyCombo target:aTarget action:anAction withObject:nil]; |
||||||
|
} |
||||||
|
|
||||||
|
+ (PTHotKey *)hotKeyWithIdentifier:(id)anIdentifier |
||||||
|
keyCombo:(NSDictionary *)aKeyCombo |
||||||
|
target:(id)aTarget |
||||||
|
action:(SEL)anAction |
||||||
|
withObject:(id)anObject |
||||||
|
{ |
||||||
|
NSInteger keyCode = [[aKeyCombo objectForKey:@"keyCode"] integerValue]; |
||||||
|
NSUInteger modifiers = SRCocoaToCarbonFlags([[aKeyCombo objectForKey:@"modifierFlags"] unsignedIntegerValue]); |
||||||
|
PTKeyCombo *newKeyCombo = [[PTKeyCombo alloc] initWithKeyCode:keyCode modifiers:modifiers]; |
||||||
|
PTHotKey *newHotKey = [[PTHotKey alloc] initWithIdentifier:anIdentifier keyCombo:newKeyCombo]; |
||||||
|
[newHotKey setTarget:aTarget]; |
||||||
|
[newHotKey setAction:anAction]; |
||||||
|
[newHotKey setObject:anObject]; |
||||||
|
return newHotKey; |
||||||
|
} |
||||||
|
|
||||||
|
+ (PTHotKey *)hotKeyWithIdentifier:(id)anIdentifier |
||||||
|
keyCombo:(NSDictionary *)aKeyCombo |
||||||
|
target:(id)aTarget |
||||||
|
action:(SEL)anAction |
||||||
|
keyUpAction:(SEL)aKeyUpAction |
||||||
|
{ |
||||||
|
PTHotKey *newHotKey = [PTHotKey hotKeyWithIdentifier:anIdentifier |
||||||
|
keyCombo:aKeyCombo |
||||||
|
target:aTarget |
||||||
|
action:anAction]; |
||||||
|
[newHotKey setKeyUpAction:aKeyUpAction]; |
||||||
|
return newHotKey; |
||||||
|
} |
||||||
|
|
||||||
|
@end |
@ -0,0 +1,60 @@ |
|||||||
|
//
|
||||||
|
// PTHotKey.h
|
||||||
|
// Protein
|
||||||
|
//
|
||||||
|
// Created by Quentin Carnicelli on Sat Aug 02 2003.
|
||||||
|
// Copyright (c) 2003 Quentin D. Carnicelli. All rights reserved.
|
||||||
|
//
|
||||||
|
// Contributors:
|
||||||
|
// Andy Kim
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h> |
||||||
|
#import <Carbon/Carbon.h> |
||||||
|
#import "PTKeyCombo.h" |
||||||
|
|
||||||
|
@interface PTHotKey : NSObject |
||||||
|
{ |
||||||
|
NSString* mIdentifier; |
||||||
|
NSString* mName; |
||||||
|
PTKeyCombo* mKeyCombo; |
||||||
|
id mTarget; |
||||||
|
id mObject; |
||||||
|
SEL mAction; |
||||||
|
SEL mKeyUpAction; |
||||||
|
|
||||||
|
UInt32 mCarbonHotKeyID; |
||||||
|
EventHotKeyRef mCarbonEventHotKeyRef; |
||||||
|
} |
||||||
|
|
||||||
|
- (id)initWithIdentifier: (id)identifier keyCombo: (PTKeyCombo*)combo; |
||||||
|
- (id)initWithIdentifier: (id)identifier keyCombo: (PTKeyCombo*)combo withObject: (id)object; |
||||||
|
- (id)init; |
||||||
|
|
||||||
|
- (void)setIdentifier: (id)ident; |
||||||
|
- (id)identifier; |
||||||
|
|
||||||
|
- (void)setName: (NSString*)name; |
||||||
|
- (NSString*)name; |
||||||
|
|
||||||
|
- (void)setKeyCombo: (PTKeyCombo*)combo; |
||||||
|
- (PTKeyCombo*)keyCombo; |
||||||
|
|
||||||
|
- (void)setTarget: (id)target; |
||||||
|
- (id)target; |
||||||
|
- (void)setObject: (id)object; |
||||||
|
- (id)object; |
||||||
|
- (void)setAction: (SEL)action; |
||||||
|
- (SEL)action; |
||||||
|
- (void)setKeyUpAction: (SEL)action; |
||||||
|
- (SEL)keyUpAction; |
||||||
|
|
||||||
|
- (UInt32)carbonHotKeyID; |
||||||
|
- (void)setCarbonHotKeyID: (UInt32)hotKeyID; |
||||||
|
|
||||||
|
- (EventHotKeyRef)carbonEventHotKeyRef; |
||||||
|
- (void)setCarbonEventHotKeyRef:(EventHotKeyRef)hotKeyRef; |
||||||
|
|
||||||
|
- (void)invoke; |
||||||
|
- (void)uninvoke; |
||||||
|
|
||||||
|
@end |
@ -0,0 +1,156 @@ |
|||||||
|
// |
||||||
|
// PTHotKey.m |
||||||
|
// Protein |
||||||
|
// |
||||||
|
// Created by Quentin Carnicelli on Sat Aug 02 2003. |
||||||
|
// Copyright (c) 2003 Quentin D. Carnicelli. All rights reserved. |
||||||
|
// |
||||||
|
|
||||||
|
#import "PTHotKey.h" |
||||||
|
|
||||||
|
#import "PTHotKeyCenter.h" |
||||||
|
#import "PTKeyCombo.h" |
||||||
|
|
||||||
|
@implementation PTHotKey |
||||||
|
|
||||||
|
- (id)init |
||||||
|
{ |
||||||
|
return [self initWithIdentifier: nil keyCombo: nil withObject:nil]; |
||||||
|
} |
||||||
|
|
||||||
|
- (id)initWithIdentifier: (id)identifier keyCombo: (PTKeyCombo*)combo |
||||||
|
{ |
||||||
|
return [self initWithIdentifier: identifier keyCombo: combo withObject:nil]; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
- (id)initWithIdentifier: (id)identifier keyCombo: (PTKeyCombo*)combo withObject: (id)object |
||||||
|
{ |
||||||
|
self = [super init]; |
||||||
|
|
||||||
|
if( self ) |
||||||
|
{ |
||||||
|
[self setIdentifier: identifier]; |
||||||
|
[self setKeyCombo: combo]; |
||||||
|
[self setObject: object]; |
||||||
|
} |
||||||
|
|
||||||
|
return self; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
- (NSString*)description |
||||||
|
{ |
||||||
|
return [NSString stringWithFormat: @"<%@: %@, %@>", NSStringFromClass( [self class] ), [self identifier], [self keyCombo]]; |
||||||
|
} |
||||||
|
|
||||||
|
#pragma mark - |
||||||
|
|
||||||
|
- (void)setIdentifier: (id)ident |
||||||
|
{ |
||||||
|
mIdentifier = ident; |
||||||
|
} |
||||||
|
|
||||||
|
- (id)identifier |
||||||
|
{ |
||||||
|
return mIdentifier; |
||||||
|
} |
||||||
|
|
||||||
|
- (void)setKeyCombo: (PTKeyCombo*)combo |
||||||
|
{ |
||||||
|
if( combo == nil ) |
||||||
|
combo = [PTKeyCombo clearKeyCombo]; |
||||||
|
|
||||||
|
mKeyCombo = combo; |
||||||
|
} |
||||||
|
|
||||||
|
- (PTKeyCombo*)keyCombo |
||||||
|
{ |
||||||
|
return mKeyCombo; |
||||||
|
} |
||||||
|
|
||||||
|
- (void)setName: (NSString*)name |
||||||
|
{ |
||||||
|
mName = name; |
||||||
|
} |
||||||
|
|
||||||
|
- (NSString*)name |
||||||
|
{ |
||||||
|
return mName; |
||||||
|
} |
||||||
|
|
||||||
|
- (void)setTarget: (id)target |
||||||
|
{ |
||||||
|
mTarget = target; |
||||||
|
} |
||||||
|
|
||||||
|
- (id)target |
||||||
|
{ |
||||||
|
return mTarget; |
||||||
|
} |
||||||
|
|
||||||
|
- (void)setObject:(id)object |
||||||
|
{ |
||||||
|
mObject = object; |
||||||
|
} |
||||||
|
|
||||||
|
- (id)object |
||||||
|
{ |
||||||
|
return mObject; |
||||||
|
} |
||||||
|
|
||||||
|
- (void)setAction: (SEL)action |
||||||
|
{ |
||||||
|
mAction = action; |
||||||
|
} |
||||||
|
|
||||||
|
- (SEL)action |
||||||
|
{ |
||||||
|
return mAction; |
||||||
|
} |
||||||
|
|
||||||
|
- (void)setKeyUpAction: (SEL)action |
||||||
|
{ |
||||||
|
mKeyUpAction = action; |
||||||
|
} |
||||||
|
|
||||||
|
- (SEL)keyUpAction |
||||||
|
{ |
||||||
|
return mKeyUpAction; |
||||||
|
} |
||||||
|
|
||||||
|
- (UInt32)carbonHotKeyID |
||||||
|
{ |
||||||
|
return mCarbonHotKeyID; |
||||||
|
} |
||||||
|
|
||||||
|
- (void)setCarbonHotKeyID: (UInt32)hotKeyID; |
||||||
|
{ |
||||||
|
mCarbonHotKeyID = hotKeyID; |
||||||
|
} |
||||||
|
|
||||||
|
- (EventHotKeyRef)carbonEventHotKeyRef |
||||||
|
{ |
||||||
|
return mCarbonEventHotKeyRef; |
||||||
|
} |
||||||
|
|
||||||
|
- (void)setCarbonEventHotKeyRef: (EventHotKeyRef)hotKeyRef |
||||||
|
{ |
||||||
|
mCarbonEventHotKeyRef = hotKeyRef; |
||||||
|
} |
||||||
|
|
||||||
|
#pragma mark - |
||||||
|
|
||||||
|
- (void)invoke |
||||||
|
{ |
||||||
|
if(mAction) |
||||||
|
[NSApp sendAction:mAction to:mTarget from:self]; |
||||||
|
} |
||||||
|
|
||||||
|
- (void)uninvoke |
||||||
|
{ |
||||||
|
if(mKeyUpAction) |
||||||
|
[NSApp sendAction:mKeyUpAction to:mTarget from:self]; |
||||||
|
} |
||||||
|
|
||||||
|
@end |
@ -0,0 +1,44 @@ |
|||||||
|
//
|
||||||
|
// PTHotKeyCenter.h
|
||||||
|
// Protein
|
||||||
|
//
|
||||||
|
// Created by Quentin Carnicelli on Sat Aug 02 2003.
|
||||||
|
// Copyright (c) 2003 Quentin D. Carnicelli. All rights reserved.
|
||||||
|
//
|
||||||
|
// Contributors:
|
||||||
|
// Quentin D. Carnicelli
|
||||||
|
// Finlay Dobbie
|
||||||
|
// Vincent Pottier
|
||||||
|
// Andy Kim
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h> |
||||||
|
#import <Carbon/Carbon.h> |
||||||
|
|
||||||
|
@class PTHotKey; |
||||||
|
|
||||||
|
@interface PTHotKeyCenter : NSObject |
||||||
|
{ |
||||||
|
NSMutableDictionary* mHotKeys; //Keys are carbon hot key IDs
|
||||||
|
BOOL mEventHandlerInstalled; |
||||||
|
UInt32 mHotKeyCount; // Used to assign new hot key ID
|
||||||
|
BOOL mIsPaused; |
||||||
|
EventHandlerRef mEventHandler; |
||||||
|
} |
||||||
|
|
||||||
|
+ (PTHotKeyCenter *)sharedCenter; |
||||||
|
|
||||||
|
- (BOOL)registerHotKey: (PTHotKey*)hotKey; |
||||||
|
- (void)unregisterHotKey: (PTHotKey*)hotKey; |
||||||
|
|
||||||
|
- (NSArray*)allHotKeys; |
||||||
|
- (PTHotKey*)hotKeyWithIdentifier: (id)ident; |
||||||
|
|
||||||
|
- (void)sendEvent: (NSEvent*)event; |
||||||
|
|
||||||
|
- (void)pause; |
||||||
|
|
||||||
|
- (void)resume; |
||||||
|
|
||||||
|
- (BOOL)isPaused; |
||||||
|
|
||||||
|
@end |
@ -0,0 +1,334 @@ |
|||||||
|
// |
||||||
|
// PTHotKeyCenter.m |
||||||
|
// Protein |
||||||
|
// |
||||||
|
// Created by Quentin Carnicelli on Sat Aug 02 2003. |
||||||
|
// Copyright (c) 2003 Quentin D. Carnicelli. All rights reserved. |
||||||
|
// |
||||||
|
|
||||||
|
#import "PTHotKeyCenter.h" |
||||||
|
#import "PTHotKey.h" |
||||||
|
#import "PTKeyCombo.h" |
||||||
|
|
||||||
|
@interface PTHotKeyCenter (Private) |
||||||
|
- (PTHotKey*)_hotKeyForCarbonHotKey: (EventHotKeyRef)carbonHotKey; |
||||||
|
- (PTHotKey*)_hotKeyForCarbonHotKeyID: (EventHotKeyID)hotKeyID; |
||||||
|
|
||||||
|
- (void)_updateEventHandler; |
||||||
|
- (void)_hotKeyDown: (PTHotKey*)hotKey; |
||||||
|
- (void)_hotKeyUp: (PTHotKey*)hotKey; |
||||||
|
static OSStatus hotKeyEventHandler(EventHandlerCallRef inHandlerRef, EventRef inEvent, void* refCon ); |
||||||
|
@end |
||||||
|
|
||||||
|
@implementation PTHotKeyCenter |
||||||
|
|
||||||
|
static PTHotKeyCenter *_sharedHotKeyCenter = nil; |
||||||
|
|
||||||
|
+ (PTHotKeyCenter*)sharedCenter |
||||||
|
{ |
||||||
|
if( _sharedHotKeyCenter == nil ) |
||||||
|
{ |
||||||
|
_sharedHotKeyCenter = [[self alloc] init]; |
||||||
|
} |
||||||
|
|
||||||
|
return _sharedHotKeyCenter; |
||||||
|
} |
||||||
|
|
||||||
|
- (id)init |
||||||
|
{ |
||||||
|
self = [super init]; |
||||||
|
|
||||||
|
if( self ) |
||||||
|
{ |
||||||
|
mHotKeys = [[NSMutableDictionary alloc] init]; |
||||||
|
} |
||||||
|
|
||||||
|
return self; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
#pragma mark - |
||||||
|
|
||||||
|
- (BOOL)registerHotKey: (PTHotKey*)hotKey |
||||||
|
{ |
||||||
|
if ( mIsPaused == NO ) |
||||||
|
{ |
||||||
|
OSStatus err; |
||||||
|
EventHotKeyID hotKeyID; |
||||||
|
EventHotKeyRef carbonHotKey; |
||||||
|
|
||||||
|
if( [[self allHotKeys] containsObject: hotKey] == YES ) |
||||||
|
[self unregisterHotKey: hotKey]; |
||||||
|
|
||||||
|
if( [[hotKey keyCombo] isValidHotKeyCombo] == NO ) |
||||||
|
return YES; |
||||||
|
|
||||||
|
hotKeyID.signature = 'PTHk'; |
||||||
|
hotKeyID.id = ++mHotKeyCount; |
||||||
|
|
||||||
|
err = RegisterEventHotKey( (SInt32)[[hotKey keyCombo] keyCode], |
||||||
|
(UInt32)[[hotKey keyCombo] modifiers], |
||||||
|
hotKeyID, |
||||||
|
GetEventDispatcherTarget(), |
||||||
|
0, |
||||||
|
&carbonHotKey ); |
||||||
|
|
||||||
|
if( err ) |
||||||
|
return NO; |
||||||
|
|
||||||
|
[hotKey setCarbonHotKeyID:hotKeyID.id]; |
||||||
|
[hotKey setCarbonEventHotKeyRef:carbonHotKey]; |
||||||
|
|
||||||
|
if( hotKey ) |
||||||
|
[mHotKeys setObject: hotKey forKey: [NSNumber numberWithInteger:hotKeyID.id]]; |
||||||
|
|
||||||
|
[self _updateEventHandler]; |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
EventHotKeyID hotKeyID = {'PTHk', ++mHotKeyCount}; |
||||||
|
[hotKey setCarbonHotKeyID:hotKeyID.id]; |
||||||
|
|
||||||
|
if( hotKey ) |
||||||
|
[mHotKeys setObject: hotKey forKey: [NSNumber numberWithInteger:hotKeyID.id]]; |
||||||
|
} |
||||||
|
return YES; |
||||||
|
} |
||||||
|
|
||||||
|
- (void)unregisterHotKey: (PTHotKey*)hotKey |
||||||
|
{ |
||||||
|
if ( mIsPaused == NO ) |
||||||
|
{ |
||||||
|
EventHotKeyRef carbonHotKey; |
||||||
|
|
||||||
|
if( [[self allHotKeys] containsObject: hotKey] == NO ) |
||||||
|
return; |
||||||
|
|
||||||
|
carbonHotKey = [hotKey carbonEventHotKeyRef]; |
||||||
|
|
||||||
|
if( carbonHotKey ) |
||||||
|
{ |
||||||
|
UnregisterEventHotKey( carbonHotKey ); |
||||||
|
//Watch as we ignore 'err': |
||||||
|
|
||||||
|
[mHotKeys removeObjectForKey: [NSNumber numberWithInteger:[hotKey carbonHotKeyID]]]; |
||||||
|
|
||||||
|
[hotKey setCarbonHotKeyID:0]; |
||||||
|
[hotKey setCarbonEventHotKeyRef:NULL]; |
||||||
|
|
||||||
|
[self _updateEventHandler]; |
||||||
|
|
||||||
|
//See that? Completely ignored |
||||||
|
} |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
[mHotKeys removeObjectForKey: [NSNumber numberWithInteger:[hotKey carbonHotKeyID]]]; |
||||||
|
|
||||||
|
[hotKey setCarbonHotKeyID:0]; |
||||||
|
[hotKey setCarbonEventHotKeyRef:NULL]; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
- (NSArray*)allHotKeys |
||||||
|
{ |
||||||
|
return [mHotKeys allValues]; |
||||||
|
} |
||||||
|
|
||||||
|
- (PTHotKey*)hotKeyWithIdentifier: (id)ident |
||||||
|
{ |
||||||
|
NSEnumerator* hotKeysEnum = [[self allHotKeys] objectEnumerator]; |
||||||
|
PTHotKey* hotKey; |
||||||
|
|
||||||
|
if( !ident ) |
||||||
|
return nil; |
||||||
|
|
||||||
|
while( (hotKey = [hotKeysEnum nextObject]) != nil ) |
||||||
|
{ |
||||||
|
if( [[hotKey identifier] isEqual: ident] ) |
||||||
|
return hotKey; |
||||||
|
} |
||||||
|
|
||||||
|
return nil; |
||||||
|
} |
||||||
|
|
||||||
|
#pragma mark - |
||||||
|
|
||||||
|
- (PTHotKey*)_hotKeyForCarbonHotKey: (EventHotKeyRef)carbonHotKeyRef |
||||||
|
{ |
||||||
|
NSEnumerator *e = [mHotKeys objectEnumerator]; |
||||||
|
PTHotKey *hotkey = nil; |
||||||
|
|
||||||
|
while( (hotkey = [e nextObject]) ) |
||||||
|
{ |
||||||
|
if( [hotkey carbonEventHotKeyRef] == carbonHotKeyRef ) |
||||||
|
return hotkey; |
||||||
|
} |
||||||
|
|
||||||
|
return nil; |
||||||
|
} |
||||||
|
|
||||||
|
- (PTHotKey*)_hotKeyForCarbonHotKeyID: (EventHotKeyID)hotKeyID |
||||||
|
{ |
||||||
|
return [mHotKeys objectForKey:[NSNumber numberWithInteger:hotKeyID.id]]; |
||||||
|
} |
||||||
|
|
||||||
|
- (void)_updateEventHandler |
||||||
|
{ |
||||||
|
if( [mHotKeys count] && mEventHandlerInstalled == NO ) |
||||||
|
{ |
||||||
|
EventTypeSpec eventSpec[2] = { |
||||||
|
{ kEventClassKeyboard, kEventHotKeyPressed }, |
||||||
|
{ kEventClassKeyboard, kEventHotKeyReleased } |
||||||
|
}; |
||||||
|
|
||||||
|
InstallEventHandler( GetEventDispatcherTarget(), |
||||||
|
(EventHandlerProcPtr)hotKeyEventHandler, |
||||||
|
2, eventSpec, nil, &mEventHandler); |
||||||
|
|
||||||
|
mEventHandlerInstalled = YES; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
- (void)_hotKeyDown: (PTHotKey*)hotKey |
||||||
|
{ |
||||||
|
[hotKey invoke]; |
||||||
|
} |
||||||
|
|
||||||
|
- (void)_hotKeyUp: (PTHotKey*)hotKey |
||||||
|
{ |
||||||
|
[hotKey uninvoke]; |
||||||
|
} |
||||||
|
|
||||||
|
- (void)sendEvent: (NSEvent*)event |
||||||
|
{ |
||||||
|
// Not sure why this is needed? - Andy Kim (Aug 23, 2009) |
||||||
|
|
||||||
|
short subType; |
||||||
|
EventHotKeyRef carbonHotKey; |
||||||
|
|
||||||
|
if( [event type] == NSSystemDefined ) |
||||||
|
{ |
||||||
|
subType = [event subtype]; |
||||||
|
|
||||||
|
if( subType == 6 ) //6 is hot key down |
||||||
|
{ |
||||||
|
carbonHotKey= (EventHotKeyRef)[event data1]; //data1 is our hot key ref |
||||||
|
if( carbonHotKey != nil ) |
||||||
|
{ |
||||||
|
PTHotKey* hotKey = [self _hotKeyForCarbonHotKey: carbonHotKey]; |
||||||
|
[self _hotKeyDown: hotKey]; |
||||||
|
} |
||||||
|
} |
||||||
|
else if( subType == 9 ) //9 is hot key up |
||||||
|
{ |
||||||
|
carbonHotKey= (EventHotKeyRef)[event data1]; |
||||||
|
if( carbonHotKey != nil ) |
||||||
|
{ |
||||||
|
PTHotKey* hotKey = [self _hotKeyForCarbonHotKey: carbonHotKey]; |
||||||
|
[self _hotKeyUp: hotKey]; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
- (OSStatus)sendCarbonEvent: (EventRef)event |
||||||
|
{ |
||||||
|
OSStatus err; |
||||||
|
EventHotKeyID hotKeyID; |
||||||
|
PTHotKey* hotKey; |
||||||
|
|
||||||
|
NSAssert( GetEventClass( event ) == kEventClassKeyboard, @"Unknown event class" ); |
||||||
|
|
||||||
|
err = GetEventParameter( event, |
||||||
|
kEventParamDirectObject, |
||||||
|
typeEventHotKeyID, |
||||||
|
nil, |
||||||
|
sizeof(EventHotKeyID), |
||||||
|
nil, |
||||||
|
&hotKeyID ); |
||||||
|
if( err ) |
||||||
|
return err; |
||||||
|
|
||||||
|
if( hotKeyID.signature != 'PTHk' ) |
||||||
|
return eventNotHandledErr; |
||||||
|
|
||||||
|
if (hotKeyID.id == 0) |
||||||
|
return eventNotHandledErr; |
||||||
|
|
||||||
|
hotKey = [self _hotKeyForCarbonHotKeyID:hotKeyID]; |
||||||
|
|
||||||
|
switch( GetEventKind( event ) ) |
||||||
|
{ |
||||||
|
case kEventHotKeyPressed: |
||||||
|
[self _hotKeyDown: hotKey]; |
||||||
|
break; |
||||||
|
|
||||||
|
case kEventHotKeyReleased: |
||||||
|
[self _hotKeyUp: hotKey]; |
||||||
|
break; |
||||||
|
|
||||||
|
default: |
||||||
|
return eventNotHandledErr; |
||||||
|
break; |
||||||
|
} |
||||||
|
|
||||||
|
return noErr; |
||||||
|
} |
||||||
|
|
||||||
|
- (void)pause |
||||||
|
{ |
||||||
|
if ( mIsPaused ) |
||||||
|
return; |
||||||
|
|
||||||
|
mIsPaused = YES; |
||||||
|
for (NSNumber *hotKeyID in mHotKeys) |
||||||
|
{ |
||||||
|
PTHotKey *hotKey = [mHotKeys objectForKey:hotKeyID]; |
||||||
|
EventHotKeyRef carbonHotKey = [hotKey carbonEventHotKeyRef]; |
||||||
|
UnregisterEventHotKey( carbonHotKey ); |
||||||
|
[hotKey setCarbonEventHotKeyRef:NULL]; |
||||||
|
} |
||||||
|
if (mEventHandler != NULL) |
||||||
|
{ |
||||||
|
RemoveEventHandler(mEventHandler); |
||||||
|
mEventHandler = NULL; |
||||||
|
mEventHandlerInstalled = NO; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
- (void)resume |
||||||
|
{ |
||||||
|
if ( mIsPaused == NO) |
||||||
|
return; |
||||||
|
|
||||||
|
mIsPaused = NO; |
||||||
|
for (NSNumber *hotKeyIDNumber in mHotKeys) |
||||||
|
{ |
||||||
|
PTHotKey *hotKey = [mHotKeys objectForKey:hotKeyIDNumber]; |
||||||
|
EventHotKeyRef carbonHotKey = NULL; |
||||||
|
EventHotKeyID hotKeyID; |
||||||
|
hotKeyID.signature = 'PTHk'; |
||||||
|
hotKeyID.id = [hotKey carbonHotKeyID]; |
||||||
|
RegisterEventHotKey( (SInt32)[[hotKey keyCombo] keyCode], |
||||||
|
(UInt32)[[hotKey keyCombo] modifiers], |
||||||
|
hotKeyID, |
||||||
|
GetEventDispatcherTarget(), |
||||||
|
0, |
||||||
|
&carbonHotKey ); |
||||||
|
[hotKey setCarbonEventHotKeyRef:carbonHotKey]; |
||||||
|
} |
||||||
|
[self _updateEventHandler]; |
||||||
|
} |
||||||
|
|
||||||
|
- (BOOL)isPaused |
||||||
|
{ |
||||||
|
return mIsPaused; |
||||||
|
} |
||||||
|
|
||||||
|
static OSStatus hotKeyEventHandler(EventHandlerCallRef inHandlerRef, EventRef inEvent, void* refCon ) |
||||||
|
{ |
||||||
|
return [[PTHotKeyCenter sharedCenter] sendCarbonEvent: inEvent]; |
||||||
|
} |
||||||
|
|
||||||
|
@end |
@ -0,0 +1,26 @@ |
|||||||
|
//
|
||||||
|
// PTKeyCodeTranslator.h
|
||||||
|
// Chercher
|
||||||
|
//
|
||||||
|
// Created by Finlay Dobbie on Sat Oct 11 2003.
|
||||||
|
// Copyright (c) 2003 Cliché Software. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Carbon/Carbon.h> |
||||||
|
|
||||||
|
@interface PTKeyCodeTranslator : NSObject |
||||||
|
{ |
||||||
|
TISInputSourceRef keyboardLayout; |
||||||
|
const UCKeyboardLayout *uchrData; |
||||||
|
UInt32 keyTranslateState; |
||||||
|
UInt32 deadKeyState; |
||||||
|
} |
||||||
|
|
||||||
|
+ (id)currentTranslator; |
||||||
|
|
||||||
|
- (id)initWithKeyboardLayout:(TISInputSourceRef)aLayout; |
||||||
|
- (NSString *)translateKeyCode:(short)keyCode; |
||||||
|
|
||||||
|
- (TISInputSourceRef)keyboardLayout; |
||||||
|
|
||||||
|
@end |
@ -0,0 +1,71 @@ |
|||||||
|
// |
||||||
|
// PTKeyCodeTranslator.m |
||||||
|
// Chercher |
||||||
|
// |
||||||
|
// Created by Finlay Dobbie on Sat Oct 11 2003. |
||||||
|
// Copyright (c) 2003 Cliché Software. All rights reserved. |
||||||
|
// |
||||||
|
|
||||||
|
#import "PTKeyCodeTranslator.h" |
||||||
|
|
||||||
|
|
||||||
|
@implementation PTKeyCodeTranslator |
||||||
|
|
||||||
|
+ (id)currentTranslator |
||||||
|
{ |
||||||
|
static PTKeyCodeTranslator *current = nil; |
||||||
|
TISInputSourceRef currentLayout = TISCopyCurrentKeyboardLayoutInputSource(); |
||||||
|
|
||||||
|
if (current == nil) { |
||||||
|
current = [[PTKeyCodeTranslator alloc] initWithKeyboardLayout:currentLayout]; |
||||||
|
} else if ([current keyboardLayout] != currentLayout) { |
||||||
|
current = [[PTKeyCodeTranslator alloc] initWithKeyboardLayout:currentLayout]; |
||||||
|
} |
||||||
|
|
||||||
|
CFRelease(currentLayout); |
||||||
|
|
||||||
|
return current; |
||||||
|
} |
||||||
|
|
||||||
|
- (id)initWithKeyboardLayout:(TISInputSourceRef)aLayout |
||||||
|
{ |
||||||
|
if ((self = [super init]) != nil) { |
||||||
|
keyboardLayout = aLayout; |
||||||
|
|
||||||
|
CFRetain(keyboardLayout); |
||||||
|
|
||||||
|
CFDataRef uchr = TISGetInputSourceProperty( keyboardLayout , kTISPropertyUnicodeKeyLayoutData ); |
||||||
|
uchrData = ( const UCKeyboardLayout* )CFDataGetBytePtr(uchr); |
||||||
|
} |
||||||
|
|
||||||
|
return self; |
||||||
|
} |
||||||
|
|
||||||
|
- (void)dealloc |
||||||
|
{ |
||||||
|
|
||||||
|
CFRelease(keyboardLayout); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
- (NSString *)translateKeyCode:(short)keyCode { |
||||||
|
UniCharCount maxStringLength = 4, actualStringLength; |
||||||
|
UniChar unicodeString[4]; |
||||||
|
UCKeyTranslate( uchrData, keyCode, kUCKeyActionDisplay, 0, LMGetKbdType(), kUCKeyTranslateNoDeadKeysBit, &deadKeyState, maxStringLength, &actualStringLength, unicodeString ); |
||||||
|
return [NSString stringWithCharacters:unicodeString length:1]; |
||||||
|
} |
||||||
|
|
||||||
|
- (TISInputSourceRef)keyboardLayout { |
||||||
|
return keyboardLayout; |
||||||
|
} |
||||||
|
|
||||||
|
- (NSString *)description { |
||||||
|
NSString *kind; |
||||||
|
kind = @"uchr"; |
||||||
|
|
||||||
|
NSString *layoutName; |
||||||
|
layoutName = (__bridge NSString *)(TISGetInputSourceProperty( keyboardLayout, kTISPropertyLocalizedName )); |
||||||
|
return [NSString stringWithFormat:@"PTKeyCodeTranslator layout=%@ (%@)", layoutName, kind]; |
||||||
|
} |
||||||
|
|
||||||
|
@end |
@ -0,0 +1,38 @@ |
|||||||
|
//
|
||||||
|
// PTKeyCombo.h
|
||||||
|
// Protein
|
||||||
|
//
|
||||||
|
// Created by Quentin Carnicelli on Sat Aug 02 2003.
|
||||||
|
// Copyright (c) 2003 Quentin D. Carnicelli. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h> |
||||||
|
|
||||||
|
@interface PTKeyCombo : NSObject <NSCopying> |
||||||
|
{ |
||||||
|
NSInteger mKeyCode; |
||||||
|
NSUInteger mModifiers; |
||||||
|
} |
||||||
|
|
||||||
|
+ (id)clearKeyCombo; |
||||||
|
+ (id)keyComboWithKeyCode: (NSInteger)keyCode modifiers: (NSUInteger)modifiers; |
||||||
|
- (id)initWithKeyCode: (NSInteger)keyCode modifiers: (NSUInteger)modifiers; |
||||||
|
|
||||||
|
- (id)initWithPlistRepresentation: (id)plist; |
||||||
|
- (id)plistRepresentation; |
||||||
|
|
||||||
|
- (BOOL)isEqual: (PTKeyCombo*)combo; |
||||||
|
|
||||||
|
- (NSInteger)keyCode; |
||||||
|
- (NSUInteger)modifiers; |
||||||
|
|
||||||
|
- (BOOL)isClearCombo; |
||||||
|
- (BOOL)isValidHotKeyCombo; |
||||||
|
|
||||||
|
@end |
||||||
|
|
||||||
|
|
||||||
|
@interface PTKeyCombo (UserDisplayAdditions) |
||||||
|
- (NSString*)keyCodeString; |
||||||
|
- (NSUInteger)modifierMask; |
||||||
|
@end |
@ -0,0 +1,127 @@ |
|||||||
|
// |
||||||
|
// PTKeyCombo.m |
||||||
|
// Protein |
||||||
|
// |
||||||
|
// Created by Quentin Carnicelli on Sat Aug 02 2003. |
||||||
|
// Copyright (c) 2003 Quentin D. Carnicelli. All rights reserved. |
||||||
|
// |
||||||
|
|
||||||
|
#import "PTKeyCombo.h" |
||||||
|
#import "PTKeyCodeTranslator.h" |
||||||
|
|
||||||
|
@implementation PTKeyCombo |
||||||
|
|
||||||
|
+ (id)clearKeyCombo |
||||||
|
{ |
||||||
|
return [self keyComboWithKeyCode: -1 modifiers: -1]; |
||||||
|
} |
||||||
|
|
||||||
|
+ (id)keyComboWithKeyCode: (NSInteger)keyCode modifiers: (NSUInteger)modifiers |
||||||
|
{ |
||||||
|
return [[self alloc] initWithKeyCode: keyCode modifiers: modifiers]; |
||||||
|
} |
||||||
|
|
||||||
|
- (id)initWithKeyCode: (NSInteger)keyCode modifiers: (NSUInteger)modifiers |
||||||
|
{ |
||||||
|
self = [super init]; |
||||||
|
|
||||||
|
if( self ) |
||||||
|
{ |
||||||
|
switch ( keyCode ) |
||||||
|
{ |
||||||
|
case kVK_F1: |
||||||
|
case kVK_F2: |
||||||
|
case kVK_F3: |
||||||
|
case kVK_F4: |
||||||
|
case kVK_F5: |
||||||
|
case kVK_F6: |
||||||
|
case kVK_F7: |
||||||
|
case kVK_F8: |
||||||
|
case kVK_F9: |
||||||
|
case kVK_F10: |
||||||
|
case kVK_F11: |
||||||
|
case kVK_F12: |
||||||
|
case kVK_F13: |
||||||
|
case kVK_F14: |
||||||
|
case kVK_F15: |
||||||
|
case kVK_F16: |
||||||
|
case kVK_F17: |
||||||
|
case kVK_F18: |
||||||
|
case kVK_F19: |
||||||
|
case kVK_F20: |
||||||
|
mModifiers = modifiers | NSFunctionKeyMask; |
||||||
|
break; |
||||||
|
default: |
||||||
|
mModifiers = modifiers; |
||||||
|
break; |
||||||
|
} |
||||||
|
|
||||||
|
mKeyCode = keyCode; |
||||||
|
} |
||||||
|
|
||||||
|
return self; |
||||||
|
} |
||||||
|
|
||||||
|
- (id)initWithPlistRepresentation: (id)plist |
||||||
|
{ |
||||||
|
int keyCode, modifiers; |
||||||
|
|
||||||
|
if( !plist || ![plist count] ) |
||||||
|
{ |
||||||
|
keyCode = -1; |
||||||
|
modifiers = -1; |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
keyCode = [[plist objectForKey: @"keyCode"] intValue]; |
||||||
|
if( keyCode < 0 ) keyCode = -1; |
||||||
|
|
||||||
|
modifiers = [[plist objectForKey: @"modifiers"] intValue]; |
||||||
|
if( modifiers <= 0 ) modifiers = -1; |
||||||
|
} |
||||||
|
|
||||||
|
return [self initWithKeyCode: keyCode modifiers: modifiers]; |
||||||
|
} |
||||||
|
|
||||||
|
- (id)plistRepresentation |
||||||
|
{ |
||||||
|
return [NSDictionary dictionaryWithObjectsAndKeys: |
||||||
|
[NSNumber numberWithInteger: [self keyCode]], @"keyCode", |
||||||
|
[NSNumber numberWithInteger: [self modifiers]], @"modifiers", |
||||||
|
nil]; |
||||||
|
} |
||||||
|
|
||||||
|
- (id)copyWithZone:(NSZone*)zone; |
||||||
|
{ |
||||||
|
return self; |
||||||
|
} |
||||||
|
|
||||||
|
- (BOOL)isEqual: (PTKeyCombo*)combo |
||||||
|
{ |
||||||
|
return [self keyCode] == [combo keyCode] && |
||||||
|
[self modifiers] == [combo modifiers]; |
||||||
|
} |
||||||
|
|
||||||
|
#pragma mark - |
||||||
|
|
||||||
|
- (NSInteger)keyCode |
||||||
|
{ |
||||||
|
return mKeyCode; |
||||||
|
} |
||||||
|
|
||||||
|
- (NSUInteger)modifiers |
||||||
|
{ |
||||||
|
return mModifiers; |
||||||
|
} |
||||||
|
|
||||||
|
- (BOOL)isValidHotKeyCombo |
||||||
|
{ |
||||||
|
return mKeyCode >= 0 && mModifiers > 0; |
||||||
|
} |
||||||
|
|
||||||
|
- (BOOL)isClearCombo |
||||||
|
{ |
||||||
|
return mKeyCode == -1 && mModifiers == 0; |
||||||
|
} |
||||||
|
|
||||||
|
@end |
@ -0,0 +1,112 @@ |
|||||||
|
ShortcutRecorder 2 |
||||||
|
==================== |
||||||
|
![pre-Yosemite ShortcutRecorder Preview](Demo/example.png) |
||||||
|
![Yosemite ShortcutRecorder Preview](Demo/example-yosemite.png) |
||||||
|
|
||||||
|
The only user interface control to record shortcuts. For Mac OS X 10.6+, 64bit. |
||||||
|
|
||||||
|
- :microscope: Support for Xcode 6 Quick Help |
||||||
|
- :microscope: Support for Xcode 6 Interface Builder integration |
||||||
|
- Fresh Look & Feel (brought to you by [Wireload](http://wireload.net) and [John Wells](https://github.com/jwells89)) |
||||||
|
- With Retina support |
||||||
|
- Auto Layout ready |
||||||
|
- Correct drawing on Layer-backed and Layer-hosted views |
||||||
|
- Accessibility for people with disabilities |
||||||
|
- Revised codebase with Automatic Reference Counting support |
||||||
|
- Translated into 24 languages |
||||||
|
|
||||||
|
Includes framework to set global shortcuts (PTHotKey). |
||||||
|
|
||||||
|
Get Sources |
||||||
|
----------- |
||||||
|
The preferred way to add the ShortcutRecorder to your project is to use git submodules: |
||||||
|
`git submodule add git://github.com/Kentzo/ShortcutRecorder.git` |
||||||
|
You can download sources from the site as well. |
||||||
|
|
||||||
|
Integrate into your project |
||||||
|
--------------------------- |
||||||
|
First, add ShortcutRecorder.xcodeproj to your workspace via Xcode ([Apple docs](https://developer.apple.com/library/mac/recipes/xcode_help-structure_navigator/articles/Adding_an_Existing_Project_to_a_Workspace.html)). Don't have a workspace? No problem, just add ShortcutRecorder.xcodeproj via the "Add Files to" dialog. |
||||||
|
|
||||||
|
Next step is to ensure your target is linked against the ShortcutRecorder or/and PTHotKey frameworks ([Apple docs](http://developer.apple.com/library/ios/#recipes/xcode_help-project_editor/Articles/AddingaLibrarytoaTarget.html#//apple_ref/doc/uid/TP40010155-CH17)). Desired frameworks will be listed under *Workspace*. |
||||||
|
|
||||||
|
Now it's time to make frameworks part of your app. To do this, you need to add custom Build Phase ([Apple docs](http://developer.apple.com/library/ios/#recipes/xcode_help-project_editor/Articles/CreatingaCopyFilesBuildPhase.html)). Remember to set *Destination* to *Frameworks* and clean up *Subpath*. |
||||||
|
|
||||||
|
Finally, ensure your app will find frameworks upon start. Open Build Settings of your target, look up *Runtime Search Paths*. Add `@executable_path/../Frameworks` to the list of paths. |
||||||
|
|
||||||
|
Add control in Interface Builder |
||||||
|
-------------------------------- |
||||||
|
Since Xcode 4 Apple removed Interface Builder Plugins. You can only use it to add and position/resize ShortcutRecorder control. To do this, add Custom View and set its class to SRRecorderControl. |
||||||
|
|
||||||
|
SRRecorderControl has fixed height of 25 points so ensure you do not use autoresizing masks/layout rules which allows vertical resizing. I recommend you to pin height in case you're using Auto Layout. |
||||||
|
|
||||||
|
Usage |
||||||
|
----- |
||||||
|
First, we want to keep value of the control across relaunches of the app. We can simply achieve this by using NSUserDefaultsController and bindings: |
||||||
|
|
||||||
|
[self.pingShortcutRecorder bind:NSValueBinding |
||||||
|
toObject:[NSUserDefaultsController sharedUserDefaultsController] |
||||||
|
withKeyPath:@"values.ping" |
||||||
|
options:nil]; |
||||||
|
|
||||||
|
The value can be used to set key equivalent of NSMenuItem or NSButton. It can also be used to register a global shortcut. |
||||||
|
|
||||||
|
Setting key equivalent of NSMenuItem using bindings: |
||||||
|
|
||||||
|
[self.pingItem bind:@"keyEquivalent" |
||||||
|
toObject:defaults |
||||||
|
withKeyPath:@"values.ping" |
||||||
|
options:@{NSValueTransformerBindingOption: [SRKeyEquivalentTransformer new]}]; |
||||||
|
[self.pingItem bind:@"keyEquivalentModifierMask" |
||||||
|
toObject:defaults |
||||||
|
withKeyPath:@"values.ping" |
||||||
|
options:@{NSValueTransformerBindingOption: [SRKeyEquivalentModifierMaskTransformer new]}]; |
||||||
|
|
||||||
|
Setting key equivalent of NSButton using bindings: |
||||||
|
|
||||||
|
[self.pingButton bind:@"keyEquivalent" |
||||||
|
toObject:defaults |
||||||
|
withKeyPath:@"values.ping" |
||||||
|
options:@{NSValueTransformerBindingOption: [SRKeyEquivalentTransformer new]}]; |
||||||
|
[self.pingButton bind:@"keyEquivalentModifierMask" |
||||||
|
toObject:defaults |
||||||
|
withKeyPath:@"values.ping" |
||||||
|
options:@{NSValueTransformerBindingOption: [SRKeyEquivalentModifierMaskTransformer new]}]; |
||||||
|
|
||||||
|
Setting global shortcut using PTHotKeyCenter: |
||||||
|
|
||||||
|
PTHotKeyCenter *hotKeyCenter = [PTHotKeyCenter sharedCenter]; |
||||||
|
PTHotKey *oldHotKey = [hotKeyCenter hotKeyWithIdentifier:aKeyPath]; |
||||||
|
[hotKeyCenter unregisterHotKey:oldHotKey]; |
||||||
|
|
||||||
|
PTHotKey *newHotKey = [PTHotKey hotKeyWithIdentifier:aKeyPath |
||||||
|
keyCombo:newShortcut |
||||||
|
target:self |
||||||
|
action:@selector(ping:)]; |
||||||
|
[hotKeyCenter registerHotKey:newHotKey]; |
||||||
|
|
||||||
|
Key Equivalents and Keyboard Layout |
||||||
|
---------------------------------------------------- |
||||||
|
While ShortcutRecorder keeps your shortcuts as combination of *key code* and modifier masks, key equivalents are expressed using *key character* and modifier mask. The difference is that position of key code on keyboard does not depend on current keyboard layout while position of key character does. |
||||||
|
|
||||||
|
ShortcutRecorder includes two special transformers to simplify binding to the key equivalents of NSMenuItem and NSButton: |
||||||
|
|
||||||
|
- SRKeyEquivalentTransformer |
||||||
|
- SRKeyEquivalentModifierMaskTransformer |
||||||
|
|
||||||
|
SRKeyEquivalentTransformer uses ASCII keyboard layout to convert key code into character, therefore resulting character does not depend on keyboard layout. |
||||||
|
The drawback is that position of the character on keyboard may change depending on layout and used modifier keys (primarly Option and Shift). |
||||||
|
|
||||||
|
NSButton |
||||||
|
-------- |
||||||
|
If you're going to bind ShortcutRecorder to key equivalent of NSButton, I encourage you to require `NSCommandKeyMask`. |
||||||
|
This is because NSButton handles key equivalents very strange. Rather than investigating full information of the keyboard event, it just asks for `charactersIgnoringModifiers` |
||||||
|
and compares returned value with its `keyEquivalent`. Unfortunately, Cocoa returns layout-independent (ASCII) representation of characters only when NSCommandKeyMask is set. |
||||||
|
If it's not set, assigned shortcut likely won't work with other layouts. |
||||||
|
|
||||||
|
Questions |
||||||
|
--------- |
||||||
|
Still have questions? [Create an issue](https://github.com/Kentzo/ShortcutRecorder/issues/new) immediately and feel free to ping me. |
||||||
|
|
||||||
|
Paid Support |
||||||
|
------------ |
||||||
|
If functional you need is missing but you're ready to pay for it, feel free to contact me. If not, create an issue anyway, I'll take a look as soon as I can. |
@ -0,0 +1,40 @@ |
|||||||
|
Copyright (c) 2006, contributors to ShortcutRecorder. (See the contributors listed in detail later in the file, or see <http://wafflesoftware.net/shortcut/contributors/>.) |
||||||
|
|
||||||
|
All rights reserved. |
||||||
|
Redistribution and use in source and binary forms, with or without |
||||||
|
modification, are permitted provided that the following conditions are met: |
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright |
||||||
|
notice, this list of conditions and the following disclaimer. |
||||||
|
* Redistributions in binary form must reproduce the above copyright |
||||||
|
notice, this list of conditions and the following disclaimer in the |
||||||
|
documentation and/or other materials provided with the distribution. |
||||||
|
* The name of the contributors may not be used to endorse or promote |
||||||
|
products derived from this software without specific prior written |
||||||
|
permission. |
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS "AS IS" AND ANY |
||||||
|
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY |
||||||
|
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
||||||
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
||||||
|
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
|
||||||
|
===================================================================== |
||||||
|
|
||||||
|
Contributors to Shortcut Recorder, in no order in particular: |
||||||
|
Jesper, waffle software, <wootest+shortcutrecorder@gmail.com>. Initial idea and concept, first shot at implementation using NSView. |
||||||
|
David Dauer, <david@daviddauer.de>. Refinement, cleaner reimplementation, documentation, IB Palette. |
||||||
|
Jamie Kirkpatrick, Kirk Consulting Ltd, <jkp@kirkconsulting.co.uk>. Further modularisation and re-factoring, and general bug fixes. |
||||||
|
Ilya Kulakov, <kulakov.ilya@gmail.com>. ShortcutRecorder 2.0 and further support. |
||||||
|
Alexander Ljungberg, <aljungberg@wireload.net>. Graphics for ShortcutRecorder 2.0 |
||||||
|
|
||||||
|
===================================================================== |
||||||
|
|
||||||
|
Some rights reserved: <http://creativecommons.org/licenses/by/3.0/> |
||||||
|
|
||||||
|
For more information, visit <http://blog.oofn.net/projects/misc/> |
After Width: | Height: | Size: 527 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 116 B |
After Width: | Height: | Size: 179 B |
After Width: | Height: | Size: 557 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 505 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 111 B |
After Width: | Height: | Size: 162 B |
After Width: | Height: | Size: 524 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 525 B |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 106 B |
After Width: | Height: | Size: 171 B |
After Width: | Height: | Size: 575 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 563 B |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 105 B |
After Width: | Height: | Size: 171 B |
After Width: | Height: | Size: 584 B |
After Width: | Height: | Size: 1.2 KiB |