Sunday, August 22, 2010

Howto: Hide the cursor in Windows

A problem I had during the development of my gaze-enhanced tab switching, was that the mouse cursor was diverting the user's gaze. That's why I decided to hide the cursor, while gaze control is active.

A major problem here was that the .net funktions Cursor.Hide() and WinApi ShowCursor(false) are only valid for the user control they are called from.
I searched for a way to hide the cursors globally in windows.

One possibility which came to my mind was to change the Windows cursor temporarily (as you can also do it via System Control->Mouse Settings) to an invisible dummy cursor, which is basically just a .cur file without any content. The information for the currently active cursors is stored in the Windows registry. Reading from and changing the registry is not that big of a problem for C#.

So here is what I had to do:
  1. Store the current cursor path
  2. Change the cursors "Arrow" and "Hand" to the invisible.cur file
  3. Force a reload of the registry
  4. Later: restore the original cursors again.
After the jump is the code, which does what I wanted to accomplish. It is called on pressing the hotkey combination for "enable gaze control", which I set to the same hotkey combo as "show tab previews" in firefox :)

[...] //Global variables in my class
private string m_arrowCursor, m_handCursor; // Stores the initial cursors for Arrow and Hand
// Function is called to force a reload of the Windows Registry
[DllImport("user32.dll", EntryPoint = "SystemParametersInfo")]
public static extern bool SystemParametersInfo(int uAction, int uParam, string lpvParam, int fuWinIni);



[...]



//Reading and storing the original cursor files
//Done in my class constructor

// read current cursor values from the registry
RegistryKey rk = Registry.CurrentUser.OpenSubKey(@"Control Panel\Cursors");
if (rk != null)
{
    m_arrowCursor = (string)rk.GetValue("Arrow");
    m_handCursor = (string)rk.GetValue("Hand");
    rk.Close();
}


[...]  
private void ShowCursor(bool show)
{  
    // 3 variables are needed for forcing the registry reload
    const int SPI_SETCURSORS = 0x0057;
    const int SPIF_UPDATEINIFILE = 0x01;
    const int SPIF_SENDCHANGE = 0x02;

    if (!show)
    {
        // Change the default arrow cursor
        Registry.SetValue("HKEY_CURRENT_USER\\Control Panel\\Cursors", "Arrow", @"C:\Users\Dan\Documents\My Dropbox\Magisterarbeit\Code\iGazeWeb\iGazeWeb_Client\iGazeWeb_Client\bin\Debug\invisible.cur");
        Registry.SetValue("HKEY_CURRENT_USER\\Control Panel\\Cursors", "Hand", @"C:\Users\Dan\Documents\My Dropbox\Magisterarbeit\Code\iGazeWeb\iGazeWeb_Client\iGazeWeb_Client\bin\Debug\invisible.cur");
        // Force the registry reload
        SystemParametersInfo(SPI_SETCURSORS, 0, null, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE);
    }
    else
    {
        // restore the default cursors
        Registry.SetValue("HKEY_CURRENT_USER\\Control Panel\\Cursors", "Arrow", m_arrowCursor);
        Registry.SetValue("HKEY_CURRENT_USER\\Control Panel\\Cursors", "Hand", m_handCursor);
        // Force the registry reload
        SystemParametersInfo(SPI_SETCURSORS, 0, null, SPIF_UPDATEINIFILE | SPIF_SENDCHANGE);
    }
}


I am still feeling a bit shaky because of modifying the registry, but as there seems to be no other way to change the Windows cursors i'll have to stick with it... If somebody know a better solution, just post a comment, or e-mail me (see About).

This forum entry was essential for me for creating this solution:
http://www.csharpfriends.com/Forums/ShowPost.aspx?PostID=80020

No comments:

Post a Comment