[PATCH 1/2] Reworked the keymap so it is more flexible for suppo= mappings that include modifiers. Everything is explained in the updated = files. Removed SDL 1.2 support as per recent conversations on the hatari mailing list.

[ Thread Index | Date Index | More lists.tuxfamily.org/hatari-devel Archives ]


---
 doc/fr/clavier-exemple.txt |  268 +++++-----
 doc/keymap-sample.txt      |   90 ++--
 src/includes/keymap.h      |    2 +-
 src/keymap.c               | 1007 +++++++++++++++---------------------
 4 files changed, 619 insertions(+), 748 deletions(-)

diff --git a/doc/fr/clavier-exemple.txt b/doc/fr/clavier-exemple.txt
index d28a7628..abaf7766 100644
--- a/doc/fr/clavier-exemple.txt
+++ b/doc/fr/clavier-exemple.txt
@@ -1,131 +1,147 @@
-# This file must be UTF-8 coded
-# Mai 2017, Cocoa Pod.
-
-# FRENCH ------------------------------------------------
-# Mappage du clavier AZERTY-fr d'un Macbook Pro
-#
-# Tests sur Macbook Pro (MacBookPro5,3), MacOS 10.12 fr
-# Tests sur Macbook Air, MacOS 10.11 fr
-# Tests sur =C3=A9mulateur Hatari 2.0 _ ST, MegaST, STE, MegaSTE, tout T=
OS fr
-# Apple: Dans "Pr=C3=A9f=C3=A9rences Syst=C3=A8me / clavier",  Valider l=
'option :
-# "Utiliser les touches F1,F2,.... Comme des touches de fonction standar=
d"
-# F1-F8 presser la touche F, F9-F12  presser les touches cmd et F.
-#
-# Les commentaires commencent par un # ou un ;
-# Chaque ligne active commence par deux chiffres s=C3=A9par=C3=A9s par u=
ne virgule.
-# le premier est la valeur du symbole de la touche de votre clavier et l=
e
-# deuxi=C3=A8me est le scancode de la touche =C3=A9quivalente du clavier=
 Atari.
-# Le premier chiffre peut =C3=AAtre remplac=C3=A9 par un symbol.
-
-# ENGLISH ------------------------------------------------
-# Mapping for Macbook Pro keyboard AZERTY-fr
-#
-# Tested on Macbook Pro (MacBookPro5,3), MacOS 10.12 fr
-# Tested on Macbook Air, MacOS 10.11 fr
-# Tested on emulator Hatari 2.0 _ ST, MegaST, STE, MegaSTE, all TOS Fr
-# On Apple: in "System Preferences / Keyboard", Validate the option :
-#   "Use all F1,F2,.... as standard function keys "
-# F1-F8 press F key, F9-F12 press cmd and F keys
-#
-# 'keymap-sample.txt' file explains the syntax and values that can
-# be used for keyboard mapping.
-
-# function keys line
-#
- Escape,1
- F1,59
- F2,60
- F3,61
- F4,62
- F5,63
- F6,64
- F7,65
- F8,66
- F9,67	 # hit cmd-F9
- F10,68	 # hit cmd-F10
-# F11, 	 # cmd-F11  Does not exist in ATARI
-# F12,	 # cmd-F12  Does not exist in ATARI
-
-# first line: @ =C3=A9 " ' ( =C2=A7 =C3=A8 ! =C3=A7 =C3=A0 ) -
+# Keymap. Ce format permet d'associer des codes de touches (scancode) et=
 modificateurs
+# SDL (shift, alt, capslock, etc.) a une combinaison de touche correspon=
dante
+# sur l'ATARI =C3=A9mul=C3=A9.
 #
- <,43
- &,2
- =C3=A9,3
- ",4
- ',5
- (,6
- =C2=A7,7
- =C3=A8,8
- !,9
- =C3=A7,10
- =C3=A0,11
- ),12
- -,13
- Backspace,14
- Delete,83        #  fn + Backspace
-
-
-# second line: a z e r t y u i o p ^ $
+# Le format est le suivant:
+# <description_h=C3=B4te>,<description_Atari>
 #
- Tab,15
- a,16
- z,17
- e,18
- r,19
- t,20
- y,21
- u,22
- i,23
- o,24
- p,25
- ^,26
- $,27
-
-# third line: q s d f g h j k l m =C3=B9 `
+# <description_h=C3=B4te> est le code de touche (scancode en anglais) de=
 la touche du PC
+# concern=C3=A9e (visible dans la console quand on =C3=A9xecute hatari a=
vec l'option --trace keymap).=20
+# On peut aussi:
+# * Sp=C3=A9cifier un modificateur SDL (void https://wiki.libsdl.org/SDL=
_Keymod#Related_Functions)
+# * Ajouter un masque. Ce masque sera appliqu=C3=A9 avec l'op=C3=A9rateu=
r bool=C3=A9an ET =C3=A0 la touche
+#   press=C3=A9e avant qu'elle ne soit compar=C3=A9e aux entr=C3=A9es de=
 la liste d'association.
+#   Ceci permet d'ignorer le status de Verr.num de sorte qu'une associat=
ion puisse fonctionner
+#   ind=C3=A9pendemment de l'=C3=A9tat de cette touche.
+# Toutes ces sp=C3=A9cifications (scancode, modificateurs, masque) doive=
nt appara=C3=AEtre dans cet
+# ordre et =C3=AAtre s=C3=A9par=C3=A9s par le caract=C3=A8re barre verti=
cale '|'.
 #
