按键精灵 python加强版
主体程序,主要是一些功能的实现,具体应用需要自己写。
写的比较乱
import win32gui, win32api, win32con, win32ui
import time
from time import sleep
import random
from random import uniform
import logging
from logging import info, warning, error
from config import VK_CODE
import copy
import cv2 as cv
import traceback# mode为test意为调试模式,real则为实际应用
# In 'test' mode, it will print some hidden info for Debug
mode = 'test'# 模式图的存储路径
# The save path of pattern pics
pattern_path = 'yourpath\\'# 设置logging的书写格式
# Setting logging configs
logging.basicConfig(level=logging.DEBUG,format='%(lineno)d : %(asctime)s : %(levelname)s : %(funcName)s : %(message)s',filename='yourpath\\log{}.txt'.format(time.strftime('-%Y-%m-%d')),filemode='w')# 用当前时间初始化随机数
# Set random seed
random.seed(time.time())def Get_PosAndHwnd(hwnd=0, ClassName=None, TitleName=None):'''接受句柄、类名、标题名,返回第一个匹配的窗口位置和句柄。Accepts Handle, ClassName or TitleName of a window, returns the rect-pos of the first window that matches.Args:hwnd: 目标句柄 target handle.ClassName: 目标窗口类名 target ClassName.TitleName: 目标窗口标题 target TitleName.Returns: x1, y1, x2, y2, hwnd前四个参数描述窗口在显示器中的位置,hwnd为句柄。x1-y2 describes the pos of the window in screen, last arg is the handle.'''try:if hwnd == 0:hwnd = win32gui.FindWindow(ClassName, TitleName)x1, y1, x2, y2 = win32gui.GetWindowRect(hwnd)info('找到窗口,句柄:{},标题名:{},类名:{},坐标:{}'.format(hwnd, win32gui.GetWindowText(hwnd), win32gui.GetClassName(hwnd),(x1, y1, x2, y2)))return x1, y1, x2, y2, hwndexcept:global modeif mode == 'test':traceback.print_exc()elif mode == 'real':error('Get_PosAndHwnd 出现错误')def Activate_Hwnd(hwnd):'''激活指定句柄的窗口。每次转换时使用。Activates the window with the matching hwnd.Args:hwnd: 目标句柄 target handle.Returns:No return.'''try:win32gui.SendMessage(hwnd, win32con.WM_ACTIVATE, win32con.WA_ACTIVE, 0)# WA_CLICKACTIVE为通过鼠标激活,WA_ACTIVE为鼠标以外的东西(如键盘)激活,WA_INACTIVE为取消激活# WA_CLICKACTIVE means activate by mouse, WA_ACTIVE means other equipments( like keyboard).WA_INACTIVE means inactivate it.info('激活句柄为 {} 标题为 {} 的窗口'.format(hwnd, win32gui.GetWindowText(hwnd)))except:global modeif mode == 'test':traceback.print_exc()elif mode == 'real':error('激活窗口 出现错误')def LeftClick(hwnd, x1, y1, times='first', platform='PC'):'''左键单击(自带延时) Left Click the window (located by hwnd) once (with human-like delay). Args:hwnd: 目标窗口的句柄 target hwnd. x1, y1: 需要点击的坐标 target pos. times: 'first'表示从其他窗口转过来点击,用于调用Activate_Hwnd(hwnd)。If 'first', means target window is inactive/unfocused, thus call Activate_Hwnd(hwnd). platform: 目前无用。'PC'表示当前操作的是桌面版,不是安卓模拟器('AM')。Useless now. 'PC' means target window is PC, not Android manipulator ('AM').Returns:No return.'''try:if platform == 'PC': # 对于桌面版 # for PCtmp_pos = win32api.MAKELONG(x1, y1)#elif flag == 'AM': # 对于模拟器 # for Android manipulator#click_pos = win32gui.ScreenToClient(hwnd, (x1, y1))# 注意坐标是整个窗口还是客户区的,用ScreenToClient转换 # switch between screen/client pos#tmp_pos = win32api.MAKELONG(click_pos[0], click_pos[1])if times == 'first':Activate_Hwnd(hwnd)win32gui.SendMessage(hwnd, win32con.WM_LBUTTONDOWN,win32con.MK_LBUTTON, tmp_pos)# 鼠标点击格式为SendMessage(hWnd,WM_LBUTTONDOWN,fwKeys,MAKELONG(xPos,yPos));# fwKeys可以取:MK_CONTROL、MK_LBUTTON、MK_MBUTTON、MK_RBUTTON、MK_SHIFT等,多个值用|隔开sleep(uniform(0.05, 0.08))win32gui.SendMessage(hwnd, win32con.WM_LBUTTONUP, 0000, tmp_pos)# 抬起时有些电脑上fwKeys显示为0000,有些可能为MK_LBUTTON# Use spy++ for detailssleep(uniform(0.07, 0.095))info('对句柄 {} 标题 {} 的坐标 {} 进行 左键单击 动作'.format(hwnd, win32gui.GetWindowText(hwnd), (x1, y1)))except:global modeif mode == 'test':traceback.print_exc()elif mode == 'real':error('左键单击 出现错误')def LeftClick_sequence(hwnd, points, times='second', platform='PC'):'''左键依序单击(依次点击多个点) Click a sequence of points in order.Args: hwnd: 目标窗口的句柄 target hwnd. points: 需要点击的坐标 target points in the form like ((x1,y1),(x2,y2)...). times: 'first'表示从其他窗口转过来点击,用于调用Activate_Hwnd(hwnd)。If 'first', means target window is inactive/unfocused, thus call Activate_Hwnd(hwnd). platform: 目前无用。'PC'表示当前操作的是桌面版,不是安卓模拟器('AM')。Useless now. 'PC' means target window is PC, not Android manipulator ('AM').Returns:No return.'''try:if times == 'first':Activate_Hwnd(hwnd)for point in points:LeftClick(hwnd, point[0], point[1], 'second', platform)info('对句柄 {} 标题 {} 的坐标 {} 进行 左键依序单击 动作'.format(hwnd, win32gui.GetWindowText(hwnd), points))except:global modeif mode == 'test':traceback.print_exc()elif mode == 'real':error('左键单击 出现错误')def LeftDoubleClick(hwnd, x1, y1, times='first', platform='PC'):'''左键同一位置双击 Click the same pos twice.Args:hwnd: 目标窗口的句柄 target hwnd. x1, y1: 需要点击的坐标 target pos. times: 'first'表示从其他窗口转过来点击,用于调用Activate_Hwnd(hwnd)。If 'first', means target window is inactive/unfocused, thus call Activate_Hwnd(hwnd). platform: 目前无用。'PC'表示当前操作的是桌面版,不是安卓模拟器('AM')。Useless now. 'PC' means target window is PC, not Android manipulator ('AM').Returns:No return.'''try:if times == 'first':Activate_Hwnd(hwnd)info('左键同一位置双击--第一次点击')LeftClick(hwnd, x1, y1, 'second', platform)info('左键同一位置双击--第二次点击')LeftClick(hwnd, x1, y1, 'second', platform)except:global modeif mode == 'test':traceback.print_exc()elif mode == 'real':error('左键同一位置双击 出现错误')def LeftDifDoubleClick_Rect(hwnd,x1,y1,times='first',platform='PC',delta=(0, 4)):'''左键不同位置双击,范围为双正方形 Left click 2 pos, in a double-square-like area._________| ___ || | | || |___| ||_______|(x1, y1) is at the center, (x2, y2) between the squares (borders included).Args:hwnd: 目标窗口的句柄 target hwnd. x1, y1: 第一次点击的坐标 first pos to click. times: 'first'表示从其他窗口转过来点击,用于调用Activate_Hwnd(hwnd)。If 'first', means target window is inactive/unfocused, thus call Activate_Hwnd(hwnd). platform: 目前无用。'PC'表示当前操作的是桌面版,不是安卓模拟器('AM')。Useless now. 'PC' means target window is PC, not Android manipulator ('AM').delta: 第二个点的横坐标在x1+delta[0] 到 x1+delta[1]间(包括端点),纵坐标同样。x2 varies between x1+delta[0] to x1+delta[1], y2 the same (both ends included). Returns:No return.'''try:if times == 'first':Activate_Hwnd(hwnd)info('左键正方形双击--第一次点击')LeftClick(hwnd, x1, y1, 'second', platform)point_list = []for delta_x in range(delta[0], delta[1] + 1):for delta_y in range(delta[0], delta[1] + 1):point_list.append((x1 + delta_x, y1 + delta_y))point_list.append((x1 + delta_x, y1 - delta_y))point_list.append((x1 - delta_x, y1 + delta_y))point_list.append((x1 - delta_x, y1 - delta_y))point_list = list(set(point_list))point_list.remove((x1, y1))x1, y1 = random.sample(point_list, 1)[0]info('左键正方形双击--第二次点击')LeftClick(hwnd, x1, y1, 'second', platform)except:global modeif mode == 'test':traceback.print_exc()elif mode == 'real':error('左键正方形双击 出现错误')def LeftDifDoubleClick_Cir(hwnd, x1, y1, times='first', platform='PC', r=4):'''左键不同位置双击,范围为圆形。 Left Click 2 pos in a circle.(x1, y1)为圆心,r为半径,(x2, y2)在圆内及圆上。(x1, y1) is the center, r the radius. Generates (x2, y2) in the circle (or on the border).Args:hwnd: 目标窗口的句柄 target hwnd. x1, y1: 第一次点击的坐标 first pos to click. times: 'first'表示从其他窗口转过来点击,用于调用Activate_Hwnd(hwnd)。If 'first', means target window is inactive/unfocused, thus call Activate_Hwnd(hwnd). platform: 目前无用。'PC'表示当前操作的是桌面版,不是安卓模拟器('AM')。Useless now. 'PC' means target window is PC, not Android manipulator ('AM').r: 圆的半径。radius. Returns:返回两次点击的坐标(x1,y1,x2,y2)。Returns 2 clicked pos in (x1,y1,x2,y2). '''try:if times == 'first':Activate_Hwnd(hwnd)info('左键圆形双击--第一次点击')LeftClick(hwnd, x1, y1, 'second', platform)m, n = x1, y1point_list = []final_point_list = []for delta_x in range(r + 1):for delta_y in range(r + 1):point_list.append((delta_x, delta_y))point_list.remove((0, 0))for i in range(len(point_list)):x = point_list[i][0]y = point_list[i][1]if x * x + y * y <= r * r:final_point_list.append((x1 + x, y1 + y))final_point_list.append((x1 + x, y1 - y))final_point_list.append((x1 - x, y1 + y))final_point_list.append((x1 - x, y1 - y))final_point_list = list(set(final_point_list))x1, y1 = random.sample(final_point_list, 1)[0]info('左键圆形双击--第二次点击')LeftClick(hwnd, x1, y1, 'second', platform)return (m, n, x1, y1)except:global modeif mode == 'test':traceback.print_exc()elif mode == 'real':error('左键圆形双击 出现错误')def Random_Areas_LeftClicks(hwnd,click_areas,times='first',platform='PC',r=4,click_strategy=1):'''从几种点击策略中选一种执行,在一定范围对目标窗口进行点击。Select a click strategy/combination, click the window in some given areas. --------- 单个点击区域如右。A single click_area looks like left. | ---- | 如果只点击一次或者点击两次中的第一个坐标,该坐标位于小矩形中(包括边界)。| | | | If only click once, or the first click in 2 clicks, it locates in the minor rect (borders included).| | | | 小矩形的每条边距大矩形距离为r个像素点。| | | | Each border of the minor rect is r-pixel far from the outside rect.| ---- |---------第二次点击的区域不会超出大矩形的范围(包括边界))。对于一个点击区域[x1,y1,x2,y2],其中的小矩形为[x1+r,y1+r,x2-r,y2-r]。The second is in the big rect (borders included). For a click_area like (x1,y1,x2,y2), the minor rect is [x1+r,y1+r,x2-r,y2-r]. Args:hwnd: 目标窗口的句柄 target hwnd. click_areas: 可选的点击范围(矩形)。格式为[[x1,y1,x2,y2],[x3,y3,x4,y4]...],只有一个区域则可以写成[x1,y1,x2,y2]。Possible rect-areas to click, given in the form of [[x1,y1,x2,y2],[x3,y3,x4,y4]...]. If only one area, [x1,y1,x2,y2] is also acceptable. times: 'first'表示从其他窗口转过来点击,用于调用Activate_Hwnd(hwnd)。If 'first', means target window is inactive/unfocused, thus call Activate_Hwnd(hwnd). platform: 目前无用。'PC'表示当前操作的是桌面版,不是安卓模拟器('AM')。Useless now. 'PC' means target window is PC, not Android manipulator ('AM').r: 圆的半径。radius. click_strategy: 选择的点击策略。看看源码,很容易写自己的策略。主要包括点击方式和概率。A strategy for clicking, includes combination of clicking functions and its weights. Look at the src code, easy to construct your own click_strategy. Returns:返回两次点击的坐标(x1,y1,x2,y2)。如果只点击一次,返回(x1, y1, -1, -1)Returns 2 clicked pos in (x1,y1,x2,y2). If only clicked once, return (x1, y1, -1, -1). '''try:# 缩小边界,并加上一个值,表示区域点的坐标个数(包含边界)total = 0areas = copy.deepcopy(click_areas) # python中传列表参是浅拷贝,为了防止改变原click_areas需要写这一句。传字符串、数字是深拷贝if isinstance(areas[0], int):areas = [areas]for i in range(len(areas)):areas[i][0] = areas[i][0] + rareas[i][1] = areas[i][1] + rareas[i][2] = areas[i][2] - rareas[i][3] = areas[i][3] - rareas[i].append((areas[i][2] - areas[i][0] + 1) *(areas[i][3] - areas[i][1] + 1))total = total + areas[i][4]rand = random.randint(0, total - 1)# 找出第一次点击位置落在哪个区域,并找出具体坐标# find out the first click is in which area, and the exact pos.x = 0y = 0for i in range(len(areas)):rand = rand - areas[i][4]if rand < 0:rand = rand + areas[i][4]w = areas[i][2] - areas[i][0] + 1x = rand % w + areas[i][0]y = rand // w + areas[i][1] # 现在python中整型之间用/也会得到floatbreakif click_strategy == 1: # 1号策略,包括左键单击、左键同一位置双击、左键圆形双击三种#总结果数为173,左键单击:左键同一位置双击:左键圆形双击 的比例为 131:29:13rand = random.randint(1, 173)if times == 'first':Activate_Hwnd(hwnd)if rand <= 131: # weighs 131info('随机区域左键 选择 左键单击,坐标{}'.format((x, y)))LeftClick(hwnd, x, y, 'second', platform)return (x, y, -1, -1)elif rand >= 161: # weighs 13info('随机区域左键 选择 左键圆形双击,第一次点击坐标{}'.format((x, y)))return LeftDifDoubleClick_Cir(hwnd, x, y, 'second', platform,r)else: # weighs 29info('随机区域左键 选择 左键同位置双击,坐标{}'.format((x, y)))LeftDoubleClick(hwnd, x, y, 'second', platform)return (x, y, x, y)elif click_strategy == 2: # 2号策略,仅包括左键单击,用于只能单击的情况if times == 'first':Activate_Hwnd(hwnd)info('随机区域左键 选择 左键单击,坐标{}'.format((x, y)))LeftClick(hwnd, x, y, 'second', platform)return (x, y, -1, -1)except:global modeif mode == 'test':traceback.print_exc()elif mode == 'real':error('随机区域左键 出现错误')def press_key(hwnd, key='esc', times='second'):'''单次按键(自带延时) Press a key once (with human-like delay).Args:hwnd: 目标窗口的句柄 target hwnd. key: 需要按的键,详见config.VK_CODE。The key to press, see also in config.VK_CODE.times: 'first'表示从其他窗口转过来点击,用于调用Activate_Hwnd(hwnd)。If 'first', means target window is inactive/unfocused, thus call Activate_Hwnd(hwnd). Returns:No return. '''try:if times == 'first':Activate_Hwnd(hwnd)win32api.SendMessage(hwnd, win32con.WM_KEYDOWN, VK_CODE[key],0) # 暂时将lParam写为0# 这里不知道是否要暂停# I don't konw whether to pause here.time.sleep(0.01)win32api.SendMessage(hwnd, win32con.WM_CHAR, VK_CODE[key], 0)sleep(uniform(0.05, 0.08))win32api.SendMessage(hwnd, win32con.WM_KEYUP, VK_CODE[key], 0)sleep(uniform(0.07, 0.095))info('对句柄 {} 标题 {} 的窗口 按 {} 键一次'.format(hwnd,win32gui.GetWindowText(hwnd),key))except:global modeif mode == 'test':traceback.print_exc()elif mode == 'real':error('单次按键 出现错误')def press_keys(hwnd, keys, times='second'):'''依序按键 Press a sequence of keys in order.Args:hwnd: 目标窗口的句柄 target hwnd. keys: 需要按的键,详见config.VK_CODE。Keys to press, see also in config.VK_CODE.times: 'first'表示从其他窗口转过来点击,用于调用Activate_Hwnd(hwnd)。If 'first', means target window is inactive/unfocused, thus call Activate_Hwnd(hwnd). Returns:No return. '''try:if times == 'first':Activate_Hwnd(hwnd)for key in keys:press_key(hwnd, key, 'second')info('对句柄 {} 标题 {} 的窗口 依序按 {} 键'.format(hwnd,win32gui.GetWindowText(hwnd),keys))except:global modeif mode == 'test':traceback.print_exc()elif mode == 'real':error('依序按键 出现错误')def ClientRect_PrtSc(hwnd, area=None, filename=''):'''根据句柄、截图位置和图片路径,对窗口的客户区截图并存到指定位置。Press PrtSc for a window's client area, save the pic in the indicated path. 从https://blog.csdn.net/zhuisui_woxin/article/details/84345036和https://www.cnblogs.com/Evan-fanfan/p/11097850.html改编Made some changes and corrected some errors from 2 links above (took me some time to figure the errors).Args:hwnd: 目标窗口的句柄 target hwnd. area: 需要的区域。为None时表示整个客户区。Needed area. If None, means get the whole client area. filename: 指定路径。为''时表示文件名根据hwnd生成。Indicate the path. If '', means 'path\{}.bmp'.format. Returns:No return. '''try:hwnd = hwndif filename == '':filename = 'yourpath\\{}.bmp'.format(hwnd)hwndDC = win32gui.GetDC(hwnd) # 获取窗口的设备上下文Device Context。GetWindowDC包括了非客户区,而GetDC仅为客户区# GetWindowDC also gets the non-client area, while GetDC only gets the client area.mfcDC = win32ui.CreateDCFromHandle(hwndDC) # 获取mfcDCsaveDC = mfcDC.CreateCompatibleDC() # 创建可兼容DCsaveBitMap = win32ui.CreateBitmap() # 创建bitmap以保存图片'''MonitorDev = win32api.EnumDisplayMonitors(None, None) # 获取显示器信息,枚举显示器,笔记本据说可能有问题'''x1, y1, x2, y2 = win32gui.GetClientRect(hwnd) #GetClientRect获取客户区窗口位置,GetWindowRect获取整个窗口的位置信息x, y, w, h = (0, 0, 0, 0)if area == None:x = 0y = 0w = x2 - x1h = y2 - y1else:x, y, m, n = areaw = m - xh = n - ysaveBitMap.CreateCompatibleBitmap(mfcDC, w, h) # 为bitmap开辟空间# 对saveBitMap.CreateCompatibleBitmap(mfcDC, w, h)的理解:# 1.mfc相当于一个虚拟屏幕。这里的参数w和h决定了这个屏幕的大小。# 2.屏幕的初始状态是黑色,每个坐标都是#000000# 3.之前有mfcDC = win32ui.CreateDCFromHandle(hwndDC),又有hwndDC = win32gui.GetDC(hwnd)# mfcDC和hwnd窗口之间建立了某种关联,可以将hwnd窗口中的图像放到虚拟屏幕上saveDC.SelectObject(saveBitMap) # 将截图保存到saveBitMap中saveDC.BitBlt((0, 0), (w, h), mfcDC, (x, y), win32con.SRCCOPY)# 对saveDC.BitBlt(坐标1, (w, h), mfcDC, 坐标2, win32con.SRCCOPY)的理解:# BitBlt的功能大概是把从hwnd窗口截到的图放到虚拟屏幕上,信息转入saveDC。# 1.坐标1是针对窗口截图的,指定截图放在黑色背景上的位置(指定左上角)# 2.w和h窗口截图的长宽,而坐标2指定了开始截图的位置# 这两个参数决定了从hwnd窗口的哪里截图、截多大的图# 3.mfcDC已经和hwnd窗口建立了关联,所以不需要指定虚拟屏幕从哪个窗口获得截图# 4.SRCCOPY意为将截图直接拷贝到虚拟屏幕中# 接下来的saveBitMap.SaveBitmapFile(saveDC, filename)则是对虚拟屏幕截图并保存到指定位置# Google for more info.saveBitMap.SaveBitmapFile(saveDC, filename)# 清除数据# GetDC一类的需要用ReleaseDC释放,CreateDC一类的用DeleteDC释放,DeleteObject则删除一个逻辑笔、画笔、字体、位图、区域或者调色板win32gui.DeleteObject(saveBitMap.GetHandle())saveDC.DeleteDC()mfcDC.DeleteDC()win32gui.ReleaseDC(hwnd, hwndDC)info('对句柄 {} 标题 {} 的窗口截图并保存'.format(hwnd,win32gui.GetWindowText(hwnd)))except:global modeif mode == 'test':traceback.print_exc()elif mode == 'real':error('客户区截图 出现错误')def G(pattern_filename):'''将pattern的文件名加上路径前缀与类型后缀并返回Add path prefix and '.bmp' for a pattern pic file and return it. Args:pattern_filename: 模式图片名。Pattern pic file name. Returns: opencv2 可用的路径。The usable path for opencv2. '''try:global pattern_path # 在全局变量中 # a global variable.return pattern_path + pattern_filename + '.bmp'except:global modeif mode == 'test':traceback.print_exc()elif mode == 'real':error('加模式图路径 出现错误')def Find_Pic(hwnd,pattern,return_pos='l',find_pattern_in_area=None,filename=''):'''寻找图片,找到则返回小图在大图中的位置坐标及模板图大小,否则返回(-1,-1,tw,th)。Find the pattern pic in the target pic. Return the location and pattern's size if found, or (-1,-1,pattern-weight,pattern-height) if not.https://blog.csdn.net/wz2671/article/details/102751549和https://www.cnblogs.com/ssyfj/p/9271883.html很有帮助。Above 2 links help. Args:hwnd: 目标窗口的句柄 target hwnd. pattern: 模式图,小图。The pic to be found, pattern pic, smaller pic. return_pos: 为'l'时返回找到的左上角坐标,'c'则返回中心(偏左上)。If 'l', return the left-top corner, 'c' the centor pos (if odd, lefter and topper). find_pattern_in_area: 指定在大图的哪个区域查找。None表示在全部区域中找。In which area of the bigger pic to find. None means the whole area. filename: 指定路径。为''时表示文件名根据hwnd生成。Indicate the bigger-pic's path. If '', means 'path\{}.bmp'.format. Returns:如果找到,以(x, y, pat_w, pat_h)形式返回小图在大图中的位置;没找到则返回(-1, -1, pat_w, pat_h)。The location and pattern's size in the form of (x, y, pat_w, pat_h) if found, or (x, y, pat_w, pat_h) if not.'''try:hwnd = hwndClientRect_PrtSc(hwnd, find_pattern_in_area, filename)if filename == '': # 没有提供文件名则需要改成默认文件名filename = 'youpath\\{}.bmp'.format(hwnd)pat = cv.imread(pattern) # patternsrc = cv.imread(filename) # source# imread的文件名必须带上格式后缀theight, twidth = pat.shape[:2]# 获取pattern的高和宽result = cv.matchTemplate(src, pat, cv.TM_SQDIFF_NORMED)# 执行模板匹配,采用的匹配方式cv2.TM_SQDIFF_NORMED# matchTemplate(大图像, 小图像(子图像、模式图像)m, 匹配方式, result 和 mask 可选)# 返回一个矩阵result,大小为(W-w+1)*(H-h+1),比大图像少了右、下一圈,是子图像左上顶点在大图像中可能出现的位置# result矩阵中的每个位置,其值表示子图像左上顶点放在该位置时,子图像与大图像上相应区域的匹配度# result中的点位置和大图像保持一致。# 关于匹配方式:()# 1.TM_SQDIFF是平方差匹配;TM_SQDIFF_NORMED是标准平方差匹配。利用平方差来进行匹配,最好匹配为0;匹配越差,匹配值越大。# 2.TM_CCORR是相关性匹配;TM_CCORR_NORMED是标准相关性匹配。采用模板和图像间的乘法操作,数越大表示匹配程度较高, 0表示最坏的匹配效果。# 3.TM_CCOEFF是相关性系数匹配;TM_CCOEFF_NORMED是标准相关性系数匹配。将模版对其均值的相对值与图像对其均值的相关值进行匹配,1表示完美匹配,-1表示糟糕的匹配,0表示没有任何相关性(随机序列)。# 总结:随着从简单的测量(平方差)到更复杂的测量(相关系数),我们可获得越来越准确的匹配(同时也意味着越来越大的计算代价)。min_val, max_val, min_loc, max_loc = cv.minMaxLoc(result)# minMaxLoc(矩阵Mat),在一个矩阵中找出最大值、最小值、对应序号# 对于TM_SQDIFF_NORMED模式下最匹配的位置,如果不匹配值大于1%,就认为没有找到。if min_val > 0.01:return (-1, -1, twidth, theight)global modeif mode == 'test':# 以下代码绘制矩形边框,并将匹配区域标注出来,用于调试# codes after are used for debug, draw the big/small pic and the location.cv.rectangle(src, min_loc,(min_loc[0] + twidth, min_loc[1] + theight),(0, 0, 225), 1) # 在src图像矩阵中加上矩形,范围是模板图的范围# rectangle(目标图像, 矩形的一个顶点, 矩形对角线上的另一个顶点, 矩形线条颜色, 线条粗细)返回空值strmin_val = str(min_val)print('\n匹配度' + strmin_val)cv.imshow("MatchResult----MatchingValue=" + strmin_val,src) # 将画上了矩形的图像在窗口中显示出来cv.imshow('pattern pic', pat)# imshow(窗口名称, 图像矩阵),在窗口中显示图像,窗口自动调整到图像大小# cv.imwrite('1.png', template, [int(cv.IMWRITE_PNG_COMPRESSION), 9])# imwrite(文件名, 图像矩阵, 格式编码) 将图像矩阵以特定编码保存,暂时用不到# IMWRITE_PNG_COMPRESSION为png格式,0-9为压缩级别,9为不压缩,消耗时间最少cv.waitKey(0) # 等待键盘输入任意值,参数表示等待时间(ms),0表示一直等cv.destroyAllWindows() # 关闭所有窗口if return_pos == 'c':x = min_loc[0] + twidth // 2y = min_loc[1] + theight // 2elif return_pos == 'l':x = min_loc[0]y = min_loc[1]info('在句柄 {} 标题 {} 的窗口找到模式{}'.format(hwnd,win32gui.GetWindowText(hwnd),pattern))return (x, y, twidth, theight)except:if mode == 'test':traceback.print_exc()elif mode == 'real':error('找图 出现错误')def print_hitted_points(hitted_points, hwnd, deltas):'''测试用函数,根据hwnd找到截图文件(不要重新截图)并标注出点击过的点。Used for debug, find the big pic by hwnd (No PrtSc again) and mark the clicked pos.Args:hitted_points: 点击过的点。clicked points. hwnd: 用于找到大图。Used to find the big pic.deltas: 如果大图是客户区的一部分截图,该变量可描述大图左上角顶点在整个客户区中的位置。If the big pic is only part of the window, deltas would help describe big-pic's location (deltas is the left-top corner pos). Returns:No return. '''try:x1, y1, x2, y2 = hitted_pointsx1, x2 = x1 - deltas[0], x2 - deltas[0]y1, y2 = y1 - deltas[1], y2 - deltas[1]print('deltas = {}, '.format(deltas))print('hitted_points = ({},{}) ({},{})'.format(x1, y1, x2, y2))# 这样就得到了应该标注的坐标filename = 'yourpath\\{}.bmp'.format(hwnd)src = cv.imread(filename)if x2 < 0 and y2 < 0:cv.circle(src, (x1, y1), 1, (0, 0, 225), 4)# cv.circle(img, point, point_size, point_color, thickness)本来用来画圆的# 参数分别是图像矩阵、圆心、半径、线的颜色、稠度# 稠度可以取0、4、8,画出来点的大小不同cv.imshow('single one----hitted points', src)elif x1 == x2 and y1 == y2:cv.circle(src, (x1, y1), 1, (0, 0, 225), 4)cv.imshow('double same----hitted points', src)else:cv.circle(src, (x1, y1), 1, (0, 0, 225), 4)cv.circle(src, (x2, y2), 1, (0, 0, 225), 4)cv.imshow('double diff----hitted points', src)cv.waitKey(0)cv.destroyAllWindows()except:traceback.print_exc()def FindPic_RandomLeftClick(hwnd,pattern,max_try=20,time_interval=0.5,click_strategy=1,times='first',click_areas=None,find_pattern_in_area=None,r=4,platform='PC',click_pos='l',filename=''):'''从指定的句柄窗口寻找图片,若最大次数内找到则执行随机区域左键点击,否则返回False。返回点击的坐标(x1,y1,x2,y2),若只点击了一次则返回(x1,y1,-1,-1)。这是一个整合程度高函数,可能要看一下其中用到的其他函数。Find a pattern pic in the hwnd window, if not found after max_try, return False; if found, operate a click_strategy, and return clicked pos. If clicked only once, return (x1,y1,-1,-1). This func is highly intergrated. Turn to some called sub-funcs if confused. Args in detail:hwnd: 要截图并点击的窗口句柄。The window to PrtSc and click. pattern: 要寻找的模式小图。The pattern-pic's path to be found. max_try: 指定最多寻找的次数。If not found, after max_try, it will let go. time_interval指定每次寻找的间隔时间(实际查找间隔比该时间多一点)。Interval between each try (a little longer than given, in fact).click_strategy表示点击策略,详见Random_Areas_LeftClicks函数。Indicate the click strategy, see also in Random_Areas_LeftClicks(). times: 'first'表示从其他窗口转过来点击,用于调用Activate_Hwnd(hwnd)。If 'first', means target window is inactive/unfocused, thus call Activate_Hwnd(hwnd). click_areas: 可选的点击范围(矩形)。格式为[[x1,y1,x2,y2],[x3,y3,x4,y4]...],只有一个区域则可以写成[x1,y1,x2,y2]。为None时表示就点模式小图所在的区域。Possible rect-areas to click, given in the form of [[x1,y1,x2,y2],[x3,y3,x4,y4]...]. If only one area, [x1,y1,x2,y2] is also acceptable. If None, means to click the area where pattern pic is found. find_pattern_in_area: 指定在窗口客户区的哪个区域寻找模式图,为None时表示在整个客户区寻找。Which rect-area of the client area of the window to find the pattern pic. If None, means find in the whole area of the client area.find_pattern_in_area从技术上是只截取客户区该区域的图实现的。If not None, technically, it works by only PrtSc the partly area of the window's client area. r: 指示对指定的点击区域,应该内收多少个像素点。对于高或宽<4的模式图,可能需要自己把r设置成更小的值。Shrink r pixels for each click_area. For pat-pic smaller than 4 pixels, adjust r to a smaller value. platform: 目前无用。'PC'表示当前操作的是桌面版,不是安卓模拟器('AM')。Useless now. 'PC' means target window is PC, not Android manipulator ('AM').click_pos: 可取值'l'或'c',l表示left_top,后者表示center。详见Find_Pic()。Possible values are 'l' and 'c'. See also in Find_Pic(). 用于指示在窗口中找到模式图后,是返回其左上坐标还是中心点坐标(模式图长宽为奇数时返回值偏左上)。'l' means left-top corner pos, 'c' means center pos, used by Find_Pic(). 现在暂时只用'l'模式,'c'模式可能用于以后功能拓展。For now 'l' is enough, 'c' may help expand furthur functions. filename: 手动指定大图文件,从该文件中查找模式图。一般用不到。Indicate the big-pic's path manually, not used in ordinary applications. Returns:若最大次数后仍未找到模式图则返回False。若找到模式图,返回点击的坐标(x1,y1,x2,y2),若只点击了一次则返回(x1,y1,-1,-1)。If pattern pic not found after max_try, return False;if found, return clicked pos in (x1,y1,x2,y2). Return (x1,y1,-1,-1) if only clicked once. '''try:global modex, y = -1, -1deltas = (-1, -1) # 这是截图区域与整个客户区的左上顶点的相对位置。用于测试 # Used for debug, in print_hitted_points().for i in range(max_try):x, y, twidth, theight = Find_Pic(hwnd, pattern, 'l',find_pattern_in_area, filename)if x == -1 and y == -1:if mode == 'test':print('\r第{}次没找到'.format(i + 1), end='')sleep(time_interval)continueelse:if find_pattern_in_area == None: # 若使用默认的全客户区查找,返回的坐标是相对于整个客户区的delta_x, delta_y = 0, 0else: # 指定了查找区域,则返回的坐标是相对于查找区域的,需要转换一下delta_x, delta_y = find_pattern_in_area[0], find_pattern_in_area[1]if click_areas == None: # 不给出点击区域,则默认点击区域是窗口找到模式图片的区域click_areas = [[x + delta_x, y + delta_y, x + twidth + delta_x,y + theight + delta_y]]if mode == 'test':deltas = (delta_x, delta_y)breakif x == -1 and y == -1:info('未能找到并随机点击:对句柄 {} 标题 {} 的窗口未找到模式{},等待了{}次*{}秒'.format(hwnd, win32gui.GetWindowText(hwnd), pattern, max_try,time_interval))return Falseelse:if mode == 'test': # 在测试模式下,画出点击了窗口上的哪些点hitted_points = Random_Areas_LeftClicks(hwnd, click_areas, times, platform, r, click_strategy)print_hitted_points(hitted_points, hwnd, deltas)return hitted_pointselif mode == 'real':return Random_Areas_LeftClicks(hwnd, click_areas, times,platform, r, click_strategy)except:if mode == 'test':traceback.print_exc()elif mode == 'real':error('找图并随机左键点击 出现错误')if __name__ == '__main__':try:click_areas = [292, 175, 314, 192]find_pattern_in_area = [44, 82, 245, 313] # [44, 82, 100, 150]print(FindPic_RandomLeftClick(3212840, G('pattern1'),click_strategy=2))except:traceback.print_exc()
配置文件:
# 键盘码
VK_CODE = {'backspace': 0x08,'tab': 0x09,'clear': 0x0C,'enter': 0x0D,'shift': 0x10,'ctrl': 0x11,'alt': 0x12,'pause': 0x13,'caps_lock': 0x14,'esc': 0x1B,'spacebar': 0x20,'page_up': 0x21,'page_down': 0x22,'end': 0x23,'home': 0x24,'left_arrow': 0x25,'up_arrow': 0x26,'right_arrow': 0x27,'down_arrow': 0x28,'select': 0x29,'print': 0x2A,'execute': 0x2B,'print_screen': 0x2C,'ins': 0x2D,'del': 0x2E,'help': 0x2F,'0': 0x30,'1': 0x31,'2': 0x32,'3': 0x33,'4': 0x34,'5': 0x35,'6': 0x36,'7': 0x37,'8': 0x38,'9': 0x39,'a': 0x41,'b': 0x42,'c': 0x43,'d': 0x44,'e': 0x45,'f': 0x46,'g': 0x47,'h': 0x48,'i': 0x49,'j': 0x4A,'k': 0x4B,'l': 0x4C,'m': 0x4D,'n': 0x4E,'o': 0x4F,'p': 0x50,'q': 0x51,'r': 0x52,'s': 0x53,'t': 0x54,'u': 0x55,'v': 0x56,'w': 0x57,'x': 0x58,'y': 0x59,'z': 0x5A,'numpad_0': 0x60,'numpad_1': 0x61,'numpad_2': 0x62,'numpad_3': 0x63,'numpad_4': 0x64,'numpad_5': 0x65,'numpad_6': 0x66,'numpad_7': 0x67,'numpad_8': 0x68,'numpad_9': 0x69,'multiply_key': 0x6A,'add_key': 0x6B,'separator_key': 0x6C,'subtract_key': 0x6D,'decimal_key': 0x6E,'divide_key': 0x6F,'F1': 0x70,'F2': 0x71,'F3': 0x72,'F4': 0x73,'F5': 0x74,'F6': 0x75,'F7': 0x76,'F8': 0x77,'F9': 0x78,'F10': 0x79,'F11': 0x7A,'F12': 0x7B,'F13': 0x7C,'F14': 0x7D,'F15': 0x7E,'F16': 0x7F,'F17': 0x80,'F18': 0x81,'F19': 0x82,'F20': 0x83,'F21': 0x84,'F22': 0x85,'F23': 0x86,'F24': 0x87,'num_lock': 0x90,'scroll_lock': 0x91,'left_shift': 0xA0,'right_shift ': 0xA1,'left_control': 0xA2,'right_control': 0xA3,'left_menu': 0xA4,'right_menu': 0xA5,'browser_back': 0xA6,'browser_forward': 0xA7,'browser_refresh': 0xA8,'browser_stop': 0xA9,'browser_search': 0xAA,'browser_favorites': 0xAB,'browser_start_and_home': 0xAC,'volume_mute': 0xAD,'volume_Down': 0xAE,'volume_up': 0xAF,'next_track': 0xB0,'previous_track': 0xB1,'stop_media': 0xB2,'play/pause_media': 0xB3,'start_mail': 0xB4,'select_media': 0xB5,'start_application_1': 0xB6,'start_application_2': 0xB7,'attn_key': 0xF6,'crsel_key': 0xF7,'exsel_key': 0xF8,'play_key': 0xFA,'zoom_key': 0xFB,'clear_key': 0xFE,'+': 0xBB,',': 0xBC,'-': 0xBD,'.': 0xBE,'/': 0xBF,'`': 0xC0,';': 0xBA,'[': 0xDB,'\\': 0xDC,']': 0xDD,"'": 0xDE,'`': 0xC0
}
按键精灵 python加强版相关推荐
- 模拟器+(按键精灵+ python)实现自动化
模拟器列表: 安卓:安卓模拟器是能在个人计算机运行并模拟安卓手机系统的模拟器,并能安装.使用.卸载安卓应用的软件,利用安卓模拟器,用户即使没有手机硬件设备,也能在模拟器中使用移动应用程序.安卓模拟器能 ...
- 按键精灵 python程序互通_ERLANG和PYTHON互通实现过程详解
最近开发 Erlang ,对其字符串处理能力无言至极,于是决定把它和python联合起来,打造一个强力的分布式系统,等将来需要系统级开发时,我再把 C++/C组合进来. 首先参考了 Erlang 官方 ...
- 按键精灵pc版想试试能否自动英文视频转字幕结果....
结果卡在了找图,里面的大漠找图等都用不来 //*******************大漠插件注册开始*******************// set ws=createobject("Ws ...
- python找色_python实现按键精灵找色点击功能教程,使用pywin32和Pillow库
Python图片处理模块PIL(pillow) pywin32的主要作用 1.捕获窗口: 2.模拟鼠标键盘动作: 3.自动获取某路径下文件列表: 4.PIL截屏功能 找色点击功能思路: 抓取当前屏幕快 ...
- python 定时器_按键精灵定时器介绍和使用,不会的小伙伴速速看看精辟
金猪脚本(原飞猪脚本)以按键精灵教学为主,涉及UiBot,Python,Lua等脚本编程语言,教学包括全自动办公脚本,游戏辅助脚本,引流脚本,网页脚本,安卓脚本,IOS脚本,注册脚本,点赞脚本,阅读脚 ...
- python 按键精灵 离线_(番外篇)Python操纵网盘客户端批量离线下载电影
上回(Python实现电影排行榜自动网盘下载(4)Cookies免登录+抓包下载)说到,一段时间内能进行多少次离线下载还是受限于验证码的输入. 在此有两个解决方案, 见招拆招 通过GUI优化验证码输入 ...
- Python 实现按键精灵的功能,超简单详细(Windows版)
Python 实现按键精灵的功能,超简单详细 前言: 实现步骤 一.安装三个库 二.试运行简单的功能 三.根据需求自己写代码 注明 前言: 最近公司的同事让我帮他点点点,懒得亲自点,便在网上查找了相关 ...
- Python按键精灵自动化
最近在项目中需要进行软件的自动化操作. 本博文以两种方式介绍如何自动化打开软件(Windows下),对其进行最大化最小化关闭等操作. Python操作: 第一次接触自动化.相对比较熟悉Python自然 ...
- python 游戏按键精灵 PyDirectInput介绍
前言: 在python关于按键精灵得操作中常用的有PyAutoGUI,但在使用的过程中,针对一些游戏就直接失灵了,特别是一些以DirectX来开发的游戏或软件.我通过收索相关资料了解到之所以会这样,是 ...
最新文章
- IOError: Unable to open file (File signature not found)
- Sylius不需要缓存使用默认地址
- ipv6链路本地地址ping不通
- html页面退出用什么函数,离开网页弹窗函数onbeforeunload与onunload
- 光子浏览器_烟台招聘信息烟台光子信息科技有限公司招聘(五险一金,餐补)...
- TestNG和Maven配置指南
- python 类装饰器
- nginx配置中root与alias的区别
- 使用C#调试Windows服务模板项目
- ROS入门-11.客户端Client的编程实现
- php算法求出一个数可以被分解成多少个_小学数学必考的34个数学重难点公式,赶紧给孩子收藏!...
- John the Ripper 著名密码破解工具
- 中电网嵌入式系统主题月即将开幕
- JDK动态代理与CGLIB的区别
- 阶段3 2.Spring_09.JdbcTemplate的基本使用_6 JdbcDaoSupport的使用以及Dao的两种编写方式...
- extremecomponents
- maven命令打jar包
- mysql sniffer 官网下载_MySQL抓包工具:MySQL Sniffer 和性能优化
- 运维安全是指什么?如何做好运维安全?
- Java 中Lambda表达式的使用详解
热门文章
- 树莓派4B之火焰传感器模块(python3)
- android学习笔记之——获取SD卡及手机ROM容量
- Python周刊505期
- python生成订单失败_尝试在Steam上创建购买订单时请求错误(400)
- python 温度转换、货币转换
- win10修改用户名_win7如何设置局域网共享无需输入用户名和密码
- 17个练习自动化测试的网站,相信你一定喜欢
- SpringBoot工程使用shiro 进行MD5加密
- Uncertainty Quantification of Sparse Travel Demand Prediction with Spatial-Temporal Graph Neural Net
- windows输入法只有中文导致无法使用一系列快捷键问题