I have a number of hotkeys which go through various processes and sleep for certain periods of time to allow animations to be shown. I want to setup a variable to allow only 1 to activate at a time...so if I hit the first and then the second....the second doesn't do anything until the first completes. Similarly I don't want to double activate any of them by mashing the same key right after I first press it.
F4:ExitApp
#IfWinActive ahk_class notepad
a::
if (work:=true){
work:=false
soundbeep
;do something
sleep 1000
work:=true
}
return
b::
if (work:=true){
work:=false
soundbeep
;do something else
sleep 2000
work:=true
}
return
i.e. if I hit 'a'....'b' cannot activate until the sleep of 'a' ends. Nor should 'a' be able to activate a second time...at least not until its sleep ends and work=true again.
This leaves 2 problems. I need to first somehow specify the initial value of 'work=true'. I do not know how to do this in the traditional sense. Simply putting it at the top of the code doesn't work. Second problem, putting this in another key...like enter:: work:=true return....and pressing that key initially...this doesn't work as it allows b to beep while a is still in its sleep phase. So maybe the code above is flawed to begin with as well. Individual keys seem to respect themselves and not re-initialize until after the first instance has completed...so the beeps work if I just mash 1 key. Also I don't want to have to press enter to get the code to work after loading the script.
Is there an easy cheat here? Like in lua undeclared variables are automatically false... so I could just swap to if (work=false){...., I can't find any such behaviour with autohotkey though.
As requested, here is a different solution that uses variable logic to allow or prevent hotkey commands from executing:
#IfWinActive ahk_class Notepad
work:=true
a::
if(work){
work:=false
soundbeep
;do something
sleep 1000
work:=true
}
return
b::
if(work){
work:=false
soundbeep
;do something else
sleep 2000
work:=true
}
return
Update: Breakdown of how it works
First, the script begins in the auto-execute section. As summarized elegently by maul-esel
When an AutoHotkey script launches, it just starts execution from the
first line of your script. It continues from there line by line until
it hits an end point. This is called the auto-execute section.
As such, by including work:=true in this section of the script, not only are we initializing the value of the variable before any hotkeys are triggered, we set the scope of work to be a global variable, accessible across different hotkeys.
The rest of the script is a bit more straightforward, where each hotkey is essentially (in pseudocode):
When the hotkey is triggered
if work is true
set work to false
Beep and etc.
Wait for some amount of time
Then set work back to true so that another command can be run
End the hotkey
One simple way to do it would be to declare #MaxThreads 1 at the top of your script.
As a side note, there appear to be a few other syntax errors in the script. For example, when comparing values (like in an if statement), you still use the regular, single = and not the assignment :=. Also, the ahk_class is case sensitive, and as such #IfWinActive ahk_class notepad should be replaced with #IfWinActive ahk_class Notepad.
Updated Code (Work Variable logic was removed as it is no longer needed):
#MaxThreads 1
#IfWinActive ahk_class Notepad
a::
soundbeep
;do something
sleep 1000
return
b::
soundbeep
;do something else
sleep 2000
return
Related
So my understanding is that after command can be used to delay the execution of a script or a command for certain ms but when i execute the below command, the output is printed immediately
Command:
after 4000 [list puts "hello"]
Output:
hello
after#0
Question: Why was the output not delayed for 4s here?
That what you wrote works; I just tried it at a tclsh prompt like this:
% after 4000 [list puts "hello"]; after 5000 set x 1; vwait x
Did you write something else instead, such as this:
after 4000 [puts "hello"]
In this case, instead of delaying the execution of puts, you'd be calling it immediately and using its result (the empty string) as the argument to after (which is valid, but useless).
Think of [list …] as a special kind of quoting.
The other possibility when running interactively is that you take several seconds between running the after and starting the event loop (since the callbacks are only ever run by the event loop). You won't see that in wish of course — that's always running an event loop — but it's possible in tclsh as that doesn't start an event loop by default. But I'd put that as a far distant second in terms of probability to omitting the list word…
I want to write a wow macro that has the character say one of 2 statements and I want to be able to choose which statement. I'm fine with either having a sequence (alternates between each message), having the game detect if the player has a buff or not, or having the game detect if a modifier key (such as alt, shift, ctrl) is being held. If I wanted to create a macro for a spell, I would just use
/cast [mod] spell1
/cast [nomod] spell2
but this does not work with a /s command (I've tried). I've tried diving into basic Lua code, but have not been able to make it work. Here's what I have tried using a Lua if then else command that tests to see if the player has a buff or not (I used "Travel Form" as a placeholder buff on my druid)
/run if (UnitAura("player", "Travel Form"))
then SendChatMessage("Statement1","say")
else SendChatMessage("Statement2","say")
end
Thanks in advance for any help you can provide!
Here are two examples with using modifier keys. They are a bit condensed because I like my macros short.
https://wowpedia.fandom.com/wiki/API_IsModifierKeyDown
/run SendChatMessage(IsModifierKeyDown() and "Statement1" or "Statement2")
https://wowpedia.fandom.com/wiki/API_SecureCmdOptionParse
/run SendChatMessage(SecureCmdOptionParse("[mod] Statement1; Statement2"))
As for checking if you have e.g. a buff (by name), you need to iterate the indices for UnitAura() or use GetPlayerAuraBySpellID (less compact example)
/run if GetPlayerAuraBySpellID(783) then SendChatMessage("Statement1") else SendChatMessage("Statement2") end
I've noticed that if I press up arrow at a prompt then I get the previous command and up again gets me the command before that.
Whereas if I press up arrow before the previous program has completed then instead I get the previous command displayed, the cursor is at the end of the line, but oh-my-zsh is now in "search for lines that start with ... " mode meaning I can't press up to get the previous command.
I'm sure this behavior is well known and expected but just in case you don't get it you can repo it like this
Type ls return
Type sleep 3 return
wait 3 seconds for prompt to appear
press ⬆ (should show sleep 3)
press ⬆ again (should show ls)
press return (to run ls)
Type sleep 3 return ⬆ (press the up arrow before the 3 seconds elapses)
It should now be showing sleep 3
Press ⬆
it will still be showing sleep 3 but it want it to be showing ls. Instead it is in "search for commands that start with sleep 3 mode instead of just go to previous command mode.
To make try to clear in both cases these are the steps
lsreturn
sleep 3return
⬆
⬆
But they end up with different results depending on if step3 happens before or after step2 finishes.
Note I saw this Q&A: https://unix.stackexchange.com/questions/324623/how-to-make-oh-my-zsh-history-behavior-similar-to-bashs
But that doesn't seem to be what I'm looking for. I like oh-my-zsh's partial line + up = search for lines that start with the partial. What I'm trying to fix is that if I press up on step 2 above it magically inserts a partial where as if I wait until step 2 finishes it doesn't.
How do I get oh-my-zsh to be consistent here so that a premature up arrow behaves the same as a normal up arrow?
I'm surprised this question isn't common. It's seriously infuriating to have the terminal act inconsistently. I'd except most devs using oh-my-zsh to run into this issue all the time and be massively frustrated.
The example above with sleep 3 is only to make it easy to show the problem. In actual usage the problem happens frequently even with short lived commands. I type say git status return git commit somefile -m "short comment" return ⬆⬆ expecting to see "git status". 66% of the time I get git status and the other 34% I get `git commit somefile -m "short comment" and pressing ⬆ again just blinks the cursor and I have to press Ctrl-C to break out of zsh's partial complete mode.
The fact that this does not seem to be a common complaint for oh-my-zsh makes me wonder if I have something setup wrong.
To make it clearer run zsh without oh-my-zsh.
zsh -d -f
autoload -U up-line-or-beginning-search
zle -N up-line-or-beginning-search
bindkey "^[[A" up-line-or-beginning-search
Now try the steps above. You'll get consistent behavior.
This might be an overkill solution but, following this guide you can see that you can bind new actions to the up/down arrow key. So if you add:
bindkey "^[[A" up-line-or-beginning-search # Up
bindkey "^[[B" down-line-or-beginning-search # Down
to your ~/.zshrc, it should remove the functionality you talked about. I managed to get it to work while still maintaining regular search capabilities but this is not thoroughly tested and should probably be used with care.
A script is waiting for a process to start; it shall do so indefinitely, but only as long as there is no human input. In another words: the script shall wait for either process start or human input, whichever comes first (also, the process may already be running when the script starts, in which case the script shall close immediately). I have thought of something like this, but there’s likely a better way, since this loop doesn’t break with input:
while (A_TimeIdlePhysical > 100) {
Process, Wait, SomeProcess.exe
}
Any ideas?
Tested with notepad:
#Persistent
SetTimer, DetectProcess, 50
return
DetectProcess:
If (ProcessExist("notepad.exe")) ; if the process is already running
ExitApp
; otherwise:
If (A_TimeIdlePhysical > 100) ; as long as there is no human input
{
If (ProcessExist("notepad.exe")) ; wait for either process start
ExitApp
}
else ; or human input
ExitApp
return
ProcessExist(ProcessName){
Process, Exist, %ProcessName%
return Errorlevel
}
I wanted to create a "VLC-screensaver" script:
When the user/system is idle for a certain time VLC should start and play a video from a specified folder. I can start the script and VLC is being executed by it after the set time. Now I exit it with "Esc" and VLC closes.
After I closed it the AHK-tray is visible but VLC/the script is not starting again after the set time...
Where is the mistake? Thank you in advance!
#Persistent
SetTimer, Check, 1000
return
Check:
If (A_TimeIdle>=10000)
{
run C:\Program Files\VideoLAN\VLC\vlc.exe --repeat --fullscreen "D:\video"
SetTimer, Check, Off
}
return
#IfWinActive ahk_exe vlc.exe
Escape::Send !{F4}
#IfWinActive
return
Got it by myself:
#IfWinActive ahk_exe vlc.exe
Escape::
Send !{F4}
Reload
#IfWinActive
Return
Forgot that you can assign more than one action/paramter/value to one
key...