NSInputManager - first implementation from scratch

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gui/trunk@11794 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Nicola Pero 2001-12-18 00:31:21 +00:00
parent 12f765491d
commit 0f1621859c
2 changed files with 521 additions and 40 deletions

View file

@ -1,4 +1,4 @@
/* -*-objc-*-
/* -*-objc-*-
NSInputManager.h
Copyright (C) 2001 Free Software Foundation, Inc.
@ -6,6 +6,9 @@
Author: Fred Kiefer <FredKiefer@gmx.de>
Date: August 2001
Author: Nicola Pero <n.pero@mi.flashnet.it>
Date: December 2001
This file is part of the GNUstep GUI Library.
This library is free software; you can redistribute it and/or
@ -28,6 +31,7 @@
#define _GNUstep_H_NSInputManager
#include <objc/Protocol.h>
#include <objc/objc.h>
#include <Foundation/NSGeometry.h>
#include <Foundation/NSArray.h>
#include <Foundation/NSAttributedString.h>
@ -37,9 +41,7 @@
@class NSImage;
@protocol NSTextInput
// Marking text
- (void) setMarkedText: (id)aString
selectedRange: (NSRange)selRange;
- (void) setMarkedText: (id)aString selectedRange: (NSRange)selRange;
- (BOOL) hasMarkedText;
- (NSRange) markedRange;
- (NSRange) selectedRange;
@ -55,25 +57,54 @@
- (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];
};
@interface NSInputManager: NSObject <NSTextInput>
{
id _currentClient;
/* An array of bindings. */
struct _GSInputManagerBinding *_bindings;
/* The size of the array. */
int _bindingsCount;
}
+ (NSInputManager *) currentInputManager;
+ (void) cycleToNextInputLanguage: (id)sender;
+ (void) cycleToNextInputServerInLanguage: (id)sender;
- (id) initWithName: (NSString *)inputServerName
host: (NSString *)hostName;
- (BOOL) handleMouseEvent: (NSEvent *)theMouseEvent;
- (NSImage *) image;
- (NSInputManager *) initWithName: (NSString *)inputServerName
host: (NSString *)hostName;
- (void) handleKeyboardEvents: (NSArray *)eventArray
client: (id)client;
- (NSString *) language;
- (NSString *) localizedInputManagerName;
- (void) markedTextAbandoned: (id)client;
- (void) markedTextSelectionChanged: (NSRange)newSel
client: (id)client;
- (NSInputServer *) server;
- (BOOL) wantsToDelayTextChangeNotifications;
- (BOOL) wantsToHandleMouseEvents;
- (BOOL) wantsToInterpretAllKeystrokes;
@end
#endif //_GNUstep_H_NSInputManager
#endif /* _GNUstep_H_NSInputManager */

View file

