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;
}
}