Wrap the mouse to the window (except in debug mode)

Grab the mouse when not in the main menu (except in debug mode)
Always hide the cursor when it's over the window
Allow warping the mouse around
Handle ^C properly
actorid
Jordan Milne 12 years ago
parent 1bf36c686c
commit 02ccb75894

@ -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))

@ -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;

@ -3,6 +3,7 @@
#include <SDL2/SDL_syswm.h>
#include <OgrePlatform.h>
#include <OgreRoot.h>
#if OGRE_PLATFORM == OGRE_PLATFORM_LINUX
# include <X11/Xlib.h>
@ -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);
}
}
}

@ -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;
};
}

@ -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

Loading…
Cancel
Save