Any workaround for this getkeystate

Get help with using AutoHotkey (v1.1 and older) and its commands and hotkeys
Newbgamer

Any workaround for this getkeystate

11 Jun 2018, 18:59

Hi there ! I'm looking for a more simple way to stop the script if I release the key "#". This Getkeystate looks like a mess to me, and I'm sure there is a much better way to do it. Had to split the sleep timers to make sure it stops the script as quick as possible when the key is depressed.

Thanks !!

Code: Select all

#::
while GetKeyState("#","P")
{
Loop, 4		
		{
      		Send {6}
		Send {LButton Down}
		if not GetKeyState("#","P")
		break
		Sleep 475
		if not GetKeyState("#","P")
		break
		Sleep 475
		if not GetKeyState("#","P")
		break
		Sleep 475
		if not GetKeyState("#","P")
		break
		Sleep 475
		Send {LButton Up}
		Send {8}
		Send {LButton Down}
		if not GetKeyState("#","P")
		break
		Sleep 445
		if not GetKeyState("#","P")
		break
		Sleep 445
		Send {LButton Up}
		Sleep 20
		Send {RButton Down}
		if not GetKeyState("#","P")
		break
		Sleep 415
		Send {RButton Up}
		}
Send {LButton Down}
if not GetKeyState("#","P")
		break
Sleep 600
if not GetKeyState("#","P")
		break
Sleep 600
if not GetKeyState("#","P")
		break
Sleep 600
if not GetKeyState("#","P")
		break
Sleep 600
		}
Send {LButton Up}
Send {RButton Up}
Return
User avatar
evilC
Posts: 4823
Joined: 27 Feb 2014, 12:30

Re: Any workaround for this getkeystate

12 Jun 2018, 05:50

There is no other way to do this in a loop without making constant checks like you are doing. It could maybe be done a little cleaner, but you would still need to use the same basic technique.
If you want to shorten the code, what you could maybe do is put all the timings into an array, and then parse the array.

Something like this:

Code: Select all

#SingleInstance force

actions := [{key: "{6}", delay: -1}
		, {keys: "{LButton}", delay: 475}
		, {keys: "-1", delay: 475}
		, {keys: "-1", delay: 475}
		, {keys: "{LButton up}", delay: 8}]

currentPos := 1
max := actions.Length()
timerOn := 0

#::
	if (timerOn)
		return	; Filter key repeats
	timerOn := 1
	GoSub, SendKeys
	return

# up::
	timerOn := 0
	SetTimer, SendKeys, Off
	currentPos := 1		; If you want to reset position for each press, keep this line, else delete it
	return

SendKeys:
	Loop {
		;~ OutputDebug % "AHK| Processing item #" currentPos
		obj := actions[currentPos]
		; Increment position counter, and handle wrapping back around to start
		currentPos++
		if (currentPos > max)
			currentPos := 1
		
		; Process the item
		if (obj.Keys != -1)
			Send % obj.Keys
			;~ OutputDebug % "AHK| Sending " obj.Keys
		if (obj.Delay == -1){
			; Key has a delay of -1 (Meaning "No Delay"), so just go straight on to the next item
			;~ OutputDebug % "AHK| No delay after item"
			continue
		} else {
			; Key has a delay after it, so start a ONE TIME timer for the delay until the next key
			SetTimer, SendKeys, % "-" obj.Delay
			
			;~ OutputDebug % "AHK| Delaying " obj.Delay
			
			; Now break out of the loop
			break
		}
	}
	;~ OutputDebug % "AHK| Sending complete"
	return
So in order to use it, you need to be able to build the array which holds the data.

This is controlled by this code:

Code: Select all

actions := [{key: "{6}", delay: -1}
		, {keys: "{LButton}", delay: 475}
		, {keys: "-1", delay: 475}
		, {keys: "-1", delay: 475}
		, {keys: "{LButton up}", delay: 8}]
The structure of actions:
Start with an empty indexed array: actions := []

Then, each item in the array describes what to do for each "loop".
It has two elements:
"Key" describes what to send. A value of -1 means "Send no key"
"Delay" describes how long to wait afterwards. A value of -1 means "No delay after this key"

eg this means "Send the 6 key but do not wait after" {key: 6, delay: -1}
and this means "Send LButton and wait 475ms" {keys: "{LButton}", delay: 475}
and this means "Send no key, and wait 475ms" {keys: "-1", delay: 475}
swagfag
Posts: 6222
Joined: 11 Jan 2017, 17:59

Re: Any workaround for this getkeystate

12 Jun 2018, 07:51

