Bläddra i källkod

Merge pull request #1854 from JeffProgrammer/SDL_textinput_fix

fix SDL text events from generating a ~ key when opening the console
Areloch 8 år sedan
förälder
incheckning
2cdc596b86

+ 18 - 3
Engine/source/windowManager/sdl/sdlWindow.cpp

@@ -486,6 +486,19 @@ void PlatformWindowSDL::_triggerKeyNotify(const SDL_Event& evt)
    {
    {
       keyEvent.trigger(getWindowId(), torqueModifiers, inputAction, torqueKey);
       keyEvent.trigger(getWindowId(), torqueModifiers, inputAction, torqueKey);
       //Con::printf("Key %d : %d", tKey.sym, inputAction);
       //Con::printf("Key %d : %d", tKey.sym, inputAction);
+
+      if (inputAction == IA_MAKE && SDL_IsTextInputActive())
+      {
+         // We have to check if we already have a first responder active.
+         // We don't want to type the character if it actually creates another responder!
+         if (mWindowInputGenerator->lastKeyWasGlobalActionMap())
+         {
+            // Turn off Text input, and the next frame turn it back on. This tells SDL
+            // to not generate a text event for this global action map key.
+            SDL_StopTextInput();
+            mOwningManager->updateSDLTextInputState(PlatformWindowManagerSDL::KeyboardInputState::TEXT_INPUT);
+         }
+      }
    }
    }
 }
 }
 
 
@@ -607,8 +620,10 @@ const UTF16 *PlatformWindowSDL::getCurtainWindowClassName()
 void PlatformWindowSDL::setKeyboardTranslation(const bool enabled)
 void PlatformWindowSDL::setKeyboardTranslation(const bool enabled)
 {
 {
    mEnableKeyboardTranslation = enabled;
    mEnableKeyboardTranslation = enabled;
-   if (mEnableKeyboardTranslation)
-      SDL_StartTextInput();
+
+   // Flag for update. Let SDL know what kind of input state we are changing to.
+   if (enabled)
+      mOwningManager->updateSDLTextInputState(PlatformWindowManagerSDL::KeyboardInputState::TEXT_INPUT);
    else
    else
-      SDL_StopTextInput();
+      mOwningManager->updateSDLTextInputState(PlatformWindowManagerSDL::KeyboardInputState::RAW_INPUT);
 }
 }

+ 27 - 0
Engine/source/windowManager/sdl/sdlWindowMgr.cpp

@@ -59,6 +59,8 @@ PlatformWindowManagerSDL::PlatformWindowManagerSDL()
    mDisplayWindow = true;
    mDisplayWindow = true;
    mOffscreenRender = false;
    mOffscreenRender = false;
 
 
+   mInputState = KeyboardInputState::NONE;
+
    buildMonitorsList();
    buildMonitorsList();
 }
 }
 
 
@@ -262,6 +264,21 @@ void PlatformWindowManagerSDL::_process()
       }
       }
    }
    }
 
 
+   // After the event loop is processed, we can now see if we have to notify
+   // SDL that we want text based events. This fixes a bug where text based
+   // events would be generated while key presses would still be happening.
+   // See KeyboardInputState for further documentation.
+   if (mInputState != KeyboardInputState::NONE)
+   {
+      // Update text mode toggling.
+      if (mInputState == KeyboardInputState::TEXT_INPUT)
+         SDL_StartTextInput();
+      else
+         SDL_StopTextInput();
+
+      // Done until we need to update it again.
+      mInputState = KeyboardInputState::NONE;
+   }
 }
 }
 
 
 PlatformWindow * PlatformWindowManagerSDL::getWindowById( WindowId id )
 PlatformWindow * PlatformWindowManagerSDL::getWindowById( WindowId id )
@@ -343,6 +360,12 @@ void PlatformWindowManagerSDL::raiseCurtain()
    // TODO SDL
    // TODO SDL
 }
 }
 
 
