Page 1 of 1

Help with cursor hiding script

Posted: 30 Jun 2017, 06:43
by Hitaku
The below script seems to work perfectly when I press ScrollLock, but I was hoping to have it work without having to press any keys if a window was active. Where exactly do I place #IfWinActive? Could someone help me out with editing this? For the sake of simplicity, lets just use #IfWinActive, Paint.

Code: Select all

ScrollLock::
if (flag := !flag) {
   MouseGetPos, , , hwnd
   Gui Cursor:+Owner%hwnd%
   BlockInput MouseMove
   DllCall("ShowCursor", Int,0)
} else {
   BlockInput MouseMoveOff
   DllCall("ShowCursor", Int,1)
}
Return

Re: Help with cursor hiding script

Posted: 30 Jun 2017, 06:59
by BoBo
Hitaku wrote:[...] but I was hoping to have it work without having to press any keys [...]
#IfWinActive / #IfWinExist
Creates context-sensitive hotkeys and hotstrings. Such hotkeys perform a different action (or none at all) depending on the type of window that is active or exists.
As far as I can say you've to use SetTimer to do checks against the window itself (+ ControlGetFocus/CoordMode/...) to get this done.

Re: Help with cursor hiding script

Posted: 30 Jun 2017, 10:09
by Hitaku
I see. I've never used those before. Would you maybe be able to assist me in changing the script to use that instead?

Re: Help with cursor hiding script

Posted: 30 Jun 2017, 11:20
by BoBo

Code: Select all

#Persistent
SetTitleMatchMode, 2

SetTimer, Painter, 100
Return

Painter:
WinGetTitle, Title, A
If InStr(Title,"Paint")
   WinGetPos, X, Y, Width, Height, A
<now you've to create a condition based on the current mouse position and its position within the target windows frame>
Return
Good luck :)

Re: Help with cursor hiding script

Posted: 30 Jun 2017, 12:12
by wolf_II
There is another way with SHELLHOOK that allows you to monitor (and respond to) the active window.
Forum user SvenBent explains the benefits of SHELLHOOK over SetTimer here: https://autohotkey.com/boards/viewtopic ... 26#p109226
It works like this: Put a Watchdog function in your script and have it alert the Guard whenever the active window changes.

Example with notepad: (Paint does not play nicely with hiding cursor)

Code: Select all

SetBatchLines, -1
Return ; end of auto-execute section



;-------------------------------------------------------------------------------
Watchdog(wParam, lParam := "") { ; monitor activating windows
;-------------------------------------------------------------------------------
    static init   := DllCall("RegisterShellHookWindow", Ptr, A_ScriptHwnd)
        , MsgNum  := DllCall("RegisterWindowMessage", Str, "SHELLHOOK")
        , neglect := OnMessage(MsgNum, "Watchdog")
        , CleanUp := {base: {__Delete: "Watchdog"}}

    If Not IsObject(CleanUp) {
        OnMessage(MsgNum, "")
        DllCall("DeregisterShellHookWindow", Ptr, A_ScriptHwnd)
    }

    If (wParam = 1)     ; HSHELL_WINDOWCREATED
    Or (wParam = 4)     ; HSHELL_WINDOWACTIVATED
    Or (wParam = 32772) ; HSHELL_RUDEAPPACTIVATED

        Guard(lParam) ; alert the guard about a new active window
}



;-------------------------------------------------------------------------------
Guard(hActive) { ; toggle mouse on/off if a certain window is active
;-------------------------------------------------------------------------------
    WinGetTitle, Title, ahk_id %hActive%

    If InStr(Title, "Notepad") {        ; toggle mouse off
        MouseGetPos,,, hwnd
        Gui, Cursor: +Owner%hwnd%
        BlockInput, MouseMove
        DllCall("ShowCursor", Int,0)
    }

    Else {                              ; toggle mouse on
        BlockInput, MouseMoveOff
        DllCall("ShowCursor", Int,1)
    }
}

Re: Help with cursor hiding script

