shithub: choc

Download patch

ref: 0aece203e8fdb2848f7b19885c07f477bc03130a
parent: 410c695fa1b7994934545cccc7cc6afc28e9db3b
author: Simon Howard <fraggle@soulsphere.org>
date: Fri Jan 20 21:31:45 EST 2017

textscreen: Tweak TXT_GetKeyDescription() again.

We use the SDL APIs to get a localized name for keys now. However, we
must consider that SDL's key names are in UTF8 format and can therefore
contain non-ASCII characters which cannot be displayed on the CP437 text
screen. So double-check if key names contain any unprintable characters
and if they do, use a fallback set of default key names instead.

This fixes #840. Thanks to Julian Nechaevsky for the report.

--- a/src/doomkeys.h
+++ b/src/doomkeys.h
@@ -114,5 +114,40 @@
     0, 0, 0, KEYP_EQUALS,                                     /* 100-103 */ \
 }
 
+// Default names for keys, to use in English or as fallback.
+#define KEY_NAMES_ARRAY {                                            \
+    { KEY_BACKSPACE,  "BACKSP" },   { KEY_TAB,        "TAB" },       \
+    { KEY_INS,        "INS" },      { KEY_DEL,        "DEL" },       \
+    { KEY_PGUP,       "PGUP" },     { KEY_PGDN,       "PGDN" },      \
+    { KEY_ENTER,      "ENTER" },    { KEY_ESCAPE,     "ESC" },       \
+    { KEY_F1,         "F1" },       { KEY_F2,         "F2" },        \
+    { KEY_F3,         "F3" },       { KEY_F4,         "F4" },        \
+    { KEY_F5,         "F5" },       { KEY_F6,         "F6" },        \
+    { KEY_F7,         "F7" },       { KEY_F8,         "F8" },        \
+    { KEY_F9,         "F9" },       { KEY_F10,        "F10" },       \
+    { KEY_F11,        "F11" },      { KEY_F12,        "F12" },       \
+    { KEY_HOME,       "HOME" },     { KEY_END,        "END" },       \
+    { KEY_MINUS,      "-" },        { KEY_EQUALS,     "=" },         \
+    { KEY_NUMLOCK,    "NUMLCK" },   { KEY_SCRLCK,     "SCRLCK" },    \
+    { KEY_PAUSE,      "PAUSE" },    { KEY_PRTSCR,     "PRTSC" },     \
+    { KEY_UPARROW,    "UP" },       { KEY_DOWNARROW,  "DOWN" },      \
+    { KEY_LEFTARROW,  "LEFT" },     { KEY_RIGHTARROW, "RIGHT" },     \
+    { KEY_RALT,       "ALT" },      { KEY_LALT,       "ALT" },       \
+    { KEY_RSHIFT,     "SHIFT" },    { KEY_CAPSLOCK,   "CAPS" },      \
+    { KEY_RCTRL,      "CTRL" },     { ' ',            "SPACE" },     \
+    { 'a', "A" },   { 'b', "B" },   { 'c', "C" },   { 'd', "D" },    \
+    { 'e', "E" },   { 'f', "F" },   { 'g', "G" },   { 'h', "H" },    \
+    { 'i', "I" },   { 'j', "J" },   { 'k', "K" },   { 'l', "L" },    \
+    { 'm', "M" },   { 'n', "N" },   { 'o', "O" },   { 'p', "P" },    \
+    { 'q', "Q" },   { 'r', "R" },   { 's', "S" },   { 't', "T" },    \
+    { 'u', "U" },   { 'v', "V" },   { 'w', "W" },   { 'x', "X" },    \
+    { 'y', "Y" },   { 'z', "Z" },   { '0', "0" },   { '1', "1" },    \
+    { '2', "2" },   { '3', "3" },   { '4', "4" },   { '5', "5" },    \
+    { '6', "6" },   { '7', "7" },   { '8', "8" },   { '9', "9" },    \
+    { '[', "[" },   { ']', "]" },   { ';', ";" },   { '`', "`" },    \
+    { ',', "," },   { '.', "." },   { '/', "/" },   { '\\', "\\" },  \
+    { '\'', "\'" },                                                  \
+}
+
 #endif          // __DOOMKEYS__
 
