Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Mouse::setPosition is slow on OS X #290

Closed
mantognini opened this Issue · 5 comments

3 participants

@mantognini
Collaborator

Reported on the french forum, here.

Code reproducing the issue

#include <iostream>
#include <SFML/Graphics.hpp>

using namespace std;
using namespace sf;

int main(int argc, char *argv[])
{
    RenderWindow window(VideoMode(200, 200), "SFML works!");

    while(window.isOpen())
    {
        Event event;
        while(window.pollEvent(event))
        {
            switch(event.type)
            {
                case Event::Closed:
                    window.close();
                    break;
                case Event::KeyReleased:
                    switch(event.key.code)
                    {
                        case Keyboard::Escape:
                            window.close();
                            break;
                        default:
                            break;
                    }
                    break;
                default:
                    break;
                case Event::MouseMoved:
                    int current_x = Mouse::getPosition(window).x, current_y = Mouse::getPosition(window).y;
                    int elapsed_x = 100 - current_x, elapsed_y = 100 - current_y;

                    if(elapsed_x != 0 || elapsed_y != 0)
                    {
                        cout << elapsed_x << "-" << elapsed_y << endl;
                        Mouse::setPosition(Vector2i(100, 100), window);
                    }
                    break;
            }
        }

        window.clear();

        window.display();
    }

    return 0;
}

Expected

Lots of console output per second.

Current behaviour

~4 output per second only.

Info

Tested on Mountain Lion 10.8.2 (12C54) and Lion

Somehow related to #46

@mantognini mantognini was assigned
@ryanfields

As far as I can tell, SFML does not currently offer support for locking the mouse cursor and reading relative movement. It's not just that it doesn't work in OS X, but that there's absolutely no support for mouse locking within SFML's feature set.

The approach above will never work, even if the delay is removed, because the mouse can be moved so fast that acceleration will carry it right outside of the window and mouse events will stop being received. Trying to catch that case with Event::MouseLeft will seem like a sensible fix, but it won't actually work.

sf::Window needs a new style called sf::Style::LockMouse and a mouse-locking implementation at the Window level written for all supported platforms. Or, if you want to be able to grab and release the mouse, then we need methods on sf::Window to grab and release the mouse.

As for implementing it on OS X, it's fairly simple but is tricky to fit into SFML's event loop.

To lock the mouse, simply:

    /* Mouse::setPosition has to be called anytime the window moves, otherwise
     * clicking will cause the window to lose focus.  The locked cursor will be
     * sitting right where we left it, but now the window will be somewhere else
     * and whatever was under it (desktop, other window, etc.) gets the click.
     */
    Mouse::setPosition(Vector2i(0, 0), window);

    // Is there an SFML call to hide the mouse?
    CGDisplayHideCursor(kCGDirectMainDisplay);

    /* Disconnect the mouse from the cursor.  Mouse movements happen,
     * but no longer update the cursor location.
     */
    CGAssociateMouseAndMouseCursorPosition(FALSE);

    Vector2i mouseLastPos;
    Vector2i mousePos;

    while(/* some looping condition */) {
        CGGetLastMouseDelta(&mousePos.x, &mousePos.y);
        if (mouseLastPos != mousePos) {

            // If delta was not just a re-centering event...
            if (mousePos.x != 0 || mousePos.y != 0) {
                postAnSfmlMouseMovedEvent(mousePos.x, mousePos.y);
                cout << mousePos.x << ", " << mousePos.y << std::endl;
            }

            mouseLastPos = mousePos;
        }
    }

So all of the code before the loop needs to happen inside SFML's OS X window implementation. I imagine the user would access mouse locking with something like the following:

    sf::Window window(VideoMode(500, 500), "Mouse Locker", sf::Style::LockMouse);

    // Or...

    window.lockMouse();

And then in the main event loop, somehow SFML would need to perform the chunk of code in the loop above. Maybe on a separate thread? Can SFML post messages from other threads back into the main thread? What needs to happen is that some loop somewhere is constantly looking at CGGetLastMouseDelta. Anytime the delta changes and is NOT a (0, 0) event, SFML needs to send out a sf::Event::MouseMoved with the relative coordinates received from CGGetLastMouseDelta.

Doing this will eliminate the delay issue and will make it impossible for the mouse cursor to ever escape the window.

It's not a quick and easy change, unfortunately. It's a new feature. This is the only way SFML is going to get a working mouse-lock implementation though.

@mantognini
Collaborator

It's a new feature.

So it should be asked on the forum. ;-)

@ryanfields

Probably. I'm not the one who raised it as an issue. Just took a stab at resolving it and came to the above conclusion.

@mantognini
Collaborator

I just tested it on 10.5 and I didn't experienced any slowdown. It looks like an OS regression..

Could someone with 10.6 and/or 10.7 could test it ?

@posva

I tested it under 10.6.8 and it doesn't work. You can get out of the window and you only get a few outputs per second

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.