У меня есть приложение, использующее Ogre3D для создания нескольких окон рендеринга, и я использую решение, опубликованное здесь, для поддержки не- эксклюзивный ввод мыши в эти окна. Однако я обнаружил, что мне нужно физически щелкнуть окно рендеринга, прежде чем оно восстановит фокус, тогда как мне бы очень хотелось, чтобы окна рендеринга получали фокус на событии наведения мыши. Можно ли в Ogre3D/OIS зафиксировать событие наведения курсора мыши на несфокусированном окне рендеринга, а затем установить фокус для окна рендеринга?
Сосредоточьтесь на MouseOver в Windows с помощью Ogre3D
Ответы (1)
Чтобы поддерживать такую функциональность с помощью Ogre3D в Windows, мне пришлось реализовать объект-одиночку, который хранил коллекцию всех созданных дисплеев.
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
Затем в моем UIFrameListener (который является производным от ExampleFrameListener Ogre3D) я преобразовываю координаты окна мыши в глобальные экранные координаты. Если мышь оказывается за пределами области окна, я применяю относительное движение мыши к последней записанной позиции мыши; в противном случае я просто применяю абсолютную позицию мыши в окне:
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);
}
А в InputProcessor::processMouseMoved()
я определяю, в каком окне находится курсор мыши (если он есть), а затем соответствующим образом устанавливаю фокус, т.е.
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;
}
А в реализации Display
у меня есть метод Display::setFocus()
, который устанавливает фокус на соответствующее окно:
void
Display::setFocus(bool _hasFocus)
{
if (m_handle != NULL && _hasFocus)
{
SetFocus(m_handle);
}
}