求教AHK如何模拟鼠标左键点击任务栏托盘的图标

左键点击托盘图标坐标,如何鼠标不移过去?

直接用Click到托盘图标坐标,鼠标过去再移回来,大概好几秒

想模拟后台点击不移动鼠标

1 个赞

用快捷键吧 win+123(123是图标的顺序)

不是任务栏下面的图标哦,是右下角托盘的图标

Win+BEnter 打开托盘,然后在对应的 GUI 里找要触发的内容吧

1 个赞

ahk论坛有人发布过相关的库——trayicon,一搜就能搜到

TrayIcon_Button部分

下面是有人转成v2版的,v1版的

#Requires AutoHotkey v2.0-beta

;----------------------------------------------------------------------------------------------------------------------
; Function ......: TrayIcon_GetInfo
; Description ...: Get a series of useful information about tray icons.
; Parameters ....: sExeName  - The exe for which we are searching the tray icon data. Leave it empty to receive data for
; ...............:             all tray icons.
; Return ........: oTrayInfo - An array of objects containing tray icons data. Any entry is structured like this:
; ...............:             oTrayInfo[A_Index].idx     - 0 based tray icon index.
; ...............:             oTrayInfo[A_Index].idcmd   - Command identifier associated with the button.
; ...............:             oTrayInfo[A_Index].pid     - Process ID.
; ...............:             oTrayInfo[A_Index].uid     - Application defined identifier for the icon.
; ...............:             oTrayInfo[A_Index].msgid   - Application defined callback message.
; ...............:             oTrayInfo[A_Index].hicon   - Handle to the tray icon.
; ...............:             oTrayInfo[A_Index].hwnd    - Window handle.
; ...............:             oTrayInfo[A_Index].class   - Window class.
; ...............:             oTrayInfo[A_Index].process - Process executable.
; ...............:             oTrayInfo[A_Index].tray    - Tray Type (Shell_TrayWnd or NotifyIconOverflowWindow).
; ...............:             oTrayInfo[A_Index].tooltip - Tray icon tooltip.
; Info ..........: TB_BUTTONCOUNT message - http://goo.gl/DVxpsg
; ...............: TB_GETBUTTON message   - http://goo.gl/2oiOsl
; ...............: TBBUTTON structure     - http://goo.gl/EIE21Z
; ----------------------------------------------------------------------------------------------------------------------
; Converted to v2 by ruchuby in 2023.1.1
; ----------------------------------------------------------------------------------------------------------------------
TrayIcon_GetInfo(sExeName := "")
{
    d := A_DetectHiddenWindows
    DetectHiddenWindows(true)
    oTrayInfo := []
    For key, sTray in ["Shell_TrayWnd", "NotifyIconOverflowWindow"]
    {
        idxTB := TrayIcon_GetTrayBar(sTray)
        pidTaskbar := WinGetPID("ahk_class " sTray)
        hProc := DllCall("OpenProcess", "UInt", 0x38, "Int", 0, "UInt", pidTaskbar)
        pRB := DllCall("VirtualAllocEx", "Ptr", hProc, "Ptr", 0, "UPtr", 20, "UInt", 0x1000, "UInt", 0x04)
        btn := Buffer((A_Is64bitOS ? 32 : 20), 0)
        nfo := Buffer((A_Is64bitOS ? 32 : 24), 0)
        tip := Buffer(128 * 2, 0)
        ; TB_BUTTONCOUNT = 0x0418
        res := SendMessage(0x0418, 0, 0, "ToolbarWindow32" idxTB, "ahk_class " sTray)
        Loop res
        {
            ; TB_GETBUTTON 0x0417
            SendMessage(0x0417, A_Index - 1, pRB, "ToolbarWindow32" idxTB, "ahk_class " sTray)
            DllCall("ReadProcessMemory", "Ptr", hProc, "Ptr", pRB, "Ptr", btn.Ptr, "UPtr", btn.Size, "UPtr", 0)
            iBitmap := NumGet(btn, 0, "Int")
            idCmd := NumGet(btn, 4, "Int")
            fsState := NumGet(btn, 8, "UChar")
            fsStyle := NumGet(btn, 9, "UChar")
            dwData := NumGet(btn, (A_Is64bitOS ? 16 : 12), "UPtr")
            iString := NumGet(btn, (A_Is64bitOS ? 24 : 16), "Ptr")
            DllCall("ReadProcessMemory", "Ptr", hProc, "Ptr", dwData, "Ptr", nfo.Ptr, "UPtr", nfo.Size, "UPtr", 0)
            hWnd := NumGet(nfo, 0, "Ptr")
            uId := NumGet(nfo, (A_Is64bitOS ? 8 : 4), "UInt")
            msgId := NumGet(nfo, (A_Is64bitOS ? 12 : 8), "UPtr")
            hIcon := NumGet(nfo, (A_Is64bitOS ? 24 : 20), "Ptr")
            nPid := WinGetPID("ahk_id " hWnd)
            try sProcess := WinGetProcessName("ahk_id " hWnd)
            sClass := WinGetClass("ahk_id " hWnd)
            If (!sExeName || sExeName == sProcess || sExeName == nPid)
            {
                DllCall("ReadProcessMemory", "Ptr", hProc, "Ptr", iString, "Ptr", tip.Ptr, "UPtr", tip.Size, "UPtr", 0)
                oTrayInfo.Push(Map("idx", A_Index - 1
                    , "idcmd", idCmd
                    , "pid", nPid
                    , "uid", uId
                    , "msgid", msgId
                    , "hicon", hIcon
                    , "hwnd", hWnd
                    , "class", sClass
                    , "process", sProcess
                    , "tooltip", StrGet(tip, "UTF-16")
                    , "tray", sTray))
            }
        }
        DllCall("VirtualFreeEx", "Ptr", hProc, "Ptr", pRB, "UPtr", 0, "UInt", 0x8000)
        DllCall("CloseHandle", "Ptr", hProc)
    }
    DetectHiddenWindows(d)
    Return oTrayInfo
}
; ----------------------------------------------------------------------------------------------------------------------
; Function .....: TrayIcon_Hide
; Description ..: Hide or unhide a tray icon.
; Parameters ...: idCmd - Command identifier associated with the button.
; ..............: sTray - Place where to find the icon ("Shell_TrayWnd" or "NotifyIconOverflowWindow").
; ..............: bHide - True for hide, false for unhide.
; Info .........: TB_HIDEBUTTON message - http://goo.gl/oelsAa
; ----------------------------------------------------------------------------------------------------------------------
TrayIcon_Hide(idCmd, sTray := "Shell_TrayWnd", bHide := true)
{
    d := A_DetectHiddenWindows
    DetectHiddenWindows(true)
    idxTB := TrayIcon_GetTrayBar()
    SendMessage(0x0404, idCmd, bHide, "ToolbarWindow32" idxTB, "ahk_class " sTray)    ; TB_HIDEBUTTON
    SendMessage(0x001A, 0, 0, , "ahk_class " sTray)
    DetectHiddenWindows(d)
}
; ----------------------------------------------------------------------------------------------------------------------
; Function .....: TrayIcon_Delete
; Description ..: Delete a tray icon.
; Parameters ...: idx   - 0 based tray icon index.
; ..............: sTray - Place where to find the icon ("Shell_TrayWnd" or "NotifyIconOverflowWindow").
; Info .........: TB_DELETEBUTTON message - http://goo.gl/L0pY4R
; ----------------------------------------------------------------------------------------------------------------------
TrayIcon_Delete(idx, sTray := "Shell_TrayWnd")
{
    d := A_DetectHiddenWindows
    DetectHiddenWindows(true)
    idxTB := TrayIcon_GetTrayBar()
    SendMessage(0x0416, idx, 0, "ToolbarWindow32" idxTB, "ahk_class " sTray)    ; TB_DELETEBUTTON = 0x0416
    SendMessage(0x001A, 0, 0, , "ahk_class " sTray)
    DetectHiddenWindows(d)
}
; ----------------------------------------------------------------------------------------------------------------------
; Function .....: TrayIcon_Remove
; Description ..: Remove a Tray icon. It should be more reliable than TrayIcon_Delete.
; Parameters ...: hWnd - Window handle.
; ..............: uId  - Application defined identifier for the icon.
; Info .........: NOTIFYICONDATA structure  - https://goo.gl/1Xuw5r
; ..............: Shell_NotifyIcon function - https://goo.gl/tTSSBM
; ----------------------------------------------------------------------------------------------------------------------
TrayIcon_Remove(hWnd, uId)
{
    NID := Buffer((2 * 384 + A_PtrSize * 5 + 40), 0)
    NumPut("UInt", NID.Size, NID.Ptr, 0)
    NumPut("UInt", hWnd, NID.Ptr, A_PtrSize)
    NumPut("UInt", uId, NID.Ptr, A_PtrSize * 2)
    Return DllCall("Shell32.dll\Shell_NotifyIcon", "UInt", 0x2, "UInt", NID.Ptr)
}
; ----------------------------------------------------------------------------------------------------------------------
; Function .....: TrayIcon_Move
; Description ..: Move a tray icon.
; Parameters ...: idxOld - 0 based index of the tray icon to move.
; ..............: idxNew - 0 based index where to move the tray icon.
; ..............: sTray  - Place where to find the icon ("Shell_TrayWnd" or "NotifyIconOverflowWindow").
; Info .........: TB_MOVEBUTTON message - http://goo.gl/1F6wPw
; ----------------------------------------------------------------------------------------------------------------------
TrayIcon_Move(idxOld, idxNew, sTray := "Shell_TrayWnd")
{
    d := A_DetectHiddenWindows
    DetectHiddenWindows(true)
    idxTB := TrayIcon_GetTrayBar()
    SendMessage(0x452, idxOld, idxNew, "ToolbarWindow32 " idxTB, "ahk_class " sTray)    ; TB_MOVEBUTTON = 0x452
    DetectHiddenWindows(d)
}
; ----------------------------------------------------------------------------------------------------------------------
; Function .....: TrayIcon_Set
; Description ..: Modify icon with the given index for the given window.
; Parameters ...: hWnd       - Window handle.
; ..............: uId        - Application defined identifier for the icon.
; ..............: hIcon      - Handle to the tray icon.
; ..............: hIconSmall - Handle to the small icon, for window menubar. Optional.
; ..............: hIconBig   - Handle to the big icon, for taskbar. Optional.
; Return .......: true on success, false on failure.
; Info .........: NOTIFYICONDATA structure  - https://goo.gl/1Xuw5r
; ..............: Shell_NotifyIcon function - https://goo.gl/tTSSBM
; ----------------------------------------------------------------------------------------------------------------------
TrayIcon_Set(hWnd, uId, hIcon, hIconSmall := 0, hIconBig := 0)
{
    d := A_DetectHiddenWindows
    DetectHiddenWindows(true)
    ; WM_SETICON = 0x0080
    If (hIconSmall)
        SendMessage(0x0080, 0, hIconSmall, , "ahk_id " hWnd)
    If (hIconBig)
        SendMessage(0x0080, 1, hIconBig, , "ahk_id " hWnd)
    DetectHiddenWindows(d)
    NID := Buffer(2 * 384 + A_PtrSize * 5 + 40, 0)
    NumPut("UInt", NID.Size, NID.Ptr, 0)
    NumPut("UInt", hWnd, NID.Ptr, (A_PtrSize == 4) ? 4 : 8)
    NumPut("UInt", uId, NID.Ptr, (A_PtrSize == 4) ? 8 : 16)
    NumPut("UInt", 2, NID.Ptr, (A_PtrSize == 4) ? 12 : 20)
    NumPut("UInt", hIcon, NID.Ptr, (A_PtrSize == 4) ? 20 : 32)
    ; NIM_MODIFY := 0x1
    Return DllCall("Shell32.dll\Shell_NotifyIcon", "UInt", 0x1, "Ptr", NID.Ptr)
}
; ----------------------------------------------------------------------------------------------------------------------
; Function .....: TrayIcon_GetTrayBar
; Description ..: Get the tray icon handle.
; Parameters ...: sTray - Traybar to retrieve.
; Return .......: Tray icon handle.
; ----------------------------------------------------------------------------------------------------------------------
TrayIcon_GetTrayBar(sTray := "Shell_TrayWnd")
{
    d := A_DetectHiddenWindows
    DetectHiddenWindows(true)
    loopTimes := 0
    for v in WinGetControls("ahk_class " sTray)
        if InStr(v, "ToolbarWindow32")
            loopTimes++
    Loop loopTimes
    {
        hWnd := ControlGetHwnd("ToolbarWindow32" A_Index, "ahk_class " sTray)
        hParent := DllCall("GetParent", "Ptr", hWnd)
        sClass := WinGetClass("ahk_id " hParent)
        If !(sClass == "SysPager" || sClass == "NotifyIconOverflowWindow")
            Continue
        idxTB := A_Index
        Break
    }
    DetectHiddenWindows(d)
    Return idxTB
}
; ----------------------------------------------------------------------------------------------------------------------
; Function .....: TrayIcon_GetHotItem
; Description ..: Get the index of tray's hot item.
; Return .......: Index of tray's hot item.
; Info .........: TB_GETHOTITEM message - http://goo.gl/g70qO2
; ----------------------------------------------------------------------------------------------------------------------
TrayIcon_GetHotItem()
{
    idxTB := TrayIcon_GetTrayBar()
    res := SendMessage(0x0447, 0, 0, "ToolbarWindow32" idxTB, "ahk_class Shell_TrayWnd")    ; TB_GETHOTITEM = 0x0447
    Return res << 32 >> 32
}
; ----------------------------------------------------------------------------------------------------------------------
; Function .....: TrayIcon_Button
; Description ..: Simulate mouse button click on a tray icon.
; Parameters ...: sExeName - Executable Process Name of tray icon.
; ..............: sButton  - Mouse button to simulate (L, M, R).
; ..............: bDouble  - true to double click, false to single click.
; ..............: nIdx     - Index of tray icon to click if more than one match.
; ----------------------------------------------------------------------------------------------------------------------
TrayIcon_Button(sExeName, sButton := "L", bDouble := false, nIdx := 1)
{
    d := A_DetectHiddenWindows
    DetectHiddenWindows(true)
    msgMap := Map(
        'WM_MOUSEMOVE', 0x0200
        , 'WM_LBUTTONDOWN', 0x0201
        , 'WM_LBUTTONUP', 0x0202
        , 'WM_LBUTTONDBLCLK', 0x0203
        , 'WM_RBUTTONDOWN', 0x0204
        , 'WM_RBUTTONUP', 0x0205
        , 'WM_RBUTTONDBLCLK', 0x0206
        , 'WM_MBUTTONDOWN', 0x0207
        , 'WM_MBUTTONUP', 0x0208
        , 'WM_MBUTTONDBLCLK', 0x0209
    )
    sButton := "WM_" sButton "BUTTON"
    oIcons := TrayIcon_GetInfo(sExeName)
    If (bDouble)
        PostMessage(oIcons[nIdx]["msgid"], oIcons[nIdx]["uid"], msgMap[sButton "DBLCLK"], , "ahk_id " oIcons[nIdx]["hwnd"])
    Else
    {
        PostMessage(oIcons[nIdx]["msgid"], oIcons[nIdx]["uid"], msgMap[sButton "DOWN"], , "ahk_id " oIcons[nIdx]["hwnd"])
        PostMessage(oIcons[nIdx]["msgid"], oIcons[nIdx]["uid"], msgMap[sButton "UP"], , "ahk_id " oIcons[nIdx]["hwnd"])
    }
    DetectHiddenWindows(d)
    Return
}
1 个赞

感谢,搞定了

:face_with_peeking_eye: 我也只是知道有这么个库,还没有用过,有问题的话你查查看ahk论坛相关讨论,我猜是win11太先进?

你可以再试试这个v1 版本的一个类似代码,我用这个可以左键或右键QQ图标,不过微信只能左键有效,右键不知道为啥没效:

#NoTrayIcon
sleep,3000
if !PostMessage2TrayIconByProcName([WM_LBUTTONDOWN := 0x0201, WM_LBUTTONUP := 0x0202], "qq.exe")
   MsgBox, Not found
Sleep,3000
if !PostMessage2TrayIconByProcName([WM_RBUTTONDOWN := 0x0204, WM_RBUTTONUP := 0x0205], "qq.exe")
   MsgBox, Not found
sleep,1000	 
return

;'WM_MOUSEMOVE', 0x0200
;'WM_LBUTTONDOWN', 0x0201
;'WM_LBUTTONUP', 0x0202
;'WM_LBUTTONDBLCLK', 0x0203
;'WM_RBUTTONDOWN', 0x0204
;'WM_RBUTTONUP', 0x0205
;'WM_RBUTTONDBLCLK', 0x0206
;'WM_MBUTTONDOWN', 0x0207
;'WM_MBUTTONUP', 0x0208
;'WM_MBUTTONDBLCLK', 0x0209

PostMessage2TrayIconByProcName(Messages, procName, tip := "") {
   static TB_GETBUTTON   := 0x417
        , TB_BUTTONCOUNT := 0x418
        , PtrSize := 4 << A_Is64bitOS
        , szTBBUTTON := 8 + PtrSize*3
        , szTRAYDATA := 16 + PtrSize*2
   
   prevDHW := A_DetectHiddenWindow
   DetectHiddenWindows, On
   lastFound := WinExist()
   WinGet, PID, PID, ahk_exe explorer.exe
   RemoteBuff := new RemoteBuffer(PID, szTRAYDATA)
   found := false
   
   Loop 2 {
      if (A_Index = 2)
         ControlGet, hToolBar, hwnd,, ToolbarWindow321, ahk_class NotifyIconOverflowWindow
      else {
         for k, v in ["TrayNotifyWnd", "SysPager", "ToolbarWindow32"]
            hToolBar := DllCall("FindWindowEx", "Ptr", k = 1 ? WinExist("ahk_class Shell_TrayWnd") : hToolBar, "Ptr", 0, "Str", v, "UInt", 0, "Ptr")
      }
      WinExist("ahk_id" . hToolBar)
      SendMessage, TB_BUTTONCOUNT
      Loop % ErrorLevel {
         SendMessage, TB_GETBUTTON, A_Index - 1, RemoteBuff.ptr
         RemoteBuff.Read(TBBUTTON, szTBBUTTON)
         RemoteBuff.Read(TRAYDATA, szTRAYDATA, NumGet(&TBBUTTON + 8 + PtrSize) - RemoteBuff.ptr)
         WinGet, processName, ProcessName, % "ahk_id" hWnd := NumGet(TRAYDATA)
         if (processName = procName) {
            if (tip != "") {
               try RemoteBuff.Read(sTip, 256, NumGet(&TBBUTTON + 8 + PtrSize*2) - RemoteBuff.ptr)
               catch
                  continue
               string := StrGet(&sTip, "UTF-16")
               if (string != tip)
                  continue
            }
            found := true
            break 2
         }
      }
   }
   if found {
      uID := NumGet(&TRAYDATA + PtrSize, "UInt")
      uCallbackMessage := NumGet(&TRAYDATA + PtrSize + 4, "UInt")
      if !IsObject(Messages)
         PostMessage, uCallbackMessage, uID, Messages,, ahk_id %hWnd%
      else {
         for k, msg in Messages
            PostMessage, uCallbackMessage, uID, msg,, ahk_id %hWnd%
      }
   }
   DetectHiddenWindows, %prevDHW%
   WinExist("ahk_id" . lastFound)
   Return found
}

