Autohotkey Input Times Out Because MatchList Isn't Matched - autohotkey

Here's my AHK script
:*:if ::
SendInput IF{Space}
Input cond, I V T5,, then
msgbox %ErrorLevel%
msgbox %cond%
if (ErrorLevel = "Match")
{
SendInput {Enter}End If{Space}'%cond%
}
Return
When I type If x = 1 then I get an ErrorLevel of 'Timeout' and a cond of 'x = 1 then'
My understanding is that when I type then it's supposed to stop the Input and set the ErrorLevel to Match.
I've tried putting it in quotes, using single letters in the MatchList, and including and end key, but none of works. The few examples I could find of using MathList look just like mine.

Input cond, I V T5 *,,% " then"
Without the asterisk option, an item in MatchList needs to be the next thing typed. So If Then would match then in the MatchList. But If anything then doesn't match then in the MatchList because it's trying to match anything then, not just then.
With the asterisk option, if anything then is matched because the next thing typed after If contained then. That causes problems if you type if heathen then because the then in heathen triggers it. The space before then should fix that, but it doesn't.
AHK help says that the MatchList respects spaces, but it doesn't seem to do that when the space is before the first (or only) item in MatchList. The two ways around that are to include a dummy word at the beginning or to use the % thingy to quote the MathList item and include the space.
See also http://ahkscript.org/boards/viewtopic.php?f=5&t=3979

I strongly recommend using RegEx powered hotstrings for this purpose:
#Include <Hotstrings>
hotstrings("if (.*?) then", "If %$1% then``nEnd If%A_SPACE%")

The definition of "T" in the AutoHotkey Help File states this:
T: Timeout (e.g. T3). The number of seconds to wait before terminating the
Input and setting ErrorLevel to the word Timeout. If the Input times out,
OutputVar will be set to whatever text the user had time to enter.
Basically, this is saying exactly what is to be expected (and what is actually happening) with your script. So, for me when I type "if x = 1 then" my "if" is immediately replaced with the caps lock IF and a space.
After 5 seconds, the first MsgBox appears with "Timeout" as the text (again, expected since ErrorLevel is set to the word "Timeout" when the "T" option is present). Once that MsgBox is dismissed, I receive the second MsgBox which (according to the help file) contains OutputVar which is what I (the user) had time to enter in before the Timeout.

Related

Can anyone pls explain this ahk script logics/commands

Can anyone pls tell what is the purpose of two sequential commas and then 1 in the below given ahk script?
Pause:: Suspend
Pause,,1
return
If the script is suspended you can't unpause with that very same button because the hotkey is disabled.
In that case you need to use the OperateOnUnderlyingThread in the Pause command parameters:
Pause,,1 makes a single button (in this case the button Pause or Break) work as both pause and unpause. It allows the Pause command to run a second time (i.e. to unpause).
Pause::
Suspend ; disables or enables all or selected hotkeys and hotstrings.
Pause,,1
return
It indicates that the first parameter is blank.
https://lexikos.github.io/v1/docs/Language.htm#commands
The comma separating the command name from its parameters is optional, except in the following cases:
When it's necessary to prevent the line from being interpreted as a legacy assignment or assignment expression.
MsgBox, := This would be an assignment without the comma.
When the first parameter is blank.
MsgBox,, Second, Third
From https://www.autohotkey.com/docs/commands/Pause.htm :
Pause [, OnOffToggle, OperateOnUnderlyingThread]
OnOffToggle
If blank or omitted, it defaults to Toggle. [...]
Pause,,1 is the same as Pause,Toggle,1
I think I got the answer.
Two commas mean there is a blank value, which in ahk means 'Off'. In other words it'd be perhaps same if it were: Pause, Off, 1
And 1 means on. That means, it is equal to
Pause, Off, On
I'm only 95% sure of the above.

Trying to make a script that takes first word from a txt file, writes it, repeat till all words written

I have a text file, it has several lines. 1 line = 1 word
Now I want a script, if I press a specific button it will write the first word (first line). If I press the button again, the next word will be written, it goes like that till all words are written. I have tried to code it but it will only write the first word and will keep writing it.. It won't take next word and I don't know why because actually I have made a variable that increases...
Here is my code:
F11::
Index = 1
Array := Object()
Loop, Read, C:\Users\Emilia\Desktop\list.txt
{
Array.Push(A_LoopReadLine)
}
Send % Array[Index]
Index++
Use FileReadLine with a line number parameter
Keep the index variable outside in the global context so it doesn't get reset to 1 each time
Use SendPlay to send the word at once, not character-by-character.
You can switch the default send mode with SendMode play command.
Send Enter key at the end by adding {Enter} in the send command.
index = 1
F11::
FileReadLine line, C:\Users\Emilia\Desktop\list.txt, index
SendPlay %line%{Enter}
index++
Return

How to implement something like a select-case-esac structure in AutoHotKey

I am not sure how to start this one. I went through the help files of AHK with no result.
I need to establish a construct like this (this is not in either UNIX shell or in AHK scripting language. Just shows the idea I am after)
while true
do
gosub screenscrape
; here, all text on page is on clipboard
; variable "input" is a predefined portion of the clipboard
case $input in
string-1)
gosub subroutione1;;
string-2)
gosub subroutine2;;
...
*)
echo "not found"
sleep 1minute
done
to make the things more complex, the parts noted as string-1, through string-n are also variables, read in from few different files, depending on time of the day or by trigger from an event.
can someone point me to the right direction for this ?
Autohotkey does not have any case statements. What everyone does is to use if and else statements. (I know how it feels. I like case, too)
A few tips for you:
You can't have that $ or a - in your variable name in autohotkey
...but you CAN have an underscore.
You don't need to terminate your lines with a ;.
Here is a translation into autohotkey for you.
gosub screenscrape
; here, all text on page is on clipboard
; variable "input" is a predefined portion of the clipboard
if(string1){ ;if the variable is not blank it will evaluate to `true`
gosub subroutine1
}else if(string2){
gosub subroutine2
}else{
msgbox not found
sleep 60000 ;milliseconds
}
Also, you can use real functions in autohotkey - you don't have to rely on gosubs. If you use gosubs, make sure you place a return at the end of them. You should also read the autohotkey docs concerning the "auto execute" section.

SendInput %userInput% causes my computer to malfunction oddly

