EVT_CHAR_HOOK on letters, or conditional accelerators

383 views
Skip to first unread message

Will Sadkin

unread,
May 21, 2001, 1:26:56 PM5/21/01
to wxusers, wxpython users
Hello,

I want to have single letter key (i.e. mnemonic and non-RSI inducing)
accelerators, which function if and only if the focus is not in a text control.
(You can create a letter-key accelerator, but then the keypress it is swallowed
before reaching the text control, even if that control has the focus.)
I have seen postings which imply similar desires, but to date, I have found no
way to get such behavior. I was hoping that I could use EVT_CHAR_HOOK to
implement the conditional accelerator, but alas, I am stymied at every turn...

It appears that you cannot get EVT_CHAR_HOOK to fire on letter key events
(at least on wxFrame/Panel/Dialog classes.) There have been numerous
postings and responses about this, e.g.:

Harm Van der Heijden wrote:
>I had the exact same problem when I wrote hangman.py a couple of months ago.
> The solution was to derive the window that was supposed to capture the key
> events from a wxWindow, not from a wxPanel. (wxFrames also don't seem to
> react to key events).)

And Robin Dunn wrote in response:
> Right, this is because key and char events are not "command events" so the
> don't travel up the containment hierarchy but only go to the window where
> the event happened.

However, I don't understand this explanation, nor can I get Harm's supposed
workaround to function, e.g.:

> Oops, forgot to clarify something. In the frame's init, don't use
> EVT_CHAR(self, self.OnChar)
> but do something like
> wnd = wxWindow(self, -1) # take the whole frame client space by default
> EVT_CHAR(wnd, self.OnChar)

(the OnChar *never* fires if I do this. This may be because the frame
contains a panel for laying out controls on, but it doesn't work if I try
the above trick on the panel either.)

But why are only "command events" "hookable?" Why aren't/(can't?) char
events (be) considered commands and "travel up the containment hierarchy?"
Couldn't there be a flag somewhere where you could say you want this
behavior??

Alternatively, is there any way to have an accelerator act conditionally
based on focus?

Any help or solution would be appreciated.
/Will Sadkin
wsa...@nameconnector.com

Vadim Zeitlin

unread,
May 21, 2001, 8:02:59 PM5/21/01
to wx-u...@lists.wxwindows.org
On Mon, 21 May 2001 13:26:56 -0400 Will Sadkin <wsa...@nameconnector.com> wrote:

WS> I was hoping that I could use EVT_CHAR_HOOK to

I didn't have time to read your message in details yet, but the very first
sentence provokes this reaction from me: don't. Just don't use
EVT_CHAR_HOOK(), it is a hack . Moreover, it is a Windows-specific hack and
I'm personally not at all interested in getting it to work right. If anything,
I'd like to deprecate it and get rid of it completely.

Regards,
VZ


Robin Dunn

unread,
May 21, 2001, 11:33:59 PM5/21/01
to wx-u...@lists.wxwindows.org
>
> It appears that you cannot get EVT_CHAR_HOOK to fire on letter key events
> (at least on wxFrame/Panel/Dialog classes.) There have been numerous
> postings and responses about this, e.g.:
>

As Vadim said in the other list, you shouldn't EVT_CHAR_HOOK. I've found it
to be unpredictable...


> But why are only "command events" "hookable?" Why aren't/(can't?) char
> events (be) considered commands and "travel up the containment hierarchy?"

Because if every event went up the hierarchy then wxPython would probably be
slower than Tkinter stuck in a tar pit on a cold day.


> Couldn't there be a flag somewhere where you could say you want this
> behavior??

It's been discussed and most people were favorable to it if it couls be done
with minimal overhead.

>
> Alternatively, is there any way to have an accelerator act conditionally
> based on focus?

Python is more flexible than C++ so you can bind any callable object to any
event for any window, so you could do an EVT_CHAR for every control that you
want to be sensitive to this keystroke and bind it to a method in your frame
class. Or you could also do it the C++ way and derive a class from
wxEvtHandler that has EVT_CHAR hooked, and the for every control that you
want to handle it call control.PushEventHandler(MyEvtHandler(self))

--
Robin Dunn
Software Craftsman
ro...@AllDunn.com Java give you jitters?
http://wxPython.org Relax with wxPython!

John Skiff

unread,
May 22, 2001, 1:35:45 PM5/22/01
to Users List
Will Sadkin wrote:
>
> I want to have single letter key (i.e. mnemonic and non-RSI inducing)
> accelerators, which function if and only if the focus is not in a text control.
> (You can create a letter-key accelerator, but then the keypress it is swallowed
> before reaching the text control, even if that control has the focus.)
> I have seen postings which imply similar desires, but to date, I have found no
> way to get such behavior. I was hoping that I could use EVT_CHAR_HOOK to
> implement the conditional accelerator, but alas, I am stymied at every turn...