- q,30
- s,31
- d,32
- f,33
- g,34
- h,35
- j,36
- k,37
- l,38
- m,39
- =C3=B9,40
- `,41
-
-# forth line: < w x c v b n , ; : =3D
+# <description_Atari> est la liste (s=C3=A9par=C3=A9e par barre vertical=
e '|') des touches =C3=A0 envoyer=20
+# =C3=A0 l'Atari (4 maximum). Par facilit=C3=A9, on peut utiliser LSHIFT=
, RSHIFT et ALTERNATE au lieu=20
+# de 2a,36,38 respectively, respectivement..
+# On peut trouver les codes de touche des Atari dans de nombreux livres =
et documentations,
+# par exemple:
+# https://tho-otto.de/keyboards/
+# or https://freemint.github.io/tos.hyp/en/scancode.html
 #
- @,96
- w,44
- x,45
- c,46
- v,47
- b,48
- n,49
- 44,50    # comma
- 59,51    # semicolon
- :,52
- =3D,53
-
- Space,57
- CapsLock,58
-
- Return,28
- Left,75
- Right,77
- Down,80
- Up,72
-
- Keypad Enter,114   # fn + Return
- Home,71            # fn + Left
- End,97             # fn + Right
- PageDown,100       # fn + Down
- PageUp,99          # fn + Up
+# Notes:
+# * Tous les codes de touches doivent =C3=AAtre en hexadecimal.
+# * L'analyseur n'est pas tr=C3=A8s sophistiqu=C3=A9 donc n'ajoutez pas =
d'espace etc au milieu des specifications.
+# * Les associations les plus limitantes doivent appara=C3=AEtre en prem=
ier dans le fichier car elles ont priorit=C3=A9.
=20
- Left Ctrl,29
- Left Shift,42
-# Left Alt,56      # fail, but not need to remap !!!!!
- Right Shift,54
+04,1e
+# ,
+10,32
+# ?
+10|KMOD_LSHIFT|KMOD_LSHIFT,LSHIFT|33
+10|KMOD_RSHIFT|KMOD_RSHIFT,RSHIFT|33
+# a
+14,10
+# z
+1a,11
+# w
+1d,2c
+# 1
+1e|KMOD_LSHIFT|KMOD_LSHIFT,LSHIFT|02
+1e|KMOD_RSHIFT|KMOD_RSHIFT,RSHIFT|02
+1e|KMOD_CAPS|KMOD_CAPS,02
+# ~
+1f|KMOD_RALT|KMOD_RALT,LSHIFT|ALTERNATE|2b
+# 2
+1f|KMOD_LSHIFT|KMOD_LSHIFT,LSHIFT|03
+1f|KMOD_RSHIFT|KMOD_RSHIFT,RSHIFT|03
+1f|KMOD_CAPS|KMOD_CAPS,03
+# #
+20|KMOD_RALT|KMOD_RALT,2b
+# 3
+20|KMOD_LSHIFT|KMOD_LSHIFT,LSHIFT|04
+20|KMOD_RSHIFT|KMOD_RSHIFT,RSHIFT|04
+20|KMOD_CAPS|KMOD_CAPS,04
+# {
+21|KMOD_RALT|KMOD_RALT,2a|ALTERNATE|1a
+# 4
+21|KMOD_LSHIFT|KMOD_LSHIFT,LSHIFT|05
+21|KMOD_RSHIFT|KMOD_RSHIFT,RSHIFT|05
+# [
+22|KMOD_RALT|KMOD_RALT,ALTERNATE|1a
+# 5
+22|KMOD_LSHIFT|KMOD_LSHIFT,LSHIFT|06
+22|KMOD_RSHIFT|KMOD_RSHIFT,RSHIFT|06
+# |
+23|KMOD_RALT|KMOD_RALT,LSHIFT|2b
+# 6
+23|KMOD_LSHIFT|KMOD_LSHIFT,LSHIFT|07
+23|KMOD_RSHIFT|KMOD_RSHIFT,RSHIFT|07
+# -
+23,0d
+# 7
+24|KMOD_LSHIFT|KMOD_LSHIFT,LSHIFT|08
+24|KMOD_RSHIFT|KMOD_RSHIFT,RSHIFT|08
+# `
+24|KMOD_RALT|KMOD_RALT,29
+# 8
+25|KMOD_LSHIFT|KMOD_LSHIFT,LSHIFT|09
+25|KMOD_RSHIFT|KMOD_RSHIFT,RSHIFT|09
+# \
+25|KMOD_RALT|KMOD_RALT,ALTERNATE|28
+# _
+25,LSHIFT|0d
+# ^
+26|KMOD_RALT|KMOD_RALT,1a
+# 9
+26|KMOD_LSHIFT|KMOD_LSHIFT,LSHIFT|0a
+26|KMOD_RSHIFT|KMOD_RSHIFT,RSHIFT|0a
+# @
+27|KMOD_RALT|KMOD_RALT,ALTERNATE|2b
+# 0
+27|KMOD_LSHIFT|KMOD_LSHIFT,LSHIFT|0b
+27|KMOD_RSHIFT|KMOD_RSHIFT,RSHIFT|0b
+# =C2=B0
+2d|KMOD_LSHIFT|KMOD_LSHIFT,LSHIFT|0c
+2d|KMOD_RSHIFT|KMOD_RSHIFT,RSHIFT|0c
+# ]
+2d|KMOD_RALT|KMOD_RALT,ALTERNATE|1b
+# + (pr=C3=A8s de efface)
+2e|KMOD_SHIFT|KMOD_SHIFT,RSHIFT|35
+# }
+2e|KMOD_RALT|KMOD_RALT,LSHIFT|ALTERNATE|1b
+# =3D
+2e,35
+# =C2=A8
+2f|KMOD_LSHIFT|KMOD_LSHIFT,LSHIFT|1a
+2f|KMOD_RSHIFT|KMOD_RSHIFT,RSHIFT|1a
+# ^
+2f,1a
+# =C2=A3
+30|KMOD_LSHIFT|KMOD_LSHIFT,LSHIFT|29
+30|KMOD_RSHIFT|KMOD_RSHIFT,RSHIFT|29
+# $
+30,1b
+# =C2=B5, ouaip, on peut m=C3=AAme =C3=A9muler les ALT-xyz :)
+31|KMOD_LSHIFT|KMOD_LSHIFT,ALTERNATE|6e|6f|70
+31|KMOD_RSHIFT|KMOD_RSHIFT,ALTERNATE|6e|6f|70
+# * (pas pav=C3=A9 num=C3=A9rique)
+31,RSHIFT|1b
+# m
+33|KMOD_LSHIFT|KMOD_LSHIFT,LSHIFT|27
+33|KMOD_RSHIFT|KMOD_RSHIFT,RSHIFT|27
+33|KMOD_LALT|KMOD_LALT,ALTERNATE|27
+33,27
+# %
+34|KMOD_LSHIFT|KMOD_LSHIFT,LSHIFT|28
+34|KMOD_RSHIFT|KMOD_RSHIFT,RSHIFT|28
+# =C3=B9
+34,28
+# =C2=B3 (alt-239)
+35|KMOD_LSHIFT|KMOD_LSHIFT,ALTERNATE|6e|6b|6a
+35|KMOD_RSHIFT|KMOD_RSHIFT,ALTERNATE|6e|6b|6a
+# =C2=B2 (alt-253)
+35,ALTERNATE|6e|6b|6f
+# ;
+36,33
+# . (pas pav=C3=A9 num=C3=A9rique)
+36|KMOD_LSHIFT|KMOD_LSHIFT,LSHIFT|33
+36|KMOD_RSHIFT|KMOD_RSHIFT,RSHIFT|33
+# =C2=A7
+38|KMOD_LSHIFT|KMOD_LSHIFT,07
+38|KMOD_RSHIFT|KMOD_RSHIFT,07
diff --git a/doc/keymap-sample.txt b/doc/keymap-sample.txt
index 1c399561..16312f4b 100644
--- a/doc/keymap-sample.txt
+++ b/doc/keymap-sample.txt
@@ -1,36 +1,54 @@
-# This is an example for a keyboard mapping file that can be used in Hat=
ari
-# by loading it from the keyboard setup dialog.
-#
-# Lines starting with a '#' or with a ';' are comments. All other lines
-# should contain exactly one key name and a scancode, separated by a com=
ma.
-# Comment characters can be quoted with '\#' and '\;'.
-#
-# The key name is the libSDL symbolic name of the key, see the following
-# URL for a list: https://wiki.libsdl.org/SDL_Keycode
-# You can also use the symbolic keycode value instead of the name,
-# which you can get with the "--trace keymap" output from Hatari, for
-# example, but note that the values are different between SDL1 and SDL2
-# and thus they are not portable.
-#
-# The given host key will be mapped to the ST key which is specified by
-# second number - the ST scan code of the key.  "--trace keymap" output
-# shows the already mapped scan code.
-#
-# All numbers should be given as decimals (not hexadecimals).
-#
-# Note that using keyboard mapping file causes Hatari to use symbolic
-# key mapping.  Symbolic key mapping does not work with so called "dead"
-# keys.
-#
-# Scan codes for Atari keyboard key positions can be seen here:
-#   http://eerott.mbnet.fi/hatari/img/st-keymap.png
-#
-# tests/keymap/ directory contains programs to discover/test the PC SDL
-# and Atari scan code values.  Hatari's default PC key code -> ST scan
-# code mappings are in src/keymap.c source file.
-#
-# Example: If you want to get the 'y' and 'z' keys right with a german T=
OS
-# ROM, you can use the following two lines to map the PC keys to the rig=
ht
-# ST scan codes:
-Y,44
-Z,21
+# Keymap. This format allows you to associate SDL key descriptions with
+# scancodes simulating the corresponding keys pressed on the emulated ST=
..
+#
+# Format is the following:
+# <host_description>,<guest_description>
+#
+# <host_description> is the scancode of the key pressed (which you can s=
ee
+# when running hatari with the "--trace keymap" option).=20
+# Optionally you can:
+# * Add a SDL key modifier (see https://wiki.libsdl.org/SDL_Keymod#Relat=
ed_Functions)
+# * Add a modifier mask. This mask will be bitwise "AND"'ed to the
+#   actual key pressed before it is compared with items from this keymap=
..
+#   This allows to mask out e.g. NumLock to make mappings work regardles=
s=20
+#   of the status of that modifier.
+# All these (scancode, modifiers, mask) must appear in this order and be
+# separated by a pipe |.
+#
+# <guest_description> is the pipe-separated ordered list of scancodes to=
 send
+# to the ST (4 max). For convenience you can use LSHIFT, RSHIFT and
+# ALTERNATE in lieu of 2a,36,38 respectively.
+# You can find scancodes in many Atari documentation places, e.g.
+# https://tho-otto.de/keyboards/
+# or https://freemint.github.io/tos.hyp/en/scancode.html
+#
+# Notes:
+# * All scan codes must be in hexadecimal.
+# * The parser is not very smart so don't add spaces etc.
+# * Make the narrowest specification appear first.
+#
+# Examples (taken from the French keyboard mapping):
+
+# Simple scancode mapping
+04,1e
+
+# Mapping with SHIFT keys and mask (LSHIFT) to mask out other modifiers
+# like Numlock, so these mapping (for left and right shift) will work
+# regardless of Numlock
+10|KMOD_LSHIFT|KMOD_LSHIFT,LSHIFT|33
+10|KMOD_RSHIFT|KMOD_RSHIFT,RSHIFT|33
+
+
+# Mapping with modifier, which converst a shifted key from the host
+# to ALT-230 to display =C2=B5 on the Atari
+31|KMOD_LSHIFT|KMOD_LSHIFT,ALTERNATE|6e|6f|70
+
+
+# Mapping for CAPS LOCK 1 and shift keys, to obtain "1"
+1e|KMOD_LSHIFT|KMOD_LSHIFT,LSHIFT|02
+1e|KMOD_RSHIFT|KMOD_RSHIFT,RSHIFT|02
+1e|KMOD_CAPS|KMOD_CAPS,02
+
+# Mapping for ALT-key on the PC ~, translated to ALT-SHIFT-key
+# on the Atari
+1f|KMOD_RALT|KMOD_RALT,LSHIFT|ALTERNATE|2b
diff --git a/src/includes/keymap.h b/src/includes/keymap.h
index a443386d..1d743e1f 100644
--- a/src/includes/keymap.h
+++ b/src/includes/keymap.h
@@ -33,7 +33,7 @@
 #endif
=20
 extern void Keymap_Init(void);
-extern void Keymap_LoadRemapFile(char *pszFileName);
+extern void Keymap_LoadRemapFile(const char *pszFileName);
 extern void Keymap_DebounceAllKeys(void);
 extern void Keymap_KeyDown(SDL_keysym *sdlkey);
 extern void Keymap_KeyUp(SDL_keysym *sdlkey);
diff --git a/src/keymap.c b/src/keymap.c
index dc4119a4..6efda8fd 100644
--- a/src/keymap.c
+++ b/src/keymap.c
@@ -4,9 +4,10 @@
   This file is distributed under the GNU General Public License, version=
 2
   or at your option any later version. Read the file gpl.txt for details=
..
=20
-  Here we process a key press and the remapping of the scancodes.
+  This file is about being able to map SDL key events to scancodes to se=
nd
+  to the IKBD as pressed/released keys.
+  It is done in several ways, controlled by the configuration.
 */
-const char Keymap_fileid[] =3D "Hatari keymap.c";
=20
 #include <ctype.h>
 #include "main.h"
@@ -21,26 +22,49 @@ const char Keymap_fileid[] =3D "Hatari keymap.c";
 #include "debugui.h"
 #include "log.h"
