mirror of
https://github.com/gnustep/libs-gui.git
synced 2025-04-23 06:51:44 +00:00
New file used by the new key binding engine
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gui/trunk@12733 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
7224c000f8
commit
59dcc3e891
4 changed files with 562 additions and 0 deletions
92
Source/GSKeyBindingAction.h
Normal file
92
Source/GSKeyBindingAction.h
Normal file
|
@ -0,0 +1,92 @@
|
|||
/* GSKeyBindingAction.h -*-objc-*-
|
||||
|
||||
Copyright (C) 2002 Free Software Foundation, Inc.
|
||||
|
||||
Author: Nicola Pero <n.pero@mi.flashnet.it>
|
||||
Date: February 2002
|
||||
|
||||
This file is part of the GNUstep GUI Library.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; see the file COPYING.LIB.
|
||||
If not, write to the Free Software Foundation,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef _GS_KEYBINDING_ACTION_H
|
||||
#define _GS_KEYBINDING_ACTION_H
|
||||
|
||||
#include <Foundation/Foundation.h>
|
||||
|
||||
@class NSInputManager;
|
||||
|
||||
/* A GSKeyBindingAction represents a special action to perform. This
|
||||
* action can be bound to any sequence of keystrokes. When the
|
||||
* approrpriate sequence of keystrokes is read from the keyboard, the
|
||||
* GSKeyBindingAction object is retrieved, and it is executed. Once
|
||||
* the action object is performed, all the keystrokes which caused the
|
||||
* action to be performed are forgotten. Normally, we store into
|
||||
* action objects only actions which we want to be able to store in
|
||||
* our complicated keybinding tables ... so the default action of
|
||||
* inserting a keystroke into the text is not stored into an action
|
||||
* object.
|
||||
*/
|
||||
@interface GSKeyBindingAction: NSObject
|
||||
{}
|
||||
/* To execute the action, call the following method. The
|
||||
* implementation of the GSKeyBindingAction class does nothing -
|
||||
* actually, it raises an exception. Subclasses should implement this
|
||||
* to do what they need - in the implementation they can call any
|
||||
* methods of the input manager, to execute selectors (by calling
|
||||
* doCommandBySelector: one or multiple times), or to influence the
|
||||
* interpretation of further keystrokes (by modifying the input
|
||||
* manager context) - for example to cause the next keystroke to be
|
||||
* quoted (inserted literally into the text), or the next action to be
|
||||
* repeated N times [or, conceptually, also stuff like starting/ending
|
||||
* the recording of a keyboard macro, even if we don't need that].
|
||||
*/
|
||||
- (void) performActionWithInputManager: (NSInputManager *)manager;
|
||||
@end
|
||||
|
||||
|
||||
/* This subclass represents a keybinding where the keystroke is bound
|
||||
* to a single selector. */
|
||||
@interface GSKeyBindingActionSelector : GSKeyBindingAction
|
||||
{
|
||||
SEL _selector;
|
||||
}
|
||||
- (id) initWithSelectorName: (NSString *)sel;
|
||||
@end
|
||||
|
||||
|
||||
/* This subclass represents a keybinding where the keystroke is bound
|
||||
* to an array of selectors. */
|
||||
@interface GSKeyBindingActionSelectorArray : GSKeyBindingAction
|
||||
{
|
||||
/* Array of selectors. */
|
||||
SEL *_selectors;
|
||||
|
||||
/* Lenght of the array of selectors. */
|
||||
int _selectorsCount;
|
||||
}
|
||||
- (id) initWithSelectorNames: (NSArray *)sels;
|
||||
@end
|
||||
|
||||
|
||||
/* This subclass represents the action of quoting literally the next
|
||||
* keystroke. It is normally bound to Control-q. */
|
||||
@interface GSKeyBindingActionQuoteNextKeyStroke : GSKeyBindingAction
|
||||
{}
|
||||
@end
|
||||
|
||||
#endif _GS_KEYBINDING_ACTION_H
|
107
Source/GSKeyBindingAction.m
Normal file
107
Source/GSKeyBindingAction.m
Normal file
|
@ -0,0 +1,107 @@
|
|||
/* GSKeyBindingAction.m -*-objc-*-
|
||||
|
||||
Copyright (C) 2002 Free Software Foundation, Inc.
|
||||
|
||||
Author: Nicola Pero <n.pero@mi.flashnet.it>
|
||||
Date: February 2002
|
||||
|
||||
This file is part of the GNUstep GUI Library.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; see the file COPYING.LIB.
|
||||
If not, write to the Free Software Foundation,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "GSKeyBindingAction.h"
|
||||
#include <AppKit/NSInputManager.h>
|
||||
|
||||
@implementation GSKeyBindingAction
|
||||
- (void) performActionWithInputManager: (NSInputManager *)manager
|
||||
{
|
||||
[self subclassResponsibility: _cmd];
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
@implementation GSKeyBindingActionSelector
|
||||
- (id) initWithSelectorName: (NSString *)sel
|
||||
{
|
||||
_selector = NSSelectorFromString (sel);
|
||||
|
||||
if (_selector == NULL)
|
||||
{
|
||||
DESTROY (self);
|
||||
return nil;
|
||||
}
|
||||
|
||||
return [super init];
|
||||
}
|
||||
|
||||
- (void) performActionWithInputManager: (NSInputManager *)manager
|
||||
{
|
||||
[manager doCommandBySelector: _selector];
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
@implementation GSKeyBindingActionSelectorArray
|
||||
- (id) initWithSelectorNames: (NSArray *)sels
|
||||
{
|
||||
int i;
|
||||
|
||||
_selectorsCount = [sels count];
|
||||
|
||||
_selectors = objc_malloc (sizeof (SEL) * _selectorsCount);
|
||||
|
||||
for (i = 0; i < _selectorsCount; i++)
|
||||
{
|
||||
NSString *name = [sels objectAtIndex: i];
|
||||
|
||||
_selectors[i] = NSSelectorFromString (name);
|
||||
|
||||
if (_selectors[i] == NULL)
|
||||
{
|
||||
/* DESTROY (self) will dealloc the selectors array. */
|
||||
DESTROY (self);
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
return [super init];
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
objc_free (_selectors);
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void) performActionWithInputManager: (NSInputManager *)manager
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < _selectorsCount; i++)
|
||||
{
|
||||
[manager doCommandBySelector: _selectors[i]];
|
||||
}
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
@implementation GSKeyBindingActionQuoteNextKeyStroke
|
||||
- (void) performActionWithInputManager: (NSInputManager *)manager
|
||||
{
|
||||
[manager quoteNextKeyStroke];
|
||||
}
|
||||
@end
|
111
Source/GSKeyBindingTable.h
Normal file
111
Source/GSKeyBindingTable.h
Normal file
|
@ -0,0 +1,111 @@
|
|||
/* GSKeyBindingTable -*-objc-*-
|
||||
|
||||
Copyright (C) 2002 Free Software Foundation, Inc.
|
||||
|
||||
Author: Nicola Pero <n.pero@mi.flashnet.it>
|
||||
Date: February 2002
|
||||
|
||||
This file is part of the GNUstep GUI Library.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; see the file COPYING.LIB.
|
||||
If not, write to the Free Software Foundation,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef _GS_KEYBINDING_TABLE_H
|
||||
#define _GS_KEYBINDING_TABLE_H
|
||||
|
||||
#include "GSKeyBindingAction.h"
|
||||
|
||||
@class GSKeyBindingTable;
|
||||
|
||||
/* A struct _GSKeyBinding describes how to interpret a single
|
||||
* keystroke. It binds a keystroke to an action (when that keystroke
|
||||
* is read, the action is performed), or to a further table of
|
||||
* bindings of keystrokes to actions, to be used to interpret the next
|
||||
* keystroke.
|
||||
*
|
||||
* The table is used in the case of multi-stroke bindings, such as
|
||||
* Control-x followed by Control-s. In this case, Control-x will
|
||||
* point to a secondary table of keystrokes, which contains Control-s,
|
||||
* which binds it to the required action.
|
||||
*/
|
||||
struct _GSKeyBinding
|
||||
{
|
||||
/* The character this binding is about. */
|
||||
unichar character;
|
||||
|
||||
/* The modifier for the binding. Might be a combination of
|
||||
* NSShiftKeyMask, NSControlKeyMask, NSAlternateKeyMask,
|
||||
* NSNumericPadKeyMask.
|
||||
*/
|
||||
int modifiers;
|
||||
|
||||
/* The action, or NULL if there's no action associated. NB - the action
|
||||
* is retained here. */
|
||||
GSKeyBindingAction *action;
|
||||
|
||||
/* A further table of _GSKeyBinding to be used to interpret the next
|
||||
keystroke, or NULL if this is a 'leaf' keybinding. NB - the
|
||||
table is retained here. */
|
||||
GSKeyBindingTable *table;
|
||||
|
||||
/* Both action and table might be NULL if this is a keybinding which
|
||||
has been disabled. In that case, it's ignored. */
|
||||
};
|
||||
|
||||
|
||||
/* This class can manage a table of keybindings (that is, a table of
|
||||
* _GSKeyBinding objects). It can add and remove them, and it can
|
||||
* look up a keystroke into the table, and return the associated action,
|
||||
* or a GSKeyBindingTable object which can be used to process further
|
||||
* keystrokes, for multi-stroke keybindings.
|
||||
*/
|
||||
@interface GSKeyBindingTable : NSObject
|
||||
{
|
||||
/* The array of bindings. */
|
||||
struct _GSKeyBinding *_bindings;
|
||||
|
||||
/* The length of the array of bindings. */
|
||||
int _bindingsCount;
|
||||
}
|
||||
/* Load all the bindings from this dictionary. The dictionary binds
|
||||
keys to actions, as described below under bindKey:toAction:. The
|
||||
DefaultKeyBindings.dict file is an example of such a
|
||||
dictionary. */
|
||||
- (void) loadBindingsFromDictionary: (NSDictionary *)dict;
|
||||
|
||||
/* Bind a specific key [must be a string, representing a keystroke] to
|
||||
* a specific action, which can be a string for a selector; an array
|
||||
* of strings for an array of selectors; a dictionary if the key is
|
||||
* just the prefix to a further array of keybindings; a
|
||||
* GSKeyBindingAction for a specific prebuilt action object [this is
|
||||
* normally used by the NSInputManager to bind very special actions
|
||||
* such as Control-q (interpret literally next keystroke)].
|
||||
*/
|
||||
- (void) bindKey: (NSString *)key toAction: (id)action;
|
||||
|
||||
/* The input manager calls this when it wants to look up a keybinding
|
||||
* in the table. The method returns YES if the keybinding is in the
|
||||
* table, or NO if it's not. If it is in the table, it returns the
|
||||
* action (or nil if none), and the further keybinding table (or nil
|
||||
* if none) to use for interpreting the next keystrokes. */
|
||||
- (BOOL) lookupKeyStroke: (unichar)character
|
||||
modifiers: (int)flags
|
||||
returningActionIn: (GSKeyBindingAction **)action
|
||||
tableIn: (GSKeyBindingTable **)table;
|
||||
|
||||
@end
|
||||
|
||||
#endif /* _GS_KEYBINDING_TABLE_H */
|
252
Source/GSKeyBindingTable.m
Normal file
252
Source/GSKeyBindingTable.m
Normal file
|
@ -0,0 +1,252 @@
|
|||
/* GSKeyBindingTable.m -*-objc-*-
|
||||
|
||||
Copyright (C) 2002 Free Software Foundation, Inc.
|
||||
|
||||
Author: Nicola Pero <n.pero@mi.flashnet.it>
|
||||
Date: February 2002
|
||||
|
||||
This file is part of the GNUstep GUI Library.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; see the file COPYING.LIB.
|
||||
If not, write to the Free Software Foundation,
|
||||
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "GSKeyBindingAction.h"
|
||||
#include "GSKeyBindingTable.h"
|
||||
#include <AppKit/NSInputManager.h>
|
||||
#include <AppKit/NSEvent.h>
|
||||
|
||||
@implementation GSKeyBindingTable : NSObject
|
||||
|
||||
- (void) loadBindingsFromDictionary: (NSDictionary *)dict
|
||||
{
|
||||
NSEnumerator *e;
|
||||
NSString *key;
|
||||
|
||||
e = [dict keyEnumerator];
|
||||
while ((key = [e nextObject]) != nil)
|
||||
{
|
||||
[self bindKey: key toAction: [dict objectForKey: key]];
|
||||
}
|
||||
}
|
||||
|
||||
- (void) bindKey: (NSString *)key toAction: (id)action
|
||||
{
|
||||
unichar character;
|
||||
int modifiers;
|
||||
BOOL isFunctionKey;
|
||||
GSKeyBindingAction *a = nil;
|
||||
GSKeyBindingTable *t = nil;
|
||||
BOOL noNeedToInsert = NO;
|
||||
int i;
|
||||
|
||||
if (![NSInputManager parseKey: key
|
||||
intoCharacter: &character
|
||||
andModifiers: &modifiers])
|
||||
{
|
||||
NSLog (@"GSKeyBindingTable - Could not bind key %@", key);
|
||||
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;
|
||||
|
||||
/* 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]])
|
||||
{
|
||||
/* "" as action means disable the keybinding. It can be used to
|
||||
override a previous keybinding. */
|
||||
if ([(NSString *)action isEqualToString: @""])
|
||||
{
|
||||
a = nil;
|
||||
}
|
||||
else
|
||||
{
|
||||
a = [[GSKeyBindingActionSelector alloc]
|
||||
initWithSelectorName: (NSString *)action];
|
||||
AUTORELEASE (a);
|
||||
}
|
||||
}
|
||||
else if ([action isKindOfClass: [NSArray class]])
|
||||
{
|
||||
a = [[GSKeyBindingActionSelectorArray alloc]
|
||||
initWithSelectorNames: (NSArray *)action];
|
||||
AUTORELEASE (a);
|
||||
}
|
||||
else if ([action isKindOfClass: [NSDictionary class]])
|
||||
{
|
||||
t = [[GSKeyBindingTable alloc] init];
|
||||
[t loadBindingsFromDictionary: (NSDictionary *)action];
|
||||
AUTORELEASE (t);
|
||||
}
|
||||
else if ([action isKindOfClass: [GSKeyBindingAction class]])
|
||||
{
|
||||
a = action;
|
||||
}
|
||||
|
||||
/* Ok - at this point, we have all the elements ready, we just need
|
||||
to insert into the table. */
|
||||
|
||||
/* Check if there are already some bindings for this keystroke. */
|
||||
for (i = 0; i < _bindingsCount; i++)
|
||||
{
|
||||
if (_bindings[i].character == character)
|
||||
{
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (noNeedToInsert)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* Ok - allocate memory for the new binding. */
|
||||
{
|
||||
int newKeyBindings;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL) lookupKeyStroke: (unichar)character
|
||||
modifiers: (int)flags
|
||||
returningActionIn: (GSKeyBindingAction **)action
|
||||
tableIn: (GSKeyBindingTable **)table
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < _bindingsCount; i++)
|
||||
{
|
||||
if (_bindings[i].character == character)
|
||||
{
|
||||
if (_bindings[i].modifiers == flags)
|
||||
{
|
||||
if (_bindings[i].action == nil && _bindings[i].table == nil)
|
||||
{
|
||||
/* Found the keybinding, but it is disabled! */
|
||||
return NO;
|
||||
}
|
||||
else
|
||||
{
|
||||
*action = _bindings[i].action;
|
||||
*table = _bindings[i].table;
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void) dealloc
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < _bindingsCount; i++)
|
||||
{
|
||||
RELEASE (_bindings[i].action);
|
||||
RELEASE (_bindings[i].table);
|
||||
}
|
||||
objc_free (_bindings);
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
Loading…
Reference in a new issue