判定TC中空白处是一个困难,一些截图软件例如QQ截图、Snipaste等可以判断屏幕上一些远小于控件的元素,查阅发现是一种适合屏幕阅读的功能——ACC,尝试通过这种方式实现功能。
为防止窗口被列表占满,特地添加了右键双击功能。
#SingleInstance, Force #NoEnv ;~ #Persistent /* 提权, 使用管理员模式 */ if not A_IsAdmin { Run *RunAs "%A_ScriptFullPath%" ; 需要 v1.0.92.01+ ExitApp } ;~ 定义基本全局变量 global TCWins:={}, TCTitle := "ahk_class TTOTAL_CMD", DClkDelay:=300 ;~ 建立TC的对象 loop 4 { TCWins[A_Index] := {Name:"LCLListBox" A_Index} } ;~ 监控计时 SetTimer, MouseOver, 1 ;~ 首次检测 TestTCWin() ;~ sbox(TCWins) ;~ 快捷键定义 Hotkey, IfWinActive, % TCTitle Hotkey, ~LButton, ButtonClick Hotkey, ~RButton, ButtonClick return ;~ 通过定义对象判断TC窗口控件 /* 数据结构 LCLListBox 四个控件会随机成为TC左右窗,因此要进行判断 这个对象收集基本信息,可能一些信息在本例子中用不到,但思路是建立数据,方便扩展 0001: 键名:< 1 > 4个窗口的编号 0002: |-键名:< CanClick > 是否列表窗口 0002: |-键名:< Name > 键值:< LCLListBox1 > 名称 0002: |-键名:< NotTree > 判定控件是否树窗口状态 0002: |-键名:< Visible > 键值:< 1 > 是否当前可用 0001: 键名:< 2 > 0002: |-键名:< CanClick > 键值:< 1 > 0002: |-键名:< Name > 键值:< LCLListBox2 > 0002: |-键名:< NotTree > 键值:< 1 > 0002: |-键名:< Visible > 键值:< 1 > 0001: 键名:< 3 > 0002: |-键名:< CanClick > 键值:< 1 > 0002: |-键名:< Name > 键值:< LCLListBox3 > 0002: |-键名:< NotTree > 键值:< 1 > 0002: |-键名:< Visible > 键值:< 1 > 0001: 键名:< 4 > 0002: |-键名:< CanClick > 0002: |-键名:< Name > 键值:< LCLListBox4 > 0002: |-键名:< NotTree > 键值:< 1 > 0002: |-键名:< Visible > 0001: 键名:< LCLListBox2 > 控件名 0002: |-键名:< 1 > 键值:< 2 > 对应编号 0002: |-键名:< 2 > 键值:< 0x20ae8 > 实时 hwnd 值 0001: 键名:< LCLListBox3 > 0002: |-键名:< 1 > 键值:< 3 > 0002: |-键名:< 2 > 键值:< 0x20aee > */ TestTCWin() { loop 4 { tObj := TCWins[A_Index] ControlGetText, text, % tObj.Name, % TCTitle ControlGet, Visible, Visible,, % tObj.Name, % TCTitle tObj.NotTree := !(text~="W_TreeList") , tObj.Visible := Visible , tObj.CanClick := tObj.NotTree && tObj.Visible , TCWins["LCLListBox" A_Index] := tObj.CanClick?[A_Index, getClassNNHwnd("LCLListBox" A_Index)]: } } ;~ 激发双击模式后的处理 ButtonClick: ;~ 是否双击判定 if (A_ThisHotkey!=A_PriorHotkey) return ;~ 双击延迟判定 if (A_TimeSincePriorHotkey>DClkDelay) return ;~ 当前是否可双击 if !isCanClick return ;~ 获取当前鼠标下控件的ACC状态,byref 变量 Child 可判定当前鼠标下是否有子Acc模块,如有则不是“空白处” MouseGetPos, OutputVarX, OutputVarY Acc_ObjectFromPoint(Child, OutputVarX, OutputVarY) ;~ 判定是否空白处双击,是则发送返回上层目录消息 ;~ 发送消息的防错能力远高于发送键击 if (RB:=RegExMatch(A_ThisHotkey, "^~R")) || !Child && !RB Postmessage, 1075, 2002,,, % TCTitle return ;~ 监控鼠标悬停状态,功能是减少程序占用 MouseOver: ;~ 监控当前是否悬停于TC上 WinGetClass, OutputVar, A if !(isTCWin := RegExMatch(TCTitle,OutputVar)) { return } ;~ 获取当前悬停控件 MouseGetPos, , , , OutputVaRControl TestTCWin() OutputVaRControl := Trim(OutputVaRControl) , isNotOut:=(OldOutputVaRControl=OutputVaRControl) ;~ 悬停控件是否切换, if isNotOut return OldOutputVaRControl := OutputVaRControl ;~ 悬停于左右窗口时全速运行,否则降低占用 if (isCanClick:=TCWins[OutputVaRControl]) { SetBatchLines, -1 } else { SetBatchLines, 20ms } return getClassNNHwnd(ClassNN:="") { ControlGet, Hwnd, Hwnd,, % ClassNN, % TCTitle return Hwnd } ;~ Acc代码 Acc_Init() { Static h if Not h h:=DllCall("LoadLibrary","Str","oleacc","Ptr") } Acc_ObjectFromPoint(ByRef _idChild_ = "", x = "", y = "") { Acc_Init() if DllCall("oleacc\AccessibleObjectFromPoint", "Int64", x==""||y==""?0*DllCall("GetCursorPos","Int64*",pt)+pt:x&0xFFFFFFFF|y<<32, "Ptr*", pacc, "Ptr", VarSetCapacity(varChild,8+2*A_PtrSize,0)*0+&varChild)=0 return ComObjEnwrap(9,pacc,1), _idChild_:=NumGet(varChild,8,"UInt") }
非常感谢大神完善,不过我测试了下acc鼠标下控件判断,发现不是很有效,有时候误判,比如点击文件夹时候检测出来控件数为0
这个样本是判定鼠标下ACC元素未原则的,而且是实施了双击动作以后才进行判断,可能实现过程有瑕疵,对 ACC 的机理了解不是很透彻. 还是希望有大神能够解惑.
纯属抛砖引玉了
支持