"on keyboard down" handler still yields alert sound

I have a table that uses the ‘on keyboard down’ handler, like so:

on keyboard down theObject event theEvent
	if the name of theObject is "theTableView" then
		set theKey to characters of theEvent
		repeat with i from 1 to (count theList)
			if theKey = (first character of item i of theList) then
				set selected row of table view "theTableView" of scroll view "theScrollView" of window "mainWindow" to i
				call method "scrollRowToVisible:" of (table view "theTableView" of scroll view "theScrollView" of window "mainWindow") with parameter (i - 1)
				exit repeat
			end if
		end repeat
	end if
end on keyboard down

This works just fine. However, the alert sound is always played, whether or not the key pressed is found in the list.

I assume some other UI element is also picking up the key press and sending the alert sound to notify the user that it doesn’t respond to that keypress.

How do I make sure the whole application knows I’m getting the keypresses and there’s no need to sound the alert?

Is there some other way to avoid the alert sound being called in this circumstance?



I was able to derive a solution to this problem. But first I had to understand the problem!

It seems that Cocoa sends keyboard events up not one but /two/ responder chains: one that can lead to a ‘on keyboard down’ and/or ‘on keyboard up’ handler in Applescript Studio or the keyDown:/keyUp events in Cocoa/Obj-C; and one that has no interceptable route in Applescript Studio, but which is used for keyboard equivalents (i.e., command-Q for quitting out of the program, keyboard equivalents you set for your buttons and other UI elements, etc.).

So what happens with a UI element like the table view is that you write a ‘on keyboard down’ handler and it works perfectly, but you still get a beep because there is no keyboard equivalent for the keys you’re processing in your handler. In other words, the system beep is being triggered in the keyboard equivalents branch of the event chain.

To stop the keyboard equivalent chain from beeping when the user presses a valid key for my table view, I subclassed NSTableView and overrode -performKeyEquivalent:, returning YES when the key received was one my ‘on keyboard down’ handler was processing, while calling the superclasse’s performKeyEquivalent method in all other cases.

Here’s my “first cut” code, which would have to be modified for your specific situation, and which needs to be cleaned up. Still, it will give you a starting point, and at least in my case it both stopped the errant system beeps from happening and allowed the keys through that should get through (menu item shortcuts, arrow keys, etc.).

  • (BOOL) performKeyEquivalent: (NSEvent *) theEvent
    NSString * characters, * charactersWithoutModifiers;
    NSCharacterSet * anCharacterSet;
    unichar character, characterWithoutModifiers;

    characters = [theEvent characters];
    charactersWithoutModifiers = [theEvent charactersIgnoringModifiers];
    unsigned int theModifiers = [theEvent modifierFlags];

    character = [characters characterAtIndex: 0];
    characterWithoutModifiers = [charactersWithoutModifiers length] ? [charactersWithoutModifiers characterAtIndex:0] : 0;

    if((theModifiers & NSCommandKeyMask) || (theModifiers & NSControlKeyMask) || (theModifiers & NSAlternateKeyMask))
    return [super performKeyEquivalent];

    anCharacterSet = [NSCharacterSet alphanumericCharacterSet];

    if([anCharacterSet characterIsMember:characterWithoutModifiers])
    return YES;

    return [super performKeyEquivalent];

Thank you for sharing this, it’s just what I was looking for.