heres a different way, provided you can keep your script immutable. it will run your script in a separate instance of AHK and kill it when u let go of w, bypassing the need for breaking up sleep statements and doing checks after every function call:

Code: Select all

#NoEnv
#SingleInstance Force
#MaxThreadsPerHotkey 2
SendMode Input
SetBatchLines -1
SetWorkingDir %A_ScriptDir%

slaveScript := recreateSlave()
OnExit("Cleanup")
canRun := true
Return

*w::
	if !canRun
		return

	Run % slaveScript, , , slavePID
	canRun := false
Return

*w Up::
	Process, Close, % slavePID
	Send {LButton Up}{RButton Up}
	canRun := true
Return

Esc::Cleanup()

Cleanup()
{
	global

	Process, Close, % slavePID
	ExitApp
}

recreateSlave()
{
	static fileName := "slave.ahk"
	static script := "
	(
		#NoEnv
		#SingleInstance Force
		#NoTrayIcon
		SendMode Input
		SetBatchLines -1

		Loop
		{
			Loop 4
			{
				Send 6
				Send {LButton Down}
				Sleep 1900
				Send {LButton Up}
				Send 8
				Send {LButton Down}
				Sleep 890
				Send {LButton Up}
				Sleep 20
				Send {RButton Down}
				Sleep 415
				Send {RButton Up}
			}

			Send {LButton Down}
			Sleep 2400
		}
	)"

	FileDelete % fileName
	FileAppend % script, % fileName

	return fileName
}
Nator
Posts: 4
Joined: 11 Jun 2018, 18:41

Re: Any workaround for this getkeystate

12 Jun 2018, 12:53

Hey thanks guys, i really appreciate the help here. I was thinking about a way to do an action then start a timer, then check the keystate in a loop while waiting for the timer to reach a custom value. It doesn't look like ahk can do that. Either way your replies work, thanks.


Would it be possible to create a popup window so I could tweak the 4 main timers I use dynamically? This wouldn't need to keep the script doing actions, but it would be nice to be able to just hit a key to pop the config window, set the timers and restart the script. Without having to actually edit the code and restart the script. I think I saw a script like this which would save the timers in a separate .ini file.
Nator
Posts: 4
Joined: 11 Jun 2018, 18:41

Re: Any workaround for this getkeystate

13 Jun 2018, 07:17

Not sure this is what I'm looking for exactly. Maybe, but I just don't have the knowledge yet.

I don't have a clue how to use a GUI in ahk and use input variables from the GUI/ini file in my script.

I could use a link to a simple script that reads a timer value from an ini file and use it in the script. And one that use a GUI to input a number and then store it in an INI file. This way, I'd understand better how to do it in my application.
User avatar
evilC
Posts: 4823
Joined: 27 Feb 2014, 12:30

Re: Any workaround for this getkeystate

13 Jun 2018, 10:49

Code: Select all

#SingleInstance force
#NoEnv
#Include AppFactory.ahk

factory := new AppFactory()
factory.AddInputButton("HK1", "w200", Func("InputEvent"))
Gui, Add, Text, xm w94, Timer Frequency:
factory.AddControl("MyEdit", "Edit", "x+5 yp-3 w100", "1000", Func("EditChanged"))
timerRunning := 0

Gui, Show, x0 y0
return

InputEvent(state){
	Global factory, timerRunning
	if (!state)
		return	; Ignore button releases
	timerRunning := !timerRunning
	if (timerRunning){
		; Start of timer. First pull the value from the MyEdit control...
		freq := factory.GuiControls.MyEdit.Get()
		; And use that to set the frequency of the timer
		SetTimer, DoThing, % freq
		ToolTip % "Starting Timer with freq " freq
	} else {
		SetTimer, DoThing, Off
		ToolTip % "Stopping Timer"
	}
}

EditChanged(state){
	global timerRunning
	if (timerRunning){
		; EditBox changed while timer was running. Stop the timer ...
		InputEvent(1)
		; ... then restart with the new time
		InputEvent(1)
	}
}

DoThing:
	return

^Esc::
GuiClose:
	ExitApp
Image
Click "Select Input Button...", press the hotkey you wish to use (eg F12)
The EditBox controls the frequency of the timer (Default is 1000)
F12 starts/stops the timer
If you alter the EditBox while the timer is running, it will stop the timer and restart it at the new frequency.
All settings (Chosen hotkey, timer frequency) are stored in an INI file between runs

Return to “Ask for Help (v1)”

Who is online

Users browsing this forum: Bing [Bot], iamasink, jollyjoe, peter_ahk, RareUserGerman, Rohwedder and 302 guests