+void PlatformWindowManagerSDL::updateSDLTextInputState(KeyboardInputState state)
+{
+   // Force update state. This will respond at the end of the event loop.
+   mInputState = state;
+}
+
 void Platform::openFolder(const char* path )
 void Platform::openFolder(const char* path )
 {
 {
     AssertFatal(0, "Not Implemented");
     AssertFatal(0, "Not Implemented");
@@ -369,4 +392,8 @@ AFTER_MODULE_INIT(gfx)
 {   
 {   
    int res = SDL_Init( SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_GAMECONTROLLER | SDL_INIT_EVENTS | SDL_INIT_NOPARACHUTE );
    int res = SDL_Init( SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_GAMECONTROLLER | SDL_INIT_EVENTS | SDL_INIT_NOPARACHUTE );
    AssertFatal(res != -1, "SDL init error");
    AssertFatal(res != -1, "SDL init error");
+
+   // By default, SDL enables text input. We disable it on initialization, and
+   // we will enable it whenever the time is right.
+   SDL_StopTextInput();
 }
 }

+ 34 - 0
Engine/source/windowManager/sdl/sdlWindowMgr.h

@@ -34,6 +34,30 @@ class FileDialog; // TODO SDL REMOVE
 /// SDL2 implementation of the window manager interface.
 /// SDL2 implementation of the window manager interface.
 class PlatformWindowManagerSDL : public PlatformWindowManager
 class PlatformWindowManagerSDL : public PlatformWindowManager
 {
 {
+public:
+   /// An enum that holds an event loop frame of the state of the
+   /// keyboard for how the keyboard is interpreted inside of Torque.
+   ///
+   /// SDL has a concept of text editing events as well as raw input
+   /// events. Because of this, SDL needs notified whenever it needs
+   /// to fire text based events. SDL will continue firing raw input
+   /// events as well during this time.
+   ///
+   /// The reason why this was created is because we needed time to
+   /// transition between raw input to raw input + text based events.
+   /// If we take a raw input and notify SDL we wanted text during the
+   /// event loop, SDL will issue a text input event as well. This was
+   /// causing issues with the console, where the console key would be
+   /// appended to the console buffer upon opening it. We fix this by
+   /// delaying the notification to SDL until the event loop is complete.
+   enum class KeyboardInputState
+   {
+      NONE = 0,       /// < No state change during this event loop cycle.
+      TEXT_INPUT = 1, /// < We want to change to text based events & raw input.
+      RAW_INPUT = 2   /// < We only want raw input.
+   };
+
+protected:
    friend class PlatformWindowSDL;
    friend class PlatformWindowSDL;
    friend class FileDialog; // TODO SDL REMOVE
    friend class FileDialog; // TODO SDL REMOVE
 
 
@@ -69,6 +93,10 @@ class PlatformWindowManagerSDL : public PlatformWindowManager
 
 
    SignalSlot<void()> mOnProcessSignalSlot;
    SignalSlot<void()> mOnProcessSignalSlot;
 
 
+   /// The input state that will change whenever SDL needs notified.
+   /// After it is handled, it will return to state NONE.
+   KeyboardInputState mInputState;
+
 public:
 public:
    PlatformWindowManagerSDL();
    PlatformWindowManagerSDL();
    ~PlatformWindowManagerSDL();
    ~PlatformWindowManagerSDL();
@@ -100,6 +128,12 @@ public:
    virtual void raiseCurtain();
    virtual void raiseCurtain();
 
 
    virtual void setDisplayWindow(bool set) { mDisplayWindow = set; }
    virtual void setDisplayWindow(bool set) { mDisplayWindow = set; }
+
+   /// Stores the input state so that the event loop will fire a check if we need
+   /// to change how keyboard input is being handled.
+   /// @param state The state of the keyboard input, either being raw input or text
+   ///  based input.
+   void updateSDLTextInputState(KeyboardInputState state);
 };
 };
 
 
 #endif
 #endif

+ 8 - 1
Engine/source/windowManager/windowInputGenerator.cpp

@@ -39,7 +39,8 @@ WindowInputGenerator::WindowInputGenerator( PlatformWindow *window ) :
                                              mLastCursorPos(0,0),
                                              mLastCursorPos(0,0),
                                              mClampToWindow(true),
                                              mClampToWindow(true),
                                              mFocused(false),
                                              mFocused(false),
-                                             mPixelsPerMickey(1.0f)
+                                             mPixelsPerMickey(1.0f),
+                                             mLastPressWasGlobalActionMap(false)
 {
 {
    AssertFatal(mWindow, "NULL PlatformWindow on WindowInputGenerator creation");
    AssertFatal(mWindow, "NULL PlatformWindow on WindowInputGenerator creation");
 
 
@@ -82,6 +83,9 @@ WindowInputGenerator::~WindowInputGenerator()
 //-----------------------------------------------------------------------------
 //-----------------------------------------------------------------------------
 void WindowInputGenerator::generateInputEvent( InputEventInfo &inputEvent )
 void WindowInputGenerator::generateInputEvent( InputEventInfo &inputEvent )
 {
 {
+   // Reset last press being global
+   mLastPressWasGlobalActionMap = false;
+
    if (!mInputController)// || !mFocused)
    if (!mInputController)// || !mFocused)
       return;
       return;
 
 
@@ -102,7 +106,10 @@ void WindowInputGenerator::generateInputEvent( InputEventInfo &inputEvent )
 
 
    // Give the ActionMap first shot.
    // Give the ActionMap first shot.
    if (ActionMap::handleEventGlobal(&inputEvent))
    if (ActionMap::handleEventGlobal(&inputEvent))
+   {
+      mLastPressWasGlobalActionMap = true;
       return;
       return;
+   }
 
 
    if (mInputController->processInputEvent(inputEvent))
    if (mInputController->processInputEvent(inputEvent))
       return;
       return;

+ 10 - 0
Engine/source/windowManager/windowInputGenerator.h

@@ -51,6 +51,9 @@ class WindowInputGenerator
       /// (one unit of mouse movement is a mickey) to units in the GUI.
       /// (one unit of mouse movement is a mickey) to units in the GUI.
       F32             mPixelsPerMickey;
       F32             mPixelsPerMickey;
 
 
+      /// This tells us if the last key we pressed was used from the global action map.
+      bool mLastPressWasGlobalActionMap;
+
       // Event Handlers
       // Event Handlers
       void handleMouseButton(WindowId did, U32 modifier,  U32 action, U16 button);
       void handleMouseButton(WindowId did, U32 modifier,  U32 action, U16 button);
       void handleMouseWheel (WindowId did, U32 modifier,  S32 wheelDeltaX, S32 wheelDeltaY);
       void handleMouseWheel (WindowId did, U32 modifier,  S32 wheelDeltaX, S32 wheelDeltaY);
@@ -83,6 +86,13 @@ class WindowInputGenerator
       /// event even if it maps to a character input event.
       /// event even if it maps to a character input event.
       bool wantAsKeyboardEvent( U32 modifiers, U32 key );
       bool wantAsKeyboardEvent( U32 modifiers, U32 key );
 
 
+      /// Tells us if the last key was used within the global action map.
+      /// @return true if the key was a global action map key, false otherwise.
+      /// @note Useful and currently used to tell if we just opened the console 
+      ///  by using the console key. Currently this is used to fix a bug in SDL
+      ///  but it is not limited to that use.
+      bool lastKeyWasGlobalActionMap() const { return mLastPressWasGlobalActionMap; }
+
     void addAcceleratorKey( void *hnd, const String &cmd, U32 keycode, U32 modifier)
     void addAcceleratorKey( void *hnd, const String &cmd, U32 keycode, U32 modifier)
     {
     {
         AccKeyMap acc;
         AccKeyMap acc;