[Tool] AutoHotkey scripts

IF you use it , it can hide the mousebutton from the game, so you can create (mouserelated) hotkes in ahk w/o having the game executing the bound action in game, since the game doesnt see any mousclick unless you send one by ahk. so its way more felxible as just remap mousebuttons in the mousedriver.

it may be overkill, but anyway, it confirms that AHK itself doesnt provide buildin drivers/methods to intercept stuff below wndows.

Sorry guys for being retarded but just this works

*RButton::
    while GetKeyState("RButton", "P")
    {
        Click, right
        Sleep, 200
    }
Return

even these two work together

~*LButton::
Return

*RButton::
    while GetKeyState("RButton", "P")
    {
        Click, right
        Sleep, 200
    }
Return

However my longer Left Click function doesnā€™t work with this Right click and thatā€™s was the cause of the problem (of Left and Right click not working well when you hold them and release in various orders). Why? No clue itā€™s very weird since very similar function above works. Iā€™m going to attempt fixing it now. I overblew the whole problem it seems

*RButton::
    while GetKeyState("RButton", "P")
    {
        Click, right
        Sleep, 200
    }
Return

~*LButton::
    KeyWait, LButton, T0.2
    if ErrorLevel
    {    
        counter := 0
        items_hidden := false
        
        while GetKeyState("LButton", "P")
        {
            if GetKeyState("Space", "P")
               Send {Space}
            
            if GetKeyState("Shift", "P")
            {
                if !items_hidden
                {
                    Send {RAlt}
                    items_hidden := true
                }
                
                Send {6} ; War Cry
                
                if counter < 24 ;trying as long as possible but shorter than cooldown
                    Send {7} ; Wendigo Totem

                counter := Mod(counter + 1, 65)
            }
            else
            {
                if items_hidden
                {
                    items_hidden := false
                    Send {RAlt}
                }
                counter := 0
            }
                
            Send {8} ; Wind Devil 
            
            Sleep, 200
        }
    }
Return
1 Like

no one here is retarded! :slight_smile: seriously! just dont underestimate how fast simple things get complex and ist soo easy to oversee a logical shortcoming. (my script worked, the compiled not - -> going mad, then saw i missed a sleep and the compliled one was so fast = overflows) - found out by using the opening the ahk console - doing stuff ingame, then back to console and checke what was going on - . maybe that could help you too to see where culprit is?

1 Like

I testing this stuff right now and I seriously donā€™t now what works and what doesnā€™t sorry for polluting the thread.

thats intended that its just doing nothing but sleep? any click / action forgotten?

Ok. Two while loops in different hotkeys block each other.

~*LButton::
    KeyWait, LButton, T0.2
    if ErrorLevel
    {   
        while GetKeyState("LButton", "P")
        {
            Sleep, 200
        }
    }
Return

*RButton::
    while GetKeyState("RButton", "P")
    {        
        Click, right       
        Sleep, 200
    }
Return

Now I know :rofl: Itā€™s probably super basic but I honestly thought they are in different threads or something. Knowing that Iā€™ve simply rewritten this code and it works 100%. Itā€™s also simpler than the nightmare that I wrote a few posts ago.

~*LButton::
    KeyWait, LButton, T0.2
    if ErrorLevel
    {   
        while GetKeyState("LButton", "P")
        {
            if GetKeyState("RButton", "P")
                Click, right
           
            ;autocast some skills here

            Sleep, 200
        }
        
        while GetKeyState("RButton", "P")
        {
            Click, right
            Sleep, 200
        }
    }
Return

but w8! @klasperstanze and I were testing automatic camera rotation with while loop on Left Click and some other while loop in Right Click and it worked (but @klasperstanze first said they were blocking each other) ? Or maybe it didnā€™t and I tested it wrong.

or I should better use setTimers and have much simpler code, w8.

Can you write function inside a hotkey?
Can you write a function object to achieve that?
I donā€™t want a separate function for Right Click setTimer
It would be nice if the whole code was in RButton hotkey with local SetTimer argument

IF you have a custom combinaton in your script (as i guess from the sniplets further above)
you basically call for trouble:

https://www.autohotkey.com/docs/Hotkeys.htm#combo

The prefix key loses its native function: In the above example, Numpad0 becomes a prefix key ; but this also causes Numpad0 to lose its original/native function when it is pressed by itself. To avoid this, a script may configure Numpad0 to perform a new action such as one of the following:"

(mho this is quite confusing, and the manual could have needed a better examples)

in my sniplet abobe i used Lbutton & Rbutton:: and with that i killed my Lbutton:: hotkey.

mb the same happened in your script?

sorry to say but: no, they dont :slight_smile: if theyā€™re in different hotkey sections- and in your case they are. each fired hotkey opens its own thread and therefore the while loops are ofc totally independent - unless you use the same variable eg-

Timers: they rock. each timer = its own thread. and its easy to configure them

Explain me the following then (I no longer have ā€œ&ā€ combinations in my code btw)

This does work

  1. you start holding Right Click and jumping (movement skill)
  2. you start holding Left Click as well -> you move and jump from time to time
~*LButton::
Return

