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
RodgerA
  • Guests
  • Last active:
  • Joined: --
Hello, thank you for this script. If I have set my cursor, ... and I want to Reverse it, put things back to stock normal. Is there a way to do this? :)

ruespe
  • Members
  • 567 posts
  • Last active: Dec 01 2014 07:59 PM
  • Joined: 17 Jun 2008
Have a look at the 1st post here.

ColbyK
  • Members
  • 35 posts
  • Last active: Dec 06 2012 03:03 PM
  • Joined: 10 Sep 2010
Is there a way to dynamically scale each cursor?

For example, I want all my cursors to be 40x40, but I want to still keep the system cursors and I want them to still change depending on what you hover over, so the pointer will still turn into a caret over a text box.



Is there a way to do that with this function?


Also, i've been trying
SetSystemCursor("IDC_ARROW",%size%,%size%)
but that doesn't seem to work, using the variables. Any ideas why?


Thanks![/code]

Klaus
  • Members
  • 333 posts
  • Last active: Feb 17 2015 09:31 AM
  • Joined: 12 May 2005
Hi, CobaltKitsune,
using variables as parameters for a function call, you must not enclose them with %'s. Try it like this
SetSystemCursor("IDC_ARROW",size,size)
Regards,
Klaus

ColbyK
  • Members
  • 35 posts
  • Last active: Dec 06 2012 03:03 PM
  • Joined: 10 Sep 2010
Klaus,

but of course! Thanks for pointing that out to me!

AndrewC
  • Guests
  • Last active:
  • Joined: --
Thanks a lot for this - really nice little script and exactly what I wanted.

Asking One
  • Guests
  • Last active:
  • Joined: --
It would be highly appreciated if some images of these cursors are posted for reference. :lol:

  • Guests
  • Last active:
  • Joined: --
would be nice to be able to change the blinking caret to indicate which hotkeys are on for example (like in normal mode in VIM).

Guest2
  • Guests
  • Last active:
  • Joined: --
Help! I am not sure what I am doing wrong... I can load the cursors with the specified sizes as long as I use a system cursor name. When I attempt to specify any .cur file the script loads, but nothing happens. What am I missing?
#SingleInstance Force

space::
   SetSystemCursor("C:\cursors\TEST2.cur")
   KeyWait, Space
   RestoreCursors()
Return
esc::exitapp



SetSystemCursor( Cursor = "", cx = 64, cy = 64 )
{
   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( "LoadImageA"
            , 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 )
}


Guest2
  • Guests
  • Last active:
  • Joined: --
As an FYI to anyone I was able to fix my error by making a change to line 88. I was not familiar with the 'LoadImage' function so I did not know to change this until I found the link at the bottom. All works as needed now.

Line 88 Original = %Type%%A_Index% := DllCall( "LoadImageA"
Line 88 Modified = %Type%%A_Index% := DllCall( "LoadImageW"

http://msdn.microsof... ... 45(v=vs.85).aspx

berban_
  • Members
  • 202 posts
  • Last active: Aug 05 2014 11:52 PM
  • Joined: 16 Mar 2011
Hey,

Thanks for this great function! I've been using it for a long time and am very grateful for it :)

I've long had an odd problem where it seemed that on occasion - like once a week or so - the cursor would freeze in a certain shape. Reloading the script fixed the problem though so it was never a big deal. However recently I changed to have far more cursor updates and the problem became much more common.

I noticed that in process explorer each cursor change correlated with an increase in the number of GDI Objects. (I have no idea why I happened to have this column showing but it was fortunate :p). When the GDI objects reach 10,000 they go no higher, and at this point the cursor stops changing. Also when the script has accumulated so many GDI objects I've noticed that sometimes it takes 10-20 seconds to reload it, i.e. far longer than normal.

Below is a link to a screenr video recording that demonstrates the problem:
<!-- m -->http://www.screenr.com/5HS8<!-- m -->
Although the cursor appears unchanged in the recording, it was changing on my monitor - at least until the GDI objects hit 10,000, at which point it froze on "IDC_NO".

And here's the script I used for the demonstration. Once more it does indeed work, it just accumulates GDI objects and stops working once this reaches 10k.

loop {
setsystemcursor("idc_no")
sleep 50
restorecursors()
sleep 50
}

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

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( "LoadImageA"
            , UInt,0, Str,Cursor, UInt,uType, Int,cx, Int,cy, UInt,0x10 )
            DllCall( "SetSystemCursor", Uint,%Type%%A_Index%, Int,SubStr( A_Loopfield, 1, 5 ) )         
         }         
      }
   }   
}


just me
  • Members
  • 1496 posts
  • Last active: Nov 03 2015 04:32 PM
  • Joined: 28 May 2011
I'd assume that this is caused by the double CopyImage in Else If SystemCursor = 1. The second copy is destroyed automatically by the system, but not the first.

I'd also assume that loading all system cursors only once should be sufficient.

berban_
  • Members
  • 202 posts
  • Last active: Aug 05 2014 11:52 PM
  • Joined: 16 Mar 2011

I'd assume that this is caused by the double CopyImage in Else If SystemCursor = 1. The second copy is destroyed automatically by the system, but not the first.

I'd also assume that loading all system cursors only once should be sufficient.


Hm, I tried commenting out both CopyImage calls one at a time. When the second one was commented it still sorta worked, although not as well, and the GDI objects still went up to 10,000. When the first one was commented nothing happened.

just me
  • Members
  • 1496 posts
  • Last active: Nov 03 2015 04:32 PM
  • Joined: 28 May 2011
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,[color=darkred] %Type%%A_Index%[/color] , Int,SubStr( A_Loopfield, 1, 5 ) )

         }
?

berban_
  • Members
  • 202 posts
  • Last active: Aug 05 2014 11:52 PM
  • Joined: 16 Mar 2011
Ah. Thanks :)

Now the script still accumulates GDI objects but at a much slower rate. For instance if I change the cursor 50 times now, it'll have 160 as opposed to 2500 before. (So that makes it 16x slower I suppose?) However I if change it 400 times it'll end up with around 1200 objects, which I suppose is roughly 8x160.

Sorry I'm like a toddler assembling a puzzle with this stuff - just putting pieces together with no rhyme or reason and seeing if it fits. I just know nothing about this stuff :( (and I'm too stubborn to learn)