Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

Hiding the mouse cursor


  • Please log in to reply
21 replies to this topic
MisterW
  • Members
  • 65 posts
  • Last active: Jun 18 2007 11:14 AM
  • Joined: 20 Jul 2005
How can I:

a) Hide the mouse cursor
B) Change it (very temporarily) to something else while performing an action

I suspect I need a DLL call?

MisterW
  • Members
  • 65 posts
  • Last active: Jun 18 2007 11:14 AM
  • Joined: 20 Jul 2005
This sort of works, but it's slow (takes a while to take effect) and the cursor appears again as soon as I move the mouse.

DllCall("ShowCursor","Uint",0)

Interestingly, the showcount is not reset to zero once the cursor is made visible again by moving the mouse. It stays at it's negative value and can be decremented further by repeatedly executing this call. The reverse of this call seems to have no effect on making the cursor visible again.

Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005
DllCall("ShowCursor","Uint",0) does not do anything in my laptop (XP SP2). Even calling it in a loop hundreds of times does not hide a cursor (in 2-3 minutes).

MisterW
  • Members
  • 65 posts
  • Last active: Jun 18 2007 11:14 AM
  • Joined: 20 Jul 2005

DllCall("ShowCursor","Uint",0) does not do anything in my laptop (XP SP2). Even calling it in a loop hundreds of times does not hide a cursor (in 2-3 minutes).


Yeah, I think you're right.

It was only working for me because I had my cursor over a vim window and triggering a hotkey to hide the cursor also tells vim to hide the cursor. It hides the cursor when you start typing | press a key.

An unfortunate false positive.

Chris
  • Administrators
  • 10727 posts
  • Last active:
  • Joined: 02 Mar 2004
Others have had success hiding the cursor with Corrupt's nomousy.

I think there's also a way to do it with DllCall and the DirectX API, but I haven't researched it enough yet.

MisterW
  • Members
  • 65 posts
  • Last active: Jun 18 2007 11:14 AM
  • Joined: 20 Jul 2005

Others have had success hiding the cursor with Corrupt's nomousy.

Thanks Chris, I'll check it out.

Is the source for nomousy available?

shimanov
  • Members
  • 610 posts
  • Last active: Jul 18 2006 08:35 PM
  • Joined: 25 Sep 2005
Try the following:

loop, 13
	ToggleSystemCursor( A_Index, true )
	
MsgBox, Just in time for Halloween ...

loop, 13
	ToggleSystemCursor( A_Index )
return

ToggleSystemCursor( p_id, p_hide=false )
{
	/*
	OCR_NORMAL		IDC_ARROW		32512	1
	OCR_IBEAM		IDC_IBEAM		32513	2
	OCR_WAIT		IDC_WAIT		32514	3
	OCR_CROSS		IDC_CROSS		32515	4
	OCR_UP			IDC_UPARROW		32516	5
	OCR_SIZENWSE	IDC_SIZENWSE	32642	6
	OCR_SIZENESW	IDC_SIZENESW	32643	7
	OCR_SIZEWE		IDC_SIZEWE		32644	8
	OCR_SIZENS		IDC_SIZENS		32645	9
	OCR_SIZEALL		IDC_SIZEALL		32646	10
	OCR_NO			IDC_NO			32648	11
	OCR_HAND		IDC_HAND		32649	12
	OCR_APPSTARTING	IDC_APPSTARTING	32650	13
	*/
	
	static	system_cursor_list
	
	if system_cursor_list=
		system_cursor_list = |1:32512|2:32513|3:32514|4:32515|5:32516|6:32642|7:32643|8:32644|9:32645|10:32646|11:32648|12:32649|13:32650|
	
	ix := InStr( system_cursor_list, "|" p_id )
	ix := InStr( system_cursor_list, ":", false, ix )+1
	
	StringMid, id, system_cursor_list, ix, 5
	
	ix_b := ix+6
	ix_e := InStr( system_cursor_list, "|", false, ix )-1
	
	SysGet, cursor_w, 13
	SysGet, cursor_h, 14
	
	if ( cursor_w != 32 or cursor_h != 32 )
	{
		MsgBox, System parameters not supported!
		return
	}
	
	if ( p_hide )
	{
		if ( ix_b < ix_e )
			return

		h_cursor := DllCall( "LoadCursor", "uint", 0, "uint", id )
		
		h_cursor := DllCall( "CopyImage", "uint", h_cursor, "uint", 2, "int", 0, "int", 0, "uint", 0 )
		
		StringReplace, system_cursor_list, system_cursor_list, |%p_id%:%id%, |%p_id%:%id%`,%h_cursor%
		
		VarSetCapacity( AndMask, 32*4, 0xFF )
		VarSetCapacity( XorMask, 32*4, 0 )
		
		h_cursor := DllCall( "CreateCursor"
								, "uint", 0
								, "int", 0
								, "int", 0
								, "int", cursor_w
								, "int", cursor_h
								, "uint", &AndMask
								, "uint", &XorMask )
	}
	else
	{
		if ( ix_b > ix_e )
			return

		StringMid, h_cursor, system_cursor_list, ix_b, ix_e-ix_b+1
		
		StringReplace, system_cursor_list, system_cursor_list, |%p_id%:%id%`,%h_cursor%, |%p_id%:%id% 
	}
	
	result := DllCall( "SetSystemCursor", "uint", h_cursor, "uint", id )
}


MisterW
  • Members
  • 65 posts
  • Last active: Jun 18 2007 11:14 AM
  • Joined: 20 Jul 2005
Thanks Mate. This should work well!

It took me a bit of time to work out exactly what the script was doing.

Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005
Thanks, Shimanov! That's great!

I could not resist, but modified your script a bit: At the first call all the blank cursors are created and saved along to the current cursors, in two static arrays. Later only the desired set has to be loaded in a loop. It should be faster and easier to understand.

The script is extended further: with a Toggle parameter: change On/Off; there is a parameter value "Init" or "I" to force re-initialization (after the system cursors changed).

Edit: see the script in my next post.

shimanov
  • Members
  • 610 posts
  • Last active: Jul 18 2006 08:35 PM
  • Joined: 25 Sep 2005

Thanks, Shimanov! That's great!


Did you notice the "ghost" effect when moving or hovering over controls while the cursors are hidden?

Kind of cool and appropriate on this, the day of All Hallow's Eve.

Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005

the "ghost" effect when moving or hovering over controls while the cursors are hidden

It is cool! What are the appropriate system calls to make me invisible, too, but still be able to press buttons and pop up balloon texts?

Chris
  • Administrators
  • 10727 posts
  • Last active:
  • Joined: 02 Mar 2004
Great script. It seems to hide the cursor very well.

This script is perfect candidate for the standard library, which when it gets launched will be distributed with the program as a set of includable files.

Thanks for sharing it.

shimanov
  • Members
  • 610 posts
  • Last active: Jul 18 2006 08:35 PM
  • Joined: 25 Sep 2005

What are the appropriate system calls to make me invisible, too, but still be able to press buttons and pop up balloon texts?


This knowledge has eluded all of us since time immemorial. Though enlightenment will be ours in the end.

Laszlo
  • Moderators
  • 4713 posts
  • Last active: Mar 31 2012 03:17 AM
  • Joined: 14 Feb 2005
It looks like the size of the standard Windows cursors (even the extra large pointer set) is always 32 pixels. The invisible cursors can be made just 1 pixel large, so we could drop acquiring the cursor parameters. Is it true? If yes, we could save a few more lines of code:
Loop 9
{
   x := !x
   SystemCursor(x)
   MsgBox CURSOR VISIBLE = %x%
}

SystemCursor(OnOff=1)   ; INIT = "I","Init"; OFF = 0,"Off"; TOGGLE = -1,"T","Toggle"; ON = others
{
   static AndMask, XorMask, $, h_cursor
      ,c0,c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11,c12,c13  ; system cursors
        , b1,b2,b3,b4,b5,b6,b7,b8,b9,b10,b11,b12,b13  ; blank cursors
        , h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11,h12,h13  ; handles of default cursors
   if (OnOff = "Init" or OnOff = "I" or $ = "")       ; init when requested or at first call
   {
      $ = h                                           ; active default cursors
      VarSetCapacity( h_cursor,4444, 1 )
      VarSetCapacity( AndMask, 32*4, 0xFF )
      VarSetCapacity( XorMask, 32*4, 0 )
      system_cursors = 32512,32513,32514,32515,32516,32642,32643,32644,32645,32646,32648,32649,32650
      StringSplit c, system_cursors, `,
      Loop %c0%
      {
         h_cursor   := DllCall( "LoadCursor", "uint",0, "uint",c%A_Index% )
         h%A_Index% := DllCall( "CopyImage",  "uint",h_cursor, "uint",2, "int",0, "int",0, "uint",0 )
         b%A_Index% := DllCall("CreateCursor","uint",0, "int",0, "int",0
                             , "int",32, "int",32, "uint",&AndMask, "uint",&XorMask )
      }
   }
   if (OnOff = 0 or OnOff = "Off" or $ = "h" and (OnOff < 0 or OnOff = "Toggle" or OnOff = "T"))
      $ = b       ; use blank cursors
   else
      $ = h       ; use the saved cursors

   Loop %c0%
   {
      h_cursor := DllCall( "CopyImage", "uint",%$%%A_Index%, "uint",2, "int",0, "int",0, "uint",0 )
      DllCall( "SetSystemCursor", "uint",h_cursor, "uint",c%A_Index% )
   }
}
Another question: when the pointer becomes a hand sign, it becomes visible even when other cursors are not. Is it a bug or a feature?

Edit: make a copy of the cursor before SetSystemCursor, which destroyes it.

shimanov
  • Members
  • 610 posts
  • Last active: Jul 18 2006 08:35 PM
  • Joined: 25 Sep 2005

It looks like the size of the standard Windows cursors (even the extra large pointer set) is always 32 pixels. The invisible cursors can be made just 1 pixel large, so we could drop acquiring the cursor parameters.


That may be true, but it isn't documented as such. If it works, then great.

The nWidth and nHeight parameters must specify a width and height that are supported by the current display driver, because the system cannot create cursors of other sizes. To determine the width and height supported by the display driver, use the GetSystemMetrics function, specifying the SM_CXCURSOR or SM_CYCURSOR value.


although ...

Windows 95/98/Me: The width and height of the cursor must be the values returned by the GetSystemMetrics function for SM_CXCURSOR and SM_CYCURSOR.


when the pointer becomes a hand sign, it becomes visible even when other cursors are not. Is it a bug or a feature?


Maybe neither. The "hand sign" cursor could be assigned to appear in multiple contexts. Furthermore, it is possible that each window assigns a custom cursor or, at least, reinstates the original cursor.