=20
+/* Highest scancode number. See https://wiki.libsdl.org/SDLScancodeLooku=
p */
+#define MAX_SDLK_SCANCODES 284+1=20
=20
-#if !WITH_SDL2
-/* This table is used to translate a symbolic keycode to the (SDL) scanc=
ode */
-static Uint8 SdlSymToSdlScan[SDLK_LAST];
-#endif
+/* Scancodes of ST keyboard */
+#define ST_ESC		 0x01
+#define ST_CTRL		0x1d
+#define ST_LSHIFT	0x2a
+#define ST_RSHIFT	0x36
+#define ST_ALTERNATE 	0x38
+#define ST_CAPSLOCK	0x3a
=20
-/* Table for loaded keys: */
-static int LoadedKeymap[KBD_MAX_SCANCODE][2];
+/* Key mappings: pair a SDL definition with a list of keys we have to pr=
ess/release on the ST */
+#define MAX_ST_SCANCODES 4 /* Max is alt-a-b-c, so 4 chars */
+struct KeyMapping
+{
+	/* Input on PC keyboard */
+	SDL_keysym SdlKeysym;
+	SDL_Keymod modmask;
+	/* Output on the ST's keyboard */
+	uint8_t	   STScanCodesLength;
+	uint8_t    STScanCodes[MAX_ST_SCANCODES];
+	/* What modifiers we effectively had to press (and will have to release=
 when the key is up.
+	 * WARNING: this assumes the keyboard doesn't let you press a key that =
is already pressed. */
+	uint8_t	   PressedModifiers[MAX_ST_SCANCODES];
+};
+static struct KeyMapping LoadedKeyMap[KBD_MAX_SCANCODE];
+static struct KeyMapping KeysDownMapping[MAX_SDLK_SCANCODES]; /* Mapping=
s associated with keys when they're down. The index is the SDL scancode. =
*/
=20
 /* List of ST scan codes to NOT de-bounce when running in maximum speed =
*/
 static const char DebounceExtendedKeys[] =3D
 {
-	0x1d,  /* CTRL */
-	0x2a,  /* Left SHIFT */
-	0x01,  /* ESC */
-	0x38,  /* ALT */
-	0x36,  /* Right SHIFT */
-	0      /* term */
+	ST_CTRL,
+	ST_LSHIFT,
+	ST_ESC,
+	ST_ALTERNATE,
+	ST_RSHIFT,
+	0  /* End of list */
 };
=20
+/* Helper functions for parsing the keymap file */
+static int HostSpecToSDLKeysym(const char *spec, struct KeyMapping* resu=
lt);
+static int GuestSpecToSTScanCodes(const char *spec, struct KeyMapping *r=
esult);
+static SDL_Keymod SDLKeymodFromName(const char *name);
=20
=20
 /*----------------------------------------------------------------------=
-*/
@@ -49,18 +73,17 @@ static const char DebounceExtendedKeys[] =3D
  */
 void Keymap_Init(void)
 {
-#if !WITH_SDL2
-	memset(SdlSymToSdlScan, 0, sizeof(SdlSymToSdlScan));      /* Clear arra=
y */
-#endif
 	Keymap_LoadRemapFile(ConfigureParams.Keyboard.szMappingFileName);
 }
=20
+
 /**
- * Map SDL symbolic key to ST scan code
+ * Map SDL symbolic key to ST scan code.
+ * This assumes a QWERTY ST keyboard.
  */
