如何使用 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()
我正在尝试使用 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
:
可以先获取桌面的点击事件,然后获取任务图标的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()