Posted: 01 Jul 2017, 08:23
by Hitaku
wolf_II wrote:There is another way with SHELLHOOK that allows you to monitor (and respond to) the active window.
Forum user SvenBent explains the benefits of SHELLHOOK over SetTimer here: https://autohotkey.com/boards/viewtopic ... 26#p109226
It works like this: Put a Watchdog function in your script and have it alert the Guard whenever the active window changes.

Example with notepad: (Paint does not play nicely with hiding cursor)

Code: Select all

SetBatchLines, -1
Return ; end of auto-execute section



;-------------------------------------------------------------------------------
Watchdog(wParam, lParam := "") { ; monitor activating windows
;-------------------------------------------------------------------------------
    static init   := DllCall("RegisterShellHookWindow", Ptr, A_ScriptHwnd)
        , MsgNum  := DllCall("RegisterWindowMessage", Str, "SHELLHOOK")
        , neglect := OnMessage(MsgNum, "Watchdog")
        , CleanUp := {base: {__Delete: "Watchdog"}}

    If Not IsObject(CleanUp) {
        OnMessage(MsgNum, "")
        DllCall("DeregisterShellHookWindow", Ptr, A_ScriptHwnd)
    }

    If (wParam = 1)     ; HSHELL_WINDOWCREATED
    Or (wParam = 4)     ; HSHELL_WINDOWACTIVATED
    Or (wParam = 32772) ; HSHELL_RUDEAPPACTIVATED

        Guard(lParam) ; alert the guard about a new active window
}



;-------------------------------------------------------------------------------
Guard(hActive) { ; toggle mouse on/off if a certain window is active
;-------------------------------------------------------------------------------
    WinGetTitle, Title, ahk_id %hActive%

    If InStr(Title, "Notepad") {        ; toggle mouse off
        MouseGetPos,,, hwnd
        Gui, Cursor: +Owner%hwnd%
        BlockInput, MouseMove
        DllCall("ShowCursor", Int,0)
    }

    Else {                              ; toggle mouse on
        BlockInput, MouseMoveOff
        DllCall("ShowCursor", Int,1)
    }
}

When I tried this script out, it worked great, but if I tab out / tab back in the cursor shows again. It's not active anymore, but it still shows. Is there a fix to that?

Re: Help with cursor hiding script  Topic is solved

Posted: 01 Jul 2017, 13:34
by wolf_II
Hitaku wrote:Is there a fix to that?
I think there is a way, but I don't like it very much. :( I had to get rid of your very elegant Gui Cursor and DllCall, and use a separate function to show/hide the mouse cursor.
This is a function I found somewhere on this forum and edited the hell out of. (A bad thing I do to understand other people's code.)

Where did you first read about this Gui Cursor:+Owner%hwnd% :?: I have not seen that used like that before, I would like to read more about its use and maybe use it again for this thread.
I presume, it does not like being inside a function? :think:
Meanwhile, here is a possible alternative:

Re: Help with cursor hiding script

Posted: 01 Jul 2017, 16:12
by Hitaku
Your alternative script worked perfectly for me! As for the script I originally linked, it was something that I picked up from a previous thread so I don't know much about that function. I'm sorry. =(

Thank you all though for taking the time to help me, happy I ended up with something that worked.

Re: Help with cursor hiding script

Posted: 04 Aug 2017, 15:47
by zertrax
Hello there,

Is it possible to globally hide the cursor after X seconds of inactivity while turning on/off the script with a shortcut?
Some programs change name and the window name solution may not always work

Re: Help with cursor hiding script

Posted: 02 Oct 2017, 01:38
by SkyBreather
Is there anyway to get the script to stay on top? Whenever I use that script on a certain window, and then alt+tab to a different one the mouse is shown. Is there anyway to avoid this conundrum? (P.S: I removed the BlockInput command)

Re: Help with cursor hiding script

Posted: 02 Oct 2017, 07:29
by wolf_II
Conundrum

Re: Help with cursor hiding script

Posted: 02 Oct 2017, 08:05
by Helgef
Hello wolf_II
wolf_II wrote:

Code: Select all

ShowMouse()
I take this one, thanks :wave: (I change BlankCursor to be static and make it only once though.)

Cheers.

Re: Help with cursor hiding script

Posted: 02 Oct 2017, 09:44
by wolf_II
Hi Helgef, :wave:

Thank you for the suggestion. Excellent.
  • While I was at it, I implemented the protect local vars from interfering globals that the user might put up, that I learned from you.
  • While I was at it, I also decided to use e.g. "Int" over Int and so on, since omitting the quotes seems to create variables named Int and so on.
  • I then commented every parameter to a WinAPI DllCall with the TYPE of info the API expects for this parameter.
    I included links to MSDN pages where I got all the comments from, the translation from a comment like "HCURSOR" to "Ptr" is my own. (and may be wrong :oops: )

Code: Select all

;-------------------------------------------------------------------------------
show_Mouse(bShow := True) { ; show/hide the mouse cursor
;-------------------------------------------------------------------------------
    ; WINAPI: SystemParametersInfo, CreateCursor, CopyImage, SetSystemCursor
    ; https://msdn.microsoft.com/en-us/library/windows/desktop/ms724947.aspx
    ; https://msdn.microsoft.com/en-us/library/windows/desktop/ms648385.aspx
    ; https://msdn.microsoft.com/en-us/library/windows/desktop/ms648031.aspx
    ; https://msdn.microsoft.com/en-us/library/windows/desktop/ms648395.aspx
    ;---------------------------------------------------------------------------
    static BlankCursor
    static CursorList := "32512, 32513, 32514, 32515, 32516, 32640, 32641"
        . ",32642, 32643, 32644, 32645, 32646, 32648, 32649, 32650, 32651"
    local ANDmask, XORmask, CursorHandle

    If bShow ; shortcut for showing the mouse cursor
        Return, DllCall("SystemParametersInfo"
            , "UInt", 0x57              ; UINT  uiAction    (SPI_SETCURSORS)
            , "UInt", 0                 ; UINT  uiParam
            , "Ptr",  0                 ; PVOID pvParam
            , "UInt", 0)                ; UINT  fWinIni

    If Not BlankCursor { ; create BlankCursor only once
        VarSetCapacity(ANDmask, 32 * 4, 0xFF)
        VarSetCapacity(XORmask, 32 * 4, 0x00)
        BlankCursor := DllCall("CreateCursor"
            , "Ptr", 0                  ; HINSTANCE  hInst
            , "Int", 0                  ; int        xHotSpot
            , "Int", 0                  ; int        yHotSpot
            , "Int", 32                 ; int        nWidth
            , "Int", 32                 ; int        nHeight
            , "Ptr", &ANDmask           ; const VOID *pvANDPlane
            , "Ptr", &XORmask)          ; const VOID *pvXORPlane
    }

    ; set all system cursors to blank, each needs a new copy
    Loop, Parse, CursorList, `,, %A_Space%
    {
        CursorHandle := DllCall("CopyImage"
            , "Ptr",  BlankCursor       ; HANDLE hImage
            , "UInt", 2                 ; UINT   uType      (IMAGE_CURSOR)
            , "Int",  0                 ; int    cxDesired
            , "Int",  0                 ; int    cyDesired
            , "UInt", 0)                ; UINT   fuFlags
        DllCall("SetSystemCursor"
            , "Ptr",  CursorHandle      ; HCURSOR hcur
            , "UInt", A_Loopfield)      ; DWORD   id
    }
}
Edit: May it's protect globel vars that the user might have put up from interference by this function. Maybe it's both.
In any case, it's making up for a missing local command, that would do the same, when called without arguments.

Re: Help with cursor hiding script

Posted: 02 Oct 2017, 10:31
by Helgef
Excellent wolf_II :thumbup:
"Int" over Int and so on, since omitting the quotes seems to create variables named Int and so on.
This is my preference, mostly due to syntax highligthing. I checked with DebugVars, omitting the quotes doesn't seem to create any Int variable. Also, having a global variable Int:="somethingIncorrectForDllCall" doesn't seem to affect the dllcall either.
"HCURSOR" to "Ptr"
That is correct.

Cheers.
--- > Scripts and Functions < ---

Re: Help with cursor hiding script

Posted: 02 Oct 2017, 11:14
by wolf_II
Thanks for responding!
Helgef wrote:omitting the quotes doesn't seem to create any Int variable
DebugVars does show them, and ListVars does. Please check the following stand-alone script. Int is listed under global vars.

Next "iteration" of this function
  • use two temporary added lines for debug/demo
  • "Int" replaced by Int, for demo (also temporary)
  • every DllCall's return value is now commented with TYPE info as well

Code: Select all

;-------------------------------------------------------------------------------
; this example hides the mouse cursor for 5 seconds, then shows it again
;-------------------------------------------------------------------------------
    show_Mouse(False)
    Sleep, 5000
    show_Mouse(True)

ExitApp ; end of auto-execute section



;-------------------------------------------------------------------------------
show_Mouse(bShow := True) { ; show/hide the mouse cursor
;-------------------------------------------------------------------------------
    ; WINAPI: SystemParametersInfo, CreateCursor, CopyImage, SetSystemCursor
    ; https://msdn.microsoft.com/en-us/library/windows/desktop/ms724947.aspx
    ; https://msdn.microsoft.com/en-us/library/windows/desktop/ms648385.aspx
    ; https://msdn.microsoft.com/en-us/library/windows/desktop/ms648031.aspx
    ; https://msdn.microsoft.com/en-us/library/windows/desktop/ms648395.aspx
    ;---------------------------------------------------------------------------
    static BlankCursor
    static CursorList := "32512, 32513, 32514, 32515, 32516, 32640, 32641"
        . ",32642, 32643, 32644, 32645, 32646, 32648, 32649, 32650, 32651"
    local ANDmask, XORmask, CursorHandle

ListVars ; debug/demo
MsgBox   ; debug/demo

    If bShow ; shortcut for showing the mouse cursor

        Return, DllCall("SystemParametersInfo"
            , "UInt", 0x57              ; UINT  uiAction    (SPI_SETCURSORS)
            , "UInt", 0                 ; UINT  uiParam
            , "Ptr",  0                 ; PVOID pvParam
            , "UInt", 0                 ; UINT  fWinIni
            , "Cdecl Int")              ; return BOOL

    If Not BlankCursor { ; create BlankCursor only once
        VarSetCapacity(ANDmask, 32 * 4, 0xFF)
        VarSetCapacity(XORmask, 32 * 4, 0x00)

        BlankCursor := DllCall("CreateCursor"
            , "Ptr", 0                  ; HINSTANCE  hInst
            , Int  , 0                  ; int        xHotSpot
            , Int  , 0                  ; int        yHotSpot
            , Int  , 32                 ; int        nWidth
            , Int  , 32                 ; int        nHeight
            , "Ptr", &ANDmask           ; const VOID *pvANDPlane
            , "Ptr", &XORmask           ; const VOID *pvXORPlane
            , "Cdecl Ptr")              ; return HCURSOR
    }

    ; set all system cursors to blank, each needs a new copy
    Loop, Parse, CursorList, `,, %A_Space%
    {
        CursorHandle := DllCall("CopyImage"
            , "Ptr",  BlankCursor       ; HANDLE hImage
            , "UInt", 2                 ; UINT   uType      (IMAGE_CURSOR)
            , Int  ,  0                 ; int    cxDesired
            , Int  ,  0                 ; int    cyDesired
            , "UInt", 0                 ; UINT   fuFlags
            , "Cdecl Ptr")              ; return HANDLE

        DllCall("SetSystemCursor"
            , "Ptr",  CursorHandle      ; HCURSOR hcur
            , "UInt", A_Loopfield       ; DWORD   id
            , "Cdecl Int")              ; return BOOL
    }
}
Edit I only just noticed your tiny writing ... I assume you encourage me to post there ... Rather than going on offtopic here ... Ok then, will do!

Re: Help with cursor hiding script

Posted: 02 Oct 2017, 11:37
by Helgef
You are right, my eyes where not doing their job. :crazy:
Note: CreateCursor SystemParametersInfo, CopyImage and SetSystemCursor uses the WINAPI calling convention, which is defined as stdcall, which is the default for DllCall, hence, cdecl should be omitted.
Your assumption was correct.