Intercepting keyDown event from NSComboBox
-
I have a window that has an NSComboBox in it; it is the only thing in
the window that can acquire keyboard focus.
The window also has a button in it, which my client has decided he
wants activated by pressing the space bar. Therefore I need a way to
intercept keyDown events to the combo box (which *always* has keyboard
focus).
My first attempt was to subclass the NSComboBox, and receive the
controlTextDidChange notification, look for a space character in the
stringValue of the control (any other valid value of the combo box
will NOT contain a space character), and if one is found, delete it
and call performClick on the button. This works, but I view it as an
ugly hack. And, it has a nasty side effect: if any of the text
displayed in the combo box is selected, that selection effectively
gets deleted; this is counter to the purpose of the combo box, which
is to display information about the current "stuff" being worked on in
the window. I'm thinking I can get around this by refreshing the
display of the combo box with the current value, but to me that's just
adding more ugly to the hackery that I dislike to begin with.
Is there a better way to intercept keyDown events before the
firstResponder gets a whack at it? (Assume that changing the actual
UI/UE, at this point, is not an option.)
Thanks!
randy -
On 2/12/08, Randall Meadows <cocoa-dev...> wrote:> Is there a better way to intercept keyDown events before the
> firstResponder gets a whack at it? (Assume that changing the actual
> UI/UE, at this point, is not an option.)
According to the Cocoa Event-Handling Guide, NSApplication receives
incoming events from the window server, and finds the approrpiate
window to handle the event. It then gives the event to the window,
which sends it to its first responder:
http://developer.apple.com/documentation/Cocoa/Conceptual/EventOverview/Eve
ntArchitecture/chapter_2_section_3.html#//apple_ref/doc/uid/10000060i-CH3-S
W4
The short answer: override -[NSWindow sendEvent:] and capture the
event before it gets dispatched to the first responder.
--Kyle Sluder -
On 13/02/2008, at 12:07 PM, Randall Meadows wrote:> I have a window that has an NSComboBox in it; it is the only thing
> in the window that can acquire keyboard focus.
>
> The window also has a button in it, which my client has decided he
> wants activated by pressing the space bar. Therefore I need a way
> to intercept keyDown events to the combo box (which *always* has
> keyboard focus).
>
> My first attempt was to subclass the NSComboBox, and receive the
> controlTextDidChange notification, look for a space character in
> the stringValue of the control (any other valid value of the combo
> box will NOT contain a space character), and if one is found,
> delete it and call performClick on the button. This works, but I
> view it as an ugly hack. And, it has a nasty side effect: if any
> of the text displayed in the combo box is selected, that selection
> effectively gets deleted; this is counter to the purpose of the
> combo box, which is to display information about the current
> "stuff" being worked on in the window. I'm thinking I can get
> around this by refreshing the display of the combo box with the
> current value, but to me that's just adding more ugly to the
> hackery that I dislike to begin with.
>
> Is there a better way to intercept keyDown events before the
> firstResponder gets a whack at it? (Assume that changing the
> actual UI/UE, at this point, is not an option.)
Or re-educate the client ;-) What if he wants to type a space into
the combo-box?
While this is an unhelpful and glib answer, I do feel we have to at
least try to get clients to understand why things are not done
certain ways and why deeper thinking on an issue will often make them
realise that any given idea can be worse than useless.
--------
S.O.S. -
You can subclass NSComboBox and override -keyDown: or -insertText:.
Of course, pass the message on to super if it's not a space.
Graham wrote:>
> On 13/02/2008, at 12:07 PM, Randall Meadows wrote:
>
>> I have a window that has an NSComboBox in it; it is the only thing in
>> the window that can acquire keyboard focus.
>>
>> The window also has a button in it, which my client has decided he
>> wants activated by pressing the space bar. Therefore I need a way to
>> intercept keyDown events to the combo box (which *always* has
>> keyboard focus).
>>
>> My first attempt was to subclass the NSComboBox, and receive the
>> controlTextDidChange notification, look for a space character in the
>> stringValue of the control (any other valid value of the combo box
>> will NOT contain a space character), and if one is found, delete it
>> and call performClick on the button. This works, but I view it as an
>> ugly hack. And, it has a nasty side effect: if any of the text
>> displayed in the combo box is selected, that selection effectively
>> gets deleted; this is counter to the purpose of the combo box, which
>> is to display information about the current "stuff" being worked on
>> in the window. I'm thinking I can get around this by refreshing the
>> display of the combo box with the current value, but to me that's
>> just adding more ugly to the hackery that I dislike to begin with.
>>
>> Is there a better way to intercept keyDown events before the
>> firstResponder gets a whack at it? (Assume that changing the actual
>> UI/UE, at this point, is not an option.)
>
>
> Or re-educate the client ;-) What if he wants to type a space into the
> combo-box?
>
> While this is an unhelpful and glib answer, I do feel we have to at
> least try to get clients to understand why things are not done certain
> ways and why deeper thinking on an issue will often make them realise
> that any given idea can be worse than useless.
>
> --------
> S.O.S. -
On Feb 12, 2008, at 7:18 PM, John Stiles wrote:> You can subclass NSComboBox and override -keyDown: or -insertText:.
Well, I didn't try insertText:, but keyDown did not ever get called. -
On Feb 12, 2008, at 7:13 PM, Graham wrote:>> Is there a better way to intercept keyDown events before the
>> firstResponder gets a whack at it? (Assume that changing the
>> actual UI/UE, at this point, is not an option.)
>
> Or re-educate the client ;-) What if he wants to type a space into
> the combo-box?
>
> While this is an unhelpful and glib answer, I do feel we have to at
> least try to get clients to understand why things are not done
> certain ways and why deeper thinking on an issue will often make
> them realise that any given idea can be worse than useless.
Well, as I said in my original post, a space in the combo box is not
valid. The contents of the combo box are identification numbers, and
as such will never contain a space. The use of the space bar to
activate the button is for convenience; the button is controlling
hardware (a camera), and the space bar is just the easiest thing for
the end users (typically computer-illiterate photographers). -
OK, I looked at this a little more closely because I was curious and it
is probably an issue I will eventually need to grapple with as well :)
Recently, if there's a nonstandard way of doing things, I've been having
to do it!
So the root issue is this: there is a -keyDown: event being generated,
but the combo box isn't the receiver. The receiving object is the field
editor!
There are technotes on returning a custom field editor which you can
look at. All you really need to do is subclass NSTextView and implement
a -keyDown: or -insertText: in your subclass, then provide that text
view as the field editor for the combo box. That should solve it.
Good luck.
Randall Meadows wrote:> On Feb 12, 2008, at 7:18 PM, John Stiles wrote:
>
>> You can subclass NSComboBox and override -keyDown: or -insertText:.
>
> Well, I didn't try insertText:, but keyDown did not ever get called. -
On Feb 13, 2008 12:37 PM, John Stiles <JStiles...> wrote:> There are technotes on returning a custom field editor which you can
> look at. All you really need to do is subclass NSTextView and implement
> a -keyDown: or -insertText: in your subclass, then provide that text
> view as the field editor for the combo box. That should solve it.
I'm still really confused as to why everyone is recommending
subclassing the first responder instead of catching the event as it
enters the window. To accomplish your goal, you need to change the
event dispatching logic, which is not a property of the first
responder, but the mechanism that gets the event to it.
And then what happens if you get another control in the window? Are
you going to subclass this control too?
--Kyle Sluder -
On Feb 13, 2008, at 1:41 PM, Kyle Sluder wrote:> On Feb 13, 2008 12:37 PM, John Stiles <JStiles...> wrote:
>> There are technotes on returning a custom field editor which you can
>> look at. All you really need to do is subclass NSTextView and
>> implement
Except this is an NSTextFIELD, not -View (well, actually, NSComboBox,
but that is an NSTextField).>> a -keyDown: or -insertText: in your subclass, then provide that text
>> view as the field editor for the combo box. That should solve it.
>
> I'm still really confused as to why everyone is recommending
> subclassing the first responder
Which, as I noted, DOESN'T WORK ANYWAY!!! (Go ahead, try it; I'll
wait......See?)> instead of catching the event as it
> enters the window. To accomplish your goal, you need to change the
> event dispatching logic, which is not a property of the first
> responder, but the mechanism that gets the event to it.
Just for the record, that is now what I'm doing; I had subclassed
NSWindow anyway, so it was trivial to add the sendEvent: override in
there as well. And, it works perfectly; much better than my hack.> -
Randall Meadows wrote:> On Feb 13, 2008, at 1:41 PM, Kyle Sluder wrote:Right, I am well aware of that.
>
>> On Feb 13, 2008 12:37 PM, John Stiles <JStiles...> wrote:
>>> There are technotes on returning a custom field editor which you can
>>> look at. All you really need to do is subclass NSTextView and implement
>
> Except this is an NSTextFIELD, not -View (well, actually, NSComboBox,
> but that is an NSTextField).
>
Please look up field editors and how they work. It's a pretty important
concept for Cocoa development.>> enters the window. To accomplish your goal, you need to change the
>> event dispatching logic, which is not a property of the first
>> responder, but the mechanism that gets the event to it.
> instead of catching the event as it
>
> Just for the record, that is now what I'm doing; I had subclassed
> NSWindow anyway, so it was trivial to add the sendEvent: override in
> there as well. And, it works perfectly; much better than my hack.
Well, I'm glad you have a working technique. It's probably a better way
to go.
Still, I recommend you look up the field editor in the docs. -
On Feb 13, 2008, at 2:29 PM, Randall Meadows <cocoa-dev...>
wrote:> On Feb 13, 2008, at 1:41 PM, Kyle Sluder wrote:
>
>> On Feb 13, 2008 12:37 PM, John Stiles <JStiles...> wrote:
>>> There are technotes on returning a custom field editor which you can
>>> look at. All you really need to do is subclass NSTextView and
>>> implement
>
> Except this is an NSTextFIELD, not -View (well, actually,
> NSComboBox, but that is an NSTextField).
>
Something that often surprises new developers is that text fields
don't edit themselves. They're edited by a field editor, which is a
subclass of NSTextView. You can read about the concept of a field
editor in the docs. I would provide a link but I'm composing this on
my phone.
Good luck -
Jon Hess>>> a -keyDown: or -insertText: in your subclass, then provide that text
>>> view as the field editor for the combo box. That should solve it.
>>
>> I'm still really confused as to why everyone is recommending
>> subclassing the first responder
>
> Which, as I noted, DOESN'T WORK ANYWAY!!! (Go ahead, try it; I'll
> wait......See?)
>
>> instead of catching the event as it
>> enters the window. To accomplish your goal, you need to change the
>> event dispatching logic, which is not a property of the first
>> responder, but the mechanism that gets the event to it.
>
> Just for the record, that is now what I'm doing; I had subclassed
> NSWindow anyway, so it was trivial to add the sendEvent: override in
> there as well. And, it works perfectly; much better than my hack.
>>


