5-Minute-Snack: Hiding or changing the mouse cursor system-wide

At first look, this might seem like a very easy task. Especially, when you simply want to hide the mouse cursor, you will find the method 

function ShowCursor; external user32 name 'ShowCursor';

in the Windows API.

Simply state…

ShowCursor( False );

..and the mouse cursor disappears. Or does it? 

Building a very simple demo application using the VCL teaches you something totally different: The cursor is hidden whenever your form is the top-most form, the mouse is moving over that form and that windows has inout-focus. If you leave the area of your form, the cursor will reappear. Again, it will suffice to change focus away from the app. So if you have two windows and the other window takes all input the cursor will also be shown if you move the mouse over the other form. There are several instances when this behavior might not be what you want to happen. 

In my case, I wanted the mouse cursor to disappear completely. No matter what was happening on the desktop PC the application was running on.

Let’s have a look at mouse cursors in Windows to evaluate our options. There is not only one mouse cursor, depending on the “target” the cursor is pointing towards, its appearance might change. Thus, we can load several cursors into the system.

The VCL wraps a mouse cursor in the class TCursor . The following cursor “shapes” have been defined:

Internally, a cursor is very similar to an icon with masking. I explicitly exclude animated cursors — completely different.

Using the Windows API you can load cursor files and assign them to these cursor types. Again, if you are just changing the cursor inside your VCL application, it will suffice to stay in the VCL world.

Changing it system-wide does, of course, require usage of the Windows API.

MSDN reveals a function called 

function SetSystemCursor(hcur: HICON; id: DWORD): BOOL; stdcall;

This function allows you to define a cursor, identified by an HICON-handle, for a certain appearance. Here very nicely referred to as “id”. You could not name it any better, I guess… 

Browing the documentation yields the following table for the DWORD-parameter:

Another thing to realize is that you are unable to assign “no cursor” to a certain id. Thus, we will need to create a cursor that is 100% transparent. You will find hundreds of cursor files on the internet that will provide just that (e.g. Google for “hidden cursor .cur”). 

In order to load the cursor file, we use

function LoadCursorFromFile(lpFileName: LPCWSTR): HCURSOR; stdcall;

which will yield the desired reference for SetSystemCursor .

We are able to replace the cursor now, but how can we get back to the initital setting when our app is closed? The TCursor class is very tightly tied to the Windows API. So we can store the initial cursor in another HCURSOR-reference. Be careful to get this reference before replacing the cursor! Otherwise, the VCL will load your replacement into TScreen.Cursors !

procedure TForm1.Panel1DblClick(Sender: TObject);
  LHiddenCursor : HCURSOR;

  // save default cursor
  LDefaultCursor := CopyIcon( Screen.Cursors[ crDefault ] );

  // load blank cursor
  LHiddenCursor := LoadCursorFromFile('HiddenCursor.cur');

  // set blank cursor
  SetSystemCursor( LHiddenCursor, OCR_NORMAL );

  // wait a bit

  // set default cursor
  SetSystemCursor( LDefaultCursor, OCR_NORMAL );

Above, you see the source code that replaces the cursor and also takes care of saving the state before your application was started. We only replace the standard arrow using OCR_NORMAL . Of course, you can change multiple cursor appearances using this approach.

Tags: ,