Assigning shortcut keys in Interface Builder

Hi All

How can I assign keys in Interface Builder to a button that don´t appear in the dropdown list and are not “typable” in the text field “Key Equiv:”
In my case I want to assign the space and the arrow keys

I second the question about the arrow keys. I think it has something to do with typing in the ASCII values, but I’m not exactly sure.

As for space, I wouldn’t use it because cmd-space is reserved by many utilities (QuickSilver, Butler, various iTunes controllers).

Hi

The space key is “typable” (in the text field) but with now effect: the next time I choose the text field it is empty again
In my case I want a shortcut for controlling toggle-Play for remote controlling iTunes and I would prefer space therefore

Okay, I changed my post. I couldn’t test whether or not it actually works because of the aforementioned reason (the keystroke is already reserved for QuickSilver).

No one knows?

I’ve set up a five buttons {“LEFT”,“RIGHT”,“UP”,“DOWN”,“SPACE”}, and a text field {“keyboardInput”} that acts as an input receiver for key presses. The text field is mandatory and must be enabled and visible (although not necessarily on the visible part of the window). I placed the text field off the edge of the window, because making it invisible does not allow it to be used or focused. The buttons just show that you can handle both buttons and text, AS IF you were assigning key equivs.

When you press a key, it displays a dialog stating which key you pressed. When you push a button, it display’s a dialog based on the name of the button. You’ll have to figure out how to handle the processing of “theResults” from there. You can further configure this to evaluate more basic characters (in the script), or to look for more apple key event constants (in the obj-c class).

You’ll notice the “setDefaultResponder()” subroutine, which I think is important. It makes sure that your receiver text field is always waiting for input. Any time you do (or even think you might) lose focus on that ‘keyboardInput’ text field, use that sub to set the first responder back to the text field, just to be safe. If you have other text fields, they can be focused and used, but afterusing them, set the responder back to the input receiver right away.

First, this code goes in your script. Wire up the handlers to the objects commented in the code…

(* Connect to the 'keyboardInput' text field *)
on keyboard up theObject event theEvent
	if (characters of theEvent) is " " then
		set theResults to "SPACE"
	else
		set theResults to call method "evaluateEventChars:" of class "MenuController" with parameters {theEvent}
	end if
	doSomethingWith(theResults)
end keyboard up

(* Connected to any buttons that will handle mouse clicks *)
on clicked theObject
	set theResults to (name of theObject)
	doSomethingWith(theResults)
	setDefaultResponder()
end clicked

(* Connect to window *)
on will open theObject
	setDefaultResponder()
end will open

(* Subroutines *)
to setDefaultResponder()
	tell window "window"
		set first responder to text field "keyboardInput"
	end tell
end setDefaultResponder

to doSomethingWith(theResults)
	display dialog theResults
end doSomethingWith

Next, create a new obj-c class (File > New File…). Name it “MenuController” and only create a “MenuController.m” file. Open the new file, and put this in it…

#import "Cocoa/Cocoa.h"
#import "AppKit/AppKit.h"

@interface MenuController : NSObject
{}
+(NSString *)evaluateEventChars:(NSEvent *)theEvent;
@end

@implementation MenuController

+(NSString *)evaluateEventChars:(NSEvent *)theEvent
{
	switch([[theEvent characters] characterAtIndex:0]) {
		case NSUpArrowFunctionKey:
			return @"UP"; break;
		case NSDownArrowFunctionKey:
			return @"DOWN"; break;
		case NSLeftArrowFunctionKey:
			return @"LEFT"; break;
		case NSRightArrowFunctionKey:
			return @"RIGHT"; break;

		default:
			return @"some other key"; 
	}
	return nil;
}
@end

EDIT >> Thanks to mooresan, this class code was cleaned up and the warning was eliminated.

Good luck, and have fun… :smiley:
j

The code reaches the end of a non-void function without a return :slight_smile:

ie. The method is declared as returning an NSString* (the first thing in parentheses)… so the last thing in your method should be a return statement that returns a string. in this case, reaching that would be very strange. To indicate a very odd occurrence, or a failure in the function, apple recommends returning nil. so just before the final curly brace throw in a “return nil;” and that warning will go away.

also this is a multiple brach case, and while this is purely aesthetic, C provides a nice multiple branch construct:


…
switch([[theEvent characters] characterAtIndex:characterIndex]) {
    case NSUpArrowFunctionKey:
         return @"UP";
         break; // not strictly required
    case NSDownArrowFunctionKey:
         return @"DOWN";
         break;
...
    default:
        return @"some other key";
}
…

and finally, since you return on the first time into the loop no matter what, why not remove the for loop and just use the 0th character… or leave the loop but move the default response out of the loop to where we put “return nil;”, so you go through the characters one at a time looking for arrow keys and only return @“some other key” should there be no arrow key in the string. As it is it looks at the 0th character, checks if it’s a arrow key and if it’s not returns the default text without looping onto the second character. This may lead to unpredicted results when multiple key events are sent simultaneously.

Fantastic, mooresan! I knew that could be cleaned up nice. I’ve updated my post above to reflect your improvements.

j