23 Commits

Author SHA1 Message Date
Tomáš Znamenáček 3ebbb7efde Version bump to 2.1.0. 2015-01-16 11:53:19 +01:00
Tomáš Znamenáček 66fd9b8e41 Merge pull request #57 from shpakovski/legacy-osx-support
Legacy OS X support down to 10.6 included (fixes #56).
2015-01-16 11:38:43 +01:00
Tomáš Znamenáček 1baa2bae9d Removed section about ARC support from README.
There are now two officially supported ways to use MASShortcut: through
including the Xcode project in your app’s workspace and linking against
MASShortcut.framework, and through CocoaPods. Both options work well in both
ARC and MRC projects with no additional settings needed. (I use MASShortcut in
a MRC project myself.)
2015-01-16 09:42:37 +01:00
Tomáš Znamenáček 27eace979e Added test for hotkeys and shortcut monitor. 2015-01-14 12:54:49 +01:00
Tomáš Znamenáček 44542896d4 Updating to current master. 2015-01-14 11:07:22 +01:00
Tomáš Znamenáček bdb64f0177 Use the clear glyph instead of backspace for clearing a shortcut.
The recording control used to display the backspace glyph (U+232B)
on the button that clears the shortcut. That’s a bit confusing, since
the same backspace glyph can also appear inside the control,
representing the recorded shortcut. The clear glyph (U+2715,
diagonal cross) seems like a better fit – it’s already used in
similar context throughout the Apple UIs like search bars.
2015-01-14 10:03:31 +01:00
Tomáš Znamenáček cfc4bd64d0 Updated headerdoc markup for MASShortcutView+Bindings. 2015-01-14 09:59:28 +01:00
Vadim Shpakovski 988fcee208 Fix README. 2015-01-13 20:45:29 +03:00
Vadim Shpakovski ca561ca70c Merge pull request #59 from aral/patch-1
Added explicit instructions for use in Swift
2015-01-13 20:25:58 +03:00
Aral Balkan 8dc86c9b62 Added explicit instructions for use in Swift
The explicit Cocoa import had tripped me up. Would be good to save someone the same hassle.
2015-01-13 17:21:27 +00:00
Tomáš Znamenáček 86eff031bf Merge branch 'master' into legacy-osx-support.
Conflicts:
	CHANGES
2015-01-13 13:26:24 +01:00
Tomáš Znamenáček 62c142a7f5 Added the Travis build status badge to the README. 2015-01-13 13:24:59 +01:00
Vadim Shpakovski 8286403add Merge pull request #58 from zoul/travis
Add support for Travis Continuous Integration server.
2015-01-13 13:56:55 +03:00
Tomáš Znamenáček a045295531 Added shared Xcode schemes to help Travis with the build. 2015-01-13 09:21:58 +01:00
Tomáš Znamenáček 807c5d782b Added a barebones Travis config file. 2015-01-13 09:14:23 +01:00
Tomáš Znamenáček cd0926808c Changed headerdoc markup to work better with CocoaDocs (closes #55). 2015-01-13 08:49:56 +01:00
Tomáš Znamenáček b9b1964b3f Non-exclusive hotkey registration (#56). 2015-01-12 17:10:20 +01:00
Tomáš Znamenáček 5208c981af Updated Deployment Target setting in podspec. 2015-01-12 17:10:20 +01:00
Tomáš Znamenáček 86a3231398 Added support for older OS X releases back to 10.6 included.
Apart from turning off Auto Layout for the Demo project, the only
thing remaining was several __weak qualifiers to prevent retain
cycles in blocks. I have replaced them with __unsafe_unretained
since __weak is not supported on 10.6. There should be no safety
concerns here, since we are certain the pointers will remain valid.
2015-01-12 17:10:20 +01:00
Vadim Shpakovski 0a0619461d Remove Xcode warnings and fix the hard-coded shortcut. 2015-01-09 22:04:10 +03:00
Tomáš Znamenáček 25d97b68c7 Removed an obsolete reference to the XCTest framework. 2015-01-09 12:58:06 +01:00
Tomáš Znamenáček 179dcd6cc2 Trivial podspec whitespace fixes. 2015-01-09 11:53:46 +01:00
Tomáš Znamenáček 2bbdbbfff9 Fixed Podspec (silly me). 2015-01-09 11:37:00 +01:00
20 changed files with 370 additions and 95 deletions
+3
View File
@@ -0,0 +1,3 @@
language: objective-c
xcode_project: MASShortcut.xcodeproj
xcode_scheme: MASShortcut
+7
View File
@@ -1,3 +1,10 @@
2.1.0 2015/1/16
- Added support for older OS X versions down to 10.6 included.
- Headerdoc markup that plays better with CocoaDocs.
2.0.1 2015/1/9
- Trivial Podspec fix.
2.0.0 2015/1/9
- First version with a changes file :)
- Major, backwards incompatible refactoring to simplify long-term maintenance.
+2 -2
View File
@@ -43,7 +43,7 @@ static void *MASObservingContext = &MASObservingContext;
context:MASObservingContext];
}
- (void) playShortcutFeedback
- (void)playShortcutFeedback
{
[[NSSound soundNamed:@"Ping"] play];
[_feedbackTextField setStringValue:@"Shortcut pressed!"];
@@ -83,7 +83,7 @@ static void *MASObservingContext = &MASObservingContext;
- (void) setHardcodedShortcutEnabled: (BOOL) enabled
{
MASShortcut *shortcut = [MASShortcut shortcutWithKeyCode:kVK_ANSI_Keypad2 modifierFlags:NSCommandKeyMask];
MASShortcut *shortcut = [MASShortcut shortcutWithKeyCode:kVK_F2 modifierFlags:NSCommandKeyMask];
if (enabled) {
[[MASShortcutMonitor sharedMonitor] registerShortcut:shortcut withAction:^{
[self playShortcutFeedback];
+22 -15
View File
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="6254" systemVersion="14B25" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="6254" systemVersion="14B25" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="6254"/>
@@ -649,25 +649,28 @@
</menu>
<window title="Demo" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" frameAutosaveName="DemoWindow" animationBehavior="default" id="371">
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES"/>
<rect key="contentRect" x="335" y="390" width="385" height="129"/>
<rect key="screenRect" x="0.0" y="0.0" width="1920" height="1057"/>
<rect key="contentRect" x="335" y="390" width="393" height="129"/>
<rect key="screenRect" x="0.0" y="0.0" width="1440" height="877"/>
<view key="contentView" id="372">
<rect key="frame" x="0.0" y="0.0" width="385" height="129"/>
<rect key="frame" x="0.0" y="0.0" width="393" height="129"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<customView fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="536" customClass="MASShortcutView">
<customView id="536" customClass="MASShortcutView">
<rect key="frame" x="142" y="90" width="158" height="19"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
</customView>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="PG0-jh-Onh">
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" id="PG0-jh-Onh">
<rect key="frame" x="18" y="92" width="111" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Custom shortcut:" id="85u-1A-n7H">
<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>
<button fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="zCi-ki-Uuh">
<button id="zCi-ki-Uuh">
<rect key="frame" x="140" y="63" width="169" height="18"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="check" title="Enable custom shortcut" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="Y47-p3-sDa">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
@@ -676,17 +679,19 @@
<binding destination="rCO-Ve-DT5" name="value" keyPath="values.customShortcutEnabled" id="VjS-3V-VdA"/>
</connections>
</button>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="KnS-ut-phz">
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" id="KnS-ut-phz">
<rect key="frame" x="18" y="65" width="111" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Options:" id="cUE-gA-heG">
<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>
<button fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="F4r-KM-wn9">
<rect key="frame" x="140" y="43" width="227" height="18"/>
<buttonCell key="cell" type="check" title="Enable hard-coded shortcut (⌘2)" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="7gv-jN-44g">
<button id="F4r-KM-wn9">
<rect key="frame" x="140" y="43" width="235" height="18"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="check" title="Enable hard-coded shortcut (⌘F2)" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="7gv-jN-44g">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
@@ -694,25 +699,27 @@
<binding destination="rCO-Ve-DT5" name="value" keyPath="values.hardcodedShortcutEnabled" id="dlZ-si-HeN"/>
</connections>
</button>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="9fB-XS-8pK">
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" id="9fB-XS-8pK">
<rect key="frame" x="18" y="20" width="111" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Feedback:" id="Zbz-mV-NDc">
<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="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Aso-dH-W8I">
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" id="Aso-dH-W8I">
<rect key="frame" x="140" y="20" width="211" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="left" placeholderString="Press a shortcut to see feedback" id="Ckx-v7-e6x">
<font key="font" metaFont="system"/>
<color key="textColor" red="1" green="0.14901961389999999" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="calibratedRGB"/>
<color key="textColor" red="0.37647062540054321" green="0.85098046064376831" blue="0.17647059261798859" alpha="1" colorSpace="deviceRGB"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
</view>
<point key="canvasLocation" x="348.5" y="367.5"/>
<point key="canvasLocation" x="352.5" y="367.5"/>
</window>
<customObject id="494" customClass="AppDelegate">
<connections>
+2 -2
View File
@@ -15,9 +15,9 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>2.0.0</string>
<string>2.1.0</string>
<key>CFBundleVersion</key>
<string>2.0.0</string>
<string>2.1.0</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 20142015 Vadim Shpakovski. All rights reserved.</string>
</dict>
+6 -6
View File
@@ -1,17 +1,17 @@
extern NSString *const MASDictionaryTransformerName;
/**
@brief Converts shortcuts for storage in user defaults.
Converts shortcuts for storage in user defaults.
User defaults cant stored custom types directly, they have to
be serialized to @p NSData or some other supported type like an
@p NSDictionary. In Cocoa Bindings, the conversion can be done
be serialized to `NSData` or some other supported type like an
`NSDictionary`. In Cocoa Bindings, the conversion can be done
using value transformers like this one.
Theres a built-in transformer (@p NSKeyedUnarchiveFromDataTransformerName)
that converts any @p NSCoding types to @p NSData, but with shortcuts
Theres a built-in transformer (`NSKeyedUnarchiveFromDataTransformerName`)
that converts any `NSCoding` types to `NSData`, but with shortcuts
it makes sense to use a dictionary instead the defaults look better
when inspected with the @p defaults command-line utility and the
when inspected with the `defaults` command-line utility and the
format is compatible with an older sortcut library called Shortcut
Recorder.
*/
+1 -1
View File
@@ -19,7 +19,7 @@ FourCharCode const MASHotKeySignature = 'MASS';
EventHotKeyID hotKeyID = { .signature = MASHotKeySignature, .id = _carbonID };
OSStatus status = RegisterEventHotKey([shortcut carbonKeyCode], [shortcut carbonFlags],
hotKeyID, GetEventDispatcherTarget(), kEventHotKeyExclusive, &_hotKeyRef);
hotKeyID, GetEventDispatcherTarget(), 0, &_hotKeyRef);
if (status != noErr) {
return nil;
+15
View File
@@ -0,0 +1,15 @@
#import "MASHotKey.h"
@interface MASHotKeyTests : XCTestCase
@end
@implementation MASHotKeyTests
- (void) testBasicFunctionality
{
MASHotKey *hotKey = [MASHotKey registeredHotKeyWithShortcut:
[MASShortcut shortcutWithKeyCode:kVK_ANSI_H modifierFlags:NSCommandKeyMask|NSAlternateKeyMask]];
XCTAssertNotNil(hotKey, @"Register a simple Cmd-Alt-H hotkey.");
}
@end
+17 -17
View File
@@ -1,7 +1,7 @@
#import "MASKeyCodes.h"
/**
@brief A model class to hold a key combination.
A model class to hold a key combination.
This class just represents a combination of keys. It does not care if
the combination is valid or can be used as a hotkey, it doesnt watch
@@ -11,49 +11,49 @@
@interface MASShortcut : NSObject <NSSecureCoding, NSCopying>
/**
@brief The virtual key code for the keyboard key.
The virtual key code for the keyboard key.
@Hardware independent, same as in NSEvent. Events.h in the HIToolbox
framework for a complete list, or Command-click this symbol: kVK_ANSI_A.
Hardware independent, same as in `NSEvent`. See `Events.h` in the HIToolbox
framework for a complete list, or Command-click this symbol: `kVK_ANSI_A`.
*/
@property (nonatomic, readonly) NSUInteger keyCode;
/**
@brief Cocoa keyboard modifier flags.
Cocoa keyboard modifier flags.
Same as in NSEvent: NSCommandKeyMask, NSAlternateKeyMask, etc.
Same as in `NSEvent`: `NSCommandKeyMask`, `NSAlternateKeyMask`, etc.
*/
@property (nonatomic, readonly) NSUInteger modifierFlags;
/**
@brief Same as @p keyCode, just a different type.
Same as `keyCode`, just a different type.
*/
@property (nonatomic, readonly) UInt32 carbonKeyCode;
/**
@brief Carbon modifier flags.
Carbon modifier flags.
A bit sum of @p cmdKey, @p optionKey, etc.
A bit sum of `cmdKey`, `optionKey`, etc.
*/
@property (nonatomic, readonly) UInt32 carbonFlags;
/**
@brief A string representing the “key” part of a shortcut, like the “5” in ⌘5.
A string representing the “key” part of a shortcut, like the `5` in `⌘5`.
*/
@property (nonatomic, readonly) NSString *keyCodeString;
/**
@brief A key-code string used in key equivalent matching.
A key-code string used in key equivalent matching.
For precise meaning of “key equivalents” see the @p keyEquivalent
property of @p NSMenuItem. Here the string is used to support shortcut
For precise meaning of “key equivalents” see the `keyEquivalent`
property of `NSMenuItem`. Here the string is used to support shortcut
validation (“is the shortcut already taken in this menu?”) and
for display in @p NSMenu.
for display in `NSMenu`.
*/
@property (nonatomic, readonly) NSString *keyCodeStringForKeyEquivalent;
/**
@brief A string representing the shortcut modifiers, like the “⌘” in ⌘5.
A string representing the shortcut modifiers, like the `⌘` in `⌘5`.
*/
@property (nonatomic, readonly) NSString *modifierFlagsString;
@@ -61,9 +61,9 @@
+ (instancetype)shortcutWithKeyCode:(NSUInteger)code modifierFlags:(NSUInteger)flags;
/**
@brief Creates a new shortcut from an NSEvent object.
Creates a new shortcut from an `NSEvent` object.
This is just a convenience initializer that reads the key code and modifiers from an NSEvent.
This is just a convenience initializer that reads the key code and modifiers from an `NSEvent`.
*/
+ (instancetype)shortcutWithEvent:(NSEvent *)anEvent;
+14 -14
View File
@@ -1,22 +1,22 @@
#import "MASShortcutMonitor.h"
/**
@brief Binds actions to user defaults keys.
Binds actions to user defaults keys.
If you store shortcuts in user defaults (for example by binding
a @p MASShortcutView to user defaults), you can use this class to
a `MASShortcutView` to user defaults), you can use this class to
connect an action directly to a user defaults key. If the shortcut
stored under the key changes, the action will get automatically
updated to the new one.
This class is mostly a wrapper around a @p MASShortcutMonitor. It
This class is mostly a wrapper around a `MASShortcutMonitor`. It
watches the changes in user defaults and updates the shortcut monitor
accordingly with the new shortcuts.
*/
@interface MASShortcutBinder : NSObject
/**
@brief A convenience shared instance.
A convenience shared instance.
You may use it so that you dont have to manage an instance by hand,
but its perfectly fine to allocate and use a separate instance instead.
@@ -24,23 +24,23 @@
+ (instancetype) sharedBinder;
/**
@brief The underlying shortcut monitor.
The underlying shortcut monitor.
*/
@property(strong) MASShortcutMonitor *shortcutMonitor;
/**
@brief Binding options customizing the access to user defaults.
Binding options customizing the access to user defaults.
As an example, you can use @p NSValueTransformerNameBindingOption to customize
As an example, you can use `NSValueTransformerNameBindingOption` to customize
the storage format used for the shortcuts. By default the shortcuts are converted
from @p NSData (@p NSKeyedUnarchiveFromDataTransformerName). Note that if the
binder is to work with @p MASShortcutView, both object have to use the same storage
from `NSData` (`NSKeyedUnarchiveFromDataTransformerName`). Note that if the
binder is to work with `MASShortcutView`, both object have to use the same storage
format.
*/
@property(copy) NSDictionary *bindingOptions;
/**
@brief Binds given action to a shortcut stored under the given defaults key.
Binds given action to a shortcut stored under the given defaults key.
In other words, no matter what shortcut you store under the given key,
pressing it will always trigger the given action.
@@ -48,19 +48,19 @@
- (void) bindShortcutWithDefaultsKey: (NSString*) defaultsKeyName toAction: (dispatch_block_t) action;
/**
@brief Disconnect the binding between user defaults and action.
Disconnect the binding between user defaults and action.
In other words, the shortcut stored under the given key will no longer trigger an action.
*/
- (void) breakBindingWithDefaultsKey: (NSString*) defaultsKeyName;
/**
@brief Register default shortcuts in user defaults.
Register default shortcuts in user defaults.
This is a convenience frontent to [NSUserDefaults registerDefaults].
This is a convenience frontent to `[NSUserDefaults registerDefaults]`.
The dictionary should contain a map of user defaults keys to appropriate
keyboard shortcuts. The shortcuts will be transformed according to
@p bindingOptions and registered using @p registerDefaults.
`bindingOptions` and registered using `registerDefaults`.
*/
- (void) registerDefaultShortcuts: (NSDictionary*) defaultShortcuts;
+3 -3
View File
@@ -1,7 +1,7 @@
#import "MASShortcut.h"
/**
@brief Executes action when a shortcut is pressed.
Executes action when a shortcut is pressed.
There can only be one instance of this class, otherwise things
will probably not work. (Theres a Carbon event handler inside
@@ -13,12 +13,12 @@
+ (instancetype) sharedMonitor;
/**
@brief Register a shortcut along with an action.
Register a shortcut along with an action.
Attempting to insert an already registered shortcut probably wont work.
It may burn your house or cut your fingers. You have been warned.
*/
- (void) registerShortcut: (MASShortcut*) shortcut withAction: (dispatch_block_t) action;
- (BOOL) registerShortcut: (MASShortcut*) shortcut withAction: (dispatch_block_t) action;
- (BOOL) isShortcutRegistered: (MASShortcut*) shortcut;
- (void) unregisterShortcut: (MASShortcut*) shortcut;
+8 -3
View File
@@ -45,11 +45,16 @@ static OSStatus MASCarbonEventCallback(EventHandlerCallRef, EventRef, void*);
#pragma mark Registration
- (void) registerShortcut: (MASShortcut*) shortcut withAction: (dispatch_block_t) action
- (BOOL) registerShortcut: (MASShortcut*) shortcut withAction: (dispatch_block_t) action
{
MASHotKey *hotKey = [MASHotKey registeredHotKeyWithShortcut:shortcut];
[hotKey setAction:action];
[_hotKeys setObject:hotKey forKey:shortcut];
if (hotKey) {
[hotKey setAction:action];
[_hotKeys setObject:hotKey forKey:shortcut];
return YES;
} else {
return NO;
}
}
- (void) unregisterShortcut: (MASShortcut*) shortcut
+23
View File
@@ -0,0 +1,23 @@
#import "MASShortcutMonitor.h"
@interface MASShortcutMonitorTests : XCTestCase
@end
@implementation MASShortcutMonitorTests
- (void) testMonitorCreation
{
XCTAssertNotNil([MASShortcutMonitor sharedMonitor], @"Create a shared shortcut monitor.");
}
- (void) testShortcutRegistration
{
MASShortcutMonitor *monitor = [MASShortcutMonitor sharedMonitor];
MASShortcut *shortcut = [MASShortcut shortcutWithKeyCode:kVK_ANSI_H modifierFlags:NSCommandKeyMask|NSAlternateKeyMask];
XCTAssertTrue([monitor registerShortcut:shortcut withAction:NULL], @"Register a shortcut.");
XCTAssertTrue([monitor isShortcutRegistered:shortcut], @"Remember a previously registered shortcut.");
[monitor unregisterShortcut:shortcut];
XCTAssertFalse([monitor isShortcutRegistered:shortcut], @"Forget shortcut after unregistering.");
}
@end
+7 -7
View File
@@ -1,19 +1,19 @@
#import "MASShortcutView.h"
/**
@brief A simplified interface to bind the recorder value to user defaults.
A simplified interface to bind the recorder value to user defaults.
You can bind the @p shortcutValue to user defaults using the standard
@p bind:toObject:withKeyPath:options: call, but since thats a lot to type
You can bind the `shortcutValue` to user defaults using the standard
`bind:toObject:withKeyPath:options:` call, but since thats a lot to type
and read, heres a simpler option.
Setting the @p associatedUserDefaultsKey binds the views shortcut value
Setting the `associatedUserDefaultsKey` binds the views shortcut value
to the given user defaults key. You can supply a value transformer to convert
values between user defaults and @p MASShortcut. If you dont supply
a transformer, the @p NSUnarchiveFromDataTransformerName will be used
values between user defaults and `MASShortcut`. If you dont supply
a transformer, the `NSUnarchiveFromDataTransformerName` will be used
automatically.
Set @p associatedUserDefaultsKey to @p nil to disconnect the binding.
Set `associatedUserDefaultsKey` to `nil` to disconnect the binding.
*/
@interface MASShortcutView (Bindings)
+3 -3
View File
@@ -188,7 +188,7 @@ NSString *const MASShortcutBinding = @"shortcutValue";
- (void)drawRect:(CGRect)dirtyRect
{
if (self.shortcutValue) {
[self drawInRect:self.bounds withTitle:NSStringFromMASKeyCode(self.recording ? kMASShortcutGlyphEscape : kMASShortcutGlyphDeleteLeft)
[self drawInRect:self.bounds withTitle:NSStringFromMASKeyCode(self.recording ? kMASShortcutGlyphEscape : kMASShortcutGlyphClear)
alignment:NSRightTextAlignment state:NSOffState];
CGRect shortcutRect;
@@ -369,7 +369,7 @@ void *kUserDataHint = &kUserDataHint;
static id eventMonitor = nil;
if (shouldActivate) {
__weak MASShortcutView *weakSelf = self;
__unsafe_unretained MASShortcutView *weakSelf = self;
NSEventMask eventMask = (NSKeyDownMask | NSFlagsChangedMask);
eventMonitor = [NSEvent addLocalMonitorForEventsMatchingMask:eventMask handler:^(NSEvent *event) {
@@ -450,7 +450,7 @@ void *kUserDataHint = &kUserDataHint;
static id observer = nil;
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
if (shouldActivate) {
__weak MASShortcutView *weakSelf = self;
__unsafe_unretained MASShortcutView *weakSelf = self;
observer = [notificationCenter addObserverForName:NSWindowDidResignKeyNotification object:self.window
queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notification) {
weakSelf.recording = NO;
+14 -14
View File
@@ -1,17 +1,17 @@
Pod::Spec.new do |s|
s.name = 'MASShortcut'
s.version = '2.0.0'
s.summary = 'Modern framework for managing global keyboard shortcuts compatible with Mac App Store'
s.homepage = 'https://github.com/shpakovski/MASShortcut'
s.license = 'BSD 2-clause'
s.authors = { 'Vadim Shpakovski' => 'vadim@shpakovski.com',
'Tomáš Znamenáček' => 'tomas.znamenacek@gmail.com' }
s.name = 'MASShortcut'
s.version = '2.1.0'
s.summary = 'Modern framework for managing global keyboard shortcuts compatible with Mac App Store'
s.homepage = 'https://github.com/shpakovski/MASShortcut'
s.license = 'BSD 2-clause'
s.authors = { 'Vadim Shpakovski' => 'vadim@shpakovski.com',
'Tomáš Znamenáček' => 'tomas.znamenacek@gmail.com' }
s.platform = :osx
s.deployment_target = "10.7"
s.source = { :git => 'https://github.com/shpakovski/MASShortcut.git', :tag => '2.0.0' }
s.source_files = 'Framework/*.{h,m}'
s.exclude_files = 'Framework/*Tests.m'
s.osx.frameworks = 'Carbon', 'AppKit'
s.requires_arc = true
s.platform = :osx
s.osx.deployment_target = "10.6"
s.source = { :git => 'https://github.com/shpakovski/MASShortcut.git', :tag => '2.1.0' }
s.source_files = 'Framework/*.{h,m}'
s.exclude_files = 'Framework/*Tests.m'
s.osx.frameworks = 'Carbon', 'AppKit'
s.requires_arc = true
end
+16 -6
View File
@@ -7,6 +7,8 @@
objects = {
/* Begin PBXBuildFile section */
0D39DCA21A668A4400639145 /* MASHotKeyTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D39DCA11A668A4400639145 /* MASHotKeyTests.m */; };
0D39DCA41A668E5500639145 /* MASShortcutMonitorTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D39DCA31A668E5500639145 /* MASShortcutMonitorTests.m */; };
0D827CD71990D4420010B8EF /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0D827CD61990D4420010B8EF /* Cocoa.framework */; };
0D827D251990D55E0010B8EF /* MASShortcut.h in Headers */ = {isa = PBXBuildFile; fileRef = 0D827D1B1990D55E0010B8EF /* MASShortcut.h */; settings = {ATTRIBUTES = (Public, ); }; };
0D827D261990D55E0010B8EF /* MASShortcut.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D827D1C1990D55E0010B8EF /* MASShortcut.m */; };
@@ -17,9 +19,8 @@
0D827D711990D6110010B8EF /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D827D6D1990D6110010B8EF /* main.m */; };
0D827D721990D6110010B8EF /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 0D827D6E1990D6110010B8EF /* MainMenu.xib */; };
0D827D731990D6590010B8EF /* MASShortcut.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0D827CD31990D4420010B8EF /* MASShortcut.framework */; };
0D827D751990D6A60010B8EF /* MASShortcut.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = 0D827CD31990D4420010B8EF /* MASShortcut.framework */; };
0D827D751990D6A60010B8EF /* MASShortcut.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = 0D827CD31990D4420010B8EF /* MASShortcut.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
0D827D771990F81E0010B8EF /* Shortcut.h in Headers */ = {isa = PBXBuildFile; fileRef = 0D827D761990F81E0010B8EF /* Shortcut.h */; settings = {ATTRIBUTES = (Public, ); }; };
0D827D8419910AFF0010B8EF /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0D827CEB1990D4420010B8EF /* XCTest.framework */; };
0D827D9419910B740010B8EF /* MASShortcutTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D827D9319910B740010B8EF /* MASShortcutTests.m */; };
0D827D9519910C1E0010B8EF /* MASShortcut.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0D827CD31990D4420010B8EF /* MASShortcut.framework */; };
0D827D9719910FF70010B8EF /* MASKeyCodes.h in Headers */ = {isa = PBXBuildFile; fileRef = 0D827D9619910FF70010B8EF /* MASKeyCodes.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -65,12 +66,13 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
0D39DCA11A668A4400639145 /* MASHotKeyTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MASHotKeyTests.m; path = Framework/MASHotKeyTests.m; sourceTree = "<group>"; };
0D39DCA31A668E5500639145 /* MASShortcutMonitorTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MASShortcutMonitorTests.m; path = Framework/MASShortcutMonitorTests.m; sourceTree = "<group>"; };
0D827CD31990D4420010B8EF /* MASShortcut.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MASShortcut.framework; sourceTree = BUILT_PRODUCTS_DIR; };
0D827CD61990D4420010B8EF /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
0D827CD91990D4420010B8EF /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
0D827CDA1990D4420010B8EF /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; };
0D827CDB1990D4420010B8EF /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = SDKROOT; };
0D827CEB1990D4420010B8EF /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; };
0D827D1B1990D55E0010B8EF /* MASShortcut.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MASShortcut.h; path = Framework/MASShortcut.h; sourceTree = "<group>"; };
0D827D1C1990D55E0010B8EF /* MASShortcut.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MASShortcut.m; path = Framework/MASShortcut.m; sourceTree = "<group>"; };
0D827D211990D55E0010B8EF /* MASShortcutView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MASShortcutView.h; path = Framework/MASShortcutView.h; sourceTree = "<group>"; };
@@ -128,7 +130,6 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
0D827D8419910AFF0010B8EF /* XCTest.framework in Frameworks */,
0D827D9519910C1E0010B8EF /* MASShortcut.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -161,7 +162,6 @@
isa = PBXGroup;
children = (
0D827CD61990D4420010B8EF /* Cocoa.framework */,
0D827CEB1990D4420010B8EF /* XCTest.framework */,
0D827CD91990D4420010B8EF /* Foundation.framework */,
0D827CDA1990D4420010B8EF /* CoreData.framework */,
0D827CDB1990D4420010B8EF /* AppKit.framework */,
@@ -235,8 +235,10 @@
children = (
0DC2F17419922798003A0131 /* MASHotKey.h */,
0DC2F17519922798003A0131 /* MASHotKey.m */,
0D39DCA11A668A4400639145 /* MASHotKeyTests.m */,
0D827DA319912D240010B8EF /* MASShortcutMonitor.h */,
0D827DA419912D240010B8EF /* MASShortcutMonitor.m */,
0D39DCA31A668E5500639145 /* MASShortcutMonitorTests.m */,
);
name = Monitoring;
sourceTree = "<group>";
@@ -338,7 +340,7 @@
0D827CCA1990D4420010B8EF /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0510;
LastUpgradeCheck = 0610;
ORGANIZATIONNAME = "Vadim Shpakovski";
TargetAttributes = {
0D827D8219910AFF0010B8EF = {
@@ -423,6 +425,8 @@
0DC2F190199372B4003A0131 /* MASDictionaryTransformerTests.m in Sources */,
0D827D9419910B740010B8EF /* MASShortcutTests.m in Sources */,
0DC2F18919925F8F003A0131 /* MASShortcutBinderTests.m in Sources */,
0D39DCA21A668A4400639145 /* MASHotKeyTests.m in Sources */,
0D39DCA41A668E5500639145 /* MASShortcutMonitorTests.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -520,6 +524,7 @@
GCC_PREFIX_HEADER = Framework/Prefix.pch;
INFOPLIST_FILE = Framework/Info.plist;
INSTALL_PATH = "@executable_path/../Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.6;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
WRAPPER_EXTENSION = framework;
@@ -537,6 +542,7 @@
GCC_PREFIX_HEADER = Framework/Prefix.pch;
INFOPLIST_FILE = Framework/Info.plist;
INSTALL_PATH = "@executable_path/../Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.6;
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
WRAPPER_EXTENSION = framework;
@@ -555,6 +561,7 @@
"$(inherited)",
);
INFOPLIST_FILE = Demo/Info.plist;
MACOSX_DEPLOYMENT_TARGET = 10.6;
PRODUCT_NAME = "$(TARGET_NAME)";
WRAPPER_EXTENSION = app;
};
@@ -568,6 +575,7 @@
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = Demo/Prefix.pch;
INFOPLIST_FILE = Demo/Info.plist;
MACOSX_DEPLOYMENT_TARGET = 10.6;
PRODUCT_NAME = "$(TARGET_NAME)";
WRAPPER_EXTENSION = app;
};
@@ -576,6 +584,7 @@
0D827D9019910AFF0010B8EF /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
COMBINE_HIDPI_IMAGES = YES;
FRAMEWORK_SEARCH_PATHS = (
"$(DEVELOPER_FRAMEWORKS_DIR)",
"$(inherited)",
@@ -595,6 +604,7 @@
0D827D9119910AFF0010B8EF /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
COMBINE_HIDPI_IMAGES = YES;
FRAMEWORK_SEARCH_PATHS = (
"$(DEVELOPER_FRAMEWORKS_DIR)",
"$(inherited)",
@@ -0,0 +1,86 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0610"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0D827D361990D5E70010B8EF"
BuildableName = "Demo.app"
BlueprintName = "Demo"
ReferencedContainer = "container:MASShortcut.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
buildConfiguration = "Debug">
<Testables>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0D827D361990D5E70010B8EF"
BuildableName = "Demo.app"
BlueprintName = "Demo"
ReferencedContainer = "container:MASShortcut.xcodeproj">
</BuildableReference>
</MacroExpansion>
</TestAction>
<LaunchAction
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
buildConfiguration = "Debug"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
allowLocationSimulation = "YES">
<BuildableProductRunnable>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0D827D361990D5E70010B8EF"
BuildableName = "Demo.app"
BlueprintName = "Demo"
ReferencedContainer = "container:MASShortcut.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
buildConfiguration = "Release"
debugDocumentVersioning = "YES">
<BuildableProductRunnable>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0D827D361990D5E70010B8EF"
BuildableName = "Demo.app"
BlueprintName = "Demo"
ReferencedContainer = "container:MASShortcut.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
@@ -0,0 +1,110 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0610"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0D827CD21990D4420010B8EF"
BuildableName = "MASShortcut.framework"
BlueprintName = "MASShortcut"
ReferencedContainer = "container:MASShortcut.xcodeproj">
</BuildableReference>
</BuildActionEntry>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "NO"
buildForArchiving = "NO"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0D827D8219910AFF0010B8EF"
BuildableName = "Tests.xctest"
BlueprintName = "Tests"
ReferencedContainer = "container:MASShortcut.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
buildConfiguration = "Debug">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0D827D8219910AFF0010B8EF"
BuildableName = "Tests.xctest"
BlueprintName = "Tests"
ReferencedContainer = "container:MASShortcut.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0D827CD21990D4420010B8EF"
BuildableName = "MASShortcut.framework"
BlueprintName = "MASShortcut"
ReferencedContainer = "container:MASShortcut.xcodeproj">
</BuildableReference>
</MacroExpansion>
</TestAction>
<LaunchAction
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
buildConfiguration = "Debug"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0D827CD21990D4420010B8EF"
BuildableName = "MASShortcut.framework"
BlueprintName = "MASShortcut"
ReferencedContainer = "container:MASShortcut.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
buildConfiguration = "Release"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0D827CD21990D4420010B8EF"
BuildableName = "MASShortcut.framework"
BlueprintName = "MASShortcut"
ReferencedContainer = "container:MASShortcut.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
+11 -2
View File
@@ -1,3 +1,5 @@
[![Build Status](https://travis-ci.org/shpakovski/MASShortcut.svg?branch=master)](https://travis-ci.org/shpakovski/MASShortcut)
# Intro
Some time ago Cocoa developers used a brilliant framework [ShortcutRecorder](http://wafflesoftware.net/shortcut/) for managing keyboard shortcuts in application preferences. However, it became incompatible with the new plugin architecture of Xcode 4.
@@ -93,9 +95,16 @@ _observableKeyPath = [@"values." stringByAppendingString:kPreferenceGlobalShortc
context:kGlobalShortcutContext];
```
# Non-ARC Version
# Using in Swift projects
If you like retain/release, please check out these forks: [heardrwt/MASShortcut](https://github.com/heardrwt/MASShortcut) and [chendo/MASShortcut](https://github.com/chendo/MASShortcut). However, the preferred way is to enable the `-fobjc-arc` in Xcode source options.
1. Install as a Pod using the latest CocoaPods with Swift support.
2. Create a bridging header file [using the instructions here](http://swiftalicio.us/2014/11/using-cocoapods-from-swift/)
3. Your bridging header file should contain the following [two](https://github.com/shpakovski/MASShortcut/issues/36) imports:
```objective-c
#import <Cocoa/Cocoa.h>
#import <MASShortcut/Shortcut.h>
```
# Copyright