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) , mUserFile(userFile)
, mDragDrop(false) , mDragDrop(false)
, mGuiCursorEnabled(false) , mGuiCursorEnabled(false)
, mDebug(debug)
, mInvertY (Settings::Manager::getBool("invert y axis", "Input")) , mInvertY (Settings::Manager::getBool("invert y axis", "Input"))
, mCameraSensitivity (Settings::Manager::getFloat("camera sensitivity", "Input")) , mCameraSensitivity (Settings::Manager::getFloat("camera sensitivity", "Input"))
, mUISensitivity (Settings::Manager::getFloat("ui sensitivity", "Input")) , mUISensitivity (Settings::Manager::getFloat("ui sensitivity", "Input"))
@ -52,50 +53,6 @@ namespace MWInput
, mPreviewPOVDelay(0.f) , mPreviewPOVDelay(0.f)
, mTimeIdle(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__) #if defined(__APPLE__) && !defined(__LP64__)
// Give the application window focus to receive input events // Give the application window focus to receive input events
ProcessSerialNumber psn = { 0, kCurrentProcess }; ProcessSerialNumber psn = { 0, kCurrentProcess };
@ -103,9 +60,12 @@ namespace MWInput
SetFrontProcess(&psn); SetFrontProcess(&psn);
#endif #endif
Ogre::RenderWindow* window = ogre.getWindow ();
mInputManager = new MWSDLInputWrapper(window); mInputManager = new MWSDLInputWrapper(window);
mInputManager->setMouseEventCallback (this); mInputManager->setMouseEventCallback (this);
mInputManager->setKeyboardEventCallback (this); mInputManager->setKeyboardEventCallback (this);
mInputManager->setWindowEventCallback(this);
std::string file = userFileExists ? userFile : ""; std::string file = userFileExists ? userFile : "";
mInputCtrl = new ICS::InputControlSystem(file, true, this, NULL, A_Last); mInputCtrl = new ICS::InputControlSystem(file, true, this, NULL, A_Last);
@ -256,6 +216,15 @@ namespace MWInput
// event callbacks (which may crash) // event callbacks (which may crash)
mWindows.update(); 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 // Disable movement in Gui mode
if (mWindows.isGuiMode()) return; if (mWindows.isGuiMode()) return;
@ -510,6 +479,24 @@ namespace MWInput
return true; 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() void InputManager::toggleMainMenu()
{ {
if (mWindows.isGuiMode () && (mWindows.getMode () == MWGui::GM_MainMenu || mWindows.getMode () == MWGui::GM_Settings)) if (mWindows.isGuiMode () && (mWindows.getMode () == MWGui::GM_MainMenu || mWindows.getMode () == MWGui::GM_Settings))

@ -55,6 +55,7 @@ namespace MWInput
public MWBase::InputManager, public MWBase::InputManager,
public ICS::MWSDLKeyListener, public ICS::MWSDLKeyListener,
public ICS::MWSDLMouseListener, public ICS::MWSDLMouseListener,
public ICS::MWSDLWindowListener,
public ICS::ChannelListener, public ICS::ChannelListener,
public ICS::DetectingBindingListener public ICS::DetectingBindingListener
{ {
@ -94,6 +95,9 @@ namespace MWInput
virtual bool mouseReleased( const SDL_MouseButtonEvent &arg, Uint8 id ); virtual bool mouseReleased( const SDL_MouseButtonEvent &arg, Uint8 id );
virtual bool mouseMoved( const ICS::MWSDLMouseMotionEvent &arg ); 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 channelChanged(ICS::Channel* channel, float currentValue, float previousValue);
virtual void mouseAxisBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control virtual void mouseAxisBindingDetected(ICS::InputControlSystem* ICS, ICS::Control* control
@ -145,6 +149,7 @@ namespace MWInput
bool mMouseLookEnabled; bool mMouseLookEnabled;
bool mGuiCursorEnabled; bool mGuiCursorEnabled;
bool mDebug;
float mMouseX; float mMouseX;
float mMouseY; float mMouseY;

@ -3,6 +3,7 @@
#include <SDL2/SDL_syswm.h> #include <SDL2/SDL_syswm.h>
#include <OgrePlatform.h> #include <OgrePlatform.h>
#include <OgreRoot.h>
#if OGRE_PLATFORM == OGRE_PLATFORM_LINUX #if OGRE_PLATFORM == OGRE_PLATFORM_LINUX
# include <X11/Xlib.h> # include <X11/Xlib.h>
@ -14,7 +15,11 @@
namespace MWInput namespace MWInput
{ {
MWSDLInputWrapper::MWSDLInputWrapper(Ogre::RenderWindow *window) : MWSDLInputWrapper::MWSDLInputWrapper(Ogre::RenderWindow *window) :
mWindow(window), mStarted(false), mSDLWindow(NULL) mWindow(window),
mSDLWindow(NULL),
mWarpCompensate(false),
mWrapPointer(false),
mGrabPointer(false)
{ {
_start(); _start();
} }
@ -26,9 +31,66 @@ namespace MWInput
SDL_Quit(); 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() void MWSDLInputWrapper::capture()
{ {
_start(); if(!_start())
throw std::runtime_error(SDL_GetError());
SDL_Event evt; SDL_Event evt;
while(SDL_PollEvent(&evt)) while(SDL_PollEvent(&evt))
@ -36,7 +98,14 @@ namespace MWInput
switch(evt.type) switch(evt.type)
{ {
case SDL_MOUSEMOTION: case SDL_MOUSEMOTION:
//ignore this if it happened due to a warp
if(!_handleWarpMotion(evt.motion))
{
mMouseListener->mouseMoved(ICS::MWSDLMouseMotionEvent(evt.motion)); mMouseListener->mouseMoved(ICS::MWSDLMouseMotionEvent(evt.motion));
//try to keep the mouse inside the window
_wrapMousePointer(evt.motion);
}
break; break;
case SDL_MOUSEWHEEL: case SDL_MOUSEWHEEL:
mMouseListener->mouseMoved(ICS::MWSDLMouseMotionEvent(evt.wheel)); mMouseListener->mouseMoved(ICS::MWSDLMouseMotionEvent(evt.wheel));
@ -54,6 +123,24 @@ namespace MWInput
case SDL_KEYUP: case SDL_KEYUP:
mKeyboardListener->keyReleased(evt.key); mKeyboardListener->keyReleased(evt.key);
break; 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; return SDL_GetModState() & mod;
} }
void MWSDLInputWrapper::_start() void MWSDLInputWrapper::warpMouse(int x, int y)
{ {
Uint32 flags = SDL_INIT_VIDEO; SDL_WarpMouseInWindow(mSDLWindow, x, y);
if(SDL_WasInit(flags) == 0) mWarpCompensate = true;
mWarpX = x;
mWarpY = y;
}
void MWSDLInputWrapper::setGrabPointer(bool grab)
{ {
//get the HWND from ogre's renderwindow SDL_bool sdlGrab = grab ? SDL_TRUE : SDL_FALSE;
size_t windowHnd;
mWindow->getCustomAttribute("WINDOW", &windowHnd);
//kindly ask SDL not to trash our OGL context mGrabPointer = grab;
SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software"); SDL_SetWindowGrab(mSDLWindow, sdlGrab);
SDL_Init(SDL_INIT_VIDEO); }
//wrap our own event handler around ogre's bool MWSDLInputWrapper::_handleWarpMotion(const SDL_MouseMotionEvent& evt)
mSDLWindow = SDL_CreateWindowFrom((void*)windowHnd); {
if(!mWarpCompensate) return false;
#if OGRE_PLATFORM == OGRE_PLATFORM_LINUX //this was a warp event, signal the caller to eat it.
//linux-specific event-handling fixups if(evt.x == mWarpX && evt.y == mWarpY)
SDL_SysWMinfo wm_info; {
SDL_VERSION(&wm_info.version); 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; int width = 0;
Window w = wm_info.info.x11.window; int height = 0;
// Set the input hints so we get keyboard input SDL_GetWindowSize(mSDLWindow, &width, &height);
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 const int FUDGE_FACTOR_X = width / 4;
XSelectInput(display, w, const int FUDGE_FACTOR_Y = height / 4;
(FocusChangeMask | EnterWindowMask | LeaveWindowMask |
ExposureMask | ButtonPressMask | ButtonReleaseMask |
PointerMotionMask | KeyPressMask | KeyReleaseMask |
PropertyChangeMask | StructureNotifyMask |
KeymapStateMask));
XFlush(display); //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
#endif || 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 setMouseEventCallback(ICS::MWSDLMouseListener* listen) { mMouseListener = listen; }
void setKeyboardEventCallback(ICS::MWSDLKeyListener* listen) { mKeyboardListener = listen; } void setKeyboardEventCallback(ICS::MWSDLKeyListener* listen) { mKeyboardListener = listen; }
void setWindowEventCallback(ICS::MWSDLWindowListener* listen) { mWindowListener = listen; }
void capture(); void capture();
bool isModifierHeld(int mod); bool isModifierHeld(int mod);
void setWrapPointer(bool wrap) { mWrapPointer = wrap; }
void setGrabPointer(bool grab);
void warpMouse(int x, int y);
private: private:
bool _handleWarpMotion(const SDL_MouseMotionEvent& evt);
void _wrapMousePointer(const SDL_MouseMotionEvent &evt);
bool _start();
ICS::MWSDLMouseListener* mMouseListener; ICS::MWSDLMouseListener* mMouseListener;
ICS::MWSDLKeyListener* mKeyboardListener; ICS::MWSDLKeyListener* mKeyboardListener;
Ogre::RenderWindow* mWindow; ICS::MWSDLWindowListener* mWindowListener;
SDL_Window* mSDLWindow;
bool mStarted; Uint16 mWarpX;
void _start(); 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;} 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 #endif

Loading…
Cancel
Save