mirror of
https://github.com/gnustep/libs-gui.git
synced 2025-04-25 12:50:55 +00:00
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/gui/trunk@12733 72102866-910b-0410-8b05-ffd578937521
252 lines
6 KiB
Objective-C
252 lines
6 KiB
Objective-C
/* 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
|
|
|
|
|