Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mouse::setPosition is slow on OS X #290

Closed
mantognini opened this issue Oct 1, 2012 · 5 comments
Closed

Mouse::setPosition is slow on OS X #290

mantognini opened this issue Oct 1, 2012 · 5 comments

Comments

@mantognini
Copy link
Member

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

@ghost ghost assigned mantognini Oct 1, 2012
@beverlycodes
Copy link
Contributor

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
Copy link
Member Author

It's a new feature.

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

@beverlycodes
Copy link
Contributor

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
Copy link
Member Author

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
Copy link

posva commented Feb 24, 2013

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

@mantognini mantognini removed their assignment Apr 30, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants