naocist
naocist

Reputation: 15

How to exit a loop depending on how long I keep a key pressed?

How can I end this loop depending on how long I keep X pressed? If I hold X for five seconds it should send B, S, C, Y, and U at one second intervals.

When I hold X for one second it should only send B, if I hold X for two seconds it should send B and S, etc. Currently it simply sends B, S, C, Y, and U.

*$x::
While(GetKeyState("x", "P"))
{
send b
Sleep 1000
send s
Sleep 1000
send c
Sleep 1000
send y
Sleep 1000
send u
Sleep 1000
}
Return

Solution does not have to be a loop.

Upvotes: 1

Views: 1170

Answers (3)

T_Lube
T_Lube

Reputation: 331

This post is so old, but I just can't help it.

sendChars := "bscyu"
$x::
i := 1 ; (!i ? 1 : i) ; permits starting where left off.
While (getKeyState("x", "P")) {
    Send % subStr(sendChars, i, 1)
    i := ((i==strLen(sendChars)) ? 1 : (i+1))
    if (getKeyState("x", "P")) { ; why wait if you don't have to.
        Sleep 1000
    }
}

The docs point out that a While loop is only evaluated at the beginning of each iteration, so listing all the keys in a loop will just send all the keys, then break out of loop once at that top again and sees that "x" is no longer being pressed.

Upvotes: 0

Dewi Morgan
Dewi Morgan

Reputation: 1239

I can see a few possible approaches.

1) The first and perhaps worst is to have an if... to test the keystate, and an exit, after every single send. This is extremely repetitive, but not too terrible if you stick it in a function, and just call that, something like:

*$x::
while (GetKeyState("x", "P")) {
    sendStuff('b')
    sendStuff('s')
    sendStuff('c')
...
}

sendStuff(str) {
    Send str
    if (!GetKeyState("x", "P")) {
        exit
    }
    sleep 1000
}

2) The next is to continue operating as you are, with a chained series of commands, and have an external, separate script kill that series of commands while running, then re-Run() your script when you wish to restart. Killing external scripts is covered in the FAQ, here: http://www.autohotkey.com/docs/FAQ.htm#close

There are three relevant sections there which are a little long to paste here, but in summary, you may be interested in the following commands:

; Allow script's hidden main window to be detected.
DetectHiddenWindows On
; Avoid need to specify full path of file.
SetTitleMatchMode 2
; Kill another script: Update params to the script's case sensitive name.
WinClose Script Filemame.ahk - AutoHotkey
; Suspend other script.
PostMessage, 0x111, 65305,,, Script Filename.ahk - AutoHotkey
; Pause other script.
PostMessage, 0x111, 65306,,, Script Filename.ahk - AutoHotkey
; Pause/resume current script on Ctrl+Alt+P
^!p::Pause

3) There's also a longer code sample just below that, which describes canceling a loop, and it's my belief that this is the correct approach to this problem, as while it might be fiddlier initially, it is considerably more scalable, reduces code duplication, and permits you to handle multiple loop entry/exit conditions in a single place.

It is, in short, the best in terms of Programming Style.

Place the entries (b, s, c, y, u) that you wish to sent into a string, array or other iterable datastructure, and iterate over it, so that your while loop sends only a single item and a pause each iteration. Then the next time you hit your hotkey, you can either resume the loop from where you left off, or start over, depending on whether you maintain a pointer to your current position in the structure.

For example, using the above sendStuff function, a loop will give you the very powerful and trivially extensible:

*$x::
{
    letters = b,s,c,y,u
    Loop, parse, letters, `,
        sendStuff(%A_LoopField%)
    return
}

Upvotes: 0

Travis Quick
Travis Quick

Reputation: 71

x::
  index:="i"
  letters:="l"
  output:="o"
  l:="bscyu"
  i:=(i<o0?++i:1)
  StringSplit,o,l
  send % o%i%
  sleep,1000
return

x Up::i:=0

Upvotes: 1

Related Questions