Win+Tab键实现自定义程序列表间的窗口切换
程序是用AutoHotkey语言写的,
说明:
以自己使用频率的顺序在ExeList自定义的程序间切换
切换可以以所有窗口切换,也可以按程序组切换(比如在word窗口间切换)
程序组可以分别定义排除的窗口(比如想激活QQ聊天界面,但是想排除QQ主窗口)
切换顺序:
如果当前激活程序在列表内,并有多个同类程序,则优先切换到同类窗口(比如打开多个word)
否则切换到ExeList里按顺序第一个找到的窗口
使用方法:
按热键后继续按Tab键则在所有匹配的窗口间切换,按应用热键则切换到程序窗口,按其他任意虚拟按键则脚本退出
各程序可以分别设置热键,比如Word设置为W,Excel设置为E,按W就可以切换到Word组,继续按W,会在Word窗口间切换
要求:
在应用程序名后面增加\加标题名,增加排除的标题名,比如QQ.exe排除标题为abc的窗口,则写QQ.exe\abc
在应用程序名后面增加&字母,则为给该类应用增加热键,否则默认为程序名第一个字母
示例:每个应用程序格式QQ.exe\QQ&Q,因为QQ.exe第一个字母为Q,最后的&Q可省略,各应用之间用|隔开
下载:https://files.cnblogs.com/files/hyaray/WinTab.7z
#Tab:: ;特定窗口间切换 ExeList := "excel.exe|WINWORD.EXE|PotPlayerMini64.exe|Xmind.exe|Foxit_Reader.exe" ;前面的窗口优先,别忘了.exe后缀 ;看当前窗口是否在列表里,如果在,则标记InList = 1,并移动到列表第一项 WinGet, pn, ProcessName, A ;获取当前窗口应用名,如notepad.exe InList := InStr(ExeList, pn) ? 1 : 0 ;当前窗口在列表里,记录变量InList If (InStr(ExeList, pn) > 2) ;当前窗口移到ExeList最前面 { List_Tmp := "" Loop, Parse, ExeList, | List_Tmp := (InStr(A_LoopField, pn)) ? A_LoopField . "|" . List_Tmp : List_Tmp . A_LoopField . "|" ExeList := Trim(List_Tmp, "|") ;去除两边的|符,防止A_LoopField出来空值 } ;通过ExeList获取窗口信息并存入ObjTotal和ObjKeyAndNum ;下面的变量说明:i为每个应用找到的有效窗口数 ObjTotal := {} ;把所有匹配窗口信息写入此对象 ObjKeyAndNum := {} ;以热键分组,把匹配的窗口信息写入此对象 total := 0 ;记录所有匹配窗口总数,ObjTotal用 Loop, Parse, ExeList, | { ;获取应用程序名name Loop, Parse, A_LoopField, &\| { name := A_LoopField Break } ;获取快捷键k(后面找到的窗口都放在k对应的对象里) If InStr(A_LoopField, "&") ;自定义了快捷键 k := SubStr(A_LoopField, InStr(A_LoopField, "&") + 1) ;&后一位为快捷键 Else { StringLeft, k, A_LoopField, 1 ;默认首字母当快捷键 StringUpper, k, k } ;获取排除窗口标题数组ms p2 := InStr(A_LoopField, "\") If p2 ;有排除窗口内容 ms := hyf_gREP_Match(A_LoopField, "(?<=\\).*?(?=\\|&|$)") ;获取当前应用所有有效窗口列表 WinGet, idList, List, Ahk_exe %name% ;获取当前应用所有窗口ID i := 0 ;记录当前应用提取窗口数 Loop,% idList ;遍历窗口ID,提取想要的窗口 { tt := hyf_winGet("title", "Ahk_id " . idList%A_Index%) ;过滤空标题(有些隐藏程序,比如hh.exe)2015-08-02 19:22:26 If (tt = "") Continue ;过滤自定义标题(若有) If p2 { For k, m In ms { If (tt = m.value(0)) Continue 2 ;跳到Loop,% ID的下个循环(找下个窗口) } } ;记录匹配窗口的各类信息(关键)★★★★★★★★★★★★★★★★★★★★★★★★★★★★ ;心得:如果以应用程序为出发点,记录多个窗口的数据,理解上就需要3维数组,这结构更像是树状的,不是数组的标准结构 ;但是以窗口为出发点,还是简单的2维数组,好理解多了。。。 i++ total++ ;把ID值写入两个对象,因为索引有两种方式 ObjTotal[total] := {"hwnd":IDList%A_Index%, "key": k, "exe": name, "title":tt} ObjKeyAndNum[k, i] := {"hwnd":IDList%A_Index%, "key": k, "exe": name, "title":tt} } } ;该If判断匹配窗口为0或1个时,特殊处理后,提示信息并退出脚本 If (total = 0) hyf_tooltip("没有找到窗口,脚本退出", , 1) Else If (total = 1) { If InList hyf_tooltip("当前已是唯一目标窗口,脚本退出", , 1) Else { hyf_winActivate(ObjTotal[1].hwnd, "ID") hyf_tooltip("已激活唯一窗口,脚本退出", , 1) } } Else If (total = 2) && InList ;有2个窗口,且当前已在其中1个窗口 { Num_InTotal := Mod(hyf_getKeyOfValueInObj1(ObjTotal, hyf_winGet("ID"), "hwnd"), total) + 1 hyf_winActivate(ObjTotal[Num_InTotal].hwnd, "ID") hyf_tooltip("共2个窗口,已激活另一个窗口,脚本退出", , 1) } ;有2个及2个以上匹配窗口时按热键后的操作 Num_InTotal := InList ? 2 : 1 ;在列表则直接切换到第2个窗口,否则切换第1个找到的窗口 hyf_winActivate(ObjTotal[Num_InTotal].hwnd, "ID") ;列出热键列表和窗口列表 Key_All := "" Win_All := "" Num_Tmp := 0 For k1, v1 In ObjKeyAndNum For k2, v2 In v1 { If !InStr(key_All, k1) Key_All .= v1[1].exe "热键为" . k1 . "`n" } For k1, v1 In ObjTotal Win_All .= A_Index . ": " . v1.title . "`n" ;这里开始自定义按键并跳转到相应的程序,脚本主要功能。 ToolTip,% "等待按键(Tab或数字或字母键)`n按其他键则脚本退出。`n`n窗口列表:`n" . Win_All Loop ;等待按键继续切换 { kp := hyf_waitKeyAndReturn() If (kp = "Tab") ;按Tab则依次切换到下个窗口 { Num_InTotal := Mod(hyf_getKeyOfValueInObj1(ObjTotal, hyf_winGet("ID"), "hwnd"), total) + 1 hyf_winActivate(ObjTotal[Num_InTotal].hwnd, "ID") hyf_tooltip("您按下了" . kp . "键,窗口位置为" . Num_InTotal . "/" . total . "`n`nPS:按窗口热键会在热键窗口内切换。`n您识别到的应用名和热键分别为:`n" . key_All, 2) Continue } Else If hyf_isWord(kp) ;是字母,则判断是否存在该热键窗口 { If ObjKeyAndNum[kp,1].hwnd ;存在该热键窗口 { If (hyf_winGet("ProcessName") = ObjKeyAndNum[kp,1].exe) ;如果按的热键和当前窗口一样,则跳到该类的下一个窗口 { kn := ObjKeyAndNum[kp].MaxIndex() i := Mod(hyf_getKeyOfValueInObj2(ObjKeyAndNum, hyf_winGet("ID"), "hwnd")[2], kn) + 1 hyf_winActivate(ObjKeyAndNum[kp, i].hwnd, "ID") hyf_tooltip("您按下了" . kp . "键,已激活热键内第" . i . "/" . kn . "个窗口`n`nPS:按Tab会按总窗口顺序切换") } Else { hyf_winActivate(ObjKeyAndNum[kp, 1].hwnd, "ID") hyf_tooltip("您按下了" . kp . "键`n之前窗口和该窗口不同类,已激活热键第1个窗口", 2) } Continue } Else ;不存在该快捷键窗口 hyf_tooltip("按键" . kp . "不是热键,脚本退出", 2, 1) Continue } Else If hyf_isNum(kp) ;是数字,则直接跳到该窗口 { If ObjTotal[kp].hwnd { hyf_winActivate(ObjTotal[kp].hwnd, "ID") hyf_tooltip("您按下了" . kp . "键`n之前窗口和该窗口不同类,已激活热键第1个窗口`n窗口列表:`n`n" . Win_All, 2) } Else hyf_tooltip("按键" . kp . "无效,脚本退出", , 1) Continue } Else hyf_tooltip("按键" . kp . "无效,脚本退出", , 1) } Return hyf_gREP_Match(str, zz) ;全局正则 {{{3 { ;ms.value(0), ms.Len(0), ms.Pos(0)分别存储子项目的值,长度和位置 options := "U)^[imsxACDJOPSUX`a`n`r]+\)" zz := (RegExMatch(zz, options, Opt) ? (InStr(Opt, "O", 1) ? "" : "O") : "O)") . zz m := {Len:{0:0}} ms := [] p := 1 While (p := RegExMatch(str, zz, m, p + m.Len[0])) ms[A_Index] := m Return ms } hyf_winGet(cmd := "title", WinTitle := "A") ;不支持Pos等多变量输出命令 {{{3 { If (cmd = "title") WinGetTitle, v, %WinTitle% Else If (cmd = "Class") WinGetClass, v, %WinTitle% Else If (cmd = "Text") WinGetText, v, %WinTitle% Else WinGet, v, %cmd%, %WinTitle% Return v } hyf_tooltip(str, t := 1, ExitScript := 0, x := "", y := "") ;提示t秒并自动消失 {{{3 { t *= 1000 ToolTip, %str%, %x%, %y% SetTimer, hyf_removeToolTip, -%t% If ExitScript { Gui, Destroy Exit } } hyf_winActivate(t, m := "") ;可以支持对象的值,m为Ahk_后面的值,如ID, Class, pid, exe等 {{{3 { t := (m = "") ? t :"Ahk_" . m . A_Space . t WinActivate %t% } hyf_getKeyOfValueInObj1(obj, value, key := "") ;获取单索引参数对象里的k键匹配v值的键 {{{3 { ;比如获取obj[n] = {"a":x1, "b":y1}里键b的值为3的序号n,则函数参数为(obj, 3, "b"),若为数组,则key="" If (key = "") { For k, v In obj If (v = value) Return k } Else { For k, v In obj If (v[key] = value) Return k } } hyf_waitKeyAndReturn(k := "All", t := "") ;t秒内等待按下任意键并返回按键名或超时(个人修改版) {{{3 { If (t != "") t := "T" . t Suspend On If (k = "All") || (k = "A") Input, SingleKey, I%t%, ``0123456789-=:[]\'./ABCDEFGHIJKLMNOPQRSTUVWXYZ{LControl}{RControl}{LAlt}{RAlt}{LShift}{RShift}{LWin}{RWin}{Enter}{Escape}{CapsLock}{AppsKey}{F1}{F2}{F3}{F4}{F5}{F6}{F7}{F8}{F9}{F10}{F11}{F12}{Left}{Right}{Up}{Down}{Home}{End}{PGUP}{PGDN}{Del}{Ins}{BS}{CapsLock}{NumLock}{Numpad0}{Numpad1}{Numpad2}{Numpad3}{Numpad4}{Numpad5}{Numpad6}{Numpad7}{Numpad8}{Numpad9}{NumpadDot}{NumpadDiv}{NumpadMult}{NumpadAdd}{NumpadSub}{NumpadEnter}{PrintScreen}{ScrollLock}{Pause}{Space}{Tab}`,; ;最后为需要转义的特殊符号,;放最后只是避免语法错误显示 Else If (k = "xsj") ;修饰键,包括了Tab Input, SingleKey, I%t%, {Tab}{LControl}{RControl}{LAlt}{RAlt}{LShift}{RShift}{LWin}{RWin}{Enter}{Escape}{CapsLock}{AppsKey}{F1}{F2}{F3}{F4}{F5}{F6}{F7}{F8}{F9}{F10}{F11}{F12}{Left}{Right}{Up}{Down}{Home}{End}{PGUP}{PGDN}{Del}{Ins}{BS}{CapsLock}{NumLock}{NumpadDot}{NumpadDiv}{NumpadMult}{NumpadAdd}{NumpadSub}{NumpadEnter}{PrintScreen}{ScrollLock}{Pause} ;最后为需要转义的特殊符号,;放最后只是避免语法错误显示 Else Input, SingleKey, I%t%, %k% Suspend Off Return (ErrorLevel = "TimeOut") ? "TimeOut" : SubStr(ErrorLevel, 8) } hyf_isWord(char) ;是否字母 {{{3 { Return (char ~= "i)[a-z]") } hyf_getKeyOfValueInObj2(obj, value, key := "") ;获取双索引参数对象里的k键匹配v值的键,返回数组 {{{3 { ;比如获取obj[m][n] = {"a":x1, "b":y1}里键b的值为3的序号m和n,则函数参数为(obj, 3, "b") o := {} If (key = "") { For k1, v1 In obj For k2, v2 In v1 If (v2 = value) { o[1] := k1 o[2] := k2 Return o } } Else { For k1, v1 In obj For k2, v2 In v1 If (v2[key] = value) { o[1] := k1 o[2] := k2 Return o } } } hyf_isNum(char) ;是否数字 {{{3 { Return (char ~= "\d") } hyf_removeToolTip() ;清除ToolTip {{{3 { ToolTip }