shithub: choc

Download patch

ref: c1ff9bfd5b0effd4377c0a9f669ca96093547d98
parent: 805c6718912fb2532341f36d8f0b4b5092a35d00
author: Simon Howard <fraggle@soulsphere.org>
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)