I have a Euro keyboard (PS/2 connector) with the AltGr key and Euro
symbols - Robin or others who are based here in the U.S. and would like to
tackle this problem - I am willing to ship it to someone if that would
help with this problem or others relating to these event problems.
Hubert Hickman
hubert@tconl.com
Robin Dunn wrote:
Jean-Michel Fauth wrote:
iii) I'm not affraid to say there is a basic design issue in
wxWidgets. It is not necessary to dive into the C++ code. If you have
some programming experience and if you compare wxWidgets with other
toolkits, you are able to understand the
underlying mechanic. Of course, I do not know all gui toolkits,
all I know (VB, VS, FOX, Borland Pascal) behave the same way
except wxWidget regarding the "keyboard" handling.I will start my explanation with Visual Basic, since it is
a toolkit I know very well.In vb, the key/char handling is achieved through 3 functions,
bound to a "text control". These are:Private Sub <control>_KeyPress(KeyAscii As Integer)
Private Sub <control>_KeyDown(KeyCode As Integer, Shift As Integer)
Private Sub <control>_KeyUp(KeyCode As Integer, Shift As Integer)
Some explanation (for non expert).
The functions KeyDown/Up return two things. The keycode of the
pressed key, an ASCII value (if fact it is an ANSI value!), an
identical value for "a", "A" or "Ctrl+a" and a Shift value which holds
information about the modifier keys, Alt, Ctrl, and
Shift. Note the AltGr info is given by Alt and Ctrl, since AltGr = Ctrl
+ Alt.
The KeyPress returns one and **solely** one value. The code
of the char, which has been entered by pressing a key or a combination
of keys. It does not give any information about
the modifiers. If you enter "Ctrl+Alt+e", it returns 128, the
char code of the euro currency symbol.
What are the allowed KeyAscii values? The answer lies in the
MS doc, the returned values are in the range 32..255 plus the
char code of enter, tab and backspace. You may notice, these
values correspond to the printable characters. The characters,
that are displayed in your "text control". Here, the enter,
must be seen as a carriage return.
Function, edition and navigation keys are not intercepted in
a KeyPress event. Interestingly, all returned char values correspond to
the keys of the main block of keys of a keyboard.
In other word, the keys you need to type your text.
I leave away the discussion about focussing, tab focussing,
Ctrl+enter.Conclusion: it is very easy to write a clean keys handler. Either,
the programmer is interested in char codes or in the key codes.I think that things are closer to this than you think. KEY_UP/KEY_DOWN
events always give (mostly) "raw" keycodes, and CHAR events always give
either a "cooked" char value, or the original keycode if there is no
cooked representation. You can easily see this by using the
KeyEvents.py module in the demo. Run it and check the "Call
evt.Skip..." checkbox and then click in the blue box and type some keys.
See below for a couple samples of the output.
The problem really just boils down to programmers using only KEY_DOWN
events when they should really be using CHAR events, or perhpas a
combination of the two.
Now, let's have a look in wxWidgets. The event handlers are
EVT_KEY_UP, EVT_KEY_DOWN and EVT_CHAR. All handlers are
returning the same information, to be short, the modifiers
and keys information. This is rather confusing. The EVT_CHAR
handler has the word char in it, but it returns keycodes too.The "keyup/keydown" are working ok. The EVT_CHAR is more
ambigous, it does not always return, what the user expects.
You never know if the returned code should be interpreted as
a char code or a key code.Think of it as always being a char code for all events where
evt.GetKeyCode() <= 255. The confusion is that there are also CHAR
events sent for Function keys and etc. I don't know why wxWidgets does
that but it has been doing it forever and if it was changed then it
would break more apps than it fixes. It's insanely easy to filter those
out in your EVT_CHAR handler though.
An added wrinkle is getting unicode characters in wxPython unicode
builds. I've recently changed the EVT_CHAR handler in the StyleTextCtrl
to handle it correctly like this C++ code, (which should translate to
Python easily):
#if wxUSE_UNICODE
int key = evt.GetUnicodeKey();
bool keyOk = true;// if the unicode key code is not really a unicode character (it
may
// be a function key or etc., the platforms appear to always
give us a
// small value in this case) then fallback to the ascii key code
but
// don't do anything for function keys or etc.
if (key <= 127) {
key = evt.GetKeyCode();
keyOk = (key <= 127);
}
if (keyOk) {
m_swx->DoAddChar(key);
return;
}
#else
int key = evt.GetKeyCode();
if (key <= WXK_START || key > WXK_COMMAND) {
m_swx->DoAddChar(key);
return;
}
#endifIt is necessarily to include "dirty tricks" to filter the incoming
information and these
"filters" are not programmed correctly. In my mind, this the
place that causes the malfunction of the keys/chars handler.People are using KeyUp/Down events, when a char event should
be used, and vice versa. The present situation does not force
a programmer to use the correct handler. Beside this, they
understand char code where they should understang key code,
and vice versa.Personally I hate languages or toolkits that force the programmer to do
something a certain way. There always seems to be situations arise
where something not allowed by the toolkit or language is called for.
Just to make things a little complicate, some widgets have
flags to get around this, eg. wx.PROCESS_ENTER. These would
not exist if the event handlers were doing their work properly.Those are needed to allow ENTER/TAB etc. to *not* be used for
navigation. I don't see this as a workaround, but as a way to change
behaviour.
KeyEvents.py samples
--------------------On windows with an ansi build and US keyboard layout, typed Alt-0128.
Notice that the only CHAR event with a keycode < 255 is the euro symbol.
Event Type Key Name Key Code Modifiers Unicode RawKeyCode
RawKeyFlags
KeyDown WXK_ALT 307 -A-- 0 18 540540929
KeyDown WXK_NUMPAD0 326 -A-- 0 96 542244865
Char WXK_NUMPAD0 326 -A-- 0 96 542244865
KeyUp WXK_NUMPAD0 326 -A-- 0 96 3763470337
KeyDown WXK_NUMPAD1 327 -A-- 0 97 542048257
Char WXK_NUMPAD1 327 -A-- 0 97 542048257
KeyUp WXK_NUMPAD1 327 -A-- 0 97 3763273729
KeyDown WXK_NUMPAD2 328 -A-- 0 98 542113793
Char WXK_NUMPAD2 328 -A-- 0 98 542113793
KeyUp WXK_NUMPAD2 328 -A-- 0 98 3763339265
KeyDown WXK_NUMPAD8 334 -A-- 0 104 541589505
Char WXK_NUMPAD8 334 -A-- 0 104 541589505
KeyUp WXK_NUMPAD8 334 -A-- 0 104 3762814977
KeyUp WXK_ALT 307 ---- 0 18 3224895489
Char "" 128 ---- 0 128 3224895489On Linux with a unicode GTK2 build, using a french keyboard layout,
typed AltGr-e. I think that the KEY events got eaten by the unicode
IME, we still get the euro char but with its unicode value this time.
Event Type Key Name Key Code Modifiers Unicode RawKeyCode
RawKeyFlags
···
Char "" 0 ---- 8364 23 16