You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ORPA-pyOpenRPA/winGUI.py

753 lines
35 KiB

6 years ago
from http.server import BaseHTTPRequestHandler, HTTPServer
from pywinauto import win32defines, win32structures, win32functions
import pdb
import pywinauto
import json
import sys
import ctypes
import struct
import os
import select
import zlib
import win32api
import time
from threading import Timer
mFlagIsDebug=False
mPywinautoApplication=pywinauto.Application(backend="win32")
#mPywinautoApplication=pywinauto.Application(backend="uia")
#####
##Внимание! Нельзя делать print так как он уходит в родительский поток и ломает механизм взаимодействия
##Чтобы его использовать надо писать функцию обертку
#####
###########################
####Модуль Automation
###########################
#inElementSpecificationList = [ [{lvl_0},{lvl_1},{lvl_2}],... ]
#result = pywinauto element wrapper instance or None
def AutomationSearchMouseElement(inElementSpecification):
lBitmap={}
lGUISearchElementSelected=None
#Создать карту пикселей и элементов
lBitmap=GUISearchBitmapCreate(GetControl(inElementSpecification),lBitmap)
#Выдать сообщение, что поиск готов к использованию
#print("GUISearch: Ready for search!")
###########
#Версия с задержкой (без таймеров, событий в отдельных потоках)
###########
#Сбросить нажатие Ctrl, если оно было
bool(win32api.GetAsyncKeyState(17))
#Настройка - частота обновления подсвечивания
lTimeSleepSeconds=0.7
lFlagLoop = True
while lFlagLoop:
#Проверить, нажата ли клавиша Ctrl (код 17)
lFlagKeyPressedCtrl=bool(win32api.GetAsyncKeyState(17))
#Подсветить объект, если мышка наведена над тем объектом, который не подсвечивался в прошлый раз
if not lFlagKeyPressedCtrl:
#Получить координаты мыши
(lX,lY) = win32api.GetCursorPos()
#Подсветить объект, если мышь над ним
if (lX,lY) in lBitmap:
if lGUISearchElementSelected != lBitmap[lX,lY]:
lGUISearchElementSelected = lBitmap[lX,lY]
#Классическая функция отрисовки (из pywinauto)
#lBitmap[lX,lY].draw_outline()
#Доработанная функция отрисовки
draw_outline_new(lBitmap[lX,lY])
else:
lGUISearchElementSelected = None
else:
#Была нажата клавиша Ctrl - выйти из цикла
lFlagLoop=False;
#Заснуть до следующего цикла
time.sleep(lTimeSleepSeconds)
#Вернуть результат поиска
return lGUISearchElementSelected
def AutomationSearchMouseElementHierarchy(inElementSpecification):
lItemInfo = None
#Запустить функцию поиска элемента по мыши
lElement = AutomationSearchMouseElement(inElementSpecification)
#Detect backend of the elements
lFlagIsBackendWin32 = True
if lElement.backend.name == 'uia':
lFlagIsBackendWin32 = False
#Если объект имеется (не None), то выполнить построение иерархии
if lElement is not None:
#Циклическое создание дерева
while lElement is not None:
#Продолжать построение иерархии во всех случаях кроме бэк uia & parent() is None
if not lFlagIsBackendWin32 and lElement.parent() is None:
lElement = None
else:
#Получить информацию про объект
lItemInfo2 = ElementInfoExportObject(lElement.element_info)
#Дообогатить информацией об индексе ребенка в родительском объекте
lItemInfo2['ctrl_index']=PywinautoExtElementCtrlIndexGet(lElement)
#Оборачиваем потомка в массив, потому что у родителя по структуре интерфейса может быть больше одного наследников
lItemInfo2['SpecificationChild']=[lItemInfo]
lItemInfo=lItemInfo2
#Переход на родительский объект
lElement = lElement.parent()
#Вернуть результат
return [lItemInfo]
#return [1,2,3,4,5,3]
###########################
####Модуль PywinautoExt
###########################
def PywinautoExtElementCtrlIndexGet(inElement):
lResult = None
#Выполнить алгоритм, если есть Element
if inElement is not None:
lElementParent = inElement.parent()
if lElementParent is not None:
lResult = 0
lFlagFind = True
#Получить список потомков
lElementParentChildrenList = lElementParent.children()
#Циклический поиск до того момента, пока не упремся в текущий элемент
while lFlagFind:
#Прекратить поиск, если элемент был обнаружен
if inElement == lElementParentChildrenList[lResult]:
lFlagFind = False
else:
#Прекратить поиски, если итератор вышел за пределы списка
if lResult>=len(lElementParentChildrenList):
lResult = None
lFlagFind = False
else:
lResult = lResult + 1
#Вернуть результат
return lResult
################################
#Функция повторяющегося таймера
#############################
class RepeatedTimer(object):
def __init__(self, interval, function, *args, **kwargs):
self._timer = None
self.interval = interval
self.function = function
self.args = args
self.kwargs = kwargs
self.is_running = False
self.start()
def _run(self):
self.is_running = False
self.start()
self.function(*self.args, **self.kwargs)
def start(self):
if not self.is_running:
self._timer = Timer(self.interval, self._run)
self._timer.start()
self.is_running = True
def stop(self):
self._timer.cancel()
self.is_running = False
#mTimer.start() # after 30 seconds, "hello, world" will be printed
#Флаг отладки напрямую (не выполнять чтение буфера stdin)
############################################
####Межпроцессное взаимодействие
############################################
#ProcessParentReadWaitString
def ProcessParentReadWaitString():
#Выполнить чтение строки
#ctypes.windll.user32.MessageBoxW(0, "Hello", "Your title", 1)
lResult = sys.stdin.buffer.readline()
#Вернуть потенциальные \n
lResult = lResult.replace(b'{{n}}',b'\n')
lResult = zlib.decompress(lResult[0:-1])
lResult = lResult.decode("utf-8")
#Вернуть результат
return lResult
#ParentProcessWriteString
def ProcessParentWriteString(lString):
lByteString = zlib.compress(lString.encode("utf-8"))
#Выполнить отправку строки в родительский процесс
#Вернуть потенциальные \n
lByteString = lByteString.replace(b'\n',b'{{{n}}}')
#Вернуть \r
lByteString = lByteString.replace(b'\r',b'{{{r}}}')
#Вернуть \0
lByteString = lByteString.replace(b'\0',b'{{{0}}}')
#Вернуть \a
lByteString = lByteString.replace(b'\a',b'{{{a}}}')
#Вернуть \b
lByteString = lByteString.replace(b'\b',b'{{{b}}}')
#Вернуть \t
lByteString = lByteString.replace(b'\t',b'{{{t}}}')
#Вернуть \v
lByteString = lByteString.replace(b'\v',b'{{{v}}}')
#Вернуть \f
lByteString = lByteString.replace(b'\f',b'{{{f}}}')
############################
#print(b"Result: "+lByteString)
#lByteString= b'x\x9c\xdd\x95]O\xc20\x14\x86\xffJ\xb3[5\xa1Cqz\x07\xc4\xe8\x8d\x1fQ\x13.\x0cYJw\xb6U\xbav\xe9\xce"\x84\xf0\xdfm\'"\xb8\xa0L%Q\xb3\x9b\xf6=\xdfO\x9a\xb3\x99\x17\x97\x8a\xa3\xd0\xea\x8ae\xe0\x9d\x12\xaf[\xa2\xce\x98S\xee\x80\x19\x9e^\xea\xb2\x803\t\x19(\xbc\x10`\x9c6\xf5\xf6\x89\xc7LRt\x8daS\x1b\xf5\xf00\xf3\xd4"\xc1u\x0e\xea\xf6\xa6K\x0e\xc8\xb9\xd6\x89\x04\xd2O\x8d\xb6&\x1bb\x04OC\x84\t~\xe2\x97\x1b\xcd\xa1(B\x11YG\xdaj\xfb\xc1\x9b\xb8\xa2\xa4LE\xd2\xd5\xa4\xf6\xdenY\x85Kf\xc3^;yI\x18\x0eD\x94\x00\x0e\x84{{n}}\xa9K\xce\xb5B\xa3e\x88\xd3\xbc\xf2Z\xd5\xaa\x82\xaa\x94\xd25\x0b\x1c\x99J\xaa\x023OB\xec\xbavEP\xe7\x8b\x93\x11I\xeaTz\xe2\xbb\xebH\xa3eW5\xe8\xb7\xe6\xce^*\x14\xb6\x83e\xda\xf9phe]b^\xe2\xf5\xe8\xd1Vp\xf0\xfe.\xbb\x1b\xa6`\x87\xfc8\x1a\x9bSE0q\xa2\x15\xeer\xe0"\x16\xbcz\x9f\xfdT\xc8h\x9d\xdf\xc7\xd4\xbe\xcdj1\xd9:\xa9\x1f\xe1B7\x81\xa1\xef\xc0\xd0:\x98\xc3-\xc0\xd4X\xfc\xda\xf1i\xbb\xe9\xfc\xdb<\x8c\xff2\x7f\'\xa8\x8d\xdf\xdab\xfc\x9e\xd6\xe3\x8c\x99qQ\xe3\xb0f\xd9\x19\x90{\xade\x8f\x99/3\xa1AC(\xfe\x16P\x06F \x90\xb3\t\x07Iba\x17\x83P\xa4\xbf\xb7G\x9e\x04\xa6vE\x13\xb6\xfc\x13\xd6\xa85\x0b\xdd\x19\xd6^i\x11\xa8FT;G\xfe\x06\xac\xc1q\xb0N\x956\xd84\xae\xe4p\xbe\xfa=\x03\x01\xce\x95\x9a'
#lByteString = b"x\x9c\xb5\x91\xcfO\xc3 \x14\xc7\xff\x95\xa6\xd7uI\xf9Q\x8a\xde\xd4\x93\x07\xbdx\xf00\x97\x05)[I(\x90\x8ef3\xcb\xfew\x81M\xbb\xd9M]\x8c!y\xd0\xf7}\xbc\xef\xe3\xd3\xc9&\xd5\xac\x11\xe9u\x92j\xb1J@2N\x1e\x8d\x13\x96U\xa3Q\x9a%i+y=sb\xed\xceV\xd8\xd6p\xb1\\\xced\xe5K{{n}}\x80`\x9f\xeb\x135\xd3\x95{{n}}.\x08RR\xe4>\xc3\x15\xf3\x97>\xbc\x8f:r\xa3]k\xd4\xcc\xbd\xd9(>K]\x99\xd5\xa1\x12\xbd\x00\xc6\xb0\xcc\xcb0\xa4\xe0\x8e\xe9E4\xd8\xa4J\xcc\xc3\xb44\x07^r\xc6\xfa3\x04(\xbeeQ\x07\x05P\x1a\xa4W\xe3\x9ci\xfc\xf7\x15(\xb6A\xee\xb4\x93\x8d\xd85\x9f`?\xf6n\xd8i0v\xadw\xd5\x95X\x87n>\xf1d\x05\x97s\xc9\x99\x93F\xdf\xd5R\xc5K=\xcc\x1bk\xd5^\x1d`\xfc\xa2]\x06PwJ\r\xf0\x9d\xa2\xf6 tw\xcb\xda\x01\xb6}\x83\xd3\xcc\x00\xec\x99\x15\xf4\x88Y\x99\x1f2\x83\xb4\xfc\x8e\x99\xdf\xb3d\x0c\x01.1E\x04\x93l\xff\x8e\xcf\x7f6\xa4Z\xfc\x82\xeaK\x97c BD\xf3\x101\x89g\xba\x8b\x03\xd0?\x97\xff#\xfb{'\x9a\x8b\xe0\x03H\xc89\xfa\x08\x15\x7f\xa2\x0f >\x80_\x0e\xe0\x93\xb3\xf0\xc3\xc4\xd3m\\\xef\xf8\x958\xa0"
lt=open("logSendByteStringWithoutN.log","wb")
lt.write(lByteString)
lt.close()
############################
sys.stdout.buffer.write(lByteString+bytes("\n","utf-8"))
sys.stdout.flush();
return
#ProcessParentWriteObject
def ProcessParentWriteObject(inObject):
#Выполнить отправку сконвертированного объекта в JSON
ProcessParentWriteString(json.dumps(inObject))
return
#ProcessParentReadWaitObject
def ProcessParentReadWaitObject():
#Выполнить получение и разбор объекта
lResult=json.loads(ProcessParentReadWaitString());
return lResult;
##################################
###Методы взаимодействия с GUI интерфейсом
##################################
#pywinauto
def GetControl(inControlSpecificationArray):
#Подготовка взодного массива
inControlSpecificationArray=ElementSpecificationArraySearchPrepare(inControlSpecificationArray)
#Выполнить идентификацию объектов, если передан массив
lResultList=[];
if len(inControlSpecificationArray) > 0:
#Выполнить подключение к объекту
lRPAApplication = pywinauto.Application()
#Проверка разрядности
lRPAApplication.connect(**inControlSpecificationArray[0])
#lTempObject=lRPAApplication.window(**inControlSpecificationArray[0])
#Скорректировано из-за недопонимания структуры
lTempObject=lRPAApplication
#Нормализация массива для целей выборки объекта (удаление конфликтующих ключей)
inControlSpecificationArray=ElementSpecificationListNormalize(inControlSpecificationArray)
#Циклическое прохождение к недрам объекта
for lWindowSpecification in inControlSpecificationArray[0:]:
lTempObject=lTempObject.window(**lWindowSpecification)
return lTempObject
#Получить массив свойств и методов у элемента
def ElementActionGetList (inControlSpecificationArray):
#Получить объект
lObject=GetControl(inControlSpecificationArray)
return dir(lObject.wrapper_object())
#Выполнить действие над элементом
def ElementRunAction(inControlSpecificationArray,inActionName,inArgumentList=[],inkwArgumentObject={}):
#Определить объект
lObject=GetControl(inControlSpecificationArray)
#Получить метод для вызова
lFunction = getattr(lObject.wrapper_object(), inActionName)
#Выполнить действие
return lFunction(*inArgumentList,**inkwArgumentObject)
def ElementGetInfo(inControlSpecificationArray):
#Подготовка входного массива
inControlSpecificationArray=ElementSpecificationArraySearchPrepare(inControlSpecificationArray)
#Выполнить идентификацию объектов, если передан массив
lResultList=[];
if len(inControlSpecificationArray) > 0:
#Получить объект
lTempObject=GetControl(inControlSpecificationArray)
#Получить инфо объект
lTempObjectInfo = lTempObject.wrapper_object().element_info
#Добавить информацию об обнаруженом объекте
lResultList.append(ElementInfoExportObject(lTempObjectInfo));
return lResultList
############################################
###Модуль поиска объекта на экране
############################################
#Инициализация глобальных переменных
mBitmap={}
mGUISearchElementSelected={}
def GUISearchEvent_on_move(lX, lY):
global mBitmap
global mGUISearchElementSelected
if (lX,lY) in mBitmap:
if mGUISearchElementSelected != mBitmap[lX,lY]:
mGUISearchElementSelected = mBitmap[lX,lY]
mBitmap[lX,lY].draw_outline()
def GUISearchEvent_on_click(x, y, button, pressed):
global mBitmap
global mGUISearchElementSelected
print('{0} at {1}'.format(
'Pressed' if pressed else 'Released',
(x, y)))
print(str(len(mBitmap)))
if not pressed:
# Stop listener
del mBitmap
mBitmap={}
del mGUISearchElementSelected
mGUISearchElementSelected={}
return False
def GUISearchEvent_on_scroll(x, y, dx, dy):
print('Scrolled {0} at {1}'.format(
'down' if dy < 0 else 'up',
(x, y)))
#Создать bitmap карту объектов
#GUISearchBitmapCreate
#inElement - wrapper_object()
# dict: x_y_ : elementObject
def GUISearchRun(inSpecificationArray):
lBitmap={}
lGUISearchElementSelected=None
#Создать карту пикселей и элементов
lBitmap=GUISearchBitmapCreate(GetControl(inSpecificationArray),lBitmap)
#Выдать сообщение, что поиск готов к использованию
print("GUISearch: Ready for search!")
#mBitmap=lBitmap
# Collect events until released
#Версия с Events (занимает поток, чтобы использовать общие переменные)
#with mouse.Listener(
# on_move=GUISearchEvent_on_move,
# on_click=GUISearchEvent_on_click,
# on_scroll=GUISearchEvent_on_scroll) as listener:
#listener.join()
# True == False
#####################
###Версия с таймером
#####################
#mTimer = RepeatedTimer(0.5, GUISearchDraw, lBitmap) # it auto-starts, no need of rt.start()
#mTimer.start()
###########
#Версия с задержкой
###########
#Сбросить нажатие Ctrl, если оно было
bool(win32api.GetAsyncKeyState(17))
lTimeSleepSeconds=0.7
lFlagLoop = True
while lFlagLoop:
#Проверить, нажата ли клавиша Ctrl (код 17)
lFlagKeyPressedCtrl=bool(win32api.GetAsyncKeyState(17))
#Подсветить объект, если мышка наведена над тем объектом, который не подсвечивался в прошлый раз
if not lFlagKeyPressedCtrl:
#Получить координаты мыши
(lX,lY) = win32api.GetCursorPos()
#Подсветить объект, если мышь над ним
if (lX,lY) in lBitmap:
if lGUISearchElementSelected != lBitmap[lX,lY]:
lGUISearchElementSelected = lBitmap[lX,lY]
lBitmap[lX,lY].draw_outline()
else:
lGUISearchElementSelected = None
else:
#Была нажата клавиша Ctrl - выйти из цикла
lFlagLoop=False;
#Заснуть до следующего цикла
time.sleep(lTimeSleepSeconds)
#Вернуть результат поиска
return lGUISearchElementSelected
def GUISearchBitmapCreate (inElement,inBitmapDict={}):
#Добавить в карту информацию о текущем объекте
inBitmapDict=GUISearchBitmapElementFill(inElement,inBitmapDict)
#Получить список детей и добавить в карту
for lItem in inElement.children():
inBitmapDict=GUISearchBitmapCreate(lItem,inBitmapDict)
return inBitmapDict
#GUISearchBitmapElementFill
def GUISearchBitmapElementFill (inElement,inBitmapDict):
lElementInfo=inElement.element_info
#Получить параметры прямоугольника
lElementRectX1 = 0
lElementRectX2 = 0
lElementRectY1 = 0
lElementRectY2 = 0
lFlagHasRect = True
try:
lElementRectX1=lElementInfo.rectangle.left
lElementRectX2=lElementInfo.rectangle.right
lElementRectY1=lElementInfo.rectangle.top
lElementRectY2=lElementInfo.rectangle.bottom
except Exception as e:
lFlagHasRect = False
#Выполнить установку элемента, если прямоугольник получить удалось
if lFlagHasRect:
lX=lElementRectX1
#Циклический обход по оси X
while lX<=lElementRectX2:
lY=lElementRectY1
#Циклический обход по Оси Y
while lY<=lElementRectY2:
#Установка элемента по адресу [<x>,<y>]
inBitmapDict[lX,lY]=inElement
#Инкремент y
lY=lY+1
#Инкремент X
lX=lX+1
return inBitmapDict
#debug
def ElementGetChildElementList(inControlSpecificationArray=[]):
#Подготовка входного массива
inControlSpecificationArray=ElementSpecificationArraySearchPrepare(inControlSpecificationArray)
#Выполнить идентификацию объектов, если передан массив
lResultList=[];
#ctypes.windll.user32.MessageBoxW(0, str(inControlSpecificationArray), "Your title", 1)
if len(inControlSpecificationArray) > 0:
#Получить объект
lTempObject = GetControl(inControlSpecificationArray)
#Получить список дочерних объектов
lTempChildList = lTempObject.wrapper_object().children()
lIterator=0
#Подготовить результирующий объект
for lChild in lTempChildList:
lTempObjectInfo=lChild.element_info
#Добавить информацию об обнаруженом объекте
lObjectInfoItem=ElementInfoExportObject(lTempObjectInfo)
#Итератор внутри объекта (для точной идентификации)
lObjectInfoItem['ctrl_index']=lIterator;
lResultList.append(lObjectInfoItem);
#Инкремент счетчика
lIterator=lIterator+1
else:
lResultList=GetRootElementList()
return lResultList
#Подготовить спецификацию для поиска элемента
def ElementSpecificationListNormalize(inElementSpecification):
lResult=[]
#Циклический обход
for lSpecificationItem in inElementSpecification:
lSpecificationItemNew=lSpecificationItem.copy()
#Перебор всех элементов
for lItemKey,lItemValue in lSpecificationItem.items():
#Флаг удаления атрибута
lFlagRemoveAttribute=False
#############################
#Если является вложенным словарем - удалить
if type(lItemValue) is dict:
lFlagRemoveAttribute=True
#Является типом None
if lItemValue is None:
lFlagRemoveAttribute=True
#Проверка допустимого ключевого слова
if (
lItemKey == "class_name" or
lItemKey == "class_name_re" or
lItemKey == "parent" or
lItemKey == "title" or
lItemKey == "title_re" or
lItemKey == "top_level_only" or
lItemKey == "visible_only" or
lItemKey == "enabled_only" or
lItemKey == "best_match" or
lItemKey == "handle" or
lItemKey == "ctrl_index" or
lItemKey == "found_index" or
lItemKey == "predicate_func" or
lItemKey == "active_only" or
lItemKey == "control_id" or
lItemKey == "control_type" or
lItemKey == "auto_id" or
lItemKey == "framework_id" or
lItemKey == "backend"):
True == True
else:
lFlagRemoveAttribute=True
#############################
#Конструкция по удалению ключа из словаря
if lFlagRemoveAttribute:
lSpecificationItemNew.pop(lItemKey)
#Проверит наличие ctrl_index - если он есть, то удалить control_id и control_type из-за того, что они мешают друг другу
if 'ctrl_index' in lSpecificationItemNew:
if "control_id" in lSpecificationItemNew:
lSpecificationItemNew.pop("control_id")
if "control_type" in lSpecificationItemNew:
lSpecificationItemNew.pop("control_type")
#Добавить строку в результирующий массив
lResult.append(lSpecificationItemNew)
#Вернуть результат
return lResult
#Подготовить массив для обращшения к поиску элемементов
def ElementSpecificationArraySearchPrepare(inControlSpecificationArray):
lResult=[]
#Циклический обход
for lSpecificationItem in inControlSpecificationArray:
lSpecificationItemNew=lSpecificationItem.copy()
#Перебор всех элементов
for lItemKey,lItemValue in lSpecificationItem.items():
#Флаг удаления атрибута
lFlagRemoveAttribute=False
#############################
#Если является вложенным словарем - удалить
if type(lItemValue) is dict:
lFlagRemoveAttribute=True
#Является типом None
if lItemValue is None:
lFlagRemoveAttribute=True
#Проверка допустимого ключевого слова
if (
lItemKey == "class_name" or
lItemKey == "class_name_re" or
lItemKey == "parent" or
lItemKey == "process" or
lItemKey == "title" or
lItemKey == "title_re" or
lItemKey == "top_level_only" or
lItemKey == "visible_only" or
lItemKey == "enabled_only" or
lItemKey == "best_match" or
lItemKey == "handle" or
lItemKey == "ctrl_index" or
lItemKey == "found_index" or
lItemKey == "predicate_func" or
lItemKey == "active_only" or
lItemKey == "control_id" or
lItemKey == "control_type" or
lItemKey == "auto_id" or
lItemKey == "framework_id" or
lItemKey == "backend"):
True == True
else:
lFlagRemoveAttribute=True
#############################
#Конструкция по удалению ключа из словаря
if lFlagRemoveAttribute:
lSpecificationItemNew.pop(lItemKey)
#Проверит наличие ctrl_index - если он есть, то удалить control_id и control_type из-за того, что они мешают друг другу
if 'ctrl_index' in lSpecificationItemNew:
if "control_id" in lSpecificationItemNew:
lSpecificationItemNew.pop("control_id")
if "control_type" in lSpecificationItemNew:
lSpecificationItemNew.pop("control_type")
#Добавить строку в результирующий массив
lResult.append(lSpecificationItemNew)
#Вернуть результат
return lResult
###############################
####Нормализация под JSON (в JSON нельзя передавать классы - только null, числа, строки, словари и массивы)
###############################
#Нормализация словаря под JSON
def JSONNormalizeDictionary(inDictionary):
#Сделать копию объекта
lResult=inDictionary.copy()
#Перебор всех элементов
for lItemKey,lItemValue in inDictionary.items():
#Флаг удаления атрибута
lFlagRemoveAttribute=False
#Если строка или число или массив или объект или None - оставить
if (
type(lItemValue) is dict or
type(lItemValue) is int or
type(lItemValue) is str or
type(lItemValue) is list or
lItemValue is None):
True==True
else:
lFlagRemoveAttribute=True
#Рекурсивный вызов, если объект является словарем
if type(lItemValue) is dict:
lResult[lItemKey]=JSONNormalizeDictionary(lItemValue)
#Рекурсивный вызов, если объект является списком
if type(lItemValue) is list:
lResult[lItemKey]=JSONNormalizeList(lItemValue)
#############################
#Конструкция по удалению ключа из словаря
if lFlagRemoveAttribute:
lResult.pop(lItemKey)
#Вернуть результат
return lResult
#Нормализация массива под JSON
def JSONNormalizeList(inList):
lResult=[]
#Циклический обход
for lItemValue in inList:
#Если строка или число или массив или объект или None - оставить
if (
type(lItemValue) is int or
type(lItemValue) is str or
lItemValue is None):
lResult.append(lItemValue)
#Если является словарем - вызвать функцию нормализации словаря
if type(lItemValue) is dict:
lResult.append(JSONNormalizeDictionary(lItemValue))
#Если является массиваом - вызвать функцию нормализации массива
if type(lItemValue) is list:
lResult.append(JSONNormalizeList(lItemValue))
#Вернуть результат
return lResult
#Определить объект - dict or list - и нормализовать его для JSON
def JSONNormalizeDictList(inDictList):
lResult={}
if type(inDictList) is dict:
lResult=JSONNormalizeDictionary(inDictList)
if type(inDictList) is list:
lResult=JSONNormalizeList(inDictList)
return lResult;
#Получить объект из атрибутов, которые удалось прочитать
def ElementInfoExportObject(inElementInfo):
#Подготовить выходную структуру данных
lResult = {"name":None,"rich_text":None,"process_id":None,"process":None,"handle":None,"class_name":None,"control_type":None,"control_id":None,"rectangle":{"left":None,"top":None,"right":None,"bottom":None}, 'runtime_id':None}
#Проверка name
try:
lResult['name']=inElementInfo.name
except Exception as e:
True == False
#Проверка rich_text
try:
lResult['rich_text']=inElementInfo.rich_text
except Exception as e:
True == False
#Проверка process_id
try:
lResult['process_id']=inElementInfo.process_id
lResult['process']=inElementInfo.process_id
except Exception as e:
True == False
#Проверка handle
try:
lResult['handle']=inElementInfo.handle
except Exception as e:
True == False
#Проверка class_name
try:
lResult['class_name']=inElementInfo.class_name
except Exception as e:
True == False
#Проверка control_type
try:
lResult['control_type']=inElementInfo.control_type
except Exception as e:
True == False
#Проверка control_id
try:
if inElementInfo.control_id!=0:
lResult['control_id']=inElementInfo.control_id
except Exception as e:
True == False
#Проверка rectangle left
try:
lResult['rectangle']['left']=inElementInfo.rectangle.left
except Exception as e:
True == False
#Проверка rectangle right
try:
lResult['rectangle']['right']=inElementInfo.rectangle.right
except Exception as e:
True == False
#Проверка rectangle top
try:
lResult['rectangle']['top']=inElementInfo.rectangle.top
except Exception as e:
True == False
#Проверка rectangle bottom
try:
lResult['rectangle']['bottom']=inElementInfo.rectangle.bottom
except Exception as e:
True == False
#Проверка runtime_id
try:
lResult['runtime_id']=inElementInfo.runtime_id
except Exception as e:
True == False
#Вернуть результат
return lResult
def GetRootElementList():
#Получить список объектов
lResultList=pywinauto.findwindows.find_elements(top_level_only=True)
lResultList2=[]
for lI in lResultList:
lTempObjectInfo=lI
lResultList2.append(ElementInfoExportObject(lI));
return lResultList2
def ElementDrawOutlineNew(inSpecificationArray):
draw_outline_new(GetControl(inSpecificationArray))
return
def draw_outline_new(lWrapperObject,colour='green',thickness=2,fill=win32defines.BS_NULL,rect=None):
"""
Draw an outline around the window.
* **colour** can be either an integer or one of 'red', 'green', 'blue'
(default 'green')
* **thickness** thickness of rectangle (default 2)
* **fill** how to fill in the rectangle (default BS_NULL)
* **rect** the coordinates of the rectangle to draw (defaults to
the rectangle of the control)
"""
#pdb.set_trace()
# don't draw if dialog is not visible
#if not lWrapperObject.is_visible():
# return
colours = {
"green": 0x00ff00,
"blue": 0xff0000,
"red": 0x0000ff,
}
# if it's a known colour
if colour in colours:
colour = colours[colour]
if rect is None:
rect = lWrapperObject.rectangle()
# create the pen(outline)
pen_handle = win32functions.CreatePen(
win32defines.PS_SOLID, thickness, colour)
# create the brush (inside)
brush = win32structures.LOGBRUSH()
brush.lbStyle = fill
brush.lbHatch = win32defines.HS_DIAGCROSS
brush_handle = win32functions.CreateBrushIndirect(ctypes.byref(brush))
# get the Device Context
dc = win32functions.CreateDC("DISPLAY", None, None, None )
# push our objects into it
win32functions.SelectObject(dc, brush_handle)
win32functions.SelectObject(dc, pen_handle)
# draw the rectangle to the DC
win32functions.Rectangle(
dc, rect.left, rect.top, rect.right, rect.bottom)
# Delete the brush and pen we created
win32functions.DeleteObject(brush_handle)
win32functions.DeleteObject(pen_handle)
# delete the Display context that we created
win32functions.DeleteDC(dc)
#run()
lText = "Bitness:" + str(struct.calcsize("P") * 8)
#for line in sys.stdin:
# lText=lText+line;
#ctypes.windll.user32.MessageBoxW(0, lText, "Your title", 1)
buffer = ""
lJSONInputString=""
#Выполнить чтение буфера, если не отладка библиотеки
if not mFlagIsDebug:
#{'functionName':'', 'argsArray':[]}
while True:
try:
lJSONInput = ProcessParentReadWaitObject()
lJSONInputString=str(lJSONInput)
#{'outputObject':''}
#Выполнить вызов функции
lResult=locals()[lJSONInput['functionName']](*lJSONInput['argsArray'])
lJSONInput['outputObject']=JSONNormalizeDictList(lResult)
ProcessParentWriteObject(lJSONInput)
except Exception as e:
#Вывод ошибки в родительский поток
ProcessParentWriteObject({'Error':str(e), 'ArgObject':str(lJSONInputString)})
#ctypes.windll.user32.MessageBoxW(0, str(e), "Your title", 1)
else:
print('Debug mode is turned on!')
#if __name__ == '__main__':
# if len(sys.argv) > 1:
# lFunctionArgs = sys.argv[2:]
# print(locals()[sys.argv[1]](*lFunctionArgs))