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.
This commit is contained in:
Simon Howard 2017-01-21 02:31:45 +00:00
parent 410c695fa1
commit 0aece203e8
3 changed files with 114 additions and 19 deletions

View file

@ -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__

View file

@ -149,6 +149,8 @@ int TXT_GetModifierState(txt_modifier_t mod);
// 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

View file

@ -715,30 +715,72 @@ int TXT_GetModifierState(txt_modifier_t mod)
}
}
// 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 @@ static const char *NameForKey(int key)
{
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;
}
}