International keyboards on Mac OS X SDL

Hi,
I maintain a Mac OS X SDL version of a Sinclair ZX Spectrum emulator
called Fuse.

I use SDL_PollEvent to get key events and examine the events retrieved
to send the press/release event to the correct emulated key using the
sym member of the SDL_keysym structure.

I have had reports from some users that when the Mac has an
international keyboard selected (i.e. not US/UK), various keys are not
handled properly.

Most recently an Italian user has reported that the number keys 1-0 do
not work with the Italian keyboard selected, if the program is started
with a US keyboard selected the keys work as expected.

Why does the sym member of SDL_keysym not have SDLK_1 when say an
Italian keyboard is selected, and how should I handle this situation
correctly?

TIA,
Fred

Hi Max,

Thanks for the clear and extensive reply!

Max Horn wrote:

Why does the sym member of SDL_keysym not have SDLK_1 when say an
Italian keyboard is selected, and how should I handle this situation
correctly?

I don’t know how italian keyboards look like, but maybe they share the
layout of french ones (where to get a ‘1’ you have to use Shift) ? It’s
pretty hard to tell the cause for sure w/o actually owning such a
keyboard. If anybody wants to donate non-german, non-british USB
keyboards to me (Italian, French, whatever else you have), I’ll happily
look into improving support for them. As it is, we have to rely on
testers to report problems and then try our fixes (or even better,
submit patches to us :slight_smile:

Only US-style keyboards here, but I saw this webpage which outlines a
few layouts:
http://www.sussex.ac.uk/USCS/Facilities/PC/Keyboards/

Anyway, I hope I was able to shed a little light on the issue of
keyboard input in SDL in general and on OSX in special. Feel free to
hammer me with further questions, just don’t forget that you need to CC
me since I am not on the list.

I am still not sure which approach is best when implementing an emulator:

  1. the positional layout may be important for some programs running on
    the emulator, and some emulated machine keyboards may have little in
    common with modern keyboards,
  2. the printed key value may be useful for the user due to it’s obvious
    mapping with the problems that the emulator may need to know which
    modifier keys are pressed on the source machine to interpret the symbol,
    and not all the keysyms on the emulated machine may be present on the
    keyboard,
  3. the character value has the same drawbacks as the printed key value
    approach.

In my case, the machines being emulated has a layout similar (but not
the same as) a modern UK or US keyboard, it has numbers 1-0 and letters
A-Z + some modifier keys and enter. I take the approach that the keys
map to the equivalent SDL keysym. e.g. when the user hits shift and
SDLK_1 the emulated machine sees it’s shift and 1 keys pressed. This
works well when the keyboard layout produces the same letters and
numbers as UK/US keyboards without shifting or extra keys, but not so
well for my Dutch or Italian users :(.

The extra difficulty with the computer being emulated is that there are
about 4 extended symbols that are not available on any modern keyboard
for each key which are accessed by various modifier keys being mapped to
emulator shift keys - this means that a French keyboard 1 looks like
shift-1 to the emulator.

I am starting to think that the best advice for users is to select a UK
or US layout before starting the emulator :frowning:

Fred

Max, any ideas?

I am sending my reply to the mailing list. Anybody who wants to reply,
please keep in mind I am not on the list, so if you want me to see your
mail, CC me :-)Am 28.02.2004 um 04:11 schrieb Darrell Walisser:

Begin forwarded message:

Message: 12
Date: Fri, 27 Feb 2004 17:23:31 +1100
From: Fred
To: sdl at libsdl.org
Subject: [SDL] International keyboards on Mac OS X SDL
Reply-To: sdl at libsdl.org

Hi,
I maintain a Mac OS X SDL version of a Sinclair ZX Spectrum emulator
called Fuse.

I use SDL_PollEvent to get key events and examine the events retrieved
to send the press/release event to the correct emulated key using the
sym member of the SDL_keysym structure.

I have had reports from some users that when the Mac has an
international keyboard selected (i.e. not US/UK), various keys are not
handled properly.

Most recently an Italian user has reported that the number keys 1-0 do
not work with the Italian keyboard selected, if the program is started
with a US keyboard selected the keys work as expected.

Let me first explain the background of the issue, which has two main
causes:

  1. A design problem with the SDL keyboard input system (and/or problems
    with how people (ab)use it)
  2. Limitations in the keyboard handling & mapping code on OS X.

The first issue is that SDL essentially tries to map three different
concepts onto only two members in the SDL_keysym struct. Let me explain
the three main different concepts:

(i) Positional: if an arcade game maps ‘y’ to “rotate left” and ‘x’ to
"rotate right", it does so because on an US keyboard, ‘y’ is to the
direct right of ‘x’.
Problem: This is not the case on e.g. a German keyboard, where 'z’
and ‘y’ are swapped. There is simply no way in SDL to specify a
keyboard mapping based on the position of the keys. Any attempts to do
so are doomed to fail. Hence esp. for games which rely on the key
position, it is vital to provide a way for the use to change the
mapping, else you are likely to alienate a lot of potential non-US
users.

(ii) What’s printed on the key: If in an RPG, ‘a’ maps to “attack” and
’q’ to “quaff” (for example), you don’t care where those keys are.
Problem #1: On a french keyboard (AFAIK), those two keys are swapped.
But it doesn’t matter, only what is printed on the keyboard counts.
This is what the SDLKey value in the SDL_keysym struct attempts.
Problem #2: However, on a french keyboard, there are normally no number
keys at the top - if you want a ‘1’ you have to press
Shift-. This can be a serious
problem for apps which want to map ‘1’ etc. to a function. Should SDL
map that key to SDLK_1 ? On the one hand that is what might be most
natural; but it would actually be a lie, since that is not they key
symbol. And, if you want to map ‘1’ and Shift-‘1’ to different things,
it might get confusing for those poor french users - for them, pressing
’1’ always implies pressing Shift, too…

(iii) Character value: That is actually in some sense the ‘easiest’:
you need this when you want to let the user type in some text. Well
luckily SDL has some Unicode support, at least on systems supporting
it; for most basic cases this is fully sufficient if you want to allow
the user to type in e.g. a name for the highscore, even if you don’t
add full unicode to your project (since the first 128 chars in unicode
are simply ASCII).

In all of the above, I completely ignored the issue totally different
keyboards (think of some asian ones). But still, I hope it outlines why
proper keyboard is actually a pretty hard issue (unlike what some
people think), because of the greatly varying needs. SDL’s keyboard
input designed currently simply is too limited to satisfy them all
properly (that’s one of the things I hope will get a redesign in SDL
2.0 :-).

Anyway, that was the SDL specific part; on OS X, you have some
additional problem. There exists three (or more, depending on how you
count) major APIs and OS subsytems to handle keyboard input. The bad
part is that they all apparently use a slightly different keyboard
mapping (or at least that’s how it used to be up and including 10.2; I
haven’t conducted proper tests on 10.3 yet). Add in that it’s not 100%
clear what an SDLKey mod value is supposed to mean, and you have a big
mess.

First off, we start with a fixed keycode-to-SDLKey mapping table (the
keyCode from NSEvent, which is a) hardware independent and b) identical
to kEventParamKeyCode in Carbon events - at least that’s what Apple’s
documentation claims). Next we query Carbon / the Script Manager for
the KCHR resource of the OS, which is used by Carbon to map scancodes.
We iterate over it and then adjust our scancode table with the data
derived from this. Finally, we have to do a last run where we re-adjust
the mappings of the keypad, since there is (apparently?) no way to
distinguish between normal and keypad keys within the KCHR resources.

If you think that is this a hack (even an evil one), I’ll agrre. But it
was the best solution I could come up with (and believe me, I tried a
lot); if anybody knows of a better one (and one which will also work on
10.1 and 10.2 !) please step forward and enlighten me, and my gratitude
will be yours forever :slight_smile:

Why does the sym member of SDL_keysym not have SDLK_1 when say an
Italian keyboard is selected, and how should I handle this situation
correctly?

I don’t know how italian keyboards look like, but maybe they share the
layout of french ones (where to get a ‘1’ you have to use Shift) ? It’s
pretty hard to tell the cause for sure w/o actually owning such a
keyboard. If anybody wants to donate non-german, non-british USB
keyboards to me (Italian, French, whatever else you have), I’ll happily
look into improving support for them. As it is, we have to rely on
testers to report problems and then try our fixes (or even better,
submit patches to us :slight_smile:

Anyway, I hope I was able to shed a little light on the issue of
keyboard input in SDL in general and on OSX in special. Feel free to
hammer me with further questions, just don’t forget that you need to CC
me since I am not on the list.

Cheers,

Max