*RButton::
    while GetKeyState("RButton", "P")
    {
        Click, right
        Sleep, 200
    }
Return

We adding while loop to the Left Click and it no longer works as I described! No jumping after you added Left Click hold to the Right Click hold, only movement

~*LButton::
    KeyWait, LButton, T0.2
    if ErrorLevel
    {   
        while GetKeyState("LButton", "P")
        {
            Sleep, 200
        }
    }
Return

*RButton::
    while GetKeyState("RButton", "P")
    {        
        Click, right       
        Sleep, 200
    }
Return

I completely donā€™t understand that. Retesting it right now to be 100%

[edit] Confirmed! What the hell?

simplified it a bit for testing

Summary

*LButton::
while GetKeyState(ā€œLButtonā€, ā€œPā€)
{
send i ;opens and closes inventory
sleep 1000
}

Return

*RButton::
while GetKeyState(ā€œRButtonā€, ā€œPā€)
{
send q ;opens and closes questlog
sleep 1000
}
Return

f12::suspend

tested in in notepad (to exclude game interefence) and indeed, once the 2. button is pressed the first one is magically lifted.

got ā€œiiiqqqqqqqqqqqqqiiiiiiiiiiiqqqqqqqqiiiiiiiiiiqqqiiā€ so one htkey blocks the interpretation of the other (but its not due to the while loops)

too tired now to get a clear head on this. im sure it has a simple explanation :slight_smile:

Sure. Thanks for your help anyway. Iā€™ve learnt a ton from you already. Iā€™ll rewrite with Timers and donā€™t bother with this crap anymore I think

1 Like

Hereā€™s a second while loop that was in RButton rewritten to timers @klasperstanze to try out if you ever have any problems with 2 while loops in your code. Works very well for me at the moment. They donā€™t block each other like 2 whiles did for me. However in was not working when I was sendind Space instead of click, right so I cannot really say itā€™s some magical bulletproof solution.

~*LButton::
    KeyWait, LButton, T0.2
    if ErrorLevel
    {   
        while GetKeyState("LButton", "P")
        {
            ;DO STUFF
            Sleep, 200 ;1st loop delay
        }
    }
Return

RightClick() ;DO STUFF 2
{
    Click, right
}

*RButton::
    KeyWait, RButton, T0.2
    if ErrorLevel
    {
        RightClick()
        SetTimer, RightClick, 2700 ;2th loop delay
    }
Return

*RButton up::
    SetTimer, RightClick, Off
Return
1 Like

just rewrote some stuff, back to an older solution, but cleverer:

~Lbutton::
some code
gosub, label1
return

..
..
..


label1:
IfWinActive, %clientstring%
	{
		While (GetKeyState("LButton", "p")) 
			{
				while  (!GetKeyState("RButton", "p") && (stopped = 0))
					{
						if (onsleep = 0) ;is timer free?
							{
								SetTimer, reapspirit, -20
							}
						
						sleep, %sleepvalue%	
						
						if (onsleep_2 = 0) ;is timer free
							{
								SetTimer, stormbox, -20
							}
						sleep, 200 	
							
					}		
							
				While ((GetKeyState("RButton", "p")) && (!GetKeyState("SHIFT", "p")))
					{
						 send {rbutton up}
						 send {blind}{f down} ;move to
						 sleep 100
					}
					send {blind}{f up}	
			}
	}
return

trick: multiple while loops tiered, finally solved it for me and replaced the need for custom combinations and their limitationsā€¦ (and works interpreted as well as compiled, in opposite to my older weirdness above)
just needed a coffee to get insight state , ele dmg + logic works :slight_smile:
hope you get your stuff running too!

1 Like

In my current script the 2 while loops block each other only quite rarely.
lmb = while loop for camera rotation
rmb = attack + some auto casts in between.

holding lmb, camera rotates a bit
hilding rmb, attacking.
releasing lmb: ERROR occurs (symptom: camera rotates infinetely although only rmb is pressed).

So what line or block of lines seems to be the solution for dual-loop-blocking now?

Checking if 20 ms timers are onā€¦ you donā€™t leave anything to chance and want your script behave exactly as you want to the milliseconds :grinning: this must be that Quake background. Iā€™m more laid-back.

There is this problem in GD that you cannot cast two skills at the same time (doesnā€™t need to be at the same time, there can be a small break) when you move your character. So I thought there might be two causes

  • character movement
  • holding LMB

But if you do two tests:

  • Holding LMB in a building while character not moving because of blockade
  • Just clicking long distance so that character moves but you release LMB

it works!
So it only doesnā€™t work when you BOTH hold the button and are moving with your character. Iā€™m going to write a bug report

My fix for that is literally stopping the character if heā€™s moving. I mean stopping for good, no sleeps are going to help.

1::
    if GetKeyState("LButton", "P") ; if moving, you have to stop if you want to cast 2 skills at once
    {
        Click, up
        WinGetActiveStats, Title, Width, Height, X, Y
        MouseGetPos, xpos, ypos
        BlockInput, MouseMove
        MouseMove, Width/2, Height/2
        Click
        MouseMove, xpos, ypos
        send {2}
        Sleep, 20
        Send {3}
        BlockInput, MouseMoveOff
    }
    else ;if not moving, we're doing stuff the usual way
    {
        send {2}
        Sleep, 20
        Send {3}
    }
