opengl - Fokus på MouseOver i Windows med Ogre3D

Indlæg af Hanne Mølgaard Plasc

Problem



Jeg har en applikation, der bruger Ogre3D til at oprette flere render windows, og jeg bruger løsningen, der er indsendt her for at understøtte ikke-eksklusiv musindgang til disse vinduer. Jeg finder imidlertid, at jeg fysisk skal klikke på et renderingsvindue, før det genvinder fokus, mens jeg virkelig ligner, at render windows får fokus på en mouseover-begivenhed. Er det muligt at indfange en mouseover-begivenhed på et ufokuseret renderingsvindue i Ogre3D/OIS og derefter sætte fokus for rendervinduet?

Bedste reference


For at understøtte denne form for funktionalitet ved hjælp af Ogre3D i Windows, var jeg nødt til at implementere et singleton objekt, der holdt en samling af alle de 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


Derefter transformerer jeg i my UIFrameListener (som kommer fra Ogre3Ds EksempelFrameListener) musekoordinaterne til globale skærmkoordinater. Hvis musen opholder sig udenfor vinduesområdet, anvender jeg den relative mus bevægelse til den sidst optagne musposition ellers bruger jeg simpelthen den absolutte musposition i vinduet:


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


Og i InputProcessor::processMouseMoved() bestemmer jeg hvilket vindue musemarkøren er i (hvis nogen), og sæt derefter fokuset korrekt, dvs.


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


Og i implementeringen af ​​Display har jeg en metode Display::setFocus(), der sætter fokus på det relevante vindue:


void
Display::setFocus(bool \_hasFocus)
{
    if (m\_handle != NULL && \_hasFocus)
    {
        SetFocus(m\_handle);
    }
}