Trying to up my game - questions for the gurus

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
Miguel7
Posts: 186
Joined: 08 Sep 2014, 07:06

Trying to up my game - questions for the gurus

11 May 2017, 20:58

Hey what's up,

I found a function I wanted to use in a project, and it works great, but I have absolutely no idea what the heck it's doing. Here's the code:

Code: Select all

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", "Ptr",0, "Ptr",c%A_Index% )
            h%A_Index% := DllCall( "CopyImage", "Ptr",h_cursor, "UInt",2, "Int",0, "Int",0, "UInt",0 )
            b%A_Index% := DllCall( "CreateCursor", "Ptr",0, "Int",0, "Int",0
                , "Int",32, "Int",32, "Ptr",&AndMask, "Ptr",&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", "Ptr",%$%%A_Index%, "UInt",2, "Int",0, "Int",0, "UInt",0 )
        DllCall( "SetSystemCursor", "Ptr",h_cursor, "UInt",c%A_Index% )
    }
}
This basically shows/hides/toggles the cursor, I get that, but I would really like to understand how it works. I know C++ pretty well, and I understand DllCalls, but when it comes to VarSetCapacity and NumGet/Put and stuff like that, I'm absolutely clueless. I know it basically boils down to the math involved in passing certain data types (which leads to my next question, see below). And AHK kinda has 2 syntaxes - and this guy used the one I've always avoided (that's way too many percent signs, = instead of := etc. IMO). But that's just me - my style in AHK is more like C++; I prefer functions over commands and expressions over... whatever the heck this nonsense is. :lol: It's funny, cuz I've been writing AHK for like 3 years now, and scripts like this are still borderline jibberish to me. I'm sure I could look up the functions on MSDN and kinda get the gist, but I'd be interested to find out what exactly the developer was doing here. All those long comma-separated lines (strings? lol strings have quotes IMO so maybe not), combined with the DllCalls and other cool stuff I don't understand yet.

The second question, probably related, is how would DllCalls work when they take or return a structure? It's all very straightforward with ints and floats and string variants and even pointers, but structs are not a thing in AHK. So for example (bad example, cuz AHK can already do this), the Win32 function "GetCursorPos" takes a pointer to an "LPPOINT" structure. So in the DllCall I'm thinking the type would be "Ptr", but what would it point to? I'm guessing that's where the VarSetCapacity and NumPut/Get come in. Am I way out in left field on that, or am I on the right track?

Thanks in advance for any pointers (no corny pun intended). :)

Anyway,
User avatar
Xtra
Posts: 2750
Joined: 02 Oct 2015, 12:15

Re: Trying to up my game - questions for the gurus

11 May 2017, 23:42

That was probably written long ago. Them pseudo arrays are terrible to read with all the %'s.

Code: Select all

#NoEnv
OnExit, Exit

$1::SystemCursor(0)    ; testing
$2::SystemCursor(1)    ; testing
$3::ExitApp            ; testing

SystemCursor(OnOff:=1)   ; 1 = On , 0 = Off
{
	static cursors := {}, INIT := 1, curr
	if (INIT)
	{
		cursors.system := [32512,32513,32514,32515,32516,32642,32643,32644,32645,32646,32648,32649,32650]    ; system cursors
		cursors.blank := []      ; blank cursors
		cursors.handles := []    ; handles of default cursors
		status := "handles"      ; active default cursors
		VarSetCapacity( h_cursor,4444, 1 ) , VarSetCapacity( AndMask, 32*4, 0xFF ) , VarSetCapacity( XorMask, 32*4, 0 )
		Loop, 13
		{
            h_cursor   := DllCall( "LoadCursor", "Ptr",0, "Ptr", cursors.system[A_Index] )
            cursors.handles[A_Index] := DllCall( "CopyImage", "Ptr",h_cursor, "UInt",2, "Int",0, "Int",0, "UInt",0 )
            cursors.blank[A_Index] := DllCall( "CreateCursor", "Ptr",0, "Int",0, "Int", 0, "Int",32, "Int",32, "Ptr",&AndMask, "Ptr",&XorMask )
		}
		INIT := 0
	}
    if (OnOff = 0) or (curr = "handles" and OnOff < 0)
        curr := "blank"    ; use blank cursors
    else
        curr := "handles"  ; use the saved cursors
    Loop, 13
    {
		cursor_num := cursors[curr][A_Index]
        h_cursor := DllCall( "CopyImage", "Ptr", cursor_num, "UInt",2, "Int",0, "Int",0, "UInt",0 )
        DllCall( "SetSystemCursor", "Ptr",h_cursor, "UInt", cursors.system[A_Index] )
    }
}

Exit:
    SystemCursor(1)
    ExitApp
Maybe this will help.

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: Aqualest, Google [Bot], mikeyww and 320 guests