Hi All,
I've been using Ogre for a while in conjunction with OIS and CEGUI, but haven't really needed to tamper with OIS too much till now..
Our Win32 application operates primarily with the mouse in non-exclusive mode, but when the user clicks and drags on the viewport we want to change to exclusive mode to allow them to pan the scene. I do this by completely destroying the input manager and re-creating one in the mode I want to change to.. (I haven't been able to find a way to simply change the mode for your already-initialized input manager???).
Previously I used the F1 key to toggle modes, and I think this got around a couple of problems due only to luck... now I've changed to holding down the left mouse button to toggle modes, it's all falling apart. I've had the following two problems (and associated theories on why they occur):
Crash on mMouse->capture();
First off, I've made the blind assumption that there's a separate OIS thread, and have only just questioned that now.. that is the case isn't it?
Anyway, in the mousePressed() callback I was detecting the LMB going down over the viewport, then destroying and re-creating the input manager in exclusive mode before exiting the callback. This seemed to work okay at first, but every so-often I'd get a random crash under mMouse->capture(); in my main render loop (which I call at the start of each frame). I assumed this was because the OIS thread was destroying the mouse while the Render thread was trying to capture() it..
To fix this, I first tried wrapping the relevant OIS sections of code in a mutex, which failed to solve the problem.. <confusion>..
Then I changed it so the mousePressed() callback just set a flag requesting the input manager get destroyed and re-created, and the actual destruction/creation was done in the Render thread just after mMouse->capture(); had been called. This seemed to work fine, until I noticed issue 2:
Application still has exclusive access to the mouse in non-exclusive mode?!?!
After I've toggled between non-exclusive and exclusive mode, then back again, (so I should be in non-exclusive mode now), if I click on another application the other application doesn't get my click, and instead my Ogre application gets the click! (with the mouse not over the Ogre window at the time).
I suspect this might just be to do with destroying the input manager while the GUI thread (if one exists) is handling mouse events, and maybe the only reason it was ever working in the first place (back when I was using [F1] to toggle) is because the OIS thread was specifically not handling mouse events at the time (as it was handling a keyboard event). If this assumption is correct, then my problem is that I have no way to know when the OIS thread's *not* processing a mouse event...
By the way, I still get this same problem if I do the destruction/creation in the mousePressed() callback rather than in the Render thread.
ANY thoughts on what I can do to get the desired interaction would be most appreciated.
Here's the code I'm using:
//---------------------------------------------------------------------
AirwayFrameListener::AirwayFrameListener( ... )
{
initGUIInput(false); //false == non-exclusive
}
//---------------------------------------------------------------------
bool AirwayFrameListener::mousePressed(const OIS::MouseEvent& evt, OIS::MouseButtonID id)
{
if( it's the LMB and it's over the viewport )
{
mViewportEngagedDesired = true;
}
else
{
...
}
return true;
}
//---------------------------------------------------------------------
bool AirwayFrameListener::mouseReleased(const OIS::MouseEvent& evt, OIS::MouseButtonID id)
{
if( it's the LMB and the viewport's engaged )
{
mViewportEngagedDesired = false;
}
else
{
...
}
return true;
}
//---------------------------------------------------------------------
bool AirwayFrameListener::frameStarted(const FrameEvent& evt)
{
if(mMouse) mMouse->capture();
if(mKeyboard) mKeyboard->capture();
//Check "viewport engaged" state - this is done here rather than when mViewportEngagedDesired
// was set to avoid threading issues and crashes in the "if(mMouse) mMouse->capture();" line above.
if(mViewportEngagedDesired != mViewportEngaged)
{
mViewportEngaged = mViewportEngagedDesired;
uninitGUIInput();
initGUIInput(mViewportEngaged);
}
...
}
//---------------------------------------------------------------------
void AirwayFrameListener::initGUIInput(bool exclusive)
{
using namespace OIS;
ParamList pl;
size_t windowHnd = 0;
std::ostringstream windowHndStr;
mWindow->getCustomAttribute("WINDOW", &windowHnd);
windowHndStr << windowHnd;
pl.insert(std::make_pair(std::string("WINDOW"), windowHndStr.str()));
if(!exclusive)
{
//Setup OIS in non-exclusive mode
#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
}
mInputManager = InputManager::createInputSystem(pl);
//Create devices
mMouse = static_cast<Mouse*>(mInputManager->createInputObject( OISMouse, true ));
mMouse->setEventCallback(this);
mKeyboard = static_cast<Keyboard*>(mInputManager->createInputObject( OISKeyboard, true ));
mKeyboard->setEventCallback(this);
//Set initial mouse clipping size
windowResized(mWindow);
}
//---------------------------------------------------------------------
void AirwayFrameListener::uninitGUIInput()
{
using namespace OIS;
if(mInputManager)
{
mInputManager->destroyInputObject( mMouse ); mMouse = NULL;
mInputManager->destroyInputObject( mKeyboard ); mKeyboard = NULL;
InputManager::destroyInputSystem(mInputManager); mInputManager = NULL;
}
}
//---------------------------------------------------------------------