I have an application using the Ogre3D to create multiple render windows, and I'm using the solution posted here to support non-exclusive mouse input to these windows. However, I find that I have to physically click on a render window before it regains focus, whereas I'd really like the render windows to gain focus on a mouseover event. Is it possible to capture a mouseover event on an unfocused render window in Ogre3D/OIS and then subsequently set the focus for the render window?
-
1Be advised that in many window managers, gaining focus also means bringing the window to the font. Such behavior will likely be very... unusual for users who are used to their window manager. – Nicol Bolas Mar 06 '12 at 23:19
-
Duly noted -- in my particular application, the windows are tiled and have static positions, and the behavior you are suggesting is actually desired... – hatboyzero Mar 07 '12 at 02:39
-
If that's true, why are they windows at all? Can't you just render to separate tiled viewports? – Nicol Bolas Mar 07 '12 at 02:47
-
1If I was dealing with a single monitor, handling it as tiled viewports in a fullscreen render window would be the ideal approach, yes. However, I'm dealing with six monitors, and I need to be able to interact with the render windows on each -- so far, the best way I've found to do this is to use borderless windows the size of each monitor with the mouse configured for non-exclusive mode -- unfortunately, this requires clicking on a particular render window before UI elements in it respond to mouseover events... – hatboyzero Mar 07 '12 at 03:19
-
1Do you have any way to get leave/enter events for the windows? If you hook those up to focusing it should do the trick. I don't think Ogre or OIS provide that though, so you'll need to go one level deeper depending on your OS... – LiMuBei Jun 28 '12 at 07:33
1 Answers
To support this kind of functionality using Ogre3D in Windows, I had to implement a singleton object that kept a collection of all of the instantiated displays.
class InputProcessor
{
/// @name Types
/// @{
public:
/// @}
/// @name InputProcessor implementation
/// @{
public:
void addDisplay(Display* _pDisplay);
bool processMouseMoved(int _x, int _y, int _z, int _keyModifier);
bool processMousePressed(int _keyModifier, int _id);
bool processMouseReleased(int _keyModifier, int _id);
static InputProcessor& getSingleton();
/// @}
/// @name 'Structors
/// @{
private:
InputProcessor();
~InputProcessor();
/// @}
/// @name Member Variables
/// @{
private:
typedef std::set<Display*> Displays_type;
Displays_type m_displays;
/// @}
}; // class InputProcessor
Then, in my UIFrameListener (which derives from Ogre3D's ExampleFrameListener), I transform the mouse window coordinates to global screen coordinates. If the mouse happens to reside outside of the window region, I apply the relative mouse movement to the last recorded mouse position; otherwise, I simply apply the absolute mouse position within the window:
bool
UIFrameListener::mouseMoved(const OIS::MouseEvent& e)
{
int keyModifierState = GetKeyModifierState();
int windowLeft = m_display.getLeft();
int windowTop = m_display.getTop();
int windowWidth = m_display.m_pWindow->getWidth();
int windowHeight = m_display.m_pWindow->getHeight();
if (e.state.X.abs != 0 && e.state.X.abs != windowWidth)
{
m_lastX = e.state.X.abs;
}
else
{
m_lastX += e.state.X.rel;
}
int x = windowLeft + (m_display.m_width * m_lastX) / windowWidth;
if (e.state.Y.abs != 0 && e.state.Y.abs != windowHeight)
{
m_lastY = e.state.Y.abs;
}
else
{
m_lastY += e.state.Y.rel;
}
int y = windowTop + (m_display.m_height * m_lastY) / windowHeight;
int z = 0;
if (e.state.Z.rel != 0)
{
z = e.state.Z.rel / -120;
}
return InputProcessor::getSingleton().processMouseMoved(x, y, z, keyModifierState);
}
And in InputProcessor::processMouseMoved()
, I determine which window the mouse cursor is in (if any), and then set the focus appropriately, i.e.
bool
InputProcessor::processMouseMoved(int _x,
int _y,
int _z,
int _keyModifier)
{
bool found = false;
Displays_type::iterator iter = m_displays.begin();
while (iter != m_displays.end() && !found)
{
int left = (*iter)->getLeft();
int top = (*iter)->getTop();
int width = (*iter)->m_pWindow->getWidth();
int height = (*iter)->m_pWindow->getHeight();
if (left <= _x && left + width > _x &&
top <= _y && top + height > _y)
{
found = true;
}
else
{
iter++;
}
}
if (iter != m_displays.end())
{
int left = (*iter)->getLeft();
int top = (*iter)->getTop();
(*iter)->m_pContext->ProcessMouseMove(
_x - left, _y - top, _keyModifier
);
(*iter)->m_pContext->ProcessMouseWheel(_z, _keyModifier);
if (!(*iter)->hasFocus())
{
(*iter)->setFocus(true);
}
}
return true;
}
And in the implementation of Display
, I have a method Display::setFocus()
that sets the focus on the appropriate window:
void
Display::setFocus(bool _hasFocus)
{
if (m_handle != NULL && _hasFocus)
{
SetFocus(m_handle);
}
}

- 1,929
- 1
- 21
- 44