[wxPython] Character code and keyboards

Hi all wxPython developers

Character code and keyboards under windows

*Character set*

Basically, windows uses the ANSI character set and not the 8-bits ASCII char
set. The ANSI char set contains 255 chars. To enter a char, the user hit a
key or a combination of keys (shift, ctrl, ...). He (she) can also use the
Alt+0nnn command, where nnn represents the ANSI code of the char set. To use
this command, keep the Alt key down and enter the char code from the numeric
pad, NumLock beeing on. Exemples: In order to get the char a, I can hit the
a key on my keyboard or I can enter the command Alt+097.
To obtain an e acute, one can use the Alt+0233 command; for a n tilde, I use
Alt+241; for an angstroem, Alt+0229. Alt+0nnn is working for every kbd (US
or not US).
The european chars are in the range 128..255 of the ANSI char set.

*keyboards*

Every language has its own keyboard. The system provides a keyboard/language
"driver" for every language. Roughly speaking, when the user hit a key or a
combination of keys, the keyboard/language driver translates the 'pressed
keys' into an Alt+0nnn char code.
Some more exemples coming from my swiss french keyboard:
In order to get an 'a' , I hit the a key or I may enter the Alt+097 command.
To get the A, I press Shift+a or I enter the command Alt+065. To get the a #
char (comment char in python), I should press Ctrl+Alt+3. A } is obtained by
Ctrl+Alt+$ or by the command Alt+0125.
Pressing simultaneously three keys is not very pratical. That the reason why
on european keyboards we have a key called AltGr. AltGr is nothing else than
Ctrl and Alt used simultaneoulsy. So in my exemple, if I want to get the #
char, I can press Ctrl+Alt+3, AltGr+3 or enter the command Alt+035. AltGr
can be see as a 'super Shift' or as 'one another shift' key.
On a US keyboard, you can not type directly an e acute, you have to enter
the command Alt+0233. (Yes, I installed a us kbd and tested it under
windows, this can be done in 2 minutes)
Things can be even a litte bit more complicate with the so called dead keys.
(correct english name?). What is a dead key? When you press a dead key, the
caret will not move. It will move only after a secong key has been pressed.
Exemple: On my swiss french keyboard, I can not enter directly an e
circumflex. I have to use the circumflex key which is a dead key. In order
to obtain an e cicumflex, I hit the circumflex key, the carret is not
moving, then I hit the e key and the e circumlflex appears on my screen. An
alternative way is to use the Alt+0234 command.

*Python coding using wxPython*

What can go wrong within (wx)Python? I see two problems.
1) It seems that some wxPython (wxWindows?) ctrls are using only the first
half of the ANSI char set. That means only a 7 bits char code. (The first
half of the ANSI char set is identical to the 7-bits ASCII char set).
2) We have seen that AltGr = Ctrl + Alt. So if your application needs to
check the Ctrl key status (up/down), do not forget to check the Alt key
status too. Ctrl can be seen down, just because the AltGr key is pressed. By
not doing this, an european may not use a AltGr key correclty.
Below an exemple showing how pressed key(s) are handled correcly. From
shell.py, PyCrust, available in the demo. I deleted some lines.

def OnKeyDown(self, event):
    """Key down event handler.
    ...
    key = event.KeyCode()
    controlDown = event.ControlDown()
    altDown = event.AltDown()
    shiftDown = event.ShiftDown()
    currpos = self.GetCurrentPos()
    endpos = self.GetTextLength()
    # Return (Enter) is used to submit a command to the interpreter.
    if not controlDown and key == WXK_RETURN:
        ...
        self.processLine()
    # If the auto-complete window is up let it do its thing.
    elif self.AutoCompActive():
        ...
        event.Skip()
    # Let Ctrl-Alt-* get handled normally.
    elif controlDown and altDown:
        event.Skip()
    ...
    ...
    # Cut to the clipboard.
    elif (controlDown and key in (ord('X'), ord('x'))) \
    or (shiftDown and key == WXK_DELETE):
        self.Cut()
    ...
    ...
    # Insert the next command from the history buffer.
    else:
        event.Skip()

The two lines of code
elif controlDown and altDown:
    event.Skip()
let european people use smoothly their AltGr keys.

*char codes and key codes*

Char codes and key codes are two different things. The method
event.KeyCode() returns a key code, not a char code. The left arrow has a
key code but no char code.

*The char issue: Python, wxPython or UNICODE problem?*

I don't know. Using pyCrust under windows, you can test the following code:

for i in range(32, 255):

... print i, chr(i)

You will see, that you obtain (correcly) all the ANSI chars.
Note: if you try the same test using IDLE, you don't get the same result.
This is normal, chr() will return a char based on the 8-bits ASCII char set
(DOS).

*Are my fonts updated?*

This may sound stupid, but the TTF font files have changed. Try the
following key combination Ctrl+Alt+e or AltGr+e or Alt+0128. You should
obtain the euro char, the new currency unit symbol used in Europe. If not,
update your ttf files (free).

The developers using an US kbd can easily test their code with some non
english chars just by using a few Alt+0nnn commands. Preferably, test some
chars with an ANSI code > 127, just to see what's happen. A serious
developer must do this.
If you don't know what to type, try to enter correctly the word:
attaché-case (attache[acute]-case) :wink:

Regards to all.
Jean-Michel Fauth, Switzerland.

Very nice writeup, Jean-Michel. This should definitely go on the wxPython
wiki.

···

---
Patrick K. O'Brien
Orbtech

Character code and keyboards under windows

Thanks! I've just put this into the wiki at
http://wiki.wxpython.org/index.cgi/CharacterCodesAndKeyboards

···

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