mirror of
https://github.com/TES3MP/openmw-tes3mp.git
synced 2025-01-29 02:45:32 +00:00
02ccb75894
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
202 lines
6.1 KiB
C++
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);
|
|
}
|
|
}
|
|
}
|