用 AutoHotkey 实现【同一按键】在任意界面执行【默认功能】
AutoHotkey 对热键的控制非常强大。可以通过窗口的以下信息综合起来作为条件判断
- class
- 标题
- 程序名
- 控件信息(当前激活控件,当前鼠标所在控件,控件状态,控件值)
正因为有如此强大的判断条件,就可以轻松设计一个(或多个)通用热键(我用 F4
)来针对各种界面的【默认功能】实现一键完成。
首先根据程序名分类
为大部分【主流程序】建个单独的ahk文件(比如微信用 WeChat.ahk
)
并用#HotIf WinActive("ahk_exe WeChat.exe")
来定义动态热键条件(优先级高)
这样后续定义的热键只会在微信生效(其他应用的热键也用此法定义)
以下用 微信 举例
- 在程序里,可能需要根据不同的子窗口做相应的事
- 微信的主界面 class =
WeChatMainWndForPC
- 转发界面 class =
SelectContactWnd
- 设置界面 class =
SettingWnd
- 查看聊天记录界面 class =
FileManagerWnd
(还可定义针对不同人的聊天记录,自动设置默认要查找的内容)
- 另存为界面 class = #32770(大部分的保存对话框都是这个类名,由于有通用性,放到后面通用功能内)
- 微信的主界面 class =
- 如果不匹配,则调用下方定义的【通用函数】
非主流程序
其他通用功能,就不需要单独建文件了,直接由自定义的【通用函数】(如general_smartDo()
)判断执行
步骤
- 程序名(由于程序名可能会带 x64 或【空格】等内容,所以需要做下处理)
exeName := StrReplace(RegExReplace(WinGetProcessName("A"), "i)_?(x?(64))?(\.\w+)?$"), " ", "_")
定义各【程序名】的
map
列表,如果包含exeName
则执行相应的函数(以下都是用此思想判断) class
(获取方法cls := WinGetClass("A")
)
上面提及的通用#32770
保存对话框,我的主需求就是一键保存到桌面,就是在这里定义功能- 标题(获取方法
tt := WinGetTitle("A")
) 其他原理同上 - 控件等其他方式
- 确定没定义功能,则模拟发送F4热键执行原生功能
send("{F4}")
示例代码如下,主要看思路结构
#HotIf WinActive("ahk_exe WeChat.exe") ;指定微信界面的热键
F4::wechat_smartDo() ;在微信界面,则执行此函数(如果函数里都不匹配,可考虑执行通用函数 general_smartDo)
#HotIf WinActive("ahk_exe Excel.exe") ;指定Excel界面的热键
F4::excel_smartDo()
#HotIf ;结束特定界面热键定义,以下是通用的热键
F4::general_smartDo() ;通用功能定义
;微信各界面的默认功能
wechat_smartDo(*) {
if WinActive("ahk_class SelectContactWnd") {
msgbox("【转发】界面的自动化处理")
} else if WinActive("ahk_class ImagePreviewWnd") { ;图片查看
WinGetPos(&winX, &winY, &w, &h)
ControlClick(format("X{1} Y{2}", w//2+14, h-33)) ;图片旋转90度
} else if WinActive("ahk_class SettingWnd") { ;设置界面
msgbox("【设置】界面的自动化处理")
} else ;NOTE 如果微信里没定义,可考虑执行通用的功能
general_smartDo()
}
excel_smartDo(*) {
titleA := WinGetTitle("A")
if WinActive("ahk_class NetUIHWND1") { ;打印页面
msgbox("空白打印页如何解决?")
} else if WinActive("排序") {
t := ControlGetText("REComboBox20W3")
if (t = "升序")
ControlChooseIndex(2, "REComboBox20W3")
else ;选升序
ControlChooseIndex(1, "REComboBox20W3")
} else {
general_smartDo()
}
}
;通用的功能定义模板
general_smartDo(*) {
WinActive("A")
;程序名由于不规则,建议删除 x64等文字,并把空格替换成_
exeName := StrReplace(RegExReplace(WinGetProcessName(), "i)_?(x?(64))?(\.\w+)?$"), A_Space, "_")
cls := WinGetClass()
tt := WinGetTitle()
;exeName
objExe := map(
"rundll32",(p*)=>exe_rundll32(),
)
if objExe.has(exeName) {
objExe[exeName].call()
return
}
;class
objClass := map(
"#32770" , (p*)=>class_32770(),
"TMainFormFontCreator" , (p*)=>class_TMainFormFontCreator(),
)
if objClass.has(cls) {
objClass[cls].call()
return
}
exe_rundll32() {
if WinActive("Internet 属性") {
ControlChooseIndex(5, "SysTabControl321")
send("{alt down}l{alt up}")
}
}
class_32770() {
;先判断保存对话框的数据类型
MouseGetPos(&x, &y, &hwnd, &ctlName)
if instr(ctlName, "ComboBox") {
hCtl := ControlGetHwnd(ctlName)
if (UIA.ElementFromHandle(hCtl).GetCurrentPropertyValue("LegacyIAccessibleState") == 1049092) { ;1049604
_ComboBox(ctlName).selectByText()
return
} else {
tooltip("未扩展")
SetTimer(tooltip, -1000)
}
}
WinActive("A")
sText := WinGetText()
if instr(sText, "MSVCP120.dll") { ;由于找不到 MSVCP120.dll,无法继续执行代码。重新安装程序可能会解决此问题。
WinClose
msgbox(sText)
}
}
}