SendInput %userInput% causes my computer to do very weird stuff. Sometimes it logs off, sometimes my arrows of the keyboard get disabled, sometimes it runs cmd in windows an infinite times...
UPDATE:
this is the thing that gets inputed in the command line and runs:
runas /user:administrator cmd
UPDATE:
I think I almost got the problem, as such I edited the question to leave out what I deem to be irrelevant now.
When SendInput is happening, and the user is still inputting data in the keyboard, such as pressing the win-key, then this can cause the system to log off because win-key + l is a shortcut for that. Likewise must be for all the other things that are happening. Another observation is that SendInput skips certain characters, like {enter} etc. It only processes them at the end, when all the regular characters are put into place. I notice that at the end, SendInput is still busy doing stuff, perhaps some exotic characters it delayed till the end. Because the user think the output is complete, he ends up pressing the shortcut key again which in combination with the current sendInput is causing the system to crash.
UPDATE:
It also goes bezerk if there is a "!" to be send with SendInput.
This is one string I pasted to the copyboard:
dsjkfhjdsfsjdh!!!!!!!!!!!####################$$$$$$$$$$$%%%%%%%%%^^^^^^^^^^^^^&&&&&&&&&&&&&*****(((((((((())))))))))))____++++++++++++++++=======------------000000000000000099999988888.
But the output is WITHOUT the exclamation marks. Like this:
dsjkfhjdsfsjdh#######$$$$$$$$$$%%%%%%%%%&&&&&&&&&&&&*****(((((((((())))))))))))____+======------------000000000000000099999988888.
Why is that? Are there any other characters? Exclamation marks are important I feel, and I don't want to remove them. Are there any workarounds?
UPDATE:
It is more complicated than that. When I copy paste the above characters WITHOUT the exclamation marks, it still does weird stuff.
Here is some of the code that eventually userInput combines and sends away with SendInput:
StringReplace, contents, save_selection, ``, ````, All ; Do this replacement first to avoid interfering with the others below.
StringReplace, contents, contents, `r`n, %A_SPACE%, All ; Using `r works better than `n in MS Word, etc.
StringReplace, contents, contents, `;, ```;, All
;* loc_title origanally contains browser specification. Remove it.
StringGetPos, pos_delim, loc_title, - , R
length := StrLen(loc_title)
count := length - pos_delim
StringTrimRight, loc_title, loc_title, count
You could use sendraw instead of sendinput.
Here is what the docs say:
Raw mode: The SendRaw command interprets all characters literally
rather than translating {Enter} to an ENTER keystroke, ^c to
Control-C, etc. However, the normal rules for escape sequences,
variable references and expressions still apply since these are
processed before the command executes. To use raw mode with SendInput,
SendPlay, or SendEvent, write {Raw} as the first item in the string;
for example: SendInput {Raw}abc.
Then you don't have to worry about the ! or other control modifiers.
The reason that the exclamation mark character is an issue is because SendInput treats it as a code to press the Alt key.
There are several similar codes:
^ = Ctrl
+ = Shift
# = Windows key
You can find the others listed in the documentation for SendInput.
It seems like you want to send the raw text and not have SendInput look for these codes. You should be able to put {Raw} at the beginning of the userinput variable and it will ignore any codes in the rest of the characters.
If it is typing too slowly, you could put SetKeyDelay,-1 in your script to remove the key sending delay.
A good workaround that I found was to avoid SendInput altogether. Rather use the clipboard to copy the string inside, to then paste it on your screen. It works flawlessly, and is a billion times faster. Why would a person utilize SendInput in the first place? However, the actual question still is standing, why does SendInput behave so strangely? What is inside that string: %userInput% that causes my system to crash? How can I find out?

Eval / RegExp listen with Autohotkey

I think this must be possible but I can't find it in the documentation anywhere on autohotkey
I want to do something like:
[a-z0-9]::
SoundPlay, %A_WinDir%\Media\[\1].wav
SoundPlay *-1
i.e. listen for all keys a to z and 0-9 find the relevant wav file (a.wav etc..) and play it. If it can't be found Play a default sound.
Is this way out of AHK's league? Should I stick to doing this in python??!
Many thanks in advance
You can use the Hotkey Command to assign all possible hotkeys to the label.
The first loop here uses a trick with converting values to their ASCII codes, doing math, and converting them back to characters. The logic works like, "What is the 5th character after 'a'?" -- to which it replies 'f'.
#Persistent
Loop, 26
Hotkey, % Chr(Asc("a") + A_Index - 1), MyLabel
Loop, 10
Hotkey, % A_Index - 1, MyLabel
return
MyLabel:
MsgBox You pressed %A_ThisHotkey%
return
I'm not aware of a way to use a regex to specify the hotkey, but this is how I've done it in one of my scripts:
#::
a::
b::
c::
; (all other alpha keys...)
; Pass key on, if not in subscription list
If(in_edit_screen())
{
; Handle caps lock
If(GetKeyState("Capslock", "T"))
{
; Send uppercase letter
StringUpper key, A_ThisHotkey
Send %key%
}
Else
{
Send %A_ThisHotkey%
}
Return
}
; etc.
Return
This is part of a routine that's called whenever a certain window is focused, but the window in question has a few different modes; in one of those modes (indicated by the in_edit_screen flag), I want to just pass the keys through, while in another mode, I want the keys to do something special. A_ThisHotkey is the variable that tells the routine which key/key combination the user actually pressed.
Why not launch a script where you use:
Input, CI_KeyVar, I L1
and then read-out which key was pressed (variable = CI_KeyVar), do your thing (check if the ascii code falls between 0 and Z because this input will act on any input) and re-launch the script to wait for the next key press....
The way out would be to trigger on e.g. the esc key, so the script stops.