diff --git a/Source/GSKeyBindingTable.m b/Source/GSKeyBindingTable.m index 8e3074db0..9adb6ae99 100644 --- a/Source/GSKeyBindingTable.m +++ b/Source/GSKeyBindingTable.m @@ -46,10 +46,8 @@ { unichar character; int modifiers; - BOOL isFunctionKey; GSKeyBindingAction *a = nil; GSKeyBindingTable *t = nil; - BOOL noNeedToInsert = NO; int i; if (![NSInputManager parseKey: key @@ -60,16 +58,25 @@ return; } - /* If it is not a function key, we automatically bind the key both - with Shift and without (because we don't know if it's typed with - shift or without). */ - isFunctionKey = modifiers & NSFunctionKeyMask; + /* If it is not a function key, we automatically ignore the Shift + * modifier. You shouldn't use it unless you are describing a modification + * of a function key. The NSInputManager will ignore Shift modifiers + * as well for non-function keys. */ + if (modifiers & NSFunctionKeyMask) + { + /* Ignore all other modifiers when storing the keystroke modifiers. */ + modifiers = modifiers & (NSShiftKeyMask + | NSAlternateKeyMask + | NSControlKeyMask + | NSNumericPadKeyMask); + } + else + { + modifiers = modifiers & (NSAlternateKeyMask + | NSControlKeyMask + | NSNumericPadKeyMask); + } - /* Ignore all other modifiers when storing the keystroke modifiers. */ - modifiers = modifiers & (NSShiftKeyMask - | NSAlternateKeyMask - | NSControlKeyMask - | NSNumericPadKeyMask); /* Now build the associated action/table. */ if ([action isKindOfClass: [NSString class]]) @@ -110,98 +117,38 @@ /* Check if there are already some bindings for this keystroke. */ for (i = 0; i < _bindingsCount; i++) { - if (_bindings[i].character == character) + if ((_bindings[i].character == character) + && (_bindings[i].modifiers == modifiers)) { - /* Uhmm ... suspiciously similar. Let's check the - modifiers. */ - BOOL found = NO; - - if (isFunctionKey) - { - /* Function keys must have all modifiers perfectly the - same. */ - if (_bindings[i].modifiers == modifiers) - { - found = YES; - } - } - else - { - /* Non function keys might differ by a Shift. */ - int mask = ~NSShiftKeyMask; - - if ((_bindings[i].modifiers & mask) == (modifiers & mask)) - { - found = YES; - } - } - - if (found) - { - /* Replace/override the existing action/table with the - new ones. */ - RETAIN (a); - _bindings[i].action = a; - - RETAIN (t); - _bindings[i].table = t; - - noNeedToInsert = YES; - } + /* Replace/override the existing action/table with the new + ones. */ + ASSIGN (_bindings[i].action, a); + ASSIGN (_bindings[i].table, t); + return; } } - if (noNeedToInsert) - { - return; - } - /* Ok - allocate memory for the new binding. */ - { - int newKeyBindings; + if (_bindingsCount == 0) + { + _bindingsCount = 1; + _bindings = objc_malloc (sizeof (struct _GSKeyBinding)); + } + else + { + _bindingsCount++; + _bindings = objc_realloc (_bindings, sizeof (struct _GSKeyBinding) + * _bindingsCount); + } + _bindings[_bindingsCount - 1].character = character; + _bindings[_bindingsCount - 1].modifiers = modifiers; - if (isFunctionKey) - { - newKeyBindings = 1; - } - else - { - /* Need to allocate two, for the binding with and without - Shift. */ - newKeyBindings = 2; - } - - - if (_bindingsCount == 0) - { - _bindingsCount = newKeyBindings; - _bindings = objc_malloc (sizeof (struct _GSKeyBinding) - * newKeyBindings); - } - else - { - _bindingsCount += newKeyBindings; - _bindings = objc_realloc (_bindings, sizeof (struct _GSKeyBinding) - * _bindingsCount); - } - _bindings[_bindingsCount - 1].character = character; - _bindings[_bindingsCount - 1].modifiers = modifiers; - _bindings[_bindingsCount - 1].action = a; - RETAIN (a); - _bindings[_bindingsCount - 1].table = t; - RETAIN (t); - - if (!isFunctionKey) - { - modifiers |= NSShiftKeyMask; - _bindings[_bindingsCount - 2].character = character; - _bindings[_bindingsCount - 2].modifiers = modifiers; - _bindings[_bindingsCount - 2].action = a; - RETAIN (a); - _bindings[_bindingsCount - 2].table = t; - RETAIN (t); - } - } + /* Don't use ASSIGN here because that uses the previous value of + _bindings[_bindingsCount - 1] ... which is undefined. */ + _bindings[_bindingsCount - 1].action = a; + RETAIN (a); + _bindings[_bindingsCount - 1].table = t; + RETAIN (t); } - (BOOL) lookupKeyStroke: (unichar)character diff --git a/Source/NSInputManager.m b/Source/NSInputManager.m index 33a2aee7c..286bbc952 100644 --- a/Source/NSInputManager.m +++ b/Source/NSInputManager.m @@ -172,6 +172,10 @@ static NSInputManager *currentInputManager = nil; { flags |= NSAlternateKeyMask; } + /* The Shift modifier is only meaningful when used in + * conjunction with function keys. 'Shift-LeftArrow' is + * meaningful; 'Control-Shift-g' is not - you should use + * 'Control-G' instead. */ else if ([modifier isEqualToString: @"Shift"] || [modifier isEqualToString: @"S"]) { @@ -262,7 +266,7 @@ static NSInputManager *currentInputManager = nil; if (modifiers & NSNumericPadKeyMask) { - [description appendString: @"Numeric-"]; + [description appendString: @"NumericPad-"]; } for (i = 0; i < CHARACTER_TABLE_SIZE; i++) @@ -476,25 +480,47 @@ static NSInputManager *currentInputManager = nil; unichar character = 0; unsigned flags = [theEvent modifierFlags] & (NSShiftKeyMask | NSAlternateKeyMask - | NSControlKeyMask); + | NSControlKeyMask + | NSNumericPadKeyMask); + BOOL isFunctionKey = [theEvent modifierFlags] & NSFunctionKeyMask; if ([unmodifiedCharacters length] > 0) { character = [unmodifiedCharacters characterAtIndex: 0]; } - + if (!_interpretNextKeyStrokeLiterally) { GSKeyBindingAction *action; GSKeyBindingTable *table; BOOL found; + unsigned adaptedFlags; + + /* If the keystroke is a function key, then we need to use + * the full modifier flags to compare it against stored + * keybindings, so that we can make a difference for example + * between Shift-LeftArrow and LeftArrow. But if it's not a + * function key, then we should ignore the shift modifier - + * for example Control-g is a keystroke, and Control-G is + * another one. The shift modifier flag is not used to + * match these keystrokes - the fact that it's 'G' rather + * than 'g' already contains the fact that it's typed in + * with Shift. */ + if (!isFunctionKey) + { + adaptedFlags = flags & (~NSShiftKeyMask); + } + else + { + adaptedFlags = flags; + } /* Special keybinding recognized in all contexts - abort - normally bound to Control-g. The user is confused and wants to go home. Abort whatever train of thoughts we were following, discarding whatever pending keystrokes we have, and return into default state. */ - if (character == _abortCharacter && flags == _abortFlags) + if (character == _abortCharacter && adaptedFlags == _abortFlags) { [self resetInternalState]; break; @@ -502,7 +528,7 @@ static NSInputManager *currentInputManager = nil; /* Look up the character in the current keybindings table. */ found = [_currentBindingTable lookupKeyStroke: character - modifiers: flags + modifiers: adaptedFlags returningActionIn: &action tableIn: &table]; @@ -581,6 +607,13 @@ static NSInputManager *currentInputManager = nil; next one is interpreted normally. */ _interpretNextKeyStrokeLiterally = NO; + /* During literal interpretation, function keys are ignored. + Trying to insert 'PageUp' literally makes simply no sense. */ + if (isFunctionKey) + { + break; + } + switch (character) { case NSBackspaceCharacter: