172 lines
6.3 KiB
Markdown
172 lines
6.3 KiB
Markdown
# CLAUDE.md — KVMote
|
|
|
|
Arquivo de contexto para o Claude Code. Leia antes de qualquer alteração no projeto.
|
|
|
|
---
|
|
|
|
## O que é o KVMote
|
|
|
|
KVM (Keyboard/Video/Mouse) over Bluetooth. Controla um PC remoto (cliente) a partir de um PC host usando um Arduino Leonardo como dispositivo HID USB. O host captura teclado e mouse via hooks globais do Windows e retransmite os eventos ao Arduino por Bluetooth Serial (HC-06), que os injeta como HID no PC cliente.
|
|
|
|
**Sem software no PC cliente.** O Arduino aparece como teclado + mouse USB padrão.
|
|
|
|
---
|
|
|
|
## Hardware
|
|
|
|
- **Arduino Leonardo** (ATmega32U4) — único modelo com HID USB nativo
|
|
- **HC-06** módulo Bluetooth (Slave) conectado ao Serial1 do Leonardo
|
|
- **LED RGB** nos pinos: R=5, G=6, B=9 (PWM, analogWrite)
|
|
- **Baud rate:** 9600 (padrão HC-06 de fábrica)
|
|
|
|
```
|
|
Host PC ──BT SPP──► HC-06 ──Serial1──► Arduino Leonardo ──USB HID──► Cliente PC
|
|
(KVMote.exe) (COM virtual) (sem software)
|
|
```
|
|
|
|
---
|
|
|
|
## Estrutura de arquivos
|
|
|
|
| Arquivo | Função |
|
|
|---|---|
|
|
| `KVMote.ino` | Firmware Arduino: máquina de estados, HID, LED |
|
|
| `Principal.cs` | Lógica principal C#: hooks, KVM, serial, clipboard |
|
|
| `Principal.Designer.cs` | UI WinForms: layout, controles |
|
|
| `Program.cs` | Entry point: DPI + ApplicationConfiguration |
|
|
| `Form1.cs` / `Form1.Designer.cs` | Stubs vazios (manter, não remover) |
|
|
| `KVMote.csproj` | .NET 8, ImplicitUsings=disable, System.IO.Ports |
|
|
|
|
---
|
|
|
|
## Protocolo serial binário (Host → Arduino)
|
|
|
|
| Comando | Bytes | Descrição |
|
|
|---|---|---|
|
|
| `M` dx dy | 3 | Mouse move (int8 com sinal) |
|
|
| `W` delta | 2 | Mouse wheel / touchpad (int8) |
|
|
| `K` char | 2 | Keyboard.write(char) — digita caractere |
|
|
| `C` L\|R | 2 | Mouse click esquerdo ou direito |
|
|
| `P` keycode | 2 | Keyboard.press(keycode) — tecla segurada |
|
|
| `U` keycode | 2 | Keyboard.release(keycode) |
|
|
| `A` | 1 | Keyboard.releaseAll() |
|
|
| `D` L\|R | 2 | Mouse.press() — botão segurado |
|
|
| `E` L\|R | 2 | Mouse.release() |
|
|
| `O` | 1 | LED magenta (entrou no cliente) |
|
|
| `H` | 1 | LED azul (host conectado) |
|
|
| `G` | 1 | LED verde (host desconectado) |
|
|
| `~` | 1 | Ping → Arduino responde `[PONG]` |
|
|
|
|
**Arduino → Host:** apenas `[PONG]` como string ASCII.
|
|
|
|
---
|
|
|
|
## LED RGB — cores e significados
|
|
|
|
| Cor | Estado |
|
|
|---|---|
|
|
| 🟢 Verde (0,255,0) | Boot / host desconectado |
|
|
| 🔵 Azul (0,0,255) | Host conectado, mouse no host |
|
|
| 🟣 Magenta (255,0,255) | Mouse no PC cliente |
|
|
|
|
Sem flashes de tráfego — cor sólida estática.
|
|
|
|
---
|
|
|
|
## Lógica KVM (Principal.cs)
|
|
|
|
### Auto-detect de porta
|
|
`AutoDetectAsync()` → `ProbePorts()`: abre cada COM, envia `~`, aguarda 500ms por `[PONG]`.
|
|
|
|
### Hooks globais
|
|
- `WH_MOUSE_LL` (14) e `WH_KEYBOARD_LL` (13) via `SetWindowsHookEx`
|
|
- Instalados após conectar, removidos ao desconectar
|
|
|
|
### Entrada no modo cliente
|
|
- Mouse atinge a borda configurada (Left/Right/Above/Below)
|
|
- `EnterClientMode()`: esconde cursor, warp para centro da tela
|
|
- Técnica FPS: `SetCursorPos` para posição fixa, acumula deltas reais
|
|
|
|
### Coordenadas virtuais
|
|
- `_virtualX/_virtualY`: acumulam deltas enviados ao cliente
|
|
- Retorno ao host quando virtual cruza `-ReturnThreshold` (15px) na direção de entrada
|
|
|
|
### Saída do modo cliente
|
|
- `ExitClientMode()`: mostra cursor, reposiciona 40px dentro da borda, envia `A` + `H`
|
|
- Também chamado em `BeginReconnect()` para não deixar cursor sumido
|
|
|
|
### Throttle de mouse
|
|
- `SendMouse()` usa `Monitor.TryEnter` (lossy) — descarta se canal ocupado
|
|
- Throttle de 50ms (~20 pacotes/s) — seguro para BT 9600 baud
|
|
|
|
### Wheel / touchpad
|
|
- Acumula `_wheelAccum += rawDelta`
|
|
- Envia ao Arduino quando acumula ±120 (1 notch de mouse wheel)
|
|
- Captura smooth scroll de touchpad (deltas pequenos ±3..±15)
|
|
|
|
### Clipboard (Ctrl+V em modo cliente)
|
|
- Hook intercepta Ctrl+V e Shift+Ins em modo cliente
|
|
- Lê `Clipboard.GetText()` do host
|
|
- Limite: `MaxClipChars = 300`
|
|
- Envia `A` (releaseAll) + 100ms antes de digitar
|
|
- Digita via `K` + byte a cada 20ms (~50 chars/s)
|
|
- Layout PT-BR ABNT2: `PtBrMap` remapeia chars via substituição de byte antes de `Keyboard.write()`
|
|
|
|
### Reconexão
|
|
- `BeginReconnect()`: chamado em timeout serial ou exceção de porta
|
|
- Retenta a cada 2500ms
|
|
- Chama `ExitClientMode()` imediatamente (cursor volta sempre)
|
|
- `!_isReconnecting` bloqueia entrada no modo cliente durante reconexão
|
|
|
|
---
|
|
|
|
## Convenções C# obrigatórias
|
|
|
|
```xml
|
|
<ImplicitUsings>disable</ImplicitUsings>
|
|
```
|
|
**Todo `using` deve ser explícito.** Faltou um → CS0103 em runtime.
|
|
|
|
**Designer file:** todos os membros de Form precisam do prefixo `this.`:
|
|
```csharp
|
|
this.btnConnect.Text = "Conectar"; // ✓
|
|
btnConnect.Text = "Conectar"; // ✗ CS0103 em ImplicitUsings=disable
|
|
```
|
|
|
|
**AutoScaleMode:** usar `Dpi` com `AutoScaleDimensions = new SizeF(96F, 96F)`. Nunca `None` (quebra DPI alto) nem `Font` (escala diferente por máquina).
|
|
|
|
**Form1.cs / Form1.Designer.cs:** manter como stubs vazios (`namespace KVMote { }`). O VS inclui no .csproj automaticamente; remover do disco pode causar erro de build.
|
|
|
|
---
|
|
|
|
## Como gerar o .exe portable
|
|
|
|
```powershell
|
|
# Self-contained (~70MB) — sem dependência de .NET no destino
|
|
dotnet publish -c Release -r win-x64 --self-contained true -p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true
|
|
```
|
|
|
|
Saída: `bin\Release\net8.0-windows\win-x64\publish\KVMote.exe`
|
|
|
|
**Não usar o "Publicar" do Visual Studio** — gera ClickOnce (setup.exe + arquivos separados).
|
|
|
|
---
|
|
|
|
## Limitações conhecidas
|
|
|
|
- **Canal único 9600 baud:** mouse trava durante paste de clipboard (design proposital)
|
|
- **Chars não-ASCII** (`é`, `ã`, `ç`...): não enviáveis via clipboard (filtrados)
|
|
- **PT-BR:** `/`, `?`, `\`, `|`, `@` não mapeáveis via `Keyboard.write()` — ignorados no paste
|
|
- **Monitor único:** `Screen.PrimaryScreen` — multi-monitor não implementado
|
|
- **Um cliente por vez:** arquitetura 1:1 (um HC-06, um Arduino)
|
|
- **BT desconectado:** se Arduino perder USB, BT cai, `BeginReconnect()` age em ~3s
|
|
|
|
---
|
|
|
|
## Roadmap (não implementado)
|
|
|
|
- **Clipboard Bridge:** app separado para compartilhar clipboard via OneDrive (pasta compartilhada) entre host e cliente corporativo
|
|
- **Multi-monitor:** detectar em qual monitor o cursor está ao cruzar a borda
|
|
- **Layout US-International completo:** mapeamento de dead keys para paste
|
|
- **Baud rate configurável:** AT commands no HC-06 para 115200
|