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