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
pull/16/head
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,9 +31,66 @@ namespace MWInput
SDL_Quit();
}
bool MWSDLInputWrapper::_start()
{
Uint32 flags = SDL_INIT_VIDEO;
if(SDL_WasInit(flags) == 0)
{
//get the HWND from ogre's renderwindow
size_t windowHnd;
mWindow->getCustomAttribute("WINDOW", &windowHnd);
//kindly ask SDL not to trash our OGL context
SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software");
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;
SDL_VERSION(&wm_info.version);
if(SDL_GetWindowWMInfo(mSDLWindow,&wm_info))
{
Display* display = wm_info.info.x11.display;
Window w = wm_info.info.x11.window;
// Set the input hints so we get keyboard input
XWMHints *wmhints = XAllocWMHints();
if (wmhints) {
wmhints->input = True;
wmhints->flags = InputHint;
XSetWMHints(display, w, wmhints);
XFree(wmhints);
}
//make sure to subscribe to XLib's events
XSelectInput(display, w,
(FocusChangeMask | EnterWindowMask | LeaveWindowMask |
ExposureMask | ButtonPressMask | ButtonReleaseMask |
PointerMotionMask | KeyPressMask | KeyReleaseMask |
PropertyChangeMask | StructureNotifyMask |
KeymapStateMask));
XFlush(display);
}
#endif
SDL_ShowCursor(SDL_FALSE);
}
return true;
}
void MWSDLInputWrapper::capture()
{
_start();
if(!_start())
throw std::runtime_error(SDL_GetError());
SDL_Event evt;
while(SDL_PollEvent(&evt))
@ -36,7 +98,14 @@ namespace MWInput
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));
@ -54,6 +123,24 @@ namespace MWInput
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;
}
}
}
@ -63,54 +150,53 @@ namespace MWInput
return SDL_GetModState() & mod;
}
void MWSDLInputWrapper::_start()
void MWSDLInputWrapper::warpMouse(int x, int y)
{
Uint32 flags = SDL_INIT_VIDEO;
if(SDL_WasInit(flags) == 0)
SDL_WarpMouseInWindow(mSDLWindow, x, y);
mWarpCompensate = true;
mWarpX = x;
mWarpY = y;
}
void MWSDLInputWrapper::setGrabPointer(bool grab)
{
//get the HWND from ogre's renderwindow
size_t windowHnd;
mWindow->getCustomAttribute("WINDOW", &windowHnd);
SDL_bool sdlGrab = grab ? SDL_TRUE : SDL_FALSE;
//kindly ask SDL not to trash our OGL context
SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software");
SDL_Init(SDL_INIT_VIDEO);
mGrabPointer = grab;
SDL_SetWindowGrab(mSDLWindow, sdlGrab);
}
//wrap our own event handler around ogre's
mSDLWindow = SDL_CreateWindowFrom((void*)windowHnd);
bool MWSDLInputWrapper::_handleWarpMotion(const SDL_MouseMotionEvent& evt)
{
if(!mWarpCompensate) return false;
#if OGRE_PLATFORM == OGRE_PLATFORM_LINUX
//linux-specific event-handling fixups
SDL_SysWMinfo wm_info;
SDL_VERSION(&wm_info.version);
//this was a warp event, signal the caller to eat it.
if(evt.x == mWarpX && evt.y == mWarpY)
{
mWarpCompensate = false;
return true;
}
if(SDL_GetWindowWMInfo(mSDLWindow,&wm_info))
return false;
}
void MWSDLInputWrapper::_wrapMousePointer(const SDL_MouseMotionEvent& evt)
{
printf("SDL version %d.%d.%d\n", wm_info.version.major, wm_info.version.minor, wm_info.version.patch);
if(!mWrapPointer || !mGrabPointer) return;
Display* display = wm_info.info.x11.display;
Window w = wm_info.info.x11.window;
int width = 0;
int height = 0;
// Set the input hints so we get keyboard input
XWMHints *wmhints = XAllocWMHints();
if (wmhints) {
wmhints->input = True;
wmhints->flags = InputHint;
XSetWMHints(display, w, wmhints);
XFree(wmhints);
}
SDL_GetWindowSize(mSDLWindow, &width, &height);
//make sure to subscribe to XLib's events
XSelectInput(display, w,
(FocusChangeMask | EnterWindowMask | LeaveWindowMask |
ExposureMask | ButtonPressMask | ButtonReleaseMask |
PointerMotionMask | KeyPressMask | KeyReleaseMask |
PropertyChangeMask | StructureNotifyMask |
KeymapStateMask));
const int FUDGE_FACTOR_X = width / 4;
const int FUDGE_FACTOR_Y = height / 4;
XFlush(display);
}
#endif
//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