How can I find the problem in the script I wrote in AHK - autohotkey

I'm making a macro of a game, and I tried a different thing, and now it doesn't seem to be working. I added if Lf := 1 and if Rg := 1 which are variables to represent the radio indicator. Here's the code:
F9::
toggle :=!Toggle
if (toggle)
{
SetTimer, Repeat, 100
Repeat()
}
else
SetTimer, Repeat, Off
return
Repeat()
{
Click, 920, 885
Sleep, 200
if (Lf := 1)
{
Click, 755, 530
Sleep, 200
Click, 550, 530
}
else if (Rg := 1)
{
Click, 1165, 530
Sleep, 200
Click, 1370, 530
}
Sleep, 200
Send, {Space Down}
Sleep, %MilSecOne%
Sleep, %MilSecOne%
Send, {Space Up}
Sleep, 200
}
It doesn't work as I expected.

The := operator is used to assign a value (which will be the result of an expression) to a variable.
So right now what you're doing, is assigning the number 1 to your variables, and then checking with the if-statement if the value of that variable evaluates to true.
(And it always will, non-zero numbers evaluate to true)
You're looking for the = operator.
In an expression (which is what your if ( ) -statement is) it compares values, rather than assigns text to a variable, which is what it does in a legacy statement.
So, change
if (Lf := 1)
else if (Rg := 1)
to
if (Lf = 1)
else if (Rg = 1)
Edit:
I'm also noticing that the variables Lf and Rg doesn't seem to exist?
At least not in that function's scope.
I hope they're defined as super-global somewhere else.
Otherwise there's no way that code is going to work.

Related

How to check if clipboard is equal to a predetermined number, or several numbers in AHK?

; Copy cell
var := clipboard
sleep, 1000
WinActivate, doesntmatter - Internet Explorer
IfEqual 30684047, %var%
{
sleep, 500
Send, inform
}
else
{
msgbox, nope
}
return
My problem is that even though I have the correct number (30684047) in the clipboard, the code still goes straight to the MsgBox and tells me that the clipboard (%var%) isnt equal to the predetermined code.
What am i missing? I am 100% sure that %var% contains my copied code from the clipboard because if i do a MsgBox with %var% after i copy it, it gives me a box containing that correct code.
Look back at the documentation for IfEqual...you switched var and value.
; Copy cell
var := clipboard
sleep, 1000
WinActivate, doesntmatter - Internet Explorer
IfEqual, var, 30684047
{
sleep, 500
Send, inform
}
else
{
msgbox, nope
}
return
There's really no need to save off the value of clipboard to a different variable unless you're wanting to re-use that value after clipboard has later changed. So the above could also be:
WinActivate, doesntmatter - Internet Explorer
If (clipboard = "30684047") {
sleep, 500
SendInput, inform
}
else
msgbox, nope
return

MATLAB auto completing start and end statements of code body?

Is it possible in MATLAB to automatically insert start and end of a code body ?
For example: classdef and end; function and end; methods and end.
classdef Circle
properties
radius
end
methods
function dia = FindDia(obj)
dia = [obj.radius]*2;
end
function %no automatic insertion of 'end'
end
end
Since I work regularly in so many different editors, I don't rely on any one editor's features. It's a pain to learn them all and keep the configuration for all these editors in sync, on all my machines. Often, it's useful to have the same feature set I'm used to, in editors not even meant for code (like MS Word, or here on Stack Overflow).
Therefore, I use AutoHotkey for this kind of thing (and Autokey on Linux).
For functions and classes, I use a paste function to paste a specific template file, depending on whether I'm at work or at home, and which project I'm working on. A small GUI then asks me for the function or class name, which it then populates the template with. I can share that too if you want.
Below are a few AutoHotkey functions and hotstrings I use for including the end keyword. Note that this might all seem overly complex just to put an end there, and in this case, it probably is. But the clipCopy, clipPaste and getIndent functions have proven their usefulness in the rest of my programming snippets, and I hope they might be for you too.
I've thrown in the error functions as well, just because.
; Copy selected text
; More robust than C-c/C-x/C-v; see
; https://autohotkey.com/board/topic/111817-robust-copy-and-paste-routine-function/
clipCopy(dontRestoreClipboard := 0)
{
prevClipboard := Clipboard
Clipboard := ""
copyKey := "vk43sc02E" ; Copy
SendInput, {Shift Down}{Shift Up}{Ctrl Down}{%copyKey% Down}
ClipWait, 0.25, 1
SendInput, {%copyKey% Up}{Ctrl Up}
str := Clipboard
if (dontRestoreClipboard == 0)
Clipboard := prevClipboard
return str
}
clipPaste(ByRef txt, dontBackupClipboard := 0)
{
if (txt != "")
{
prevClipboard := ""
pasteKey := "vk56sc02F" ; Paste
if (dontBackupClipboard == 0) {
prevClipboard := Clipboard
Clipboard := ""
}
Clipboard := txt
ClipWait, 1.00, 1
; Start pressing paste key
SendInput, {Shift Down}{Shift Up}{Ctrl Down}{%pasteKey% Down}
; Wait until clipboard is ready
startTime := A_TickCount
while (DllCall("GetOpenClipboardWindow") && (A_TickCount - startTime < 1000)) {
Sleep, 50
}
; Release paste key
SendInput, {%pasteKey% Up}{Ctrl Up}
; TODO: a manual delay still seems necessary...this vlaue needs to be this large, to also have
; correct behavior in superslow apps like MS Office, Outlook, etc. Sadly, the SetTimer approach
; does not seem to work (doesn't correctly restore the clipboard); to be investigated.
Sleep 333
; Put previous clipboard content back onto the clipboard
Clipboard := prevClipboard
}
}
; Get current indentation level in an editor-independent way
getIndent(dontRestoreClipboard := 0)
{
; Select text from cursor to start of line
SendInput, +{Home}
indent := clipCopy(dontRestoreClipboard)
numsp := 0
if (indent != "")
indent := RegExReplace(indent, ".", " ", numsp)
; Undo selection (this is tricky; different editors often have
; different behavior for Home/End keys while text is selected
SendInput, {Right}{Left}{Home}
; NOTE: don't use {End}, because we might be in the middle of a sentence
; Use the "right" key, repeatedly
Loop, %numsp% {
SendInput, {Right}
}
return indent
}
mBasic(str)
{
current_indent := getIndent()
SendInput, %str% (){Enter}+{Home}%current_indent%{Space 4}{Enter}+{Home}%current_indent%end{Up 2}{End}{Left}
}
mErrfcn(str)
{
current_indent := getIndent()
spaces := RegExReplace(str, ".", " ")
clipPaste(str . "([mfilename ':default_errorID'],...`r`n" . current_indent . spaces . " 'Default error string.');")
return current_indent
}
; MATLAB Hotstrings for basic control structures
:o:mfor::
mBasic("for")
return
:o:mpar::
mBasic("parfor")
return
:o:mwhile::
mBasic("while")
return
:o:spmd::
mBasic("spmd")
return
:o:mif::
mBasic("if")
return
; ...etc.
; error, warning, assert
:o:merr::
:o:merror::
mErrfcn("error")
SendInput, {Up}{End}{Left 21}
return
:o:mwarn::
:o:mwarning::
mErrfcn("warning")
SendInput, {Up}{End}{Left 21}
return
_mlAssert()
{
current_indent := mErrfcn("assert")
SendInput, {Up}{End}{Left 34}true,...{Enter}+{Home}%current_indent%{Space 7}{Up}{End}{Left 8}
}
:o:massert::
_mlAssert()
return

How do I condense multiple similar hotkeys into one in AutoHotkey?

I'm trying to create hotkeys to simulate input buffering in an online game I'm playing which doesn't natively support input buffering, meaning mashing a spell key so that it goes off after the previous spell is finished casting is the best method to manually do.
With the help of a hotkey I can loop the key press with minimal delay by holding down my key so that it sends the instant I'm done casting the previous spell.
However creating multiple hotkeys for each button I have bound on my keyboard to a spell seems tedious and I'm not sure how to condense these hotkeys into one using an array of defined keys (ie. 1 through 6, and F1 through F6)
An example snippet of my code so far with only 3 keys taken into account:
$5::
{
Loop
{
Loop, 5
{
Send, 5
Sleep, 1
}
GetKeyState, state, 5
if state = U
break
}
return
}
$2::
{
Loop
{
Loop, 5
{
Send, 2
Sleep, 1
}
GetKeyState, state, 2
if state = U
break
}
return
}
$F2::
{
Loop
{
Loop, 5
{
Send, {F2}
Sleep, 1
}
GetKeyState, state, F2
if state = U
break
}
return
}
I'm trying to condense it to something like this, if possible:
hotkeys := [5, 2, F2]
hotkeyCount := hotkeys.MaxIndex()
curKey := 1
Loop, hotkeyCount
{
hotkeyIndex := hotkeys[curKey]
$%hotkeyIndex%::
{
Loop
{
Loop, 5
{
Send, {%hotkeyIndex%}
Sleep, 1
}
GetKeyState, state, %hotkeyIndex%
if state = U
break
}
return
}
curKey := curKey + 1
}
Create a FIFO stack that will safe the preset actions and call them when they are ready.
Array functions contains the functions: Function_a, Function_b, Function_c, that are triggered with their respective hotkeys, a, b, c.
The hotkeys don't call the functions directly, but add their numerical index the to the stack stack.
The timer check, retrieves the numerical index from the stack, then the function from the array functions at that index is called. When the function returns, the next index is retrieved if there is any. Only one functions is running at a time.
SetBatchLines, -1
global stack := Object()
global stack_head = 0
global stack_tail = 0
global functions := [Func("Function_a"),Func("Function_b"),Func("Function_c")]
SetTimer, check , 25
return
check:
if( stack_head > stack_tail )
{
i := stack[stack_tail]
functions[i]()
stack_tail++
}
return
Function_a()
{
tooltip, Function_a running...
Sleep, 1000
tooltip,
return
}
Function_b()
{
tooltip, Function_b running...
Sleep, 1000
tooltip,
return
}
Function_c()
{
tooltip, Function_c running...
Sleep, 1000
return
}
a::
stack[stack_head] := 1
stack_head++
return
s::
stack[stack_head] := 2
stack_head++
return
d::
stack[stack_head] := 3
stack_head++
return
This enables concurrent running of the functions, that can do whatever you want, while at the same time hotkeys can add actions (functions indexes) to the stack, which will be called in order they were added one at a time.
I have edited you example to make it functional:
$a::
$s::
$d::
$1::
key := A_ThisHotkey
key :=Trim(key,"$")
Loop
{
Loop, 5
{
SendInput, %key%
Sleep, 1
}
state := GetKeyState(key , "P" )
if state = 0
{
break
}
}
return

Send hotkeys own default behavior

How can I send a keys default (from hardware) behavior in its own key definition. I mean this code:
vcerc = 0
+c::
vcerc := !vcerc
Return
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
kkey = 0
$k::
if vcerc {
kkey := !kkey
if kkey
SendInput {k down}
else
SendInput {k up}
}
else {
Send, K
}
Return
In the end part Send, K It sends the word K. I am in a multi language environment which means if I switch to the other, This key still sends K rather than sending the one that is for the second language (assume ن).
How can I make this send the default? (From hardware with no matter what the language is)
Two things that seem off to me: 1) Your initial kkey declaration will never get hit since it falls after a hotkey (and a return). Declare your variables at the top. 2) if kkey is true, your script has it holding down the k button indefinitely. Is this expected? 3) Your only looking for lowercase k's but sending uppercase k's. Is this expected?
At any rate, this example should point you in the right direction.
vcerc = 0
kkey = 0
+c::
vcerc := !vcerc
return
$k::
{
if (vcerc) {
kkey := !kkey
if (kkey) {
msgbox, k down ; SendInput {k down}
} else {
msgbox, k up ; SendInput {k up}
}
} else {
Send, K
}
}

