From 88acebf808493db19a845a5d51969778dc5b9dde Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 16 Jun 2013 17:10:30 +0200 Subject: [PATCH 1/4] Fix an uninitalized member, and also make sure the mouse is captured when OpenMW starts --- extern/sdl4ogre/sdlinputwrapper.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/extern/sdl4ogre/sdlinputwrapper.cpp b/extern/sdl4ogre/sdlinputwrapper.cpp index 3f1b8577f..e02d885b5 100644 --- a/extern/sdl4ogre/sdlinputwrapper.cpp +++ b/extern/sdl4ogre/sdlinputwrapper.cpp @@ -26,7 +26,8 @@ namespace SFO mWrapPointer(false), mMouseZ(0), mMouseY(0), - mMouseX(0) + mMouseX(0), + mMouseInWindow(true) { _setupOISKeys(); From 03682184c67c7b72a7a2f9deb21c3572b80b83fa Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 16 Jun 2013 18:06:55 +0200 Subject: [PATCH 2/4] Enable SDL_TEXTINPUT events only when a text input widget currently has key focus --- apps/openmw/mwbase/windowmanager.hpp | 2 ++ apps/openmw/mwgui/class.cpp | 4 ++-- apps/openmw/mwgui/console.cpp | 9 +++------ apps/openmw/mwgui/countdialog.cpp | 5 ++++- apps/openmw/mwgui/textinput.cpp | 8 ++++---- apps/openmw/mwgui/windowmanagerimp.cpp | 21 ++++++++++++++++++++- apps/openmw/mwgui/windowmanagerimp.hpp | 3 +++ extern/sdl4ogre/sdlinputwrapper.cpp | 5 ----- 8 files changed, 38 insertions(+), 19 deletions(-) diff --git a/apps/openmw/mwbase/windowmanager.hpp b/apps/openmw/mwbase/windowmanager.hpp index c36278b6d..36d4ab8bb 100644 --- a/apps/openmw/mwbase/windowmanager.hpp +++ b/apps/openmw/mwbase/windowmanager.hpp @@ -264,6 +264,8 @@ namespace MWBase virtual void changePointer (const std::string& name) = 0; virtual const Translation::Storage& getTranslationDataStorage() const = 0; + + virtual void setKeyFocusWidget (MyGUI::Widget* widget) = 0; }; } diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index ab8103868..2f00918b0 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -407,7 +407,7 @@ namespace MWGui getWidget(mEditName, "EditName"); // Make sure the edit box has focus - MyGUI::InputManager::getInstance().setKeyFocusWidget(mEditName); + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mEditName); MyGUI::Button* descriptionButton; getWidget(descriptionButton, "DescriptionButton"); @@ -866,7 +866,7 @@ namespace MWGui okButton->setCaption(MWBase::Environment::get().getWindowManager()->getGameSettingString("sInputMenu1", "")); // Make sure the edit box has focus - MyGUI::InputManager::getInstance().setKeyFocusWidget(mTextEdit); + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mTextEdit); } DescriptionDialog::~DescriptionDialog() diff --git a/apps/openmw/mwgui/console.cpp b/apps/openmw/mwgui/console.cpp index b69d2d6af..f438d5e09 100644 --- a/apps/openmw/mwgui/console.cpp +++ b/apps/openmw/mwgui/console.cpp @@ -5,6 +5,7 @@ #include "../mwscript/extensions.hpp" #include "../mwbase/environment.hpp" +#include "../mwbase/windowmanager.hpp" namespace MWGui { @@ -131,16 +132,12 @@ namespace MWGui // Give keyboard focus to the combo box whenever the console is // turned on - MyGUI::InputManager::getInstance().setKeyFocusWidget(command); + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(command); } void Console::disable() { setVisible(false); - - // Remove keyboard focus from the console input whenever the - // console is turned off - MyGUI::InputManager::getInstance().setKeyFocusWidget(NULL); } void Console::setFont(const std::string &fntName) @@ -415,7 +412,7 @@ namespace MWGui setTitle("#{sConsoleTitle}"); mPtr = MWWorld::Ptr(); } - MyGUI::InputManager::getInstance().setKeyFocusWidget(command); + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(command); } void Console::onReferenceUnavailable() diff --git a/apps/openmw/mwgui/countdialog.cpp b/apps/openmw/mwgui/countdialog.cpp index 354de561d..c429b0ccf 100644 --- a/apps/openmw/mwgui/countdialog.cpp +++ b/apps/openmw/mwgui/countdialog.cpp @@ -2,6 +2,9 @@ #include +#include "../mwbase/environment.hpp" +#include "../mwbase/windowmanager.hpp" + namespace MWGui { CountDialog::CountDialog() : @@ -40,7 +43,7 @@ namespace MWGui mMainWidget->getHeight()); // by default, the text edit field has the focus of the keyboard - MyGUI::InputManager::getInstance().setKeyFocusWidget(mItemEdit); + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mItemEdit); mSlider->setScrollPosition(maxCount-1); mItemEdit->setCaption(boost::lexical_cast(maxCount)); diff --git a/apps/openmw/mwgui/textinput.cpp b/apps/openmw/mwgui/textinput.cpp index d4f8a2533..954bc41ab 100644 --- a/apps/openmw/mwgui/textinput.cpp +++ b/apps/openmw/mwgui/textinput.cpp @@ -20,7 +20,7 @@ namespace MWGui okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &TextInputDialog::onOkClicked); // Make sure the edit box has focus - MyGUI::InputManager::getInstance().setKeyFocusWidget(mTextEdit); + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mTextEdit); } void TextInputDialog::setNextButtonShow(bool shown) @@ -43,7 +43,7 @@ namespace MWGui { WindowModal::open(); // Make sure the edit box has focus - MyGUI::InputManager::getInstance().setKeyFocusWidget(mTextEdit); + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mTextEdit); } // widget controls @@ -53,7 +53,7 @@ namespace MWGui if (mTextEdit->getCaption() == "") { MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage37}"); - MyGUI::InputManager::getInstance ().setKeyFocusWidget (mTextEdit); + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget (mTextEdit); } else eventDone(this); @@ -64,7 +64,7 @@ namespace MWGui if (mTextEdit->getCaption() == "") { MWBase::Environment::get().getWindowManager()->messageBox ("#{sNotifyMessage37}"); - MyGUI::InputManager::getInstance ().setKeyFocusWidget (mTextEdit); + MWBase::Environment::get().getWindowManager()->setKeyFocusWidget (mTextEdit); } else eventDone(this); diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index eafa9df6e..c57fd7550 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -225,6 +225,8 @@ namespace MWGui MyGUI::PointerManager::getInstance().eventChangeMousePointer += MyGUI::newDelegate(this, &WindowManager::onCursorChange); + MyGUI::InputManager::getInstance().eventChangeKeyFocus += MyGUI::newDelegate(this, &WindowManager::onKeyFocusChanged); + setUseHardwareCursors(mUseHardwareCursors); onCursorChange(MyGUI::PointerManager::getInstance().getDefaultPointer()); mCursorManager->cursorVisibilityChange(false); @@ -360,7 +362,7 @@ namespace MWGui mToolTips->enterGuiMode(); if (gameMode) - MyGUI::InputManager::getInstance ().setKeyFocusWidget (NULL); + setKeyFocusWidget (NULL); setMinimapVisibility((mAllowed & GW_Map) && !mMap->pinned()); setWeaponVisibility((mAllowed & GW_Inventory) && !mInventoryWindow->pinned()); @@ -1299,4 +1301,21 @@ namespace MWGui mInventoryWindow->updatePlayer(); } + void WindowManager::setKeyFocusWidget(MyGUI::Widget *widget) + { + if (widget == NULL) + MyGUI::InputManager::getInstance().resetKeyFocusWidget(); + else + MyGUI::InputManager::getInstance().setKeyFocusWidget(widget); + onKeyFocusChanged(widget); + } + + void WindowManager::onKeyFocusChanged(MyGUI::Widget *widget) + { + if (widget && widget->castType(false)) + SDL_StartTextInput(); + else + SDL_StopTextInput(); + } + } diff --git a/apps/openmw/mwgui/windowmanagerimp.hpp b/apps/openmw/mwgui/windowmanagerimp.hpp index 31b829cda..42f2f4dc2 100644 --- a/apps/openmw/mwgui/windowmanagerimp.hpp +++ b/apps/openmw/mwgui/windowmanagerimp.hpp @@ -98,6 +98,8 @@ namespace MWGui */ virtual void update(); + virtual void setKeyFocusWidget (MyGUI::Widget* widget); + virtual void setNewGame(bool newgame); virtual void pushGuiMode(GuiMode mode); @@ -353,6 +355,7 @@ namespace MWGui void onRetrieveTag(const MyGUI::UString& _tag, MyGUI::UString& _result); void onCursorChange(const std::string& name); + void onKeyFocusChanged(MyGUI::Widget* widget); }; } diff --git a/extern/sdl4ogre/sdlinputwrapper.cpp b/extern/sdl4ogre/sdlinputwrapper.cpp index e02d885b5..a6d464027 100644 --- a/extern/sdl4ogre/sdlinputwrapper.cpp +++ b/extern/sdl4ogre/sdlinputwrapper.cpp @@ -30,9 +30,6 @@ namespace SFO mMouseInWindow(true) { _setupOISKeys(); - - // FIXME: text input should only be enabled when a text input widget currently has focus - SDL_StartTextInput(); } InputWrapper::~InputWrapper() @@ -40,8 +37,6 @@ namespace SFO if(mSDLWindow != NULL && mOwnWindow) SDL_DestroyWindow(mSDLWindow); mSDLWindow = NULL; - - SDL_StopTextInput(); } void InputWrapper::capture() From b16c92c2f53f0e9b3ffc510209090c8717589deb Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 16 Jun 2013 19:43:59 +0200 Subject: [PATCH 3/4] Better handle SDL_TEXTINPUT events --- apps/openmw/mwgui/loadingscreen.cpp | 3 +- apps/openmw/mwinput/inputmanagerimp.cpp | 71 ++++++++++++++++++++++- apps/openmw/mwinput/inputmanagerimp.hpp | 1 + extern/sdl4ogre/events.h | 1 + extern/sdl4ogre/sdlinputwrapper.cpp | 75 ++----------------------- extern/sdl4ogre/sdlinputwrapper.hpp | 2 - 6 files changed, 77 insertions(+), 76 deletions(-) diff --git a/apps/openmw/mwgui/loadingscreen.cpp b/apps/openmw/mwgui/loadingscreen.cpp index 018f51feb..d4b06b2ab 100644 --- a/apps/openmw/mwgui/loadingscreen.cpp +++ b/apps/openmw/mwgui/loadingscreen.cpp @@ -10,6 +10,7 @@ #include "../mwbase/world.hpp" #include "../mwbase/windowmanager.hpp" +#include "../mwbase/inputmanager.hpp" namespace MWGui { @@ -126,7 +127,7 @@ namespace MWGui // always update input before rendering something, otherwise mygui goes crazy when something was entered in the frame before // (e.g. when using "coc" console command, it would enter an infinite loop and crash due to overflow) - //MWBase::Environment::get().getInputManager()->update(0, true); + MWBase::Environment::get().getInputManager()->update(0, true); Ogre::CompositorChain* chain = Ogre::CompositorManager::getSingleton().getCompositorChain(mWindow->getViewport(0)); diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index f53508f86..2fd8b4085 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -23,6 +23,65 @@ using namespace ICS; +namespace +{ + std::vector utf8ToUnicode(const std::string& utf8) + { + std::vector unicode; + size_t i = 0; + while (i < utf8.size()) + { + unsigned long uni; + size_t todo; + unsigned char ch = utf8[i++]; + if (ch <= 0x7F) + { + uni = ch; + todo = 0; + } + else if (ch <= 0xBF) + { + throw std::logic_error("not a UTF-8 string"); + } + else if (ch <= 0xDF) + { + uni = ch&0x1F; + todo = 1; + } + else if (ch <= 0xEF) + { + uni = ch&0x0F; + todo = 2; + } + else if (ch <= 0xF7) + { + uni = ch&0x07; + todo = 3; + } + else + { + throw std::logic_error("not a UTF-8 string"); + } + for (size_t j = 0; j < todo; ++j) + { + if (i == utf8.size()) + throw std::logic_error("not a UTF-8 string"); + unsigned char ch = utf8[i++]; + if (ch < 0x80 || ch > 0xBF) + throw std::logic_error("not a UTF-8 string"); + uni <<= 6; + uni += ch & 0x3F; + } + if (uni >= 0xD800 && uni <= 0xDFFF) + throw std::logic_error("not a UTF-8 string"); + if (uni > 0x10FFFF) + throw std::logic_error("not a UTF-8 string"); + unicode.push_back(uni); + } + return unicode; + } +} + namespace MWInput { InputManager::InputManager(OEngine::Render::OgreRenderer &ogre, @@ -422,11 +481,19 @@ namespace MWInput OIS::KeyCode kc = mInputManager->sdl2OISKeyCode(arg.keysym.sym); - MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::Enum(kc), text); - + if (kc != OIS::KC_UNASSIGNED) + MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::Enum(kc), 0); return true; } + void InputManager::textInput(const SDL_TextInputEvent &arg) + { + const char* text = &arg.text[0]; + std::vector unicode = utf8ToUnicode(std::string(text)); + for (std::vector::iterator it = unicode.begin(); it != unicode.end(); ++it) + MyGUI::InputManager::getInstance().injectKeyPress(MyGUI::KeyCode::None, *it); + } + bool InputManager::keyReleased(const SDL_KeyboardEvent &arg ) { mInputBinder->keyReleased (arg); diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 57c367bde..788f116ac 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -88,6 +88,7 @@ namespace MWInput public: virtual bool keyPressed(const SDL_KeyboardEvent &arg ); virtual bool keyReleased( const SDL_KeyboardEvent &arg ); + virtual void textInput (const SDL_TextInputEvent &arg); virtual bool mousePressed( const SDL_MouseButtonEvent &arg, Uint8 id ); virtual bool mouseReleased( const SDL_MouseButtonEvent &arg, Uint8 id ); diff --git a/extern/sdl4ogre/events.h b/extern/sdl4ogre/events.h index 5a0146635..13f8b3101 100644 --- a/extern/sdl4ogre/events.h +++ b/extern/sdl4ogre/events.h @@ -35,6 +35,7 @@ class KeyListener { public: virtual ~KeyListener() {} + virtual void textInput (const SDL_TextInputEvent& arg) {} virtual bool keyPressed(const SDL_KeyboardEvent &arg) = 0; virtual bool keyReleased(const SDL_KeyboardEvent &arg) = 0; }; diff --git a/extern/sdl4ogre/sdlinputwrapper.cpp b/extern/sdl4ogre/sdlinputwrapper.cpp index a6d464027..5c1df52c6 100644 --- a/extern/sdl4ogre/sdlinputwrapper.cpp +++ b/extern/sdl4ogre/sdlinputwrapper.cpp @@ -67,12 +67,15 @@ namespace SFO break; case SDL_KEYDOWN: if (!evt.key.repeat) - _handleKeyPress(evt.key); + mKeyboardListener->keyPressed(evt.key); break; case SDL_KEYUP: if (!evt.key.repeat) mKeyboardListener->keyReleased(evt.key); break; + case SDL_TEXTINPUT: + mKeyboardListener->textInput(evt.text); + break; case SDL_WINDOWEVENT: handleWindowEvent(evt); break; @@ -220,74 +223,6 @@ namespace SFO return pack_evt; } - void InputWrapper::_handleKeyPress(SDL_KeyboardEvent &evt) - { - //SDL keyboard events are followed by the actual text those keys would generate - //to account for languages that require multiple keystrokes to produce a key. - //Look for an event immediately following ours, assuming each key produces exactly - //one character or none at all. - - //TODO: Check if this works properly for multibyte symbols - //do we have to worry about endian-ness? - //for that matter, check if we even need to do any of this. - - SDL_Event text_evts[1]; - if(SDL_PeepEvents(text_evts, 1, SDL_GETEVENT, SDL_TEXTINPUT, SDL_TEXTINPUT) != 0) - { - if(strlen(text_evts[0].text.text) != 0) - { - const unsigned char* symbol = reinterpret_cast(&(text_evts[0].text.text[0])); - evt.keysym.unicode = _UTF8ToUTF32(symbol); - } - } - - mKeyboardListener->keyPressed(evt); - } - - //Lifted from OIS' LinuxKeyboard.cpp - Uint32 InputWrapper::_UTF8ToUTF32(const unsigned char *buf) - { - unsigned char FirstChar = buf[0]; - - //it's an ascii char, bail out early. - if(FirstChar < 128) - return FirstChar; - - Uint32 val = 0; - Sint32 len = 0; - - if((FirstChar & 0xE0) == 0xC0) //2 Chars - { - len = 2; - val = FirstChar & 0x1F; - } - else if((FirstChar & 0xF0) == 0xE0) //3 Chars - { - len = 3; - val = FirstChar & 0x0F; - } - else if((FirstChar & 0xF8) == 0xF0) //4 Chars - { - len = 4; - val = FirstChar & 0x07; - } - else if((FirstChar & 0xFC) == 0xF8) //5 Chars - { - len = 5; - val = FirstChar & 0x03; - } - else // if((FirstChar & 0xFE) == 0xFC) //6 Chars - { - len = 6; - val = FirstChar & 0x01; - } - - for(int i = 1; i < len; i++) - val = (val << 6) | (buf[i] & 0x3F); - - return val; - } - OIS::KeyCode InputWrapper::sdl2OISKeyCode(SDL_Keycode code) { OIS::KeyCode kc = OIS::KC_UNASSIGNED; @@ -296,8 +231,6 @@ namespace SFO if(ois_equiv != mKeyMap.end()) kc = ois_equiv->second; - else - std::cerr << "Couldn't find OIS key for " << code << std::endl; return kc; } diff --git a/extern/sdl4ogre/sdlinputwrapper.hpp b/extern/sdl4ogre/sdlinputwrapper.hpp index cb9804d54..08b329925 100644 --- a/extern/sdl4ogre/sdlinputwrapper.hpp +++ b/extern/sdl4ogre/sdlinputwrapper.hpp @@ -42,8 +42,6 @@ namespace SFO void _wrapMousePointer(const SDL_MouseMotionEvent &evt); MouseMotionEvent _packageMouseMotion(const SDL_Event& evt); - void _handleKeyPress(SDL_KeyboardEvent& evt); - Uint32 _UTF8ToUTF32(const unsigned char *buf); void _setupOISKeys(); SFO::MouseListener* mMouseListener; From 4fd7891d2cf57e7531c07da0e288c6eed197f186 Mon Sep 17 00:00:00 2001 From: scrawl Date: Sun, 16 Jun 2013 20:26:27 +0200 Subject: [PATCH 4/4] Fix a message box issue --- apps/openmw/mwgui/tooltips.cpp | 15 +++------------ apps/openmw/mwgui/tooltips.hpp | 5 ----- apps/openmw/mwgui/windowmanagerimp.cpp | 5 ----- apps/openmw/mwinput/inputmanagerimp.cpp | 2 +- 4 files changed, 4 insertions(+), 23 deletions(-) diff --git a/apps/openmw/mwgui/tooltips.cpp b/apps/openmw/mwgui/tooltips.cpp index e73ed6b5e..9cbb3cced 100644 --- a/apps/openmw/mwgui/tooltips.cpp +++ b/apps/openmw/mwgui/tooltips.cpp @@ -18,7 +18,6 @@ namespace MWGui ToolTips::ToolTips() : Layout("openmw_tooltips.layout") - , mGameMode(true) , mFullHelp(false) , mEnabled(true) , mFocusToolTipX(0.0) @@ -73,7 +72,9 @@ namespace MWGui return; } - if (!mGameMode) + bool gameMode = MWBase::Environment::get().getWindowManager()->isGuiMode(); + + if (gameMode) { const MyGUI::IntPoint& mousePos = MyGUI::InputManager::getInstance().getMousePosition(); @@ -297,16 +298,6 @@ namespace MWGui } } - void ToolTips::enterGameMode() - { - mGameMode = true; - } - - void ToolTips::enterGuiMode() - { - mGameMode = false; - } - void ToolTips::setFocusObject(const MWWorld::Ptr& focus) { mFocusObject = focus; diff --git a/apps/openmw/mwgui/tooltips.hpp b/apps/openmw/mwgui/tooltips.hpp index f8f256167..a8524a4ca 100644 --- a/apps/openmw/mwgui/tooltips.hpp +++ b/apps/openmw/mwgui/tooltips.hpp @@ -43,9 +43,6 @@ namespace MWGui void onFrame(float frameDuration); - void enterGameMode(); - void enterGuiMode(); - void setEnabled(bool enabled); void toggleFullHelp(); ///< show extra info in item tooltips (owner, script) @@ -104,8 +101,6 @@ namespace MWGui int mLastMouseX; int mLastMouseY; - bool mGameMode; - bool mEnabled; bool mFullHelp; diff --git a/apps/openmw/mwgui/windowmanagerimp.cpp b/apps/openmw/mwgui/windowmanagerimp.cpp index c57fd7550..5ca82bc8a 100644 --- a/apps/openmw/mwgui/windowmanagerimp.cpp +++ b/apps/openmw/mwgui/windowmanagerimp.cpp @@ -356,11 +356,6 @@ namespace MWGui mInputBlocker->setVisible (gameMode); setCursorVisible(!gameMode); - if (gameMode) - mToolTips->enterGameMode(); - else - mToolTips->enterGuiMode(); - if (gameMode) setKeyFocusWidget (NULL); diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 2fd8b4085..724caf874 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -408,6 +408,7 @@ namespace MWInput mMouseLookEnabled = !guiMode; if (guiMode) mWindows.showCrosshair(false); + mWindows.setCursorVisible(guiMode); // if not in gui mode, the camera decides whether to show crosshair or not. } @@ -470,7 +471,6 @@ namespace MWInput bool InputManager::keyPressed( const SDL_KeyboardEvent &arg ) { mInputBinder->keyPressed (arg); - unsigned int text = arg.keysym.unicode; if(arg.keysym.sym == SDLK_RETURN && MWBase::Environment::get().getWindowManager()->isGuiMode())