|
|
|
@ -10,7 +10,9 @@ import os
|
|
|
|
|
import select
|
|
|
|
|
import zlib
|
|
|
|
|
import win32api
|
|
|
|
|
import win32clipboard
|
|
|
|
|
import time
|
|
|
|
|
import traceback
|
|
|
|
|
from threading import Timer
|
|
|
|
|
|
|
|
|
|
mFlagIsDebug=False
|
|
|
|
@ -35,6 +37,7 @@ def AutomationSearchMouseElement(inElementSpecification,inFlagIsSearchOnline=Tru
|
|
|
|
|
lGUISearchElementSelected=None
|
|
|
|
|
#Настройка - частота обновления подсвечивания
|
|
|
|
|
lTimeSleepSeconds=0.4
|
|
|
|
|
lElementFoundedList=[]
|
|
|
|
|
#Ветка поиска в режиме реального времени
|
|
|
|
|
if inFlagIsSearchOnline:
|
|
|
|
|
#Сбросить нажатие Ctrl, если оно было
|
|
|
|
@ -50,7 +53,9 @@ def AutomationSearchMouseElement(inElementSpecification,inFlagIsSearchOnline=Tru
|
|
|
|
|
lElementFounded={}
|
|
|
|
|
#Создать карту пикселей и элементов
|
|
|
|
|
#####Внимание! Функция GUISearchElementByRootXY не написана
|
|
|
|
|
lElementFounded=GUISearchElementByRootXY(PywinautoExtElementGet(inElementSpecification),lX,lY)
|
|
|
|
|
lElementFoundedList=GUISearchElementByRootXY(PywinautoExtElementGet(inElementSpecification),lX,lY)
|
|
|
|
|
#print(lElementFoundedList)
|
|
|
|
|
lElementFounded=lElementFoundedList[-1]["element"]
|
|
|
|
|
#Подсветить объект, если он мышь раньше стояла на другом объекте
|
|
|
|
|
if lGUISearchElementSelected != lElementFounded:
|
|
|
|
|
lGUISearchElementSelected = lElementFounded
|
|
|
|
@ -64,6 +69,9 @@ def AutomationSearchMouseElement(inElementSpecification,inFlagIsSearchOnline=Tru
|
|
|
|
|
time.sleep(lTimeSleepSeconds)
|
|
|
|
|
#Ветка поиска по заранее созданной карте
|
|
|
|
|
else:
|
|
|
|
|
###################################
|
|
|
|
|
#Внимание Старая ветка (неправильный результат)
|
|
|
|
|
###################################
|
|
|
|
|
lBitmap={}
|
|
|
|
|
#Создать карту пикселей и элементов
|
|
|
|
|
lBitmap=GUISearchBitmapCreate(PywinautoExtElementGet(inElementSpecification),lBitmap)
|
|
|
|
@ -98,35 +106,42 @@ def AutomationSearchMouseElement(inElementSpecification,inFlagIsSearchOnline=Tru
|
|
|
|
|
#Заснуть до следующего цикла
|
|
|
|
|
time.sleep(lTimeSleepSeconds)
|
|
|
|
|
#Вернуть результат поиска
|
|
|
|
|
return lGUISearchElementSelected
|
|
|
|
|
return lElementFoundedList
|
|
|
|
|
|
|
|
|
|
def AutomationSearchMouseElementHierarchy(inElementSpecification,inFlagIsSearchOnline=True):
|
|
|
|
|
lItemInfo = None
|
|
|
|
|
lItemInfo = []
|
|
|
|
|
#Запустить функцию поиска элемента по мыши
|
|
|
|
|
lElement = AutomationSearchMouseElement(inElementSpecification,inFlagIsSearchOnline)
|
|
|
|
|
lElementList = AutomationSearchMouseElement(inElementSpecification,inFlagIsSearchOnline)
|
|
|
|
|
lElement = lElementList[-1]['element']
|
|
|
|
|
#Detect backend of the elements
|
|
|
|
|
lFlagIsBackendWin32 = True
|
|
|
|
|
#Если объект имеется (не None), то выполнить построение иерархии
|
|
|
|
|
#pdb.set_trace()
|
|
|
|
|
if lElement is not None:
|
|
|
|
|
if lElement.backend.name == 'uia':
|
|
|
|
|
lFlagIsBackendWin32 = False
|
|
|
|
|
#Циклическое создание дерева
|
|
|
|
|
while lElement is not None:
|
|
|
|
|
#while lElement is not None:
|
|
|
|
|
lListIterator=0
|
|
|
|
|
lItemInfo2=lItemInfo
|
|
|
|
|
for lListItem in lElementList:
|
|
|
|
|
lElement = lListItem["element"]
|
|
|
|
|
#Продолжать построение иерархии во всех случаях кроме бэк uia & parent() is None
|
|
|
|
|
if not lFlagIsBackendWin32 and lElement.parent() is None:
|
|
|
|
|
lElement = None
|
|
|
|
|
else:
|
|
|
|
|
#if not lFlagIsBackendWin32 and lElement.parent() is None:
|
|
|
|
|
# lElement = None
|
|
|
|
|
#else:
|
|
|
|
|
#Получить информацию про объект
|
|
|
|
|
lItemInfo2 = ElementInfoExportObject(lElement.element_info)
|
|
|
|
|
lItemInfo2.append(ElementInfoExportObject(lElement.element_info))
|
|
|
|
|
#Дообогатить информацией об индексе ребенка в родительском объекте
|
|
|
|
|
lItemInfo2['ctrl_index']=PywinautoExtElementCtrlIndexGet(lElement)
|
|
|
|
|
lItemInfo2[-1]['ctrl_index']=lListItem["index"]
|
|
|
|
|
#Оборачиваем потомка в массив, потому что у родителя по структуре интерфейса может быть больше одного наследников
|
|
|
|
|
lItemInfo2['SpecificationChild']=[lItemInfo]
|
|
|
|
|
lItemInfo=lItemInfo2
|
|
|
|
|
lItemInfo2[-1]['SpecificationChild']=[]
|
|
|
|
|
lItemInfo2=lItemInfo2[-1]['SpecificationChild']
|
|
|
|
|
#Переход на родительский объект
|
|
|
|
|
lElement = lElement.parent()
|
|
|
|
|
#lElement = lElement.parent()
|
|
|
|
|
lListIterator=lListIterator+1
|
|
|
|
|
#Вернуть результат
|
|
|
|
|
return [lItemInfo]
|
|
|
|
|
return lItemInfo
|
|
|
|
|
#return [1,2,3,4,5,3]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -161,39 +176,104 @@ def PywinautoExtElementCtrlIndexGet(inElement):
|
|
|
|
|
lFlagFind=False
|
|
|
|
|
#Вернуть результат
|
|
|
|
|
return lResult
|
|
|
|
|
#Получить элемент через расширенный движок поиска
|
|
|
|
|
#Получить список элементов, который удовлетворяет условиям через расширенный движок поиска
|
|
|
|
|
#[ {
|
|
|
|
|
#"index":<Позиция элемента в родительском объекте>,
|
|
|
|
|
#
|
|
|
|
|
# "depth_start" - глубина, с которой начинается поиск (по умолчанию 1)
|
|
|
|
|
# "depth_end" - глубина, до которой ведется поиск (по умолчанию 1)
|
|
|
|
|
# "class_name" - наименование класса, который требуется искать
|
|
|
|
|
# "title" - наименование заголовка
|
|
|
|
|
# "rich_text" - наименование rich_text
|
|
|
|
|
#} ]
|
|
|
|
|
def PywinautoExtElementGet (inSpecificationList,inElement=None):
|
|
|
|
|
lResult=None
|
|
|
|
|
lChildElement=None
|
|
|
|
|
def PywinautoExtElementsGet (inSpecificationList,inElement=None):
|
|
|
|
|
lResultList=[]
|
|
|
|
|
lChildrenList=[]
|
|
|
|
|
#Получить родительский объект если на вход ничего не поступило
|
|
|
|
|
if inElement is None:
|
|
|
|
|
#сформировать спецификацию на получение элемента
|
|
|
|
|
lRootElementSpecification=[inSpecificationList[0]]
|
|
|
|
|
lChildElement=GetControl(lRootElementSpecification)
|
|
|
|
|
lChildrenList.append(GetControl(lRootElementSpecification))
|
|
|
|
|
if lChildrenList[0] is not None:
|
|
|
|
|
lChildrenList[0] = lChildrenList[0].wrapper_object()
|
|
|
|
|
#Елемент на вход поступил - выполнить его анализ
|
|
|
|
|
else:
|
|
|
|
|
#Поступил index
|
|
|
|
|
#Получить список элементов
|
|
|
|
|
lElementChildrenList=inElement.children()
|
|
|
|
|
#Поступил index - точное добавление
|
|
|
|
|
if 'index' in inSpecificationList[0]:
|
|
|
|
|
lChildrenList=inElement.children()
|
|
|
|
|
if inSpecificationList[0]['index']<len(lChildrenList):
|
|
|
|
|
#Получить дочерний элемент
|
|
|
|
|
lChildElement=lChildrenList[inSpecificationList[0]['index']]
|
|
|
|
|
#Поступил ctrl_index
|
|
|
|
|
if inSpecificationList[0]['index']<len(lElementChildrenList):
|
|
|
|
|
#Получить дочерний элемент - точное добавление
|
|
|
|
|
lChildrenList.append(lElementChildrenList[inSpecificationList[0]['index']])
|
|
|
|
|
else:
|
|
|
|
|
raise ValueError('Object has no children with index: ' + str(inSpecificationList[0]['index']))
|
|
|
|
|
#Поступил ctrl_index - точное добавление
|
|
|
|
|
elif 'ctrl_index' in inSpecificationList[0]:
|
|
|
|
|
lChildrenList=inElement.children()
|
|
|
|
|
if inSpecificationList[0]['ctrl_index']<len(lChildrenList):
|
|
|
|
|
if inSpecificationList[0]['ctrl_index']<len(lElementChildrenList):
|
|
|
|
|
#Получить дочерний элемент
|
|
|
|
|
lChildElement=lChildrenList[inSpecificationList[0]['ctrl_index']]
|
|
|
|
|
#Выполнить рекурсивный вызов, если спецификация больше одного элемента
|
|
|
|
|
if len(inSpecificationList)>1 and lChildElement is not None:
|
|
|
|
|
lChildrenList.append(lElementChildrenList[inSpecificationList[0]['ctrl_index']])
|
|
|
|
|
else:
|
|
|
|
|
raise ValueError('Object has no children with index: ' + str(inSpecificationList[0]['ctrl_index']))
|
|
|
|
|
#Если нет точного обозначения элемента
|
|
|
|
|
else:
|
|
|
|
|
lFlagGoCheck=True
|
|
|
|
|
#Учесть поле depth_start (если указано)
|
|
|
|
|
if 'depth_start' in inSpecificationList[0]:
|
|
|
|
|
if inSpecificationList[0]["depth_start"]>1:
|
|
|
|
|
lFlagGoCheck=False
|
|
|
|
|
#pdb.set_trace()
|
|
|
|
|
#Циклический обход по детям, на предмет соответствия всем условиям
|
|
|
|
|
for lChildrenItem in lElementChildrenList:
|
|
|
|
|
#Обработка глубины depth (рекурсивный вызов для всех детей с занижением индекса глубины)
|
|
|
|
|
#По умолчанию значение глубины 1
|
|
|
|
|
if 'depth_end' in inSpecificationList[0]:
|
|
|
|
|
if inSpecificationList[0]['depth_end']>1:
|
|
|
|
|
#Подготовка новой версии спецификации
|
|
|
|
|
lChildrenItemNewSpecificationList=inSpecificationList.copy()
|
|
|
|
|
lChildrenItemNewSpecificationList[0]=lChildrenItemNewSpecificationList[0].copy()
|
|
|
|
|
lChildrenItemNewSpecificationList[0]["depth_end"]=lChildrenItemNewSpecificationList[0]["depth_end"]-1
|
|
|
|
|
if 'depth_start' in lChildrenItemNewSpecificationList[0]:
|
|
|
|
|
lChildrenItemNewSpecificationList[0]["depth_start"]=lChildrenItemNewSpecificationList[0]["depth_start"]-1
|
|
|
|
|
#pdb.set_trace()
|
|
|
|
|
#Циклический вызов для всех детей со скорректированной спецификацией
|
|
|
|
|
lResultList.extend(PywinautoExtElementsGet(lChildrenItemNewSpecificationList,lChildrenItem))
|
|
|
|
|
#Фильтрация
|
|
|
|
|
if lFlagGoCheck:
|
|
|
|
|
lFlagAddChild=True
|
|
|
|
|
#Фильтрация по title
|
|
|
|
|
if 'title' in inSpecificationList[0]:
|
|
|
|
|
if lChildrenItem.element_info.name != inSpecificationList[0]["title"]:
|
|
|
|
|
lFlagAddChild=False
|
|
|
|
|
#Фильтрация по rich_text
|
|
|
|
|
if 'rich_text' in inSpecificationList[0]:
|
|
|
|
|
if lChildrenItem.element_info.rich_text != inSpecificationList[0]["rich_text"]:
|
|
|
|
|
lFlagAddChild=False
|
|
|
|
|
#Фильтрация по class_name
|
|
|
|
|
if 'class_name' in inSpecificationList[0]:
|
|
|
|
|
if lChildrenItem.element_info.class_name != inSpecificationList[0]["class_name"]:
|
|
|
|
|
lFlagAddChild=False
|
|
|
|
|
#####
|
|
|
|
|
#Все проверки пройдены - флаг добавления
|
|
|
|
|
if lFlagAddChild:
|
|
|
|
|
lChildrenList.append(lChildrenItem)
|
|
|
|
|
#Выполнить рекурсивный вызов (уменьшение количества спецификаций), если спецификация больше одного элемента
|
|
|
|
|
if len(inSpecificationList)>1 and len(lChildrenList)>0 is not None:
|
|
|
|
|
#Вызвать рекурсивно функцию получения следующего объекта, если в спецификации есть следующий объект
|
|
|
|
|
lResult=PywinautoExtElementGet(inSpecificationList[1:],lChildElement)
|
|
|
|
|
for lChildElement in lChildrenList:
|
|
|
|
|
lResultList.extend(PywinautoExtElementsGet(inSpecificationList[1:],lChildElement))
|
|
|
|
|
else:
|
|
|
|
|
lResult=lChildElement
|
|
|
|
|
lResultList.extend(lChildrenList)
|
|
|
|
|
return lResultList
|
|
|
|
|
#Получить элемент через расширенный движок поиска
|
|
|
|
|
#[ {
|
|
|
|
|
#"index":<Позиция элемента в родительском объекте>,
|
|
|
|
|
#
|
|
|
|
|
#} ]
|
|
|
|
|
def PywinautoExtElementGet (inSpecificationList,inElement=None):
|
|
|
|
|
lResult=None
|
|
|
|
|
#Получить родительский объект если на вход ничего не поступило
|
|
|
|
|
lResultList=PywinautoExtElementsGet(inSpecificationList,inElement)
|
|
|
|
|
if len(lResultList)>0:
|
|
|
|
|
lResult=lResultList[0]
|
|
|
|
|
return lResult
|
|
|
|
|
################################
|
|
|
|
|
#Функция повторяющегося таймера
|
|
|
|
@ -432,13 +512,18 @@ def GUISearchRun(inSpecificationArray):
|
|
|
|
|
#############################################################
|
|
|
|
|
#Поиск элементов
|
|
|
|
|
#############################################################
|
|
|
|
|
def GUISearchElementByRootXY(inRootElement,inX,inY):
|
|
|
|
|
#inHierarchyList: [{"index":<>,"element":<>}]
|
|
|
|
|
#
|
|
|
|
|
#Вернуть словарь [{"index":<>,"element":<>}]
|
|
|
|
|
#Последний элемент - искомый
|
|
|
|
|
def GUISearchElementByRootXY(inRootElement,inX,inY,inHierarchyList=[]):
|
|
|
|
|
#Инициализация результирующего значения
|
|
|
|
|
lResultElement = None
|
|
|
|
|
lResultElementX1 = None
|
|
|
|
|
lResultElementX2 = None
|
|
|
|
|
lResultElementY1 = None
|
|
|
|
|
lResultElementY2 = None
|
|
|
|
|
lResultHierarchyList=[{'index':None,'element':None}]
|
|
|
|
|
#Получить координаты текущего объекта
|
|
|
|
|
try:
|
|
|
|
|
lRootElementRectX1=inRootElement.element_info.rectangle.left
|
|
|
|
@ -452,9 +537,21 @@ def GUISearchElementByRootXY(inRootElement,inX,inY):
|
|
|
|
|
lResultElementX2 = lRootElementRectX2
|
|
|
|
|
lResultElementY1 = lRootElementRectY1
|
|
|
|
|
lResultElementY2 = lRootElementRectY2
|
|
|
|
|
#Сформировать результирующий обьъект
|
|
|
|
|
lParentHierarchy = inHierarchyList
|
|
|
|
|
if len(lParentHierarchy)==0:
|
|
|
|
|
lParentHierarchy.append({"index":None,"element":lResultElement})
|
|
|
|
|
else:
|
|
|
|
|
lParentHierarchy[-1]["element"] = lResultElement
|
|
|
|
|
lResultHierarchyList=lParentHierarchy
|
|
|
|
|
#Получить список детей и добавить в карту
|
|
|
|
|
lChildIterator=0
|
|
|
|
|
for lChildElement in inRootElement.children():
|
|
|
|
|
lChildFoundedElement = GUISearchElementByRootXY(lChildElement,inX,inY)
|
|
|
|
|
#Сформировать результирующий массив
|
|
|
|
|
lChildFoundedHierarchyList = lParentHierarchy.copy()
|
|
|
|
|
lChildFoundedHierarchyList.append({'index': lChildIterator})
|
|
|
|
|
lChildFoundedHierarchyList = GUISearchElementByRootXY(lChildElement,inX,inY, lChildFoundedHierarchyList)
|
|
|
|
|
lChildFoundedElement = lChildFoundedHierarchyList[-1]["element"]
|
|
|
|
|
#Установить обнаруженный элемент, если текущий результат пустой
|
|
|
|
|
if lResultElement is None and lChildFoundedElement is not None:
|
|
|
|
|
lResultElement = lChildFoundedElement
|
|
|
|
@ -462,6 +559,7 @@ def GUISearchElementByRootXY(inRootElement,inX,inY):
|
|
|
|
|
lResultElementX2 = lResultElement.element_info.rectangle.right
|
|
|
|
|
lResultElementY1 = lResultElement.element_info.rectangle.top
|
|
|
|
|
lResultElementY2 = lResultElement.element_info.rectangle.bottom
|
|
|
|
|
lResultHierarchyList = lChildFoundedHierarchyList
|
|
|
|
|
#Выполнить сверку lChildFoundedElement и lResultElement если оба имеются
|
|
|
|
|
elif lResultElement is not None and lChildFoundedElement is not None:
|
|
|
|
|
#Правила перезатирания карты, если имеется старый объект
|
|
|
|
@ -488,6 +586,7 @@ def GUISearchElementByRootXY(inRootElement,inX,inY):
|
|
|
|
|
lResultElementX2 = lChildFoundedElementX2
|
|
|
|
|
lResultElementY1 = lChildFoundedElementY1
|
|
|
|
|
lResultElementY2 = lChildFoundedElementY2
|
|
|
|
|
lResultHierarchyList = lChildFoundedHierarchyList
|
|
|
|
|
#Проверка вхождения по типу 2
|
|
|
|
|
else:
|
|
|
|
|
lResultElement = lChildFoundedElement
|
|
|
|
@ -495,9 +594,11 @@ def GUISearchElementByRootXY(inRootElement,inX,inY):
|
|
|
|
|
lResultElementX2 = lChildFoundedElementX2
|
|
|
|
|
lResultElementY1 = lChildFoundedElementY1
|
|
|
|
|
lResultElementY2 = lChildFoundedElementY2
|
|
|
|
|
lResultHierarchyList = lChildFoundedHierarchyList
|
|
|
|
|
lChildIterator=lChildIterator+1
|
|
|
|
|
except Exception as e:
|
|
|
|
|
False == False
|
|
|
|
|
return lResultElement
|
|
|
|
|
return lResultHierarchyList
|
|
|
|
|
#Техническая функция
|
|
|
|
|
|
|
|
|
|
def GUISearchBitmapCreate (inElement,inBitmapDict={}):
|
|
|
|
@ -918,6 +1019,26 @@ def draw_outline_new(lWrapperObject,colour='green',thickness=2,fill=win32defines
|
|
|
|
|
#Аналог подсвечивания + установка фокуса
|
|
|
|
|
def draw_outline_new_focus(lWrapperObject,colour='green',thickness=2,fill=win32defines.BS_NULL,rect=None):
|
|
|
|
|
draw_outline_new(lWrapperObject,'green',2,win32defines.BS_NULL,None,True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
################
|
|
|
|
|
###GeneralClipboardGet
|
|
|
|
|
################
|
|
|
|
|
def GeneralClipboardGet():
|
|
|
|
|
win32clipboard.OpenClipboard()
|
|
|
|
|
lResult = win32clipboard.GetClipboardData()
|
|
|
|
|
win32clipboard.CloseClipboard()
|
|
|
|
|
return lResult
|
|
|
|
|
################
|
|
|
|
|
###GeneralClipboardSet
|
|
|
|
|
################
|
|
|
|
|
def GeneralClipboardSet(inText):
|
|
|
|
|
win32clipboard.OpenClipboard()
|
|
|
|
|
win32clipboard.EmptyClipboard()
|
|
|
|
|
win32clipboard.SetClipboardText(inText)
|
|
|
|
|
win32clipboard.CloseClipboard()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#run()
|
|
|
|
|
lText = "Bitness:" + str(struct.calcsize("P") * 8)
|
|
|
|
|
#for line in sys.stdin:
|
|
|
|
@ -941,7 +1062,7 @@ if not mFlagIsDebug:
|
|
|
|
|
ProcessParentWriteObject(lJSONInput)
|
|
|
|
|
except Exception as e:
|
|
|
|
|
#Вывод ошибки в родительский поток
|
|
|
|
|
ProcessParentWriteObject({'Error':str(e), 'ArgObject':str(lJSONInputString)})
|
|
|
|
|
ProcessParentWriteObject({'Error':str(e) + traceback.format_exc(), 'ArgObject':str(lJSONInputString)})
|
|
|
|
|
#ctypes.windll.user32.MessageBoxW(0, str(e), "Your title", 1)
|
|
|
|
|
else:
|
|
|
|
|
print('Debug mode is turned on!')
|
|
|
|
|