diff options
| -rw-r--r-- | MASShortcut.h | 5 | ||||
| -rw-r--r-- | MASShortcut.m | 65 |
2 files changed, 53 insertions, 17 deletions
diff --git a/MASShortcut.h b/MASShortcut.h index 3c6c109..06507f6 100644 --- a/MASShortcut.h +++ b/MASShortcut.h @@ -51,4 +51,9 @@ enum { - (BOOL)isTakenError:(NSError **)error; +// 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 ® ++ (void)setAllowsAnyHotkeyWithOptionModifier:(BOOL)allow; ++ (BOOL)allowsAnyHotkeyWithOptionModifier; + @end diff --git a/MASShortcut.m b/MASShortcut.m index ca5a1ae..b004e48 100644 --- a/MASShortcut.m +++ b/MASShortcut.m @@ -1,7 +1,7 @@ #import "MASShortcut.h" -NSString *const kMASShortcutKeyCode = @"KeyCode"; -NSString *const kMASShortcutModifierFlags = @"ModifierFlags"; +NSString *const MASShortcutKeyCode = @"KeyCode"; +NSString *const MASShortcutModifierFlags = @"ModifierFlags"; @implementation MASShortcut { NSUInteger _keyCode; // NSNotFound if empty @@ -15,17 +15,17 @@ NSString *const kMASShortcutModifierFlags = @"ModifierFlags"; - (void)encodeWithCoder:(NSCoder *)coder { - [coder encodeInteger:(self.keyCode != NSNotFound ? (NSInteger)self.keyCode : - 1) forKey:kMASShortcutKeyCode]; - [coder encodeInteger:(NSInteger)self.modifierFlags forKey:kMASShortcutModifierFlags]; + [coder encodeInteger:(self.keyCode != NSNotFound ? (NSInteger)self.keyCode : - 1) forKey:MASShortcutKeyCode]; + [coder encodeInteger:(NSInteger)self.modifierFlags forKey:MASShortcutModifierFlags]; } - (id)initWithCoder:(NSCoder *)decoder { self = [super init]; if (self) { - NSInteger code = [decoder decodeIntegerForKey:kMASShortcutKeyCode]; + NSInteger code = [decoder decodeIntegerForKey:MASShortcutKeyCode]; self.keyCode = (code < 0 ? NSNotFound : (NSUInteger)code); - self.modifierFlags = [decoder decodeIntegerForKey:kMASShortcutModifierFlags]; + self.modifierFlags = [decoder decodeIntegerForKey:MASShortcutModifierFlags]; } return self; } @@ -232,19 +232,50 @@ NSString *const kMASShortcutModifierFlags = @"ModifierFlags"; return (self.modifierFlags == NSCommandKeyMask) && ([codeString isEqualToString:@"W"] || [codeString isEqualToString:@"Q"]); } +BOOL MASShortcutAllowsAnyHotkeyWithOptionModifier = NO; + ++ (void)setAllowsAnyHotkeyWithOptionModifier:(BOOL)allow +{ + MASShortcutAllowsAnyHotkeyWithOptionModifier = allow; +} + ++ (BOOL)allowsAnyHotkeyWithOptionModifier +{ + return MASShortcutAllowsAnyHotkeyWithOptionModifier; +} + - (BOOL)isValid { - BOOL hasFlags = (_modifierFlags > 0); - BOOL hasCommand = ((_modifierFlags & NSCommandKeyMask) > 0); - BOOL hasControl = ((_modifierFlags & NSControlKeyMask) > 0); - BOOL hasOption = ((_modifierFlags & NSAlternateKeyMask) > 0); - BOOL isFunction = ((_keyCode == kVK_F1) || (_keyCode == kVK_F2) || (_keyCode == kVK_F3) || (_keyCode == kVK_F4) || - (_keyCode == kVK_F5) || (_keyCode == kVK_F6) || (_keyCode == kVK_F7) || (_keyCode == kVK_F8) || - (_keyCode == kVK_F9) || (_keyCode == kVK_F10) || (_keyCode == kVK_F11) || (_keyCode == kVK_F12) || - (_keyCode == kVK_F13) || (_keyCode == kVK_F14) || (_keyCode == kVK_F15) || (_keyCode == kVK_F16) || - (_keyCode == kVK_F17) || (_keyCode == kVK_F18) || (_keyCode == kVK_F19) || (_keyCode == kVK_F20)); - BOOL isSpecial = ((_keyCode == kVK_Space) || (_keyCode == kVK_Escape) || (_keyCode == kVK_Return)); - return ((hasFlags && (hasCommand || hasControl || (hasOption && isSpecial))) || isFunction); + // Allow any function key with any combination of modifiers + BOOL includesFunctionKey = ((_keyCode == kVK_F1) || (_keyCode == kVK_F2) || (_keyCode == kVK_F3) || (_keyCode == kVK_F4) || + (_keyCode == kVK_F5) || (_keyCode == kVK_F6) || (_keyCode == kVK_F7) || (_keyCode == kVK_F8) || + (_keyCode == kVK_F9) || (_keyCode == kVK_F10) || (_keyCode == kVK_F11) || (_keyCode == kVK_F12) || + (_keyCode == kVK_F13) || (_keyCode == kVK_F14) || (_keyCode == kVK_F15) || (_keyCode == kVK_F16) || + (_keyCode == kVK_F17) || (_keyCode == kVK_F18) || (_keyCode == kVK_F19) || (_keyCode == kVK_F20)); + if (includesFunctionKey) return YES; + + // Do not allow any other key without modifiers + BOOL hasModifierFlags = (_modifierFlags > 0); + if (!hasModifierFlags) return NO; + + // Allow any hotkey containing Control or Command modifier + BOOL includesCommand = ((_modifierFlags & NSCommandKeyMask) > 0); + BOOL includesControl = ((_modifierFlags & NSControlKeyMask) > 0); + if (includesCommand || includesControl) return YES; + + // Allow Option key only in selected cases + BOOL includesOption = ((_modifierFlags & NSAlternateKeyMask) > 0); + if (includesOption) { + + // Always allow Option-Space and Option-Escape because they do not have any bind system commands + if ((_keyCode == kVK_Space) || (_keyCode == kVK_Escape)) return YES; + + // Allow Option modifier with any key even if it will break the system binding + if ([[self class] allowsAnyHotkeyWithOptionModifier]) return YES; + } + + // The hotkey does not have any modifiers or violates system bindings + return NO; } - (BOOL)isKeyEquivalent:(NSString *)keyEquivalent flags:(NSUInteger)flags takenInMenu:(NSMenu *)menu error:(NSError **)outError |
