From 11219dedddbd66fbe949e09322a44e4208cdc619 Mon Sep 17 00:00:00 2001 From: Pedro de Oliveira Guedes Date: Wed, 29 Dec 2021 15:16:32 -0300 Subject: [PATCH] Creating the apis folder. --- api/wingui/cli.py | 744 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 744 insertions(+) create mode 100644 api/wingui/cli.py diff --git a/api/wingui/cli.py b/api/wingui/cli.py new file mode 100644 index 0000000..809f598 --- /dev/null +++ b/api/wingui/cli.py @@ -0,0 +1,744 @@ +# import datetime +import json +import urllib +import os +from typing import List + +import requests + +class Wingui: + """Classe que representa um proxy para um robo remoto. + mapeia o robo através da propriedade rid + ep significa endpoint, e aponta para o endereco na web on se hostea o serviço + Por padrão é: https://replay.digitalcircle.com.br/robotapi/cmd/ + """ + + ep: str = "" + + def __init__(self): + self.ep = "https://localhost:8443" + + def __request__(self, data: str): + + """Metodo que realiza chamadas http""" + + url = self.ep + data + print("Calling: " + url) + + apikey = os.environ.get('REPLAY_APIKEY') + headers = {"X-API-KEY": apikey} + res = requests.get(url, headers=headers, verify=False) + + if res.status_code >= 400: + raise Exception(f"HTTP ERROR: {str(res.status_code)} - {res.text}") + if res.headers.get("Content-Type") != None and res.headers.get("Content-Type").find("json") != -1: + return json.loads(res.text) + else: + return res.text + +# Funções Clip + def clip_read(self) -> str: + """Le o conteudo da clipboard na maquina do robo, e retorna como string""" + return self.__request__("/ipc/wingui/clip/read") + + def clip_write(self, m: str) -> str: + """Grava o conteudo fornecido em m na clipboard da maquina robo""" + return self.__request__("/ipc/wingui/clip/write?str={}".format(urllib.parse.quote(m, ""))) + +# Funções Screen + def screen_click(self, img: str): + + """ + Screen Click: realiza um click na tela, utilizando a imagem img como referencia. + + -img: Caminho absoluto para a imagem a ser clicada na tela. + + Caso o click ocorra, esse metodo retorna um array de inteiros, sendo o 1º o valor de X, e o 2º o valor de Y. O 3º parametro é o comprimento (width, w) da imagem e o 4º valor e a altura (height, h) de onde o click ocorreu. + """ + + return self.__request__(f"/ipc/wingui/screen/click?f={img}") + + def screen_clickcenter(self, img: str): + + """ + Análogo a screen_click, mas clica no centro da imagem. + """ + + return self.__request__(f"/ipc/wingui/screen/clickcenter?f={img}") + + def screen_capture(self, f: str, x: int, y: int, w: int, h: int): + """ + Captura a tela e salva na maquina onde o robo é executado, em formato PNG. + -f: Nome do arquivo a ser salvo + -x: X da origem da imagem - coordenada mais a esquerda e acima do retangulo + -y: Y da orgigem Analogo a x + -w: Comprimento da imagem + -h: altura da imagem. + + Para capturar um retangulo, do Pixel (10,10) ate o Pixel (110,100), utiliza-se: + screen_capture("c:\\arq.png",10,10,100,100) + """ + return self.__request__(f"/ipc/wingui/screen/capture?x={x}&y={y}&w={w}&h={h}&f={f}") + + def screen_find(self, f: str): + + """ + Envia a coordenada da imagem identificada pelo arquivo f (x,y,w,h), ou dá uma excecao caso a imagem não seja encontrada. + """ + + return self.__request__(f"/ipc/wingui/screen/find?f={f}") + + def screen_findall (self, f: str): + + """ + Busca a imagem fornecida no parâmetro "f", se a encontrar, passa a buscar todas as recorrências desta imagem na tela. Retorna um array com as posições de todas as imagens encontradas. + """ + return self.__request__(f"/ipc/wingui/screen/findall?f={f}") + + def screen_wait(self, f: str, m: int = 30): + + """ + -f: Caminho da imagem que se está buscando. + -m: Tempo máximo pelo qual se buscará a imagem na tela. + + + -retorno: Array com as coordenadas da imagem encontrada e caminho da imagem utilizada para busca. + """ + + return self.__request__(f"/ipc/wingui/screen/wait?f={f}&m={m}") + + def screen_waitclick(self, f: str, m: int = 30): + """ + Análogo a screen_wait, mas realiza click na coordenada x = 0, y = 0 da imagem. + + -f: Caminho da imagem que se está buscando. + -m: Tempo máximo pelo qual se buscará a imagem na tela. + + -retorno: Array com as coordenadas da imagem encontrada e caminho da imagem utilizada para busca. + """ + return self.__request__(f"/ipc/wingui/screen/waitclick?f={f}&m={m}") + + def screen_waitclickcenter(self, f: str, m: int = 30): + """ + Analogo a screen_waitclick, mas realiza click no CENTRO da imagem + """ + return self.__request__(f"/ipc/wingui/screen/waitclickcenter?f={f}&m={m}") + + def screen_scale(self): + """ + Retorna a escala da tela, em um array [x,y] + """ + return self.__request__("/ipc/wingui/screen/scale") + + def screen_size(self): + + """ + Retorna a tamanho da tela, em um array [x,y] + """ + return self.__request__("/ipc/wingui/screen/size") + + # def screen_res(self, d: int) -> List[int]: + + # """ + # Retorna a resolução da tela, em um array [x,y] + # """ + # return self.__request__(f"/ipc/wingui/screen/res?d={d}") + + # def screen_setres(self, x: int, y: int, c: int): + # """ + # Set resolução e cor da tela + # """ + # return self.__request__(f"/ipc/wingui/screen/setres?x={x}&y={y}&c={c}") + + def screen_shot(self, fmt: str = "b64"): + + """ + Tira um screenshot e retorna imagem como string + """ + return self.__request__(f"/ipc/wingui/screen/shot?fmt={fmt}") + + def screen_dsinternal(self): + """ + Faz com que o monitor definido como primário (através das configurações do windows) seja o único ativo. + """ + return self.__request__(f"/ipc/wingui/screen/dsinternal") + + def screen_dsexternal(self): + """ + Faz com que o monitor definido como secundário (através das configurações do windows) seja o único ativo. + """ + return self.__request__(f"/ipc/wingui/screen/dsexternal") + + def screen_dsclone(self): + """ + Faz com que o vídeo exibido no monitor definido como primário seja clonado para o secundário. + """ + return self.__request__(f"/ipc/wingui/screen/dsclone") + + def screen_dsextend(self): + """ + Faz com que o vídeo de ambos os monitores seja independente. + """ + return self.__request__(f"/ipc/wingui/screen/dsextend") + +# Funções Draw + def draw_addbox(self, x: int, y: int, w: int = 100, h: int = 100, t: int = 3): + """ + adiciona caixa a tela de overlay + + -x: Ponto inicial do eixo x para o desenho. + -y: Ponto inicial do eixo y para o desenho. + -w: Largura da caixa a ser desenhada. + -h: Altura da caixa a ser desenhada. + -t: Largura do pincel que desenhará a caixa. + + Todos os parâmetros devem ser dados em píxels. + """ + return self.__request__(f"/ipc/wingui/draw/addbox?x={x}&y={y}&w={w}&h={h}&t={t}") + + def draw_addrect(self, x: int, y: int, w: int = 100, h: int = 100): + """ + adiciona um retângulo opaco à tela de overlay + + -x: Ponto inicial do eixo x para o desenho. + -y: Ponto inicial do eixo y para o desenho. + -w: Largura do retângulo a ser desenhado. + -h: Altura do retângulo a ser desenhado. + + Todos os parâmetros devem ser dados em píxels. + """ + return self.__request__(f"/ipc/wingui/draw/addrect?x={x}&y={y}&w={w}&h={h}") + + def draw_addtext(self, x: int, y: int, t: str = "No text set"): + """ + adiciona caixa texto a tela de overlay + + -x: Ponto inicial do eixo x para a escrita. + -y: Ponto inicial do eixo y para a escrita. + -t: Texto a ser escrito. + """ + return self.__request__(f"/ipc/wingui/draw/addtext?x={x}&y={y}&t={urllib.parse.quote(t)}") + + def draw_clear(self): + """Limpa tela de overlay""" + return self.__request__("/ipc/wingui/draw/clear") + + # def draw_show(self): + # """mostra tela de overlay""" + # return self.__request__("/ipc/wingui/draw/show") + +# Funções KB + def kb_tap(self, s: str) -> str: + """Envia uma tecla ou teclas para serem clicadas no componente com foco onde o robo é executado + Em caso de teclas alteradoras, elas devem ser sempre posicionadas apos a tecla alvo. + Dessa forma, para enviar ALT+d, vc envia o string "d,alt". Para enviar C maiusculo, vc utiiliza + "c,shift". + """ + return self.__request__(f'/ipc/wingui/kb/tap?str={urllib.parse.quote(s, "")}') + + def kb_type(self, s: str) -> str: + """Semelhante a tap, mas envia textos completos. + ***ATENCAO*** Esse metodo usa urlencoding, dessa forma caracteres serao codificados para envio. # virará %23 por exemplo. Ao chegar no robo passarão pelo decoding análogo. + """ + return self.__request__("/ipc/wingui/kb/type?str={}".format(urllib.parse.quote(s, ""))) + + def kb_toggle(self, s: str) -> str: + """Semelhante a tap, mas envia textos completos. + ***ATENCAO*** Esse metodo usa urlencoding, dessa forma caracteres serao codificados para envio. # virará %23 + por exemplo. Ao chegar no robo passrão pelo decoding análogo. + """ + return self.__request__("/ipc/wingui/kb/toggle?str={}".format(urllib.parse.quote(s, ""))) + +# Funções Dialog + def dialog_color(self, t: str = "Selecione Cor", d: str = "BEBEBE") -> bool: + """ + Apresenta dialogo para que usuario escolha uma cor + Params: + - t: Titulo + - d: Cor padrao + Retorna: + Dict + """ + return self.__request__(f'/ipc/wingui/dialog/color?t={urllib.parse.quote(t, "")}&d={urllib.parse.quote(d, "")}') + + def dialog_date(self, t: str = "Selecione Data", m: str = "", d="", f="") -> str: + """ + Apresenta dialogo para que usuario escolha uma Data + Params: + - t: Titulo + - m: Mensagem de texto + - d: Data Padrao (se vazio = agora) + - f: formato para parse + Retorna: + Dict + """ + return self.__request__(f'/ipc/wingui/dialog/date?t={urllib.parse.quote(t, "")}&m={urllib.parse.quote(m, "")}&d={urllib.parse.quote(d, "")}&f={urllib.parse.quote(f, "")}') + + def dialog_entry(self, t: str = "Favor inserir", m: str = "Valor", d: str = "Valor") -> str: + """ + ## Dialog Entry + ##### Apresenta dialog para entrada de texto curto + --- + Params: + - t: Titulo + - m: Mensagem de texto + - d: valor padrao + --- + Retorna: + + -> String digitada. + """ + return self.__request__(f'/ipc/wingui/dialog/entry?t={urllib.parse.quote(t, "")}&m={urllib.parse.quote(m, "")}&d={urllib.parse.quote(d, "")}') + + def dialog_error(self, t: str = "Erro", m: str = "Houve um erro") -> bool: + """ + ## Dialog Error + ##### Apresenta dialog c msg de erro + --- + Params: + - t: Titulo + - m: Mensagem de texto + --- + Retorna: + + -> "ok" + """ + return self.__request__(f'/ipc/wingui/dialog/error?t={urllib.parse.quote(t, "")}&m={urllib.parse.quote(m, "")}') + + def dialog_file(self, t: str = "Selecionar arquivo", f: str = ".", d: str = "false") -> str: + """ + ## Dialog File + Apresenta dialog para selecionar arquivo + + --- + Params: + - t: Titulo da janela. + - f: Diretório inicial ("." por padrão) + - d: true -> Seleciona diretórios; false -> Seleciona arquivos + --- + Retorna: + + -> Caminho absoluto do arquivo selecionado + """ + return self.__request__(f'/ipc/wingui/dialog/file?t={urllib.parse.quote(t, "")}&f={urllib.parse.quote(f, "")}&d={urllib.parse.quote(d, "")}') + + def dialog_file_multi(self, t: str = "Selecionar arquivos", f: str = ".") -> List[str]: + """ + ## Dialog File Multi + Apresenta dialog para selecionar arquivo + + --- + Params: + - t: Titulo da janela. + - f: Diretório inicial ("." por padrão) + --- + Retorna: + + -> Lista com os caminhos absolutos dos arquivos selecionados. + """ + return self.__request__(f'/ipc/wingui/dialog/filemulti?t={urllib.parse.quote(t, "")}&f={urllib.parse.quote(f, "")}') + + def dialog_info(self, t: str = "Info", m: str = "Info Msg") -> bool: + """ + ## Dialog Info + Apresenta dialog msg + + --- + Params: + - t: Titulo da janela + - m: Mensagem exibida + --- + Retorna: + + -> "ok" + """ + return self.__request__(f'/ipc/wingui/dialog/info?t={urllib.parse.quote(t, "")}&m={urllib.parse.quote(m, "")}') + + def dialog_list(self, t: str = "Selecionar", m: str = "Selecione uma entrada", f: List[str] = []) -> str: + """ + ## Dialog List + Apresenta dialog com uma lista. Permite o usuário selecionar um dos itens. + + --- + Params: + - t: Titulo da janela + - m: Mensagem da janela + - f: Opções para escolher + --- + Retorna: + + -> Opção escolhida + """ + return self.__request__(f'/ipc/wingui/dialog/list?t={urllib.parse.quote(t, "")}&m={urllib.parse.quote(m, "")}&f={urllib.parse.quote(",".join(f), "")}') + + def dialog_listmulti(self, t: str = "Selecionar", m: str = "Selecione uma entrada", f: List[str] = []) -> List[str]: + """ + ## Dialog List Multi + Apresenta dialog com uma lista. Permite o usuário selecionar os itens que quiser. + + --- + Params: + - t: Titulo da janela + - m: Mensagem da janela + - f: Opções para escolher + --- + Retorna: + + -> Lista com as opções escolhidas + """ + return self.__request__(f'/ipc/wingui/dialog/listmulti?t={urllib.parse.quote(t, "")}&m={urllib.parse.quote(m, "")}&f={urllib.parse.quote(",".join(f), "")}') + + def dialog_password(self, t: str = "Entrar com Senha", m: str = "Favor fornecer sua senha") -> str: + """ + ## Dialog Password + Apresenta dialog para entrada de senha/informações confidenciais. + + --- + Params: + - t: Titulo da janela + - m: Mensagem de texto exibida + --- + Retorna: + -> Texto digitado. + """ + return self.__request__(f'/ipc/wingui/dialog/password?t={urllib.parse.quote(t, "")}&m={urllib.parse.quote(m, "")}') + + def dialog_question(self, t: str = "Question", m: str = "Question Msg") -> bool: + """ + ## Dialog Question + Apresenta dialog c pergunta sim/nao + + --- + Params: + - t: Titulo da janela + - m: Mensagem exibida. + --- + Retorna: + - True: Caso clique em sim + - False: Caso clique em não + """ + return self.__request__(f'/ipc/wingui/dialog/question?t={urllib.parse.quote(t, "")}&m={urllib.parse.quote(m, "")}') + + def dialog_warn(self, t: str = "Warn", m: str = "Warn") -> bool: + """ + ## Dialog Warn + Apresenta dialog msg + + --- + Params: + - t: Titulo da janela + - m: Mensagem exibida + --- + Retorna: + + -> "ok" + """ + return self.__request__(f'/ipc/wingui/dialog/warn?t={urllib.parse.quote(t, "")}&m={urllib.parse.quote(m, "")}') + + # def dialog_yesno(self, t: str, m: str) -> bool: + # """ + # Apresenta dialogo para que usuario escolha sim ou nao + # Params: + # - t: Titulo + # - m: Mensagem + # Retorna: + # bool + # """ + # return self.__request__("dialog/yesno?t={}&m={}".format(urllib.parse.quote(t, ""), urllib.parse.quote(m, ""))) + # + # def dialog_filesave(self, t: str, d: str, x: List[str]) -> str: + # """ + # Apresenta dialogo usuario arquivo para salvar arquivo + # Params: + # - t: Titulo + # - d: descricao + # - x: lista de extensoes SEM PONTO - ex: ["pdf","xls","py"] + # Retorna: + # str: Nome do arquivo + # """ + # xstr = ",".join(x) + # return self.__request__( + # "dialog/filesave?t={}&d={}&x={}".format(urllib.parse.quote(t, ""), urllib.parse.quote(d, ""), + # urllib.parse.quote(xstr, ""))) + # + # def dialog_fileload(self, t: str, d: str, x: List[str]) -> str: + # """ + # Apresenta dialogo usuario arquivo para carregar arquivo + # Params: + # - t: Titulo + # - d: descricao + # - x: lista de extensoes SEM PONTO - ex: ["pdf","xls","py"] + # Retorna: + # str: Nome do arquivo + # """ + # xstr = ",".join(x) + # return self.__request__( + # "dialog/fileload?t={}&d={}&x={}".format(urllib.parse.quote(t, ""), urllib.parse.quote(d, ""), + # urllib.parse.quote(xstr, ""))) + # + # def dialog_dir(self, t: str) -> str: + # """" + # Apresenta dialogo usuario selecionar pasta + # Params: + # - t: Titulo + # Retorna: + # str: Nome do diretorio + # """ + # return self.__request__("dialog/dir?t={}".format(urllib.parse.quote(t, ""))) + +# Funções Mouse + def mouse_move(self, x: int, y: int) -> str: + """ + ## Mouse Move + Move o mouse para a coordenada X, Y + + --- + Params: + - x: Posição absoluta da tela no eixo x + - y: Posição absoluta da tela no eixo y + --- + Retorna: + + --- + """ + return self.__request__(f"/ipc/wingui/mouse/move?x={x}&y={y}") + + def mouse_drag(self, x: int, y: int, btn: str = "left") -> str: + """ + ## Mouse Drag + Move o mouse para a coordenada X, Y + + --- + Params: + - x: Coordenada final do eixo x + - y: Coordenada final do eixo y + --- + Retorna: + + --- + """ + return self.__request__(f'/ipc/wingui/mouse/drag?x={x}&y={y}&btn={urllib.parse.quote(btn, "")}') + + def mouse_click(self) -> str: + """ + ## Mouse Click + Clica no local onde o mouse está repousado + + --- + Params: + --- + + --- + Retorna: + --- + """ + return self.__request__("/ipc/wingui/mouse/click") + + def mouse_moverelative(self, x: int, y: int) -> str: + """ + ## Mouse Move Relative + Move o mouse para a coordenada X, Y, relativo a coordenada atual + + --- + Params: + - x: Quantidade de píxeis que o mouse será movido no eixo x + - y: Quantidade de píxeis que o mouse será movido no eixo y + ##### No caso de valores negativos, moverá relativamente o mouse para a esquerda (x) e/ou para cima (y) + --- + Retorna: + + --- + """ + return self.__request__("/ipc/wingui/mouse/moverelative?x={}&y={}".format(x, y)) + + def mouse_clickat(self, x: int, y: int): + """ + ## Mouse Click At + Move o mouse e clica em uma única operação + + --- + Params: + - x: Coordenada absoluta do eixo x no qual o robô fará o clique + - y: Coordenada absoluta do eixo y no qual o robô fará o clique + --- + Retorna: + + --- + """ + return self.__request__("/ipc/wingui/mouse/clickat?x={}&y={}".format(x, y)) + + def mouse_clickatrelative(self, x: int, y: int): + """ + ## Mouse Click At + Move o mouse e clica em uma única operação + + --- + Params: + - x: Quantidade em píxels que o mouse se moverá no eixo X a partir da posição atual + - y: Quantidade em píxels que o mouse se moverá no eixo Y a partir da posição atual + --- + Retorna: + + --- + """ + return self.__request__("/ipc/wingui/mouse/clickatrelative?x={}&y={}".format(x, y)) + +# Funções Notify + def notify_alert(self, t: str, m: str): + + """Cria um alerta do windows. t é o título, m é o corpo da notificação""" + + t = urllib.parse.quote(t, "") + m = urllib.parse.quote(m, "") + return self.__request__("notify/alert?msg={}&title={}".format(m, t)) + + def notify_notify(self, t: str, m: str): + + """Cria um alerta do windows. t é o título, m é o corpo da notificação""" + + t = urllib.parse.quote(t, "") + m = urllib.parse.quote(m, "") + return self.__request__("notify/notify?msg={}&title={}".format(m, t)) + +# Funções proc + def proc_exec(self, cmd: str): + + """Executa o comando cmd na maquina que executa o robo + Essa operação acontece dentro de um CMD. Ou seja, para inicializar uma instancia do finado + Internet Explorer rodando: + + r.proc_exec("C:\\Program Files\\Internet Explorer\\iexplore.exe") + + """ + cmd = urllib.parse.quote(cmd, "") + return self.__request__("proc/exec?cmd={}".format(cmd)) + + def proc_kill(self, cmd: str): + """Mata processo pelo nome, ou seja se quiser matar o ie, vc passa como iexplore.exe. + ***ATENCAO*** todos os processos com o mesmo nome serao mortos por esse comando + """ + cmd = urllib.parse.quote(cmd, "") + return self.__request__("proc/kill?cmd={}".format(cmd)) + + def proc_name(self, pid: int): + """Obtem o nome do processo através de seu PID. Para obter o PID, vide proc_all e window_list""" + return self.__request__("proc/name?pid={}".format(pid)) + + def proc_path(self, pid: int): + """Retorna o PATH da imagem (.exe) que representa um processo, de acordo com seu PID""" + return self.__request__("proc/path?pid={}".format(pid)) + + def proc_all(self): + """Lista todos os processos em execução na maquina robo. + Retorna um array de dicts. Cada dict com o formato: + { + "Pid":0 + "Name":"str" + } + Onde Pid é um inteiro representando o PID do processo, e Name é o nome do processo. + """ + return self.__request__("proc/all") + + def proc_pids(self): + """Retorna um array de inteiros, representando TODOS os processos em execução""" + return self.__request__("proc/pids") + +# Funções Window + def window_activehwnd(self) -> int: + """ + Retorna o HWND da janela ativa. + HWND é um indicador unico de um componente ajanelado no windows. + """ + return self.__request__("window/activehwnd") + + def window_activetitle(self) -> str: + """ + Retorna o titulo da janela ativo. + """ + return self.__request__("window/activetitle") + + def window_list(self, s: str = "") -> List[dict]: + + """ + Lista as janelas disponiveis, fitrando por s, caso ele seja fornecido. Nesse caso, apenas janelas que + contenham o string s serao retornadas. + + Retorna um array de dicts com o seguinte formato: + { + "Hwnd":0, + "Pid":0, + "Title":"str" + + } + + Onde Hwnd é o identificador da janela, pid é o numero do processo, e Title é o titulo da janela + """ + if s == "": + return self.__request__("window/list") + s = urllib.parse.quote(s, "") + return self.__request__("window/list?s={}".format(s)) + + def window_hwnd(self, s: str = "") -> List[int]: + """ + Semelhante a window_list, mas traz apenas um array de ints com os respectivos HWND's + """ + s = urllib.parse.quote(s, "") + return self.__request__("window/Hwnd?s={}".format(s)) + + def window_activate(self, hwnd: int): + """ + Ativa uma janela de acordo com seu hwnd + """ + return self.__request__("window/activate?Hwnd={}".format(hwnd)) + + def window_close(self, hwnd: int): + """ + Fecha janela de acordo com o hwnd. + """ + return self.__request__("window/close?Hwnd={}".format(hwnd)) + + def window_max(self, s: int): + """ + Maximiza janela de acordo com o hwnd. + """ + return self.__request__("window/max?Hwnd={}".format(s)) + + def window_min(self, s: int): + """ + Minimiza janela de acordo com o hwnd. + """ + return self.__request__("window/min?Hwnd={}".format(s)) + + def window_postmsg(self, w: int, m: int) -> dict: + """ + Envia msg para janela usando postmsg + :param w: handler da janela + :param m: codigo da mensagem + :return: valor de retorno + """ + return self.__request__("window/postmsg?w={}&m={}".format(w, m)) + + def window_sendmsg(self, w: int, m: int) -> dict: + """ + Envia msg para janela isando sendmsg + :param w: handler da janela + :param m: codigo da mensagem + :return: valor de retorno + """ + return self.__request__("window/sendmsg?w={}&m={}".format(w, m)) + + def window_waitactivetitle(self, t: str, m: int = 30): + """ + Aguarda por m segundos ate que o titulo da janela ativa tenha o substring t. Caso o tempo limite seja + alcançado, dispara exceção. + """ + t = urllib.parse.quote(t, "") + return self.__request__("window/waitactivetitle?t={}&m={}".format(t, m)) + + def window_winfo(self, w: int) -> dict: + """ + Obtem informações de uma janela Win32 + :param w: int representando o hwnd da janela + :return: dict com informações da janela + """ + return self.__request__("window/winfo?w={}".format(w))