--- a/textscreen/txt_main.h
+++ b/textscreen/txt_main.h
@@ -149,6 +149,8 @@
 // keyboard (like that returned by TXT_INPUT_RAW), and the resulting string
 // takes keyboard layout into consideration. For example,
 // TXT_GetKeyDescription('q') on a French keyboard returns "A".
+// The contents of the filled buffer will be in UTF8 format, but will never
+// contain characters which can't be shown on the screen.
 void TXT_GetKeyDescription(int key, char *buf, size_t buf_len);
 
 // Retrieve the current position of the mouse
--- a/textscreen/txt_sdl.c
+++ b/textscreen/txt_sdl.c
@@ -715,30 +715,72 @@
     }
 }
 
+// Unicode characters we allow in key names because they're in the
+// CP437 extended ASCII range.
+static const short unicode_whitelist[] = {
+    0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7,
+    0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5,
+    0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9,
+    0x00ff, 0x00d6, 0x00dc, 0x00f1, 0x00e1, 0x00ed, 0x00f3, 0x00fa,
+    0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4,
+    0x03a6, 0x0398, 0x03a9, 0x03b4, 0x03c6, 0x03b5, 0x2229, 0x00d1,
+};
+
+static int PrintableChar(int c)
+{
+    unsigned int i;
+
+    if (c < 0x80)
+    {
+        return 1;
+    }
+
+    for (i = 0; i < arrlen(unicode_whitelist); ++i)
+    {
+        if (unicode_whitelist[i] == c)
+        {
+            return 1;
+        }
+    }
+
+    return 0;
+}
+
+// Returns true if the given UTF8 key name is printable to the screen.
+static int PrintableName(const char *s)
+{
+    const char *p;
+    unsigned int c;
+
+    p = s;
+    while (*p != '\0')
+    {
+        c = TXT_DecodeUTF8(&p);
+        if (!PrintableChar(c))
+        {
+            return 0;
+        }
+    }
+
+    return 1;
+}
+
+static const struct {
+    int key;
+    const char *name;
+} key_names[] = KEY_NAMES_ARRAY;
+
 static const char *NameForKey(int key)
 {
+    const char *result;
     int i;
 
+    // Overrides purely for aesthetical reasons, so that default
+    // window accelerator keys match those of setup.exe.
     switch (key)
     {
-        // A few keys which are not in the scancodes table:
-        case KEY_RSHIFT:      return "SHIFT";
-        case KEY_RCTRL:       return "CTRL";
-        case KEY_RALT:        return "ALT";
-
-        // Keys where we want to use specific strings to look more
-        // like setup.exe:
-        case KEY_CAPSLOCK:    return "CAPS";
-        case KEY_BACKSPACE:   return "BKSP";
-        case KEY_ESCAPE:      return "ESC";
-        case KEY_ENTER:       return "ENTER";
-        case KEY_SCRLCK:      return "SCRLCK";
-        case KEY_PGUP:        return "PGUP";
-        case KEY_PGDN:        return "PGDN";
-        case KEY_INS:         return "INS";
-        case KEY_DEL:         return "DEL";
-        case KEY_PRTSCR:      return "PRTSC";
-
+        case KEY_ESCAPE: return "ESC";
+        case KEY_ENTER:  return "ENTER";
         default:
             break;
     }
@@ -750,7 +792,23 @@
     {
         if (scancode_translate_table[i] == key)
         {
-            return SDL_GetKeyName(SDL_GetKeyFromScancode(i));
+            result = SDL_GetKeyName(SDL_GetKeyFromScancode(i));
+            if (TXT_UTF8_Strlen(result) > 6 || !PrintableName(result))
+            {
+                break;
+            }
+            return result;
+        }
+    }
+
+    // Use US English fallback names, if the localized name is too long,
+    // not found in the scancode table, or contains unprintable chars
+    // (non-extended ASCII character set):
+    for (i = 0; i < arrlen(key_names); ++i)
+    {
+        if (key_names[i].key == key)
+        {
+            return key_names[i].name;
         }
     }