Skip to content

Instantly share code, notes, and snippets.

@d3x0r
Created June 23, 2023 23:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save d3x0r/98b97a40511888ccfa0b0652dfa951a0 to your computer and use it in GitHub Desktop.
Save d3x0r/98b97a40511888ccfa0b0652dfa951a0 to your computer and use it in GitHub Desktop.
Test Mouse Cursor hiding (windows)

This is related to this thread: https://learn.microsoft.com/en-us/answers/questions/1315176/how-to-copy-system-cursors-properly

test_cursors.cc hides the cursor after 1 second, and exits after 15 seconds. atexit() it restores the cursors to visible if hidden.

Near the top of the cursor test file is a replacement macro for CopyCursor which uses DrawImage. The current has the options recently suggested.

test_wait.cc becomes a program 'test_wait_cursor.exe' which is a console application that opens a window. Moving the mouse over the window forces the IDC_WAIT cursor.

The CMakeLists.txt is provided for a simple build...

copy all files into the same directory (There should be a download all or clone button at the top).

mkdir build
cd build
cmake ..

open the generated test.sln file with visual studio and build as usual.

cmake_minimum_required(VERSION 3.1)
PROJECT( test )
add_executable( test_hide_cursor test_cursors.cc )
add_executable( test_wait_cursor test_wait.cc )
#include <windows.h>
#include <stdint.h>
#include <stdio.h>
#undef CopyCursor
// simple - doesn't get right resolution.
//#define CopyCursor(icon) (HCURSOR)CopyImage( icon,IMAGE_CURSOR,0, 0,0)
#define CopyCursor(icon) (HCURSOR)CopyImage( icon,IMAGE_CURSOR,0, 0, LR_COPYFROMRESOURCE | LR_DEFAULTSIZE |LR_DEFAULTCOLOR)
// uses the Registry CursorBaseSize tocopy the image...
//#define CopyCursor(icon) (HCURSOR)CopyImage( icon,IMAGE_CURSOR,cursorSize , cursorSize , LR_COPYFROMRESOURCE | LR_DEFAULTSIZE |LR_DEFAULTCOLOR)
// The cursorSize is updated from a registry setting which indicates the base cursor size.
int cursorSize = 32;
HCURSOR hCursor;
#define ALL_CURSORS 17
int oldCursors[ALL_CURSORS] = {
(int)(uintptr_t)IDC_ARROW,
(int)(uintptr_t)IDC_IBEAM,
(int)(uintptr_t)IDC_WAIT,
(int)(uintptr_t)IDC_CROSS,
(int)(uintptr_t)IDC_UPARROW,
(int)(uintptr_t)IDC_SIZE, /* OBSOLETE: use IDC_SIZEALL */
(int)(uintptr_t)IDC_ICON, /* OBSOLETE: use IDC_ARROW */
(int)(uintptr_t)IDC_SIZENWSE,
(int)(uintptr_t)IDC_SIZENESW,
(int)(uintptr_t)IDC_SIZEWE,
(int)(uintptr_t)IDC_SIZENS,
(int)(uintptr_t)IDC_SIZEALL,
(int)(uintptr_t)32647, /*not in win3.1 */
(int)(uintptr_t)IDC_NO, /*not in win3.1 */
(int)(uintptr_t)IDC_HAND,
(int)(uintptr_t)IDC_APPSTARTING, /*not in win3.1 */
(int)(uintptr_t)IDC_HELP,
};
HCURSOR hOldCursors[ALL_CURSORS];
int isHidden = 0;
void ResetCursor(void) {
if( isHidden ) {
for( int i = 0; i < ALL_CURSORS; i++ )
SetSystemCursor( hOldCursors[i], oldCursors[i]);
}
}
void GetCursorInfo( void ) {
DWORD dwStatus;
HKEY hTemp;
DWORD dwRetType;
char pValue[512];
DWORD dwBufSize;
dwStatus = RegOpenKeyEx( HKEY_CURRENT_USER,
"Control Panel\\Cursors", 0,
KEY_READ, &hTemp );
dwBufSize = 512;
dwStatus = RegQueryValueEx( hTemp, "CursorBaseSize", 0
, &dwRetType
, (PBYTE)&pValue
, &dwBufSize );
if( dwRetType == REG_DWORD ) {
DWORD size = ((DWORD*)pValue)[0];
cursorSize = size;
printf( "size:%d\n", size );
}
}
DWORD WINAPI hideCursorThread( LPVOID param ) {
int timeout = 1000; // hide after 1 second idle...
int64_t now = GetTickCount();
POINT oldPoint;
POINT newPoint;
GetCursorPos( &oldPoint );
while( 1 ) {
int64_t newNow = GetTickCount();
GetCursorPos( &newPoint );
if( ( newPoint.x != oldPoint.x ) || ( newPoint.y != oldPoint.y ) ) {
if( isHidden ) {
for( int i = 0; i < ALL_CURSORS; i++ )
SetSystemCursor( CopyCursor( hOldCursors[i] ), oldCursors[i] );
//HCURSOR hPass = CopyCursor( hOldCursor );
//SetSystemCursor( hPass, 32512/*OCR_NORMAL*/ );
isHidden = FALSE;
}
oldPoint = newPoint; // update the point position.
now = newNow;
} else
if( ( newNow - now ) > timeout ) {
if( !isHidden ) {
for( int i = 0; i < ALL_CURSORS; i++ )
SetSystemCursor( CopyCursor( hCursor ), oldCursors[i] );
//HCURSOR hPass = CopyCursor( hCursor );
//SetSystemCursor( hPass, 32512/*OCR_NORMAL*/ );
isHidden = TRUE;
}
now = newNow;
}
Sleep( 100 );
}
}
static void initBlankCursor( void ) {
BYTE ANDmaskCursor[] =
{
0xff, 0xff, 0xff, 0xff, // line 1
0xff, 0xff, 0xff, 0xff, // line 2
0xff, 0xff, 0xff, 0xff, // line 3
0xff, 0xff, 0xff, 0xff, // line 4
0xff, 0xff, 0xff, 0xff, // line 5
0xff, 0xff, 0xff, 0xff, // line 6
0xff, 0xff, 0xff, 0xff, // line 7
0xff, 0xff, 0xff, 0xff, // line 8
0xff, 0xff, 0xff, 0xff, // line 9
0xff, 0xff, 0xff, 0xff, // line 10
0xff, 0xff, 0xff, 0xff, // line 11
0xff, 0xff, 0xff, 0xff, // line 12
0xff, 0xff, 0xff, 0xff, // line 13
0xff, 0xff, 0xff, 0xff, // line 14
0xff, 0xff, 0xff, 0xff, // line 15
0xff, 0xff, 0xff, 0xff, // line 16
0xff, 0xff, 0xff, 0xff, // line 17
0xff, 0xff, 0xff, 0xff, // line 18
0xff, 0xff, 0xff, 0xff, // line 19
0xff, 0xff, 0xff, 0xff, // line 20
0xff, 0xff, 0xff, 0xff, // line 21
0xff, 0xff, 0xff, 0xff, // line 22
0xff, 0xff, 0xff, 0xff, // line 23
0xff, 0xff, 0xff, 0xff, // line 24
0xff, 0xff, 0xff, 0xff, // line 25
0xff, 0xff, 0xff, 0xff, // line 26
0xff, 0xff, 0xff, 0xff, // line 27
0xff, 0xff, 0xff, 0xff, // line 28
0xff, 0xff, 0xff, 0xff, // line 29
0xff, 0xff, 0xff, 0xff, // line 30
0xff, 0xff, 0xff, 0xff, // line 31
0xff, 0xff, 0xff, 0xff // line 32
};
// Yin-shaped cursor XOR mask
BYTE XORmaskCursor[] =
{
0, 0, 0, 0, // line 1
0, 0, 0, 0, // line 2
0, 0, 0, 0, // line 3
0, 0, 0, 0, // line 4
0, 0, 0, 0, // line 5
0, 0, 0, 0, // line 6
0, 0, 0, 0, // line 7
0, 0, 0, 0, // line 8
0, 0, 0, 0, // line 9
0, 0, 0, 0, // line 10
0, 0, 0, 0, // line 11
0, 0, 0, 0, // line 12
0, 0, 0, 0, // line 13
0, 0, 0, 0, // line 14
0, 0, 0, 0, // line 15
0, 0, 0, 0, // line 16
0, 0, 0, 0, // line 17
0, 0, 0, 0, // line 18
0, 0, 0, 0, // line 19
0, 0, 0, 0, // line 20
0, 0, 0, 0, // line 21
0, 0, 0, 0, // line 22
0, 0, 0, 0, // line 23
0, 0, 0, 0, // line 24
0, 0, 0, 0, // line 25
0, 0, 0, 0, // line 26
0, 0, 0, 0, // line 27
0, 0, 0, 0, // line 28
0, 0, 0, 0, // line 29
0, 0, 0, 0, // line 30
0, 0, 0, 0, // line 31
0, 0, 0, 0 // line 32
};
// Create a custom cursor at run time.
//return ;
{
//int x = SystemParametersInfo( )
//int x = GetSystemMetrics( SM_CXCURSOR );
//int y = GetSystemMetrics( SM_CYCURSOR );
//GetCursorInfo();
//SystemParametersInfo( )
//lprintf( "cursor is %d %d", x, y );
//hOldCursor = CopyCursor( LoadCursor( NULL, IDC_ARROW ) );
for( int i = 0; i < ALL_CURSORS; i++ ) {
//if( i == 0 )
// hOldCursors[i] = LoadCursorFromFile( "C:\\Users\\d3x0r\\AppData\\Local\\Microsoft\\Windows\\Cursors\\arrow_eoa.cur");
//else
hOldCursors[i] = CopyCursor( LoadCursor( NULL, (LPCSTR)(uintptr_t)oldCursors[i] ) );
}
//hOldCursors[i] = CopyCursor( LoadImage( NULL, (LPCSTR)(uintptr_t)oldCursors[i], IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE ) );
}
//lprintf( "Cursors: %p %p", hOldCursor, hOldCursor2 );
hCursor = CreateCursor( GetModuleHandle( NULL ), // app. instance
19, // horizontal position of hot spot
2, // vertical position of hot spot
32, // cursor width
32, // cursor height
ANDmaskCursor, // AND mask
XORmaskCursor ); // XOR mask
return;
}
int main( void ) {
uint32_t tick = GetTickCount();
atexit( ResetCursor );
GetCursorInfo();
initBlankCursor();
CreateThread( NULL, 0, hideCursorThread, NULL, 0, 0 );
while( (GetTickCount() - tick) < 15000 )
Sleep( 1000 );
return 0;
}
#include <windows.h>
#include <stdio.h>
HCURSOR hCursor;
LRESULT CALLBACK
VideoWindowProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_CREATE:
return TRUE;
case WM_CLOSE:
DestroyWindow( hWnd );
break;
case WM_DESTROY:
PostQuitMessage( 0 );
return 0;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint( hWnd, &ps );
// All painting occurs here, between BeginPaint and EndPaint.
FillRect( hdc, &ps.rcPaint, (HBRUSH)( COLOR_WINDOW + 1 ) );
EndPaint( hWnd, &ps );
}
case WM_SETCURSOR:
SetCursor( hCursor );
break;
/*
case WM_MOUSEMOVE:
printf( "MouseMove.." );
return 0;
*/
}
return DefWindowProc (hWnd, uMsg, wParam, lParam);
}
void OpenWindow() {
WNDCLASS wc;
ATOM aClass;
{
memset (&wc, 0, sizeof (WNDCLASS));
wc.style = 0
| CS_OWNDC
| CS_GLOBALCLASS
;
wc.lpfnWndProc = (WNDPROC) VideoWindowProc;
wc.hInstance = GetModuleHandle( NULL );
wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
wc.lpszClassName = "VideoOutputClass";
wc.cbWndExtra = sizeof( uintptr_t ); // one extra pointer
aClass = RegisterClass (&wc);
if (!aClass)
{
printf( "Failed to register class %s %d\n", wc.lpszClassName, GetLastError() );
return;
}
}
HWND hWndInstance = CreateWindowEx (0
, (LPSTR)aClass
, "Set Wait Cursor"
, WS_OVERLAPPEDWINDOW
, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT
, 0 // (GetDesktopWindow()), // Parent
, NULL // Menu
, GetModuleHandle( NULL )
, (void *) 1);
ShowWindow( hWndInstance, SW_SHOW );
}
int main( void ) {
MSG msg;
hCursor = LoadCursor( NULL, IDC_WAIT );
OpenWindow();
while( GetMessage( &msg, NULL, 0, 0 ) ){
DispatchMessage( &msg );
}
}
@eugenesvk
Copy link

Hey, have you found a solution to the blurry/pixelated cursor issue?

I was only able to find a workaround by reloading the cursors after unhiding/showing them back via SystemParametersInfo with SPI_SETCURSORS (=0x57), but haven't found a way to fix the pixelation properly (even though I set the correct size in the CopyImage function with proper monitor DPI and accessibility scaling and all that)

@d3x0r
Copy link
Author

d3x0r commented Aug 31, 2023

No; The next step was to make a windows support ticket... I ended up going with the suggestion to move the cursor to the far right of all monitors, which puts most of the cursor off the screen (unless you have opposite direction arrows :) )

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