-static char Keymap_SymbolicToStScanCode(SDL_keysym* pKeySym)
+static uint8_t Keymap_SymbolicToStScanCode(const SDL_keysym* pKeySym)
 {
-	char code;
+	uint8_t code;
=20
 	switch (pKeySym->sym)
 	{
@@ -68,7 +91,7 @@ static char Keymap_SymbolicToStScanCode(SDL_keysym* pKe=
ySym)
 	 case SDLK_TAB: code =3D 0x0F; break;
 	 case SDLK_CLEAR: code =3D 0x47; break;
 	 case SDLK_RETURN: code =3D 0x1C; break;
-	 case SDLK_ESCAPE: code =3D 0x01; break;
+	 case SDLK_ESCAPE: code =3D ST_ESC; break;
 	 case SDLK_SPACE: code =3D 0x39; break;
 	 case SDLK_EXCLAIM: code =3D 0x09; break;     /* on azerty? */
 	 case SDLK_QUOTEDBL: code =3D 0x04; break;    /* on azerty? */
@@ -135,24 +158,11 @@ static char Keymap_SymbolicToStScanCode(SDL_keysym*=
 pKeySym)
 	 case SDLK_z: code =3D 0x2C; break;
 	 case SDLK_DELETE: code =3D 0x53; break;
 	 /* End of ASCII mapped keysyms */
-#if WITH_SDL2
 	 case 180: code =3D 0x0D; break;
 	 case 223: code =3D 0x0C; break;
 	 case 228: code =3D 0x28; break;
 	 case 246: code =3D 0x27; break;
 	 case 252: code =3D 0x1A; break;
-#else /* !WITH_SDL2 */
-	 case SDLK_WORLD_0: code =3D 0x0d; break;
-	 case SDLK_WORLD_1: code =3D 0x0c; break;
-	 case SDLK_WORLD_2: code =3D 0x1a; break;
-	 case SDLK_WORLD_3: code =3D 0x28; break;
-	 case SDLK_WORLD_4: code =3D 0x27; break;
-	 case SDLK_WORLD_20: code =3D 0x0D; break;
-	 case SDLK_WORLD_63: code =3D 0x0C; break;
-	 case SDLK_WORLD_68: code =3D 0x28; break;
-	 case SDLK_WORLD_86: code =3D 0x27; break;
-	 case SDLK_WORLD_92: code =3D 0x1A; break;
-#endif /* !WITH_SDL2 */
 	 /* Numeric keypad: */
 	 case SDLK_KP0: code =3D 0x70; break;
 	 case SDLK_KP1: code =3D 0x6D; break;
@@ -196,14 +206,14 @@ static char Keymap_SymbolicToStScanCode(SDL_keysym*=
 pKeySym)
 	 case SDLK_F12: code =3D 0x61; break;
 	 case SDLK_F13: code =3D 0x62; break;
 	 /* Key state modifier keys */
-	 case SDLK_CAPSLOCK: code =3D 0x3A; break;
+	 case SDLK_CAPSLOCK: code =3D ST_CAPSLOCK; break;
 	 case SDLK_SCROLLOCK: code =3D 0x61; break;
-	 case SDLK_RSHIFT: code =3D 0x36; break;
-	 case SDLK_LSHIFT: code =3D 0x2A; break;
-	 case SDLK_RCTRL: code =3D 0x1D; break;
-	 case SDLK_LCTRL: code =3D 0x1D; break;
-	 case SDLK_RALT: code =3D 0x38; break;
-	 case SDLK_LALT: code =3D 0x38; break;
+	 case SDLK_RSHIFT: code =3D ST_RSHIFT; break;
+	 case SDLK_LSHIFT: code =3D ST_LSHIFT; break;
+	 case SDLK_RCTRL: code =3D ST_CTRL; break;
+	 case SDLK_LCTRL: code =3D ST_CTRL; break;
+	 case SDLK_RALT: code =3D ST_ALTERNATE; break;
+	 case SDLK_LALT: code =3D ST_ALTERNATE; break;
 	 /* Miscellaneous function keys */
 	 case SDLK_HELP: code =3D 0x62; break;
 	 case SDLK_PRINT: code =3D 0x62; break;
@@ -215,12 +225,10 @@ static char Keymap_SymbolicToStScanCode(SDL_keysym*=
 pKeySym)
 }
=20
=20
-#if WITH_SDL2
-
 /**
  * Remap SDL scancode key to ST Scan code - this is the version for SDL2
  */
-static char Keymap_PcToStScanCode(SDL_keysym* pKeySym)
+static uint8_t Keymap_PcToStScanCode(const SDL_keysym* pKeySym)
 {
 	switch (pKeySym->scancode)
 	{
@@ -321,7 +329,7 @@ static char Keymap_PcToStScanCode(SDL_keysym* pKeySym=
)
 	 case SDL_SCANCODE_KP_0: return 0x70;
 	 case SDL_SCANCODE_KP_PERIOD: return 0x71;
 	 case SDL_SCANCODE_NONUSBACKSLASH: return 0x60;
-	 //case SDL_SCANCODE_APPLICATION: return ;
+	 /*case SDL_SCANCODE_APPLICATION: return ;*/
 	 case SDL_SCANCODE_KP_EQUALS: return 0x63;
 	 case SDL_SCANCODE_F13: return 0x63;
 	 case SDL_SCANCODE_F14: return 0x64;
@@ -340,11 +348,11 @@ static char Keymap_PcToStScanCode(SDL_keysym* pKeyS=
ym)
 	 case SDL_SCANCODE_KP_HASH: return 0x0c;
 	 case SDL_SCANCODE_KP_SPACE: return 0x39;
 	 case SDL_SCANCODE_KP_CLEAR: return 0x47;
-	 case SDL_SCANCODE_LCTRL: return 0x1d;
-	 case SDL_SCANCODE_LSHIFT: return 0x2a;
-	 case SDL_SCANCODE_LALT: return 0x38;
-	 case SDL_SCANCODE_RCTRL: return 0x1d;
-	 case SDL_SCANCODE_RSHIFT: return 0x36;
+	 case SDL_SCANCODE_LCTRL: return ST_CTRL;
+	 case SDL_SCANCODE_LSHIFT: return ST_LSHIFT;
+	 case SDL_SCANCODE_LALT: return ST_ALTERNATE;
+	 case SDL_SCANCODE_RCTRL: return ST_CTRL;
+	 case SDL_SCANCODE_RSHIFT: return ST_RSHIFT;
 	 default:
 		if (!pKeySym->scancode && pKeySym->sym)
 		{
@@ -360,181 +368,13 @@ static char Keymap_PcToStScanCode(SDL_keysym* pKey=
Sym)
 	}
 }
=20
-#else /* !WITH_SDL2 */
-
-/**
- * Heuristic analysis to find out the obscure scancode offset.
- * Some keys like 'z' can't be used for detection since they are on diff=
erent
- * locations on "qwertz" and "azerty" keyboards.
- * This clever code has originally been taken from the emulator Aranym. =
(cheers!)
- */
-static int Keymap_FindScanCodeOffset(SDL_keysym* keysym)
-{
-	int offset =3D -1;    /* uninitialized scancode offset */
-	int scanPC =3D keysym->scancode;
-
-	if (scanPC =3D=3D 0)  return -1; /* Ignore illegal scancode */
-
-	switch (keysym->sym)
-	{
-	 case SDLK_ESCAPE: offset =3D scanPC - 0x01; break;
-	 case SDLK_1:  offset =3D scanPC - 0x02; break;
-	 case SDLK_2:  offset =3D scanPC - 0x03; break;
-	 case SDLK_3:  offset =3D scanPC - 0x04; break;
-	 case SDLK_4:  offset =3D scanPC - 0x05; break;
-	 case SDLK_5:  offset =3D scanPC - 0x06; break;
-	 case SDLK_6:  offset =3D scanPC - 0x07; break;
-	 case SDLK_7:  offset =3D scanPC - 0x08; break;
-	 case SDLK_8:  offset =3D scanPC - 0x09; break;
-	 case SDLK_9:  offset =3D scanPC - 0x0a; break;
-	 case SDLK_0:  offset =3D scanPC - 0x0b; break;
-	 case SDLK_BACKSPACE: offset =3D scanPC - 0x0e; break;
-	 case SDLK_TAB:    offset =3D scanPC - 0x0f; break;
-	 case SDLK_RETURN: offset =3D scanPC - 0x1c; break;
-	 case SDLK_SPACE:  offset =3D scanPC - 0x39; break;
-	 /*case SDLK_q:  offset =3D scanPC - 0x10; break;*/  /* different on az=
erty */
-	 /*case SDLK_w:  offset =3D scanPC - 0x11; break;*/  /* different on az=
erty */
-	 case SDLK_e:  offset =3D scanPC - 0x12; break;
-	 case SDLK_r:  offset =3D scanPC - 0x13; break;
-	 case SDLK_t:  offset =3D scanPC - 0x14; break;
-	 /*case SDLK_y:  offset =3D scanPC - 0x15; break;*/  /* different on qw=
ertz */
-	 case SDLK_u:  offset =3D scanPC - 0x16; break;
-	 case SDLK_i:  offset =3D scanPC - 0x17; break;
-	 case SDLK_o:  offset =3D scanPC - 0x18; break;
-	 case SDLK_p:  offset =3D scanPC - 0x19; break;
-	 /*case SDLK_a:  offset =3D scanPC - 0x1e; break;*/  /* different on az=
erty */
-	 case SDLK_s:  offset =3D scanPC - 0x1f; break;
-	 case SDLK_d:  offset =3D scanPC - 0x20; break;
-	 case SDLK_f:  offset =3D scanPC - 0x21; break;
-	 case SDLK_g:  offset =3D scanPC - 0x22; break;
-	 case SDLK_h:  offset =3D scanPC - 0x23; break;
-	 case SDLK_j:  offset =3D scanPC - 0x24; break;
-	 case SDLK_k:  offset =3D scanPC - 0x25; break;
-	 case SDLK_l:  offset =3D scanPC - 0x26; break;
-	 /*case SDLK_z:  offset =3D scanPC - 0x2c; break;*/  /* different on qw=
ertz and azerty */
-	 case SDLK_x:  offset =3D scanPC - 0x2d; break;
-	 case SDLK_c:  offset =3D scanPC - 0x2e; break;
-	 case SDLK_v:  offset =3D scanPC - 0x2f; break;
-	 case SDLK_b:  offset =3D scanPC - 0x30; break;
-	 case SDLK_n:  offset =3D scanPC - 0x31; break;
-	 /*case SDLK_m:  offset =3D scanPC - 0x32; break;*/  /* different on az=
erty */
-	 case SDLK_CAPSLOCK:  offset =3D scanPC - 0x3a; break;
-	 case SDLK_LSHIFT: offset =3D scanPC - 0x2a; break;
-	 case SDLK_LCTRL: offset =3D scanPC - 0x1d; break;
-	 case SDLK_LALT: offset =3D scanPC - 0x38; break;
-	 case SDLK_F1:  offset =3D scanPC - 0x3b; break;
-	 case SDLK_F2:  offset =3D scanPC - 0x3c; break;
-	 case SDLK_F3:  offset =3D scanPC - 0x3d; break;
-	 case SDLK_F4:  offset =3D scanPC - 0x3e; break;
-	 case SDLK_F5:  offset =3D scanPC - 0x3f; break;
-	 case SDLK_F6:  offset =3D scanPC - 0x40; break;
-	 case SDLK_F7:  offset =3D scanPC - 0x41; break;
-	 case SDLK_F8:  offset =3D scanPC - 0x42; break;
-	 case SDLK_F9:  offset =3D scanPC - 0x43; break;
-	 case SDLK_F10: offset =3D scanPC - 0x44; break;
-	 default:  break;
-	}
-
-	if (offset !=3D -1)
-	{
-		Log_Printf(LOG_WARN, "Detected scancode offset =3D %d (key: '%s' with =
scancode $%02x)\n",
-		        offset, SDL_GetKeyName(keysym->sym), scanPC);
-	}
-
-	return offset;
-}
-
-
-/**
- * Map PC scancode to ST scancode.
- * This code was heavily inspired by the emulator Aranym. (cheers!)
- */
-static char Keymap_PcToStScanCode(SDL_keysym* keysym)
-{
-	static int offset =3D -1;    /* uninitialized scancode offset */
-
-	/* We sometimes enter here with an illegal (=3D0) scancode, so we keep
-	 * track of the right scancodes in a table and then use a value from th=
ere.
-	 */
-	if (keysym->scancode !=3D 0)
-	{
-		SdlSymToSdlScan[keysym->sym] =3D keysym->scancode;
-	}
-	else
-	{
-		keysym->scancode =3D SdlSymToSdlScan[keysym->sym];
-		if (keysym->scancode =3D=3D 0)
-			Log_Printf(LOG_WARN, "Key scancode is 0!\n");
-	}
-
-	switch (keysym->sym)
-	{
-	 /* Numeric Pad */
-	 /* note that the numbers are handled in Keymap_GetKeyPadScanCode()! */
-	 case SDLK_KP_DIVIDE:   return 0x65;  /* Numpad / */
-	 case SDLK_KP_MULTIPLY: return 0x66;  /* NumPad * */
-	 case SDLK_KP_MINUS:    return 0x4a;  /* NumPad - */
-	 case SDLK_KP_PLUS:     return 0x4e;  /* NumPad + */
-	 case SDLK_KP_PERIOD:   return 0x71;  /* NumPad . */
-	 case SDLK_KP_ENTER:    return 0x72;  /* NumPad Enter */
-
-	 /* Special Keys */
-	 case SDLK_PRINT:    return 0x62;  /* Help */
-	 case SDLK_SCROLLOCK: return 0x61; /* Undo */
-	 case SDLK_PAGEUP:   return 0x63;  /* Keypad ( */
-	 case SDLK_PAGEDOWN: return 0x64;  /* Keypad ) */
-	 case SDLK_HOME:     return 0x47;  /* Home */
-	 case SDLK_END:      return 0x60;  /* End =3D> "<>" on German Atari kbd=
 */
-	 case SDLK_UP:       return 0x48;  /* Arrow Up */
-	 case SDLK_LEFT:     return 0x4b;  /* Arrow Left */
-	 case SDLK_RIGHT:    return 0x4d;  /* Arrow Right */
-	 case SDLK_DOWN:     return 0x50;  /* Arrow Down */
-	 case SDLK_INSERT:   return 0x52;  /* Insert */
-	 case SDLK_DELETE:   return 0x53;  /* Delete */
-	 case SDLK_LESS:     return 0x60;  /* "<" */
-
-	 /* Map Right Alt/Alt Gr/Control to the Atari keys */
-	 case SDLK_RCTRL:  return 0x1d;  /* Control */
-	 case SDLK_RALT:   return 0x38;  /* Alternate */
-
-	 default:
-		/* Process remaining keys: assume that it's PC101 keyboard
-		 * and that it is compatible with Atari ST keyboard (basically
-		 * same scancodes but on different platforms with different
-		 * base offset (framebuffer =3D 0, X11 =3D 8).
-		 * Try to detect the offset using a little bit of black magic.
-		 * If offset is known then simply pass the scancode. */
-		if (offset =3D=3D -1)
-		{
-			offset =3D Keymap_FindScanCodeOffset(keysym);
-		}
-
-		if (offset >=3D 0)
-		{
-			/* offset is defined so pass the scancode directly */
-			return (keysym->scancode - offset);
-		}
-		else
-		{
-			/* Failed to detect offset, so use default value 8 */
-			Log_Printf(LOG_WARN, "Offset detection failed with "
-			        "key '%s', scancode =3D 0x%02x, symcode =3D  0x%02x\n",
-			        SDL_GetKeyName(keysym->sym), keysym->scancode, keysym->sym);
-			return (keysym->scancode - 8);
-		}
-		break;
-	}
-}
-
-#endif	/* !WITH_SDL2 */
-
=20
 /**
  * Remap a keypad key to ST scan code. We use a separate function for th=
is
  * so that we can easily toggle between number and cursor mode with the
  * numlock key.
  */
-static char Keymap_GetKeyPadScanCode(SDL_keysym* pKeySym)
+static char Keymap_GetKeyPadScanCode(const SDL_keysym* pKeySym)
 {
 	if (SDL_GetModState() & KMOD_NUM)
 	{
@@ -573,39 +413,78 @@ static char Keymap_GetKeyPadScanCode(SDL_keysym* pK=
eySym)
 }
=20
=20
+static int InputMatchesKeyMapping(const SDL_keysym* keySym, const struct=
 KeyMapping *mapping)
+{
+	if (keySym->scancode =3D=3D mapping->SdlKeysym.scancode)
+		LOG_TRACE(TRACE_KEYMAP,"matching 0x%04x and 0x%04x\n", keySym->mod & m=
apping->modmask, mapping->SdlKeysym.mod);
+	return keySym->scancode =3D=3D mapping->SdlKeysym.scancode
+		&& (keySym->mod & mapping->modmask) =3D=3D mapping->SdlKeysym.mod;
+}
+
+
 /**
  * Remap SDL Key to ST Scan code
+ * Receives the pressed key from SDL, and returns a matching key mapping=
..
  */
-static char Keymap_RemapKeyToSTScanCode(SDL_keysym* pKeySym)
+static struct KeyMapping* Keymap_RemapKeyToSTScanCodes(SDL_keysym* pKeyS=
ym, bool enableTrace)
 {
+	struct KeyMapping *keyDownMapping =3D &KeysDownMapping[pKeySym->scancod=
e];
+
 	/* Check for keypad first so we can handle numlock */
 	if (ConfigureParams.Keyboard.nKeymapType !=3D KEYMAP_LOADED)
 	{
 		if (pKeySym->sym >=3D SDLK_KP1 && pKeySym->sym <=3D SDLK_KP9)
 		{
-			return Keymap_GetKeyPadScanCode(pKeySym);
+			keyDownMapping->STScanCodes[0] =3D Keymap_GetKeyPadScanCode(pKeySym);
+			keyDownMapping->STScanCodesLength =3D 1;
+			return keyDownMapping;
 		}
 	}
=20
 	/* Remap from PC scancodes? */
 	if (ConfigureParams.Keyboard.nKeymapType =3D=3D KEYMAP_SCANCODE)
 	{
-		return Keymap_PcToStScanCode(pKeySym);
+		keyDownMapping->STScanCodes[0] =3D Keymap_PcToStScanCode(pKeySym);
+		keyDownMapping->STScanCodesLength =3D 1;
+		return keyDownMapping;
 	}
=20
 	/* Use loaded keymap? */
 	if (ConfigureParams.Keyboard.nKeymapType =3D=3D KEYMAP_LOADED)
 	{
-		int i;
-		for (i =3D 0; i < KBD_MAX_SCANCODE && LoadedKeymap[i][1] !=3D 0; i++)
+		int i,j;
+
+		for (i =3D 0; i < KBD_MAX_SCANCODE; i++)
 		{
-			if (pKeySym->sym =3D=3D (SDLKey)LoadedKeymap[i][0])
-				return LoadedKeymap[i][1];
+			struct KeyMapping *mapping =3D &LoadedKeyMap[i];
+
+			if (mapping->SdlKeysym.scancode =3D=3D 0)
+				break; /* End of table */
+
+			if (!InputMatchesKeyMapping(pKeySym, mapping))
+				continue;
+
+			if (enableTrace)
+			{
+				/* This is pretty inefficient, that's why it's protected by a switch=
 */
+				LOG_TRACE(TRACE_KEYMAP,"  Mapping: ");
+				for (j =3D 0; j < mapping->STScanCodesLength; j++)
+					LOG_TRACE(TRACE_KEYMAP,"%02x ", mapping->STScanCodes[j]);
+				LOG_TRACE(TRACE_KEYMAP,"(from keymap)\n");
+			}
+
+			*keyDownMapping =3D *mapping;
+			return keyDownMapping;
 		}
 	}
=20
-	/* Use symbolic mapping */
-	return Keymap_SymbolicToStScanCode(pKeySym);
+	/* Fall back to symbolic mapping */
+	keyDownMapping->STScanCodes[0] =3D Keymap_SymbolicToStScanCode(pKeySym)=
;
+	keyDownMapping->STScanCodesLength =3D 1;
+
+	if (enableTrace)
+		LOG_TRACE(TRACE_KEYMAP,"  Mapping: %02x (symbolic)\n",keyDownMapping->=
STScanCodes[0]);
+	return keyDownMapping;
 }
=20
=20
@@ -613,20 +492,28 @@ static char Keymap_RemapKeyToSTScanCode(SDL_keysym*=
 pKeySym)
 /**
  * Load keyboard remap file
  */
-void Keymap_LoadRemapFile(char *pszFileName)
+void Keymap_LoadRemapFile(const char *pszFileName)
 {
-	char szString[1024];
-	int STScanCode, PCKeyCode;
+	char mapLine[1024];
+	int hostSpecIsOk, guestSpecIsOk;
 	FILE *in;
 	int idx =3D 0;
+	int lineNumber =3D 0; /* For logging purposes            */
+	char *token;
+	char *saveptr;		/* For saving strtok_r's state, because host/guest anal=
yses may also use strtok */
+	char hostSpec[50]; 	/* Host (PC) keys specification    */
+	char guestSpec[50];	/* Guest's (ST) keys specification */
+	const char invalidSpecificationMessage[] =3D "Keymap_LoadRemapFile: '%s=
' not a valid specification at line %d\n";
+
+	Log_Printf(LOG_DEBUG, "Keymap_LoadRemapFile: Loading '%s'\n", pszFileNa=
me);
=20
 	/* Initialize table with default values */
-	memset(LoadedKeymap, 0, sizeof(LoadedKeymap));
+	memset(LoadedKeyMap, 0, sizeof(LoadedKeyMap));
=20
-	if (!*pszFileName)
+	if (strlen(pszFileName) =3D=3D 0)
 		return;
=20
-	/* Attempt to load file */
+	/* Attempt to load mapping file */
 	if (!File_Exists(pszFileName))
 	{
 		Log_Printf(LOG_DEBUG, "Keymap_LoadRemapFile: '%s' not a file\n", pszFi=
leName);
@@ -635,66 +522,153 @@ void Keymap_LoadRemapFile(char *pszFileName)
 	in =3D fopen(pszFileName, "r");
 	if (!in)
 	{
-		Log_Printf(LOG_ERROR, "Keymap_LoadRemapFile: failed to "
-			   " open keymap file '%s'\n", pszFileName);
+		Log_Printf(LOG_ERROR, "Keymap_LoadRemapFile: failed to open keymap fil=
e '%s'\n", pszFileName);
 		return;
 	}
=20
 	while (!feof(in) && idx < KBD_MAX_SCANCODE)
 	{
 		/* Read line from file */
-		if (fgets(szString, sizeof(szString), in) =3D=3D NULL)
+		if (fgets(mapLine, sizeof(mapLine), in) =3D=3D NULL)
 			break;
+
+		++lineNumber;
+
 		/* Remove white-space from start of line */
-		Str_Trim(szString);
-		if (strlen(szString)>0)
+		Str_Trim(mapLine);
+
+		/* Ignore empty line and comments */
+		if (strlen(mapLine) =3D=3D 0 || mapLine[0] =3D=3D ';' || mapLine[0] =3D=
=3D '#')
+			continue;
+
+		/* Cut out the values between host and guest parts */
+		token =3D strtok_r(mapLine, ",", &saveptr);
+		if (token =3D=3D NULL)
+			goto invalidSpecificationError;
+
+		/* Get the host's key specification */
+		strcpy(hostSpec,token);
+		Str_Trim(hostSpec);
+		if (strlen(hostSpec) =3D=3D 0)
+			goto invalidSpecificationError;
+		hostSpecIsOk =3D HostSpecToSDLKeysym(hostSpec, &LoadedKeyMap[idx]);
+
+		/* Get the guest (ST) specification */
+		token =3D strtok_r(NULL, "\n", &saveptr);
+
+		if (token =3D=3D NULL)
+			continue;
+		strcpy(guestSpec,token);
+		Str_Trim(guestSpec);
+		if (strlen(guestSpec) =3D=3D 0)
+			goto invalidSpecificationError;
+		guestSpecIsOk =3D GuestSpecToSTScanCodes(guestSpec, &LoadedKeyMap[idx]=
);
+
+		/* Store into remap table, check both value within range */
+		if (guestSpecIsOk && hostSpecIsOk)
 		{
-			char *p;
-			/* Is a comment? */
-			if (szString[0] =3D=3D ';' || szString[0] =3D=3D '#')
-				continue;
-			/* Cut out the values */
-			p =3D strtok(szString, ",");
-			if (!p)
-				continue;
-			Str_Trim(szString);
-			PCKeyCode =3D atoi(szString);    /* Direct key code? */
-			if (PCKeyCode < 10)
-			{
-				/* If it's not a valid number >=3D 10, then
-				 * assume we've got a symbolic key name
-				 */
-				int offset =3D 0;
-				/* quoted character (e.g. comment line char)? */
-				if (*szString =3D=3D '\\' && strlen(szString) =3D=3D 2)
-					offset =3D 1;
-				PCKeyCode =3D Keymap_GetKeyFromName(szString+offset);
-			}
-			p =3D strtok(NULL, "\n");
-			if (!p)
-				continue;
-			STScanCode =3D atoi(p);
-			/* Store into remap table, check both value within range */
-			if (STScanCode > 0 && STScanCode <=3D KBD_MAX_SCANCODE
-			    && PCKeyCode >=3D 8)
-			{
-				LOG_TRACE(TRACE_KEYMAP,
-				          "keymap from file: sym=3D%i --> scan=3D%i\n",
-				          PCKeyCode, STScanCode);
-				LoadedKeymap[idx][0] =3D PCKeyCode;
-				LoadedKeymap[idx][1] =3D STScanCode;
-				idx +=3D 1;
-			}
+			LOG_TRACE(TRACE_KEYMAP,"keymap from file: host %s --> guest %s\n", ho=
stSpec, guestSpec);
+			idx +=3D 1;
+		}
+		else
+		{
+			Log_Printf(LOG_WARN, "Could not parse keymap specification: %s\n", ma=
pLine);
+		}
+
+		continue;
+
+invalidSpecificationError:
+			Log_Printf(LOG_ERROR, invalidSpecificationMessage, pszFileName, lineN=
umber);
+	}
+
+	fclose(in);
+}
+
+
+static int HostSpecToSDLKeysym(const char *spec, struct KeyMapping* resu=
lt)
+{
+	/* Analyses the host (PC) specification from the table file and populat=
e the keymapping */
+	char buf[100];
+	char *token;
+	SDL_Scancode scancode;
+
+	/* Prepare buffer */
+	strcpy(buf, spec);
+
+	/* Prepare for early returns */
+	result->SdlKeysym.mod =3D 0;
+	result->modmask =3D 0;
+
+	/* Scancode part */
+	token =3D strtok(buf,"|");
+	if (token !=3D NULL && (scancode =3D strtol(token, NULL, 16)))
+		result->SdlKeysym.scancode =3D scancode;
+	else
+		return 0;
+
+	/* Modifier part */
+	token =3D strtok(NULL,"|");
+	if (token !=3D NULL)
+	{
+		/* We have a modifier specified */
+		result->SdlKeysym.mod =3D SDLKeymodFromName(token);
+
+		/* "modifier mask" part */
+		token =3D strtok(NULL,"|");
+		if (token !=3D NULL)
+			result->modmask =3D SDLKeymodFromName(token);
+	}
+
+	return -1; /* Success */
+}
+
+
+static int GuestSpecToSTScanCodes(const char *spec, struct KeyMapping* m=
apping)
+{
+	/* Analyses the guest (Atari ST keyboard) specification from the table =
file */
+	char buf[100];
+	char *start;
+	char *separator;
+	uint8_t *scancodes =3D mapping->STScanCodes; /* Alias for readability *=
/
+	uint8_t scancode;
+	int i =3D 0;
+
+	strcpy(buf, spec);
+	separator =3D buf-1;
+	do
+	{
+		start =3D separator+1;
+		separator =3D strchr(start, '|');
+		if (separator !=3D NULL)
+			*separator =3D '\0';
+
+		if (strlen(start) <=3D 2)
+		{
+			scancode =3D strtol(start, NULL, 16);
+		}
+		else
+		{
+			/* Scancode may be expressed as LSHIFT,RSHIFT,ALTERNATE for user conv=
enience */
+			if (strcmp(start, "LSHIFT") =3D=3D 0)
+				scancode =3D ST_LSHIFT;
+			else if (strcmp(start, "RSHIFT") =3D=3D 0)
+				scancode =3D ST_RSHIFT;
+			else if (strcmp(start, "ALTERNATE") =3D=3D 0)
+				scancode =3D ST_ALTERNATE;
 			else
 			{
-				Log_Printf(LOG_WARN, "Could not parse keymap file:"
-				           " '%s' (%d >=3D 8), '%s' (0 > %d <=3D %d)\n",
-					   szString, PCKeyCode, p, STScanCode, KBD_MAX_SCANCODE);
+				Log_Printf(LOG_ERROR, "GuestSpecToSTScanCodes: Cannot understand sca=
ncode '%s'\n", start);
+				i =3D 0; /* Error out */
+				break;
 			}
 		}
-	}
=20
-	fclose(in);
+		scancodes[i++] =3D scancode;
+	} while (separator !=3D NULL);
+
+	mapping->STScanCodesLength =3D i;
+
+	return i > 0;
 }
=20
=20
@@ -764,17 +738,53 @@ void Keymap_DebounceAllKeys(void)
 }
=20
=20
+static bool IsKeyTranslatable(SDL_Keycode symkey)
+{
+	/* Ignore modifier keys that are not passed to the ST */
+	switch (symkey)
+	{
+		case SDLK_RALT:
+	 	case SDLK_LMETA:
+	 	case SDLK_RMETA:
+	 	case SDLK_MODE:
+	 	case SDLK_NUMLOCK:
+			return false;
+	}
+	return true;
+}
+
+
+/*----------------------------------------------------------------------=
-*/
+/* Returns true if the scancode is for a key that allows to a different =
character
+ * from the same key.
+ */
+static bool IsSTModifier(uint8_t scancode)
+{
+	switch (scancode)
+	{
+		case ST_LSHIFT:
+		case ST_RSHIFT:
+		case ST_ALTERNATE:
+			return true;
+	}
+	return false;
+}
+
+
 /*----------------------------------------------------------------------=
-*/
 /**
- * User press key down
+ * User pressed a key down
  */
 void Keymap_KeyDown(SDL_keysym *sdlkey)
 {
-	uint8_t STScanCode;
+	struct KeyMapping* mapping;
+	uint8_t* modifiers;
+	int i;
+	/* Convenience */
 	int symkey =3D sdlkey->sym;
 	int modkey =3D sdlkey->mod;
=20
-	LOG_TRACE(TRACE_KEYMAP, "key down: sym=3D%i scan=3D%i mod=3D0x%x name=3D=
'%s'\n",
+	LOG_TRACE(TRACE_KEYMAP, "Keymap_KeyDown: sym=3D%i scancode=3D0x%02x mod=
=3D0x%02x name=3D'%s'\n",
 	          symkey, sdlkey->scancode, modkey, Keymap_GetKeyName(symkey));
=20
 	if (ShortCut_CheckKeys(modkey, symkey, true))
@@ -785,39 +795,62 @@ void Keymap_KeyDown(SDL_keysym *sdlkey)
 	if (Joy_KeyDown(symkey, modkey))
 		return;
=20
-	/* Handle special keys */
-	if (symkey =3D=3D SDLK_RALT || symkey =3D=3D SDLK_LMETA || symkey =3D=3D=
 SDLK_RMETA
-	        || symkey =3D=3D SDLK_MODE || symkey =3D=3D SDLK_NUMLOCK)
-	{
-		/* Ignore modifier keys that aren't passed to the ST */
+	if (!IsKeyTranslatable(symkey))
 		return;
-	}
=20
-	STScanCode =3D Keymap_RemapKeyToSTScanCode(sdlkey);
-	LOG_TRACE(TRACE_KEYMAP, "key map: sym=3D0x%x to ST-scan=3D0x%02x\n", sy=
mkey, STScanCode);
-	if (STScanCode !=3D (uint8_t)-1)
+	mapping =3D Keymap_RemapKeyToSTScanCodes(sdlkey, true);
+	if (mapping =3D=3D NULL)
+		return;
+
+	int modcount =3D 0;
+
+	modifiers =3D mapping->PressedModifiers;
+	for (i =3D 0; i < mapping->STScanCodesLength ; i++)
 	{
-		if (!Keyboard.KeyStates[STScanCode])
+		uint8_t scancode =3D mapping->STScanCodes[i];
+
+		Keyboard.KeyStates[scancode]++;
+
+		/* If it's a modifier that we're pressing, remember to release it late=
r.
+		 * In case you're wondering why we don't release the modifiers immedia=
tely after
+		 * pressing the key: the reason is that if the user keeps the key down=
 to make it
+		 * repeat, the modifiers need to be there, otherwise it is the "unshif=
ter/unalted"
+		 * character that will repeat instead.
+		 * TODO: Unfortunately this causes a bug as the modifiers will accumul=
ate if you
+		 * press multiple modified keys at once. For example, if on a French k=
eyboard you
+		 * press ALT-5 (to get a [), the ALTERNATE modifier will be retained. =
Holding that
+		 * ALT down and pressing the key 6 at the same time (to get |), the | =
only requires
+		 * SHIFT to be pressed. But ALTERNATE also being emulated, you will ge=
t ~.
+		 * To maybe fix that we would have to manage a stack of modifiers, so =
we could
+		 * release ALT while 7 is pressed (as it only requires SHIFT) then pre=
ss it again
+		 * when 7 is released. Is it really worth the effort... */
+		if (IsSTModifier(scancode))
 		{
-			/* Set down */
-			Keyboard.KeyStates[STScanCode] =3D true;
-			IKBD_PressSTKey(STScanCode, true);
+			*modifiers++ =3D scancode;
+			modcount++;
 		}
+
+		/* If that key was not already pressed, press it */
+		if (Keyboard.KeyStates[scancode] =3D=3D 1)
+			IKBD_PressSTKey(scancode, true);
 	}
+	*modifiers =3D 0; /* End the list of modifiers */
 }
=20
=20
 /*----------------------------------------------------------------------=
-*/
 /**
- * User released key
+ * User released a key
  */
 void Keymap_KeyUp(SDL_keysym *sdlkey)
 {
-	uint8_t STScanCode;
+	struct KeyMapping *mapping;
+	uint8_t *modifier;
+	int i;
 	int symkey =3D sdlkey->sym;
 	int modkey =3D sdlkey->mod;
=20
-	LOG_TRACE(TRACE_KEYMAP, "key up: sym=3D%i scan=3D%i mod=3D0x%x name=3D'=
%s'\n",
+	LOG_TRACE(TRACE_KEYMAP, "Keymap_KeyUp: sym=3D%i scancode=3D0x%02x mod=3D=
0x%02x name=3D'%s'\n",
 	          symkey, sdlkey->scancode, modkey, Keymap_GetKeyName(symkey));
=20
 	/* Ignore short-cut keys here */
@@ -830,25 +863,58 @@ void Keymap_KeyUp(SDL_keysym *sdlkey)
 		return;
=20
 	/* Handle special keys */
-	if (symkey =3D=3D SDLK_RALT || symkey =3D=3D SDLK_LMETA || symkey =3D=3D=
 SDLK_RMETA
-	        || symkey =3D=3D SDLK_MODE || symkey =3D=3D SDLK_NUMLOCK)
+	if (!IsKeyTranslatable(symkey))
 	{
-		/* Ignore modifier keys that aren't passed to the ST */
+		LOG_TRACE(TRACE_KEYMAP, "   Key not translatable to ST keyboard.\n");
+		return;
+	}
+
+	mapping =3D &KeysDownMapping[sdlkey->scancode];
+
+	if (mapping =3D=3D NULL)
+	{
+		Log_Printf(LOG_ERROR, "  No key mapping found !\n");
 		return;
 	}
=20
-	STScanCode =3D Keymap_RemapKeyToSTScanCode(sdlkey);
 	/* Release key (only if was pressed) */
-	if (STScanCode !=3D (uint8_t)-1)
+	for (i =3D 0; i < mapping->STScanCodesLength ; i++)
 	{
-		if (Keyboard.KeyStates[STScanCode])
+		uint8_t scancode =3D mapping->STScanCodes[i];
+
+		if (IsSTModifier(scancode) && mapping->STScanCodesLength > 1)
+			continue; /* We release emulated modifiers last */
+
+		/* Set up */
+		if (Keyboard.KeyStates[scancode])
 		{
-			IKBD_PressSTKey(STScanCode, false);
-			Keyboard.KeyStates[STScanCode] =3D false;
+			LOG_TRACE(TRACE_KEYMAP,"  %02x was down, will be up'ed\n",scancode);
+
+			Keyboard.KeyStates[scancode]--;
+			IKBD_PressSTKey(scancode, false);
 		}
+		else
+			LOG_TRACE(TRACE_KEYMAP,"  %02x will be kept down (presses: %d)\n",sca=
ncode,Keyboard.KeyStates[scancode]);
+
 	}
+
+	/* Release modifiers that were pressed to emulate the key*/
+	modifier =3D mapping->PressedModifiers;
+	while (*modifier)
+	{
+		if (Keyboard.KeyStates[*modifier] !=3D 0)
+		{
+			if (--Keyboard.KeyStates[*modifier] =3D=3D 0)
+				IKBD_PressSTKey(*modifier, false);
+		}
+		modifier++;
+	}
+
+	/* Trace state of modifiers */
+	LOG_TRACE(TRACE_KEYMAP,"  LS:%d LR:%d CTRL:%d ALT:%d\n",Keyboard.KeySta=
tes[ST_LSHIFT],Keyboard.KeyStates[ST_RSHIFT],Keyboard.KeyStates[ST_CTRL],=
Keyboard.KeyStates[ST_ALTERNATE]);
 }
=20
+
 /*----------------------------------------------------------------------=
-*/
 /**
  * Simulate press or release of a key corresponding to given character
@@ -856,24 +922,33 @@ void Keymap_KeyUp(SDL_keysym *sdlkey)
 void Keymap_SimulateCharacter(char asckey, bool press)
 {
 	SDL_keysym sdlkey;
-
 	sdlkey.mod =3D KMOD_NONE;
 	sdlkey.scancode =3D 0;
-	if (isupper((unsigned char)asckey)) {
-		if (press) {
+
+	if (isupper((unsigned char)asckey))
+	{
+		if (press)
+		{
 			sdlkey.sym =3D SDLK_LSHIFT;
 			Keymap_KeyDown(&sdlkey);
 		}
 		sdlkey.sym =3D tolower((unsigned char)asckey);
 		sdlkey.mod =3D KMOD_LSHIFT;
-	} else {
+	}
+	else
+	{
 		sdlkey.sym =3D asckey;
 	}
-	if (press) {
+
+	if (press)
+	{
 		Keymap_KeyDown(&sdlkey);
-	} else {
+	}
+	else
+	{
 		Keymap_KeyUp(&sdlkey);
-		if (isupper((unsigned char)asckey)) {
+		if (isupper((unsigned char)asckey))
+		{
 			sdlkey.sym =3D SDLK_LSHIFT;
 			Keymap_KeyUp(&sdlkey);
 		}
@@ -881,287 +956,49 @@ void Keymap_SimulateCharacter(char asckey, bool pr=
ess)
 }
=20
=20
-#if WITH_SDL2
-
-int Keymap_GetKeyFromName(const char *name)
+SDL_Keycode Keymap_GetKeyFromName(const char *name)
 {
 	return SDL_GetKeyFromName(name);
 }
=20
-const char *Keymap_GetKeyName(int keycode)
-{
-	if (!keycode)
-		return "";
-
-	return SDL_GetKeyName(keycode);
-}
=20
-#else	/* !WITH_SDL2 */
-
-static struct {
-	int code;
-	const char *name;
-} const sdl_keytab[] =3D {
-	{ SDLK_BACKSPACE, "Backspace" },
-	{ SDLK_TAB, "Tab" },
-	{ SDLK_CLEAR, "Clear" },
-	{ SDLK_RETURN, "Return" },
-	{ SDLK_PAUSE, "Pause" },
-	{ SDLK_ESCAPE, "Escape" },
-	{ SDLK_SPACE, "Space" },
-	{ SDLK_EXCLAIM, "!" },
-	{ SDLK_QUOTEDBL, "\"" },
-	{ SDLK_HASH, "#" },
-	{ SDLK_DOLLAR, "$" },
-	{ SDLK_AMPERSAND, "&" },
-	{ SDLK_QUOTE, "'" },
-	{ SDLK_LEFTPAREN, "(" },
-	{ SDLK_RIGHTPAREN, ")" },
-	{ SDLK_ASTERISK, "*" },
-	{ SDLK_PLUS, "+" },
-	{ SDLK_COMMA, "," },
-	{ SDLK_MINUS, "-" },
-	{ SDLK_PERIOD, "." },
-	{ SDLK_SLASH, "/" },
-	{ SDLK_0, "0" },
-	{ SDLK_1, "1" },
-	{ SDLK_2, "2" },
-	{ SDLK_3, "3" },
-	{ SDLK_4, "4" },
-	{ SDLK_5, "5" },
-	{ SDLK_6, "6" },
-	{ SDLK_7, "7" },
-	{ SDLK_8, "8" },
-	{ SDLK_9, "9" },
-	{ SDLK_COLON, ":" },
-	{ SDLK_SEMICOLON, ";" },
-	{ SDLK_LESS, "<" },
-	{ SDLK_EQUALS, "=3D" },
-	{ SDLK_GREATER, ">" },
-	{ SDLK_QUESTION, "?" },
-	{ SDLK_AT, "@" },
-	{ SDLK_LEFTBRACKET, "[" },
-	{ SDLK_BACKSLASH, "\\" },
-	{ SDLK_RIGHTBRACKET, "]" },
-	{ SDLK_CARET, "^" },
-	{ SDLK_UNDERSCORE, "_" },
-	{ SDLK_BACKQUOTE, "`" },
-	{ SDLK_a, "A" },
-	{ SDLK_b, "B" },
-	{ SDLK_c, "C" },
-	{ SDLK_d, "D" },
-	{ SDLK_e, "E" },
-	{ SDLK_f, "F" },
-	{ SDLK_g, "G" },
-	{ SDLK_h, "H" },
-	{ SDLK_i, "I" },
-	{ SDLK_j, "J" },
-	{ SDLK_k, "K" },
-	{ SDLK_l, "L" },
-	{ SDLK_m, "M" },
-	{ SDLK_n, "N" },
-	{ SDLK_o, "O" },
-	{ SDLK_p, "P" },
-	{ SDLK_q, "Q" },
-	{ SDLK_r, "R" },
-	{ SDLK_s, "S" },
-	{ SDLK_t, "T" },
-	{ SDLK_u, "U" },
-	{ SDLK_v, "V" },
-	{ SDLK_w, "W" },
-	{ SDLK_x, "X" },
-	{ SDLK_y, "Y" },
-	{ SDLK_z, "Z" },
-	{ SDLK_DELETE, "Delete" },
-	{ SDLK_KP0, "Keypad 0" },
-	{ SDLK_KP1, "Keypad 1" },
-	{ SDLK_KP2, "Keypad 2" },
-	{ SDLK_KP3, "Keypad 3" },
-	{ SDLK_KP4, "Keypad 4" },
-	{ SDLK_KP5, "Keypad 5" },
-	{ SDLK_KP6, "Keypad 6" },
-	{ SDLK_KP7, "Keypad 7" },
-	{ SDLK_KP8, "Keypad 8" },
-	{ SDLK_KP9, "Keypad 9" },
-	{ SDLK_KP_PERIOD, "Keypad ." },
-	{ SDLK_KP_DIVIDE, "Keypad /" },
-	{ SDLK_KP_MULTIPLY, "Keypad *" },
-	{ SDLK_KP_MINUS, "Keypad -" },
-	{ SDLK_KP_PLUS, "Keypad +" },
-	{ SDLK_KP_ENTER, "Keypad Enter" },
-	{ SDLK_KP_EQUALS, "Keypad =3D" },
-	{ SDLK_UP, "Up" },
-	{ SDLK_DOWN, "Down" },
-	{ SDLK_RIGHT, "Right" },
-	{ SDLK_LEFT, "Left" },
-	{ SDLK_INSERT, "Insert" },
-	{ SDLK_HOME, "Home" },
-	{ SDLK_END, "End" },
-	{ SDLK_PAGEUP, "PageUp" },
-	{ SDLK_PAGEDOWN, "PageDown" },
-	{ SDLK_F1, "F1" },
-	{ SDLK_F2, "F2" },
-	{ SDLK_F3, "F3" },
-	{ SDLK_F4, "F4" },
-	{ SDLK_F5, "F5" },
-	{ SDLK_F6, "F6" },
-	{ SDLK_F7, "F7" },
-	{ SDLK_F8, "F8" },
-	{ SDLK_F9, "F9" },
-	{ SDLK_F10, "F10" },
-	{ SDLK_F11, "F11" },
-	{ SDLK_F12, "F12" },
-	{ SDLK_F13, "F13" },
-	{ SDLK_F14, "F14" },
-	{ SDLK_F15, "F15" },
-	{ SDLK_NUMLOCK, "Numlock" },
-	{ SDLK_CAPSLOCK, "CapsLock" },
-	{ SDLK_SCROLLOCK, "ScrollLock" },
-	{ SDLK_RSHIFT, "Right Shift" },
-	{ SDLK_LSHIFT, "Left Shift" },
-	{ SDLK_RCTRL, "Right Ctrl" },
-	{ SDLK_LCTRL, "Left Ctrl" },
-	{ SDLK_RALT, "Right Alt" },
-	{ SDLK_LALT, "Left Alt" },
-	{ SDLK_RMETA, "Right GUI" },
-	{ SDLK_LMETA, "Left GUI" },
-	{ SDLK_MODE, "ModeSwitch" },
-	{ SDLK_HELP, "Help" },
-	{ SDLK_PRINT, "PrintScreen" },
-	{ SDLK_SYSREQ, "SysReq" },
-	{ SDLK_BREAK, "Cancel" },
-	{ SDLK_MENU, "Menu" },
-	{ SDLK_POWER, "Power" },
-	{ SDLK_UNDO, "Undo" },
-
-	{ SDLK_WORLD_1, "=C2=A1" },	/* 161 */
-	{ SDLK_WORLD_2, "=C2=A2" },	/* 162 */
-	{ SDLK_WORLD_3, "=C2=A3" },	/* 163 */
-	{ SDLK_WORLD_4, "=C2=A4" },	/* 164 */
-	{ SDLK_WORLD_5, "=C2=A5" },	/* 165 */
-	{ SDLK_WORLD_6, "=C2=A6" },	/* 166 */
-	{ SDLK_WORLD_7, "=C2=A7" },	/* 167 */
-	{ SDLK_WORLD_8, "=C2=A8" },	/* 168 */
-	{ SDLK_WORLD_9, "=C2=A9" },	/* 169 */
-	{ SDLK_WORLD_10, "=C2=AA" },	/* 170 */
-	{ SDLK_WORLD_11, "=C2=AB" },	/* 171 */
-	{ SDLK_WORLD_12, "=C2=AC" },	/* 172 */
-	{ SDLK_WORLD_14, "=C2=AE" },	/* 174 */
-	{ SDLK_WORLD_15, "=C2=AF" },	/* 175 */
-	{ SDLK_WORLD_16, "=C2=B0" },	/* 176 */
-	{ SDLK_WORLD_17, "=C2=B1" },	/* 177 */
-	{ SDLK_WORLD_18, "=C2=B2" },	/* 178 */
-	{ SDLK_WORLD_19, "=C2=B3" },	/* 179 */
-	{ SDLK_WORLD_20, "=C2=B4" },	/* 180 */
-	{ SDLK_WORLD_21, "=C2=B5" },	/* 181 */
-	{ SDLK_WORLD_22, "=C2=B6" },	/* 182 */
-	{ SDLK_WORLD_23, "=C2=B7" },	/* 183 */
-	{ SDLK_WORLD_24, "=C2=B8" },	/* 184 */
-	{ SDLK_WORLD_25, "=C2=B9" },	/* 185 */
-	{ SDLK_WORLD_26, "=C2=BA" },	/* 186 */
-	{ SDLK_WORLD_27, "=C2=BB" },	/* 187 */
-	{ SDLK_WORLD_28, "=C2=BC" },	/* 188 */
-	{ SDLK_WORLD_29, "=C2=BD" },	/* 189 */
-	{ SDLK_WORLD_30, "=C2=BE" },	/* 190 */
-	{ SDLK_WORLD_31, "=C2=BF" },	/* 191 */
-	{ SDLK_WORLD_32, "=C3=80" },	/* 192 */
-	{ SDLK_WORLD_33, "=C3=81" },	/* 193 */
-	{ SDLK_WORLD_34, "=C3=82" },	/* 194 */
-	{ SDLK_WORLD_35, "=C3=83" },	/* 195 */
-	{ SDLK_WORLD_36, "=C3=84" },	/* 196 */
-	{ SDLK_WORLD_37, "=C3=85" },	/* 197 */
-	{ SDLK_WORLD_38, "=C3=86" },	/* 198 */
-	{ SDLK_WORLD_39, "=C3=87" },	/* 199 */
-	{ SDLK_WORLD_40, "=C3=88" },	/* 200 */
-	{ SDLK_WORLD_41, "=C3=89" },	/* 201 */
-	{ SDLK_WORLD_42, "=C3=8A" },	/* 202 */
-	{ SDLK_WORLD_43, "=C3=8B" },	/* 203 */
-	{ SDLK_WORLD_44, "=C3=8C" },	/* 204 */
-	{ SDLK_WORLD_45, "=C3=8D" },	/* 205 */
-	{ SDLK_WORLD_46, "=C3=8E" },	/* 206 */
-	{ SDLK_WORLD_47, "=C3=8F" },	/* 207 */
-	{ SDLK_WORLD_48, "=C3=90" },	/* 208 */
-	{ SDLK_WORLD_49, "=C3=91" },	/* 209 */
-	{ SDLK_WORLD_50, "=C3=92" },	/* 210 */
-	{ SDLK_WORLD_51, "=C3=93" },	/* 211 */
-	{ SDLK_WORLD_52, "=C3=94" },	/* 212 */
-	{ SDLK_WORLD_53, "=C3=95" },	/* 213 */
-	{ SDLK_WORLD_54, "=C3=96" },	/* 214 */
-	{ SDLK_WORLD_55, "=C3=97" },	/* 215 */
-	{ SDLK_WORLD_56, "=C3=98" },	/* 216 */
-	{ SDLK_WORLD_57, "=C3=99" },	/* 217 */
-	{ SDLK_WORLD_58, "=C3=9A" },	/* 218 */
-	{ SDLK_WORLD_59, "=C3=9B" },	/* 219 */
-	{ SDLK_WORLD_60, "=C3=9C" },	/* 220 */
-	{ SDLK_WORLD_61, "=C3=9D" },	/* 221 */
-	{ SDLK_WORLD_62, "=C3=9E" },	/* 222 */
-	{ SDLK_WORLD_63, "=C3=9F" },	/* 223 */
-	{ SDLK_WORLD_64, "=C3=A0" },	/* 224 */
-	{ SDLK_WORLD_65, "=C3=A1" },	/* 225 */
-	{ SDLK_WORLD_66, "=C3=A2" },	/* 226 */
-	{ SDLK_WORLD_67, "=C3=A3" },	/* 227 */
-	{ SDLK_WORLD_68, "=C3=A4" },	/* 228 */
-	{ SDLK_WORLD_69, "=C3=A5" },	/* 229 */
-	{ SDLK_WORLD_70, "=C3=A6" },	/* 230 */
-	{ SDLK_WORLD_71, "=C3=A7" },	/* 231 */
-	{ SDLK_WORLD_72, "=C3=A8" },	/* 232 */
-	{ SDLK_WORLD_73, "=C3=A9" },	/* 233 */
-	{ SDLK_WORLD_74, "=C3=AA" },	/* 234 */
-	{ SDLK_WORLD_75, "=C3=AB" },	/* 235 */
-	{ SDLK_WORLD_76, "=C3=AC" },	/* 236 */
-	{ SDLK_WORLD_77, "=C3=AD" },	/* 237 */
-	{ SDLK_WORLD_78, "=C3=AE" },	/* 238 */
-	{ SDLK_WORLD_79, "=C3=AF" },	/* 239 */
-	{ SDLK_WORLD_80, "=C3=B0" },	/* 240 */
-	{ SDLK_WORLD_81, "=C3=B1" },	/* 241 */
-	{ SDLK_WORLD_82, "=C3=B2" },	/* 242 */
-	{ SDLK_WORLD_83, "=C3=B3" },	/* 243 */
-	{ SDLK_WORLD_84, "=C3=B4" },	/* 244 */
-	{ SDLK_WORLD_85, "=C3=B5" },	/* 245 */
-	{ SDLK_WORLD_86, "=C3=B6" },	/* 246 */
-	{ SDLK_WORLD_87, "=C3=B7" },	/* 247 */
-	{ SDLK_WORLD_88, "=C3=B8" },	/* 248 */
-	{ SDLK_WORLD_89, "=C3=B9" },	/* 249 */
-	{ SDLK_WORLD_90, "=C3=BA" },	/* 250 */
-	{ SDLK_WORLD_91, "=C3=BB" },	/* 251 */
-	{ SDLK_WORLD_92, "=C3=BC" },	/* 252 */
-	{ SDLK_WORLD_93, "=C3=BD" },	/* 253 */
-	{ SDLK_WORLD_94, "=C3=BE" },	/* 254 */
-	{ SDLK_WORLD_95, "=C3=BF" },	/* 255 */
-
-	{ -1, NULL }
-};
-
-int Keymap_GetKeyFromName(const char *name)
+const char *Keymap_GetKeyName(SDL_Keycode keycode)
 {
-	int i;
-
-	if (!name[0])
-		return 0;
-
-	for (i =3D 0; sdl_keytab[i].name !=3D NULL; i++)
-	{
-		if (strcasecmp(name, sdl_keytab[i].name) =3D=3D 0)
-			return sdl_keytab[i].code;
-	}
-
-	return 0;
+	return keycode ? SDL_GetKeyName(keycode) : "";
 }
=20
-const char *Keymap_GetKeyName(int keycode)
-{
-	int i;
=20
-	if (!keycode)
-		return "";
+static SDL_Keymod SDLKeymodFromName(const char *name) {
+	struct {
+		SDL_Keymod mod;
+		const char *name;
+	} const keymodNames[] =3D {
+		{ KMOD_NONE, "KMOD_NONE" },
+		{ KMOD_LSHIFT, "KMOD_LSHIFT" },
+		{ KMOD_RSHIFT, "KMOD_RSHIFT" },
+		{ KMOD_LCTRL, "KMOD_LCTRL" },
+		{ KMOD_RCTRL, "KMOD_RCTRL" },
+		{ KMOD_LALT, "KMOD_LALT" },
+		{ KMOD_RALT, "KMOD_RALT" },
+		{ KMOD_LGUI, "KMOD_LGUI" },
+		{ KMOD_RGUI, "KMOD_RGUI" },
+		{ KMOD_NUM, "KMOD_NUM" },
+		{ KMOD_CAPS, "KMOD_CAPS" },
+		{ KMOD_MODE, "KMOD_MODE" },
+		{ KMOD_CTRL, "KMOD_CTRL" },
+		{ KMOD_SHIFT, "KMOD_SHIFT" },
+		{ KMOD_ALT, "KMOD_ALT" },
+		{ KMOD_GUI, "KMOD_GUI" },
+		{ 0/*whatever*/, NULL }};
=20
-	for (i =3D 0; sdl_keytab[i].name !=3D NULL; i++)
+	int i;
+	for (i =3D 0; keymodNames[i].name !=3D NULL; i++)
 	{
-		if (keycode =3D=3D sdl_keytab[i].code)
-			return sdl_keytab[i].name;
-	}
+		if (strcmp(name, keymodNames[i].name) =3D=3D 0)
+			return keymodNames[i].mod;
+	};
=20
-	return "";
-}
+	LOG_TRACE(TRACE_KEYMAP, "SDLKeymodFromName: Didn't find SDL_Keymod \"%s=
\", defaulting to KMOD_NONE.\n", name);
=20
-#endif /* !WITH_SDL2 */
+	return KMOD_NONE;
+}
--=20
2.25.1




Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/