Сосредоточьтесь на MouseOver в Windows с Ogre3D - PullRequest
1 голос
/ 07 марта 2012

У меня есть приложение, использующее Ogre3D для создания нескольких окон рендеринга, и я использую решение, размещенное здесь , для поддержки неисключительного ввода с помощью мыши этих окон. Тем не менее, я обнаружил, что мне нужно физически щелкнуть окно рендеринга, прежде чем оно восстановит фокус, тогда как мне бы очень хотелось, чтобы окна рендеринга фокусировались на событии при наведении курсора мыши. Можно ли захватить событие наведения мыши на не сфокусированном окне рендеринга в Ogre3D / OIS, а затем впоследствии установить фокус для окна рендеринга?

1 Ответ

0 голосов
/ 08 августа 2012

Для поддержки такого рода функциональности с использованием 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);
    }
}
...