1、先识别,再绑定热键
2、利用ACC技术来识别非标窗口的按钮, 需要用 Accview工具查看按钮的Name属性
3、全部源代码如下,F4键绑定为播放/暂停功能,其它热键类同:
;功能:用ACC技术控制酷狗播放器
;作者:sunwind
;微信:sunwind1576157
;版本:V0.1
#Persistent
#SingleInstance,force
SetBatchLines,-1
SetTitleMatchMode, 2
F2::酷狗音乐("上一首")
F3::酷狗音乐("下一首")
F4::酷狗音乐("播放/暂停")
F5::酷狗音乐("我喜欢")
return
酷狗音乐(命令)
{
AccKugo := Acc_ObjectFromWindow(WinExist("酷狗音乐 ahk_class kugou_ui"))
GetElementByName(AccKugo, 命令).accDoDefaultAction(0)
return
}
GetElementByName(AccObj, name) {
if (AccObj.accName(0) = name)
return AccObj
for k, v in Acc_Children(AccObj)
if IsObject(obj := GetElementByName(v, name))
return obj
}
; The code below is part of the Acc.ahk Standard Library by Sean (updated by jethrow)
; Found at http://autohotkey.com/board/topic/77303-/?p=491516
Acc_Init()
{
static h
If Not h
h:=DllCall("LoadLibrary","Str","oleacc","Ptr")
}
Acc_ObjectFromWindow(hWnd, idObject = 0)
{
Acc_Init()
If DllCall("oleacc\AccessibleObjectFromWindow", "Ptr", hWnd, "UInt", idObject&=0xFFFFFFFF, "Ptr", -VarSetCapacity(IID,16)+NumPut(idObject==0xFFFFFFF0?0x46000000000000C0:0x719B3800AA000C81,NumPut(idObject==0xFFFFFFF0?0x0000000000020400:0x11CF3C3D618736E0,IID,"Int64"),"Int64"), "Ptr*", pacc)=0
Return ComObjEnwrap(9,pacc,1)
}
Acc_Query(Acc) {
Try Return ComObj(9, ComObjQuery(Acc,"{618736e0-3c3d-11cf-810c-00aa00389b71}"), 1)
}
Acc_Children(Acc) {
If ComObjType(Acc,"Name") != "IAccessible"
ErrorLevel := "Invalid IAccessible Object"
Else {
Acc_Init(), cChildren:=Acc.accChildCount, Children:=[]
If DllCall("oleacc\AccessibleChildren", "Ptr",ComObjValue(Acc), "Int",0, "Int",cChildren, "Ptr",VarSetCapacity(varChildren,cChildren*(8+2*A_PtrSize),0)*0+&varChildren, "Int*",cChildren)=0 {
Loop %cChildren%
i:=(A_Index-1)*(A_PtrSize*2+8)+8, child:=NumGet(varChildren,i), Children.Insert(NumGet(varChildren,i-8)=9?Acc_Query(child):child), NumGet(varChildren,i-8)=9?ObjRelease(child):
Return Children.MaxIndex()?Children:
} Else
ErrorLevel := "AccessibleChildren DllCall Failed"
}
}
以下是网友飞跃写的代码,考虑了不同版本酷狗的兼容性问题,供参考:
/*
;-----------------------------------
; ACC控制酷狗音乐 - By FeiYue
;
; 备注:热键可以改为自己喜欢的
;-----------------------------------
*/
#NoEnv
;-- 获取【Acc路径】及其他信息
F1::
obj:=Acc_GetInfoUnderCursor()
MsgBox, 4096,, % "Path = " obj.Path
. "`nTitle = " obj.Title "`nClass = " obj.Class
. "`nRole = " obj.Role "`nState = " obj.State
. "`nName = " obj.Name "`nValue = " SubStr(obj.Value,1,100)
return
;-- 获取所有【Acc路径】及文本
F8::
MouseGetPos,,, id
MsgBox, 4096,, % Clipboard:=""
. Acc_GetAllText(id, info:={role:"", name:"", value:""})
return
F2:: 酷狗音乐("上一首")
F3:: 酷狗音乐("下一首")
F4:: 酷狗音乐("播放/暂停")
F5:: 酷狗音乐("我喜欢")
酷狗音乐(命令)
{
SetBatchLines, -1
SetTitleMatchMode, 2
DetectHiddenWindows, On
WinGet, List, List, 酷狗音乐 ahk_exe KuGou.exe
IfLess, List, 1, return
Loop, % List
{
id:=List%A_Index%
WinGetPos,,, w, h, ahk_id %id%
if (A_Index=1 or w*h>max)
okid:=id, max:=w*h
}
酷狗9:={ "上一首" : "4.2.X.16.1|4.3.X.16.1"
, "播放/暂停" : "4.2.X.16.2|4.3.X.16.2"
, "下一首" : "4.2.X.16.3|4.3.X.16.3"
, "我喜欢" : "4.2.X.15.1|4.3.X.15.1" }
酷狗8:={ "上一首" : "4.3.7.13.1"
, "播放/暂停" : "4.3.7.13.3"
, "下一首" : "4.3.7.13.2"
, "我喜欢" : "4.3.7.X.5" }
For k,v in [酷狗9, 酷狗8]
For k2,v2 in StrSplit(v[命令], "|")
if (arr:=Acc_GetObjectFromPath(okid, v2, {name:命令}))
{
Try arr[1].accDoDefaultAction(arr[2])
msgbox % arr[2]
return
}
}
;==================================================
Acc_GetAllText(hwnd, info="", first=1)
{
static arr, text
if (first)
arr:=[], text:="", hwnd:=Acc_ObjectFromWindow(hwnd, 0)
arr.Push(0)
For i,v in Acc_Children(Acc:=hwnd)
{
arr[arr.length()]++, path:=""
Loop, % arr.length()
path.=(A_Index=1 ? "" : ".") . arr[A_Index]
Role:=Name:=Value:="", j:=IsObject(v)
Try Role:=j ? v.accRole(0) : Acc.accRole(v)
Try Name:=j ? v.accName(0) : Acc.accName(v)
Try Value:=j ? v.accValue(0) : Acc.accValue(v)
path:=j ? path : RegExReplace(path, "(\w+)$", "c$1")
if (!info.role||Role=info.role)
and (!info.name||Name~=info.name)
and (!info.value||Value~=info.value)
text.=path " ---- " Acc_GetRoleText(Role) " "
. Format("0x{:X}",Role) " [" SubStr(Name,1,60)
. "][" SubStr(Value,1,60) "]`r`n"
if (j)
Acc_GetAllText(v, info, 0)
}
arr.Pop()
if (first)
return (s:=text, text:="") ? s:s
}
Acc_GetObjectFromPath(hwnd, path, info="", Acc=0, first=1)
{
if (first)
hwnd:=Acc_ObjectFromWindow(hwnd, 0)
if !IsObject(v:=hwnd) and !IsObject(Acc)
return
Loop, Parse, path, ., c C
{
if !IsObject(Acc:=v)
return
if (i:=A_LoopField)="X"
{
path:=Trim(SubStr(path, InStr(path,"X")+1), ".")
For k,v in Acc_Children(Acc)
if (arr:=Acc_GetObjectFromPath(v,path,info,Acc,0))
return arr
return
}
if (j:=Acc.accChildCount) " A_LoopField, Acc_Error(AccError)
if Acc_Error()
throw Exception("Cannot access ChildPath Item", -1, "Item #" A_Index " -> " A_LoopField)
return
}
Acc_Error(AccError)
StringReplace, Cmd, Cmd, %A_Space%, , All
properties.HasKey(Cmd)? Cmd:=properties[Cmd]:""
try
{
if (Cmd = "Location")
ret_val := Acc_Location(AccObj,ChildId+0).pos
else if (Cmd = "Object")
ret_val := AccObj
else if Cmd in Role,State
ret_val := Acc_%Cmd%(AccObj, ChildID+0)
else if Cmd in ChildCount,Selection,Focus
ret_val := AccObj["acc" Cmd]
else
ret_val := AccObj["acc" Cmd](ChildID+0)
}
catch
{
ErrorLevel := """" Cmd """ Cmd Not Implemented"
if Acc_Error()
throw Exception("Cmd Not Implemented", -1, Cmd)
return
}
return ret_val, ErrorLevel:=0
}
if Acc_Error()
throw Exception(ErrorLevel,-1)
}
Acc_Location(Acc, ChildId=0) ; adapted from Sean's code
{
try Acc.accLocation(ComObj(0x4003,&x:=0), ComObj(0x4003,&y:=0)
, ComObj(0x4003,&w:=0), ComObj(0x4003,&h:=0), ChildId)
catch
return
return { x:NumGet(x,0,"int"), y:NumGet(y,0,"int")
, w:NumGet(w,0,"int"), h:NumGet(h,0,"int")
, pos:"x" NumGet(x,0,"int")" y" NumGet(y,0,"int")
. " w" NumGet(w,0,"int") " h" NumGet(h,0,"int") }
}
Acc_Parent(Acc)
{
try parent:=Acc.accParent
return parent?Acc_Query(parent):""
}
Acc_Child(Acc, ChildId=0)
{
try child:=Acc.accChild(ChildId)
return child?Acc_Query(child):""
}
Acc_Init()
{
Static h
If (!h)
h:=DllCall("LoadLibrary","Str","oleacc","Ptr")
}
Acc_WindowFromObject(pacc)
{
Acc_Init()
If DllCall("oleacc\WindowFromAccessibleObject", "Ptr"
, IsObject(pacc)?ComObjValue(pacc):pacc, "Ptr*", hWnd)=0
return hWnd
}
Acc_ObjectFromEvent(ByRef _idChild_, hWnd, idObject, idChild)
{
Acc_Init()
If DllCall("oleacc\AccessibleObjectFromEvent", "Ptr", hWnd
, "UInt", idObject, "UInt", idChild, "Ptr*", pacc, "Ptr"
, VarSetCapacity(varChild,8+2*A_PtrSize,0)*0+&varChild)=0
return ComObjEnwrap(9,pacc,1), _idChild_:=NumGet(varChild,8,"UInt")
}
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_ObjectFromWindow(hWnd, idObject = -4)
{
Acc_Init()
If DllCall("oleacc\AccessibleObjectFromWindow"
, "Ptr", hWnd, "UInt", idObject&=0xFFFFFFFF, "Ptr", (VarSetCapacity(IID,16)
+NumPut(idObject==0xFFFFFFF0?0x0000000000020400:0x11CF3C3D618736E0,IID,"Int64")
+NumPut(idObject==0xFFFFFFF0?0x46000000000000C0:0x719B3800AA000C81,IID,8,"Int64"))*0
+&IID, "Ptr*", pacc)=0
return ComObjEnwrap(9,pacc,1)
}
Acc_Children(Acc, N="")
{
if ComObjType(Acc,"Name") != "IAccessible"
ErrorLevel := "Invalid IAccessible Object"
else
{
Acc_Init(), cChildren:=Acc.accChildCount, Children:=[]
if DllCall("oleacc\AccessibleChildren", "Ptr",ComObjValue(Acc)
, "Int",0, "Int",cChildren, "Ptr",VarSetCapacity(varChildren
, cChildren*(8+2*A_PtrSize),0)*0+&varChildren, "Int*",cChildren)=0
{
ListLines, % (lls:=A_ListLines=0?"Off":"On")?"Off":"Off"
SetBatchLines, % (bch:=A_BatchLines)?"-1":"-1"
Loop, %cChildren%
i:=(A_Index-1)*(A_PtrSize*2+8), child:=NumGet(varChildren,i+8)
, Children[A_Index]:=( (j:=NumGet(varChildren,i)=9)
&& (N=""||N=A_Index) ? Acc_Query(child):child )
, (j ? ObjRelease(child):"")
SetBatchLines, %bch%
ListLines, %lls%
return Children.MaxIndex()?(N=""?Children:Children[N]):""
} else
ErrorLevel := "AccessibleChildren DllCall Failed"
}
if Acc_Error()
throw Exception(ErrorLevel,-1)
}
Acc_ChildrenByRole(Acc, Role)
{
if ComObjType(Acc,"Name")!="IAccessible"
ErrorLevel := "Invalid IAccessible Object"
else
{
Acc_Init(), cChildren:=Acc.accChildCount, Children:=[]
if DllCall("oleacc\AccessibleChildren", "Ptr",ComObjValue(Acc)
, "Int",0, "Int",cChildren, "Ptr",VarSetCapacity(varChildren
, cChildren*(8+2*A_PtrSize),0)*0+&varChildren, "Int*",cChildren)=0
{
Loop, %cChildren%
{
i:=(A_Index-1)*(A_PtrSize*2+8)+8, child:=NumGet(varChildren,i)
if NumGet(varChildren,i-8)=9
AccChild:=Acc_Query(child), ObjRelease(child)
, Acc_Role(AccChild)=Role?Children.Push(AccChild):""
else
Acc_Role(Acc, child)=Role?Children.Push(child):""
}
return Children.MaxIndex()?Children:"", ErrorLevel:=0
} else
ErrorLevel := "AccessibleChildren DllCall Failed"
}
if Acc_Error()
throw Exception(ErrorLevel,-1)
}
Acc_Query(Acc) ; thanks Lexikos - www.autohotkey.com/forum/viewtopic.php?t=81731&p=509530#509530
{
static IAccessible:="{618736e0-3c3d-11cf-810c-00aa00389b71}"
try return ComObj(9, ComObjQuery(Acc,IAccessible), 1)
}
Acc_Role(Acc, ChildId=0)
{
try return ComObjType(Acc,"Name")="IAccessible"
? Acc_GetRoleText(Acc.accRole(ChildId)):"invalid object"
}
Acc_State(Acc, ChildId=0)
{
try return ComObjType(Acc,"Name")="IAccessible"
? Acc_GetStateText(Acc.accState(ChildId)):"invalid object"
}
Acc_GetRoleText(nRole)
{
Acc_Init()
nSize := DllCall("oleacc\GetRoleText", "Uint", nRole, "Ptr", 0, "Uint", 0)
VarSetCapacity(sRole, (A_IsUnicode?2:1)*nSize)
DllCall("oleacc\GetRoleText", "Uint", nRole, "str", sRole, "Uint", nSize+1)
return sRole
}
Acc_GetStateText(nState)
{
Acc_Init()
nSize := DllCall("oleacc\GetStateText", "Uint", nState, "Ptr", 0, "Uint", 0)
VarSetCapacity(sState, (A_IsUnicode?2:1)*nSize)
DllCall("oleacc\GetStateText", "Uint", nState, "str", sState, "Uint", nSize+1)
return sState
}
Acc_Error(p="")
{
static setting:=0
return p=""?setting:setting:=p
}