class RemoteBuffer
{
   __New(PID, size) {
      static flags := (PROCESS_VM_OPERATION := 0x8) | (PROCESS_VM_WRITE := 0x20) | (PROCESS_VM_READ := 0x10)
           , Params := ["UInt", MEM_COMMIT := 0x1000, "UInt", PAGE_READWRITE := 0x4, "Ptr"]
         
      if !this.hProc := DllCall("OpenProcess", "UInt", flags, "Int", 0, "UInt", PID, "Ptr")
         throw Exception("Can't open remote process PID = " . PID . "`nA_LastError: " . A_LastError, "RemoteBuffer.__New")
      
      if !this.ptr := DllCall("VirtualAllocEx", "Ptr", this.hProc, "Ptr", 0, "Ptr", size, Params*) {
         DllCall("CloseHandle", "Ptr", this.hProc)
         throw Exception("Can't allocate memory in remote process PID = " . PID . "`nA_LastError: " . A_LastError, "RemoteBuffer.__New")
      }
   }
   
   __Delete() {
      DllCall("VirtualFreeEx", Ptr, this.hProc, Ptr, this.ptr, UInt, 0, UInt, MEM_RELEASE := 0x8000)
      DllCall("CloseHandle", Ptr, this.hProc)
   }
   
   Read(ByRef localBuff, size, offset = 0) {
      VarSetCapacity(localBuff, size, 0)
      if !DllCall("ReadProcessMemory", "Ptr", this.hProc, "Ptr", this.ptr + offset, "Ptr", &localBuff, "Ptr", size, "PtrP", bytesRead)
         throw Exception("Can't read data from remote buffer`nA_LastError: " . A_LastError, "RemoteBuffer.Read")
      Return bytesRead
   }
   
   Write(pLocalBuff, size, offset = 0) {
      if !res := DllCall("WriteProcessMemory", "Ptr", this.hProc, "Ptr", this.ptr + offset, "Ptr", pLocalBuff, "Ptr", size, "PtrP", bytesWritten)
         throw Exception("Can't write data to remote buffer`nError: " . A_LastError, "RemoteBuffer.Write")
      Return bytesWritten
   }
}

请问可以贴一段模拟点击的示例代码吗?我写的运行好像没效果

你好,我用这个库模拟点击,但是好像没有效果 ::想请教一下

#Include TrayIcon.ahk
!o::TrayIcon_Button("obs64.exe", "L") 

前几行不就是 左右击qq图标的

我试了一下,大部分软件都能生效,但是obs没效果,进程名“obs64.exe”也没有提示Not found​:face_with_spiral_eyes:另外spotify也是一样的问题。obs这个比较刚需:persevere: