libs-gui/Source/GSKeyBindingTable.m

275 lines
7.2 KiB
Mathematica
Raw Normal View History

/* 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,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "GSKeyBindingAction.h"
#include "GSKeyBindingTable.h"
#include "AppKit/NSInputManager.h"
#include "AppKit/NSEvent.h"
@implementation GSKeyBindingTable : NSObject
- (void) loadBindingsFromDictionary: (NSDictionary *)dict
{
NSEnumerator *e;
id key;
e = [dict keyEnumerator];
while ((key = [e nextObject]) != nil)
{
[self bindKey: key toAction: [dict objectForKey: key]];
}
}
- (void) bindKey: (id)key toAction: (id)action
{
unichar character;
2005-01-21 21:43 Alexander Malmberg <alexander@malmberg.org> Various whitespace cleanups, comment type fixes, and changes to avoid warnings from recent versions of gcc. * Headers/Additions/GNUstepGUI/GSToolbar.h (-_toolbars): Declare. * Source/NSWindow+Toolbar.m: Remove conflicting declaration of [NSToolbar -_toolbars]. * Headers/Additions/GNUstepGUI/GSServicesManager.h, Source/GSServicesMananger.m (-item2title:, -validateMenuItem:): Adjust argument types. * Headers/AppKit/NSMenu.h (-validateMenuItem:): Adjust argument type. * Source/NSTextView.m (-sizeToFit): Don't use size uninitialized if neither resizable flags is set. (-insertText:): Adjust argument type. * Headers/AppKit/NSResponder.h, Source/NSResponder.m (-insertText:): Adjust argument type. Document. * Headers/AppKit/NSView.h: Change type of ivar _window to NSWindow *. * Source/GSTitleView.m (-mouseDown:): Always initialize startWindowOrigin. * Source/NSApplication.m (-setApplicationIconImage:): Add casts to avoid warnings. * Source/NSCell.m (-cellSize): Add default: case. * Source/NSPasteboard.m ([GSFiltered -pasteboard:provideDataForType:]): Detect and warn if we can't find a filter that will get us the desired type. * Source/NSProgressIndicator.m: Comment out unused variable 'images'. * Source/NSBezierPath.m: Declare GSBezierPath fully before using it. (-bezierPathByFlatteningPath, -bezierPathByReversingPath): Make sure variables are always initialized. * Source/NSMenuView.m, * Source/NSPrintOperation.m, * Source/NSSplitView.m, * Source/NSTableHeaderView.m: Make sure variables are always initialized. * Source/NSBox.m, * Source/NSImageview.m, * Source/NSText.m, * Source/NSTextStorage.m: Add missing includes. * Source/GSKeyBindingTable.m, * Source/GSLayoutManager.m, * Source/NSBitmapImageRep+PNM.m, * Source/NSBundleAdditions.m, * Source/NSLayoutManager.m, * Source/nsimage-tiff.h, * Source/tiff.m, * Headers/Additions/GNUstepGUI/GSDisplayServer.h, * Source/GSDisplayServer.m: Change signedness of various variables. * Source/NSPanel.m (-sendEvent:): Remove. * Source/NSWindow.m (-becomesKeyOnlyIfNeeded): New method. (-_sendEvent:becomesKeyOnlyIfNeeded:): Remove. Move code ... (-sendEvent:): ... here. Use -becomesKeyOnlyIfNeeded instead of the argument. git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gui/trunk@20590 72102866-910b-0410-8b05-ffd578937521
2005-01-21 20:39:18 +00:00
unsigned int modifiers;
GSKeyBindingAction *a = nil;
GSKeyBindingTable *t = nil;
BOOL isTable = NO;
int i;
/* First, try to determine what exactly is key :-) ... it might
either be a simple string, "Control-f", or an array,
("Control-x", "Control-s"). We implement the case of arrays in
terms of the case of strings. */
if ([key isKindOfClass: [NSArray class]])
{
if ([(NSArray *)key count] == 0)
{
/* Ignore them. */
return;
}
else if ([(NSArray *)key count] == 1)
{
key = [key objectAtIndex: 0];
}
else
{
/* Ok - simply convert that into a temporary dictionary
representation and store that. Eg, key ("Control-x",
"Control-s", "Control-k") action "moveUp:" gets converted
into: key "Control-x" action { "Control-s" = {
"Control-k" = "moveUp:"; }; }. */
/* Now start from the end of the array, and start building
the temporary dictionary structure going backwards. */
id value = action;
int j;
for (j = [key count] - 1; j > 0; j--)
{
NSMutableDictionary *tmp = [NSMutableDictionary dictionary];
[tmp setObject: value forKey: [key objectAtIndex: j]];
value = tmp;
}
key = [key objectAtIndex: 0];
action = value;
}
}
if (![key isKindOfClass: [NSString class]])
{
NSLog (@"GSKeyBindingTable - key %@ is not a NSString!", key);
return;
}
if (![NSInputManager parseKey: (NSString *)key
intoCharacter: &character
andModifiers: &modifiers])
{
NSLog (@"GSKeyBindingTable - Could not bind key %@", key);
return;
}
/* 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);
}
/* 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]])
{
/* Don't load the keybindings from action yet ... load them
later on when we know if we need to create a new
GSKeyBindingTable or if we need to merge them into an
existing one. */
isTable = YES;
}
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)
&& (_bindings[i].modifiers == modifiers))
{
/* Replace/override the existing action with the new one if
it's an action, or load the bindings into a (new or
existing) table if it's a table. */
if (isTable)
{
/* If there was already a table, add keybindings to that
table. */
if (_bindings[i].table != nil)
{
t = _bindings[i].table;
}
else
{
/* Else, create a new one. */
t = [[GSKeyBindingTable alloc] init];
AUTORELEASE (t);
}
[t loadBindingsFromDictionary: (NSDictionary *)action];
}
ASSIGN (_bindings[i].action, a);
ASSIGN (_bindings[i].table, t);
return;
}
}
/* Ok - new keystroke. Create the table if needed. */
if (isTable)
{
t = [[GSKeyBindingTable alloc] init];
AUTORELEASE (t);
[t loadBindingsFromDictionary: (NSDictionary *)action];
}
/* Allocate memory for the new binding. */
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;
/* 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
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