Metadata-Version: 2.5
Name: onerom-desktop
Version: 1.1.0
Summary: Runtime de automacao desktop da plataforma ONEROM (UIA, OCR, imagem, coordenadas e SAP GUI)
Project-URL: Homepage, https://onerom.dev.br
Author: ONEROM Team
License: MIT
License-File: LICENSE
Keywords: automation,desktop,ocr,onerom,rpa,sap,uia
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: Microsoft :: Windows
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Software Development :: Libraries
Requires-Python: >=3.9
Requires-Dist: mss>=9.0.0
Requires-Dist: pillow>=10.0.0
Requires-Dist: psutil>=5.9.0
Requires-Dist: pyautogui>=0.9.54
Requires-Dist: pyperclip>=1.9.0
Provides-Extra: all
Requires-Dist: comtypes>=1.4.16; (sys_platform == 'win32') and extra == 'all'
Requires-Dist: numpy>=1.24; extra == 'all'
Requires-Dist: opencv-python-headless<5,>=4.9.0; extra == 'all'
Requires-Dist: pytesseract>=0.3.10; extra == 'all'
Requires-Dist: pywin32>=306; (sys_platform == 'win32') and extra == 'all'
Requires-Dist: pywinauto>=0.6.9; (sys_platform == 'win32') and extra == 'all'
Provides-Extra: backend
Requires-Dist: comtypes>=1.4.16; (sys_platform == 'win32') and extra == 'backend'
Requires-Dist: pywin32>=306; (sys_platform == 'win32') and extra == 'backend'
Requires-Dist: pywinauto>=0.6.9; (sys_platform == 'win32') and extra == 'backend'
Provides-Extra: image
Requires-Dist: numpy>=1.24; extra == 'image'
Requires-Dist: opencv-python-headless<5,>=4.9.0; extra == 'image'
Provides-Extra: ocr
Requires-Dist: numpy>=1.24; extra == 'ocr'
Requires-Dist: opencv-python-headless<5,>=4.9.0; extra == 'ocr'
Requires-Dist: pytesseract>=0.3.10; extra == 'ocr'
Provides-Extra: sap
Requires-Dist: pywin32>=306; (sys_platform == 'win32') and extra == 'sap'
Description-Content-Type: text/markdown

# onerom-desktop

Runtime de automação desktop da plataforma ONEROM.

É a biblioteca que os bots gerados pelo **ONEROM Inspector** importam para clicar,
preencher e ler telas — de aplicações Windows nativas a SAP GUI, passando por
janelas que não expõem nenhuma árvore de automação.

```bash
pip install "onerom-desktop[all]"
```

## Uma classe, cinco estratégias

```python
from onerom_desktop import App

app = App(strategy="backend", automation_id="btnLogin", window_title="Login")
app.wait_visible()
app.click()
```

O que você passa no construtor vira padrão para todas as ações; o que passa na
ação vale só para aquela chamada. É isso que deixa o script curto sem esconder o
que ele está mirando.

| `strategy=` | Como localiza | Quando usar |
|---|---|---|
| `backend` | UIAutomation via pywinauto | **Padrão.** Sobrevive a janela movida, resolução diferente e troca de tema |
| `ocr` | Texto lido da tela (Tesseract) | Citrix, RDP, canvas Java/Delphi — quando não há árvore de automação |
| `image` | Template matching (OpenCV + ORB) | Ícones e controles desenhados, sem identidade nem rótulo |
| `coordinate` | Ponto fixo na tela | Último recurso: não verifica nada |
| `sap` | SAP GUI Scripting (COM) | Sempre, quando o alvo é SAP |
| `auto` | `backend` → `ocr` → `image` → `coordinate` | Degrada sozinho quando a aplicação muda |

```python
app.fill(strategy="ocr", text="Usuário", value="admin")
app.click(strategy="image", image="botao.png", confidence=0.9)
app.press(strategy="sap", sap_id="wnd[0]/tbar[0]/btn[0]")
app.click(strategy="auto")
```

## Âncora visual e ações relativas

Muito campo não tem identidade nenhuma — sem `automation_id`, sem texto próprio,
sem pixels distintivos — mas fica sempre ao lado de algo que tem: um rótulo, um
ícone, um cabeçalho de coluna. Ancore no que dá para ver e aja por deslocamento:

```python
app.find(strategy="image", image="rotulo_usuario.png")   # acha uma vez
app.fill_relative(140, 0, value="admin")                 # campo à direita
app.fill_relative(140, 34, value="segredo")              # o de baixo
app.click_relative(140, 70)                              # o botão
```

O deslocamento parte do **centro** da âncora, então sobrevive à janela mudar de
lugar — ao contrário de uma coordenada absoluta. E a busca por imagem acontece
**uma vez** para todos os campos ao redor, em vez de varrer a tela a cada um.

Sem âncora, dá para deslocar direto na ação:

```python
app.click(strategy="image", image="rotulo.png", offset_x=140, offset_y=0)
```

Disponíveis: `click_relative`, `double_click_relative`, `right_click_relative`,
`hover_relative`, `fill_relative`, `type_relative`. E `app.anchor` devolve a
região atual, ou `None` se ainda não houve `find()`.

## Ações

`click` · `double_click` · `right_click` · `hover` · `fill` · `click_and_fill` ·
`type_text` · `get_text` · `wait_visible` · `exists` · `screenshot`

Para SAP, também: `find` · `set_text` · `press` · `submit`.

```python
if app.exists(strategy="backend", automation_id="dlgErro", window_title="Erro"):
    app.click(automation_id="btnFechar")

total = app.get_text(strategy="ocr", x=800, y=440, width=160, height=28)
app.screenshot("evidencia.png")
```

## Erros dizem o que fazer

Tudo herda de `OneromDesktopError`, e as classes existem para separar os três
casos que pedem tratamento diferente:

```python
from onerom_desktop import (
    OneromDesktopError,          # base de tudo
    DesktopLocatorError,         # bug no bot — repetir não adianta
    DesktopBackendUnavailableError,  # ambiente quebrado — avisar o operador
    ElementNotFoundError,        # não achou agora — repetir pode funcionar
    WaitTimeoutError,
    MissingDependencyError,      # traz o comando de instalação na mensagem
)
```

`exists()` responde `False` para ausência de verdade, mas **levanta** exceção
quando a verificação em si não pôde ser feita — dependência faltando, backend
indisponível, imagem de template ausente, SAP fechado. Responder `False` nesses
casos é como um bot acaba entrando no branch errado.

## Dependências opcionais

O `import onerom_desktop` é barato: OpenCV, Tesseract, pywinauto e pywin32 só
são carregados quando a estratégia correspondente é usada.

```bash
pip install onerom-desktop              # coordenadas, teclado, screenshot
pip install "onerom-desktop[backend]"   # + UIAutomation (Windows)
pip install "onerom-desktop[image]"     # + OpenCV
pip install "onerom-desktop[ocr]"       # + Tesseract (o binário também é necessário)
pip install "onerom-desktop[sap]"       # + SAP GUI Scripting (Windows)
pip install "onerom-desktop[all]"       # tudo
```

Faltando uma delas, a mensagem já traz o `pip install` certo em vez de um
`ModuleNotFoundError` cru no log do bot.

## Coordenadas são pixels FÍSICOS

Toda coordenada nesta biblioteca é pixel físico da mesa virtual (a união de
todos os monitores) — o mesmo espaço em que o Inspector captura, o `mss`
fotografa e o `pyautogui` clica.

O processo é marcado como *per-monitor DPI aware* no import. Sem isso, o Windows
reescala silenciosamente as coordenadas de um processo DPI-unaware e todo clique
erra o alvo em tela a 125%/150% — o clássico "funciona na minha tela".

## Arquitetura

```
onerom_desktop/
├── app.py          App: defaults, dispatch e a cadeia auto
├── locators.py     kwargs soltos -> locators validados
├── strategies/     interface uniforme de ações (base + 5 estratégias)
├── engines/        uia · ocr · template · sap · windows
├── pointer.py      mouse           screen.py    captura de tela
├── keyboard.py     texto           geometry.py  Region
├── errors.py       hierarquia      optional.py  deps sob demanda
└── dpi.py          invariante de pixel físico
```

`strategies/base.py` concentra o caminho comum: as três estratégias que acabam
clicando um ponto (`ocr`, `image`, `coordinate`) só implementam `locate()` e
herdam todas as ações.

## Desenvolvimento

```bash
uv sync --group dev
./check.sh
```

MIT.
