110 Commits

Author SHA1 Message Date
Tomáš Znamenáček 409699c3c0 Version bump to 2.3.4 2016-08-12 11:49:17 +02:00
Vadim Shpakovski 928bbe25b4 Upgrade Projects to Xcode 7 2016-08-08 18:24:19 +03:00
Vadim Shpakovski 658a4e1e78 Merge pull request #94 from sfsam/master
Added Makefile to build from the command line
2016-07-15 09:45:59 +03:00
Sanjay Madan bd3cf9bf9c Added Makefile to build from the command line 2016-07-14 22:12:06 -07:00
Vadim Shpakovski a4dd585497 Merge pull request #93 from pointum/master
ru localization update
2016-07-13 17:35:07 +03:00
Maxim Ananov 843cb81697 ru localization update 2016-07-13 17:26:02 +03:00
Tomáš Znamenáček 9471ddbc7c Update CHANGES 2016-04-14 10:08:23 +02:00
Vadim Shpakovski 46bd84f57d Merge pull request #89 from radex/add-translations
Add Korean, Dutch, Polish, Russian & update Spanish translations
2016-04-14 11:04:37 +03:00
radex 6233bfac56 Add ko, nl, pl, ru, es translations 2016-04-14 09:55:34 +02:00
Tomáš Znamenáček 03e3ed398a Use correct quote signs for German translation.
The quotes should be like „this“, not ‘this’.
2016-02-14 09:44:45 +01:00
Tomáš Znamenáček 00b5041867 Shortened the new German translation strings to fit the UI.
Closes #85.
2016-02-14 09:41:52 +01:00
Tomáš Znamenáček 69b0a06656 Added basic German localization to the demo project.
This makes it possible to test the German MASShortcut localization
on the demo project.
2016-02-10 19:13:53 +01:00
Tomáš Znamenáček abb1ac2799 Updated CHANGES. 2016-02-05 10:07:59 +01:00
Vadim Shpakovski 9bbb5b3e6a Merge pull request #84 from floschliep/master
Improve German Localization
2016-02-05 09:30:17 +01:00
Florian Schliep 00dd8616f1 Improved German Localization
I translated the missing strings and improved the existing ones.
2016-02-04 18:56:50 +01:00
Tomáš Znamenáček d359752bef Updated CHANGES. 2016-01-22 10:29:17 +01:00
Tomáš Znamenáček 6b80ea95b5 Merge pull request #83 from MichaelRow/master
Simplified and traditional Chinese localizations.
2016-01-22 10:28:06 +01:00
MichaelRow 8e14c20ca4 Simplified and traditional Chinese localizations. 2016-01-22 12:04:51 +08:00
Tomáš Znamenáček d0063130b5 Version bump to 2.3.3. 2016-01-09 15:51:28 +01:00
Tomáš Znamenáček c384d0e94b Updated CHANGES. 2016-01-09 15:47:06 +01:00
Tomáš Znamenáček e267d30bfd Whitespace fixes. 2016-01-09 15:45:45 +01:00
Nikita Ivanchikov d32fc188ca Another approach to try a fix for the CocoaPods localization bundle problem (#74).
Checking if resources bundle was copied inside framework bundle, then falling back to old search methods
2016-01-09 15:43:05 +01:00
Tomáš Znamenáček 2b2fb80556 Updated changelog. 2015-12-06 16:08:46 +01:00
Tomáš Znamenáček 60978895b2 Merge pull request #80 from magiclantern/magiclantern/french-localization
Expanded Frech localization.
2015-12-06 16:07:10 +01:00
Nikita Ourazbaev 6a97ae68e9 Some suggestions for fr
Some suggestions for the gaps in the French localization
2015-12-06 10:04:45 -05:00
Tomáš Znamenáček 29d047c928 Documented that we don’t accept Option-Shift shortcuts by default.
The reason is that Option-Shift shortcuts are often already used
by system to insert some special characters. See `MASShortcutValidator`
for details, including how to enable support for these shortcuts.
Fixes #79.
2015-12-03 15:15:05 +01:00
Tomáš Znamenáček 5a18ccc5e1 Even more elaborate workaround for the CocoaPods localization problem (#74).
Just testing if the CocoaPods bundle is present didn’t work, so now we
even try to load a localized string from the bundle.
2015-11-06 08:59:52 +01:00
Tomáš Znamenáček e83732400b Trying a fix for the CocoaPods localization bundle problem (#74).
This change simply doesn’t try to detect which bundle we should use
and tries both bundles, the CocoaPods one first. The chosen bundle is
then cached to avoid the overhead on subsequent requests.
2015-11-04 15:02:55 +01:00
Tomáš Znamenáček 2730683848 Updated CHANGES. 2015-10-31 10:26:15 +01:00
Vadim Shpakovski 471322a113 Merge pull request #77 from oreshinya/japanese_localization
Japanese localization
2015-10-14 20:16:16 +03:00
shinya takahashi 09b7364130 Japanese localization 2015-10-14 18:44:06 +09:00
Tomáš Znamenáček 82a06382f0 Version bump to 2.3.2. 2015-10-12 09:31:34 +02:00
Tomáš Znamenáček dd2507b7f9 Silenced a potential “tautological compare” warning in MASShortcutView.
Fixes #76. I considered putting the #pragma just around the particular
compare line, but I think having it around the whole block is more readable
and there’s little chance of having some legitimate warnings silenced.
2015-10-12 09:28:19 +02:00
Tomáš Znamenáček a0af086f16 Typo fix. 2015-10-08 11:53:21 +02:00
Tomáš Znamenáček a73a254ce7 Documented the CocoaPods localization fix. 2015-10-08 11:30:24 +02:00
Tomáš Znamenáček ed694bc1a5 Merge pull request #75 from beaufour/master
Fixed localization when used from CocoaPods.
2015-10-08 11:26:27 +02:00
Allan Beaufour ded95506c6 fixes localized strings when using CocoaPods
Puts strings inside a MASShortcut resource bundle, and looks for
locallized strings inside that bundle when used as a CocoaPod
2015-10-07 12:52:59 -04:00
Tomáš Znamenáček b99a1a4dc4 Updated localization and accessibility status in README. 2015-09-10 10:01:40 +02:00
Tomáš Znamenáček dd0a37c785 Release 2.3.1. 2015-09-10 09:39:14 +02:00
Tomáš Znamenáček a06ef8d27c Changed MASLocalization.h to explicit import, trying to appease CocopaPods. 2015-09-10 09:37:38 +02:00
Tomáš Znamenáček 8b669cea8d Release 2.3.0. 2015-09-10 09:29:14 +02:00
Tomáš Znamenáček 3cca4da610 Added basic localization for German, Spanish, French, Italian, and Japanese. 2015-09-10 09:24:41 +02:00
Tomáš Znamenáček 78bd9fbd77 Mentioned Carthage in the installation options. 2015-08-18 17:26:41 +02:00
Tomáš Znamenáček c7fc9a555a Use an absolute URL for the demo screenshot.
An absolute URL works better on the CocoaPods website.
2015-08-18 17:24:58 +02:00
Tomáš Znamenáček 86be6257cb Updated contributing guidelines (backward compatibility, commit messages). 2015-08-18 17:23:09 +02:00
Tomáš Znamenáček 9f5db7ad25 Removed an obsolete Localizable.string file. 2015-08-18 14:01:33 +02:00
Tomáš Znamenáček 814934072a Added Czech localization. 2015-08-18 14:00:09 +02:00
Tomáš Znamenáček 74e3f32438 Updated CHANGES, Info.plist and podspec for the 2.2.0 release. 2015-08-18 11:17:51 +02:00
Vadim Shpakovski 1f3dbbce75 Merge pull request #71 from Stillness-2/master
Some fix
2015-08-10 02:44:50 +03:00
Roman Sokolov c98154e2c3 fix for keyboard navigation
Tab key must pass through. This is important if you want to do keyboard navigation through this control.
2015-08-09 21:55:03 +03:00
Roman Sokolov 5ead539397 Fix
Fix problem: 
Set hotkey [TheSameHOTKEY], then mousedown on delete button, then set hotkey again  [TheSameHOTKEY], then this hotkey do not work.
2015-08-09 21:27:19 +03:00
Tomáš Znamenáček 3f63f8fefc Merge pull request #69 from pfandrade/master
Not declaring MASShortcutGlyph as a variable in the header.

Prevents duplicate symbol errors.
2015-04-10 09:06:12 +02:00
Paulo F. Andrade dcb134242d Not declaring MASShortcutGlyph as a variable in the header 2015-04-09 20:20:36 +01:00
Tomáš Znamenáček 6c4577199c Namespaced the testing build scheme name (Tests → MASShortcutTests). 2015-03-09 14:32:38 +01:00
Tomáš Znamenáček 643e87c199 Updated CHANGES. 2015-03-09 14:15:32 +01:00
Vadim Shpakovski bc2c91fc94 Merge pull request #67 from brow/carthage
Support installation with Carthage
2015-03-09 15:37:05 +03:00
Tom Brow 7586157fe2 add Carthage compatibility flag to README 2015-03-08 15:17:58 -07:00
Tom Brow 4d3c2cad2c missing import? 2015-03-08 15:12:59 -07:00
Tom Brow d845d8cda9 module map 2015-03-08 15:12:27 -07:00
Tom Brow 2efd8d1dca DEFINES_MODULE = YES 2015-03-08 14:49:30 -07:00
Tomáš Znamenáček 7bbaed6227 Removed support for dots and spaces in user defaults keys (#64).
I could find no way to make the feature work, so I have pulled it
from the code. I have also inserted asserts to warn library users
who would attempt to use illegal characters in user defaults keys
in the future. In short, you want your user defaults keys to be
something identifier-like.
2015-03-05 14:32:51 +01:00
Tomáš Znamenáček fdc43c1cd3 Fix a problem with defaults keys with dot symbols (#64). 2015-03-05 10:59:01 +01:00
Tomáš Znamenáček a9e6e5241c Added a test case for a binder problem with dot symbols (#64). 2015-03-04 16:28:25 +01:00
Tomáš Znamenáček 67f4a5477b Trivial refactoring. 2015-03-04 16:15:47 +01:00
Tomáš Znamenáček a1eeb57ad6 Fix accessibility-related crashes on older OS X releases (#47).
The NSAccessibilityPriorityKey symbol was only introduced in 10.9,
so that we have to check for its availability before using it, otherwise
we get a SIGSEGV.
2015-03-04 16:07:46 +01:00
Tomáš Znamenáček 934abde616 Updated README and CHANGES. 2015-03-04 11:13:01 +01:00
Tomáš Znamenáček 00dd421e20 Merge pull request #66 from starkos/issue-47-accessibility
Add basic accessibility support.
2015-03-04 11:08:47 +01:00
Jason Perkins e2b2d5b9e1 Allow first responder support to be turned on and off 2015-02-16 10:22:22 -05:00
Jason Perkins 86d5b1ae49 Merge branch 'master' into issue-47-accessibility 2015-02-16 10:09:48 -05:00
Vadim Shpakovski 3ea350cec1 Merge pull request #65 from oreshinya/add_option_showing_delete_hotkey_button
Added options to show button that delete hot key.
2015-02-12 19:57:02 +03:00
shinya takahashi aeaad2986f Added options to show button that delete hot key. 2015-02-13 01:05:14 +09:00
Tomáš Znamenáček ef399290e4 Version bump to 2.1.2. 2015-01-28 16:11:36 +01:00
Tomáš Znamenáček 38fe428b19 Documented that keyCodeString depends on active keyboard layout. 2015-01-28 15:32:20 +01:00
Tomáš Znamenáček de647cf825 Talk about shortcut “formatting” instead of “rendering”. 2015-01-28 15:19:46 +01:00
Dmitry Obukhov 0db346d02b Better key equivalent handling on non-ASCII keyboard layouts.
See #60 for a discussion. In short, keyCodeStringForKeyEquivalent
should be now correct even with non-ASCII keyboard layouts such as
Russian.
2015-01-28 14:57:17 +01:00
Tomáš Znamenáček 0972882368 Clarified the spec part about rendering shortcuts. 2015-01-28 10:16:15 +01:00
Tomáš Znamenáček 72598e01af Added a note about shortcut rendering in the spec. 2015-01-28 10:13:53 +01:00
Tomáš Znamenáček 345da61b0d Added a short release guide. 2015-01-26 09:43:47 +01:00
Jason Perkins b564f5296a Enable control to become first responder 2015-01-21 07:36:08 -05:00
Jason Perkins 439ec69ab8 Fix "semicolon in method body" warning 2015-01-20 14:04:23 -05:00
Tomáš Znamenáček fd6885abdb Improved screenshot quality. 2015-01-19 15:47:35 +01:00
Tomáš Znamenáček 35e15f4950 Mentioned installation via Git submodules. 2015-01-19 15:37:14 +01:00
Tomáš Znamenáček fc1ec3eb41 Linked to the API documentation. 2015-01-19 15:32:23 +01:00
Tomáš Znamenáček bd0510c74d Smaller screenshot. 2015-01-19 15:28:31 +01:00
Tomáš Znamenáček 15dda682e4 Added a list of features and a screenshot of the demo project. 2015-01-19 15:27:36 +01:00
Tomáš Znamenáček 04987a7bd5 Version bump to 2.1.1. 2015-01-16 12:59:29 +01:00
Tomáš Znamenáček bf3a032c4b Decrease headerdoc indenting to appease appledoc (see #55).
I think I have finally found out the reason for CocoaDocs ignoring
our markup: I have indented the documentation by four spaces, which
was interpreted as “code” by appledoc. Trying now without the indent,
that should finally help.
2015-01-16 12:57:08 +01:00
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
Jason Perkins eda4bdb9c9 Add initial accessibility using 10.10 APIs 2015-01-14 12:23:22 -05: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
54 changed files with 2226 additions and 176 deletions
+3
View File
@@ -0,0 +1,3 @@
language: objective-c
xcode_project: MASShortcut.xcodeproj
xcode_scheme: MASShortcut
+39
View File
@@ -1,3 +1,42 @@
2.3.4 2016/8/12
- Simplified and traditional Chinese localization [MichaelRow]
- Add Korean, Dutch, Polish, Russian & update Spanish localizations [Radek Pietruszewski]
- Improved German localization [Florian Schliep]
Add a Makefile to improve command-line building [sfsam]
2.3.3 2016/1/9
- Improved Japanese localization [oreshinya]
- Improved Frech localization [magiclantern]
- Fixed CocoaPods localization with use_frameworks! [nivanchikov]
2.3.2 2015/10/12
- Fixed localization when building through CocoaPods [Allan Beaufour]
2.3.1 2015/9/10
- Trying to work around a strange build error in CocoaPods.
2.3.0 2015/9/10
- Basic localization support for Czech, German, Spanish,
Italian, French, and Japanese. Native speaking testers welcome!
2.2.0 2015/8/18
- Basic accessibility support [starkos]
- Added an option to hide the shortcut delete button [oreshinya]
- Advertised support for Carthage [Tom Brown]
- Bugfix for shortcuts not working after set twice [Roman Sokolov]
- Ignore a solo Tab key when recording shortcuts [Roman Sokolov]
2.1.2 2015/1/28
- Better key equivalent handling for non-ASCII layouts.
[Dmitry Obukhov]
2.1.1 2015/1/16
- Another headerdoc fix for CocoaDocs, hopefully the last one.
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.
+29
View File
@@ -0,0 +1,29 @@
# Backward Compatibility
Please note that this framework supports older OS X versions down to 10.6. When changing the code, be careful not to call any API functions not available in 10.6 or call them conditionally, only where supported.
# Commit Messages
Please use descriptive commit message. As an example, _Bug fix_ commit message doesnt say much, while _Fixed a memory-management bug in formatting code_ works much better.
# How to Release a New Version
First, update the version numbers. (MASShortcut uses [Semantic Versioning](http://semver.org/), so please read the docs if youre not sure what the deal is.) The version number is stored in `Framework/Info.plist` and `MASShortcut.podspec` (twice in both files).
Then update the `CHANGES` file. Add information about the new version (see the previous versions for an example) and add the release date.
Now commit the changes:
$ git commit -a -m "Version bump to x.y.z."
And tag the last commit:
$ git tag -a x.y.z
Now push both the commits and tags (`--tags`) to GitHub and push the new podspec to CocoaPods:
$ pod trunk push MASShortcut.podspec
This will run sanity checks on the podspec and fail if the spec does not validate.
Thats it. Go have a beer or a cup of tea to celebrate.
+3 -3
View File
@@ -43,10 +43,10 @@ static void *MASObservingContext = &MASObservingContext;
context:MASObservingContext];
}
- (void) playShortcutFeedback
- (void)playShortcutFeedback
{
[[NSSound soundNamed:@"Ping"] play];
[_feedbackTextField setStringValue:@"Shortcut pressed!"];
[_feedbackTextField setStringValue:NSLocalizedString(@"Shortcut pressed!", @"Feedback thats displayed when user presses the sample shortcut.")];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[_feedbackTextField setStringValue:@""];
});
@@ -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];
+1 -1
View File
@@ -7,7 +7,7 @@
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>com.shpakovski.mac.${PRODUCT_NAME:rfc1034identifier}</string>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
+3
View File
@@ -0,0 +1,3 @@
/* Feedback thats displayed when user presses the sample shortcut. */
"Shortcut pressed!" = "Funguje!";
+734
View File
@@ -0,0 +1,734 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="8173.3" systemVersion="14E46" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="8173.3"/>
</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" customClass="NSObject"/>
<menu title="AMainMenu" systemMenu="main" id="29">
<items>
<menuItem title="Demo" id="56">
<menu key="submenu" title="Demo" systemMenu="apple" id="57">
<items>
<menuItem title="About Demo" id="58">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="orderFrontStandardAboutPanel:" target="-2" id="142"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="236">
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
</menuItem>
<menuItem title="Preferences…" keyEquivalent="," id="129"/>
<menuItem isSeparatorItem="YES" id="143">
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
</menuItem>
<menuItem title="Services" id="131">
<menu key="submenu" title="Services" systemMenu="services" id="130"/>
</menuItem>
<menuItem isSeparatorItem="YES" id="144">
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
</menuItem>
<menuItem title="Hide Demo" 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 Demo" keyEquivalent="q" id="136">
<connections>
<action selector="terminate:" target="-3" id="449"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="File" id="83">
<menu key="submenu" title="File" id="81">
<items>
<menuItem title="New" keyEquivalent="n" id="82">
<connections>
<action selector="newDocument:" target="-1" id="373"/>
</connections>
</menuItem>
<menuItem title="Open…" keyEquivalent="o" id="72">
<connections>
<action selector="openDocument:" target="-1" id="374"/>
</connections>
</menuItem>
<menuItem title="Open Recent" id="124">
<menu key="submenu" title="Open Recent" systemMenu="recentDocuments" id="125">
<items>
<menuItem title="Clear Menu" id="126">
<connections>
<action selector="clearRecentDocuments:" target="-1" id="127"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem isSeparatorItem="YES" id="79">
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
</menuItem>
<menuItem title="Close" keyEquivalent="w" id="73">
<connections>
<action selector="performClose:" target="-1" id="193"/>
</connections>
</menuItem>
<menuItem title="Save…" keyEquivalent="s" id="75">
<connections>
<action selector="saveDocument:" target="-1" id="362"/>
</connections>
</menuItem>
<menuItem title="Revert to Saved" id="112">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="revertDocumentToSaved:" target="-1" id="364"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="74">
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
</menuItem>
<menuItem title="Page Setup..." keyEquivalent="P" id="77">
<modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
<connections>
<action selector="runPageLayout:" target="-1" id="87"/>
</connections>
</menuItem>
<menuItem title="Print…" keyEquivalent="p" id="78">
<connections>
<action selector="print:" target="-1" id="86"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Edit" id="217">
<menu key="submenu" title="Edit" id="205">
<items>
<menuItem title="Undo" keyEquivalent="z" id="207">
<connections>
<action selector="undo:" target="-1" id="223"/>
</connections>
</menuItem>
<menuItem title="Redo" keyEquivalent="Z" id="215">
<modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
<connections>
<action selector="redo:" target="-1" id="231"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="206">
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
</menuItem>
<menuItem title="Cut" keyEquivalent="x" id="199">
<connections>
<action selector="cut:" target="-1" id="228"/>
</connections>
</menuItem>
<menuItem title="Copy" keyEquivalent="c" id="197">
<connections>
<action selector="copy:" target="-1" id="224"/>
</connections>
</menuItem>
<menuItem title="Paste" keyEquivalent="v" id="203">
<connections>
<action selector="paste:" target="-1" id="226"/>
</connections>
</menuItem>
<menuItem title="Paste and Match Style" keyEquivalent="V" id="485">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="pasteAsPlainText:" target="-1" id="486"/>
</connections>
</menuItem>
<menuItem title="Delete" id="202">
<connections>
<action selector="delete:" target="-1" id="235"/>
</connections>
</menuItem>
<menuItem title="Select All" keyEquivalent="a" id="198">
<connections>
<action selector="selectAll:" target="-1" id="232"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="214">
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
</menuItem>
<menuItem title="Find" id="218">
<menu key="submenu" title="Find" id="220">
<items>
<menuItem title="Find…" tag="1" keyEquivalent="f" id="209">
<connections>
<action selector="performFindPanelAction:" target="-1" id="241"/>
</connections>
</menuItem>
<menuItem title="Find and Replace…" tag="12" keyEquivalent="f" id="534">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="performFindPanelAction:" target="-1" id="535"/>
</connections>
</menuItem>
<menuItem title="Find Next" tag="2" keyEquivalent="g" id="208">
<connections>
<action selector="performFindPanelAction:" target="-1" id="487"/>
</connections>
</menuItem>
<menuItem title="Find Previous" tag="3" keyEquivalent="G" id="213">
<modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
<connections>
<action selector="performFindPanelAction:" target="-1" id="488"/>
</connections>
</menuItem>
<menuItem title="Use Selection for Find" tag="7" keyEquivalent="e" id="221">
<connections>
<action selector="performFindPanelAction:" target="-1" id="489"/>
</connections>
</menuItem>
<menuItem title="Jump to Selection" keyEquivalent="j" id="210">
<connections>
<action selector="centerSelectionInVisibleArea:" target="-1" id="245"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Spelling and Grammar" id="216">
<menu key="submenu" title="Spelling and Grammar" id="200">
<items>
<menuItem title="Show Spelling and Grammar" keyEquivalent=":" id="204">
<connections>
<action selector="showGuessPanel:" target="-1" id="230"/>
</connections>
</menuItem>
<menuItem title="Check Document Now" keyEquivalent=";" id="201">
<connections>
<action selector="checkSpelling:" target="-1" id="225"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="453"/>
<menuItem title="Check Spelling While Typing" id="219">
<connections>
<action selector="toggleContinuousSpellChecking:" target="-1" id="222"/>
</connections>
</menuItem>
<menuItem title="Check Grammar With Spelling" id="346">
<connections>
<action selector="toggleGrammarChecking:" target="-1" id="347"/>
</connections>
</menuItem>
<menuItem title="Correct Spelling Automatically" id="454">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticSpellingCorrection:" target="-1" id="456"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Substitutions" id="348">
<menu key="submenu" title="Substitutions" id="349">
<items>
<menuItem title="Show Substitutions" id="457">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="orderFrontSubstitutionsPanel:" target="-1" id="458"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="459"/>
<menuItem title="Smart Copy/Paste" tag="1" keyEquivalent="f" id="350">
<connections>
<action selector="toggleSmartInsertDelete:" target="-1" id="355"/>
</connections>
</menuItem>
<menuItem title="Smart Quotes" tag="2" keyEquivalent="g" id="351">
<connections>
<action selector="toggleAutomaticQuoteSubstitution:" target="-1" id="356"/>
</connections>
</menuItem>
<menuItem title="Smart Dashes" id="460">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticDashSubstitution:" target="-1" id="461"/>
</connections>
</menuItem>
<menuItem title="Smart Links" tag="3" keyEquivalent="G" id="354">
<modifierMask key="keyEquivalentModifierMask" shift="YES" command="YES"/>
<connections>
<action selector="toggleAutomaticLinkDetection:" target="-1" id="357"/>
</connections>
</menuItem>
<menuItem title="Text Replacement" id="462">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleAutomaticTextReplacement:" target="-1" id="463"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Transformations" id="450">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Transformations" id="451">
<items>
<menuItem title="Make Upper Case" id="452">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="uppercaseWord:" target="-1" id="464"/>
</connections>
</menuItem>
<menuItem title="Make Lower Case" id="465">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="lowercaseWord:" target="-1" id="468"/>
</connections>
</menuItem>
<menuItem title="Capitalize" id="466">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="capitalizeWord:" target="-1" id="467"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Speech" id="211">
<menu key="submenu" title="Speech" id="212">
<items>
<menuItem title="Start Speaking" id="196">
<connections>
<action selector="startSpeaking:" target="-1" id="233"/>
</connections>
</menuItem>
<menuItem title="Stop Speaking" id="195">
<connections>
<action selector="stopSpeaking:" target="-1" id="227"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Format" id="375">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Format" id="376">
<items>
<menuItem title="Font" id="377">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Font" systemMenu="font" id="388">
<items>
<menuItem title="Show Fonts" keyEquivalent="t" id="389">
<connections>
<action selector="orderFrontFontPanel:" target="420" id="424"/>
</connections>
</menuItem>
<menuItem title="Bold" tag="2" keyEquivalent="b" id="390">
<connections>
<action selector="addFontTrait:" target="420" id="421"/>
</connections>
</menuItem>
<menuItem title="Italic" tag="1" keyEquivalent="i" id="391">
<connections>
<action selector="addFontTrait:" target="420" id="422"/>
</connections>
</menuItem>
<menuItem title="Underline" keyEquivalent="u" id="392">
<connections>
<action selector="underline:" target="-1" id="432"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="393"/>
<menuItem title="Bigger" tag="3" keyEquivalent="+" id="394">
<connections>
<action selector="modifyFont:" target="420" id="425"/>
</connections>
</menuItem>
<menuItem title="Smaller" tag="4" keyEquivalent="-" id="395">
<connections>
<action selector="modifyFont:" target="420" id="423"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="396"/>
<menuItem title="Kern" id="397">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Kern" id="415">
<items>
<menuItem title="Use Default" id="416">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="useStandardKerning:" target="-1" id="438"/>
</connections>
</menuItem>
<menuItem title="Use None" id="417">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="turnOffKerning:" target="-1" id="441"/>
</connections>
</menuItem>
<menuItem title="Tighten" id="418">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="tightenKerning:" target="-1" id="431"/>
</connections>
</menuItem>
<menuItem title="Loosen" id="419">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="loosenKerning:" target="-1" id="435"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Ligatures" id="398">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Ligatures" id="411">
<items>
<menuItem title="Use Default" id="412">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="useStandardLigatures:" target="-1" id="439"/>
</connections>
</menuItem>
<menuItem title="Use None" id="413">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="turnOffLigatures:" target="-1" id="440"/>
</connections>
</menuItem>
<menuItem title="Use All" id="414">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="useAllLigatures:" target="-1" id="434"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Baseline" id="399">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Baseline" id="405">
<items>
<menuItem title="Use Default" id="406">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="unscript:" target="-1" id="437"/>
</connections>
</menuItem>
<menuItem title="Superscript" id="407">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="superscript:" target="-1" id="430"/>
</connections>
</menuItem>
<menuItem title="Subscript" id="408">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="subscript:" target="-1" id="429"/>
</connections>
</menuItem>
<menuItem title="Raise" id="409">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="raiseBaseline:" target="-1" id="426"/>
</connections>
</menuItem>
<menuItem title="Lower" id="410">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="lowerBaseline:" target="-1" id="427"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem isSeparatorItem="YES" id="400"/>
<menuItem title="Show Colors" keyEquivalent="C" id="401">
<connections>
<action selector="orderFrontColorPanel:" target="-1" id="433"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="402"/>
<menuItem title="Copy Style" keyEquivalent="c" id="403">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="copyFont:" target="-1" id="428"/>
</connections>
</menuItem>
<menuItem title="Paste Style" keyEquivalent="v" id="404">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="pasteFont:" target="-1" id="436"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Text" id="496">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Text" id="497">
<items>
<menuItem title="Align Left" keyEquivalent="{" id="498">
<connections>
<action selector="alignLeft:" target="-1" id="524"/>
</connections>
</menuItem>
<menuItem title="Center" keyEquivalent="|" id="499">
<connections>
<action selector="alignCenter:" target="-1" id="518"/>
</connections>
</menuItem>
<menuItem title="Justify" id="500">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="alignJustified:" target="-1" id="523"/>
</connections>
</menuItem>
<menuItem title="Align Right" keyEquivalent="}" id="501">
<connections>
<action selector="alignRight:" target="-1" id="521"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="502"/>
<menuItem title="Writing Direction" id="503">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Writing Direction" id="508">
<items>
<menuItem title="Paragraph" enabled="NO" id="509">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem id="510">
<string key="title"> Default</string>
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="makeBaseWritingDirectionNatural:" target="-1" id="525"/>
</connections>
</menuItem>
<menuItem id="511">
<string key="title"> Left to Right</string>
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="makeBaseWritingDirectionLeftToRight:" target="-1" id="526"/>
</connections>
</menuItem>
<menuItem id="512">
<string key="title"> Right to Left</string>
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="makeBaseWritingDirectionRightToLeft:" target="-1" id="527"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="513"/>
<menuItem title="Selection" enabled="NO" id="514">
<modifierMask key="keyEquivalentModifierMask"/>
</menuItem>
<menuItem id="515">
<string key="title"> Default</string>
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="makeTextWritingDirectionNatural:" target="-1" id="528"/>
</connections>
</menuItem>
<menuItem id="516">
<string key="title"> Left to Right</string>
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="makeTextWritingDirectionLeftToRight:" target="-1" id="529"/>
</connections>
</menuItem>
<menuItem id="517">
<string key="title"> Right to Left</string>
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="makeTextWritingDirectionRightToLeft:" target="-1" id="530"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem isSeparatorItem="YES" id="504"/>
<menuItem title="Show Ruler" id="505">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="toggleRuler:" target="-1" id="520"/>
</connections>
</menuItem>
<menuItem title="Copy Ruler" keyEquivalent="c" id="506">
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
<connections>
<action selector="copyRuler:" target="-1" id="522"/>
</connections>
</menuItem>
<menuItem title="Paste Ruler" keyEquivalent="v" id="507">
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
<connections>
<action selector="pasteRuler:" target="-1" id="519"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="View" id="295">
<menu key="submenu" title="View" id="296">
<items>
<menuItem title="Show Toolbar" keyEquivalent="t" id="297">
<modifierMask key="keyEquivalentModifierMask" option="YES" command="YES"/>
<connections>
<action selector="toggleToolbarShown:" target="-1" id="366"/>
</connections>
</menuItem>
<menuItem title="Customize Toolbar…" id="298">
<connections>
<action selector="runToolbarCustomizationPalette:" target="-1" id="365"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Window" id="19">
<menu key="submenu" title="Window" systemMenu="window" id="24">
<items>
<menuItem title="Minimize" keyEquivalent="m" id="23">
<connections>
<action selector="performMiniaturize:" target="-1" id="37"/>
</connections>
</menuItem>
<menuItem title="Zoom" id="239">
<connections>
<action selector="performZoom:" target="-1" id="240"/>
</connections>
</menuItem>
<menuItem isSeparatorItem="YES" id="92">
<modifierMask key="keyEquivalentModifierMask" command="YES"/>
</menuItem>
<menuItem title="Bring All to Front" id="5">
<connections>
<action selector="arrangeInFront:" target="-1" id="39"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
<menuItem title="Help" id="490">
<modifierMask key="keyEquivalentModifierMask"/>
<menu key="submenu" title="Help" systemMenu="help" id="491">
<items>
<menuItem title="Demo Help" keyEquivalent="?" id="492">
<connections>
<action selector="showHelp:" target="-1" id="493"/>
</connections>
</menuItem>
</items>
</menu>
</menuItem>
</items>
</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="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="393" height="129"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<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" id="PG0-jh-Onh">
<rect key="frame" x="9" y="92" width="120" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="right" title="Klávesová zkratka:" 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 id="zCi-ki-Uuh">
<rect key="frame" x="140" y="63" width="196" height="18"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="check" title="Zapnout klávesovou zkratku" 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"/>
</buttonCell>
<connections>
<binding destination="rCO-Ve-DT5" name="value" keyPath="values.customShortcutEnabled" id="VjS-3V-VdA"/>
</connections>
</button>
<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="Předvolby:" 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 id="F4r-KM-wn9">
<rect key="frame" x="140" y="43" width="237" height="18"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="check" title="Zapnout vestavěnou zkratku (⌘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>
<connections>
<binding destination="rCO-Ve-DT5" name="value" keyPath="values.hardcodedShortcutEnabled" id="dlZ-si-HeN"/>
</connections>
</button>
<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="Zkratka v akci:" 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" 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="stiskněte klávesovou zkratku" id="Ckx-v7-e6x">
<font key="font" metaFont="system"/>
<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="6.5" y="248.5"/>
</window>
<customObject id="494" customClass="AppDelegate">
<connections>
<outlet property="customShortcutView" destination="536" id="aO6-hh-1vm"/>
<outlet property="feedbackTextField" destination="Aso-dH-W8I" id="hk8-xL-ieC"/>
<outlet property="window" destination="371" id="532"/>
</connections>
</customObject>
<customObject id="420" customClass="NSFontManager"/>
<userDefaultsController representsSharedInstance="YES" id="rCO-Ve-DT5"/>
</objects>
</document>
+3
View File
@@ -0,0 +1,3 @@
/* Feedback thats displayed when user presses the sample shortcut. */
"Shortcut pressed!" = "Kurzbefehl gedrückt!";
+3
View File
@@ -0,0 +1,3 @@
/* Feedback thats displayed when user presses the sample shortcut. */
"Shortcut pressed!" = "Shortcut pressed!";
@@ -1,8 +1,8 @@
<?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="8173.3" systemVersion="14E46" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="6254"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="8173.3"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
@@ -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>
+3
View File
@@ -0,0 +1,3 @@
/* Feedback thats displayed when user presses the sample shortcut. */
"Shortcut pressed!" = "ショートカットが押されました!";
Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

+4 -4
View File
@@ -7,7 +7,7 @@
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>com.github.shpakovski.${PRODUCT_NAME:rfc1034identifier}</string>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
@@ -15,10 +15,10 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>2.0.0</string>
<string>2.3.4</string>
<key>CFBundleVersion</key>
<string>2.0.0</string>
<string>2.3.4</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 20142015 Vadim Shpakovski. All rights reserved.</string>
<string>Copyright © Vadim Shpakovski. All rights reserved.</string>
</dict>
</plist>
+11 -11
View File
@@ -1,19 +1,19 @@
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
using value transformers like this one.
User defaults cant stored custom types directly, they have to
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
it makes sense to use a dictionary instead the defaults look better
when inspected with the @p defaults command-line utility and the
format is compatible with an older sortcut library called Shortcut
Recorder.
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 `defaults` command-line utility and the
format is compatible with an older sortcut library called Shortcut
Recorder.
*/
@interface MASDictionaryTransformer : NSValueTransformer
@end
+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
+2 -1
View File
@@ -1,4 +1,5 @@
#import <Carbon/Carbon.h>
#import <AppKit/AppKit.h>
// These glyphs are missed in Carbon.h
enum {
@@ -20,7 +21,7 @@ enum {
kMASShortcutGlyphPadClear = 0x2327,
kMASShortcutGlyphNorthwestArrow = 0x2196,
kMASShortcutGlyphSoutheastArrow = 0x2198,
} MASShortcutGlyph;
};
NS_INLINE NSString* NSStringFromMASKeyCode(unsigned short ch)
{
+13
View File
@@ -0,0 +1,13 @@
/**
Reads a localized string from the frameworks bundle.
Normally you would use NSLocalizedString to read the localized
strings, but thats just a shortcut for loading the strings from
the main bundle. And once the framework ends up in an app, the
main bundle will be the apps bundle and wont contain our strings.
So we introduced this helper function that makes sure to load the
strings from the frameworks bundle. Please avoid using
NSLocalizedString throughout the framework, it wouldnt work
properly.
*/
NSString *MASLocalizedString(NSString *key, NSString *comment);
+34
View File
@@ -0,0 +1,34 @@
#import "MASLocalization.h"
#import "MASShortcut.h"
static NSString *const MASLocalizationTableName = @"Localizable";
static NSString *const MASPlaceholderLocalizationString = @"XXX";
// The CocoaPods trickery here is needed because when the code
// is built as a part of CocoaPods, it wont make a separate framework
// and the Localized.strings file wont be bundled correctly.
// See https://github.com/shpakovski/MASShortcut/issues/74
NSString *MASLocalizedString(NSString *key, NSString *comment) {
static NSBundle *localizationBundle = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSBundle *frameworkBundle = [NSBundle bundleForClass:[MASShortcut class]];
// first we'll check if resources bundle was copied to MASShortcut framework bundle when !use_frameworks option is active
NSURL *cocoaPodsBundleURL = [frameworkBundle URLForResource:@"MASShortcut" withExtension:@"bundle"];
if (cocoaPodsBundleURL) {
localizationBundle = [NSBundle bundleWithURL: cocoaPodsBundleURL];
} else {
// trying to fetch cocoapods bundle from main bundle
cocoaPodsBundleURL = [[NSBundle mainBundle] URLForResource: @"MASShortcut" withExtension:@"bundle"];
if (cocoaPodsBundleURL) {
localizationBundle = [NSBundle bundleWithURL: cocoaPodsBundleURL];
} else {
// fallback to framework bundle
localizationBundle = frameworkBundle;
}
}
});
return [localizationBundle localizedStringForKey:key
value:MASPlaceholderLocalizationString
table:MASLocalizationTableName];
}
+33 -22
View File
@@ -1,59 +1,70 @@
#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
the input system for the shortcut appearance, nor it does access user
defaults.
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
the input system for the shortcut appearance, nor it does access user
defaults.
*/
@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`.
@warning The value may change depending on the active keyboard layout.
For example for the `^2` keyboard shortcut (`kVK_ANSI_2+NSControlKeyMask`
to be precise) the `keyCodeString` is `2` on the US keyboard, but `ě` when
the Czech keyboard layout is active. See the spec for details.
*/
@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
validation (“is the shortcut already taken in this menu?”) and
for display in @p NSMenu.
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 `NSMenu`.
The value of this property may differ from `keyCodeString`. For example
the Russian keyboard has a `Г` (Ge) Cyrillic character in place of the
latin `U` key. This means you can create a `^Г` shortcut, but in menus
thats always displayed as `^U`. So the `keyCodeString` returns `Г`
and `keyCodeStringForKeyEquivalent` returns `U`.
*/
@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 +72,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;
+4 -3
View File
@@ -1,4 +1,5 @@
#import "MASShortcut.h"
#import "MASLocalization.h"
static NSString *const MASShortcutKeyCode = @"KeyCode";
static NSString *const MASShortcutModifierFlags = @"ModifierFlags";
@@ -100,7 +101,7 @@ static NSString *const MASShortcutModifierFlags = @"ModifierFlags";
case kVK_F17: return @"F17";
case kVK_F18: return @"F18";
case kVK_F19: return @"F19";
case kVK_Space: return NSLocalizedString(@"Space", @"Shortcut glyph name for SPACE key");
case kVK_Space: return MASLocalizedString(@"Space", @"Shortcut glyph name for SPACE key");
case kVK_Escape: return NSStringFromMASKeyCode(kMASShortcutGlyphEscape);
case kVK_Delete: return NSStringFromMASKeyCode(kMASShortcutGlyphDeleteLeft);
case kVK_ForwardDelete: return NSStringFromMASKeyCode(kMASShortcutGlyphDeleteRight);
@@ -139,10 +140,10 @@ static NSString *const MASShortcutModifierFlags = @"ModifierFlags";
case 115: return NSStringFromMASKeyCode(kMASShortcutGlyphNorthwestArrow);
}
// Everything else should be printable so look it up in the current keyboard
// Everything else should be printable so look it up in the current ASCII capable keyboard layout
OSStatus error = noErr;
NSString *keystroke = nil;
TISInputSourceRef inputSource = TISCopyCurrentKeyboardLayoutInputSource();
TISInputSourceRef inputSource = TISCopyCurrentASCIICapableKeyboardLayoutInputSource();
if (inputSource) {
CFDataRef layoutDataRef = TISGetInputSourceProperty(inputSource, kTISPropertyUnicodeKeyLayoutData);
if (layoutDataRef) {
+6
View File
@@ -0,0 +1,6 @@
framework module MASShortcut {
umbrella header "Shortcut.h"
export *
module * { export * }
}
+29 -29
View File
@@ -1,66 +1,66 @@
#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
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.
If you store shortcuts in user defaults (for example by binding
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
watches the changes in user defaults and updates the shortcut monitor
accordingly with the new shortcuts.
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.
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.
*/
+ (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
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
format.
As an example, you can use `NSValueTransformerNameBindingOption` to customize
the storage format used for the shortcuts. By default the shortcuts are converted
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.
In other words, no matter what shortcut you store under the given key,
pressing it will always trigger the given action.
*/
- (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.
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].
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.
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
`bindingOptions` and registered using `registerDefaults`.
*/
- (void) registerDefaultShortcuts: (NSDictionary*) defaultShortcuts;
+9 -2
View File
@@ -41,9 +41,15 @@
- (void) bindShortcutWithDefaultsKey: (NSString*) defaultsKeyName toAction: (dispatch_block_t) action
{
NSAssert([defaultsKeyName rangeOfString:@"."].location == NSNotFound,
@"Illegal character in binding name (“.”), please see http://git.io/x5YS.");
NSAssert([defaultsKeyName rangeOfString:@" "].location == NSNotFound,
@"Illegal character in binding name (“ ”), please see http://git.io/x5YS.");
[_actions setObject:[action copy] forKey:defaultsKeyName];
[self bind:defaultsKeyName toObject:[NSUserDefaultsController sharedUserDefaultsController]
withKeyPath:[@"values." stringByAppendingString:defaultsKeyName] options:_bindingOptions];
[self bind:defaultsKeyName
toObject:[NSUserDefaultsController sharedUserDefaultsController]
withKeyPath:[@"values." stringByAppendingString:defaultsKeyName]
options:_bindingOptions];
}
- (void) breakBindingWithDefaultsKey: (NSString*) defaultsKeyName
@@ -103,6 +109,7 @@
// Just deleting the old shortcut
if (newShortcut == nil) {
[_shortcuts removeObjectForKey:key];
return;
}
+9
View File
@@ -95,4 +95,13 @@ static NSString *const SampleDefaultsKey = @"sampleShortcut";
@"Bind shortcut using a default value.");
}
// See issue #64 <http://git.io/x5YS> for rationale and discussion.
- (void) testIllegalSymbolsInBindingNames
{
XCTAssertThrows([_binder bindShortcutWithDefaultsKey:@"foo.bar" toAction:^{}],
@"Throw for illegal binding symbols: a dot (“.”).");
XCTAssertThrows([_binder bindShortcutWithDefaultsKey:@"foo bar" toAction:^{}],
@"Throw for illegal binding symbols: a space (“ ”).");
}
@end
+8 -8
View File
@@ -1,11 +1,11 @@
#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
and there can only be one Carbon event handler of a given type.)
There can only be one instance of this class, otherwise things
will probably not work. (Theres a Carbon event handler inside
and there can only be one Carbon event handler of a given type.)
*/
@interface MASShortcutMonitor : NSObject
@@ -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.
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
+16 -2
View File
@@ -1,9 +1,23 @@
#import "MASShortcut.h"
/**
This class is used by the recording control to tell which shortcuts are acceptable.
There are two kinds of shortcuts that are not considered acceptable: shortcuts that
are too simple (like single letter keys) and shortcuts that are already used by the
operating system.
*/
@interface MASShortcutValidator : NSObject
// The following API enable hotkeys with the Option key as the only modifier
// For example, Option-G will not generate © and Option-R will not paste ®
/**
Set to `YES` if you want to accept Option-something shortcuts.
`NO` by default, since Option-something shortcuts are often used by system,
for example Option-G will type the © sign. This also applies to Option-Shift
shortcuts in other words, shortcut recorder will not accept shortcuts like
Option-Shift-K by default. (Again, since Option-Shift-K inserts the Apple
logo sign by default.)
*/
@property(assign) BOOL allowAnyShortcutWithOptionModifier;
+ (instancetype) sharedValidator;
+3 -2
View File
@@ -1,4 +1,5 @@
#import "MASShortcutValidator.h"
#import "MASLocalization.h"
@implementation MASShortcutValidator
@@ -68,7 +69,7 @@
if (equalFlags && equalHotkeyLowercase) {
if (explanation) {
*explanation = NSLocalizedString(@"This shortcut cannot be used because it is already used by the menu item %@.",
*explanation = MASLocalizedString(@"This shortcut cannot be used because it is already used by the menu item %@.",
@"Message for alert when shortcut is already used");
*explanation = [NSString stringWithFormat:*explanation, menuItem.title];
}
@@ -95,7 +96,7 @@
([(__bridge NSNumber *)enabled boolValue])) {
if (explanation) {
*explanation = NSLocalizedString(@"This combination cannot be used because it is already used by a system-wide "
*explanation = MASLocalizedString(@"This combination cannot be used because it is already used by a system-wide "
@"keyboard shortcut.\nIf you really want to use this key combination, most shortcuts "
@"can be changed in the Keyboard & Mouse panel in System Preferences.",
@"Message for alert when shortcut is already used by the system");
+10 -10
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
and read, heres a simpler option.
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
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
automatically.
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 `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)
+2
View File
@@ -21,4 +21,6 @@ typedef enum {
/// Returns custom class for drawing control.
+ (Class)shortcutCellClass;
- (void)setAcceptsFirstResponder:(BOOL)value;
@end
+134 -30
View File
@@ -1,11 +1,11 @@
#import "MASShortcutView.h"
#import "MASShortcutValidator.h"
#import "MASLocalization.h"
NSString *const MASShortcutBinding = @"shortcutValue";
#define HINT_BUTTON_WIDTH 23.0
#define BUTTON_FONT_SIZE 11.0
#define SEGMENT_CHROME_WIDTH 6.0
static const CGFloat MASHintButtonWidth = 23;
static const CGFloat MASButtonFontSize = 11;
#pragma mark -
@@ -13,6 +13,7 @@ NSString *const MASShortcutBinding = @"shortcutValue";
@property (nonatomic, getter = isHinting) BOOL hinting;
@property (nonatomic, copy) NSString *shortcutPlaceholder;
@property (nonatomic, assign) BOOL showsDeleteButton;
@end
@@ -23,6 +24,7 @@ NSString *const MASShortcutBinding = @"shortcutValue";
NSInteger _shortcutToolTipTag;
NSInteger _hintToolTipTag;
NSTrackingArea *_hintArea;
BOOL _acceptsFirstResponder;
}
#pragma mark -
@@ -54,9 +56,11 @@ NSString *const MASShortcutBinding = @"shortcutValue";
{
_shortcutCell = [[[self.class shortcutCellClass] alloc] init];
_shortcutCell.buttonType = NSPushOnPushOffButton;
_shortcutCell.font = [[NSFontManager sharedFontManager] convertFont:_shortcutCell.font toSize:BUTTON_FONT_SIZE];
_shortcutCell.font = [[NSFontManager sharedFontManager] convertFont:_shortcutCell.font toSize:MASButtonFontSize];
_shortcutValidator = [MASShortcutValidator sharedValidator];
_enabled = YES;
_showsDeleteButton = YES;
_acceptsFirstResponder = NO;
[self resetShortcutCellStyle];
}
@@ -122,15 +126,35 @@ NSString *const MASShortcutBinding = @"shortcutValue";
// Only enabled view supports recording
if (flag && !self.enabled) return;
if (_recording != flag) {
_recording = flag;
self.shortcutPlaceholder = nil;
[self resetToolTips];
[self activateEventMonitoring:_recording];
[self activateResignObserver:_recording];
[self setNeedsDisplay:YES];
// Only care about changes in state
if (flag == _recording) return;
_recording = flag;
self.shortcutPlaceholder = nil;
[self resetToolTips];
[self activateEventMonitoring:_recording];
[self activateResignObserver:_recording];
[self setNeedsDisplay:YES];
// Give VoiceOver users feedback on the result. Requires at least 10.9 to run.
// Were silencing the “tautological compare” warning here so that if someone
// takes the naked source files and compiles them with -Wall, the following
// NSAccessibilityPriorityKey comparison doesnt cause a warning. See:
// https://github.com/shpakovski/MASShortcut/issues/76
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wtautological-compare"
if (_recording == NO && (&NSAccessibilityPriorityKey != NULL)) {
NSString* msg = _shortcutValue ?
MASLocalizedString(@"Shortcut set", @"VoiceOver: Shortcut set") :
MASLocalizedString(@"Shortcut cleared", @"VoiceOver: Shortcut cleared");
NSDictionary *announcementInfo = @{
NSAccessibilityAnnouncementKey : msg,
NSAccessibilityPriorityKey : @(NSAccessibilityPriorityHigh),
};
NSAccessibilityPostNotificationWithUserInfo(self, NSAccessibilityAnnouncementRequestedNotification, announcementInfo);
}
#pragma clang diagnostic pop
}
- (void)setShortcutValue:(MASShortcut *)shortcutValue
@@ -138,7 +162,7 @@ NSString *const MASShortcutBinding = @"shortcutValue";
_shortcutValue = shortcutValue;
[self resetToolTips];
[self setNeedsDisplay:YES];
[self propagateValue:shortcutValue forBinding:@"shortcutValue"];
[self propagateValue:shortcutValue forBinding:MASShortcutBinding];
if (self.shortcutValueChange) {
self.shortcutValueChange(self);
@@ -188,17 +212,23 @@ NSString *const MASShortcutBinding = @"shortcutValue";
- (void)drawRect:(CGRect)dirtyRect
{
if (self.shortcutValue) {
[self drawInRect:self.bounds withTitle:NSStringFromMASKeyCode(self.recording ? kMASShortcutGlyphEscape : kMASShortcutGlyphDeleteLeft)
alignment:NSRightTextAlignment state:NSOffState];
NSString *buttonTitle;
if (self.recording) {
buttonTitle = NSStringFromMASKeyCode(kMASShortcutGlyphEscape);
} else if (self.showsDeleteButton) {
buttonTitle = NSStringFromMASKeyCode(kMASShortcutGlyphClear);
}
if (buttonTitle != nil) {
[self drawInRect:self.bounds withTitle:buttonTitle alignment:NSRightTextAlignment state:NSOffState];
}
CGRect shortcutRect;
[self getShortcutRect:&shortcutRect hintRect:NULL];
NSString *title = (self.recording
? (_hinting
? NSLocalizedString(@"Use Old Shortcut", @"Cancel action button for non-empty shortcut in recording state")
? MASLocalizedString(@"Use Old Shortcut", @"Cancel action button for non-empty shortcut in recording state")
: (self.shortcutPlaceholder.length > 0
? self.shortcutPlaceholder
: NSLocalizedString(@"Type New Shortcut", @"Non-empty shortcut button in recording state")))
: MASLocalizedString(@"Type New Shortcut", @"Non-empty shortcut button in recording state")))
: _shortcutValue ? _shortcutValue.description : @"");
[self drawInRect:shortcutRect withTitle:title alignment:NSCenterTextAlignment state:self.isRecording ? NSOnState : NSOffState];
}
@@ -210,15 +240,15 @@ NSString *const MASShortcutBinding = @"shortcutValue";
CGRect shortcutRect;
[self getShortcutRect:&shortcutRect hintRect:NULL];
NSString *title = (_hinting
? NSLocalizedString(@"Cancel", @"Cancel action button in recording state")
? MASLocalizedString(@"Cancel", @"Cancel action button in recording state")
: (self.shortcutPlaceholder.length > 0
? self.shortcutPlaceholder
: NSLocalizedString(@"Type Shortcut", @"Empty shortcut button in recording state")));
: MASLocalizedString(@"Type Shortcut", @"Empty shortcut button in recording state")));
[self drawInRect:shortcutRect withTitle:title alignment:NSCenterTextAlignment state:NSOnState];
}
else
{
[self drawInRect:self.bounds withTitle:NSLocalizedString(@"Record Shortcut", @"Empty shortcut button in normal state")
[self drawInRect:self.bounds withTitle:MASLocalizedString(@"Record Shortcut", @"Empty shortcut button in normal state")
alignment:NSCenterTextAlignment state:NSOffState];
}
}
@@ -229,11 +259,11 @@ NSString *const MASShortcutBinding = @"shortcutValue";
- (void)getShortcutRect:(CGRect *)shortcutRectRef hintRect:(CGRect *)hintRectRef
{
CGRect shortcutRect, hintRect;
CGFloat hintButtonWidth = HINT_BUTTON_WIDTH;
CGFloat hintButtonWidth = MASHintButtonWidth;
switch (self.style) {
case MASShortcutViewStyleTexturedRect: hintButtonWidth += 2.0; break;
case MASShortcutViewStyleRounded: hintButtonWidth += 3.0; break;
case MASShortcutViewStyleFlat: hintButtonWidth -= 8.0 - (_shortcutCell.font.pointSize - BUTTON_FONT_SIZE); break;
case MASShortcutViewStyleFlat: hintButtonWidth -= 8.0 - (_shortcutCell.font.pointSize - MASButtonFontSize); break;
default: break;
}
CGRectDivide(self.bounds, &hintRect, &shortcutRect, hintButtonWidth, CGRectMaxXEdge);
@@ -351,10 +381,10 @@ void *kUserDataHint = &kUserDataHint;
- (NSString *)view:(NSView *)view stringForToolTip:(NSToolTipTag)tag point:(CGPoint)point userData:(void *)data
{
if (data == kUserDataShortcut) {
return NSLocalizedString(@"Click to record new shortcut", @"Tooltip for non-empty shortcut button");
return MASLocalizedString(@"Click to record new shortcut", @"Tooltip for non-empty shortcut button");
}
else if (data == kUserDataHint) {
return NSLocalizedString(@"Delete shortcut", @"Tooltip for hint button near the non-empty shortcut");
return MASLocalizedString(@"Delete shortcut", @"Tooltip for hint button near the non-empty shortcut");
}
return nil;
}
@@ -369,13 +399,18 @@ 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) {
// Create a shortcut from the event
MASShortcut *shortcut = [MASShortcut shortcutWithEvent:event];
// Tab key must pass through.
if (shortcut.keyCode == kVK_Tab){
return event;
}
// If the shortcut is a plain Delete or Backspace, clear the current shortcut and cancel recording
if (!shortcut.modifierFlags && ((shortcut.keyCode == kVK_Delete) || (shortcut.keyCode == kVK_ForwardDelete))) {
weakSelf.shortcutValue = nil;
@@ -404,13 +439,13 @@ void *kUserDataHint = &kUserDataHint;
// Prevent cancel of recording when Alert window is key
[weakSelf activateResignObserver:NO];
[weakSelf activateEventMonitoring:NO];
NSString *format = NSLocalizedString(@"The key combination %@ cannot be used",
NSString *format = MASLocalizedString(@"The key combination %@ cannot be used",
@"Title for alert when shortcut is already used");
NSAlert* alert = [[NSAlert alloc]init];
alert.alertStyle = NSCriticalAlertStyle;
alert.informativeText = explanation;
alert.messageText = [NSString stringWithFormat:format, shortcut];
[alert addButtonWithTitle:NSLocalizedString(@"OK", @"Alert button when shortcut is already used")];
[alert addButtonWithTitle:MASLocalizedString(@"OK", @"Alert button when shortcut is already used")];
[alert runModal];
weakSelf.shortcutPlaceholder = nil;
@@ -450,7 +485,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;
@@ -464,7 +499,7 @@ void *kUserDataHint = &kUserDataHint;
#pragma mark Bindings
// http://tomdalling.com/blog/cocoa/implementing-your-own-cocoa-bindings/
-(void) propagateValue:(id)value forBinding:(NSString*)binding;
-(void) propagateValue:(id)value forBinding:(NSString*)binding
{
NSParameterAssert(binding != nil);
@@ -508,4 +543,73 @@ void *kUserDataHint = &kUserDataHint;
[boundObject setValue:value forKeyPath:boundKeyPath];
}
#pragma mark - Accessibility
- (BOOL)accessibilityIsIgnored
{
return NO;
}
- (NSString *)accessibilityHelp
{
return MASLocalizedString(@"To record a new shortcut, click this button, and then type the"
@" new shortcut, or press delete to clear an existing shortcut.",
@"VoiceOver shortcut help");
}
- (NSString *)accessibilityLabel
{
NSString* title = _shortcutValue.description ?: @"Empty";
title = [title stringByAppendingFormat:@" %@", MASLocalizedString(@"keyboard shortcut", @"VoiceOver title")];
return title;
}
- (BOOL)accessibilityPerformPress
{
if (self.isRecording == NO) {
self.recording = YES;
return YES;
}
else {
return NO;
}
}
- (NSString *)accessibilityRole
{
return NSAccessibilityButtonRole;
}
- (BOOL)acceptsFirstResponder
{
return _acceptsFirstResponder;
}
- (void)setAcceptsFirstResponder:(BOOL)value
{
_acceptsFirstResponder = value;
}
- (BOOL)becomeFirstResponder
{
[self setNeedsDisplay:YES];
return [super becomeFirstResponder];
}
- (BOOL)resignFirstResponder
{
[self setNeedsDisplay:YES];
return [super resignFirstResponder];
}
- (void)drawFocusRingMask
{
[_shortcutCell drawFocusRingMaskWithFrame:[self bounds] inView:self];
}
- (NSRect)focusRingMaskBounds
{
return [self bounds];
}
@end
+6 -4
View File
@@ -1,6 +1,7 @@
# coding: utf-8
Pod::Spec.new do |s|
s.name = 'MASShortcut'
s.version = '2.0.1'
s.name = 'MASShortcut'
s.version = '2.3.4'
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'
@@ -8,10 +9,11 @@ Pod::Spec.new do |s|
'Tomáš Znamenáček' => 'tomas.znamenacek@gmail.com' }
s.platform = :osx
s.osx.deployment_target = "10.7"
s.source = { :git => 'https://github.com/shpakovski/MASShortcut.git', :tag => '2.0.1' }
s.osx.deployment_target = "10.6"
s.source = { :git => 'https://github.com/shpakovski/MASShortcut.git', :tag => '2.3.4' }
s.source_files = 'Framework/*.{h,m}'
s.exclude_files = 'Framework/*Tests.m'
s.osx.frameworks = 'Carbon', 'AppKit'
s.requires_arc = true
s.osx.resource_bundles = { 'MASShortcut' => ['*.lproj'] }
end
+128 -19
View File
@@ -7,6 +7,13 @@
objects = {
/* Begin PBXBuildFile section */
0D2CAB131B8332E5005431FC /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 0D2CAB151B8332E5005431FC /* Localizable.strings */; };
0D2CAB191B8339F4005431FC /* MASLocalization.h in Headers */ = {isa = PBXBuildFile; fileRef = 0D2CAB171B8339F4005431FC /* MASLocalization.h */; };
0D2CAB1A1B8339F4005431FC /* MASLocalization.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D2CAB181B8339F4005431FC /* MASLocalization.m */; };
0D2CAB1B1B83409C005431FC /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 0D2CAB1D1B83409C005431FC /* MainMenu.xib */; };
0D2CAB211B834464005431FC /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 0D2CAB231B834464005431FC /* Localizable.strings */; };
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 */; };
@@ -15,11 +22,9 @@
0D827D381990D5E70010B8EF /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0D827CD61990D4420010B8EF /* Cocoa.framework */; };
0D827D6F1990D6110010B8EF /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 0D827D6A1990D6110010B8EF /* AppDelegate.m */; };
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 +70,26 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
0D2CAB141B8332E5005431FC /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
0D2CAB161B8332EE005431FC /* cs */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = cs; path = cs.lproj/Localizable.strings; sourceTree = "<group>"; };
0D2CAB171B8339F4005431FC /* MASLocalization.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MASLocalization.h; path = Framework/MASLocalization.h; sourceTree = "<group>"; };
0D2CAB181B8339F4005431FC /* MASLocalization.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MASLocalization.m; path = Framework/MASLocalization.m; sourceTree = "<group>"; };
0D2CAB1C1B83409C005431FC /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/MainMenu.xib; sourceTree = "<group>"; };
0D2CAB1E1B8340A4005431FC /* cs */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = cs; path = cs.lproj/MainMenu.xib; sourceTree = "<group>"; };
0D2CAB221B834464005431FC /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
0D2CAB241B834467005431FC /* cs */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = cs; path = cs.lproj/Localizable.strings; sourceTree = "<group>"; };
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>"; };
0D58DE521BA165FC0023BFBE /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = "<group>"; };
0D58DE531BA166170023BFBE /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Localizable.strings; sourceTree = "<group>"; };
0D58DE541BA166270023BFBE /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/Localizable.strings; sourceTree = "<group>"; };
0D58DE551BA166390023BFBE /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = "<group>"; };
0D58DE561BA166420023BFBE /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Localizable.strings; 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>"; };
@@ -82,9 +101,8 @@
0D827D6B1990D6110010B8EF /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
0D827D6C1990D6110010B8EF /* Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Prefix.pch; sourceTree = "<group>"; };
0D827D6D1990D6110010B8EF /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
0D827D6E1990D6110010B8EF /* MainMenu.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MainMenu.xib; sourceTree = "<group>"; };
0D827D761990F81E0010B8EF /* Shortcut.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Shortcut.h; path = Framework/Shortcut.h; sourceTree = "<group>"; };
0D827D8319910AFF0010B8EF /* Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
0D827D8319910AFF0010B8EF /* MASShortcutTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MASShortcutTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
0D827D8719910AFF0010B8EF /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
0D827D8D19910AFF0010B8EF /* Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Prefix.pch; sourceTree = "<group>"; };
0D827D9319910B740010B8EF /* MASShortcutTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MASShortcutTests.m; path = Framework/MASShortcutTests.m; sourceTree = "<group>"; };
@@ -104,6 +122,15 @@
0DC2F18F199372B4003A0131 /* MASDictionaryTransformerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MASDictionaryTransformerTests.m; path = Framework/MASDictionaryTransformerTests.m; sourceTree = "<group>"; };
0DC2F19619938EFA003A0131 /* MASShortcutView+Bindings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "MASShortcutView+Bindings.h"; path = "Framework/MASShortcutView+Bindings.h"; sourceTree = "<group>"; };
0DC2F19719938EFA003A0131 /* MASShortcutView+Bindings.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "MASShortcutView+Bindings.m"; path = "Framework/MASShortcutView+Bindings.m"; sourceTree = "<group>"; };
0DEDAA021C6BB479001605F5 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = "<group>"; };
6EA6034E1CBF822000A3ED9C /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/Localizable.strings; sourceTree = "<group>"; };
6EA6034F1CBF822800A3ED9C /* ko */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ko; path = ko.lproj/Localizable.strings; sourceTree = "<group>"; };
6EA603501CBF822D00A3ED9C /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = "<group>"; };
6EA603511CBF823600A3ED9C /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/Localizable.strings; sourceTree = "<group>"; };
76A0597D1C51DC940014B271 /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Localizable.strings"; sourceTree = "<group>"; };
76A0597E1C51DC9F0014B271 /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "zh-Hant.lproj/Localizable.strings"; sourceTree = "<group>"; };
EAFFDC811AACFF3300F38834 /* MASShortcut.modulemap */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = "sourcecode.module-map"; name = MASShortcut.modulemap; path = Framework/MASShortcut.modulemap; sourceTree = "<group>"; };
ED8737791BCE459800BB1716 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Localizable.strings; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@@ -128,7 +155,6 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
0D827D8419910AFF0010B8EF /* XCTest.framework in Frameworks */,
0D827D9519910C1E0010B8EF /* MASShortcut.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -152,7 +178,7 @@
children = (
0D827CD31990D4420010B8EF /* MASShortcut.framework */,
0D827D371990D5E70010B8EF /* Demo.app */,
0D827D8319910AFF0010B8EF /* Tests.xctest */,
0D827D8319910AFF0010B8EF /* MASShortcutTests.xctest */,
);
name = Products;
sourceTree = "<group>";
@@ -161,7 +187,6 @@
isa = PBXGroup;
children = (
0D827CD61990D4420010B8EF /* Cocoa.framework */,
0D827CEB1990D4420010B8EF /* XCTest.framework */,
0D827CD91990D4420010B8EF /* Foundation.framework */,
0D827CDA1990D4420010B8EF /* CoreData.framework */,
0D827CDB1990D4420010B8EF /* AppKit.framework */,
@@ -177,6 +202,8 @@
0DC2F18A19937060003A0131 /* User Defaults Storage */,
0D827DA119912A6D0010B8EF /* UI */,
0D827D2F1990D5640010B8EF /* Info.plist */,
EAFFDC811AACFF3300F38834 /* MASShortcut.modulemap */,
0D2CAB151B8332E5005431FC /* Localizable.strings */,
0D827D98199110F60010B8EF /* Prefix.pch */,
0D827D761990F81E0010B8EF /* Shortcut.h */,
);
@@ -186,9 +213,10 @@
0D827D681990D6110010B8EF /* Demo */ = {
isa = PBXGroup;
children = (
0D2CAB231B834464005431FC /* Localizable.strings */,
0D827D691990D6110010B8EF /* AppDelegate.h */,
0D827D6A1990D6110010B8EF /* AppDelegate.m */,
0D827D6E1990D6110010B8EF /* MainMenu.xib */,
0D2CAB1D1B83409C005431FC /* MainMenu.xib */,
0D827D6B1990D6110010B8EF /* Info.plist */,
0D827D6C1990D6110010B8EF /* Prefix.pch */,
0D827D6D1990D6110010B8EF /* main.m */,
@@ -222,6 +250,8 @@
0D827DA119912A6D0010B8EF /* UI */ = {
isa = PBXGroup;
children = (
0D2CAB171B8339F4005431FC /* MASLocalization.h */,
0D2CAB181B8339F4005431FC /* MASLocalization.m */,
0D827D211990D55E0010B8EF /* MASShortcutView.h */,
0D827D221990D55E0010B8EF /* MASShortcutView.m */,
0DC2F19619938EFA003A0131 /* MASShortcutView+Bindings.h */,
@@ -235,8 +265,10 @@
children = (
0DC2F17419922798003A0131 /* MASHotKey.h */,
0DC2F17519922798003A0131 /* MASHotKey.m */,
0D39DCA11A668A4400639145 /* MASHotKeyTests.m */,
0D827DA319912D240010B8EF /* MASShortcutMonitor.h */,
0D827DA419912D240010B8EF /* MASShortcutMonitor.m */,
0D39DCA31A668E5500639145 /* MASShortcutMonitorTests.m */,
);
name = Monitoring;
sourceTree = "<group>";
@@ -270,6 +302,7 @@
0DC2F18D1993708A003A0131 /* MASDictionaryTransformer.h in Headers */,
0D827DA519912D240010B8EF /* MASShortcutMonitor.h in Headers */,
0D827DAD199132840010B8EF /* MASShortcutBinder.h in Headers */,
0D2CAB191B8339F4005431FC /* MASLocalization.h in Headers */,
0DC2F17619922798003A0131 /* MASHotKey.h in Headers */,
0D827D771990F81E0010B8EF /* Shortcut.h in Headers */,
);
@@ -314,9 +347,9 @@
productReference = 0D827D371990D5E70010B8EF /* Demo.app */;
productType = "com.apple.product-type.application";
};
0D827D8219910AFF0010B8EF /* Tests */ = {
0D827D8219910AFF0010B8EF /* MASShortcutTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 0D827D9219910AFF0010B8EF /* Build configuration list for PBXNativeTarget "Tests" */;
buildConfigurationList = 0D827D9219910AFF0010B8EF /* Build configuration list for PBXNativeTarget "MASShortcutTests" */;
buildPhases = (
0D827D7F19910AFF0010B8EF /* Sources */,
0D827D8019910AFF0010B8EF /* Frameworks */,
@@ -327,9 +360,9 @@
dependencies = (
0D827D8F19910AFF0010B8EF /* PBXTargetDependency */,
);
name = Tests;
name = MASShortcutTests;
productName = Tests;
productReference = 0D827D8319910AFF0010B8EF /* Tests.xctest */;
productReference = 0D827D8319910AFF0010B8EF /* MASShortcutTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
/* End PBXNativeTarget section */
@@ -338,7 +371,7 @@
0D827CCA1990D4420010B8EF /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0510;
LastUpgradeCheck = 0730;
ORGANIZATIONNAME = "Vadim Shpakovski";
TargetAttributes = {
0D827D8219910AFF0010B8EF = {
@@ -352,7 +385,18 @@
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
cs,
de,
es,
it,
fr,
ja,
"zh-Hans",
"zh-Hant",
pl,
ko,
ru,
nl,
);
mainGroup = 0D827CC91990D4420010B8EF;
productRefGroup = 0D827CD41990D4420010B8EF /* Products */;
@@ -360,8 +404,8 @@
projectRoot = "";
targets = (
0D827CD21990D4420010B8EF /* MASShortcut */,
0D827D8219910AFF0010B8EF /* MASShortcutTests */,
0D827D361990D5E70010B8EF /* Demo */,
0D827D8219910AFF0010B8EF /* Tests */,
);
};
/* End PBXProject section */
@@ -371,6 +415,7 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
0D2CAB131B8332E5005431FC /* Localizable.strings in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -378,7 +423,8 @@
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
0D827D721990D6110010B8EF /* MainMenu.xib in Resources */,
0D2CAB1B1B83409C005431FC /* MainMenu.xib in Resources */,
0D2CAB211B834464005431FC /* Localizable.strings in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -402,6 +448,7 @@
0D827D2C1990D55E0010B8EF /* MASShortcutView.m in Sources */,
0D827D261990D55E0010B8EF /* MASShortcut.m in Sources */,
0DC2F18E1993708A003A0131 /* MASDictionaryTransformer.m in Sources */,
0D2CAB1A1B8339F4005431FC /* MASLocalization.m in Sources */,
0DC2F19919938EFA003A0131 /* MASShortcutView+Bindings.m in Sources */,
0DC2F17D199232F7003A0131 /* MASShortcutBinder.m in Sources */,
);
@@ -423,6 +470,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;
};
@@ -436,6 +485,49 @@
};
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
0D2CAB151B8332E5005431FC /* Localizable.strings */ = {
isa = PBXVariantGroup;
children = (
0D2CAB141B8332E5005431FC /* en */,
0D2CAB161B8332EE005431FC /* cs */,
0D58DE521BA165FC0023BFBE /* de */,
0D58DE531BA166170023BFBE /* es */,
0D58DE541BA166270023BFBE /* it */,
0D58DE551BA166390023BFBE /* fr */,
0D58DE561BA166420023BFBE /* ja */,
76A0597D1C51DC940014B271 /* zh-Hans */,
76A0597E1C51DC9F0014B271 /* zh-Hant */,
6EA6034E1CBF822000A3ED9C /* pl */,
6EA6034F1CBF822800A3ED9C /* ko */,
6EA603501CBF822D00A3ED9C /* ru */,
6EA603511CBF823600A3ED9C /* nl */,
);
name = Localizable.strings;
sourceTree = "<group>";
};
0D2CAB1D1B83409C005431FC /* MainMenu.xib */ = {
isa = PBXVariantGroup;
children = (
0D2CAB1C1B83409C005431FC /* en */,
0D2CAB1E1B8340A4005431FC /* cs */,
);
name = MainMenu.xib;
sourceTree = "<group>";
};
0D2CAB231B834464005431FC /* Localizable.strings */ = {
isa = PBXVariantGroup;
children = (
0D2CAB221B834464005431FC /* en */,
0D2CAB241B834467005431FC /* cs */,
ED8737791BCE459800BB1716 /* ja */,
0DEDAA021C6BB479001605F5 /* de */,
);
name = Localizable.strings;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
0D827CF91990D4420010B8EF /* Debug */ = {
isa = XCBuildConfiguration;
@@ -454,6 +546,7 @@
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_ENABLE_OBJC_EXCEPTIONS = YES;
@@ -513,6 +606,7 @@
isa = XCBuildConfiguration;
buildSettings = {
COMBINE_HIDPI_IMAGES = YES;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
FRAMEWORK_VERSION = A;
@@ -520,6 +614,9 @@
GCC_PREFIX_HEADER = Framework/Prefix.pch;
INFOPLIST_FILE = Framework/Info.plist;
INSTALL_PATH = "@executable_path/../Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.6;
MODULEMAP_FILE = Framework/MASShortcut.modulemap;
PRODUCT_BUNDLE_IDENTIFIER = "com.github.shpakovski.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
WRAPPER_EXTENSION = framework;
@@ -530,6 +627,7 @@
isa = XCBuildConfiguration;
buildSettings = {
COMBINE_HIDPI_IMAGES = YES;
DEFINES_MODULE = YES;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
FRAMEWORK_VERSION = A;
@@ -537,6 +635,9 @@
GCC_PREFIX_HEADER = Framework/Prefix.pch;
INFOPLIST_FILE = Framework/Info.plist;
INSTALL_PATH = "@executable_path/../Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.6;
MODULEMAP_FILE = Framework/MASShortcut.modulemap;
PRODUCT_BUNDLE_IDENTIFIER = "com.github.shpakovski.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME)";
SKIP_INSTALL = YES;
WRAPPER_EXTENSION = framework;
@@ -555,6 +656,8 @@
"$(inherited)",
);
INFOPLIST_FILE = Demo/Info.plist;
MACOSX_DEPLOYMENT_TARGET = 10.6;
PRODUCT_BUNDLE_IDENTIFIER = "com.shpakovski.mac.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME)";
WRAPPER_EXTENSION = app;
};
@@ -568,6 +671,8 @@
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = Demo/Prefix.pch;
INFOPLIST_FILE = Demo/Info.plist;
MACOSX_DEPLOYMENT_TARGET = 10.6;
PRODUCT_BUNDLE_IDENTIFIER = "com.shpakovski.mac.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME)";
WRAPPER_EXTENSION = app;
};
@@ -576,6 +681,7 @@
0D827D9019910AFF0010B8EF /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
COMBINE_HIDPI_IMAGES = YES;
FRAMEWORK_SEARCH_PATHS = (
"$(DEVELOPER_FRAMEWORKS_DIR)",
"$(inherited)",
@@ -587,6 +693,7 @@
"$(inherited)",
);
INFOPLIST_FILE = Tests/Info.plist;
PRODUCT_BUNDLE_IDENTIFIER = "com.github.shpakovski.MASShortcut.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME)";
WRAPPER_EXTENSION = xctest;
};
@@ -595,6 +702,7 @@
0D827D9119910AFF0010B8EF /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
COMBINE_HIDPI_IMAGES = YES;
FRAMEWORK_SEARCH_PATHS = (
"$(DEVELOPER_FRAMEWORKS_DIR)",
"$(inherited)",
@@ -602,6 +710,7 @@
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = Tests/Prefix.pch;
INFOPLIST_FILE = Tests/Info.plist;
PRODUCT_BUNDLE_IDENTIFIER = "com.github.shpakovski.MASShortcut.${PRODUCT_NAME:rfc1034identifier}";
PRODUCT_NAME = "$(TARGET_NAME)";
WRAPPER_EXTENSION = xctest;
};
@@ -637,7 +746,7 @@
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
0D827D9219910AFF0010B8EF /* Build configuration list for PBXNativeTarget "Tests" */ = {
0D827D9219910AFF0010B8EF /* Build configuration list for PBXNativeTarget "MASShortcutTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
0D827D9019910AFF0010B8EF /* Debug */,
@@ -0,0 +1,91 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0730"
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
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0D827D361990D5E70010B8EF"
BuildableName = "Demo.app"
BlueprintName = "Demo"
ReferencedContainer = "container:MASShortcut.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0D827D361990D5E70010B8EF"
BuildableName = "Demo.app"
BlueprintName = "Demo"
ReferencedContainer = "container:MASShortcut.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<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,113 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0730"
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 = "MASShortcutTests.xctest"
BlueprintName = "MASShortcutTests"
ReferencedContainer = "container:MASShortcut.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0D827D8219910AFF0010B8EF"
BuildableName = "MASShortcutTests.xctest"
BlueprintName = "MASShortcutTests"
ReferencedContainer = "container:MASShortcut.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0D827CD21990D4420010B8EF"
BuildableName = "MASShortcut.framework"
BlueprintName = "MASShortcut"
ReferencedContainer = "container:MASShortcut.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "0D827CD21990D4420010B8EF"
BuildableName = "MASShortcut.framework"
BlueprintName = "MASShortcut"
ReferencedContainer = "container:MASShortcut.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
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>
+10
View File
@@ -0,0 +1,10 @@
.PHONY: release
ifndef BUILDDIR
BUILDDIR := $(shell mktemp -d "$(TMPDIR)/MASShortcut.XXXXXX")
endif
release:
xcodebuild -scheme MASShortcut -configuration Release -derivedDataPath "$(BUILDDIR)" build
open "$(BUILDDIR)/Build/Products/Release"
+37 -3
View File
@@ -1,8 +1,31 @@
[![Build Status](https://travis-ci.org/shpakovski/MASShortcut.svg?branch=master)](https://travis-ci.org/shpakovski/MASShortcut)
[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage)
# 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.
The MASShortcut project introduces a modern API and user interface for recording, storing and using system-wide keyboard shortcuts. All code is compatible with recent Xcode & OS X versions and the sandboxed environment.
The MASShortcut project introduces a modern API and user interface for recording, storing and using system-wide keyboard shortcuts.
![Screenshot of the demo project](https://raw.githubusercontent.com/shpakovski/MASShortcut/master/Demo/screenshot.png "This is how the demo looks like")
Features:
* Record and display keyboard shortcuts
* Watch for shortcuts and execute actions, system-wide
* A nice, [documented API](http://cocoadocs.org/docsets/MASShortcut/)
* Can be configured to be compatible with Shortcut Recorder
* Can be installed both through CocoaPods and as a Git submodule
* Mac App Store friendly
* Works on OS X 10.6 and up
* Hacking-friendly codebase covered with tests
Partially done:
* Accessibility support. Theres some basic accessibility code, testers and feedback welcome.
* Localisation. The English and Czech localization should be complete, theres basic support for German, French, Spanish, Italian, and Japanese. If youre a native speaker in one of the mentioned languages, please test the localization and report issues or add missing strings.
Pull requests welcome :)
# Installation
@@ -14,6 +37,10 @@ If you want to stick to the 1.x branch, you can use the version smart match oper
pod 'MASShortcut', '~> 1'
You can also install via [Carthage](https://github.com/Carthage/Carthage), or you can use Git submodules and link against the MASShortcut framework manually.
To build from the command line, type 'make release'. The framework will be created in a temporary directory and revealed in Finder when the build is complete.
# Usage
I hope, it is really easy:
@@ -93,9 +120,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
+11 -1
View File
@@ -12,4 +12,14 @@ Please stay high-level when writing the spec, do not document particular classes
* If the shortcut is Cmd-W or Cmd-Q, the recording must be cancelled and the keypress passed through to the system, closing the window or quitting the app.
* If a shortcut is already taken by system and is enabled, it must be rejected. (Examples: Cmd-S, Cmd-N. TBD: What exactly does it mean that the shortcut is “enabled”?)
* TBD: Option-key handling.
* All other shortcuts must be accepted. (Examples: Ctrl-Esc, Cmd-Delete, F16.)
* All other shortcuts must be accepted. (Examples: Ctrl-Esc, Cmd-Delete, F16.)
# Formatting Shortcuts
On different keyboard layouts (such as US and Czech), a single shortcut (a combination of physical keys) may be formatted into different strings.
For example, the default system shortcut for toggling directly to Space #2 is Control2. But when you switch to the Czech keyboard layout, the physical key with the `2` label now inserts the `ě` character. Thus, on most keyboard layouts the shortcut for toggling to Space #2 is called `^2`, but on the Czech layout its called `^ě`. (I stress that this is the same combination of hardware keys and the same `MASShortcut` instance.)
This is reflected by the system: When you open the System Preferences → Keyboard → Shortcuts pane, the shortcuts displayed depend on the currently selected keyboard layout (try switching between the US and Czech keyboard layouts and reopening the preference pane).
This means that the identity of a shortcut is given by its key code and modifiers (such as `kVK_ANSI_2` and `NSControlKeyMask`), not the `keyCodeString` returned by the `MASShortcut` class. This string may change depending on the current keyboard layout: `^2` with the US keyboard active, but `^ě` with the Czech keyboard active.
+1 -1
View File
@@ -7,7 +7,7 @@
<key>CFBundleExecutable</key>
<string>${EXECUTABLE_NAME}</string>
<key>CFBundleIdentifier</key>
<string>com.github.shpakovski.MASShortcut.${PRODUCT_NAME:rfc1034identifier}</string>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
+47
View File
@@ -0,0 +1,47 @@
/* Cancel action button in recording state */
"Cancel" = "Zrušit";
/* Tooltip for non-empty shortcut button */
"Click to record new shortcut" = "Kliknutím nahrajete novou zkratku";
/* Tooltip for hint button near the non-empty shortcut */
"Delete shortcut" = "Smazat zkratku";
/* VoiceOver title */
"keyboard shortcut" = "klávesová zkratka";
/* Alert button when shortcut is already used */
"OK" = "OK";
/* Empty shortcut button in normal state */
"Record Shortcut" = "Nahrát zkratku";
/* VoiceOver: Shortcut cleared */
"Shortcut cleared" = "zkratka smazána";
/* VoiceOver: Shortcut set */
"Shortcut set" = "zkratka nastavena";
/* Shortcut glyph name for SPACE key */
"Space" = "Mezerník";
/* Title for alert when shortcut is already used */
"The key combination %@ cannot be used" = "Kombinace %@ se nedá použít";
/* Message for alert when shortcut is already used by the system */
"This combination cannot be used because it is already used by a system-wide keyboard shortcut.\nIf you really want to use this key combination, most shortcuts can be changed in the Keyboard & Mouse panel in System Preferences." = "Tato zkratka se nedá použít, protože už ji obsadil systém.\nKdybyste na ní trvali, většina systémových zkratek se dá přenastavit v Předvolbách systému.";
/* Message for alert when shortcut is already used */
"This shortcut cannot be used because it is already used by the menu item %@." = "Tato zkratka se nedá použít, protože už je použita pro menu (%@).";
/* VoiceOver shortcut help */
"To record a new shortcut, click this button, and then type the new shortcut, or press delete to clear an existing shortcut." = "Pokud chcete nahrát novou zkratku, stiskněte toto tlačítko a následně vybranou zkratku. Stisknutím Delete vymažete stávající zkratku.";
/* Non-empty shortcut button in recording state */
"Type New Shortcut" = "Stiskněte zkratku";
/* Empty shortcut button in recording state */
"Type Shortcut" = "Stiskněte zkratku";
/* Cancel action button for non-empty shortcut in recording state */
"Use Old Shortcut" = "Vrátit se k původní";
+47
View File
@@ -0,0 +1,47 @@
/* Cancel action button in recording state */
"Cancel" = "Abbrechen";
/* Tooltip for non-empty shortcut button */
"Click to record new shortcut" = "Klicken um neuen Kurzbefehl aufzunehmen";
/* Tooltip for hint button near the non-empty shortcut */
"Delete shortcut" = "Kurzbefehl Löschen";
/* VoiceOver title */
"keyboard shortcut" = "Kurzbefehl";
/* Alert button when shortcut is already used */
"OK" = "OK";
/* Empty shortcut button in normal state */
"Record Shortcut" = "Kurzbefehl aufnehmen";
/* VoiceOver: Shortcut cleared */
"Shortcut cleared" = "Kurzbefehl gelöscht";
/* VoiceOver: Shortcut set */
"Shortcut set" = "Kurzbefehl gesetzt";
/* Shortcut glyph name for SPACE key */
"Space" = "Leertaste";
/* Title for alert when shortcut is already used */
"The key combination %@ cannot be used" = "Die Tastenkombination %@ kann nicht genutzt werden";
/* Message for alert when shortcut is already used by the system */
"This combination cannot be used because it is already used by a system-wide keyboard shortcut.\nIf you really want to use this key combination, most shortcuts can be changed in the Keyboard & Mouse panel in System Preferences." = "Diese Kombination kann nicht genutzt werden, weil sie bereits als systemweiter Kurzbefehl genutzt wird.\nFalls du diese Tastenkombination wirklich benutzen willst, können die meisten Kurzbefehle in den Tastatur Systemeinstellungen geändert werden.";
/* Message for alert when shortcut is already used */
"This shortcut cannot be used because it is already used by the menu item %@." = "Dieser Kurzbefehl kann nicht genutzt werden, weil er bereits vom Menüpunkt „%@“ genutzt wird.";
/* VoiceOver shortcut help */
"To record a new shortcut, click this button, and then type the new shortcut, or press delete to clear an existing shortcut." = "Drücke diesen Button, um einen neuen Kurzbefehl aufzunehmen. Tippe dann den neuen Kurzbefehl oder drücke Löschen, um den aktuellen Kurzbefehl zu löschen.";
/* Non-empty shortcut button in recording state */
"Type New Shortcut" = "Neuen eingeben";
/* Empty shortcut button in recording state */
"Type Shortcut" = "Kurzbefehl eingeben";
/* Cancel action button for non-empty shortcut in recording state */
"Use Old Shortcut" = "Alten nutzen";
+47
View File
@@ -0,0 +1,47 @@
/* Cancel action button in recording state */
"Cancel" = "Cancel";
/* Tooltip for non-empty shortcut button */
"Click to record new shortcut" = "Click to record new shortcut";
/* Tooltip for hint button near the non-empty shortcut */
"Delete shortcut" = "Delete shortcut";
/* VoiceOver title */
"keyboard shortcut" = "keyboard shortcut";
/* Alert button when shortcut is already used */
"OK" = "OK";
/* Empty shortcut button in normal state */
"Record Shortcut" = "Record Shortcut";
/* VoiceOver: Shortcut cleared */
"Shortcut cleared" = "Shortcut cleared";
/* VoiceOver: Shortcut set */
"Shortcut set" = "Shortcut set";
/* Shortcut glyph name for SPACE key */
"Space" = "Space";
/* Title for alert when shortcut is already used */
"The key combination %@ cannot be used" = "The key combination %@ cannot be used";
/* Message for alert when shortcut is already used by the system */
"This combination cannot be used because it is already used by a system-wide keyboard shortcut.\nIf you really want to use this key combination, most shortcuts can be changed in the Keyboard & Mouse panel in System Preferences." = "This combination cannot be used because it is already used by a system-wide keyboard shortcut.\nIf you really want to use this key combination, most shortcuts can be changed in the Keyboard & Mouse panel in System Preferences.";
/* Message for alert when shortcut is already used */
"This shortcut cannot be used because it is already used by the menu item %@." = "This shortcut cannot be used because it is already used by the menu item %@.";
/* VoiceOver shortcut help */
"To record a new shortcut, click this button, and then type the new shortcut, or press delete to clear an existing shortcut." = "To record a new shortcut, click this button, and then type the new shortcut, or press delete to clear an existing shortcut.";
/* Non-empty shortcut button in recording state */
"Type New Shortcut" = "Type New Shortcut";
/* Empty shortcut button in recording state */
"Type Shortcut" = "Type Shortcut";
/* Cancel action button for non-empty shortcut in recording state */
"Use Old Shortcut" = "Use Old Shortcut";
+47
View File
@@ -0,0 +1,47 @@
/* Cancel action button in recording state */
"Cancel" = "Cancelar";
/* Tooltip for non-empty shortcut button */
"Click to record new shortcut" = "Haga clic para grabar nuevo atajo";
/* Tooltip for hint button near the non-empty shortcut */
"Delete shortcut" = "Borrar atajo";
/* VoiceOver title */
"keyboard shortcut" = "atajo de teklado";
/* Alert button when shortcut is already used */
"OK" = "OK";
/* Empty shortcut button in normal state */
"Record Shortcut" = "Grabar atajo";
/* VoiceOver: Shortcut cleared */
"Shortcut cleared" = "Atajo borrado";
/* VoiceOver: Shortcut set */
"Shortcut set" = "Atajo creado";
/* Shortcut glyph name for SPACE key */
"Space" = "Espacio";
/* Title for alert when shortcut is already used */
"The key combination %@ cannot be used" = "La combinación de claves %@ no se puede utilizada";
/* Message for alert when shortcut is already used by the system */
"This combination cannot be used because it is already used by a system-wide keyboard shortcut.\nIf you really want to use this key combination, most shortcuts can be changed in the Keyboard & Mouse panel in System Preferences." = "Esta combinación no se puede utilizar debido a que ya es en us como atajo del sistema.\nSi realmente desea utilizar esta combinación de teclas, la mayoría de los atajos se puede cambiar en el panel de Teclado y Ratón de Preferencias del Sistema.";
/* Message for alert when shortcut is already used */
"This shortcut cannot be used because it is already used by the menu item %@." = "Este atajo no se puede utilizar debido a que ya es utilizado por el elemento de menú '%@'.";
/* VoiceOver shortcut help */
"To record a new shortcut, click this button, and then type the new shortcut, or press delete to clear an existing shortcut." = "Para grabar un nuevo atajo, haga clic en este botón, a continuar, escriba el nuevo atajo, o pulse borrar para qutar un atajo existente.";
/* Non-empty shortcut button in recording state */
"Type New Shortcut" = "Escribir atajo";
/* Empty shortcut button in recording state */
"Type Shortcut" = "Escribir atajo";
/* Cancel action button for non-empty shortcut in recording state */
"Use Old Shortcut" = "Usa atajo anterior";
+47
View File
@@ -0,0 +1,47 @@
/* Cancel action button in recording state */
"Cancel" = "Annuler";
/* Tooltip for non-empty shortcut button */
"Click to record new shortcut" = "Cliquez pour enregistrer le raccourci";
/* Tooltip for hint button near the non-empty shortcut */
"Delete shortcut" = "Supprimer le raccourci";
/* VoiceOver title */
"keyboard shortcut" = "raccourci clavier";
/* Alert button when shortcut is already used */
"OK" = "OK";
/* Empty shortcut button in normal state */
"Record Shortcut" = "Enregistrer le raccourci";
/* VoiceOver: Shortcut cleared */
"Shortcut cleared" = "Raccourci supprimé";
/* VoiceOver: Shortcut set */
"Shortcut set" = "Raccourci configuré";
/* Shortcut glyph name for SPACE key */
"Space" = "Espace";
/* Title for alert when shortcut is already used */
"The key combination %@ cannot be used" = "La combinaison %@ ne peut être utilisée";
/* Message for alert when shortcut is already used by the system */
"This combination cannot be used because it is already used by a system-wide keyboard shortcut.\nIf you really want to use this key combination, most shortcuts can be changed in the Keyboard & Mouse panel in System Preferences." = "Cette combinaison de touches ne peut être utilisée parce quelle est réservée pour un raccourci du système.\nSi vous désirez lutiliser, la plupart des raccourcis peuvent être modifiés dans longlet Clavier, dans Préférences Système.";
/* Message for alert when shortcut is already used */
"This shortcut cannot be used because it is already used by the menu item %@." = "Ce raccourci ne peut être utilisé parce quil est déjà utilisé par le point de menu «%@».";
/* VoiceOver shortcut help */
"To record a new shortcut, click this button, and then type the new shortcut, or press delete to clear an existing shortcut." = "Pour enregistrer un nouveau raccourci, cliquez sur ce bouton et tapez le nouveau raccourci, ou bien, tapez sur «Supprimer» pour supprimer le raccourci configuré.";
/* Non-empty shortcut button in recording state */
"Type New Shortcut" = "Saisir un raccourci";
/* Empty shortcut button in recording state */
"Type Shortcut" = "Saisir un raccourci";
/* Cancel action button for non-empty shortcut in recording state */
"Use Old Shortcut" = "Revenir au raccourci précédent";
+47
View File
@@ -0,0 +1,47 @@
/* Cancel action button in recording state */
"Cancel" = "Annulla";
/* Tooltip for non-empty shortcut button */
"Click to record new shortcut" = "Click to record new shortcut";
/* Tooltip for hint button near the non-empty shortcut */
"Delete shortcut" = "Delete shortcut";
/* VoiceOver title */
"keyboard shortcut" = "keyboard shortcut";
/* Alert button when shortcut is already used */
"OK" = "OK";
/* Empty shortcut button in normal state */
"Record Shortcut" = "Registra scorciatoia";
/* VoiceOver: Shortcut cleared */
"Shortcut cleared" = "Shortcut cleared";
/* VoiceOver: Shortcut set */
"Shortcut set" = "Shortcut set";
/* Shortcut glyph name for SPACE key */
"Space" = "Spazio";
/* Title for alert when shortcut is already used */
"The key combination %@ cannot be used" = "The key combination %@ cannot be used";
/* Message for alert when shortcut is already used by the system */
"This combination cannot be used because it is already used by a system-wide keyboard shortcut.\nIf you really want to use this key combination, most shortcuts can be changed in the Keyboard & Mouse panel in System Preferences." = "This combination cannot be used because it is already used by a system-wide keyboard shortcut.\nIf you really want to use this key combination, most shortcuts can be changed in the Keyboard & Mouse panel in System Preferences.";
/* Message for alert when shortcut is already used */
"This shortcut cannot be used because it is already used by the menu item %@." = "This shortcut cannot be used because it is already used by the menu item %@.";
/* VoiceOver shortcut help */
"To record a new shortcut, click this button, and then type the new shortcut, or press delete to clear an existing shortcut." = "To record a new shortcut, click this button, and then type the new shortcut, or press delete to clear an existing shortcut.";
/* Non-empty shortcut button in recording state */
"Type New Shortcut" = "Digita scorciatoia";
/* Empty shortcut button in recording state */
"Type Shortcut" = "Digita scorciatoia";
/* Cancel action button for non-empty shortcut in recording state */
"Use Old Shortcut" = "Use Old Shortcut";
+47
View File
@@ -0,0 +1,47 @@
/* Cancel action button in recording state */
"Cancel" = "キャンセルする";
/* Tooltip for non-empty shortcut button */
"Click to record new shortcut" = "クリックしてショートカットを入力";
/* Tooltip for hint button near the non-empty shortcut */
"Delete shortcut" = "ショートカットを削除";
/* VoiceOver title */
"keyboard shortcut" = "キーボードショートカット";
/* Alert button when shortcut is already used */
"OK" = "OK";
/* Empty shortcut button in normal state */
"Record Shortcut" = "ショートカットを入力";
/* VoiceOver: Shortcut cleared */
"Shortcut cleared" = "ショートカットが削除されました";
/* VoiceOver: Shortcut set */
"Shortcut set" = "ショートカットが設定されました";
/* Shortcut glyph name for SPACE key */
"Space" = "スペース";
/* Title for alert when shortcut is already used */
"The key combination %@ cannot be used" = "%@ はショートカットに設定できません";
/* Message for alert when shortcut is already used by the system */
"This combination cannot be used because it is already used by a system-wide keyboard shortcut.\nIf you really want to use this key combination, most shortcuts can be changed in the Keyboard & Mouse panel in System Preferences." = "このショートカットは、システム全体で使用されているショートカットのため、設定することができません。\nもしこのショートカットを使用したい場合、「システム環境設定」の「キーボード」、「マウス」のパネルから既に設定されているショートカットを変更してください。";
/* Message for alert when shortcut is already used */
"This shortcut cannot be used because it is already used by the menu item %@." = "このショートカットは、メニュー操作の「%@」で使われているため、設定できません。";
/* VoiceOver shortcut help */
"To record a new shortcut, click this button, and then type the new shortcut, or press delete to clear an existing shortcut." = "このボタンをクリックし、ショートカットを入力すると、新しいショートカットが設定されます。また、削除ボタンをおすと、ショートカットが削除されます。";
/* Non-empty shortcut button in recording state */
"Type New Shortcut" = "ショートカットを入力";
/* Empty shortcut button in recording state */
"Type Shortcut" = "ショートカットを入力";
/* Cancel action button for non-empty shortcut in recording state */
"Use Old Shortcut" = "古いショートカットを使用";
+47
View File
@@ -0,0 +1,47 @@
/* Cancel action button in recording state */
"Cancel" = "취소";
/* Tooltip for non-empty shortcut button */
"Click to record new shortcut" = "클릭해 단축 키를 입력";
/* Tooltip for hint button near the non-empty shortcut */
"Delete shortcut" = "단축키 삭제";
/* VoiceOver title */
"keyboard shortcut" = "키보드 단축키";
/* Alert button when shortcut is already used */
"OK" = "좋아";
/* Empty shortcut button in normal state */
"Record Shortcut" = "단축키 입력";
/* VoiceOver: Shortcut cleared */
"Shortcut cleared" = "단축키 삭제됨";
/* VoiceOver: Shortcut set */
"Shortcut set" = "단축키 설정됨";
/* Shortcut glyph name for SPACE key */
"Space" = "스페이스 바";
/* Title for alert when shortcut is already used */
"The key combination %@ cannot be used" = "%@ 단축키로 설정할 수 없습니다";
/* Message for alert when shortcut is already used by the system */
"This combination cannot be used because it is already used by a system-wide keyboard shortcut.\nIf you really want to use this key combination, most shortcuts can be changed in the Keyboard & Mouse panel in System Preferences." = "이 결합은 시스템 전체에서 사용 때문에 단축키로 설정 할 수 없습니다.\n단축키를 사용하고 싶으면 시스템 환경 설정의 키보드, 마우스 패널에서 이미 설정되어있는 단축키를 변경하십시오.";
/* Message for alert when shortcut is already used */
"This shortcut cannot be used because it is already used by the menu item %@." = "이 단축키는 ‘%@’ 메뉴 아이템에 사용되고 있기 때문에 설정할 수 없습니다.";
/* VoiceOver shortcut help */
"To record a new shortcut, click this button, and then type the new shortcut, or press delete to clear an existing shortcut." = "이 버튼을 클릭하고 단축키를 입력하면 새로운 단축키가 설정됩니다. 또한 삭제 버튼을 누르면 단축키가 삭제됩니다.";
/* Non-empty shortcut button in recording state */
"Type New Shortcut" = "새 단축키 입력";
/* Empty shortcut button in recording state */
"Type Shortcut" = "단축키 입력";
/* Cancel action button for non-empty shortcut in recording state */
"Use Old Shortcut" = "오래된 단축키를 사용";
+47
View File
@@ -0,0 +1,47 @@
/* Cancel action button in recording state */
"Cancel" = "Verbreken";
/* Tooltip for non-empty shortcut button */
"Click to record new shortcut" = "Druk om een nieuwe sneltoets in te voeren";
/* Tooltip for hint button near the non-empty shortcut */
"Delete shortcut" = "Verwijder sneltoets";
/* VoiceOver title */
"keyboard shortcut" = "sneltoets";
/* Alert button when shortcut is already used */
"OK" = "OK";
/* Empty shortcut button in normal state */
"Record Shortcut" = "Sneltoets opnemen";
/* VoiceOver: Shortcut cleared */
"Shortcut cleared" = "Sneltoets verwijderd";
/* VoiceOver: Shortcut set */
"Shortcut set" = "Sneltoets zetten";
/* Shortcut glyph name for SPACE key */
"Space" = "Spatie";
/* Title for alert when shortcut is already used */
"The key combination %@ cannot be used" = "De sneltoetsencombinatie kan niet worden gebruikt";
/* Message for alert when shortcut is already used by the system */
"This combination cannot be used because it is already used by a system-wide keyboard shortcut.\nIf you really want to use this key combination, most shortcuts can be changed in the Keyboard & Mouse panel in System Preferences." = "Deze combinatie kan niet worden gebruikt want hij wordt al gebruikt door een systeembreed sneltoets.\nAls je deze combinatie echt wilt gebruiken, kun je de meeste sneltoetsen binnen Toetsenbordinstellingen veranderen.";
/* Message for alert when shortcut is already used */
"This shortcut cannot be used because it is already used by the menu item %@." = "Deze sneltoets kan niet worden gebruikt want hij wordt al gebruikt door het menu item %@.";
/* VoiceOver shortcut help */
"To record a new shortcut, click this button, and then type the new shortcut, or press delete to clear an existing shortcut." = "Om nieuwe sneltoets op te nemen, druk op deze knop, en voer een nieuwe sneltoets in, of druk op verwijder om bestaande sneltoets te verwijderen.";
/* Non-empty shortcut button in recording state */
"Type New Shortcut" = "Voer Nieuwe Sneltoets in";
/* Empty shortcut button in recording state */
"Type Shortcut" = "Voer Sneltoets in";
/* Cancel action button for non-empty shortcut in recording state */
"Use Old Shortcut" = "Gebruik Oude Sneltoets";
+47
View File
@@ -0,0 +1,47 @@
/* Cancel action button in recording state */
"Cancel" = "Anuluj";
/* Tooltip for non-empty shortcut button */
"Click to record new shortcut" = "Kliknij, by ustawić nowy skrót";
/* Tooltip for hint button near the non-empty shortcut */
"Delete shortcut" = "Usuń skrót";
/* VoiceOver title */
"keyboard shortcut" = "skrót klawiszowy";
/* Alert button when shortcut is already used */
"OK" = "OK";
/* Empty shortcut button in normal state */
"Record Shortcut" = "Utwórz skrót";
/* VoiceOver: Shortcut cleared */
"Shortcut cleared" = "Skrót usunięty";
/* VoiceOver: Shortcut set */
"Shortcut set" = "Skrót ustawiony";
/* Shortcut glyph name for SPACE key */
"Space" = "Spacja";
/* Title for alert when shortcut is already used */
"The key combination %@ cannot be used" = "Nie można użyć kombinacji klawiszy %@";
/* Message for alert when shortcut is already used by the system */
"This combination cannot be used because it is already used by a system-wide keyboard shortcut.\nIf you really want to use this key combination, most shortcuts can be changed in the Keyboard & Mouse panel in System Preferences." = "Nie można użyć tej kombinacji, ponieważ jest już zajęta przez skrót systemowy.\nMożesz to zmienić w panelu Klawiatura w Preferencjach systemowych.";
/* Message for alert when shortcut is already used */
"This shortcut cannot be used because it is already used by the menu item %@." = "Ten skrót nie może być użyty, ponieważ w menu ma już przypisaną funkcję %@.";
/* VoiceOver shortcut help */
"To record a new shortcut, click this button, and then type the new shortcut, or press delete to clear an existing shortcut." = "Aby ustawić nowy skrót, użyj tego przycisku, a następnie wpisz nowy skrót albo naciśnij klawisz delete, by usunąć istniejący skrót";
/* Non-empty shortcut button in recording state */
"Type New Shortcut" = "Wpisz nowy skrót";
/* Empty shortcut button in recording state */
"Type Shortcut" = "Wpisz skrót";
/* Cancel action button for non-empty shortcut in recording state */
"Use Old Shortcut" = "Użyj starego skrótu";
+47
View File
@@ -0,0 +1,47 @@
/* Cancel action button in recording state */
"Cancel" = "Отмена";
/* Tooltip for non-empty shortcut button */
"Click to record new shortcut" = "Нажмите для записи сочетания клавиш";
/* Tooltip for hint button near the non-empty shortcut */
"Delete shortcut" = "Удалить горячую клавишу";
/* VoiceOver title */
"keyboard shortcut" = "сочетание клавиш";
/* Alert button when shortcut is already used */
"OK" = "ОК";
/* Empty shortcut button in normal state */
"Record Shortcut" = "Ввести сочетание";
/* VoiceOver: Shortcut cleared */
"Shortcut cleared" = "Сочетание клавиш удалено";
/* VoiceOver: Shortcut set */
"Shortcut set" = "Сочетание клавиш назначено";
/* Shortcut glyph name for SPACE key */
"Space" = "Пробел";
/* Title for alert when shortcut is already used */
"The key combination %@ cannot be used" = "Нельзя использовать сочетание клавиш %@";
/* Message for alert when shortcut is already used by the system */
"This combination cannot be used because it is already used by a system-wide keyboard shortcut.\nIf you really want to use this key combination, most shortcuts can be changed in the Keyboard & Mouse panel in System Preferences." = "Нельзя использовать это сочетание клавиш, потому что оно уже используется в системе.\n Если вы хотите использовать это сочетание, измените существующее системное сочетание клавиш через панель Клавиатура в Cистемных настройках.";
/* Message for alert when shortcut is already used */
"This shortcut cannot be used because it is already used by the menu item %@." = "Нельзя использовать это сочетание, потому что оно уже связано с элементом ‘%@’.";
/* VoiceOver shortcut help */
"To record a new shortcut, click this button, and then type the new shortcut, or press delete to clear an existing shortcut." = "Чтобы назначить новое сочетание клавиш, нажмите эту кнопку и введите новое сочетание, или нажмите \"Удалить\", чтобы удалить действующее сочетание клавиш.";
/* Non-empty shortcut button in recording state */
"Type New Shortcut" = "Введите сочетание";
/* Empty shortcut button in recording state */
"Type Shortcut" = "Введите сочетание";
/* Cancel action button for non-empty shortcut in recording state */
"Use Old Shortcut" = "Вернуть старое";
+47
View File
@@ -0,0 +1,47 @@
/* Cancel action button in recording state */
"Cancel" = "取消";
/* Tooltip for non-empty shortcut button */
"Click to record new shortcut" = "点击以记录新快捷键";
/* Tooltip for hint button near the non-empty shortcut */
"Delete shortcut" = "删除快捷键";
/* VoiceOver title */
"keyboard shortcut" = "键盘快捷键";
/* Alert button when shortcut is already used */
"OK" = "好";
/* Empty shortcut button in normal state */
"Record Shortcut" = "记录快捷键";
/* VoiceOver: Shortcut cleared */
"Shortcut cleared" = "快捷键已清除";
/* VoiceOver: Shortcut set */
"Shortcut set" = "快捷键已设置";
/* Shortcut glyph name for SPACE key */
"Space" = "空格键";
/* Title for alert when shortcut is already used */
"The key combination %@ cannot be used" = "按键组合“%@”无法使用";
/* Message for alert when shortcut is already used by the system */
"This combination cannot be used because it is already used by a system-wide keyboard shortcut.\nIf you really want to use this key combination, most shortcuts can be changed in the Keyboard & Mouse panel in System Preferences." = "当前按键组合无法使用,因为它已经用作其他系统全局快捷键。\n如果您真的想使用这个按键组合,大部分系统全局快捷键能在“系统偏好设置”里的“键盘”和“鼠标”面板中重设。";
/* Message for alert when shortcut is already used */
"This shortcut cannot be used because it is already used by the menu item %@." = "当前快捷键无法使用,因为它已用作菜单项“%@”的快捷键。";
/* VoiceOver shortcut help */
"To record a new shortcut, click this button, and then type the new shortcut, or press delete to clear an existing shortcut." = "若要记录新的快捷键,单击此按钮,然后键入新的快捷键,或者按“delete键”删除已经存在的快捷键。";
/* Non-empty shortcut button in recording state */
"Type New Shortcut" = "键入新快捷键";
/* Empty shortcut button in recording state */
"Type Shortcut" = "键入快捷键";
/* Cancel action button for non-empty shortcut in recording state */
"Use Old Shortcut" = "还原快捷键";
+47
View File
@@ -0,0 +1,47 @@
/* Cancel action button in recording state */
"Cancel" = "取消";
/* Tooltip for non-empty shortcut button */
"Click to record new shortcut" = "點選以記錄新快捷鍵";
/* Tooltip for hint button near the non-empty shortcut */
"Delete shortcut" = "刪除快捷鍵";
/* VoiceOver title */
"keyboard shortcut" = "鍵盤快捷鍵";
/* Alert button when shortcut is already used */
"OK" = "好";
/* Empty shortcut button in normal state */
"Record Shortcut" = "記錄快捷鍵";
/* VoiceOver: Shortcut cleared */
"Shortcut cleared" = "快捷鍵已清除";
/* VoiceOver: Shortcut set */
"Shortcut set" = "快捷鍵已設定";
/* Shortcut glyph name for SPACE key */
"Space" = "空格鍵";
/* Title for alert when shortcut is already used */
"The key combination %@ cannot be used" = "按鍵組合“%@”無法使用";
/* Message for alert when shortcut is already used by the system */
"This combination cannot be used because it is already used by a system-wide keyboard shortcut.\nIf you really want to use this key combination, most shortcuts can be changed in the Keyboard & Mouse panel in System Preferences." = "當前按鍵組合無法使用,因為它已經用作其他系統全局快捷鍵。\n如果您真的想使用這個按鍵組合,大部分系統全局快捷鍵能在“系統偏好設定”裡的“鍵盤”和“滑鼠”面板中重設。";
/* Message for alert when shortcut is already used */
"This shortcut cannot be used because it is already used by the menu item %@." = "當前快捷鍵無法使用,因為它已用作選單項“%@”的快捷鍵。";
/* VoiceOver shortcut help */
"To record a new shortcut, click this button, and then type the new shortcut, or press delete to clear an existing shortcut." = "若要記錄新的快捷鍵,單擊此按鈕,然後鍵入新的快捷鍵,或者按“delete鍵”刪除已經存在的快捷鍵。";
/* Non-empty shortcut button in recording state */
"Type New Shortcut" = "鍵入新快捷鍵";
/* Empty shortcut button in recording state */
"Type Shortcut" = "鍵入快捷鍵";
/* Cancel action button for non-empty shortcut in recording state */
"Use Old Shortcut" = "還原快捷鍵";