mirror of
https://github.com/gnustep/libs-gui.git
synced 2025-04-23 20:01:11 +00:00
Rewritten the keybinding engine
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gui/trunk@12735 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
9a3e9ff590
commit
85f076c0ad
2 changed files with 363 additions and 189 deletions
|
@ -1,13 +1,10 @@
|
|||
/* -*-objc-*-
|
||||
NSInputManager.h
|
||||
|
||||
Copyright (C) 2001 Free Software Foundation, Inc.
|
||||
|
||||
Author: Fred Kiefer <FredKiefer@gmx.de>
|
||||
Date: August 2001
|
||||
Copyright (C) 2001, 2002 Free Software Foundation, Inc.
|
||||
|
||||
Author: Nicola Pero <n.pero@mi.flashnet.it>
|
||||
Date: December 2001
|
||||
Date: December 2001, February 2002
|
||||
|
||||
This file is part of the GNUstep GUI Library.
|
||||
|
||||
|
@ -57,37 +54,76 @@
|
|||
- (void) insertText: (id)aString;
|
||||
@end
|
||||
|
||||
struct _GSInputManagerBinding
|
||||
{
|
||||
/* The character this binding is about. */
|
||||
unichar character;
|
||||
|
||||
/* The character is bound to different selectors according to the
|
||||
various modifiers which can be used with the character.
|
||||
|
||||
There are eight selectors for the eight possibilities - each of
|
||||
NSShiftKeyMask, NSControlKeyMask, NSAlternateKeyMask might be on
|
||||
or off and each combination gives a different selector.
|
||||
|
||||
The index of the selector to use is given by
|
||||
|
||||
(modifiers & (NSShiftKeyMask | NSControlKeyMask | NSAlternateKeyMask)) / 2
|
||||
|
||||
a NULL selector means use the default action */
|
||||
SEL selector[8];
|
||||
};
|
||||
|
||||
/* The input manager understands quite sophisticated keybindings.
|
||||
*
|
||||
* A certain keystroke (represented by a unichar + some modifiers) can
|
||||
* be bound to a selector. For example: "Control-f" = "moveForward:";
|
||||
* If you press Control-f, the selector moveForward: is invoked.
|
||||
*
|
||||
* A certain keystroke can be bound to an array of selectors. For
|
||||
* example: "Control-k" = ("moveToBeginningOfLine:", "deleteToEndOfLine:");
|
||||
* If you press Control-k, the selector moveToBeginningOfLine: is invoked,
|
||||
* immediately followed by deleteToEndOfLine:.
|
||||
*
|
||||
* A certain keystroke can be bound to a dictionary of other
|
||||
* keybindings. For example "Control-c" = { "Control-f" =
|
||||
* "openFile:"; "Control-s" = "save:"; };
|
||||
* If you press Control-c followed by Control-f, openFile: is invoked;
|
||||
* if you press Control-c followed by Control-s, save: is invoked.
|
||||
*
|
||||
* Any keystroke which is not bound by a keybinding is basically inserted
|
||||
* as it is by calling 'insertText:' of the caller.
|
||||
*
|
||||
* Control-g is normally bound to aborting the current keybinding
|
||||
* sequence. Whenever you are confused about what the hell you have
|
||||
* typed and what strange command the input manager is going to
|
||||
* understand, just type Control-g to discard past pending keystrokes,
|
||||
* and reset the input manager.
|
||||
*
|
||||
* Control-q is normally bound to literally quoting the next
|
||||
* keystroke. That is, the next keystroke is *not* interpreted by the
|
||||
* input manager, but rather inserted literally into the text.
|
||||
*/
|
||||
|
||||
@class GSKeyBindingTable;
|
||||
|
||||
@interface NSInputManager: NSObject <NSTextInput>
|
||||
{
|
||||
/* The current client we are working for. */
|
||||
id _currentClient;
|
||||
|
||||
/* An array of bindings. */
|
||||
struct _GSInputManagerBinding *_bindings;
|
||||
|
||||
/* The size of the array. */
|
||||
int _bindingsCount;
|
||||
/* This is the basic, root set of bindings. Whenever the input
|
||||
manager detects that the current client has changed, it immediately
|
||||
resets the current key bindings to the root ones. If you are typing
|
||||
and are confused about what's happening, pressing Control-g always
|
||||
resets the bindings to the root bindings. */
|
||||
GSKeyBindingTable *_rootBindingTable;
|
||||
|
||||
/* These are the bindings which will be used to interpret the next
|
||||
keystroke. At the beginning, this is the same as the
|
||||
_rootBindingTable. But when you type a keystroke which is the
|
||||
beginning of a sequence of keystrokes producing a certain action,
|
||||
then the input manager updates the _currentBindingTable to be the
|
||||
table where he looks up the next keystroke you put in.
|
||||
*/
|
||||
GSKeyBindingTable *_currentBindingTable;
|
||||
|
||||
/* When we are reading multi-keystroke bindings, we need to remember
|
||||
the keystrokes we read thinking they were the beginning of a
|
||||
multi-keystroke binding ... just in case it turns out that they
|
||||
are not :-) */
|
||||
NSMutableArray *_pendingKeyEvents;
|
||||
|
||||
/* When it is YES, the next key stroke is interpreted literally rather
|
||||
than looked up using the _currentBindingTable. */
|
||||
BOOL _interpretNextKeyStrokeLiterally;
|
||||
|
||||
/* Extremely special keybinding which overrides any other keybinding
|
||||
in all contexts - abort - normally bound to Control-g. When we
|
||||
encounter this keystroke, we abort all pending keystrokes and
|
||||
reset ourselves immediately into vanilla root input state. */
|
||||
unichar _abortCharacter;
|
||||
int _abortFlags;
|
||||
}
|
||||
+ (NSInputManager *) currentInputManager;
|
||||
|
||||
|
@ -105,6 +141,41 @@ struct _GSInputManagerBinding
|
|||
- (BOOL) wantsToDelayTextChangeNotifications;
|
||||
- (BOOL) wantsToHandleMouseEvents;
|
||||
- (BOOL) wantsToInterpretAllKeystrokes;
|
||||
|
||||
/* GNUstep Extensions. */
|
||||
|
||||
/* Parses a key as found in a keybinding file.
|
||||
key is something like 'Control-f' or 'Control-Shift-LeftArrow'.
|
||||
Returns YES if the key could be parsed, NO if not. If the key
|
||||
could be parsed, character will contain the unichar, and modifiers
|
||||
the modifiers. */
|
||||
+ (BOOL) parseKey: (NSString *)key
|
||||
intoCharacter: (unichar *)character
|
||||
andModifiers: (int *)modifiers;
|
||||
|
||||
/* This is used to produce a key description which can be put into a
|
||||
keybinding file from an actual keystroke. The gnustep-gui never
|
||||
needs this :-) since it only reads keybinding files, never writes
|
||||
them, but Preferences applications might need it - they can have
|
||||
the user type in the desired keystroke, then call this method to
|
||||
turn the keystroke into a string which can be put in keybindings
|
||||
files. Pass 0 as modifiers if you only want the name of the
|
||||
keystroke, ignoring modifiers. */
|
||||
+ (NSString *) describeKeyStroke: (unichar)character
|
||||
withModifiers: (int)modifiers;
|
||||
|
||||
/* Methods used internally ... not really part of the public API, can change
|
||||
without notice. */
|
||||
|
||||
/* Reset the internal state. Normally bound to Control-g [regardless
|
||||
of context!], but also automatically done whenever the current
|
||||
client changes. */
|
||||
- (void) resetInternalState;
|
||||
|
||||
/* Quote the next key stroke. Normally bound to Control-q. */
|
||||
- (void) quoteNextKeyStroke;
|
||||
|
||||
|
||||
@end
|
||||
|
||||
#endif /* _GNUstep_H_NSInputManager */
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
/** <title>NSInputManager</title> -*-objc-*-
|
||||
/* NSInputManager -*-objc-*-
|
||||
|
||||
Copyright (C) 2001 Free Software Foundation, Inc.
|
||||
|
||||
Author: Nicola Pero <n.pero@mi.flashnet.it>
|
||||
Date: December 2001
|
||||
Date: December 2001, January 2002
|
||||
|
||||
This file is part of the GNUstep GUI Library.
|
||||
|
||||
|
@ -28,8 +28,11 @@
|
|||
#include <AppKit/NSInputServer.h>
|
||||
#include <AppKit/NSText.h>
|
||||
|
||||
#include "GSKeyBindingAction.h"
|
||||
#include "GSKeyBindingTable.h"
|
||||
|
||||
/* A table mapping character names to characters, used to interpret
|
||||
the character names found in KeyBindings dictionary files. */
|
||||
the character names found in KeyBindings dictionaries. */
|
||||
#define CHARACTER_TABLE_SIZE 77
|
||||
|
||||
static struct
|
||||
|
@ -124,7 +127,6 @@ character_table[CHARACTER_TABLE_SIZE] =
|
|||
|
||||
static NSInputManager *currentInputManager = nil;
|
||||
|
||||
|
||||
@implementation NSInputManager
|
||||
|
||||
+ (NSInputManager *) currentInputManager
|
||||
|
@ -137,24 +139,20 @@ static NSInputManager *currentInputManager = nil;
|
|||
return currentInputManager;
|
||||
}
|
||||
|
||||
- (void) bindKey: (NSString *)key toAction: (NSString *)action
|
||||
+ (BOOL) parseKey: (NSString *)key
|
||||
intoCharacter: (unichar *)character
|
||||
andModifiers: (int *)modifiers
|
||||
{
|
||||
/* First we try to parse the key into a character/flags couple */
|
||||
unichar character = 0;
|
||||
unsigned flags = 0;
|
||||
BOOL isFunctionKey = NO;
|
||||
/* Then we parse the action into a selector */
|
||||
SEL selector;
|
||||
|
||||
NSString *c;
|
||||
int flags = 0;
|
||||
unichar c = 0;
|
||||
|
||||
/* Parse the key: first break it into segments separated by - */
|
||||
NSArray *components = [key componentsSeparatedByString: @"-"];
|
||||
NSString *name;
|
||||
|
||||
/* Then, parse the modifiers. The modifiers are the components
|
||||
- all of them except the last one! */
|
||||
int i, count = [components count];
|
||||
int index;
|
||||
|
||||
for (i = 0; i < count - 1; i++)
|
||||
{
|
||||
|
@ -179,122 +177,109 @@ static NSInputManager *currentInputManager = nil;
|
|||
{
|
||||
flags |= NSShiftKeyMask;
|
||||
}
|
||||
else if ([modifier isEqualToString: @"NumericPad"]
|
||||
|| [modifier isEqualToString: @"Numeric"]
|
||||
|| [modifier isEqualToString: @"N"])
|
||||
{
|
||||
flags |= NSNumericPadKeyMask;
|
||||
}
|
||||
else
|
||||
{
|
||||
NSLog (@"NSInputManager - unknown modifier '%@' ignored", modifier);
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
/* The actual index in the little SEL table is the following one. */
|
||||
index = flags / 2;
|
||||
|
||||
/* Now, parse the actual key. */
|
||||
c = [components objectAtIndex: (count - 1)];
|
||||
name = [components objectAtIndex: (count - 1)];
|
||||
|
||||
if ([c isEqualToString: @""])
|
||||
if ([name isEqualToString: @""])
|
||||
{
|
||||
/* This happens if '-' was the character. */
|
||||
character = '-';
|
||||
c = '-';
|
||||
}
|
||||
else if ([c length] == 1)
|
||||
else if ([name length] == 1)
|
||||
{
|
||||
/* A single character, such as 'a'. */
|
||||
character = [c characterAtIndex: 0];
|
||||
c = [name characterAtIndex: 0];
|
||||
}
|
||||
else
|
||||
{
|
||||
/* A descriptive string, such as Tab or Home. */
|
||||
for (i = 0; i < CHARACTER_TABLE_SIZE; i++)
|
||||
{
|
||||
if ([c isEqualToString: (character_table[i]).name])
|
||||
if ([name isEqualToString: (character_table[i]).name])
|
||||
{
|
||||
character = (character_table[i]).character;
|
||||
isFunctionKey = YES;
|
||||
c = (character_table[i]).character;
|
||||
flags |= NSFunctionKeyMask;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == CHARACTER_TABLE_SIZE)
|
||||
{
|
||||
NSLog (@"NSInputManager - unknown character '%@' ignored", c);
|
||||
return;
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
if (character != NULL)
|
||||
{
|
||||
*character = c;
|
||||
}
|
||||
|
||||
if (modifiers != NULL)
|
||||
{
|
||||
*modifiers = flags;
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
+ (NSString *) describeKeyStroke: (unichar)character
|
||||
withModifiers: (int)modifiers
|
||||
{
|
||||
NSMutableString *description = [NSMutableString new];
|
||||
int i;
|
||||
|
||||
if (modifiers & NSCommandKeyMask)
|
||||
{
|
||||
[description appendString: @"Command-"];
|
||||
}
|
||||
|
||||
if (modifiers & NSControlKeyMask)
|
||||
{
|
||||
[description appendString: @"Control-"];
|
||||
}
|
||||
|
||||
if (modifiers & NSAlternateKeyMask)
|
||||
{
|
||||
[description appendString: @"Alternate-"];
|
||||
}
|
||||
|
||||
if (modifiers & NSShiftKeyMask)
|
||||
{
|
||||
[description appendString: @"Shift-"];
|
||||
}
|
||||
|
||||
if (modifiers & NSNumericPadKeyMask)
|
||||
{
|
||||
[description appendString: @"Numeric-"];
|
||||
}
|
||||
|
||||
for (i = 0; i < CHARACTER_TABLE_SIZE; i++)
|
||||
{
|
||||
if (character == ((character_table[i]).character))
|
||||
{
|
||||
[description appendString: character_table[i].name];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* "" as action means disable the keybinding. It can be used to override
|
||||
a previous keybinding. */
|
||||
if ([action isEqualToString: @""])
|
||||
if (i == CHARACTER_TABLE_SIZE)
|
||||
{
|
||||
selector = NULL;
|
||||
NSString *c = [NSString stringWithCharacters: &character length: 1];
|
||||
[description appendString: c];
|
||||
}
|
||||
else
|
||||
{
|
||||
selector = NSSelectorFromString (action);
|
||||
if (selector == NULL)
|
||||
{
|
||||
NSLog (@"NSInputManager: unknown selector '%@' ignored", action);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if there are already some bindings for this character. */
|
||||
for (i = 0; i < _bindingsCount; i++)
|
||||
{
|
||||
if (_bindings[i].character == character)
|
||||
{
|
||||
(_bindings[i]).selector[index] = selector;
|
||||
if (!isFunctionKey)
|
||||
{
|
||||
/* Not a function key - set the selector for the character
|
||||
with shift as well - we don't actually know if the character
|
||||
is typed with shift or not ! */
|
||||
flags |= NSShiftKeyMask;
|
||||
index = flags / 2;
|
||||
|
||||
(_bindings[i]).selector[index] = selector;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* Ok - allocate memory for the new binding. */
|
||||
if (_bindingsCount == 0)
|
||||
{
|
||||
_bindingsCount = 1;
|
||||
_bindings = objc_malloc (sizeof (struct _GSInputManagerBinding));
|
||||
}
|
||||
else
|
||||
{
|
||||
_bindingsCount++;
|
||||
_bindings = objc_realloc (_bindings,
|
||||
sizeof (struct _GSInputManagerBinding)
|
||||
* _bindingsCount);
|
||||
}
|
||||
_bindings[_bindingsCount - 1].character = character;
|
||||
|
||||
/* Set to NULL all selectors. */
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
(_bindings[_bindingsCount - 1]).selector[i] = NULL;
|
||||
}
|
||||
|
||||
/* Now save the selector. */
|
||||
(_bindings[_bindingsCount - 1]).selector[index] = selector;
|
||||
if (!isFunctionKey)
|
||||
{
|
||||
/* Not a function key - set the selector for the character
|
||||
with shift as well - we don't actually know if the character
|
||||
is typed with shift or not ! */
|
||||
flags |= NSShiftKeyMask;
|
||||
index = flags / 2;
|
||||
|
||||
(_bindings[_bindingsCount - 1]).selector[index] = selector;
|
||||
}
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
objc_free (_bindings);
|
||||
return;
|
||||
return description;
|
||||
}
|
||||
|
||||
- (void) loadBindingsFromFile: (NSString *)fullPath
|
||||
|
@ -302,8 +287,6 @@ static NSInputManager *currentInputManager = nil;
|
|||
NS_DURING
|
||||
{
|
||||
NSDictionary *bindings;
|
||||
NSEnumerator *e;
|
||||
NSString *key;
|
||||
|
||||
bindings = [NSDictionary dictionaryWithContentsOfFile: fullPath];
|
||||
if (bindings == nil)
|
||||
|
@ -311,12 +294,7 @@ static NSInputManager *currentInputManager = nil;
|
|||
[NSException raise];
|
||||
}
|
||||
|
||||
e = [bindings keyEnumerator];
|
||||
while ((key = [e nextObject]) != nil)
|
||||
{
|
||||
[self bindKey: key
|
||||
toAction: [bindings objectForKey: key]];
|
||||
}
|
||||
[_rootBindingTable loadBindingsFromDictionary: bindings];
|
||||
}
|
||||
NS_HANDLER
|
||||
{
|
||||
|
@ -363,6 +341,46 @@ static NSInputManager *currentInputManager = nil;
|
|||
|
||||
self = [super init];
|
||||
|
||||
_rootBindingTable = [GSKeyBindingTable new];
|
||||
|
||||
/* Read the abort key from the user defaults. */
|
||||
{
|
||||
NSString *abortKey = [defaults stringForKey: @"GSAbortKey"];
|
||||
|
||||
if (abortKey == nil)
|
||||
{
|
||||
_abortCharacter = 'g';
|
||||
_abortFlags = NSControlKeyMask;
|
||||
}
|
||||
else if (![NSInputManager parseKey: abortKey
|
||||
intoCharacter: &_abortCharacter
|
||||
andModifiers: &_abortFlags])
|
||||
{
|
||||
NSLog (@"Could not parse GSAbortKey - using Control-g");
|
||||
_abortCharacter = 'g';
|
||||
_abortFlags = NSControlKeyMask;
|
||||
}
|
||||
}
|
||||
|
||||
/* Read the quote key from the user defaults. */
|
||||
{
|
||||
NSString *quoteKey = [defaults stringForKey: @"GSQuoteKey"];
|
||||
GSKeyBindingActionQuoteNextKeyStroke *quoteAction;
|
||||
|
||||
quoteAction = [[GSKeyBindingActionQuoteNextKeyStroke alloc] init];
|
||||
|
||||
if (quoteKey == nil)
|
||||
{
|
||||
quoteKey = @"Control-q";
|
||||
}
|
||||
|
||||
[_rootBindingTable bindKey: quoteKey toAction: quoteAction];
|
||||
RELEASE (quoteAction);
|
||||
}
|
||||
|
||||
|
||||
/* FIXME all the following is gonna change. */
|
||||
|
||||
/* Normally, when we start up, we load all the keybindings we find
|
||||
in the following files, in this order:
|
||||
|
||||
|
@ -436,6 +454,13 @@ static NSInputManager *currentInputManager = nil;
|
|||
NSEvent *theEvent;
|
||||
NSEnumerator *eventEnum = [eventArray objectEnumerator];
|
||||
|
||||
/* If the client has changed, reset our internal state before going
|
||||
on. */
|
||||
if (client != _currentClient)
|
||||
{
|
||||
[self resetInternalState];
|
||||
}
|
||||
|
||||
_currentClient = client;
|
||||
|
||||
while ((theEvent = [eventEnum nextObject]) != nil)
|
||||
|
@ -446,73 +471,151 @@ static NSInputManager *currentInputManager = nil;
|
|||
unsigned flags = [theEvent modifierFlags] & (NSShiftKeyMask
|
||||
| NSAlternateKeyMask
|
||||
| NSControlKeyMask);
|
||||
BOOL done = NO;
|
||||
int i;
|
||||
|
||||
|
||||
if ([unmodifiedCharacters length] > 0)
|
||||
{
|
||||
character = [unmodifiedCharacters characterAtIndex: 0];
|
||||
}
|
||||
|
||||
|
||||
/* Look up the character in the keybindings dictionary. */
|
||||
for (i = 0; i < _bindingsCount; i++)
|
||||
if (!_interpretNextKeyStrokeLiterally)
|
||||
{
|
||||
if (_bindings[i].character == character)
|
||||
GSKeyBindingAction *action;
|
||||
GSKeyBindingTable *table;
|
||||
BOOL found;
|
||||
|
||||
/* 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)
|
||||
{
|
||||
SEL selector = (_bindings[i]).selector[flags / 2];
|
||||
[self resetInternalState];
|
||||
break;
|
||||
}
|
||||
|
||||
/* Look up the character in the current keybindings table. */
|
||||
found = [_currentBindingTable lookupKeyStroke: character
|
||||
modifiers: flags
|
||||
returningActionIn: &action
|
||||
tableIn: &table];
|
||||
|
||||
if (found)
|
||||
{
|
||||
if (action != nil)
|
||||
{
|
||||
/* First reset our internal state - we are done
|
||||
interpreting this keystroke sequence. */
|
||||
[self resetInternalState];
|
||||
|
||||
/* Then perform the action. The action might actually
|
||||
modify our internal state, which is why we reset it
|
||||
before calling the action! (for example, performing
|
||||
the action might cause us to interpret the next
|
||||
keystroke literally). */
|
||||
[action performActionWithInputManager: self];
|
||||
break;
|
||||
}
|
||||
else if (table != nil)
|
||||
{
|
||||
/* It's part of a composite multi-stroke
|
||||
keybinding. */
|
||||
_currentBindingTable = table;
|
||||
[_pendingKeyEvents addObject: theEvent];
|
||||
break;
|
||||
}
|
||||
/* Else it is as if we didn't find it! */
|
||||
}
|
||||
|
||||
/* Ok - the keybinding wasn't found. If we were tracking a
|
||||
multi-stroke keybinding, it means we were on a false
|
||||
track. */
|
||||
if ([_pendingKeyEvents count] > 0)
|
||||
{
|
||||
NSEvent *e;
|
||||
|
||||
/* Save the pending events locally in this stack
|
||||
frame. */
|
||||
NSMutableArray *a = _pendingKeyEvents;
|
||||
RETAIN (a);
|
||||
|
||||
if (selector == NULL)
|
||||
{
|
||||
/* Get out of loop with done = NO - we found the
|
||||
keybinding, but it was bound to the default
|
||||
action, so we stop searching and fall back on the
|
||||
default action. */
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
[self doCommandBySelector: selector];
|
||||
done = YES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Reset our internal state. */
|
||||
[self resetInternalState];
|
||||
|
||||
/* Take the very first event we received and which we
|
||||
tried to interpret as a key binding, which now we
|
||||
know was the wrong thing to do. */
|
||||
e = [a objectAtIndex: 0];
|
||||
|
||||
/* If not yet found, perform the default action. */
|
||||
if (!done)
|
||||
/* Interpret it literally, since interpreting it as a
|
||||
keybinding failed. */
|
||||
_interpretNextKeyStrokeLiterally = YES;
|
||||
[self handleKeyboardEvents: [NSArray arrayWithObject: e]
|
||||
client: client];
|
||||
|
||||
/* Now feed the remaining pending key events to
|
||||
ourselves for interpretation - again from
|
||||
scratch. */
|
||||
[a removeObjectAtIndex: 0];
|
||||
[a addObject: theEvent];
|
||||
|
||||
[self handleKeyboardEvents: a
|
||||
client: client];
|
||||
|
||||
RELEASE (a);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* We couldn't (or shouldn't) find the keybinding ... perform
|
||||
the default action - literally interpreting the
|
||||
keystroke. */
|
||||
|
||||
/* If this was a forced literal interpretation, make sure the
|
||||
next one is interpreted normally. */
|
||||
_interpretNextKeyStrokeLiterally = NO;
|
||||
|
||||
switch (character)
|
||||
{
|
||||
switch (character)
|
||||
case NSBackspaceCharacter:
|
||||
[self doCommandBySelector: @selector (deleteBackward:)];
|
||||
break;
|
||||
|
||||
case NSTabCharacter:
|
||||
if (flags & NSShiftKeyMask)
|
||||
{
|
||||
case NSBackspaceCharacter:
|
||||
[self doCommandBySelector: @selector (deleteBackward:)];
|
||||
break;
|
||||
|
||||
case NSTabCharacter:
|
||||
if (flags & NSShiftKeyMask)
|
||||
{
|
||||
[self doCommandBySelector: @selector (insertBacktab:)];
|
||||
}
|
||||
else
|
||||
{
|
||||
[self doCommandBySelector: @selector (insertTab:)];
|
||||
}
|
||||
break;
|
||||
|
||||
case NSEnterCharacter:
|
||||
case NSFormFeedCharacter:
|
||||
case NSCarriageReturnCharacter:
|
||||
[self doCommandBySelector: @selector (insertNewline:)];
|
||||
break;
|
||||
|
||||
default:
|
||||
[self insertText: characters];
|
||||
break;
|
||||
[self doCommandBySelector: @selector (insertBacktab:)];
|
||||
}
|
||||
else
|
||||
{
|
||||
[self doCommandBySelector: @selector (insertTab:)];
|
||||
}
|
||||
break;
|
||||
|
||||
case NSEnterCharacter:
|
||||
case NSFormFeedCharacter:
|
||||
case NSCarriageReturnCharacter:
|
||||
[self doCommandBySelector: @selector (insertNewline:)];
|
||||
break;
|
||||
|
||||
default:
|
||||
[self insertText: characters];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void) resetInternalState
|
||||
{
|
||||
_currentBindingTable = _rootBindingTable;
|
||||
ASSIGN (_pendingKeyEvents, [NSMutableArray array]);
|
||||
_interpretNextKeyStrokeLiterally = NO;
|
||||
}
|
||||
|
||||
- (void) quoteNextKeyStroke
|
||||
{
|
||||
_interpretNextKeyStrokeLiterally = YES;
|
||||
}
|
||||
|
||||
- (BOOL) handleMouseEvent: (NSEvent *)theMouseEvent
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue