[Tool] AutoHotkey scripts

Not necessarily. AHK has tools to manage Threads.

see the Priority Parameter or Critical. If you have a Hotkey that handles super important stuff and must not be interrupted by a launch of another hotkeythread, you can assign either a Critcal, on or lift its Priority - OR make thread(s) non-interruptible. All of it can backfire though, if you dont use it thoughtfully.

i did the following:

  • Assigned a Critical, on to hotkeys where timing is crucial (and those hotkeys shoudnt take more than ~1 sec to finish, less is better ofc)

  • Removed all While Loops that werent necessary and could be replaced by peridodic timers with checks.

e.g:

 while !WinExist(clientstring)
              {
                sleep 10000
              }

just occupies a thread slot / time and is doing nothing

it can be easily replaced with a peridocical timer that runs just for the time it needs to do the check and then is silent again til its launched again.

so go through your hotkeys and see how long they run once activated and check if running loops can be replaced by timers. Thats already solving 90% of any interrupting problem

1 Like

Depends what the scripts do. While we surely dont need to worry about ram usage or performance when running a second script (can even be lanched by the first via RUN cmd) on nowadys CPUs, 2 independent threads dont know each other and dont share variables/information unless you cover that topic if it poses a problem. Ad hoc i dont know any neat method to let 2 scripts communicate with each other.

p.s with the Hotkey command, we can create situational Hotkeys, eg activate or deactivate another hotkey inside a current running hotkey routine (at least thats my idea to reduce interferences)

Stupid AHK.
Named the function “TimersOn” and for half an hour I couldn’t make it work (but it kinda worked)
Eventually renamed it to “TimersOnn” and now everything’s working.
I guess there’s some name conflict but documentation doesn’t mention this at all.

Also I keep forgetting about “global” declarations in functions (in C you don’t need them)
and it also takes me some time to remember that :wink:

Noob problems.

:slight_smile: i can beat that maybe?
you code and code, but whatever you do, the changes just seem to not have any effect. you start doubting your mental sanity .

until you recognize, that you saved the script as older version but ran the higher version number for testing … talk about wasting time :slight_smile:

1 Like

OK, what happens when you try to get a glimpse on how ‘Hotkey’ works together wih existing #if directives, trying to get a sense out of that %§"%$ manual about that topic. “hey guys, lets make the examples even shorter, max 2 line are sufficient, DO NOT show real scenarios, if we do it in a comprehensive style well get struck by lightning”
Worst documentation ever on this topic, making me want kicking the laptop through the window right now…

1 Like

so basically it seems i cant have multiple defining rules for a hotkey.

either its enabled or disabled by an positional #if directive
or it is switched either on or off.

but combined, aka having a hotkey thats only active when its including #if directive says so, but can be additionally (as second condition) turned on or off by using hotkey, name, label, on/off - that doesnt seem to work. (even though they state that the condition can be updated - but … wordz …)

ofc you can use a normal if (whatever) for stuff inside the hotkey, but thats not the same.

update1: hotkey, if, expression only works if you have a) an active #if directive and b) the expression is exactly the same as the one from the directive.

update2: If, % FunctionObject could do the trick

update3: screw the hotkey command.

Summary
#if (winactive("ahk_class Notepad") && myswitch=1)

Rbutton::
        send "rbuttonmania"
        sleep 100
        return

#if

does it all, why complicated when easy :wink:

Ever noticed some mischief with the comment function? Sometimes got problems with is.
So i write a line, i put a semicolon. Sometimes i put a TAB or some blanks before.
And ofc i got some SEND commands in my script.
And unless I delete every single comment, my script tends to SEND every letter of the comment…

I SEND something somewhere,
I comment something like " ;word of renewal"
And my script is SENDING w, o, r, d, blank, etc. Is this plausible (sending something that is not inside the send-brackets?) Or are there some comment-rules i do not know?

I don’t think I ever had such a bug/problem

https://www.autohotkey.com/docs/Language.htm#comments
according to documentation tab is ok too

Even here in examples they have such comments
https://www.autohotkey.com/docs/commands/Send.htm

Send Sincerely,{enter}John Smith  ; Types a two-line signature.
Send !fs ; Select the File->Save menu (Alt+F followed by S).
Send {End}+{Left 4} ; Jump to the end of the text then send four shift+left-arrow keystrokes.
SendInput {Raw}A long series of raw characters sent via the fastest method. ; See {Raw} for details.

Strange.
I mean, even IF I accidentally typed a : instead of a ; (which is quite unlikely due to the font in the editor) - SEND cannot send something outside its brackets, right?
It only happened with RMB, the SENDs for RBM were quite short and simple and ofc EVERY SEND was 100% closed with a bracket. As I said, the bug vanished with eliminating all comments, semicolons included.

Beside that, it was really funny. You push your RMB and all hell breaks loose.
Camera goes to default, Inventory opens, you sip a healing pot etc. xD

1 Like

This sounds crazy :rofl:Based on examples I quoted I seems it can but I don’t really know since I’ve never used it. You would have to study
https://www.autohotkey.com/docs/commands/Send.htm
to find out.

Wanted to modify your CameraAutoRotation, so that it rotates (when approaching the edges) even WITHOUT holding LMB.
So instead of the whole

~*LMB / while getkeystate LMB "P" etc

I put a Loop {} around the block.
Didnt work. I read that Loop can be interrupted via a return.
So I tried a Loop {} until 0.
Doesnt do a thing as well…
Any ideas…?

Loop
{
}
definitely work. You probably had some other error. Have you tried modyfing the following script? (take out everything from the existing Loop and put rotation stuff there, adjust sleep time etc

SendMode Input
#NoEnv
#SingleInstance Force
#MaxHotkeysPerInterval 1000 
#MaxThreadsPerHotkey 2
#KeyHistory 50
SetWorkingDir %A_ScriptDir%

hotkeys_turned_on := true

SetTitleMatchMode, 3
Loop
{
    Sleep, 1000
    if WinActive("Grim Dawn")
    {
        if hotkeys_turned_on
            continue
    }
    else if !hotkeys_turned_on
        continue
    
    hotkeys_turned_on ^= true
    Suspend, Toggle
}

~*LButton::
    KeyWait, LButton, T0.2 ;need to hold the button for 200ms to follow
    if ErrorLevel
    {         
        while GetKeyState("LButton", "P")
        {
            WinGetActiveStats, Title, Width, Height, X, Y
            MouseGetPos, xpos, ypos 
            xpos := xpos - Width/2 ;vector from the middle of the screen to the cursor
            ypos := Height/2 - ypos
            
            if (xpos*xpos + ypos*ypos < 10000)
                continue

            if (ypos > 0) and (Abs(ATan(xpos / ypos)) * 57.29578 < 20) 
                continue ; 20° degrees from 12 o'clock -> 40° no rotation sector (10)
            
            if xpos > 0 ;right half of screen -> rotate right
            {
                Send {n down}
                Sleep, 100 ; haven't tested other values here
                Send {n up}
            }
            else ;left half of screen -> rotate left
            {
                Send {b down}
                Sleep, 100
                Send {b up}
            }
            
            Sleep, 20
        }
    }
Return

Strange, alright. Gonna try it one more time today. Maybe there was a mistake with the brackets.
Wanted to try that out, because as soon as I had 2 different SetTimers in my script, both of them sometimes … die when holding LMB with its camera-loop for a while.
So I thought, I´ll add a logical [LMB down] as soon as I attack with RMB. This way i have

  1. an auto run. Never have to press LMB the whole time - quite nice
  2. maybe solved the SetTimer dying problem, but of course:
    No rotation without a physical LMB down, so I wanted to try the Loop {}.

maybe try using timer instead of loop, it’s probably even better
something like
[just a reminder] if you use some variable in function, you have to use global
i.e. if you have global value
angle := 1000
then in function you have to do

f()
{
   global angle
}

but in hotkey (i.e. LButton:: you don’t have to
The following code doesn’t read any global values though

SetTimer, AutoRotation, 120 ;(or 20??? but I think 120 is correct)

AutoRotation()
{
    WinGetActiveStats, Title, Width, Height, X, Y
    MouseGetPos, xpos, ypos 
    xpos := xpos - Width/2 ;vector from the middle of the screen to the cursor
    ypos := Height/2 - ypos

    if (xpos*xpos + ypos*ypos < 10000)
        continue

    if (ypos > 0) and (Abs(ATan(xpos / ypos)) * 57.29578 < 20) 
        continue ; 20° degrees from 12 o'clock -> 40° no rotation sector (10)

    if xpos > 0 ;right half of screen -> rotate right
    {
        Send {n down}
        Sleep, 100 ; haven't tested other values here
        Send {n up}
    }
    else ;left half of screen -> rotate left
    {
        Send {b down}
        Sleep, 100
        Send {b up}
    }
}

Nice idea. Gonna try it.
Timers are quite powerful and often seem to be the best method for stuff like GD.

  • Is it valid to use Settimer, activating “Autorotation”, when “Autorotation ()” is defined afterwards, not before?
  • Concerning the global variables: So in Autorotation() : Does it need to be global xpos instead of xpos, etc?
  • suprisingly yes, it is valid
  • it know it is weird but here xpos, ypos are local to the function, created in MouseGetPos, xpos, ypos, have cursor position stored them and are available to use further in the function. So much stuff going on in one line In other programming languages this stuff wouldn’t work and the program (compiler) wouldn’t know where xpos, ypos are coming from because there don’t seem to be created/declared anywhere. In AHK I think the moment you use some variable, it’s created and available to use so you probably can use it for the first time for example in if (new_var = 0) and it will work. Scripting languages are weird but on the other hand easy to use. https://www.autohotkey.com/docs/commands/MouseGetPos.htm
1 Like

settimer solution:
Script wont start. “Break/Continue must be enclosed by a loop”, referring to Autorotation()… Dont know why. To be precise, I think the compiler wants the MOUSEGETPOS to have a loop…

loop solution:
And loop still doesnt do a thing.

using q to click the key icon to show/hide active quests because there’s no keybinding for it. Nothing new in terms of AutoHotkey

q::
    WinGetActiveStats, Title, Width, Height, X, Y
    MouseGetPos, xpos, ypos
    BlockInput, MouseMove
    MouseMove, 1270, 230
    Sleep, 50
    Click
    Sleep, 50
    MouseMove, xpos, ypos
    BlockInput, MouseMoveOff
Return

Nice! This is resolution dependent, right?