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 " )
#mPywinautoActiveBackend="win32"
mPywinautoActiveBackend = " uia "
#mPywinautoApplication=pywinauto.Application(backend="uia")
#####
##Внимание! Нельзя делать print так как он уходит в родительский поток и ломает механизм взаимодействия
##Чтобы е г о использовать надо писать функцию обертку
#####
###########################
####Модуль Automation
###########################
#inElementSpecificationList = [ [{lvl_0},{lvl_1},{lvl_2}],... ]
#result = pywinauto element wrapper instance or None
def AutomationSearchMouseElement ( inElementSpecification , inFlagIsSearchOnline = True ) :
lGUISearchElementSelected = None
#Настройка - частота обновления подсвечивания
lTimeSleepSeconds = 0.4
#Ветка поиска в режиме реального времени
if inFlagIsSearchOnline :
#Сбросить нажатие Ctrl, если оно было
bool ( win32api . GetAsyncKeyState ( 17 ) )
lFlagLoop = True
while lFlagLoop :
#Проверить, нажата ли клавиша Ctrl (код 17)
lFlagKeyPressedCtrl = bool ( win32api . GetAsyncKeyState ( 17 ) )
#Подсветить объект, если мышка наведена над тем объектом, который не подсвечивался в прошлый раз
if not lFlagKeyPressedCtrl :
#Получить координаты мыши
( lX , lY ) = win32api . GetCursorPos ( )
lElementFounded = { }
#Создать карту пикселей и элементов
#####Внимание! Функция GUISearchElementByRootXY не написана
lElementFounded = GUISearchElementByRootXY ( PywinautoExtElementGet ( inElementSpecification ) , lX , lY )
#Подсветить объект, если он мышь раньше стояла на другом объекте
if lGUISearchElementSelected != lElementFounded :
lGUISearchElementSelected = lElementFounded
#Доработанная функция отрисовки
if lElementFounded is not None :
draw_outline_new ( lElementFounded )
else :
#Была нажата клавиша Ctrl - выйти из цикла
lFlagLoop = False ;
#Заснуть до следующего цикла
time . sleep ( lTimeSleepSeconds )
#Ветка поиска по заранее созданной карте
else :
lBitmap = { }
#Создать карту пикселей и элементов
lBitmap = GUISearchBitmapCreate ( PywinautoExtElementGet ( inElementSpecification ) , lBitmap )
#Выдать сообщение, что поиск готов к использованию
#print("GUISearch: Ready for search!")
###########
#Версия с задержкой (без таймеров, событий в отдельных потоках)
###########
#Сбросить нажатие Ctrl, если оно было
bool ( win32api . GetAsyncKeyState ( 17 ) )
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 , inFlagIsSearchOnline = True ) :
lItemInfo = None
#Запустить функцию поиска элемента по мыши
lElement = AutomationSearchMouseElement ( inElementSpecification , inFlagIsSearchOnline )
#Detect backend of the elements
lFlagIsBackendWin32 = True
#Если объект имеется (не None), то выполнить построение иерархии
if lElement is not None :
if lElement . backend . name == ' uia ' :
lFlagIsBackendWin32 = False
#Циклическое создание дерева
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 lResult < len ( lElementParentChildrenList ) :
#Прекратить поиск, если элемент был обнаружен
if inElement == lElementParentChildrenList [ lResult ] :
lFlagFind = False
else :
#Прекратить поиски, если итератор вышел за пределы списка
if lResult > = len ( lElementParentChildrenList ) :
lResult = None
lFlagFind = False
else :
lResult = lResult + 1
else :
lResult = - 1
lFlagFind = False
#Вернуть результат
return lResult
#Получить элемент через расширенный движок поиска
#[ {
#"index":<Позиция элемента в родительском объекте>,
#
#} ]
def PywinautoExtElementGet ( inSpecificationList , inElement = None ) :
lResult = None
lChildElement = None
#Получить родительский объект если на вход ничего не поступило
if inElement is None :
#сформировать спецификацию на получение элемента
lRootElementSpecification = [ inSpecificationList [ 0 ] ]
lChildElement = GetControl ( lRootElementSpecification )
#Елемент на вход поступил - выполнить е г о анализ
else :
#Поступил index
if ' index ' in inSpecificationList [ 0 ] :
lChildrenList = inElement . children ( )
if inSpecificationList [ 0 ] [ ' index ' ] < len ( lChildrenList ) :
#Получить дочерний элемент
lChildElement = lChildrenList [ inSpecificationList [ 0 ] [ ' index ' ] ]
#Поступил ctrl_index
elif ' ctrl_index ' in inSpecificationList [ 0 ] :
lChildrenList = inElement . children ( )
if inSpecificationList [ 0 ] [ ' ctrl_index ' ] < len ( lChildrenList ) :
#Получить дочерний элемент
lChildElement = lChildrenList [ inSpecificationList [ 0 ] [ ' ctrl_index ' ] ]
#Выполнить рекурсивный вызов, если спецификация больше одного элемента
if len ( inSpecificationList ) > 1 and lChildElement is not None :
#Вызвать рекурсивно функцию получения следующего объекта, если в спецификации есть следующий объект
lResult = PywinautoExtElementGet ( inSpecificationList [ 1 : ] , lChildElement )
else :
lResult = lChildElement
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 ( backend = mPywinautoActiveBackend )
#Проверка разрядности
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 = PywinautoExtElementGet ( inControlSpecificationArray )
lActionList = dir ( lObject )
lResult = dir ( lObject )
#Выполнить чистку списка от неактуальных методов
for lActionItem in lActionList :
#Удалить те, которые начинаются на _
if lActionItem [ 0 ] == ' _ ' :
lResult . remove ( lActionItem )
#Удалить те, которые начинаются с символа верхнего регистра
if lActionItem [ 0 ] . isupper ( ) :
lResult . remove ( lActionItem )
return lResult
#Выполнить действие над элементом
def ElementRunAction ( inControlSpecificationArray , inActionName , inArgumentList = [ ] , inkwArgumentObject = { } ) :
#Определить объект
lObject = PywinautoExtElementGet ( inControlSpecificationArray )
#Получить метод для вызова
lFunction = getattr ( lObject , inActionName )
#Выполнить действие
return lFunction ( * inArgumentList , * * inkwArgumentObject )
def ElementGetInfo ( inControlSpecificationArray ) :
#Подготовка входного массива
inControlSpecificationArray = ElementSpecificationArraySearchPrepare ( inControlSpecificationArray )
#Выполнить идентификацию объектов, если передан массив
lResultList = [ ] ;
if len ( inControlSpecificationArray ) > 0 :
#Получить объект
lTempObject = PywinautoExtElementGet ( inControlSpecificationArray )
#Получить инфо объект
lTempObjectInfo = lTempObject . 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 GUISearchElementByRootXY ( inRootElement , inX , inY ) :
#Инициализация результирующего значения
lResultElement = None
lResultElementX1 = None
lResultElementX2 = None
lResultElementY1 = None
lResultElementY2 = None
#Получить координаты текущего объекта
try :
lRootElementRectX1 = inRootElement . element_info . rectangle . left
lRootElementRectX2 = inRootElement . element_info . rectangle . right
lRootElementRectY1 = inRootElement . element_info . rectangle . top
lRootElementRectY2 = inRootElement . element_info . rectangle . bottom
#Добавить объект в результирующий, если координаты попадают в него
if inX > = lRootElementRectX1 and inX < = lRootElementRectX2 and inY > = lRootElementRectY1 and inY < = lRootElementRectY2 :
lResultElement = inRootElement
lResultElementX1 = lRootElementRectX1
lResultElementX2 = lRootElementRectX2
lResultElementY1 = lRootElementRectY1
lResultElementY2 = lRootElementRectY2
#Получить список детей и добавить в карту
for lChildElement in inRootElement . children ( ) :
lChildFoundedElement = GUISearchElementByRootXY ( lChildElement , inX , inY )
#Установить обнаруженный элемент, если текущий результат пустой
if lResultElement is None and lChildFoundedElement is not None :
lResultElement = lChildFoundedElement
lResultElementX1 = lResultElement . element_info . rectangle . left
lResultElementX2 = lResultElement . element_info . rectangle . right
lResultElementY1 = lResultElement . element_info . rectangle . top
lResultElementY2 = lResultElement . element_info . rectangle . bottom
#Выполнить сверку lChildFoundedElement и lResultElement если о б а имеются
elif lResultElement is not None and lChildFoundedElement is not None :
#Правила перезатирания карты, если имеется старый объект
#[Накладываемый объект] - Н О - ElementNew
#[Имеющийся объект] - ИО - ElementOld
#3 типа вхождения объектов
#тип 1 - [имеющийся объект] полностью входит в [накладываемый объект] (ИО X1 Y1 >= Н О X1 Y1; ИО X2 Y2 <= Н О X2 Y2) - не вносить Н О в bitmap в эти диапазоны
#тип 2 - [имеющийся объект] полностью выходит за пределы [накладываемого объекта] (ИО X1 Y1 < Н О X1 Y1; ИО X2 Y2 > Н О X2 Y2) - вносить Н О в bitmap
#тип 3 - [имеющийся объект] частично входит в [накладываемый объект] (все остальные случаи)- вносить Н О в bitmap
#Получить координаты ИО
lChildFoundedElementInfo = lChildFoundedElement . element_info
#lElementNew = inElement
lChildFoundedElementX1 = lChildFoundedElementInfo . rectangle . left
lChildFoundedElementX2 = lChildFoundedElementInfo . rectangle . right
lChildFoundedElementY1 = lChildFoundedElementInfo . rectangle . top
lChildFoundedElementY2 = lChildFoundedElementInfo . rectangle . bottom
#Проверка вхождения по типу 1
if ( lResultElementX1 > = lChildFoundedElementX1 ) and ( lResultElementY1 > = lChildFoundedElementY1 ) and ( lResultElementX2 < = lChildFoundedElementX2 ) and ( lResultElementY2 < = lChildFoundedElementY2 ) :
False == True
#Проверка вхождения по типу 3
elif ( lResultElementX1 < lChildFoundedElementX1 ) and ( lResultElementY1 < lChildFoundedElementY1 ) and ( lResultElementX2 > lChildFoundedElementX2 ) and ( lResultElementY2 > lChildFoundedElementY2 ) :
lResultElement = lChildFoundedElement
lResultElementX1 = lChildFoundedElementX1
lResultElementX2 = lChildFoundedElementX2
lResultElementY1 = lChildFoundedElementY1
lResultElementY2 = lChildFoundedElementY2
#Проверка вхождения по типу 2
else :
lResultElement = lChildFoundedElement
lResultElementX1 = lChildFoundedElementX1
lResultElementX2 = lChildFoundedElementX2
lResultElementY1 = lChildFoundedElementY1
lResultElementY2 = lChildFoundedElementY2
except Exception as e :
False == False
return lResultElement
#Техническая функция
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
#pdb.set_trace()
#Получить параметры прямоугольника
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
#Выполнить установку элемента, если прямоугольник получить удалось
if lFlagHasRect :
lX = lElementRectX1
#Циклический обход по оси X
while lX < = lElementRectX2 :
lY = lElementRectY1
#Циклический обход по Оси Y
while lY < = lElementRectY2 :
######################
#Если объект в карте есть
if ( lX , lY ) in inBitmapDict :
if inBitmapDict [ lX , lY ] is not None :
#Правила перезатирания карты, если имеется старый объект
#[Накладываемый объект] - Н О - ElementNew
#[Имеющийся объект] - ИО - ElementOld
#3 типа вхождения объектов
#тип 1 - [имеющийся объект] полностью входит в [накладываемый объект] (ИО X1 Y1 >= Н О X1 Y1; ИО X2 Y2 <= Н О X2 Y2) - не вносить Н О в bitmap в эти диапазоны
#тип 2 - [имеющийся объект] полностью выходит за пределы [накладываемого объекта] (ИО X1 Y1 < Н О X1 Y1; ИО X2 Y2 > Н О X2 Y2) - вносить Н О в bitmap
#тип 3 - [имеющийся объект] частично входит в [накладываемый объект] (все остальные случаи)- вносить Н О в bitmap
#Получить координаты ИО
lElementOldInfo = inBitmapDict [ lX , lY ] . element_info
#lElementNew = inElement
lElementOldX1 = lElementOldInfo . rectangle . left
lElementOldX2 = lElementOldInfo . rectangle . right
lElementOldY1 = lElementOldInfo . rectangle . top
lElementOldY2 = lElementOldInfo . rectangle . bottom
#Проверка вхождения по типу 1
if ( lElementOldX1 > = lElementRectX1 ) and ( lElementOldY1 > = lElementRectY1 ) and ( lElementOldX2 < = lElementRectX2 ) and ( lElementOldY2 < = lElementRectY2 ) :
#Выполнить корректировку каретки по lY, чтобы не проходить по всем пикселям в рамках этой линии
lY = lElementOldY2 + 1
#Проверка вхождения по типу 3
elif ( lElementOldX1 < lElementRectX1 ) and ( lElementOldY1 < lElementRectY1 ) and ( lElementOldX2 > lElementRectX2 ) and ( lElementOldY2 > lElementRectY2 ) :
#Установка элемента по адресу [<x>,<y>]
inBitmapDict [ lX , lY ] = inElement
#Инкремент y
lY = lY + 1
#Проверка вхождения по типу 2
else :
#Установка элемента по адресу [<x>,<y>]
inBitmapDict [ lX , lY ] = inElement
#Инкремент y
lY = lY + 1
#Если объекта в карте нет
else :
#Установка элемента по адресу [<x>,<y>]
inBitmapDict [ lX , lY ] = inElement
#Инкремент y
lY = lY + 1
else :
#Установка элемента по адресу [<x>,<y>]
inBitmapDict [ lX , lY ] = inElement
#Инкремент y
lY = lY + 1
######################
#Инкремент X
lX = lX + 1
except Exception as e :
lFlagHasRect = False
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 = PywinautoExtElementGet ( inControlSpecificationArray )
#Получить список дочерних объектов
lTempChildList = lTempObject . 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 = { " title " : 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 [ ' title ' ] = 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 ( PywinautoExtElementGet ( inSpecificationArray ) )
return
def ElementDrawOutlineNewFocus ( inSpecificationArray ) :
draw_outline_new_focus ( PywinautoExtElementGet ( inSpecificationArray ) )
return
def draw_outline_new ( lWrapperObject , colour = ' green ' , thickness = 2 , fill = win32defines . BS_NULL , rect = None , inFlagSetFocus = False ) :
if lWrapperObject is not 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 )
"""
if inFlagSetFocus :
#Установить фокус на объект, чтобы было видно выделение
lWrapperObject . set_focus ( )
time . sleep ( 0.5 )
#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 )
#Аналог подсвечивания + установка фокуса
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 )
#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))