ref: c1ff9bfd5b0effd4377c0a9f669ca96093547d98
parent: 805c6718912fb2532341f36d8f0b4b5092a35d00
author: Simon Howard <[email protected]>
date: Sat Dec 17 16:14:13 EST 2016
textscreen: Add input mode switching. This replaces the old control over whether key mapping is enabled. We have three different modes used in different situations: "normal" (used when navigating windows, etc.); "raw" (used when configuring a key and we want something derived from the scancode) and "text" (used when typing something into an input box widget).
--- a/src/setup/txt_keyinput.c
+++ b/src/setup/txt_keyinput.c
@@ -33,7 +33,7 @@
if (key != KEY_ESCAPE)
{
- // Got the key press. Save to the variable and close the window.
+ // Got the key press. Save to the variable and close the window.
*key_input->variable = key;
@@ -44,10 +44,9 @@
TXT_CloseWindow(window);
- // Re-enable key mappings now that we have the key
+ // Return to normal input mode now that we have the key.
+ TXT_SetInputMode(TXT_INPUT_NORMAL);
- TXT_EnableKeyMapping(1);
-
return 1;
}
else
@@ -74,9 +73,8 @@
TXT_SetKeyListener(window, KeyPressCallback, key_input);
- // Disable key mappings while we prompt for the key press
-
- TXT_EnableKeyMapping(0);
+ // Switch to raw input mode while we're grabbing the key.
+ TXT_SetInputMode(TXT_INPUT_RAW);
// Grab input while reading the key. On Windows Mobile
// handheld devices, the hardware keypresses are only
--- a/textscreen/txt_inputbox.c
+++ b/textscreen/txt_inputbox.c
@@ -64,9 +64,21 @@
SetBufferFromValue(inputbox);
}
+ // Switch to text input mode so we get shifted input.
+ TXT_SetInputMode(TXT_INPUT_TEXT);
inputbox->editing = 1;
}
+static void StopEditing(txt_inputbox_t *inputbox)
+{
+ if (inputbox->editing)
+ {
+ // Switch back to normal input mode.
+ TXT_SetInputMode(TXT_INPUT_NORMAL);
+ inputbox->editing = 0;
+ }
+}
+
static void FinishEditing(txt_inputbox_t *inputbox)
{
if (!inputbox->editing)
@@ -88,7 +100,7 @@
TXT_EmitSignal(&inputbox->widget, "changed");
- inputbox->editing = 0;
+ StopEditing(inputbox);
}
static void TXT_InputBoxSizeCalc(TXT_UNCAST_ARG(inputbox))
@@ -164,6 +176,7 @@
{
TXT_CAST_ARG(txt_inputbox_t, inputbox);
+ StopEditing(inputbox);
free(inputbox->buffer);
}
@@ -227,7 +240,7 @@
if (key == KEY_ESCAPE)
{
- inputbox->editing = 0;
+ StopEditing(inputbox);
}
if (key == KEY_BACKSPACE)
--- a/textscreen/txt_main.h
+++ b/textscreen/txt_main.h
@@ -98,6 +98,25 @@
TXT_NUM_MODIFIERS
} txt_modifier_t;
+// Due to the way the SDL API works, we provide different ways of configuring
+// how we read input events, each of which is useful in different scenarios.
+typedef enum
+{
+ // "Localized" output that takes software keyboard layout into account,
+ // but key shifting has no effect.
+ TXT_INPUT_NORMAL,
+
+ // "Raw" input; the keys correspond to physical keyboard layout and
+ // software keyboard layout has no effect.
+ TXT_INPUT_RAW,
+
+ // Used for full text input. Events are fully shifted and localized.
+ // However, not all keyboard keys will generate input.
+ // Setting this mode may activate the on-screen keyboard, depending on
+ // device and OS.
+ TXT_INPUT_TEXT,
+} txt_input_mode_t;
+
// Initialize the screen
// Returns 1 if successful, 0 if failed.
int TXT_Init(void);
@@ -131,9 +150,8 @@
// Optional timeout in ms (timeout == 0 : sleep forever)
void TXT_Sleep(int timeout);
-// Controls whether keys are returned from TXT_GetChar based on keyboard
-// mapping, or raw key code.
-void TXT_EnableKeyMapping(int enable);
+// Change mode for text input.
+void TXT_SetInputMode(txt_input_mode_t mode);
// Set the window title of the window containing the text mode screen
void TXT_SetWindowTitle(char *title);
--- a/textscreen/txt_sdl.c
+++ b/textscreen/txt_sdl.c
@@ -53,8 +53,10 @@
static SDL_Surface *screenbuffer;
static unsigned char *screendata;
static SDL_Renderer *renderer;
-static int key_mapping = 1;
+// Current input mode.
+static txt_input_mode_t input_mode = TXT_INPUT_NORMAL;
+
// Dimensions of the screen image in screen coordinates (not pixels); this
// is the value that was passed to SDL_CreateWindow().
static int screen_image_w, screen_image_h;
@@ -514,10 +516,8 @@
// XXX: duplicate from doomtype.h
#define arrlen(array) (sizeof(array) / sizeof(*array))
-static int TranslateKey(SDL_Keysym *sym)
+static int TranslateScancode(SDL_Scancode scancode)
{
- int scancode = sym->scancode;
-
switch (scancode)
{
case SDL_SCANCODE_LCTRL:
@@ -535,7 +535,7 @@
return KEY_RALT;
default:
- if (scancode >= 0 && scancode < arrlen(scancode_translate_table))
+ if (scancode < arrlen(scancode_translate_table))
{
return scancode_translate_table[scancode];
}
@@ -546,6 +546,25 @@
}
}
+static int TranslateKeysym(SDL_Keysym *sym)
+{
+ int translated;
+
+ // We cheat here and make use of TranslateScancode. The range of keys
+ // associated with printable characters is pretty contiguous, so if it's
+ // inside that range we want the localized version of the key instead.
+ translated = TranslateScancode(sym->scancode);
+
+ if (translated >= 0x20 && translated < 0x7f)
+ {
+ return sym->sym;
+ }
+ else
+ {
+ return translated;
+ }
+}
+
// Convert an SDL button index to textscreen button index.
//
// Note special cases because 2 == mid in SDL, 3 == mid in textscreen/setup
@@ -669,12 +688,37 @@
case SDL_KEYDOWN:
UpdateModifierState(&ev.key.keysym, 1);
- return TranslateKey(&ev.key.keysym);
+ switch (input_mode)
+ {
+ case TXT_INPUT_RAW:
+ return TranslateScancode(ev.key.keysym.scancode);
+ case TXT_INPUT_NORMAL:
+ return TranslateKeysym(&ev.key.keysym);
+ case TXT_INPUT_TEXT:
+ // We ignore key inputs in this mode, except for a
+ // few special cases needed during text input:
+ if (ev.key.keysym.sym == SDLK_ESCAPE
+ || ev.key.keysym.sym == SDLK_BACKSPACE
+ || ev.key.keysym.sym == SDLK_RETURN)
+ {
+ return TranslateKeysym(&ev.key.keysym);
+ }
+ break;
+ }
+ break;
case SDL_KEYUP:
UpdateModifierState(&ev.key.keysym, 0);
break;
+ case SDL_TEXTINPUT:
+ if (input_mode == TXT_INPUT_TEXT)
+ {
+ // TODO: Support input of more than just the first char.
+ return ev.text.text[0];
+ }
+ break;
+
case SDL_QUIT:
// Quit = escape
return 27;
@@ -871,9 +915,18 @@
}
}
-void TXT_EnableKeyMapping(int enable)
+void TXT_SetInputMode(txt_input_mode_t mode)
{
- key_mapping = enable;
+ if (mode == TXT_INPUT_TEXT && !SDL_IsTextInputActive())
+ {
+ SDL_StartTextInput();
+ }
+ else if (SDL_IsTextInputActive() && mode != TXT_INPUT_TEXT)
+ {
+ SDL_StopTextInput();
+ }
+
+ input_mode = mode;
}
void TXT_SetWindowTitle(char *title)