I tried EVT_CHAR_HOOK when I was trying to have one letter accelerators
in my main window not fire when a text widget had focus. I had exactly
the same problem that you have seen. However Vadim kindly fixed the
problem late last week. Accelerator checking doesn't propagate to the
parent any more.

John

Will Sadkin

unread,
May 22, 2001, 4:33:56 PM5/22/01
to wx-u...@lists.wxwindows.org
Vadim Zeitlin wrote:
> WS> I was hoping that I could use EVT_CHAR_HOOK to
>
> I didn't have time to read your message in details yet, but the very first
> sentence provokes this reaction from me: don't. Just don't use
> EVT_CHAR_HOOK(), it is a hack . Moreover, it is a Windows-specific hack and
> I'm personally not at all interested in getting it to work right. If anything,
> I'd like to deprecate it and get rid of it completely.

Alas, it may be *implemented* as a hack, but it is the only way I can find to conditionally process navigation events like wxK_TAB, which I currently need
to do to fake tab traversal across multiple panels in a splitter window, or
wxK_UP and wxK_DOWN, which I also want to react to (ie. "if not in a menu or
text ctrl, then call my OnNext/OnPrev function, even if the listctrl doesn't
have the focus.") If I use EVT_CHAR, I never see any of these events as
they are swallowed by the framework.

In fact, I can't seem to get EVT_CHAR to fire at all, whereas EVT_CHAR_HOOK
seems to "do the right thing" (except for not firing on letters :-).

If you really want to get rid of EVT_CHAR_HOOK, then you need to provide a
wxWindows facility for saying "I want (these particular?) char events to go
to his wxWindow *first* before being handled in the default way.
(event.Skip() should then allow the default behavior.) Then you could use
EVT_CHAR in the "normal way" and manipulate things accordingly. However,
this is what I thought EVT_CHAR_HOOK *was*...

>From the documentation:
"wxWindow::OnCharHook
This member is called to allow the window to intercept keyboard
events before they are processed by child windows."

It goes on to say:
"An example of using this function is in the implementation of
escape-character processing for wxDialog, where pressing ESC
dismisses the dialog by OnCharHook 'forging' a cancel button press
event.

Note that the ASCII values do not have explicit key codes: they are
passed as ASCII values.

This function is only relevant to top-level windows (frames and
dialogs), and under Windows only. Under GTK the normal EVT_CHAR_
event has the functionality, i.e. you can intercepts it and if you
don't call wxEvent::Skip the window won't get the event."

This would seem to imply that you're supposed to get letter events (but you
don't.) It also seems to imply that EVT_CHAR_HOOK is unnecessary under GTK,
and, by contrast, that EVT_CHAR_HOOK is necessary for Windows wxapps to get
this functionality. Is this true? Does the EVT_CHAR fire *before* default
handling under GTK? If not, can you get this feature at all?
Either way, this seems like a huge problem for writing a portable app...

If you can get EVT_CHAR to fire on windows the way the doc indicates it does
under GTK (ie. the top-level window can get the keys before the children),
then by all means, deprecate EVT_CHAR_HOOK. If it doesn't in fact work
that way, then perhaps you should make EVT_CHAR_HOOK less of a hack, and
make it work everywhere?

Regards,
/WS

Vadim Zeitlin

unread,
May 24, 2001, 10:43:08 AM5/24/01
to wx-u...@lists.wxwindows.org
On Tue, 22 May 2001 16:33:56 -0400 Will Sadkin <wsa...@nameconnector.com> wrote:

WS> If I use EVT_CHAR, I never see any of these events as
WS> they are swallowed by the framework.

Use wxWANTS_CHARS style.

WS> In fact, I can't seem to get EVT_CHAR to fire at all

This is surely a problem in your code as these events are generated.

WS> If you really want to get rid of EVT_CHAR_HOOK, then you need to provide a
WS> wxWindows facility for saying "I want (these particular?) char events to go
WS> to his wxWindow *first* before being handled in the default way.

It exists and is called wxAcceleratorTable. It doesn't work in exactly the
same manner, but it does just this, basicly: allows to intercept the key
presses before processing them normally.

WS> This would seem to imply that you're supposed to get letter events (but you
WS> don't.) It also seems to imply that EVT_CHAR_HOOK is unnecessary under GTK,
WS> and, by contrast, that EVT_CHAR_HOOK is necessary for Windows wxapps to get
WS> this functionality. Is this true? Does the EVT_CHAR fire *before* default
WS> handling under GTK?

EVT_CHAR_HOOK isn't fired at all under wxGTK to the best of my knowledge.
This is why I wrote that it was a wxMSW hack.

WS> If you can get EVT_CHAR to fire on windows the way the doc indicates it does
WS> under GTK (ie. the top-level window can get the keys before the children),

The docs don't say this! The char events always go to the window which has
the focus, this is the definition of "focus" anyhow.

If you need to propagate the char events to the parent, it _can_ be done.
Just push an event handler which processes them on top of each children (this
can be done easily by overriding wxWindow::AddChild()).

Regards,
VZ


Reply all
Reply to author
Forward
0 new messages