@ -2,8 +2,8 @@
Copyright (C) 2001 Free Software Foundation, Inc.
Author: Fred Kiefer <FredKiefer@gmx.de>
Date: August 2001
Author: Nicola Pero <n.pero@mi.flashnet.it>
Date: December 2001
This file is part of the GNUstep GUI Library.
@ -24,46 +24,498 @@
*/
#include <AppKit/NSEvent.h>
#include <AppKit/NSImage.h>
#include <AppKit/NSInputManager.h>
#include <AppKit/NSInputServer.h>
#include <AppKit/NSText.h>
/* A table mapping character names to characters, used to interpret
the character names found in KeyBindings dictionary files. */
#define CHARACTER_TABLE_SIZE 77
static struct
{
NSString *name;
unichar character;
}
character_table[CHARACTER_TABLE_SIZE] =
{
/* Function keys. */
{ @"UpArrow", NSUpArrowFunctionKey },
{ @"DownArrow", NSDownArrowFunctionKey },
{ @"LeftArrow", NSLeftArrowFunctionKey },
{ @"RightArrow", NSRightArrowFunctionKey },
{ @"F1", NSF1FunctionKey },
{ @"F2", NSF2FunctionKey },
{ @"F3", NSF3FunctionKey },
{ @"F4", NSF4FunctionKey },
{ @"F5", NSF5FunctionKey },
{ @"F6", NSF6FunctionKey },
{ @"F7", NSF7FunctionKey },
{ @"F8", NSF8FunctionKey },
{ @"F9", NSF9FunctionKey },
{ @"F10", NSF10FunctionKey },
{ @"F11", NSF11FunctionKey },
{ @"F12", NSF12FunctionKey },
{ @"F13", NSF13FunctionKey },
{ @"F14", NSF14FunctionKey },
{ @"F15", NSF15FunctionKey },
{ @"F16", NSF16FunctionKey },
{ @"F17", NSF17FunctionKey },
{ @"F18", NSF18FunctionKey },
{ @"F19", NSF19FunctionKey },
{ @"F20", NSF20FunctionKey },
{ @"F21", NSF21FunctionKey },
{ @"F22", NSF22FunctionKey },
{ @"F23", NSF23FunctionKey },
{ @"F24", NSF24FunctionKey },
{ @"F25", NSF25FunctionKey },
{ @"F26", NSF26FunctionKey },
{ @"F27", NSF27FunctionKey },
{ @"F28", NSF28FunctionKey },
{ @"F29", NSF29FunctionKey },
{ @"F30", NSF30FunctionKey },
{ @"F31", NSF31FunctionKey },
{ @"F32", NSF32FunctionKey },
{ @"F33", NSF33FunctionKey },
{ @"F34", NSF34FunctionKey },
{ @"F35", NSF35FunctionKey },
{ @"Insert", NSInsertFunctionKey },
{ @"Delete", NSDeleteFunctionKey },
{ @"Home", NSHomeFunctionKey },
{ @"Begin", NSBeginFunctionKey },
{ @"End", NSEndFunctionKey },
{ @"PageUp", NSPageUpFunctionKey },
{ @"PageDown", NSPageDownFunctionKey },
{ @"PrintScreen", NSPrintScreenFunctionKey },
{ @"ScrollLock", NSScrollLockFunctionKey },
{ @"Pause", NSPauseFunctionKey },
{ @"SysReq", NSSysReqFunctionKey },
{ @"Break", NSBreakFunctionKey },
{ @"Reset", NSResetFunctionKey },
{ @"Stop", NSStopFunctionKey },
{ @"Menu", NSMenuFunctionKey },
{ @"User", NSUserFunctionKey },
{ @"System", NSSystemFunctionKey },
{ @"Print", NSPrintFunctionKey },
{ @"ClearLine", NSClearLineFunctionKey },
{ @"ClearDisplay", NSClearDisplayFunctionKey },
{ @"InsertLine", NSInsertLineFunctionKey },
{ @"DeleteLine", NSDeleteLineFunctionKey },
{ @"InsertChar", NSInsertCharFunctionKey },
{ @"DeleteChar", NSDeleteCharFunctionKey },
{ @"Prev", NSPrevFunctionKey },
{ @"Next", NSNextFunctionKey },
{ @"Select", NSSelectFunctionKey },
{ @"Execute", NSExecuteFunctionKey },
{ @"Undo", NSUndoFunctionKey },
{ @"Redo", NSRedoFunctionKey },
{ @"Find", NSFindFunctionKey },
{ @"Help", NSHelpFunctionKey },
{ @"ModeSwitch", NSModeSwitchFunctionKey },
/* Special characters by name. Useful if you want, for example,
to associate some special action to C-Tab or similar evils. */
{ @"Backspace", NSBackspaceCharacter },
{ @"Tab", NSTabCharacter },
{ @"Enter", NSEnterCharacter },
{ @"FormFeed", NSFormFeedCharacter },
{ @"CarriageReturn", NSCarriageReturnCharacter }
};
static NSInputManager *currentInputManager = nil;
@implementation NSInputManager
// Class methods
+ (NSInputManager *) currentInputManager
{
return nil;
if (currentInputManager == nil)
{
currentInputManager = [[self alloc] initWithName: nil host: nil];
}
return currentInputManager;
}
+ (void) cycleToNextInputLanguage: (id)sender
{}
- (void) bindKey: (NSString *)key toAction: (NSString *)action
{
/* 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;
+ (void) cycleToNextInputServerInLanguage: (id)sender
{}
NSString *c;
/* Parse the key: first break it into segments separated by - */
NSArray *components = [key componentsSeparatedByString: @"-"];
/* 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++)
{
NSString *modifier = [components objectAtIndex: i];
if ([modifier isEqualToString: @"Control"]
|| [modifier isEqualToString: @"Ctrl"]
|| [modifier isEqualToString: @"C"])
{
flags |= NSControlKeyMask;
}
else if ([modifier isEqualToString: @"Alternate"]
|| [modifier isEqualToString: @"Alt"]
|| [modifier isEqualToString: @"A"]
|| [modifier isEqualToString: @"Meta"]
|| [modifier isEqualToString: @"M"])
{
flags |= NSAlternateKeyMask;
}
else if ([modifier isEqualToString: @"Shift"]
|| [modifier isEqualToString: @"S"])
{
flags |= NSShiftKeyMask;
}
else
{
NSLog (@"NSInputManager - unknown modifier '%@' ignored", modifier);
}
}
/* 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)];
if ([c isEqualToString: @""])
{
/* This happens if '-' was the character. */
character = '-';
}
else if ([c length] == 1)
{
/* A single character, such as 'a'. */
character = [c 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])
{
character = (character_table[i]).character;
isFunctionKey = YES;
break;
}
}
if (i == CHARACTER_TABLE_SIZE)
{
NSLog (@"NSInputManager - unknown character '%@' ignored", c);
return;
}
}
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;
}
- (void) loadBindingsFromFile: (NSString *)fullPath
{
NS_DURING
{
NSDictionary *bindings;
NSEnumerator *e;
NSString *key;
bindings = [NSDictionary dictionaryWithContentsOfFile: fullPath];
if (bindings == nil)
{
[NSException raise];
}
e = [bindings keyEnumerator];
while ((key = [e nextObject]) != nil)
{
[self bindKey: key
toAction: [bindings objectForKey: key]];
}
}
NS_HANDLER
{
NSLog (@"Unable to load KeyBindings from file %@", fullPath);
}
NS_ENDHANDLER
}
- (void) loadBindingsWithName: (NSString *)fileName
{
NSArray *paths;
NSEnumerator *enumerator;
NSString *bundlePath;
paths = NSSearchPathForDirectoriesInDomains (GSLibrariesDirectory,
NSAllDomainsMask, YES);
/* paths are in the order - user, network, local, root. Instead we
want to load keybindings in the order root, local, network, user
- so that user can override root - for this reason we use a
reverseObjectEnumerator. */
enumerator = [paths reverseObjectEnumerator];
while ((bundlePath = [enumerator nextObject]) != nil)
{
NSBundle *bundle = [NSBundle bundleWithPath: bundlePath];
NSString *fullPath = [bundle pathForResource: fileName
ofType: @"dict"
inDirectory: @"KeyBindings"];
if (fullPath != nil)
{
[self loadBindingsFromFile: fullPath];
}
}
}
- (NSInputManager *) initWithName: (NSString *)inputServerName
host: (NSString *)hostName
host: (NSString *)hostName
{
return nil;
NSString *defaultKeyBindings;
NSArray *customKeyBindings;
NSUserDefaults *defaults;
CREATE_AUTORELEASE_POOL (pool);
defaults = [NSUserDefaults standardUserDefaults];
self = [super init];
/* Normally, when we start up, we load all the keybindings we find
in the following files, in this order:
$GNUSTEP_SYSTEM_ROOT/Libraries/Resources/KeyBindings/DefaultKeyBindings.dict
$GNUSTEP_LOCAL_ROOT/Libraries/Resources/KeyBindings/DefaultKeyBindings.dict
$GNUSTEP_NETWORK_ROOT/Libraries/Resources/KeyBindings/DefaultKeyBindings.dict
$GNUSTEP_USER_ROOT/Libraries/Resources/KeyBindings/DefaultKeyBindings.dict
This gives you a first way of adding your customized keybindings
- adding a DefaultKeyBindings.dict to your GNUSTEP_USER_ROOT, and
putting additional keybindings in there. This allows you to add
new keybindings to the standard ones, or override standard ones
with your own. These keybindings are normally used by all your
applications (this is why they are in 'DefaultKeyBindings').
In addition, you can specify a list of additional key bindings
files to be loaded by setting the GSCustomKeyBindings default to
an array of file names. We will attempt to load all those
keybindings in a way similar to what we do with the
DefaultKeyBindings. We load them after the default ones, in the
order you specify. This allows you to have application-specific
keybindings, where you put different keybindings in different
files, and run different applications with different
GSCustomKeyBindings, telling them to use different keybindings
files.
Last, in special cases you might want to have the
DefaultKeybindings totally ignored. In this case, you set the
GSDefaultKeyBindings variable to a different filename (different
from 'DefaultKeybindings'). We attempt to load all keybindings
stored in the files with that name where we normally would load
DefaultKeybindings. */
/* First, load the DefaultKeyBindings. */
defaultKeyBindings = [defaults stringForKey: @"GSDefaultKeyBindings"];
if (defaultKeyBindings == nil)
{
defaultKeyBindings = @"DefaultKeyBindings";
}
[self loadBindingsWithName: defaultKeyBindings];
/* Then, if any, the CustomKeyBindings, in the specified order. */
customKeyBindings = [defaults arrayForKey: @"GSCustomKeyBindings"];
if (customKeyBindings != nil)
{
int i, count = [customKeyBindings count];
Class string = [NSString class];
for (i = 0; i < count; i++)
{
NSString *filename = [customKeyBindings objectAtIndex: i];
if ([filename isKindOfClass: string])
{
[self loadBindingsWithName: filename];
}
}
}
RELEASE (pool);
return self;
}
- (void) handleKeyboardEvents: (NSArray *)eventArray
client: (id)client
{
NSEvent *theEvent;
NSEnumerator *eventEnum = [eventArray objectEnumerator];
_currentClient = client;
while ((theEvent = [eventEnum nextObject]) != nil)
{
NSString *characters = [theEvent characters];
NSString *unmodifiedCharacters = [theEvent charactersIgnoringModifiers];
unichar character = 0;
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 (_bindings[i].character == character)
{
SEL selector = (_bindings[i]).selector[flags / 2];
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;
}
}
}
/* If not yet found, perform the default action. */
if (!done)
{
switch (character)
{
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;
}
}
}
}
- (BOOL) handleMouseEvent: (NSEvent *)theMouseEvent
{
return NO;
}
- (NSImage *) image
{
return nil;
}
- (NSString *) language
{
return nil;
return @"English";
}
- (NSString *) localizedInputManagerName
{
return nil;
@ -73,14 +525,9 @@
{}
- (void) markedTextSelectionChanged: (NSRange)newSel
client: (id)client
client: (id)client
{}
- (NSInputServer *) server
{
return nil;
}
- (BOOL) wantsToDelayTextChangeNotifications
{
return NO;
@ -96,7 +543,6 @@
return NO;
}
// NSTextInput protocol
- (void) setMarkedText: (id)aString
selectedRange: (NSRange)selRange
{}
@ -108,12 +554,12 @@
- (NSRange) markedRange
{
return NSMakeRange(NSNotFound, 0);
return NSMakeRange (NSNotFound, 0);
}
- (NSRange) selectedRange
{
return NSMakeRange(NSNotFound, 0);
return NSMakeRange (NSNotFound, 0);
}
- (void) unmarkText
@ -140,7 +586,9 @@
}
- (void) doCommandBySelector: (SEL)aSelector
{}
{
[_currentClient doCommandBySelector: aSelector];
}
- (NSRect) firstRectForCharacterRange: (NSRange)theRange
{
@ -148,6 +596,8 @@
}
- (void) insertText: (id)aString
{}
{
[_currentClient insertText: aString];
}
@end