Pywin32是一个Python库,为python提供访问Windows API的扩展,提供了齐全的windows常量、接口、线程以及COM机制等等。
一,Python对Windows程序窗口操作,最大化,最小化,关闭
import win32con
import win32gui
import time
'''
hwnd = win32gui.FindWindow(lpClassName=None, lpWindowName=None) # 查找窗口,不找子窗口,返回值为0表示未找到窗口
hwnd = win32gui.FindWindowEx(hwndParent=0, hwndChildAfter=0, lpszClass=None, lpszWindow=None) # 查找子窗口,返回值为0表示未找到子窗口
win32gui.ShowWindow(hwnd, win32con.SW_SHOWNORMAL)
SW_HIDE:隐藏窗口并激活其他窗口。nCmdShow=0。
SW_SHOWNORMAL:激活并显示一个窗口。如果窗口被最小化或最大化,系统将其恢复到原来的尺寸和大小。应用程序在第一次显示窗口的时候应该指定此标志。nCmdShow=1。
SW_SHOWMINIMIZED:激活窗口并将其最小化。nCmdShow=2。
SW_SHOWMAXIMIZED:激活窗口并将其最大化。nCmdShow=3。
SW_SHOWNOACTIVATE:以窗口最近一次的大小和状态显示窗口。激活窗口仍然维持激活状态。nCmdShow=4。
SW_SHOW:在窗口原来的位置以原来的尺寸激活和显示窗口。nCmdShow=5。
SW_MINIMIZE:最小化指定的窗口并且激活在Z序中的下一个顶层窗口。nCmdShow=6。
SW_SHOWMINNOACTIVE:窗口最小化,激活窗口仍然维持激活状态。nCmdShow=7。
SW_SHOWNA:以窗口原来的状态显示窗口。激活窗口仍然维持激活状态。nCmdShow=8。
SW_RESTORE:激活并显示窗口。如果窗口最小化或最大化,则系统将窗口恢复到原来的尺寸和位置。在恢复最小化窗口时,应用程序应该指定这个标志。nCmdShow=9。
'''
# 先等待3秒
time. sleep( 3 )
# 查找窗口句柄
hwnd = win32gui. FindWindow( "YodaoMainWndClass" , u"网易有道词典" )
print ( hwnd)
if hwnd != 0 :
# 若最小化,则将其显示,反之则最小化
if win32gui. IsIconic( hwnd) :
win32gui. ShowWindow( hwnd, win32con. SW_SHOWMAXIMIZED)
else :
win32gui. ShowWindow( hwnd, win32con. SW_SHOWMINIMIZED)
win32gui. SetForegroundWindow( hwnd) # 设置前置窗口
# win32gui.SetFocus(hwnd) # 设置聚焦窗口
# 关闭窗口
win32gui. PostMessage( hwnd, win32con. WM_CLOSE, 0 , 0 )
二,Python窗体操作函数
实现了一个window下对窗体操作的类,实现的功能如:移动窗体、获取窗体位置和大小、截取窗体图片、坐标转换等。
# coding=utf-8
import win32con
import win32api
import win32gui
import win32ui
from ctypes import *
from ctypes import wintypes
GetForegroundWindow = windll. user32. GetForegroundWindow
GetWindowRect = windll. user32. GetWindowRect
SetForegroundWindow = windll. user32. SetForegroundWindow
GetWindowText = windll. user32. GetWindowTextA
MoveWindow = windll. user32. MoveWindow
EnumWindows = windll. user32. EnumWindows
class RECT ( Structure) :
_fields_ = [
( 'left' , c_long) ,
( 'top' , c_long) ,
( 'right' , c_long) ,
( 'bottom' , c_long)
]
class POINT ( Structure) :
_fields_ = [
( 'x' , c_long) ,
( 'y' , c_long) ,
]
class FormControl ( object ) :
def __init__ ( self) :
self. win_hd = None
self. win_title = ''
def bindActiveWindow ( self) :
"""
函数功能:获取当前焦点所在窗口
"""
self. win_hd = GetForegroundWindow( )
def bindWindowByName ( self, win_name) :
"""
函数功能:根据窗体名获取窗体句柄
"""
self. win_title = win_name
pro_fun_type = CFUNCTYPE( c_bool, c_int, c_long)
pro_fun_p = pro_fun_type( self. EnumWindowsProc)
EnumWindows( pro_fun_p, None )
def getWinRect ( self) :
"""
函数功能:获取窗体的位置和大小
"""
if self. win_hd is None :
return None
rect= RECT( )
GetWindowRect( self. win_hd, byref( rect) )
return rect
def toScreenPos ( self, x, y) :
"""
函数功能:将窗体内部坐标转换为相对于显示屏的绝对坐标
"""
#未指定窗口,则结束函数
if self. win_hd is None :
return None
rect= self. getWinRect( )
#指定的坐标不在窗体内,则结束函数
if x < 0 or y < 0 or x > rect. right or y > rect. bottom:
return None
pos = POINT( )
pos. x = x + rect. left
pos. y = y + rect. top
return pos
def toWindowPos ( self, x, y) :
"""
函数功能:将绝对坐标转换成相对于窗体内部坐标
"""
if self. win_hd is None :
return None
rect = self. getWinRect( )
pos = POINT( )
pos. x = x - rect. left
pos. y = y - rect. top
# 指定的坐标不在窗体内,则结束函数
if pos. x < 0 or pos. y < 0 or pos. x > rect. right or pos. y > rect. bottom:
return None
return pos
def WindowActive ( self) :
"""
函数功能:将窗体置前
"""
if self. win_hd is None :
return None
SetForegroundWindow( self. win_hd)
def getHWND ( self) :
return self. win_hd
def getWinTitle ( self) :
"""
函数功能:获取窗体的标题
"""
if self. win_hd is None :
return None
buffer = create_string_buffer( 255 , '\0' )
GetWindowText( self. win_hd, buffer , 255 )
value= buffer . value. decode( 'gbk' )
return value
def MoveTo ( self, x, y) :
"""
函数功能:移动窗体到指定坐标位置
"""
if self. win_hd is None :
return None
rect = self. getWinRect( )
MoveWindow( self. win_hd, x, y, rect. right- rect. left, rect. bottom- rect. top, True )
def WinCapture ( self, path, x, y, w, h) :
"""
函数功能:抓取窗体截图,并保存到文件
参 数:path 保存路径
x 截取起始x坐标(窗体内相对坐标)
y 截取起始y坐标(窗体内相对坐标)
w 截取宽度,为0则取窗体宽度
h 截取长度,为0则取窗体高度
"""
if self. win_hd is None :
return None
rect = self. getWinRect( )
if w == 0 :
w = rect. right - rect. left
if h == 0 :
h = rect. bottom - rect. top
if x < 0 or y < 0 or ( x+ w) > rect. right or ( y+ h) > rect. bottom:
return None
self. Capture( self. win_hd, path, x, y, w, h, 0 )
def WinCapture_Mem ( self, x, y, w, h) :
"""
函数功能:抓取窗体截图,并返回图像内存数据
参 数:
x 截取起始x坐标(窗体内相对坐标)
y 截取起始y坐标(窗体内相对坐标)
w 截取宽度,为0则取窗体宽度
h 截取长度,为0则取窗体高度
"""
if self. win_hd is None :
return None
rect = self. getWinRect( )
if w == 0 :
w = rect. right - rect. left
if h == 0 :
h = rect. bottom - rect. top
if x < 0 or y < 0 or ( x+ w) > rect. right or ( y+ h) > rect. bottom:
return None
return self. Capture( self. win_hd, '' , x, y, w, h, 1 )
def Capture ( self, hd, path, x, y, w, h, mode) :
"""
函数功能:截图
参 数:hd 截取的窗口句柄
path 保存路径
x 截取起始x坐标(窗体内相对坐标)
y 截取起始y坐标(窗体内相对坐标)
w 截取宽度,为0则取窗体宽度
h 截取长度,为0则取窗体高度
mode 保存模式 0:保存为图片,1:返回图像字节数据
"""
# 根据窗口句柄获取窗口的设备上下文
hwndDC = win32gui. GetWindowDC( self. win_hd)
# 根据窗口的DC获取memDC
srcdc = win32ui. CreateDCFromHandle( hwndDC)
# memDC创建可兼容的DC
saveDC = srcdc. CreateCompatibleDC( )
# 创建bigmap准备保存图片
saveBitMap = win32ui. CreateBitmap( )
# 为bitmap开辟空间
saveBitMap. CreateCompatibleBitmap( srcdc, w, h)
# 高度saveDC,将截图保存到saveBitmap中
saveDC. SelectObject( saveBitMap)
# 截取从左上角(0,0)长宽为(w,h)的图片
saveDC. BitBlt( ( 0 , 0 ) , ( w, h) , srcdc, ( x, y) , win32con. SRCCOPY)
if mode == 0 :
saveBitMap. SaveBitmapFile( saveDC, path)
else :
signedIntsArray = saveBitMap. GetBitmapBits( True )
return signedIntsArray
# 释放内存
srcdc. DeleteDC( )
saveDC. DeleteDC( )
win32gui. ReleaseDC( self. win_hd, hwndDC)
win32gui. DeleteObject( saveBitMap. GetHandle( ) )
def EnumWindowsProc ( self, hwnd, lParam) :
buffer = create_string_buffer( 255 , '\0' )
GetWindowText( hwnd, buffer , 255 )
value= buffer . value. decode( 'gbk' )
if value == self. win_title:
self. win_hd = hwnd
print ( self. win_hd)
return False
return True
三,Python pywin32 获取 windows 的窗体内文本框的内容
用函数 win32gui .SendMessage 获取不了文本框的文本内容,用 str 类型的参数接收获取的内容的话没有获取到东西,而用 PyBuffer 类型去获取则得到类似于 16 进制的东西。
from win32gui import *
from win32api import *
from win32process import *
import win32con
import time
time. sleep( 3 )
# 获取窗体句柄
hWnd = GetForegroundWindow( )
print ( 'hownd: ' , hWnd)
FormThreadID = GetCurrentThreadId( )
print ( 'FormThreadID: ' , FormThreadID)
CWndThreadID = GetWindowThreadProcessId( hWnd)
print ( 'CWndThreadID: ' , CWndThreadID)
AttachThreadInput( CWndThreadID[ 0 ] , FormThreadID, True )
# 获取光标所在文本框句柄
hWnd = GetFocus( )
print ( 'hWnd: ' , hWnd)
AttachThreadInput( CWndThreadID[ 0 ] , FormThreadID, False )
# SendMessage(hWnd, win32con.WM_SETTEXT, 0, "mextb1860 第一个文本框")
# 文本框内容长度
length = SendMessage( hWnd, win32con. WM_GETTEXTLENGTH) + 1
print ( 'Length: ' , length)
buf = '0' * length
# 生成buffer对象
# buf = PyMakeBuffer(length)
# 获取文本框内容
print ( 'get: ' , SendMessage( hWnd, win32con. WM_GETTEXT, length, buf) )
print ( 'text: ' , buf)
四,Pywin32是一个Python库,为python提供访问Windows API的扩展,提供了齐全的windows常量、接口、线程以及COM机制等等。
通过类名和标题查找窗口句柄,并获得窗口位置和大小
import < span class = "wp_keywordlink_affiliate" > < a href= "http://www./tag/win32gui/" title= "View all posts in win32gui" target= "_blank" > win32gui< / a> < / span>
import < span class = "wp_keywordlink_affiliate" > < a href= "http://www./tag/win32api/" title= "View all posts in win32api" target= "_blank" > win32api< / a> < / span>
classname = "MozillaWindowClass"
titlename = "百度一下,你就知道 - Mozilla Firefox"
#获取句柄
hwnd = < span class = "wp_keywordlink_affiliate" > < a href= "http://www./tag/win32gui/" title= "View all posts in win32gui" target= "_blank" > win32gui< / a> < / span> . FindWindow( classname, titlename)
#获取窗口左上角和右下角坐标
left, top, right, bottom = win32gui. GetWindowRect( hwnd)
通过父句柄获取子句柄
def get_child_windows ( parent) :
'''
获得parent的所有子窗口句柄
返回子窗口句柄列表
'''
if not parent:
return
hwndChildList = [ ]
win32gui. EnumChildWindows( parent, lambda hwnd, param: param. append( hwnd) , hwndChildList)
return hwndChildList
#获取某个句柄的类名和标题
title = win32gui. GetWindowText( hwnd)
clsname = win32gui. GetClassName( hwnd)
#获取父句柄hwnd类名为clsname的子句柄
hwnd1= win32gui. FindWindowEx( hwnd, None , clsname, None )
鼠标定位与点击
#鼠标定位到(30,50)
< span class = "wp_keywordlink_affiliate" > < a href= "http://www./tag/win32api/" title= "View all posts in win32api" target= "_blank" > win32api< / a> < / span> . SetCursorPos( [ 30 , 150 ] )
#执行左单键击,若需要双击则延时几毫秒再点击一次即可
win32api. mouse_event( < span class = "wp_keywordlink_affiliate" > < a href= "http://www./tag/win32con/" title= "View all posts in win32con" target= "_blank" > win32con< / a> < / span> . MOUSEEVENTF_LEFTUP | < span class = "wp_keywordlink_affiliate" > < a href= "http://www./tag/win32con/" title= "View all posts in win32con" target= "_blank" > win32con< / a> < / span> . MOUSEEVENTF_LEFTDOWN, 0 , 0 , 0 , 0 )
#右键单击
win32api. mouse_event( win32con. MOUSEEVENTF_RIGHTUP | win32con. MOUSEEVENTF_RIGHTDOWN, 0 , 0 , 0 , 0 )
发送回车键
win32api. keybd_event( 13 , 0 , 0 , 0 )
win32api. keybd_event( 13 , 0 , win32con. KEYEVENTF_KEYUP, 0 )
关闭窗口
win32gui. PostMessage( win32lib. findWindow( classname, titlename) , win32con. WM_CLOSE, 0 , 0 )
一, 首先import win32gui, win32con
二, 使用win32gui. FindWindow找到目标程序:
win = win32gui. FindWindow( None , 'User Login’)
三, 使用win32gui. FindWindowEx找到目标文本框:
tid = win32gui. FindWindowEx( win, None , 'Edit’, None )
四, 使用win32gui. SendMessage发送文本到目标文本框:
win32gui. SendMessage( tid, win32con. WM_SETTEXT, None , 'hello’)
当然了,可以继续找到下一个文本框:
username = win32gui. FindWindowEx( win, tid, 'Edit’, None )
更新:已经找到发送回车的方法:
win32gui. SendMessage( tid, win32con. WM_SETTEXT, None , 'hello’)
win32gui. PostMessage( tid, win32con. WM_KEYDOWN, win32con. VK_RETURN, 0 )
win32gui. PostMessage( tid, win32con. WM_KEYUP, win32con. VK_RETURN, 0 )
实例:
import win32gui
import win32con
import win32api
# 从顶层窗口向下搜索主窗口,无法搜索子窗口
# FindWindow(lpClassName=None, lpWindowName=None) 窗口类名 窗口标题名
handle = win32gui. FindWindow( "Notepad" , None )
# 获取窗口位置
left, top, right, bottom = win32gui. GetWindowRect( handle)
#获取某个句柄的类名和标题
title = win32gui. GetWindowText( handle)
clsname = win32gui. GetClassName( handle)
# 打印句柄
# 十进制
print ( handle)
# 十六进制
print ( "%x" % ( handle) )
# 搜索子窗口
# 枚举子窗口
hwndChildList = [ ]
win32gui. EnumChildWindows( handle, lambda hwnd, param: param. append( hwnd) , hwndChildList)
# FindWindowEx(hwndParent=0, hwndChildAfter=0, lpszClass=None, lpszWindow=None) 父窗口句柄 若不为0,则按照z-index的顺序从hwndChildAfter向后开始搜索子窗体,否则从第一个子窗体开始搜索。 子窗口类名 子窗口标题
subHandle = win32gui. FindWindowEx( handle, 0 , "EDIT" , None )
# 获得窗口的菜单句柄
menuHandle = win32gui. GetMenu( subHandle)
# 获得子菜单或下拉菜单句柄
# 参数:菜单句柄 子菜单索引号
subMenuHandle = win32gui. GetSubMenu( menuHandle, 0 )
# 获得菜单项中的的标志符,注意,分隔符是被编入索引的
# 参数:子菜单句柄 项目索引号
menuItemHandle = win32gui. GetMenuItemID( subMenuHandle, 0 )
# 发送消息,加入消息队列,无返回
# 参数:句柄 消息类型 WParam IParam
win32gui. postMessage( subHandle, win32con. WM_COMMAND, menuItemHandle, 0 )
# wParam的定义是32位整型,high word就是他的31至16位,low word是它的15至0位。
# 当参数超过两个,wParam和lParam不够用时,可以将wParam就给拆成两个int16来使用。
# 这种时候在python里记得用把HIWORD的常数向左移16位,再加LOWORD,即wParam = HIWORD<<16+LOWORD。
# 下选框内容更改
# 参数:下选框句柄; 消息内容; 参数下选框的哪一个item,以0起始的待选选项的索引;如果该值为-1,将从组合框列表中删除当前选项,并使当前选项为空; 参数
# CB_Handle为下选框句柄,PCB_handle下选框父窗口句柄
if win32api. SendMessage( CB_handle, win32con. CB_SETCURSEL, 1 , 0 ) == 1 :
# 下选框的父窗口命令
# 参数:父窗口句柄; 命令; 参数:WParam:高位表示类型,低位表示内容;参数IParam,下选框句柄
# CBN_SELENDOK当用户选择了有效的列表项时发送,提示父窗体处理用户的选择。 LOWORD为组合框的ID. HIWORD为CBN_SELENDOK的值。
win32api. SendMessage( PCB_handle, win32con. WM_COMMAND, 0x90000 , CB_handle)
# CBN_SELCHANGE当用户更改了列表项的选择时发送,不论用户是通过鼠标选择或是通过方向键选择都会发送此通知。LOWORD为组合框的ID. HIWORD为CBN_SELCHANGE的值。
win32api. SendMessage( PCB_handle, win32con. WM_COMMAND, 0x10000 , CB_handle)
# 设置文本框内容,等窗口处理完毕后返回true。中文需编码成gbk
# 参数:句柄;消息类型;参数WParam,无需使用; 参数IParam,要设置的内容,字符串
win32api. SendMessage( handle, win32con. WM_SETTEXT, 0 , os. path. abspath( fgFilePath) . encode( 'gbk' ) )
# 控件点击确定,处理消息后返回0
# 参数:窗口句柄; 消息类型; 参数WParam HIWORD为0(未使用),LOWORD为控件的ID; 参数IParam 0(未使用),确定控件的句柄
win32api. SendMessage( Mhandle, win32con. WM_COMMAND, 1 , confirmBTN_handle)
# 获取窗口文本不含截尾空字符的长度
# 参数:窗口句柄; 消息类型; 参数WParam; 参数IParam
bufSize = win32api. SendMessage( subHandle, win32con. WM_GETTEXTLENGTH, 0 , 0 ) + 1
# 利用api生成Buffer
strBuf = win32gui. PyMakeBuffer( bufSize)
print ( strBuf)
# 发送消息获取文本内容
# 参数:窗口句柄; 消息类型;文本大小; 存储位置
length = win32gui. SendMessage( subHandle, win32con. WM_GETTEXT, bufSize, strBuf)
# 反向内容,转为字符串
# text = str(strBuf[:-1])
address, length = win32gui. PyGetBufferAddressAndLen( strBuf)
text = win32gui. PyGetString( address, length)
# print('text: ', text)
# 鼠标单击事件
#鼠标定位到(30,50)
win32api. SetCursorPos( [ 30 , 150 ] )
#执行左单键击,若需要双击则延时几毫秒再点击一次即可
win32api. mouse_event( win32con. MOUSEEVENTF_LEFTUP | win32con. MOUSEEVENTF_LEFTDOWN, 0 , 0 , 0 , 0 )
#右键单击
win32api. mouse_event( win32con. MOUSEEVENTF_RIGHTUP | win32con. MOUSEEVENTF_RIGHTDOWN, 0 , 0 , 0 , 0 )
def click1 ( x, y) : #第一种
win32api. SetCursorPos( ( x, y) )
win32api. mouse_event( win32con. MOUSEEVENTF_LEFTDOWN, x, y, 0 , 0 )
win32api. mouse_event( win32con. MOUSEEVENTF_LEFTUP, x, y, 0 , 0 )
def click2 ( x, y) : #第二种
ctypes. windll. user32. SetCursorPos( x, y)
ctypes. windll. user32. mouse_event( 2 , 0 , 0 , 0 , 0 )
ctypes. windll. user32. mouse_event( 4 , 0 , 0 , 0 , 0 )
def click_it ( pos) : #第三种
handle= win32gui. WindowFromPoint( pos)
client_pos = win32gui. ScreenToClient( handle, pos)
tmp= win32api. MAKELONG( client_pos[ 0 ] , client_pos[ 1 ] )
win32gui. SendMessage( handle, win32con. WM_ACTIVATE, win32con. WA_ACTIVE, 0 )
win32gui. SendMessage( handle, win32con. WM_LBUTTONDOWN, win32con. MK_LBUTTON, tmp)
win32gui. SendMessage( handle, win32con. WM_LBUTTONUP, win32con. MK_LBUTTON, tmp)
# 发送回车
win32api. keybd_event( 13 , 0 , 0 , 0 )
win32api. keybd_event( 13 , 0 , win32con. KEYEVENTF_KEYUP, 0 )
# 关闭窗口
win32gui. PostMessage( win32lib. findWindow( classname, titlename) , win32con. WM_CLOSE, 0 , 0 )
# 检查窗口是否最小化,如果是最大化
if ( win32gui. IsIconic( hwnd) ) :
# win32gui.ShowWindow(hwnd, win32con.SW_SHOWNORMAL)
win32gui. ShowWindow( hwnd, 8 )
sleep( 0.5 )
# SW_HIDE:隐藏窗口并激活其他窗口。nCmdShow=0。
# SW_MAXIMIZE:最大化指定的窗口。nCmdShow=3。
# SW_MINIMIZE:最小化指定的窗口并且激活在Z序中的下一个顶层窗口。nCmdShow=6。
# SW_RESTORE:激活并显示窗口。如果窗口最小化或最大化,则系统将窗口恢复到原来的尺寸和位置。在恢复最小化窗口时,应用程序应该指定这个标志。nCmdShow=9。
# SW_SHOW:在窗口原来的位置以原来的尺寸激活和显示窗口。nCmdShow=5。
# SW_SHOWDEFAULT:依据在STARTUPINFO结构中指定的SW_FLAG标志设定显示状态,STARTUPINFO 结构是由启动应用程序的程序传递给CreateProcess函数的。nCmdShow=10。
# SW_SHOWMAXIMIZED:激活窗口并将其最大化。nCmdShow=3。
# SW_SHOWMINIMIZED:激活窗口并将其最小化。nCmdShow=2。
# SW_SHOWMINNOACTIVE:窗口最小化,激活窗口仍然维持激活状态。nCmdShow=7。
# SW_SHOWNA:以窗口原来的状态显示窗口。激活窗口仍然维持激活状态。nCmdShow=8。
# SW_SHOWNOACTIVATE:以窗口最近一次的大小和状态显示窗口。激活窗口仍然维持激活状态。nCmdShow=4。
# SW_SHOWNORMAL:激活并显示一个窗口。如果窗口被最小化或最大化,系统将其恢复到原来的尺寸和大小。应用程序在第一次显示窗口的时候应该指定此标志。nCmdShow=1。
# win32虽然也可控制键盘,但不如使用PyUserInput的方便。需要注意在windows和mac下接口参数可能有所不同。
from pymouse import PyMouse
from pykeyboard import PyKeyboard
m = PyMouse( )
k = PyKeyboard( )
x_dim, y_dim = m. screen_size( )
# 鼠标点击
m. click( x_dim/ 2 , y_dim/ 2 , 1 )
# 键盘输入
k. type_string( 'Hello, World!' )
# 按住一个键
k. press_key( 'H' )
# 松开一个键
k. release_key( 'H' )
# 按住并松开,tap一个键
k. tap_key( 'e' )
# tap支持重复的间歇点击键
k. tap_key( 'l' , n= 2 , interval= 5 )
# 发送判断文字
k. type_string( '123456' )
#创建组合键
k. press_key( k. alt_key)
k. tap_key( k. tab_key)
k. release_key( k. alt_key)
# 特殊功能键
k. tap_key( k. function_keys[ 5 ] ) # Tap F5
k. tap_key( k. numpad_keys[ 'Home' ] ) # Tap 'Home' on the numpad
k. tap_key( k. numpad_keys[ 5 ] , n= 3 ) # Tap 5 on the numpad, thrice
# Mac系统
k. press_keys( [ 'Command' , 'shift' , '3' ] )
# Windows系统
k. press_keys( [ k. windows_l_key, 'd' ] )
其中的PyMouseEvent和PyKeyboardEvent还可用于监听鼠标和键盘事件的输入