diff --git a/source/build/src/baselayer.cpp b/source/build/src/baselayer.cpp index 48238e864..1aba73d1e 100644 --- a/source/build/src/baselayer.cpp +++ b/source/build/src/baselayer.cpp @@ -26,12 +26,6 @@ int32_t g_borderless=2; // input char inputdevices = 0; - -void (*keypresscallback)(int32_t, int32_t); - -void keySetCallback(void (*callback)(int32_t, int32_t)) { keypresscallback = callback; } - - vec2_t g_mousePos; vec2_t g_mouseAbs; int32_t g_mouseBits; diff --git a/source/build/src/sdlayer.cpp b/source/build/src/sdlayer.cpp index 60d562df6..bd9dc2b5a 100644 --- a/source/build/src/sdlayer.cpp +++ b/source/build/src/sdlayer.cpp @@ -136,6 +136,7 @@ uint16_t joydead[9], joysatur[9]; #define MAX_ERRORTEXT 4096 + //========================================================================== // // I_Error @@ -1871,6 +1872,85 @@ int32_t handleevents_sdlcommon(SDL_Event *ev) return 0; } +// So this is how the engine handles text input? +// Argh. This is just gross. +int scancodetoasciihack(SDL_Event &ev) +{ + SDL_Keycode keyvalue = ev.key.keysym.sym; + // Modifiers that have to be held down to be effective + // (excludes KMOD_NUM, for example). + static const int MODIFIERS = + KMOD_LSHIFT|KMOD_RSHIFT|KMOD_LCTRL|KMOD_RCTRL| + KMOD_LALT|KMOD_RALT|KMOD_LGUI|KMOD_RGUI; + + // XXX: see osd.c, OSD_HandleChar(), there are more... + if ( + (sc == SDL_SCANCODE_RETURN || sc == SDL_SCANCODE_KP_ENTER || + sc == SDL_SCANCODE_ESCAPE || + sc == SDL_SCANCODE_BACKSPACE || + sc == SDL_SCANCODE_TAB || + (((ev.key.keysym.mod) & MODIFIERS) == KMOD_LCTRL && + (sc >= SDL_SCANCODE_A && sc <= SDL_SCANCODE_Z)))) + { + char keyvalue; + switch (sc) + { + case SDL_SCANCODE_RETURN: case SDL_SCANCODE_KP_ENTER: keyvalue = '\r'; break; + case SDL_SCANCODE_ESCAPE: keyvalue = 27; break; + case SDL_SCANCODE_BACKSPACE: keyvalue = '\b'; break; + case SDL_SCANCODE_TAB: keyvalue = '\t'; break; + default: keyvalue = sc - SDL_SCANCODE_A + 1; break; // Ctrl+A --> 1, etc. + } + } + else if ( + ev.key.keysym.sym != g_keyAsciiTable[OSD_OSDKey()] && !SDL_IsTextInputActive()) // What is this? Preventing key repeat or what? :? + { + /* + Necessary for Duke 3D's method of entering cheats to work without showing IMEs. + SDL_TEXTINPUT is preferable overall, but with bitmap fonts it has no advantage. + */ + // Note that this is not how text input is supposed to be handled! + + if ('a' <= keyvalue && keyvalue <= 'z') + { + if (!!(ev.key.keysym.mod & KMOD_SHIFT) ^ !!(ev.key.keysym.mod & KMOD_CAPS)) + keyvalue -= 'a'-'A'; + } + else if (ev.key.keysym.mod & KMOD_SHIFT) + { + keyvalue = g_keyAsciiTableShift[code]; + } + else if (ev.key.keysym.mod & KMOD_NUM) // && !(ev.key.keysym.mod & KMOD_SHIFT) + { + switch (keyvalue) + { + case SDLK_KP_1: keyvalue = '1'; break; + case SDLK_KP_2: keyvalue = '2'; break; + case SDLK_KP_3: keyvalue = '3'; break; + case SDLK_KP_4: keyvalue = '4'; break; + case SDLK_KP_5: keyvalue = '5'; break; + case SDLK_KP_6: keyvalue = '6'; break; + case SDLK_KP_7: keyvalue = '7'; break; + case SDLK_KP_8: keyvalue = '8'; break; + case SDLK_KP_9: keyvalue = '9'; break; + case SDLK_KP_0: keyvalue = '0'; break; + case SDLK_KP_PERIOD: keyvalue = '.'; break; + case SDLK_KP_COMMA: keyvalue = ','; break; + } + } + + switch (keyvalue) + { + case SDLK_KP_DIVIDE: keyvalue = '/'; break; + case SDLK_KP_MULTIPLY: keyvalue = '*'; break; + case SDLK_KP_MINUS: keyvalue = '-'; break; + case SDLK_KP_PLUS: keyvalue = '+'; break; + } + } + if (keyvalue >= 0x80) keyvalue = 0; // Sadly ASCII only... + return keyvalue; +} + int32_t handleevents_pollsdl(void); #if SDL_MAJOR_VERSION != 1 // SDL 2.0 specific event handling @@ -1901,158 +1981,33 @@ int32_t handleevents_pollsdl(void) case SDL_KEYUP: { auto const &sc = ev.key.keysym.scancode; + code = keytranslation[sc]; - // Modifiers that have to be held down to be effective - // (excludes KMOD_NUM, for example). - static const int MODIFIERS = - KMOD_LSHIFT|KMOD_RSHIFT|KMOD_LCTRL|KMOD_RCTRL| - KMOD_LALT|KMOD_RALT|KMOD_LGUI|KMOD_RGUI; + // The pause key generates a release event right after + // the pressing one. As a result, it gets unseen + // by the game most of the time. + if (code == 0x59 && ev.type == SDL_KEYUP) // pause + break; + - // XXX: see osd.c, OSD_HandleChar(), there are more... - if (ev.key.type == SDL_KEYDOWN && !inputState.keyBufferFull() && - (sc == SDL_SCANCODE_RETURN || sc == SDL_SCANCODE_KP_ENTER || - sc == SDL_SCANCODE_ESCAPE || - sc == SDL_SCANCODE_BACKSPACE || - sc == SDL_SCANCODE_TAB || - (((ev.key.keysym.mod) & MODIFIERS) == KMOD_LCTRL && - (sc >= SDL_SCANCODE_A && sc <= SDL_SCANCODE_Z)))) - { - char keyvalue; - switch (sc) - { - case SDL_SCANCODE_RETURN: case SDL_SCANCODE_KP_ENTER: keyvalue = '\r'; break; - case SDL_SCANCODE_ESCAPE: keyvalue = 27; break; - case SDL_SCANCODE_BACKSPACE: keyvalue = '\b'; break; - case SDL_SCANCODE_TAB: keyvalue = '\t'; break; - default: keyvalue = sc - SDL_SCANCODE_A + 1; break; // Ctrl+A --> 1, etc. - } - if (OSD_HandleChar(keyvalue)) - inputState.keyBufferInsert(keyvalue); - } - else if (ev.key.type == SDL_KEYDOWN && - ev.key.keysym.sym != g_keyAsciiTable[OSD_OSDKey()] && !inputState.keyBufferFull() && - !SDL_IsTextInputActive()) - { - /* - Necessary for Duke 3D's method of entering cheats to work without showing IMEs. - SDL_TEXTINPUT is preferable overall, but with bitmap fonts it has no advantage. - */ - SDL_Keycode keyvalue = ev.key.keysym.sym; + int keyvalue = ev.type == SDL_KEYDOWN? scancodetoasciihack(ev) : 0; + if (keyvalue > 0) + { + keyvalue = OSD_HandleChar(keyvalue); // returns the char if it doesn't process it. + if (keyvalue == 0) break; + } + j = OSD_HandleScanCode(code, (ev.type == SDL_KEYDOWN)); + // returns are: + // j == -1: Console was opened + // j == 0: Console is active and used the key + // j == 2: Console is inactive and did not use the key + + if (j == -1) inputState.ClearKeysDown(); // Flush the entire keyboard state for the game when the console opens. + if (j <= 0) break; // Do not pass on to the game - if ('a' <= keyvalue && keyvalue <= 'z') - { - if (!!(ev.key.keysym.mod & KMOD_SHIFT) ^ !!(ev.key.keysym.mod & KMOD_CAPS)) - keyvalue -= 'a'-'A'; - } - else if (ev.key.keysym.mod & KMOD_SHIFT) - { - switch (keyvalue) - { - case '\'': keyvalue = '"'; break; - - case ',': keyvalue = '<'; break; - case '-': keyvalue = '_'; break; - case '.': keyvalue = '>'; break; - case '/': keyvalue = '?'; break; - case '0': keyvalue = ')'; break; - case '1': keyvalue = '!'; break; - case '2': keyvalue = '@'; break; - case '3': keyvalue = '#'; break; - case '4': keyvalue = '$'; break; - case '5': keyvalue = '%'; break; - case '6': keyvalue = '^'; break; - case '7': keyvalue = '&'; break; - case '8': keyvalue = '*'; break; - case '9': keyvalue = '('; break; - - case ';': keyvalue = ':'; break; - - case '=': keyvalue = '+'; break; - - case '[': keyvalue = '{'; break; - case '\\': keyvalue = '|'; break; - case ']': keyvalue = '}'; break; - - case '`': keyvalue = '~'; break; - } - } - else if (ev.key.keysym.mod & KMOD_NUM) // && !(ev.key.keysym.mod & KMOD_SHIFT) - { - switch (keyvalue) - { - case SDLK_KP_1: keyvalue = '1'; break; - case SDLK_KP_2: keyvalue = '2'; break; - case SDLK_KP_3: keyvalue = '3'; break; - case SDLK_KP_4: keyvalue = '4'; break; - case SDLK_KP_5: keyvalue = '5'; break; - case SDLK_KP_6: keyvalue = '6'; break; - case SDLK_KP_7: keyvalue = '7'; break; - case SDLK_KP_8: keyvalue = '8'; break; - case SDLK_KP_9: keyvalue = '9'; break; - case SDLK_KP_0: keyvalue = '0'; break; - case SDLK_KP_PERIOD: keyvalue = '.'; break; - case SDLK_KP_COMMA: keyvalue = ','; break; - } - } - - switch (keyvalue) - { - case SDLK_KP_DIVIDE: keyvalue = '/'; break; - case SDLK_KP_MULTIPLY: keyvalue = '*'; break; - case SDLK_KP_MINUS: keyvalue = '-'; break; - case SDLK_KP_PLUS: keyvalue = '+'; break; - } - - if ((unsigned)keyvalue <= 0x7Fu) - { - if (OSD_HandleChar(keyvalue)) - inputState.keyBufferInsert(keyvalue); - } - } - - // initprintf("SDL2: got key %d, %d, %u\n", ev.key.keysym.scancode, code, ev.key.type); - - // hook in the osd - if ((j = OSD_HandleScanCode(code, (ev.key.type == SDL_KEYDOWN))) <= 0) - { - if (j == -1) // osdkey - { - for (j = 0; j < NUMKEYS; ++j) - { - if (inputState.GetKeyStatus(j)) - { - if (keypresscallback) - keypresscallback(j, 0); - } - inputState.keySetState(j, 0); - } - } - break; - } - - if (ev.key.type == SDL_KEYDOWN) - { - if (!inputState.GetKeyStatus(code)) - { - if (keypresscallback) - keypresscallback(code, 1); - } - inputState.keySetState(code, 1); - } - else - { -# if 1 - // The pause key generates a release event right after - // the pressing one. As a result, it gets unseen - // by the game most of the time. - if (code == 0x59) // pause - break; -# endif - inputState.keySetState(code, 0); - if (keypresscallback) - keypresscallback(code, 0); - } + event_t ev = { (uint8_t)ev.type == SDL_KEYUP? EV_KeyUp : EV_KeyDown, 0, (int16_t)code, (int16_t)keyvalue }; + D_PostEvent(&ev); break; } diff --git a/source/common/console/d_event.cpp b/source/common/console/d_event.cpp index be5413251..10ae8e19e 100644 --- a/source/common/console/d_event.cpp +++ b/source/common/console/d_event.cpp @@ -23,6 +23,7 @@ #include "c_bind.h" #include "d_event.h" #include "d_gui.h" +#include "inputstate.h" int eventhead; int eventtail; @@ -193,6 +194,15 @@ void D_PostEvent (const event_t *ev) } } #endif + + // Add the key to the global keyboard state. + // This is probably the biggest roadblock with the input system as it undermines a proper event driven approach. + // Too much code depends on just checking this instead of waiting for events to happen. + // Here's also definitely not the best place to maintain the keyboard state but right now it's unavoidable to do this outside the event processing because so much code depends on it. + // Once all those busy waiting loops can poll the event queue for a proper skip event, this will mostly go away. + inputState.AddEvent(ev); + + // Also add it to the event queue - this is where everything should transition to eventually. eventhead = (eventhead+1)&(NUM_EVENTS-1); } @@ -230,4 +240,4 @@ void D_RemoveNextCharEvent() } } } - \ No newline at end of file + diff --git a/source/common/inputstate.h b/source/common/inputstate.h index 1366d69dc..425172c14 100644 --- a/source/common/inputstate.h +++ b/source/common/inputstate.h @@ -247,11 +247,14 @@ public: void keySetState(int32_t key, int32_t state) { + if (state && !GetKeyStatus(key)) + { + KB_LastScan = key; + } + SetKeyStatus(key, state); event_t ev = { (uint8_t)(state ? EV_KeyDown : EV_KeyUp), 0, (int16_t)key }; - D_PostEvent(&ev); - if (state) { g_keyFIFO[g_keyFIFOend] = key; @@ -290,6 +293,12 @@ public: return c; } + + void keySetChar(int key) + { + g_keyAsciiFIFO[g_keyAsciiEnd] = key; + g_keyAsciiEnd = ((g_keyAsciiEnd + 1) & (KEYFIFOSIZ - 1)); + } void keyFlushChars(void) { @@ -323,19 +332,15 @@ public: KB_LastScan = 0; ClearAllKeyStatus(); } + + void AddEvent(const event_t *ev) + { + keySetState(ev->data1, ev->type == EV_KeyDown); + if (ev->data2) keySetChar(ev->data2); + } }; extern InputState inputState; -static inline void KB_KeyEvent(int32_t scancode, int32_t keypressed) -{ - if (keypressed) inputState.SetLastScanCode(scancode); -} - -void keySetCallback(void (*callback)(int32_t, int32_t)); -inline void KB_Startup(void) { keySetCallback(KB_KeyEvent); } -inline void KB_Shutdown(void) { keySetCallback((void (*)(int32_t, int32_t))NULL); } - - diff --git a/source/rr/src/menus.cpp b/source/rr/src/menus.cpp index d36c5c033..634571628 100644 --- a/source/rr/src/menus.cpp +++ b/source/rr/src/menus.cpp @@ -48,24 +48,10 @@ static FORCE_INLINE void Menu_StartTextInput() { inputState.keyFlushChars(); inputState.ClearKeysDown(); -#if defined EDUKE32_TOUCH_DEVICES && defined SDL_MAJOR_VERSION && SDL_MAJOR_VERSION > 1 -# if defined __ANDROID__ - AndroidShowKeyboard(1); -# else - SDL_StartTextInput(); -# endif -#endif } static FORCE_INLINE void Menu_StopTextInput() { -#if defined EDUKE32_TOUCH_DEVICES && defined SDL_MAJOR_VERSION && SDL_MAJOR_VERSION > 1 -# if defined __ANDROID__ - AndroidShowKeyboard(0); -# else - SDL_StopTextInput(); -# endif -#endif } static FORCE_INLINE void rotatesprite_ybounds(int32_t sx, int32_t sy, int32_t z, int16_t a, int16_t picnum, int8_t dashade, uint8_t dapalnum, int32_t dastat, int32_t ydim_upper, int32_t ydim_lower)