我的AutoHotKey脚本如何相应地启动批处理脚本? [英] How can my AutoHotKey script launch batch scripts accordingly?
问题描述
该脚本应该将我从Windows切换到Linux(VM),反之亦然:
Pause::vmStart()
return
runVM := false
linux := false
vmStart()
{
If (!runVM and !linux) {
Run, C:\Users\patrick\dev-vm\PS.cmd
runVM := true
sleep, 18000
}
If (!linux and !WinExist("DevVM - 127.0.0.1:23389 - RDP")) {
Run, C:\Users\patrick\dev-vm\RDP.cmd
}
if (!linux) {
WinShow, DevVM - 127.0.0.1:23389 - RDP
WinActivate, DevVM - 127.0.0.1:23389 - RDP
}
Send ^!{CtrlBreak}
linux := !linux
}
- 在Windows中时,它需要先激活我的RDP窗口(有效的方法) 很好).
- 当我使用Windows且VM不是以PS.cmd启动时,它应该启动它(也可以运行,大约需要18秒)
- 使用^!{CtrlBreak}是正常的开关,也可以使用.
我认为方括号/函数/布尔定义有问题.你发现错误了吗?
有一些问题,但只有一个很重要.
首先,您的变量定义是无法访问的代码.
Pause::vmStart()
return
runVM := false
linux := false
代码执行在遇到的第一个热键处停止.
另外,您还在那里有一个Return
,这也将停止代码执行.因此,您确实要确保代码执行永远不会达到变量定义haha.
幸运的是,AHK是超级宽容的,如果您引用尚未声明的任何变量,则会使用默认值 nothing 创建该变量,该默认值还会计算为 false .>
所以这不是实际的问题,但是仍然需要解决.如前所述,将定义移到热键上方,或将其删除,由于AHK的宽容程度,因此不需要它们.
然后进入下一个问题,可变范围.
在该函数的作用域中,您引用的变量不存在,并且每次运行该函数时都会创建并释放它们.
您可以选择几种方法.您可以将变量定义为全局,超级全局(超级全局是一种不好的做法,不建议使用).
将它们定义为全局变量意味着您引用了在函数范围之外找到的变量,并且其值将存储在该变量中.要将变量定义为全局变量,您可以使函数的第一行像这样:
vmStart()
{
global runVM, linux
...
或者您可以仅使函数的第一行成为关键字global
,这意味着该函数假定所有变量都是全局变量.
要将变量定义为静态变量,您将执行与全局变量相同的操作(使用关键字static
).将它们定义为静态基本上意味着它们在函数完成执行后不会释放.因此,下次调用该函数时,它们的值就是您最后一次将其设置为该函数中的值.
要将它们定义为超级全局变量,您可以使用关键字global
在函数外部(在脚本的顶部)定义变量,如下所示:
global runVM := false
global linux := false
Pause::vmStart()
...
这意味着任何试图通过该名称引用变量的范围都将使用您的超级全局变量.这是一种不好的做法,并且可能会很危险,尤其是在使用外部库的情况下.不会意外破坏某物不会太难.
当然,当您有一个像这样的小脚本时,无论使用哪种方法都没有什么区别.甚至我也承认有时在我的个人脚本上使用super global,只是因为不必担心作用域是很方便的.
如果您想听听我的建议,我会说去找静态变量.
这完全是您在这里所做的事情.
这是您的成品(进行了一些其他更改),以防万一我的解释不够清楚:
Pause::vmStart()
;the 'return' here did nothing for us, removed
vmStart()
{
;using the static keyword to make the function assume
;all variables are static, and also skipped even
;declaring the variables, not needed due to how forgiving AHK is
static
;got rid of the 'and' keyword in your if statements
;that's legacy syntax, big ew, it's not 2005
If (!runVM && !linux) {
Run, C:\Users\patrick\dev-vm\PS.cmd
runVM := true
sleep, 18000
}
;removed braces, one-liner statments don't need them
;just personal preference though, of course
If (!linux && !WinExist("DevVM - 127.0.0.1:23389 - RDP"))
Run, C:\Users\patrick\dev-vm\RDP.cmd
if (!linux) {
WinShow, DevVM - 127.0.0.1:23389 - RDP
WinActivate, DevVM - 127.0.0.1:23389 - RDP
}
;switched to SendInput, it's faster and more reliable
SendInput, ^!{CtrlBreak}
linux := !linux
}
This script is supposed to switch me from Windows to Linux(VM) and vice versa:
Pause::vmStart()
return
runVM := false
linux := false
vmStart()
{
If (!runVM and !linux) {
Run, C:\Users\patrick\dev-vm\PS.cmd
runVM := true
sleep, 18000
}
If (!linux and !WinExist("DevVM - 127.0.0.1:23389 - RDP")) {
Run, C:\Users\patrick\dev-vm\RDP.cmd
}
if (!linux) {
WinShow, DevVM - 127.0.0.1:23389 - RDP
WinActivate, DevVM - 127.0.0.1:23389 - RDP
}
Send ^!{CtrlBreak}
linux := !linux
}
- When I am in Windows, it needs to activate my RDP window first (what works fine).
- When I am in Windows and the VM was not started with PS.cmd, then it should launch it (what also works and takes about 18 sec)
- Using ^!{CtrlBreak} is the normal switch that also works.
I think that there is something wrong with my brackets/function/boolean definition. Do you find the mistake?
Has a few problems, but just one that matters.
Firstly, your variable definitions are unreachable code.
Pause::vmStart()
return
runVM := false
linux := false
Code execution stops at the first hotkey that is met.
In addition you also have a Return
in there, which would also stop code execution. So you really are making sure code execution will never reach the variable definitions haha.
Luckily AHK is super forgiving and if you reference any variable that hasn't been declared yet, it's created with the default value of nothing, which also evaluates to false.
So that wasn't the actual problem, but still something that needs fixing. Move the definitions to be above your hotkey, or just remove them, they're not needed due to how forgiving AHK is, as explained above.
Then onto the next problem, variable scope.
In that function's scope the variables you reference don't exist, and they're created and freed every time you run the function.
You have a few options you can do. You can either define the variables as global, static, or super global (super global is bad practice and not recommended).
Defining them as global means you reference a variable that's found outside of the function's scope and its value will be stored there. To define the variables as global, you'd make the first line(s) of your function do that like this:
vmStart()
{
global runVM, linux
...
Or you could just make the first line of function be nothing but the keyword global
, and that means the function assumes all variables are global.
To define the variables as static, you'd do the same as for global (with the keyword static
). Defining them as static basically means they aren't freed after the function completes its execution. So next time you call the function their value is what you last set it to be in the function.
To define them as super global, you'd define the variables outside of the function (at the very top of your script) with the keyword global
like this:
global runVM := false
global linux := false
Pause::vmStart()
...
This would mean any scope anywhere that tried to reference a variable by that name would use your super global variable. This is bad practice and can be dangerous to do, especially if you use external libraries. Wouldn't be too hard to accidentally break something.
Of course when you have a little script like that, is makes no difference whatsoever what method you use. Even I confess to sometimes using super global on my personal scripts, just because it's quite convenient to not have to worry about scopes.
If you'd like to hear my recommendation, I'd say go for static variables.
It's pretty much exactly intended for what you're doing here.
Here's your finished product (with some miscellaneous changes) in case I didn't explain something well enough:
Pause::vmStart()
;the 'return' here did nothing for us, removed
vmStart()
{
;using the static keyword to make the function assume
;all variables are static, and also skipped even
;declaring the variables, not needed due to how forgiving AHK is
static
;got rid of the 'and' keyword in your if statements
;that's legacy syntax, big ew, it's not 2005
If (!runVM && !linux) {
Run, C:\Users\patrick\dev-vm\PS.cmd
runVM := true
sleep, 18000
}
;removed braces, one-liner statments don't need them
;just personal preference though, of course
If (!linux && !WinExist("DevVM - 127.0.0.1:23389 - RDP"))
Run, C:\Users\patrick\dev-vm\RDP.cmd
if (!linux) {
WinShow, DevVM - 127.0.0.1:23389 - RDP
WinActivate, DevVM - 127.0.0.1:23389 - RDP
}
;switched to SendInput, it's faster and more reliable
SendInput, ^!{CtrlBreak}
linux := !linux
}
这篇关于我的AutoHotKey脚本如何相应地启动批处理脚本?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!