diff --git a/src/console.c b/src/console.c index bded0279a..8039ff888 100644 --- a/src/console.c +++ b/src/console.c @@ -727,6 +727,8 @@ void CON_ToggleOff(void) I_UpdateMouseGrab(); + I_SetTextInput(false); + Unlock_state(); } @@ -767,17 +769,24 @@ void CON_Ticker(void) con_destlines = 0; CON_ClearHUD(); I_UpdateMouseGrab(); + I_SetTextInput(false); } else + { CON_ChangeHeight(); + I_SetTextInput(true); + } } // check if console ready for prompt if (con_destlines >= minheight) + { consoleready = true; + } else + { consoleready = false; - + } // make overlay messages disappear after a while for (i = 0; i < con_hudlines; i++) { diff --git a/src/hu_stuff.c b/src/hu_stuff.c index 6258ff241..2435df770 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -1155,6 +1155,7 @@ void HU_clearChatChars(void) chat_on = false; I_UpdateMouseGrab(); + I_SetTextInput(false); } // @@ -1200,6 +1201,7 @@ boolean HU_Responder(event_t *ev) teamtalk = false; chat_scrollmedown = true; typelines = 1; + I_SetTextInput(true); return true; } if (G_ControlBoundToKey(0, gc_teamkey, ev->data1, false) @@ -1212,6 +1214,7 @@ boolean HU_Responder(event_t *ev) teamtalk = G_GametypeHasTeams(); // Don't teamtalk if we don't have teams. chat_scrollmedown = true; typelines = 1; + I_SetTextInput(true); return true; } } @@ -1241,6 +1244,7 @@ boolean HU_Responder(event_t *ev) chat_on = false; chat_scrollmedown = true; // you hit enter, so you might wanna autoscroll to see what you just sent. :) + I_SetTextInput(false); I_UpdateMouseGrab(); } else if (c == KEY_ESCAPE @@ -1249,6 +1253,7 @@ boolean HU_Responder(event_t *ev) && c >= NUMKEYS)) // If it's not a keyboard key, then the chat button is used as a toggle. { chat_on = false; + I_SetTextInput(false); I_UpdateMouseGrab(); } else if ((c == KEY_UPARROW || c == KEY_MOUSEWHEELUP) && chat_scroll > 0 && !OLDCHAT) // CHAT SCROLLING YAYS! diff --git a/src/i_video.h b/src/i_video.h index 9d101a0b0..e94017778 100644 --- a/src/i_video.h +++ b/src/i_video.h @@ -20,6 +20,9 @@ extern "C" { #endif +boolean I_UseNativeKeyboard(void); +void I_SetTextInput(boolean enable); + typedef enum { /// Software @@ -153,8 +156,6 @@ void I_EndRead(void); UINT32 I_GetRefreshRate(void); -boolean I_UseNativeKeyboard(void); - extern consvar_t cv_keyboardlayout; void I_SetBorderlessWindow(void); diff --git a/src/keys.h b/src/keys.h index 2ae5a5d44..ae31209ec 100644 --- a/src/keys.h +++ b/src/keys.h @@ -30,6 +30,14 @@ extern "C" { #define KEY_MINUS 45 #define KEY_EQUALS 61 +//azerty special keys support +//(necessary for being able to print 'regular' chars in azerty) +#define KEY_FR_E_AIGUE (0x80+2) +#define KEY_FR_E_GRAVE (0x80+10) +#define KEY_FR_C_CEDILLE (0x80+7) +#define KEY_FR_A_GRAVE (0x80+5) +#define KEY_FR_U_GRAVE (0x80+13) + #define KEY_NUMLOCK (0x80+69) #define KEY_SCROLLLOCK (0x80+70) diff --git a/src/m_menu.c b/src/m_menu.c index c1f1f4fb9..ac1365536 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -147,7 +147,6 @@ const char *quitmsg[NUM_QUITMESSAGES]; boolean fromlevelselect = false; -boolean menu_text_input = false; static char menu_text_input_buf[MAXSTRINGLENGTH]; static textinput_t menuinput; @@ -363,6 +362,11 @@ static void M_RawSetItemOn(menu_t *menu, INT16 index) { M_TextInputInit(&menuinput, menu_text_input_buf, M_StringCvarLength(cv)); M_TextInputSetString(&menuinput, cv->string); + I_SetTextInput(true); + } + else + { + I_SetTextInput(false); } } @@ -1970,6 +1974,8 @@ void M_StartControlPanel(void) // void M_ClearMenus(boolean callexitmenufunc) { + I_SetTextInput(false); + if (currentMenu) { if (currentMenu->quitroutine && callexitmenufunc) @@ -1991,7 +1997,6 @@ void M_ClearMenus(boolean callexitmenufunc) currentMenu = NULL; messagebox.active = false; hidetitlemap = false; - menu_text_input = false; // D_StartTitle does its own wipe, since GS_TIMEATTACK is now a complete gamestate. if (gamestate == GS_TIMEATTACK) @@ -2161,7 +2166,6 @@ void M_EnterMenu(menutype_t menunum, boolean callexit, INT32 arg) if (menustack[0] == MN_NONE) menustack[0] = menunum; // M_ClearMenus got called, put it back on the stack - menu_text_input = true; M_SetupNextMenu(menunum, callexit); } diff --git a/src/sdl/i_video.cpp b/src/sdl/i_video.cpp index 14a4e472f..45ff58a2e 100644 --- a/src/sdl/i_video.cpp +++ b/src/sdl/i_video.cpp @@ -87,12 +87,7 @@ rendermode_t rendermode = render_soft; rendermode_t chosenrendermode = render_none; // set by command line arguments -boolean I_UseNativeKeyboard(void) -{ - return cv_keyboardlayout.value == 2 && (chat_on || CON_Ready() || (menu_text_input && menustack[0])); -} - -static CV_PossibleValue_t keyboardlayout_cons_t[] = {{1,"Default US"}, {2, "Native"}, {0, NULL}}; +static CV_PossibleValue_t keyboardlayout_cons_t[] = {{1,"Default US"}, {2, "Native"}, {3, "AZERTY"}, {0, NULL}}; consvar_t cv_keyboardlayout = CVAR_INIT ("keyboardlayout", "Default US", CV_SAVE, keyboardlayout_cons_t, NULL); boolean highcolor = false; @@ -464,35 +459,6 @@ static INT32 Impl_SDL_Scancode_To_Keycode(SDL_Scancode code) return 0; } -// Get the equivalent ASCII (Unicode?) character for a keypress. -static INT32 GetTypedChar(SDL_KeyboardEvent *evt) -{ - SDL_Event next_event; - SDL_Keycode keycode = evt->key; - SDL_Scancode scancode = evt->scancode; - const boolean Text_Input_Only = (chat_on || CON_Ready() || (menu_text_input && menustack[0])); // only use this this if on chat or console or the current menu wants inputs from us (except if its the control setup menu ig) - - // Special cases, where we always return a fixed value. - switch (keycode) - { - case SDLK_BACKSPACE: return KEY_BACKSPACE; - case SDLK_RETURN: return KEY_ENTER; - default: - break; - } - - if (Text_Input_Only) - { - if (SDL_PeepEvents(&next_event, 1, SDL_PEEKEVENT, SDL_EVENT_FIRST, SDL_EVENT_LAST) == 1 && next_event.type == SDL_EVENT_TEXT_INPUT) - { - if (next_event.text.text[1] == '\0') // limit to ASCII - return next_event.text.text[0]; - } - } - - return Impl_SDL_Scancode_To_Keycode(scancode); // fallback -} - static boolean IgnoreMouse(void) { if (cv_alwaysgrabmouse.value) @@ -677,6 +643,145 @@ static void Impl_HandleWindowEvent(SDL_WindowEvent evt) } } +static INT32 Impl_SDL_Keysym_To_Keycode(SDL_KeyboardEvent evt) +{ + SDL_Keycode keycode = evt.key; + SDL_Scancode scancode = evt.scancode; + + if (keycode >= SDLK_A && keycode <= SDLK_Z) + { + // get lowercase ASCII + return keycode; + } + if (keycode >= SDLK_F1 && keycode <= SDLK_F10) + { + return KEY_F1 + (keycode - SDLK_F1); + } + + switch (scancode) + { + case SDL_SCANCODE_APOSTROPHE: return KEY_FR_U_GRAVE; + case SDL_SCANCODE_LEFTBRACKET: return '^'; + default: break; + } + + switch (keycode) + { + // F11 and F12 are separated from the rest of the function keys + case SDLK_F11: return KEY_F11; + case SDLK_F12: return KEY_F12; + + case SDLK_RETURN: return KEY_ENTER; + case SDLK_ESCAPE: return KEY_ESCAPE; + case SDLK_BACKSPACE: return KEY_BACKSPACE; + case SDLK_TAB: return KEY_TAB; + case SDLK_SPACE: return KEY_SPACE; + case SDLK_EQUALS: return KEY_EQUALS; + case SDLK_SEMICOLON: return ';'; + case SDLK_COMMA: return ','; + case SDLK_COLON: return ':'; + case SDLK_EXCLAIM: return '!'; + case SDLK_DOLLAR: return '$'; + case SDLK_ASTERISK: return '*'; + case SDLK_PERCENT: return '%'; + case SDLK_0: return KEY_FR_A_GRAVE; + case SDLK_1: + case SDLK_AMPERSAND: return '&'; + case SDLK_2: return KEY_FR_E_AIGUE; + case SDLK_3: + case SDLK_DBLAPOSTROPHE: return '"'; + case SDLK_4: return '\''; + case SDLK_5: + case SDLK_LEFTPAREN: return '('; + case SDLK_6: + case SDLK_MINUS: return KEY_MINUS; + case SDLK_7: return KEY_FR_E_GRAVE; + case SDLK_8: + case SDLK_UNDERSCORE: return '_'; + case SDLK_9: return KEY_FR_C_CEDILLE; + case SDLK_RIGHTPAREN: return ')'; + case SDLK_SLASH: return '/'; + case SDLK_LESS: return '<'; + + + case SDLK_KP_0: return KEY_KEYPAD0; + case SDLK_KP_1: return KEY_KEYPAD1; + case SDLK_KP_2: return KEY_KEYPAD2; + case SDLK_KP_3: return KEY_KEYPAD3; + case SDLK_KP_4: return KEY_KEYPAD4; + case SDLK_KP_5: return KEY_KEYPAD5; + case SDLK_KP_6: return KEY_KEYPAD6; + case SDLK_KP_7: return KEY_KEYPAD7; + case SDLK_KP_8: return KEY_KEYPAD8; + case SDLK_KP_9: return KEY_KEYPAD9; + + default: break; + } + + return Impl_SDL_Scancode_To_Keycode(scancode); +} + +static boolean native_input_active = false; + +// used to supress the games shift/alt handling +boolean I_UseNativeKeyboard(void) +{ + return (cv_keyboardlayout.value == 2 && native_input_active); +} + +void I_SetTextInput(boolean enable) +{ + if (!window) + return; + + if (enable && !native_input_active) + { + SDL_StartTextInput(window); + native_input_active = true; + } + else if (!enable && native_input_active) + { + SDL_StopTextInput(window); + native_input_active = false; + } +} + +// Get the equivalent ASCII (Unicode?) character for a keypress. +static INT32 GetTypedChar(SDL_KeyboardEvent evt) +{ + SDL_Event next_event; + SDL_Keycode keycode = evt.key; + SDL_Scancode scancode = evt.scancode; + + // only use this this if on chat or console or the current menu wants inputs from us (except if its the control setup menu ig) + if (native_input_active) + { + // Special cases, where we always return a fixed value. + switch (keycode) + { + case SDLK_BACKSPACE: return KEY_BACKSPACE; + case SDLK_RETURN: return KEY_ENTER; + default: + break; + } + + // Special case for console key + if (scancode == SDL_SCANCODE_GRAVE) + return '`'; + + if (SDL_PeepEvents(&next_event, 1, SDL_PEEKEVENT, SDL_EVENT_FIRST, SDL_EVENT_LAST) == 1 && next_event.type == SDL_EVENT_TEXT_INPUT) + { + if (next_event.text.text[1] == '\0') // limit to ASCII + { + return next_event.text.text[0]; + } + } + } + + // otherwise fallback to scancodes + return Impl_SDL_Scancode_To_Keycode(scancode); +} + static void Impl_HandleKeyboardEvent(SDL_KeyboardEvent evt, Uint32 type) { event_t event; @@ -699,7 +804,10 @@ static void Impl_HandleKeyboardEvent(SDL_KeyboardEvent evt, Uint32 type) switch (cv_keyboardlayout.value) { case 2: // "native" - event.data1 = GetTypedChar(&evt); + event.data1 = GetTypedChar(evt); + break; + case 3: // AZERTY + event.data1 = Impl_SDL_Keysym_To_Keycode(evt); break; default: event.data1 = Impl_SDL_Scancode_To_Keycode(evt.scancode);