Temporarily Pause Autofire loop on holding button

I wrote a script that sends autofire left clicks and can be triggered on and off. The script works. However, the problem is that holding the right mouse button does not work properly anymore because the left click keeps getting sent. So I want to change the script that it gets temporarily paused while I hold down the right mouse button.
How would I go about doing this? Here is my current code:
#MaxThreadsPerHotkey 3
#z::
#MaxThreadsPerHotkey 1
if keep_winz_running = y
{
keep_winz_running = n
return
}
; Otherwise:
keep_winz_running = y
Loop
{
GetKeyState, rbut, Rbutton
If rbut, = U
{
Loop,
{
MouseClick, left
Sleep, 50 ;This means the script will wait 1.5 secs
if keep_winz_running = n ; The user signaled the loop to stop.
break ; break out of the loop
}
Timers are the best!
sendToggle := false
#z::
if(!sendToggle) {
sendToggle := true
SetTimer, SendClick, 100
} else {
sendToggle := false
SetTimer, SendClick, Off
}
return
#If sendToggle
RButton::
SetTimer, SendClick, Off
KeyWait, RButton
SetTimer, SendClick, 100
return
SendClick:
Click
return
I find the send interval of 50 ms awfully fast, especially since you won't be able to actually reach 50 ms without reducing SetBatchLines and SetKeyDelay. If it really needs to be that fast, consider changing them.