本文主要介绍 aardio + AutoHotkey 混合编程。
在 aardio 中可以调用很多编程语言,例如 C语言、C++、C#、Java、Python、R、Javascript、Node.Js、Fortran、VB、Flash ActionScript、PHP、VBScript、PowerShell、NewLISP、AutoLISP、Delphi、FreeBASIC、Ruby、Rust、Julia、Nim、Go 语言、批处理 ...... 请参考《 aardio 调用第三方编程语言示例》。
1、双击打开:aardio 工具 / 扩展库
2、扩展库名字输入 ahk,搜索结果中双击 ahk 扩展库 —— 打开最新范例。
aardio 提供了 ahk 扩展库可用于嵌入 AutoHotkey 并与 AutoHotkey 交互调用,支持 AutoHotkey v1 以及 AutoHotkey v2 版本。
▶ aardio 调用 AutoHotkey v1
aardio 可以直接调用 AutoHotkey 函数,AutoHotkey 也可以调用 aardio 函数,非常简单:
import win.ui; /*DSG{{*/ var winform = win.form(text="嵌入 AutoHotkey v1 演示") winform.add( edit={cls="edit";left=17;top=18;right=741;bottom=445;edge=1;multiline=1;z=1} ) /*}}*/ //导入 AutoHotkey v1 扩展库 import ahk; /* 导出允许AutoHotkey 调用的 aardio 函数(函数名必须以 on 开头)。 */ ahk.onTest = function(param){ winform.edit.print( "winform.onTest被ahk调用",param ); winform.show(); } //运行ahk代码 ahk.run( ` #Persistent ;保持 AHK 线程不退出 #NoTrayIcon ;不显示托盘图标 #include <aardio> ;启动 AHK 代码中必须加入这句才能与 aardio 交互 ; 定义函数与 aardio 有点像,aardio 一般会写为 GetPoint = function(hwnd){ return value;} GetPoint(){ ; 直接调用aardio函数,支持任意类型、不定个数的调用参数 aardio.onTest({ x : 2, y : 3 }) return { x : 2, y : 3 } }`); /* 直接调用ahk里定义的全局函数, 参数和返回值自动支持各种数据类型,就像调用普通aardio函数。 是不是很神奇?! */ var point = ahk.GetPoint(); winform.edit.print("调用ahk函数的返回值:",point); win.loopMessage();
请注意 aardio 中文件路径以斜杆(或反斜杆)开始表示应用程序根目录,应用程序根目录在开发时指工程目录或工程外独立启动的文件所在目录,发布后指 EXE 所在目录。应用程序根目录已设为 AHK 工作目录 %A_WorkingDir% 。
导出 aardio 函数给 ahk 时也可以返回一个异步执行的函数对象,调用虚拟桌面示例:
import ahk; import dotNet.desktop; import win.ui; /*DSG{{*/ var winform = win.form(text="虚拟桌面切换";right=599;bottom=399) winform.add( edit={cls="edit";left=17;top=18;right=565;bottom=374;edge=1;multiline=1;z=1} ) /*}}*/ //导出 AutoHotkey 函数 ahk.onSwitch = function(index){ winform.edit.print("已切换桌面到:",index); //虚拟桌面在键盘钩子中需要通过返回异步函数异步调用。 return function() { dotNet.desktop.get(index).MakeVisible() } } //运行 AutoHotkey 代码注册热键 ahk.run( ` #Persistent #NoTrayIcon #include <aardio> ^j:: aardio.onSwitch(1) ^k:: aardio.onSwitch(2) `); winform.show(); win.loopMessage();
如果在 aardio 中执行以下代码:
ahk.import("path/libName");
则由 aardio 导入
\AutoHotkey\Lib\path\libName.ahk
可以在 aardio 工程中添加上面的 ahk 文件 到内嵌资源目录,这样该 ahk 文件会被编译到 exe 资源内,运行时自动转存为以下文件:
%A_MyDocuments%\AutoHotkey\Lib\path\libName.ahk
在 AHK 中可以使用以下代码引用该模块:
#include <path/libName>
在 aardio 中可使用 ahk.setGlobal() 函数修改 AHK 全局变量:
//直接修改 AHK 全局变量的值 ahk.setGlobal("gVar","测试一下")
在 aardio 中执行 AHK 代码时还可以支持 aardio 模板语法,也就是在 AHK 代码中可以直接写 aardio 代码,只要将 aardio 代码包含在 <? ?> 标记中就可以了(类似 PHP 模板语法),例如:
//运行 AHK 代码 ahk.run( ` #Persistent ; #NoTrayIcon ; #include <aardio> ; global gVar := "<?="允许嵌入 aardio 代码"?>" ; `); //直接修改 AHK 全局变量的值 ahk.setGlobal("gVar","测试一下")
关于 aardio 模板语法请参考 aardio 文档。
▶ aardio 调用 AutoHotkey v2
在 aardio 使用 ahk.thread 扩展库可以调用 AutoHotkey v2,ahk.thread 不再需要在 AHK 启动代码中包含 #include <aardio>,其他用法与调用 ahk 扩展库类似。下面看例子:
import win.ui; /*DSG{{*/ var winform = win.form(text="嵌入 AutoHotkey v2 演示") winform.add( edit={cls="edit";left=8;top=10;right=749;bottom=452;edge=1;multiline=1;z=1} ) /*}}*/ winform.show(); import ahk.thread; var ahk2 = ahk.thread(); //直接定义允许 AHK 调用的 aardio 函数(函数名以on开头) ahk2.onTest = function(param){ winform.edit.print( "winform.onTest被ahk调用",param ); return 123 } //运行 AHK 代码 ahk2.run( ` #NoTrayIcon ;不显示托盘图标 Persistent( true) ;保持ahk线程不退出 ; 定义函数与 aardio 有点像,aardio 一般会写为 GetPoint = function(hwnd){ return value;} GetPoint(){ ; 直接调用aardio函数,支持任意类型、不定个数的调用参数 aardio.onTest({ x : 2, y : 3 }) return { x : 2, y : 3 } }`); /* 直接调用ahk里定义的全局函数, 参数和返回值自动支持各种数据类型,就像调用普通aardio函数。 是不是很神奇?! */ var point = ahk2.GetPoint(); winform.edit.print("调用ahk函数的返回值:",point); win.loopMessage();
要注意 AHK 中的变量默认是局部变量,定义全局变量要用 global 语句,aardio 则是默认全局变量,定义局部变量要用 var 语句。
▶ 进阶
有了前面的基础,我们再将范例稍微整复杂一点,例如调用 AHK v1 :
import win.ui; /*DSG{{*/ var winform = win.form(text="嵌入 AutoHotkey v1") winform.add( edit={cls="edit";left=17;top=18;right=734;bottom=444;edge=1;multiline=1;z=1} ) /*}}*/ import ahk; ahk.onTest = function(param){ winform.edit.print( "winform.onTest被ahk调用",param ); winform.show(); } ahk.run( ` #Persistent #NoTrayIcon #include <aardio> GetPoint(){ ; 命令式语法 = 号后面是字符串,变量要放到百分号里 POINT_TYPE = ( UInt x; UInt y; ) ; 首尾两个括号都必须独占一行,用于包含多行字符串 ; 新语法 := 后面是表达式,和其他编程语言类似字符串放引号里,变量不用放百分号里 point := Struct( POINT_TYPE ) ; ; 取结构体指针,aardio 里调用 API 时结构体总是自动转为指针,不需要写这些代码 ptr := point[] ; DllCall("user32.dll\GetCursorPos", "Ptr", ptr) GetCursorPos(ptr) ; ; 直接调用aardio函数,支持任意类型、不定个数的调用参数 aardio.onTest({ x : point.x, y : point.y }) ; 命令式语法, 百分号加一个空格表示后面是表达式 MsgBox, % "x:" point.x ",y:" point.y return { x : point.x, y : point.y } }`); /* 直接调用ahk里定义的全局函数 */ var point = ahk.GetPoint(); winform.edit.print("调用ahk函数的返回值:",point); win.loopMessage();
以上主要是演示 aardio 与 AHK 交互,其实 aardio 直接调用 ::User32.GetCursorPos() 代码更简单,示例:
// 当然上面的代码用 aardio 直接写会更简单,例如: var point = {int x;int y}; //不用声明直接调用 API,不用写参数类型这些 ::User32.GetCursorPos(point);
aardio 可以免声明直接调用 WinAPI ,不需要指定参数类型。
下面再来个例子,使用 aardio 暂停、继续 AHK 脚本:
import fonts.fontAwesome; import win.ui; /*DSG{{*/ var winform = win.form(text="嵌入autohotkey演示";right=757;bottom=467) winform.add( button={cls="plus";text="暂停AHK";left=19;top=11;right=109;bottom=41;bgcolor=-6960024;font=LOGFONT(name='FontAwesome';charset=0);z=2}; edit={cls="edit";left=17;top=56;right=729;bottom=443;edge=1;multiline=1;z=1} ) /*}}*/ import ahk; var handle = ahk.run( ` #Persistent ;保持ahk线程不退出 #NoTrayIcon ;不显示托盘图标 #include <aardio> ;启动ahk代码中必须加入这句才能与aardio交互 ::hj::run无乱码 `); winform.button.onMouseClick = function(){ if(winform.button.text=="暂停AHK"){ thread.suspend(handle) winform.button.text = "继续AHK" } else { thread.resume(handle) winform.button.text = "暂停AHK" } } winform.button.skin({ color={ active=0xFFFFFFFF; default=0xFF000000; hover=0xFFFFFFFF }; }); winform.show(); win.loopMessage();