1
0
Fork 1
mirror of https://github.com/TES3MP/openmw-tes3mp.git synced 2025-01-29 02:45:32 +00:00
openmw-tes3mp/apps/openmw/mwinput/sdlinputwrapper.cpp
Jordan Milne 02ccb75894 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
2013-01-09 06:10:05 -04:00

202 lines
6.1 KiB
C++

#include "sdlinputwrapper.hpp"
#include <SDL2/SDL.h>
#include <SDL2/SDL_syswm.h>
#include <OgrePlatform.h>
#include <OgreRoot.h>
#if OGRE_PLATFORM == OGRE_PLATFORM_LINUX
# include <X11/Xlib.h>
# include <X11/Xutil.h>
# include <X11/Xos.h>
#endif
namespace MWInput
{
MWSDLInputWrapper::MWSDLInputWrapper(Ogre::RenderWindow *window) :
mWindow(window),
mSDLWindow(NULL),
mWarpCompensate(false),
mWrapPointer(false),
mGrabPointer(false)
{
_start();
}
MWSDLInputWrapper::~MWSDLInputWrapper()
{
SDL_DestroyWindow(mSDLWindow);
mSDLWindow = NULL;
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()
{
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);
}
}
}