@ -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 |