My main Frame has a menu bar and some of the menu items have
accelerator keys. My problem is that the accelerator keys are being
automatically translated into EVT_MENU events. I want to handle the
EVT_KEY_DOWN events manually so that subwindows can process the
accelerator keys differently. Is it possible to disable the automatic
translation of key events to menu events? I've tried calling
SetAcceleratorTable(wx.NullAcceleratorTable) after the call to
SetMenuBar() but this doesn't work. I don't want to set an accelerator
table for every subwindow - this would work but would be very
inconvenient.
Actually I'm wrong, using SetAcceleratorTable to handle accelerators
in subwindows doesn't work on GTK, so there seems to be no solution
except from removing the accelerators from the menu items, which isn't
very desirable.
···
On Nov 9, 12:45 pm, Luke McCarthy <luke.mccar...@gmail.com> wrote:
My main Frame has a menu bar and some of the menu items have
accelerator keys. My problem is that the accelerator keys are being
automatically translated into EVT_MENU events. I want to handle the
EVT_KEY_DOWN events manually so that subwindows can process the
accelerator keys differently. Is it possible to disable the automatic
translation of key events to menu events? I've tried calling
SetAcceleratorTable(wx.NullAcceleratorTable) after the call to
SetMenuBar() but this doesn't work. I don't want to set an accelerator
table for every subwindow - this would work but would be very
inconvenient.
I was looking to do something similar, to have accelerator keys in
menu items but to process the keys myself. (I wanted to emulate
emacs-style multi-key keystrokes in peppy, my editor project.) I also
experimented with accelerator tables and found the same issue.
I was able to come up with a convoluted process to do this, but it
involves trapping the EVT_MENU, EVT_KEY_DOWN, and EVT_CHAR events for
the frame and every subwindow that can take keyboard focus.
It works on all 3 platforms, but it does change the way you process
events. Instead of using Bind on an EVT_MENU or EVT_KEY_DOWN, it uses
an event abstraction called an "action" that you register for each
menu item or keyboard command, and the AcceleratorManager calls these
actions.
The source for the keyboard manager is here:
http://trac.flipturn.org/browser/trunk/peppy/lib/multikey.py
The basic idea is that any accelerator that appears in a menu item
will be turned into an EVT_MENU, and anything else will be turned into
an EVT_KEY_DOWN or EVT_CHAR. So, you have to build up a mapping of
those accelerators than get turned into EVT_MENU events and those that
don't. My issue was complicated by the need to process the multi-key
keystrokes, so some multi-key commands may turn out to have the first
accelerator from an EVT_MENU and the second from an EVT_KEY_DOWN, so I
have to keep track of all that. If you don't care about multi-key
stuff, it would be simpler.
Anyway, for what it's worth... That's the only thing I've discovered
that works for all platforms.
Rob
···
On Mon, Nov 9, 2009 at 7:28 AM, Luke McCarthy <luke.mccarthy@gmail.com> wrote:
Actually I'm wrong, using SetAcceleratorTable to handle accelerators
in subwindows doesn't work on GTK, so there seems to be no solution
except from removing the accelerators from the menu items, which isn't
very desirable.
My application also has an "action" abstraction. The problem is that
the action for a particular key in a menu, e.g. Ctrl+D, corresponds to
a different action in a certain tab (it's a terminal emulator so it
catches all Ctrl+Letter keys). The other problem is I would need to
find the focused window and refire the event. Perhaps I could create a
table of (accelerator name -> menu id) and give menu items an ID which
corresponds to an accelerator key, rather than an action, and refire
the event as a key event in the focused window... I'll try that.
OK, this worked... I catch EVT_MENU events and look up the accelerator
from the ID, then I find the focused window and process the event as
if an accelerator key has been pressed. Not the nicest solution but
it's the only one I can think of.
Just another note here: I catch EVT_MENU_OPEN and EVT_MENU_CLOSE to
distinguish menu clicks from accelerator key presses. But they way it
works is counter-intuitive. Pressing an accelerator key actually
causes EVT_MENU_OPEN to be signalled, but clicking on a menu causes
EVT_MENU_CLOSE to be signall just before the command event is sent.
So, it's an accelerator if EVT_MENU_OPEN was called last, or a menu
click if EVT_MENU_CLOSE was called last.
Except... this is only true on Windows. On GTK, accelerators do not
signal EVT_MENU_OPEN at all...
···
On Nov 10, 11:28 am, Luke McCarthy <luke.mccar...@gmail.com> wrote:
Just another note here: I catch EVT_MENU_OPEN and EVT_MENU_CLOSE to
distinguish menu clicks from accelerator key presses. But they way it
works is counter-intuitive. Pressing an accelerator key actually
causes EVT_MENU_OPEN to be signalled, but clicking on a menu causes
EVT_MENU_CLOSE to be signall just before the command event is sent.
So, it's an accelerator if EVT_MENU_OPEN was called last, or a menu
click if EVT_MENU_CLOSE was called last.
Also something that I found that in retrospect seemed obvious: if the
accelerator is in a menu item that is *disabled*, you'll never get
that keystroke in an EVT_KEY_DOWN.
The way I had to work around this was to dynamically modify the
disabled menu items to remove the accelerator key, and then put the
accelerator key back when it is re-enabled.
Rob
···
On Tue, Nov 10, 2009 at 3:31 AM, Luke McCarthy <luke.mccarthy@gmail.com> wrote:
Except... this is only true on Windows. On GTK, accelerators do not
signal EVT_MENU_OPEN at all...