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

Already on GitHub? Sign in to your account

[X11] Mouse.SetPosition does not work when GameWindow.CursorVisible = false #28

Closed
thefiddler opened this Issue Jan 4, 2014 · 6 comments

Comments

Projects
None yet
3 participants
Contributor

thefiddler commented Jan 4, 2014

Separate issue split from: #24 (comment)

In the following code, when the cursor hidden "CursorVisible = false" this is not maintained in the coordinates corresponding to the center of the window.

By contrast, when the cursor is visible "CursorVisible = true" everything works properly and keep the cursor centered in the window.

Using:
Mono 3.2.5
GTK+ 2.24.20
GTK# (2.12.0.0)

I use the installation 'OPT' of (Monodevelop + mono); see http://software.opensuse.org/download/package?project=home:tpokorra:mono&package=monodevelop-opt

using System;
using System.Drawing;
using OpenTK;
using OpenTK.Graphics.OpenGL;
using OpenTK.Input;

namespace Examples.Tutorial
{
/// 
/// Demonstrates the GameWindow class.
/// 

public class SimpleWindow : GameWindow
{
public SimpleWindow() : base(800, 600)
{
   CursorVisible = false;
   Keyboard.KeyDown += Keyboard_KeyDown;
}

    #region Keyboard_KeyDown

    /// <summary>
    /// Occurs when a key is pressed.
    /// </summary>
    /// <param name="sender">The KeyboardDevice which generated this event.</param>
    /// <param name="e">The key that was pressed.</param>
    void Keyboard_KeyDown(object sender, KeyboardKeyEventArgs e)
    {
        if (e.Key == Key.Escape)
            this.Exit();

        if (e.Key == Key.F11)
        if (this.WindowState == WindowState.Fullscreen)
            this.WindowState = WindowState.Normal;
        else
            this.WindowState = WindowState.Fullscreen;
    }

    #endregion

    #region OnLoad

    /// <summary>
    /// Setup OpenGL and load resources here.
    /// </summary>
    /// <param name="e">Not used.</param>
    protected override void OnLoad(EventArgs e)
    {
        GL.ClearColor(Color.MidnightBlue);
    }

    #endregion

    #region OnResize

    /// <summary>
    /// Respond to resize events here.
    /// </summary>
    /// <param name="e">Contains information on the new GameWindow size.</param>
    /// <remarks>There is no need to call the base implementation.</remarks>
    protected override void OnResize(EventArgs e)
    {
        GL.Viewport(0, 0, Width, Height);

        GL.MatrixMode(MatrixMode.Projection);
        GL.LoadIdentity();
        GL.Ortho(-1.0, 1.0, -1.0, 1.0, 0.0, 4.0);
    }

    #endregion

    #region OnUpdateFrame

    /// <summary>
    /// Add your game logic here.
    /// </summary>
    /// <param name="e">Contains timing information.</param>
    /// <remarks>There is no need to call the base implementation.</remarks>
    protected override void OnUpdateFrame(FrameEventArgs e)
    {
        // Nothing to do!
        Point center = new Point(Width / 2, Height / 2);
        Point mousePos = PointToScreen(center);
        OpenTK.Input.Mouse.SetPosition(mousePos.X, mousePos.Y);
    }

    #endregion

    #region OnRenderFrame

    /// <summary>
    /// Add your game rendering code here.
    /// </summary>
    /// <param name="e">Contains timing information.</param>
    /// <remarks>There is no need to call the base implementation.</remarks>
    protected override void OnRenderFrame(FrameEventArgs e)
    {
        Title = "mouseX: " + Mouse.X + " mouseY: " + Mouse.Y;

        GL.Clear(ClearBufferMask.ColorBufferBit);

        GL.Begin(PrimitiveType.Triangles);

        GL.Color3(Color.MidnightBlue);
        GL.Vertex2(-1.0f, 1.0f);
        GL.Color3(Color.SpringGreen);
        GL.Vertex2(0.0f, -1.0f);
        GL.Color3(Color.Ivory);
        GL.Vertex2(1.0f, 1.0f);

        GL.End();

        this.SwapBuffers();
    }

    #endregion

    #region public static void Main()

    /// <summary>
    /// Entry point of this example.
    /// </summary>
    [STAThread]
    public static void Main()
    {
        using (SimpleWindow example = new SimpleWindow())
        {
            // Get the title and category  of this example using reflection.
            //Utilities.SetWindowTitle(example);
            example.Run(30.0, 0.0);
        }
    }

    #endregion
    }
}
Contributor

thefiddler commented Jan 4, 2014

Does this work on Windows or when using the SDL2 backend on Linux?

Setting CursorVisible = false essentially decouples the physical mouse cursor from the position reported by OpenTK. For all intents and purposes, the physical cursor stops existing when hidden. I am not sure if Mouse.SetPosition() can be supported in a cross-platform manner under this condition.

Orthogonal question to this bug report: why are you trying to set the mouse position after hiding the cursor?

migueltk commented Jan 4, 2014

In linux (ubuntu) with both X11 as SDL2 the result is the same, Mouse.SetPosition does not work when GameWindow.CursorVisible = false.
There is another problem (linux - ubuntu) with SDL2 and CursorVisible = true, the cursor is not positioned in the center of the window.

In Windows the result is correct, both CursorVisible = true or false. The cursor is always in the center of the window.

I need this to handle a first-person camera mode, I need the cursor is hidden and this occupies the central position of the window. Small variations in position translate into small rotations of the camera.

Contributor

thefiddler commented Jan 4, 2014

For an FPS, use OpenTK.Input.Mouse.GetState() with CursorVisible = false. No need to center the mouse.

From http://www.opentk.com/doc/input

using OpenTK;
using OpenTK.Input;

Vector3 mouse_delta;
MouseState current, previous;

void UpdateMouse()
{
    current = Mouse.GetState();
    if (current != previous)
    {
        // Mouse state has changed
        mouse_delta = new Vector3(
           current.X - previous.X,
           current.Y - previous.Y,
           current.WheelPrecise - previous.WheelPrecise);
    }
    else
    {
        mouse_delta = Vector3.Zero;
    }
    previous = current;
}

Mouse.SetPosition should only be used for UI purposes, not for real-time input. Mac OS X, specifically, adds a 500ms delay between SetPosition and sending new mouse events, presumably to protect against malware hijacking your mouse.

This is orthogonal to the present bug report.

migueltk commented Jan 4, 2014

Thanks for the reply, this solves my problem

@thefiddler thefiddler added a commit that referenced this issue May 14, 2014

@thefiddler thefiddler [X11] Improved CursorVisible = false behavior
We now use an XGrabPointer to confine the cursor to the window,
instead of the XWarpPointer hack. Fixes issue #28 and #36.
a30af54
Contributor

thefiddler commented May 19, 2014

Fixed via #120

@thefiddler thefiddler closed this May 19, 2014

Contributor

Phyyl commented Nov 22, 2016

I would like to point out that

For an FPS, use OpenTK.Input.Mouse.GetState() with CursorVisible = false

Does not work on mac with an external mouse. The trackpad works fine, but the external mouse does not change the reported position from OpenTK.Input.Mouse.GetState().

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment