Jump to content

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

Changing the system cursor


  • Please log in to reply
53 replies to this topic
just me
  • Members
  • 1496 posts
  • Last active: Nov 03 2015 04:32 PM
  • Joined: 28 May 2011
If you only use the system cursor part you might try this:

; AHK Basic
OnExit, AppExit
I := 0

Loop {
   SetSystemCursor("IDC_NO")
   ToolTip, % ++I
   Sleep 500
   RestoreCursors()
   Sleep 500
}

AppExit:
   RestoreCursors()
ExitApp

RestoreCursors()
{
   SPI_SETCURSORS := 0x57
   DllCall("SystemParametersInfo", "UInt", SPI_SETCURSORS, "UInt", 0, "UInt", 0, "UInt", 0)
}

SetSystemCursor(Cursor) {
   ; Cursor has to contain the name of a system cursor (IDC_...)
   ; IDC_ICON and IDC_SIZE are "Obsolete for applications marked version 4.0 or later."
   ; -> http://msdn.microsoft.com/en-us/library/ms648391%28v=vs.85%29.aspx
   ; and not listed in the OCR_... values of the SetSystemCursor function.
   ; -> http://msdn.microsoft.com/en-us/library/ms648395%28v=vs.85%29.aspx
   Static 
   Initialized := False
   SystemCursors := "32512IDC_ARROW|32513IDC_IBEAM|32514IDC_WAIT|32515IDC_CROSS|"
                  . "32516IDC_UPARROW|32642IDC_SIZENWSE|"
                  . "32643IDC_SIZENESW|32644IDC_SIZEWE|32645IDC_SIZENS|32646IDC_SIZEALL|"
                  . "32648IDC_NO|32649IDC_HAND|32650IDC_APPSTARTING|32651IDC_HELP"
   If !(Initialized) { ; load system cursors only once
      Loop, Parse, SystemCursors, |
      {
         CID := SubStr(A_LoopField, 1, 5)
         CNA := SubStr(A_LoopField, 6)
         HC%CNA% := DllCall("LoadCursor", "UInt", 0, "Int", CID)
      }
      Initialized := True
   }
   If !(HC%Cursor%) {
      Msgbox, 0, SetSystemCursor, Error: Invalid cursor name %Cursor%
      Return False
   }
   Loop, Parse, SystemCursors, |
   {
      CID := SubStr(A_LoopField, 1, 5)
      HCUR := DllCall("CopyIcon", "UInt" , HC%Cursor%)
      DllCall("SetSystemCursor", "UInt", HCUR, "Int", CID)
   }
   Return True
}

BTW: The script does not run slower.

berban_
  • Members
  • 202 posts
  • Last active: Aug 05 2014 11:52 PM
  • Joined: 16 Mar 2011
Thank you just me!!!!! As far as I can tell that fixes the problem! GDI objects do not increase with each call to the function. :D

I will now use this version instead. Also I'd recommend to Serenity that you update the main posting to incorporate this modification.

By the way your initializing thing didn't work. You just have to remove the line
Initialized := False
and it's fine

Here's a shortened version of the script (sorry but I compulsively shorten things):

SetSystemCursor(Cursor="") ;http://www.autohotkey.com/forum/viewtopic.php?p=524686#524686
{
	Static SystemCursors := "32512IDC_ARROW|32513IDC_IBEAM|32514IDC_WAIT|32515IDC_CROSS|32516IDC_UPARROW|32642IDC_SIZENWSE|32643IDC_SIZENESW|32644IDC_SIZEWE|32645IDC_SIZENS|32646IDC_SIZEALL|32648IDC_NO|32649IDC_HAND|32650IDC_APPSTARTING|32651IDC_HELP"
	If (Cursor = "")
		Return DllCall("SystemParametersInfo", "UInt", 0x57, "UInt", 0, "UInt", 0, "UInt", 0) 
	If (StrLen(SystemCursors) = 221)
		Loop, Parse, SystemCursors, |
			StringReplace, SystemCursors, SystemCursors, %A_LoopField%, % DllCall("LoadCursor", "UInt", 0, "Int", SubStr(A_LoopField, 1, 5)) A_LoopField
	If !(Cursor := SubStr(SystemCursors, InStr(SystemCursors "|", "IDC_" Cursor "|") - 5 - p := (StrLen(SystemCursors) - 221) / 14, 5))
		MsgBox, 262160, %A_ScriptName% - %A_ThisFunc%(): Error, Invalid cursor name!
	Else
		Loop, Parse, SystemCursors, |
			DllCall("SetSystemCursor", "UInt", DllCall("CopyIcon", "UInt", Cursor), "Int", SubStr(A_LoopField, 6, p))
}

It's also altered in a few other ways, for instance you omit the "IDC_" part, and you call the function again with no params to restore cursors.

Thanks again just me

EveryUser
  • Guests
  • Last active:
  • Joined: --
Does this change the cursor for every user? Ie: if used on a server, would the mouse be changing for everyone?

Cattleya
  • Members
  • 90 posts
  • Last active: Sep 13 2013 05:11 AM
  • Joined: 28 Sep 2011

I use the wrapper function to set cursor from my cur/ani file but don't work, anyone have an example ?

 

Ok, I solved this problem, problem is LoadImageA is only for ANSI (AHK_Basic), but I use AHK_L Unicode, so I replace LoadImageA with LoadImage then work fine:

Here is modified code:

#SingleInstance Force
#Persistent
SetWorkingDir, %A_ScriptDir%

Cursor = %A_ScriptDir%\anicursor.ani
SetSystemCursor(Cursor)
;CursorHandle := DllCall( "LoadCursorFromFile", Str,Cursor )
 
;DllCall( "SetSystemCursor", Uint,CursorHandle, Int,Cursors )

Return

!d::
RestoreCursors()
return

SetSystemCursor( Cursor = "", cx = 0, cy = 0 )
{
   BlankCursor := 0, SystemCursor := 0, FileCursor := 0 ; init
   
   SystemCursors = 32512IDC_ARROW,32513IDC_IBEAM,32514IDC_WAIT,32515IDC_CROSS
   ,32516IDC_UPARROW,32640IDC_SIZE,32641IDC_ICON,32642IDC_SIZENWSE
   ,32643IDC_SIZENESW,32644IDC_SIZEWE,32645IDC_SIZENS,32646IDC_SIZEALL
   ,32648IDC_NO,32649IDC_HAND,32650IDC_APPSTARTING,32651IDC_HELP
   
   If Cursor = ; empty, so create blank cursor
   {
      VarSetCapacity( AndMask, 32*4, 0xFF ), VarSetCapacity( XorMask, 32*4, 0 )
      BlankCursor = 1 ; flag for later
   }
   Else If SubStr( Cursor,1,4 ) = "IDC_" ; load system cursor
   {
      Loop, Parse, SystemCursors, `,
      {
         CursorName := SubStr( A_Loopfield, 6, 15 ) ; get the cursor name, no trailing space with substr
         CursorID := SubStr( A_Loopfield, 1, 5 ) ; get the cursor id
         SystemCursor = 1
         If ( CursorName = Cursor )
         {
            CursorHandle := DllCall( "LoadCursor", Uint,0, Int,CursorID )   
            Break               
         }
      }   
      If CursorHandle = ; invalid cursor name given
      {
         Msgbox,, SetCursor, Error: Invalid cursor name
         CursorHandle = Error
      }
   }   
   Else If FileExist( Cursor )
   {
      SplitPath, Cursor,,, Ext ; auto-detect type
      If Ext = ico
         uType := 0x1   
      Else If Ext in cur,ani
         uType := 0x2      
      Else ; invalid file ext
      {
         Msgbox,, SetCursor, Error: Invalid file type
         CursorHandle = Error
      }      
      FileCursor = 1
   }
   Else
   {   
      Msgbox,, SetCursor, Error: Invalid file path or cursor name
      CursorHandle = Error ; raise for later
   }
   If CursorHandle != Error
   {
      Loop, Parse, SystemCursors, `,
      {
         If BlankCursor = 1
         {
            Type = BlankCursor
            %Type%%A_Index% := DllCall( "CreateCursor"
            , Uint,0, Int,0, Int,0, Int,32, Int,32, Uint,&AndMask, Uint,&XorMask )
            CursorHandle := DllCall( "CopyImage", Uint,%Type%%A_Index%, Uint,0x2, Int,0, Int,0, Int,0 )
            DllCall( "SetSystemCursor", Uint,CursorHandle, Int,SubStr( A_Loopfield, 1, 5 ) )
         }         
         Else If SystemCursor = 1
         {
            Type = SystemCursor
            CursorHandle := DllCall( "LoadCursor", Uint,0, Int,CursorID )   
            %Type%%A_Index% := DllCall( "CopyImage"
            , Uint,CursorHandle, Uint,0x2, Int,cx, Int,cy, Uint,0 )      
            CursorHandle := DllCall( "CopyImage", Uint,%Type%%A_Index%, Uint,0x2, Int,0, Int,0, Int,0 )
            DllCall( "SetSystemCursor", Uint,CursorHandle, Int,SubStr( A_Loopfield, 1, 5 ) )
         }
         Else If FileCursor = 1
         {
            Type = FileCursor
            %Type%%A_Index% := DllCall( "LoadImage"
            , UInt,0, Str,Cursor, UInt,uType, Int,cx, Int,cy, UInt,0x10 )
            DllCall( "SetSystemCursor", Uint,%Type%%A_Index%, Int,SubStr( A_Loopfield, 1, 5 ) )         
         }         
      }
   }   
}

RestoreCursors()
{
	SPI_SETCURSORS := 0x57
	DllCall( "SystemParametersInfo", UInt,SPI_SETCURSORS, UInt,0, UInt,0, UInt,0 )
}


LexF0ri
  • Members
  • 2 posts
  • Last active: Jan 24 2015 11:36 AM
  • Joined: 19 Jan 2015
I have a problem with the active part of the cursor.
 
Can I just preface this by saying I am an absolute novice at Autohotkey, or any form of scripting.  This is my first time doing anything like this at all, so please forgive me if I am asking obvious questions.  To get this far has taken a good few hours of reading the tutorials, browsing the forums and lots of trial and error scripts that usually fail...
 
I am attempting to use this script to autoload a large custom cursor from an ico file in certain situations.  the file is 64 x 64.
 
I have managed to get this script to work, using Serenity's script in post 1, and then amending it per Cattleya (ie changing 'LoadA' to 'LoadW' in the 'setsystemcursor' line).
 
However I have encountered one difficulty - the cursor changes as expected, however the 'active' part of the cursor is not where I would like it to be (ie the point which is treated as the point of the cursor which selects items).  The cursor is a large version of the standard arrow, ie with the tip at the very top left corner.  However, Windows is using what appears to be the centre of the cursor as the active part.  With such a large cursor, the problem is obvious - the effect is that apparently wrong items are selected in menus etc.
 
I cannot work out if the active part is the very centre of the image or the point which was the active part of the much smaller system icon immediately prior to the change, but either way I need to change this.
 
Is there a variable in this script that I need to change?  Any help would be much appreciated.  I appreciate this thread is a little old, but hopefully someone is still watching?
 


LexF0ri
  • Members
  • 2 posts
  • Last active: Jan 24 2015 11:36 AM
  • Joined: 19 Jan 2015
I have solved this myself. There may be other solutions, but I downloaded realworld cursor editor from http://www.rw-designer.com/, and created a custom .cur file with a manually selected 'hotspot'. I think tthe problem may have been that I was previously attempting to use a .ico file.

coolykoen
  • Members
  • 47 posts
  • Last active: Apr 05 2016 06:31 AM
  • Joined: 29 Mar 2015

Maybe a little late, but i can't get this to work, as an example, hers my code:

SetSystemCursor()
{
	Image = C:\Users\coolykoen\Desktop\cursor.ico
	
	; uType:
	IMAGE_BITMAP := 0x0
	IMAGE_CURSOR := 0x2
	IMAGE_ICON := 0x1
	
	; Size:
	cx := 48, cy := cx
	
	; fuLoad:
	LR_COLOR := 0x2
	LR_CREATEDIBSECTION := 0x2000
	LR_DEFAULTSIZE := 0x40
	LR_LOADFROMFILE := 0x10
	LR_LOADMAP3DCOLORS := 0x1000
	
	CursorHandle := DllCall( "LoadImageA", UInt,0, Str,Image, UInt,IMAGE_ICON, Int,cx, Int,cy, UInt,0x10 )
}

I't simply won't load the image, what am i doing wrong?

I also tried to use the .png version ("Image = C:\Users\coolykoen\Desktop\cursor.png")... didn't work

Oh and using "%A_ScriptDir%\cursor.ico" and placing the file (named cursor.ico" in the script directory didn't work either

 

Thanks for any help :)



Normand
  • Members
  • 90 posts
  • Last active: Aug 31 2015 10:53 AM
  • Joined: 21 May 2007

Thanks for sharing this code.

Very usefull for visual impaired people.

Works well with Windows 7, but not with Windows 8.1.

Any tips will be appreciate.

Regards,


Normand Lamoureux

Normand
  • Members
  • 90 posts
  • Last active: Aug 31 2015 10:53 AM
  • Joined: 21 May 2007

Hi,

Here is the piece of code I use to replace arrow and i-beam cursors by 48x48 corresponding images.

It works well on Windows 7 32/64 bits, but not on Windows 8.1, and I don't know why.

size:="48"
SetSystemCursor1("arrow.cur",size,size)
SetSystemCursor2("i-beam.cur",size,size)

; Arrow (32512)
SetSystemCursor1( Cursor = "", cx = 0, cy = 0 )
{
    %A_Index% := DllCall( "LoadImageW"
    , UInt,0, Str,Cursor, UInt,0x2, Int,cx, Int,cy, UInt,0x10 )
    DllCall( "SetSystemCursor", Uint,%A_Index%, Int,32512 )
}

; I-Beam (32513)
SetSystemCursor2( Cursor = "", cx = 0, cy = 0 )
{
    %A_Index% := DllCall( "LoadImageW"
    , UInt,0, Str,Cursor, UInt,0x2, Int,cx, Int,cy, UInt,0x10 )
    DllCall( "SetSystemCursor", Uint,%A_Index%, Int,32513 )
}

Of course, the script is in the same folder than .cur images.

Is it possible to achieve this kind of cursors replacements on Windows 8.1?

If yes, what am I doing wrong?

Regards,

Normand


Normand Lamoureux