Return
1 Like

na, actually its not the case :slight_smile:

ill explain:
negative numbers on settimer makes it a 1 shot timer (aka not periodoically) and the value determines the delay before it starts. Periodic Timers on abilities wih a very short cooldown are not needed in that case, esp when they get triggered by a permanent down mousebutton. i needed the timers only for their own thread feature whats crucial and circumvents many pitholes.

i STILL have exact time(er) measurement to be as effective as possible (that includes modulo to find the ideal sleep value for multiple shortCD timers)

each timer here looks like this example (not fully featured yet)

wordofrenewal: ;standardtimer1
IfWinActive, %clientstring%
	{
		Elapsed_5 := A_TickCount-startTime_5
		if (barswitched = 1)
			{
				return
			}
		send {blind}5
		startTime_5 := A_TickCount
	}
return

A_TickCount is an AHK internal var that is needed when you have to time things on the millisecond (and it allows more flexible timeout behaviours too, in opposite to the errorlevel method on keywait.) E.g you could define different timedeltas that lead to different actions depending on how long you held a key wth only one keywait.)

additional stuff:

Summary

but my todo is to write a complete timerlibary/function like the one on the link below, that manages all what youll ever needed from timers: their current stats/states, remaining time, cooldowns etc.
theres already a great one available, but i dont learn much personally by just including foreign code. the coding is actually a big part of the fun and i rather have a inferior selfcoded script than something i just copy pasted unless efficiency is needed or in a professional scope. But this is hobby learning fun, so i stuck with my impefect code on a neverending quest for improvement :slight_smile:

in case you want to use it:
https://autohotkey.com/board/topic/93687-function-timer/

its really good!

some important knowlege about Threads in AHK - please read carefully to understand
it explains e.g why a while loop under hotkey1 is stopping (if its still running by a held down button) when activating a whileloop in hotkey2.
(same for timers)

https://www.autohotkey.com/docs/misc/Threads.htm

basically:

" If a second thread is started ā€“ such as by pressing another hotkey while the previous is still running ā€“ the current thread will be interrupted (temporarily halted) to allow the new thread to become current
When the current thread finishes, the one most recently interrupted will be resumed, and so on "

testscript reflected that perfectly, if a second hotkey was pressed while a former one was already kept pressing, the second hotkeys action went live and the stuff from hotkey1 got halted unless you releaseed hotkey2.

that doesnt affect the GetKeyState() ability to simultaneous ask multiple keys about their state.

So, if you have actually bound hotkeys for Lbutton and Rbutton, the recently pressed one (and its commands) getting active while the previous one gets halted. even though youre still pressing it.
If you actually want to deal with simultaneous Mousebuttons, you need to do that inside a hotkeys/thread command. aka dont have a hotkey for each of the simultaneous pressed keys, that just wont work its for held down keys.

(not to talk about gaming keyboards and n-key rollover etc)

Summary
Suspend
;#maxthreadsperhotkey 2
;#MaxHotkeysPerInterval 100
#usehook

    f11::Suspend
    f12::ExitApp

; ### some blatant test for while / hotkey threading / timer threading (in notepad)
; ### start notepad, start script, move cursor inside notepad, activate script by f11, press a -> 0 , keep 
; ### pressed, -> 0000 , keep ressing a, now additionally press s, -> 111111, no more 0. lift s, keep pressing
; ### a - 000 again. etc

    a::
    SetTimer, timer1, on
    return
    /*
        while GetKeyState("a", "P")
            {
                send 0 
    			sleep 1000
            }
        
        Return
    */

    s::
    SetTimer, timer2, on
    ;SetTimer, timer4, on
    return
    /*
        while GetKeyState("s", "P")
        {        
            send 1 
    		sleep 1000     
        }
        Return
    */

    d::
    SetTimer, timer3, on
    return

    f::
    while GetKeyState("f", "P")
            {
                send 2 
    			sleep 1000
            }
            return

    timer1:
    while GetKeyState("a", "P")
            {
                send 0 
    			sleep 1000
            }
            return
            
    timer2:
    while GetKeyState("s", "P")
        {        
            send 1
    		sleep 1000     
        }
    return
        
    timer3:
    while (GetKeyState("d", "P") &&  GetKeyState("f", "P"))
        {        
            send 1
    		sleep 1000
            send 0
        }
    return

    timer4:
    while GetKeyState("s", "P")
            {
                send - 
    			sleep 1000
            }
            return

if you outcomment the whiles in timer1 and timer2, you will get the oscillating 10101010, because the timer just runs, sends the key and stops til its restarted (default period is 250). But a while loop keeps the a current timer instance running obviosuly so it gets pushed back to halt if another timer comes active.

that also means, that if you want truly independent hotkey actions, you may need to run a second AHK script instance

1 Like

Alright.
To avoid unwanted interchange when using multiple loops, you need to run it in two (or more) scripts.
Anything to be careful of when doing soā€¦?