diff --git a/Slate/Binding.h b/Slate/Binding.h index b51fe4cc..9e4cd8cd 100644 --- a/Slate/Binding.h +++ b/Slate/Binding.h @@ -29,6 +29,7 @@ UInt32 keyCode; UInt32 modifiers; NSNumber *modalKey; + UInt32 modalModifiers; EventHotKeyRef hotKeyRef; BOOL repeat; BOOL toggle; @@ -38,6 +39,7 @@ @property (assign) UInt32 keyCode; @property (assign) UInt32 modifiers; @property NSNumber *modalKey; +@property (assign) UInt32 modalModifiers; @property (assign) EventHotKeyRef hotKeyRef; @property (assign) BOOL repeat; @property (assign) BOOL toggle; diff --git a/Slate/Binding.m b/Slate/Binding.m index b8442fc6..b68a3105 100644 --- a/Slate/Binding.m +++ b/Slate/Binding.m @@ -34,6 +34,7 @@ @implementation Binding @synthesize keyCode; @synthesize modifiers; @synthesize modalKey; +@synthesize modalModifiers; @synthesize hotKeyRef; @synthesize repeat; @synthesize toggle; @@ -113,6 +114,7 @@ + (UInt32)modifierFromString:(NSString *)mod { + (NSArray *)getKeystrokeFromString:(NSString *)keystroke { NSNumber *theKeyCode = [NSNumber numberWithUnsignedInt:0]; UInt32 theModifiers = 0; + UInt32 theModalModifiers = 0; NSNumber *theModalKey = nil; NSArray *keyAndModifiers = [keystroke componentsSeparatedByString:COLON]; if ([keyAndModifiers count] >= 1) { @@ -132,7 +134,15 @@ + (NSArray *)getKeystrokeFromString:(NSString *)keystroke { while (mod) { NSNumber *_theModalKey = [[Binding asciiToCodeDict] objectForKey:mod]; if (_theModalKey != nil) { - theModalKey = _theModalKey; + if(theModalKey == nil) { + theModalKey = _theModalKey; + } else { + SlateLogger(@"Fatal: Two modal keys (codes %@ and %@) found in binding \"%@\"", theModalKey, _theModalKey, keystroke); + @throw([NSException exceptionWithName:@"Two Modal Keys" reason:[NSString stringWithFormat:@"Duplicate modal keys (%@ and %@) found in binding \"%@\"", theModalKey, _theModalKey, keystroke] userInfo:nil]); + } + } else if(theModalKey != nil) { + //Assume every modifier defined after a modal key to be a modifier for the modal key (to be pressed when entering modal mode) as opposed to the actual key + theModalModifiers = [Binding modifierFromString:mod]; } else { theModifiers += [Binding modifierFromString:mod]; } @@ -141,7 +151,7 @@ + (NSArray *)getKeystrokeFromString:(NSString *)keystroke { } } } - return [NSArray arrayWithObjects:theKeyCode, [NSNumber numberWithInteger:theModifiers], theModalKey, nil]; + return [NSArray arrayWithObjects:theKeyCode, [NSNumber numberWithInteger:theModifiers], theModalKey, [NSNumber numberWithInteger:theModalModifiers], nil]; } - (void)setKeystrokeFromString:(NSString*)keystroke { @@ -151,7 +161,8 @@ - (void)setKeystrokeFromString:(NSString*)keystroke { keyCode = [[keyarr objectAtIndex:0] unsignedIntValue]; modifiers = [[keyarr objectAtIndex:1] unsignedIntValue]; if ([keyarr count] >= 3 ) { - [self setModalKey:[keyarr objectAtIndex:2]]; + self.modalKey = [keyarr objectAtIndex:2]; + modalModifiers = [[keyarr objectAtIndex:3] unsignedIntValue]; } } if ([modalAndKey count] >= 3){ // modal toggle @@ -211,7 +222,7 @@ - (NSString *)modalHashKey { if ([self modalKey] == nil) { return nil; } - return [NSString stringWithFormat:@"%@%@%u", [self modalKey], PLUS, [self modifiers]]; + return [NSString stringWithFormat:@"%@%@%u", [self modalKey], PLUS, [self modalModifiers]]; } + (NSArray *)modalHashKeyToKeyAndModifiers:(NSString *)modalHashKey { diff --git a/Slate/SlateAppDelegate.m b/Slate/SlateAppDelegate.m index 791bd685..feb0e0de 100644 --- a/Slate/SlateAppDelegate.m +++ b/Slate/SlateAppDelegate.m @@ -242,7 +242,7 @@ - (OSStatus)activateBinding:(EventHotKeyID)hkCom isRepeat:(BOOL)isRepeat { EventHotKeyRef myHotKeyRef; myHotKeyID.signature = *[[NSString stringWithFormat:@"hotkey%li",i] cStringUsingEncoding:NSASCIIStringEncoding]; myHotKeyID.id = (UInt32)i; - RegisterEventHotKey([binding keyCode], 0, myHotKeyID, GetEventMonitorTarget(), 0, &myHotKeyRef); + RegisterEventHotKey([binding keyCode], [binding modifiers], myHotKeyID, GetEventMonitorTarget(), 0, &myHotKeyRef); [binding setHotKeyRef:myHotKeyRef]; [[self currentModalHotKeyRefs] addObject:[NSValue valueWithPointer:myHotKeyRef]]; i++; diff --git a/doc/directive-bind.md b/doc/directive-bind.md index 9fff7e68..c6c71f3f 100644 --- a/doc/directive-bind.md +++ b/doc/directive-bind.md @@ -26,11 +26,17 @@ bind key:modal-key operation parameter+ ## `modal-key` ## -`modal-key` is any one of the Allowed Keys. If using a `modal-key`, pressing that key will cause the Slate menu bar icon to change indicating modal mode is activated. then clicking `key` will activate the binding. Modal mode will remain active until `key` has been pressed or `modal-key` is pressed again. You may specify multiple bindings with the same `modal-key` as long as `key` is different. Also, `modal-key` can accompany a comma or semicolon separated list of modifier keys listed above. This will cause that entire keystroke to be considered the modal activation binding. For example: `bind 1:f4,ctrl,alt` will result in the modal keystroke being `ctrl+alt+f4`. After pressing that keystroke, modal mode will be activated and pressing `1` after that will activate the binding. +`modal-key` is any one of the Allowed Keys. If using a `modal-key`, pressing that key will cause the Slate menu bar icon to change indicating modal mode is activated. then clicking `key` will activate the binding. Modal mode will remain active until `key` has been pressed or `modal-key` is pressed again. + +You may specify multiple bindings with the same `modal-key` as long as `key` is different. + +Also, `modal-key` can accompany a comma or semicolon separated list of modifier keys (listed above). These modifier keys can either precede the `modal-key` (in which case they will apply to the `key` itself, in modal mode) or they can follow the `modal-key` (which will cause the entire keystroke, including modifiers, to be the modal activation binding). + +For example: `bind 1:f4,ctrl,alt` will result in the modal keystroke being `ctrl+alt+f4`. After pressing that keystroke, modal mode will be activated and pressing `1` after that will activate the binding, whereas `bind 1:ctrl,f4,alt` will result in the modal mode being activated with `alt+f4` and the action being triggered with `ctrl+1` (while modal mode is active). ### Modal Toggle Behavior ### -If you add `:toggle` to the end of a modal binding it will cause that binding to not end the modal mode. For example with the binding `1:ctrl,f4`, you press `ctrl+f4` and then press `1` to activate the binding. Once that binding is activated, modal mode will end and you have to press `ctrl+f4` again to activate it. However, with the binding `1:ctrl,f4:toggle` pressing `ctrl+f4` will toggle modal mode. pressing `1` will activate the binding but not end modal mode. To end modal mode, press `ctrl+f4` again or use the config `modalEscapeKey`. +If you add `:toggle` to the end of a modal binding it will cause that binding to not end the modal mode. For example with the binding `1:ctrl,f4`, you press `f4` and then press `ctrl+1` to activate the binding. Once that binding is activated, modal mode will end and you have to press `f4` again to activate it. However, with the binding `1:ctrl,f4:toggle` pressing `f4` will toggle modal mode. pressing `ctrl+1` will activate the binding but not end modal mode. To end modal mode, press `f4` again or use the config `modalEscapeKey`. ## `operation` ##