Re: Subverting the first responder chain
Re: Subverting the first responder chain
- Subject: Re: Subverting the first responder chain
- From: John Stiles <email@hidden>
- Date: Mon, 31 Mar 2008 10:12:24 -0700
No problem. I'd rather have 90% good info and a bit of confusion than no
response at all :)
I've filed a radar:
rdar://5831739 [Cocoa]Hotkey matching works differently for menu
items that use the Command key
The root of the problem is really in the docs which you posted earlier.
They say that NSApplication does early matching of potential key
equivalents by checking for the presence of modifier flags. But the
problem with this logic is that "potential key equivalents" has nothing
to do with "the presence of modifier flags". Anything can be a key
equivalent.
Allen Smith wrote:
I'm sorry, my memory seems to have gotten muddled since I investigated this
issue. Upon revisiting my old test program, I realized -[super keyDown:]
*will* ultimately trigger menu items, barring weird issues like a superclass
or higher responder that intercepts the key. Apparently I believed that the
message to super didn't work precisely because the next responder in my main
application was accidentally swallowing all keyDowns. I apologize for the
misinformation, but thank you for helping me find a bug.
Allen
-----Original Message-----
From: John Stiles [mailto:email@hidden]
Sent: Fri 3/28/2008 2:35 PM
To: Allen Smith
Cc: cocoa dev
Subject: Re: Subverting the first responder chain
I did a test and if I call
[[self nextResponder] keyDown:theEvent];
from inside the -keyDown: method, it does in fact trigger the
appropriate hotkey on the menu. (On the other hand, the documentation
recommends your technique of handing off to super here:
http://developer.apple.com/documentation/Cocoa/Conceptual/EventOverview/Event
HandlingBasics/chapter_4_section_2.html
which is probably a good idea if you want your view's superclass to take
a stab at the event, but in this case I have no interest in doing that.
I want the menu bar to get the event, not any views in the middle.)
So now I "just" keep a hash table of all the application's hotkeys and
query that at the top of -keyDown:. If the pressed key matches, I punt
the event to next responder, and everything works again. It's
disappointing and ugly, but it turned out to be less code than I
thought. Walking the menus and submenus recursively to build the table
is pretty simple, and I've already got a good hash table class which I
was able to put to good use.
Maybe I'll file a bug on this...
Allen Smith wrote:
On Mar 27, 2008, at 8:12 PM, John Stiles wrote:
Wow, this sounds like a disaster.
Maybe in my -keyDown: call I can walk the menus in the menu bar and
call -performKeyEquivalent on all of them. It's probably not fast :|
I was in the process of writing code that stores the menu bar's key
equivalents in a hash table and checks the hash table before handling
-keyDown:, maybe I'll just keep doing that. It's gross but I guess
all the potential solutions are gross.
Also be aware that if any other view in your application becomes first
responder, it too will swallow up your key equivalents. Short of
overriding -[NSApp sendEvent:], I don't know of universal fix. Calling
-[super keyDown:] as another poster suggested doesn't work; by the
time an event is routed to -keyDown:, the system no longer appears to
consider it a candidate for menu actions.
Allen
Ken Thomases wrote:
On Mar 27, 2008, at 7:52 PM, John Stiles wrote:
I am implementing a custom NSView subclass (actually a simple
subclass of NSOpenGLView) that implements -keyDown: in order to
respond to user typing. Typically, this works great.
However, I have a few menu items which respond to atypical hotkeys
(e.g. one responds to "space", another to "option+X"). In this
case, I've found that the view gets a -keyDown: event, which it
dutifully handles, and the menu hotkey is never handled. I'd prefer
it if the menu action were triggered and no -keyDown: event were
generated, and that's exactly what happens with more typical menu
hotkeys like command+letters. But my view doesn't know what is in
the menubar and so, without adding a lot of ugly special-case code,
from within the view's -keyDown: handler, it would be difficult to
know whether I need to send the event to the next responder or
handle the key myself.
Is there any elegant solution to this problem? The last thing I
want to do is reimplement hotkey handling on my own, but I can't
think of any workarounds to this issue that don't involve my view
taking on a lot of extra knowledge about what's in the menubar, or
completely hacking the responder chain in some ugly way. It seems
that I can't forward on to the next responder and then ask "did you
handle it?"-if the responder chain fails to handle the event,
apparently it just calls -noResponderFor: on the window and that is
that-there's no return value of "YES" or "NO" or anything like that.
From
<http://developer.apple.com/documentation/Cocoa/Conceptual/EventOverview/Hand
lingKeyEvents/chapter_6_section_4.html>:
"An application routes a key-equivalent event by sending it first
down the view hierarchy of a window. The global NSApplication object
dispatches events it recognizes as potential key equivalents (based
on the presence of modifier flags) in its sendEvent: method. It
sends a performKeyEquivalent: message to the key NSWindow object.
[...] If no object in the view hierarchy handles the key
equivalent, NSApp then sends performKeyEquivalent: to the menus in
the menu bar."
So, NSApplication requires modifier flags on the key event to
recognize it as a potential key equivalent. Unfortunately, I find
no documented way of changing the application object's criteria for
recognizing key equivalents.
So, I think you'll need to subclass NSApplication, override
sendEvent:, check for key events which you think should be candidate
key equivalents, and pass them to the key window and then the menu
bar via performKeyEquivalent:. If either returns YES, stop
processing the event. Otherwise, pass the event to [super sendEvent:].
Cheers,
Ken
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden