diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index f13eb9daf7..805f4926c1 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -44,6 +44,7 @@ namespace MWInput , mUserFile(userFile) , mDragDrop(false) , mGuiCursorEnabled(false) + , mDebug(debug) , mInvertY (Settings::Manager::getBool("invert y axis", "Input")) , mCameraSensitivity (Settings::Manager::getFloat("camera sensitivity", "Input")) , mUISensitivity (Settings::Manager::getFloat("ui sensitivity", "Input")) @@ -52,50 +53,6 @@ namespace MWInput , mPreviewPOVDelay(0.f) , mTimeIdle(0.f) { - Ogre::RenderWindow* window = ogre.getWindow (); - size_t windowHnd; - - resetIdleTime(); - - window->getCustomAttribute("WINDOW", &windowHnd); - - - // Set non-exclusive mouse and keyboard input if the user requested - // it. - - //TODO: re-enable this and make it work with SDL - /* - - std::ostringstream windowHndStr; - OIS::ParamList pl; - - windowHndStr << windowHnd; - pl.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str())); - - if (debug) - { - #if defined OIS_WIN32_PLATFORM - pl.insert(std::make_pair(std::string("w32_mouse"), - std::string("DISCL_FOREGROUND" ))); - pl.insert(std::make_pair(std::string("w32_mouse"), - std::string("DISCL_NONEXCLUSIVE"))); - pl.insert(std::make_pair(std::string("w32_keyboard"), - std::string("DISCL_FOREGROUND"))); - pl.insert(std::make_pair(std::string("w32_keyboard"), - std::string("DISCL_NONEXCLUSIVE"))); - #elif defined OIS_LINUX_PLATFORM - pl.insert(std::make_pair(std::string("x11_mouse_grab"), - std::string("false"))); - pl.insert(std::make_pair(std::string("x11_mouse_hide"), - std::string("false"))); - pl.insert(std::make_pair(std::string("x11_keyboard_grab"), - std::string("false"))); - pl.insert(std::make_pair(std::string("XAutoRepeatOn"), - std::string("true"))); - #endif - } - */ - #if defined(__APPLE__) && !defined(__LP64__) // Give the application window focus to receive input events ProcessSerialNumber psn = { 0, kCurrentProcess }; @@ -103,9 +60,12 @@ namespace MWInput SetFrontProcess(&psn); #endif + Ogre::RenderWindow* window = ogre.getWindow (); + mInputManager = new MWSDLInputWrapper(window); mInputManager->setMouseEventCallback (this); mInputManager->setKeyboardEventCallback (this); + mInputManager->setWindowEventCallback(this); std::string file = userFileExists ? userFile : ""; mInputCtrl = new ICS::InputControlSystem(file, true, this, NULL, A_Last); @@ -256,6 +216,15 @@ namespace MWInput // event callbacks (which may crash) mWindows.update(); + if(!mDebug) + { + //don't keep the pointer away from the window edge in GUI mode + mInputManager->setWrapPointer(!mWindows.isGuiMode()); + + //we let the mouse escape in the main menu + mInputManager->setGrabPointer(!mWindows.containsMode(MWGui::GM_MainMenu)); + } + // Disable movement in Gui mode if (mWindows.isGuiMode()) return; @@ -510,6 +479,24 @@ namespace MWInput return true; } + bool InputManager::windowFocusChange(bool have_focus) + { + if(!mDebug) + { + + } + return true; + } + + bool InputManager::windowVisibilityChange(bool visible) + { + if(!mDebug) + { + //TODO: Pause game? + } + return true; + } + void InputManager::toggleMainMenu() { if (mWindows.isGuiMode () && (mWindows.getMode () == MWGui::GM_MainMenu || mWindows.getMode () == MWGui::GM_Settings)) diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index df6ce3c434..9a7656a67b 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -55,6 +55,7 @@ namespace MWInput public MWBase::InputManager, public ICS::MWSDLKeyListener, public ICS::MWSDLMouseListener, + public ICS::MWSDLWindowListener, public ICS::ChannelListener, public ICS::DetectingBindingListener { @@ -94,6 +95,9 @@ namespace MWInput virtual bool mouseReleased( const SDL_MouseButtonEvent &arg, Uint8 id ); virtual bool mouseMoved( const ICS::MWSDLMouseMotionEvent &arg ); + virtual bool windowVisibilityChange( bool visible ); + virtual bool windowFocusChange( bool have_focus ); + virtual void channelChanged(ICS::Channel* channel, float currentValue, float previousValue); virtual void mouseAxisBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control @@ -145,6 +149,7 @@ namespace MWInput bool mMouseLookEnabled; bool mGuiCursorEnabled; + bool mDebug; float mMouseX; float mMouseY; diff --git a/apps/openmw/mwinput/sdlinputwrapper.cpp b/apps/openmw/mwinput/sdlinputwrapper.cpp index 61fc3fc8b8..c8922cf3a5 100644 --- a/apps/openmw/mwinput/sdlinputwrapper.cpp +++ b/apps/openmw/mwinput/sdlinputwrapper.cpp @@ -3,6 +3,7 @@ #include #include +#include #if OGRE_PLATFORM == OGRE_PLATFORM_LINUX # include @@ -14,7 +15,11 @@ namespace MWInput { MWSDLInputWrapper::MWSDLInputWrapper(Ogre::RenderWindow *window) : - mWindow(window), mStarted(false), mSDLWindow(NULL) + mWindow(window), + mSDLWindow(NULL), + mWarpCompensate(false), + mWrapPointer(false), + mGrabPointer(false) { _start(); } @@ -26,44 +31,7 @@ namespace MWInput SDL_Quit(); } - void MWSDLInputWrapper::capture() - { - _start(); - - SDL_Event evt; - while(SDL_PollEvent(&evt)) - { - switch(evt.type) - { - case SDL_MOUSEMOTION: - mMouseListener->mouseMoved(ICS::MWSDLMouseMotionEvent(evt.motion)); - break; - case SDL_MOUSEWHEEL: - mMouseListener->mouseMoved(ICS::MWSDLMouseMotionEvent(evt.wheel)); - break; - case SDL_MOUSEBUTTONDOWN: - mMouseListener->mousePressed(evt.button, evt.button.button); - break; - case SDL_MOUSEBUTTONUP: - mMouseListener->mouseReleased(evt.button, evt.button.button); - break; - - case SDL_KEYDOWN: - mKeyboardListener->keyPressed(evt.key); - break; - case SDL_KEYUP: - mKeyboardListener->keyReleased(evt.key); - break; - } - } - } - - bool MWSDLInputWrapper::isModifierHeld(int mod) - { - return SDL_GetModState() & mod; - } - - void MWSDLInputWrapper::_start() + bool MWSDLInputWrapper::_start() { Uint32 flags = SDL_INIT_VIDEO; if(SDL_WasInit(flags) == 0) @@ -74,11 +42,15 @@ namespace MWInput //kindly ask SDL not to trash our OGL context SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software"); - SDL_Init(SDL_INIT_VIDEO); + if(SDL_Init(SDL_INIT_VIDEO) != 0) + return false; //wrap our own event handler around ogre's mSDLWindow = SDL_CreateWindowFrom((void*)windowHnd); + if(mSDLWindow == NULL) + return false; + #if OGRE_PLATFORM == OGRE_PLATFORM_LINUX //linux-specific event-handling fixups SDL_SysWMinfo wm_info; @@ -86,8 +58,6 @@ namespace MWInput if(SDL_GetWindowWMInfo(mSDLWindow,&wm_info)) { - printf("SDL version %d.%d.%d\n", wm_info.version.major, wm_info.version.minor, wm_info.version.patch); - Display* display = wm_info.info.x11.display; Window w = wm_info.info.x11.window; @@ -111,6 +81,122 @@ namespace MWInput XFlush(display); } #endif + SDL_ShowCursor(SDL_FALSE); + } + + return true; + } + + void MWSDLInputWrapper::capture() + { + if(!_start()) + throw std::runtime_error(SDL_GetError()); + + SDL_Event evt; + while(SDL_PollEvent(&evt)) + { + switch(evt.type) + { + case SDL_MOUSEMOTION: + //ignore this if it happened due to a warp + if(!_handleWarpMotion(evt.motion)) + { + mMouseListener->mouseMoved(ICS::MWSDLMouseMotionEvent(evt.motion)); + + //try to keep the mouse inside the window + _wrapMousePointer(evt.motion); + } + break; + case SDL_MOUSEWHEEL: + mMouseListener->mouseMoved(ICS::MWSDLMouseMotionEvent(evt.wheel)); + break; + case SDL_MOUSEBUTTONDOWN: + mMouseListener->mousePressed(evt.button, evt.button.button); + break; + case SDL_MOUSEBUTTONUP: + mMouseListener->mouseReleased(evt.button, evt.button.button); + break; + + case SDL_KEYDOWN: + mKeyboardListener->keyPressed(evt.key); + break; + case SDL_KEYUP: + mKeyboardListener->keyReleased(evt.key); + break; + + case SDL_WINDOWEVENT_FOCUS_GAINED: + mWindowListener->windowFocusChange(true); + break; + case SDL_WINDOWEVENT_FOCUS_LOST: + mWindowListener->windowFocusChange(false); + break; + case SDL_WINDOWEVENT_EXPOSED: + mWindowListener->windowVisibilityChange(true); + break; + case SDL_WINDOWEVENT_HIDDEN: + mWindowListener->windowVisibilityChange(false); + break; + + //SDL traps ^C signals, pass it to OGRE. + case SDL_QUIT: + Ogre::Root::getSingleton().queueEndRendering(); + break; + } + } + } + + bool MWSDLInputWrapper::isModifierHeld(int mod) + { + return SDL_GetModState() & mod; + } + + void MWSDLInputWrapper::warpMouse(int x, int y) + { + SDL_WarpMouseInWindow(mSDLWindow, x, y); + mWarpCompensate = true; + mWarpX = x; + mWarpY = y; + } + + void MWSDLInputWrapper::setGrabPointer(bool grab) + { + SDL_bool sdlGrab = grab ? SDL_TRUE : SDL_FALSE; + + mGrabPointer = grab; + SDL_SetWindowGrab(mSDLWindow, sdlGrab); + } + + bool MWSDLInputWrapper::_handleWarpMotion(const SDL_MouseMotionEvent& evt) + { + if(!mWarpCompensate) return false; + + //this was a warp event, signal the caller to eat it. + if(evt.x == mWarpX && evt.y == mWarpY) + { + mWarpCompensate = false; + return true; + } + + return false; + } + + void MWSDLInputWrapper::_wrapMousePointer(const SDL_MouseMotionEvent& evt) + { + if(!mWrapPointer || !mGrabPointer) return; + + int width = 0; + int height = 0; + + SDL_GetWindowSize(mSDLWindow, &width, &height); + + const int FUDGE_FACTOR_X = width / 4; + const int FUDGE_FACTOR_Y = height / 4; + + //warp the mouse if it's about to go outside the window + if(evt.x - FUDGE_FACTOR_X < 0 || evt.x + FUDGE_FACTOR_X > width + || evt.y - FUDGE_FACTOR_Y < 0 || evt.y + FUDGE_FACTOR_Y > height) + { + warpMouse(width / 2, height / 2); } } } diff --git a/apps/openmw/mwinput/sdlinputwrapper.hpp b/apps/openmw/mwinput/sdlinputwrapper.hpp index ee07efbdb4..d507073b86 100644 --- a/apps/openmw/mwinput/sdlinputwrapper.hpp +++ b/apps/openmw/mwinput/sdlinputwrapper.hpp @@ -16,19 +16,33 @@ namespace MWInput void setMouseEventCallback(ICS::MWSDLMouseListener* listen) { mMouseListener = listen; } void setKeyboardEventCallback(ICS::MWSDLKeyListener* listen) { mKeyboardListener = listen; } + void setWindowEventCallback(ICS::MWSDLWindowListener* listen) { mWindowListener = listen; } void capture(); bool isModifierHeld(int mod); + void setWrapPointer(bool wrap) { mWrapPointer = wrap; } + void setGrabPointer(bool grab); + + void warpMouse(int x, int y); private: + bool _handleWarpMotion(const SDL_MouseMotionEvent& evt); + void _wrapMousePointer(const SDL_MouseMotionEvent &evt); + + bool _start(); + ICS::MWSDLMouseListener* mMouseListener; ICS::MWSDLKeyListener* mKeyboardListener; - Ogre::RenderWindow* mWindow; - SDL_Window* mSDLWindow; + ICS::MWSDLWindowListener* mWindowListener; - bool mStarted; - void _start(); + Uint16 mWarpX; + Uint16 mWarpY; + bool mWarpCompensate; + bool mWrapPointer; + bool mGrabPointer; + Ogre::RenderWindow* mWindow; + SDL_Window* mSDLWindow; }; } diff --git a/extern/oics/OISCompat.h b/extern/oics/OISCompat.h index e8fd6904cb..5813c17bfd 100644 --- a/extern/oics/OISCompat.h +++ b/extern/oics/OISCompat.h @@ -91,5 +91,17 @@ public: virtual bool povMoved( const SDL_JoyHatEvent &arg, int index) {return true;} }; +class MWSDLWindowListener +{ +public: + virtual ~MWSDLWindowListener() {} + + /** @remarks The window's visibility changed */ + virtual bool windowVisibilityChange( bool visible ) = 0; + + /** @remarks The window got / lost input focus */ + virtual bool windowFocusChange( bool have_focus ) = 0; +}; + } #endif