利用ACC控制酷狗音樂

因爲開機腳本中需要使用熱鍵控制酷狗音樂,所以研究了一下ACC,可以簡單實現控制各種不規則的程序界面功能,當然也包括酷狗音樂。

/*
;-----------------------------------
;  ACC控制酷狗音樂 - By FeiYue
;
;  備註:熱鍵可以改爲自己喜歡的
;-----------------------------------
*/

#NoEnv


F1::
obj := Acc_GetInfoUnderCursor(), id:=obj.hwnd
DetectHiddenWindows, On
WinGetTitle, tt, ahk_id %id%
WinGetClass, class, ahk_id %id%
tt:=Trim(class="" ? tt : tt " ahk_class " class)
MsgBox, 4096,, % tt " --> " obj.path " --> " SubStr(obj.text,1,100)
return

F2:: 酷狗音樂("上一首")

F3:: 酷狗音樂("下一首")

F4:: 酷狗音樂("播放/暫停")

F5:: 酷狗音樂("我喜歡")


酷狗音樂(命令)
{
    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
    }

    路徑1:={ "上一首"   : "4.2.13.16.1"
          , "播放/暫停" : "4.2.13.16.2"
          , "下一首"    : "4.2.13.16.3"
          , "我喜歡"    : "4.2.13.15.1" }  ; 酷狗9

    路徑2:={ "上一首"   : "4.2.11.16.1"
          , "播放/暫停" : "4.2.11.16.2"
          , "下一首"    : "4.2.11.16.3"
          , "我喜歡"    : "4.2.11.15.1" }  ; 酷狗9

    路徑3:={ "上一首"   : "4.3.7.16.1"
          , "播放/暫停" : "4.3.7.16.2"
          , "下一首"    : "4.3.7.16.3"
          , "我喜歡"    : "4.3.7.15.1" }  ; 酷狗9

    路徑4:={ "上一首"   : "4.3.6.16.1"
          , "播放/暫停" : "4.3.6.16.2"
          , "下一首"    : "4.3.6.16.3"
          , "我喜歡"    : "4.3.6.15.1" }  ; 酷狗9

    路徑5:={ "上一首"   : "4.3.7.13.1"
          , "播放/暫停" : "4.3.7.13.3"
          , "下一首"    : "4.3.7.13.2"
          , "我喜歡"    : "4.3.7.27.5 | 4.3.7.26.5" }  ; 酷狗8.0

    For k,v in [路徑1, 路徑2, 路徑3, 路徑4, 路徑5]
    For k2,v2 in StrSplit(v[命令],"|")
    Try
    {
        Acc:=Acc_Get("Object", v2, 0, "ahk_id " okid)
        if IsObject(Acc) and (Acc.accName(0) = 命令)
        {
            Acc.accDoDefaultAction(0)
            return
        }
    }
}


;==================================================


; Acc.ahk - thanks Sean, jethrow, jeeswg, teadrinker
Acc_Get(Cmd, ChildPath="", ChildID=0, WinTitle="", WinText="", ExcludeTitle="", ExcludeText="")
{
    static properties := {Action:"DefaultAction", DoAction:"DoDefaultAction", Keyboard:"KeyboardShortcut"}
    AccObj := IsObject(WinTitle) ? WinTitle
           :  Acc_ObjectFromWindow( WinExist(WinTitle, WinText, ExcludeTitle, ExcludeText), 0 )
    if ComObjType(AccObj, "Name") != "IAccessible"
        ErrorLevel := "Could not access an IAccessible Object"
    else
    {
        StringReplace, ChildPath, ChildPath, _, %A_Space%, All
        AccError:=Acc_Error(), Acc_Error(true)
        Loop Parse, ChildPath, ., %A_Space%
            try
            {
                if A_LoopField is digit
                    Children:=Acc_Children(AccObj), m2:=A_LoopField ; mimic "m2" output in else-statement
                else
                    RegExMatch(A_LoopField, "(\D*)(\d*)", m)
                    , Children:=Acc_ChildrenByRole(AccObj, m1), m2:=(m2?m2:1)
                if Not Children.HasKey(m2)
                    throw
                AccObj := Children[m2]
            }
            catch
            {
                ErrorLevel:="Cannot access ChildPath Item #" A_Index " -> " 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")
                AccObj.accLocation(ComObj(0x4003,&x:=0), ComObj(0x4003,&y:=0)
                , ComObj(0x4003,&w:=0), ComObj(0x4003,&h:=0), ChildId)
                , ret_val := "x" NumGet(x,0,"int") " y" NumGet(y,0,"int")
                . " w" NumGet(w,0,"int") " h" NumGet(h,0,"int")
            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_GetInfoUnderCursor()
{
  Acc := Acc_ObjectFromPoint(child)
  Try value := Acc.accValue(child)
  if (!value)
    Try value := Acc.accName(child)
  accPath := Acc_GetAccPath(acc, hwnd).path
  return {text: value, path: accPath, hwnd: hwnd}
}

Acc_GetAccPath(Acc, byref hwnd="")
{
  hwnd:=Acc_WindowFromObject(Acc)
  While Acc_WindowFromObject(Parent:=Acc_Parent(Acc))=hwnd
    t2 := Acc_GetEnumIndex(Acc) "." t2, Acc := Parent
  return {AccObj:Acc, Path:SubStr(t2,1,-1)}
}

Acc_GetEnumIndex(Acc, ChildId=0)
{
  if Not ChildId
  {
    Role:=Name:=""
    Try Role:=Acc.accRole(0)
    Try Name:=Acc.accName(0)
    Count:=Acc.accChildCount, Pos:=Acc_Location(Acc).pos
    For Each, child in Acc_Children(Acc_Parent(Acc))
    {
      if Not IsObject(child)
        Continue
      vRole:=vName:=""
      Try vRole:=child.accRole(0)
      Try vName:=child.accName(0)
      if (Role=vRole and Name=vName and Count=child.accChildCount
      and Pos=Acc_Location(child).pos)
        return A_Index
    }
  }
  else
  {
    Role:=Name:=""
    Try Role:=Acc.accRole(ChildId)
    Try Name:=Acc.accName(ChildId)
    Pos:=Acc_Location(Acc,ChildId).pos
    For Each, child in Acc_Children(Acc)
    {
      if IsObject(child)
        Continue
      vRole:=vName:=""
      Try vRole:=Acc.accRole(child)
      Try vName:=Acc.accName(child)
      if (Role=vRole and Name=vName
      and Pos=Acc_Location(Acc,child).pos)
        return A_Index
    }
  }
}

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)
{
    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"
    }
    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.Insert(AccChild):""
                else
                    Acc_Role(Acc, child)=Role?Children.Insert(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
{
    try return ComObj(9, ComObjQuery(Acc,"{618736e0-3c3d-11cf-810c-00aa00389b71}"), 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
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章