KVMote/CLAUDE.md
Ricardo Carneiro 91e43e73d5 fix: ajustes
2026-03-22 18:59:18 -03:00

6.3 KiB

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
  • 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

<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.:

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

# 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