如何使用 python 监听 windows 中当前 运行 应用程序任务栏图标上的鼠标单击事件?

How to listen for mouse click events on task bar icon for a currently running application in windows using python?

我正在尝试使用 python 监听 windows 中当前 运行 应用程序任务栏应用程序图标上的鼠标单击事件。在下面的示例中,我使用 python 来启动 Internet Explorer 应用程序。应用程序启动后,我然后使用 FindWindow windows API 函数获取 window ID/handle。

有没有办法使用 windows API 或其他方法来监听用户在 Internet Explorer 任务栏图标上的鼠标点击?单击任务栏中的 IE 图标时需要打印一条消息。

这是我目前正在使用的代码:

from win32gui import GetWindowText, GetForegroundWindow, FindWindow
import win32api, win32gui
import win32con
import sys, os

os.system('"C:\Program Files (x86)\Internet Explorer\iexplore.exe"') #open internet explorer application.. this will make the internet explorer icon appear in the taskbar..

window_id = FindWindow(0, 'Internet Explorer') #find the newly opened IE window's id/handle
print (window_id) 

class test:

    def __init__(self, **kwargs):
        super(test, self).__init__(**kwargs)
        self.oldWndProc = win32gui.SetWindowLong(window_id, win32con.GWL_WNDPROC, self.MyWndProc)
        self.msgdict = {} 
        for name in dir(win32con):
            if name.startswith("WM_"):
                value = getattr(win32con, name)
                self.msgdict[value] = name
        print (self.msgdict) #I can access all the win32 window events using this dictionary..

    #listener to track win32 window events related to the newly opened internet explorer window..
    #how do I track when the internet explorer icon is CLICKED in the task bar??
    def MyWndProc(self, hWnd, msg, wParam, lParam):
        print (self.msgdict.get(msg)) #none of the window events print here..
        return win32gui.CallWindowProc(self.oldWndProc, hWnd, msg, wParam, lParam)

t = test()

尝试使用UI Automation.

任务栏的windowclass名称是MSTaskListWClass:

您还可以从 inspect.exe:

中看到 UIA 元素及其 BoundingRectangle

可以先获取桌面的点击事件,然后获取任务图标的IUIAutomationElement,再用GetClickablePoint判断点击是否在元素上。

感谢 Drake Wu 为我指明了正确的方向,我能够使用 python 获取有关被单击元素及其父元素的 UI 自动化信息。使用该信息,我可以知道当单击的元素的 ControlType 为 'ButtonControl' 且其父项的 class 名称为 'MSTaskListWClass' 时,任务栏中的应用程序图标被单击。您可以通过查看被单击元素的自动化 ID 来确定单击了哪个应用程序。

您需要为此示例安装 uiautomation。我必须向 uiautomation.py 文件添加一些额外的 functions/methods,因为它缺少所需的功能。

以下是我添加到 uiautomation.py 文件中的方法,以使其对本示例更有用(请参阅此处显示新代码的位置):

def ControlFromPoint(x: int, y: int) -> Control:
    """
    Call IUIAutomation ElementFromPoint x,y. May return None if mouse is over cmd's title bar icon.
    Return `Control` subclass or None.
    """
    element = _AutomationClient.instance().IUIAutomation.ElementFromPoint(ctypes.wintypes.POINT(x, y))
    return Control.CreateControlFromElement(element)

#NEW CODE HERE
def GetElementFromPoint(x: int, y: int) -> Control: #gets the element from a point (x, y)
    element = _AutomationClient.instance().IUIAutomation.ElementFromPoint(ctypes.wintypes.POINT(x, y))
    return element

#NEW CODE HERE
def GetParentElement(element): #gets the parent of an element input
    parent_element = _AutomationClient.instance().ViewWalker.GetParentElement(element)
    return parent_element

#NEW CODE HERE
def GetElementInfo(element): #gets the property information about an element
    element_info = Control.CreateControlFromElement(element)
    return element_info

然后我在下面的主要示例中使用了这些新添加的 uiautomation 方法:

import sys, os
from pynput import mouse
from pynput.mouse import Controller
from pynput.mouse import Listener
import uiautomation
from uiautomation import GetElementFromPoint, GetParentElement, GetElementInfo #these are newly added methods to make this example work

mouse2 = mouse.Controller()

class test:

    last_mouse_pos_x = ''
    last_mouse_pos_y = ''

    def __init__(self, **kwargs):
        super(test, self).__init__(**kwargs)
        self.mouse_listener() #start mouse listener

    def mouse_listener(self):
        global element_clicked
        while True:
            if mouse2.position[0] != test.last_mouse_pos_x or mouse2.position[1] != test.last_mouse_pos_y:
                element_clicked = uiautomation.GetElementFromPoint(mouse2.position[0], mouse2.position[1]) #returns the element that you clicked (this has to run here or it errors)
                test.last_mouse_pos_x = mouse2.position[0]
                test.last_mouse_pos_y = mouse2.position[1]

    def on_click(x, y, button, pressed):
        if pressed:
            try:
                element_clicked_info = GetElementInfo(element_clicked) #returns info about the element you clicked
                parent_of_element_clicked = uiautomation.GetParentElement(element_clicked) #returns the parent of the element that you clicked
                parent_of_element_clicked_info = GetElementInfo(parent_of_element_clicked) #returns info about the parent of the element you clicked
                #print info about the element you clicked and its parent
                print ("ELEMENT CLICKED INFO: " + str(element_clicked_info))
                print ("PARENT ELEMENT INFO: " + str(parent_of_element_clicked_info)) 
            except:
                pass #skip over any errors

            #ANALYSIS: If ControlType of element clicked = 'ButtonControl' AND class name of its parent = 'MSTaskListWClass', then an app icon in the taskbar was clicked!

    listener = mouse.Listener(on_click=on_click)
    listener.start()

t = test()