9.7 KiB
KVMote — Conhecimento do Projeto
Documento de referência técnica e histórico de decisões do projeto KVMote.
O que é
KVMote é um KVM (Keyboard, Video, Mouse) over Bluetooth que permite controlar um PC remoto usando o teclado e mouse do seu PC principal, sem instalar nenhum software no PC controlado.
Inspirado em: Barrier / InputLeap / Mouse Without Borders — mas funciona em ambientes corporativos restritivos porque o PC cliente enxerga apenas um teclado e mouse USB comuns (Arduino).
Como funciona
┌─────────────────────┐ Bluetooth SPP ┌──────────────────┐
│ PC Host │ ◄────── (COM virtual) ────────► │ HC-06 │
│ KVMote.exe │ │ (Bluetooth) │
│ - captura mouse │ └──────┬───────────┘
│ - captura teclado │ │ Serial 9600
│ - detecta borda │ ┌──────▼───────────┐
└─────────────────────┘ │ Arduino Leonardo │
│ (USB HID) │
└──────┬────────────┘
│ USB
┌──────▼───────────┐
│ PC Cliente │
│ (sem software) │
└───────────────────┘
- O KVMote.exe roda no PC host (onde estão teclado e mouse físicos)
- O mouse chega na borda da tela configurada → cursor some → modo cliente ativo
- Movimentos de mouse e teclas são capturados por hooks globais do Windows
- Enviados via Bluetooth Serial ao HC-06 → Arduino Leonardo
- O Arduino injeta os eventos como USB HID no PC cliente
- Para voltar: mova o mouse ~15px de volta na direção do host
Hardware necessário
| Componente | Modelo | Observação |
|---|---|---|
| Microcontrolador | Arduino Leonardo | Obrigatório — único com HID USB nativo (ATmega32U4) |
| Bluetooth | HC-06 | Módulo slave, 9600 baud padrão |
| LED indicador | LED RGB catodo comum | Pinos R=5, G=6, B=9 (PWM) |
| Resistores | ~100Ω por canal | Proteção do LED |
Arduino Uno não funciona — não tem suporte HID nativo.
Instalação e configuração
PC Cliente (onde o Arduino fica conectado)
- Conectar o Arduino Leonardo via USB (aparece como teclado + mouse)
- Verificar que o HC-06 está pareado com o PC Host via Bluetooth Windows
- Nenhum software adicional necessário
PC Host (onde o KVMote.exe roda)
- Parear o HC-06 no Bluetooth do Windows → anota a porta COM gerada
- Rodar
KVMote.exe(portable, sem instalação) - Selecionar a posição do PC cliente (Esquerda / Direita / Acima / Abaixo)
- Clicar Detectar → aguarda auto-detecção da porta COM
- Selecionar o layout do teclado do PC cliente (US ou PT-BR ABNT2)
- Clicar Conectar
Indicadores LED do Arduino
| Cor | Significado |
|---|---|
| 🟢 Verde | Arduino ligado, aguardando conexão do host |
| 🔵 Azul | Host conectado, mouse no PC host |
| 🟣 Magenta | Mouse no PC cliente (modo ativo) |
Protocolo serial binário
Comunicação Host → Arduino a 9600 baud:
| Comando | Bytes | Ação |
|---|---|---|
M + dx + dy |
3 | Mover mouse (valores int8 com sinal) |
W + delta |
2 | Roda do mouse / scroll touchpad |
K + char |
2 | Digitar caractere (Keyboard.write) |
P + keycode |
2 | Pressionar tecla (mantém pressionada) |
U + keycode |
2 | Soltar tecla |
A |
1 | Soltar todas as teclas |
C + L/R |
2 | Clique do mouse |
D + L/R |
2 | Pressionar botão do mouse (arrastar) |
E + L/R |
2 | Soltar botão do mouse |
O |
1 | LED magenta (entrou no cliente) |
H |
1 | LED azul (host conectado) |
G |
1 | LED verde (host desconectado) |
~ |
1 | Ping → Arduino responde [PONG] |
Funcionalidades implementadas
KVM básico
- ✅ Controle de mouse (move, clique, arraste, scroll)
- ✅ Controle de teclado (todas as teclas, modificadores, F-keys, numpad)
- ✅ Detecção de borda (Left, Right, Above, Below)
- ✅ Retorno ao host por coordenadas virtuais (threshold 15px)
- ✅ Cursor escondido durante modo cliente
Conexão
- ✅ Auto-detecção de porta COM por PONG handshake
- ✅ Heartbeat a cada 3s (PONG timeout = 9s)
- ✅ Reconexão automática em loop
- ✅ Saída do modo cliente ao perder conexão (cursor sempre volta)
Scroll
- ✅ Mouse wheel físico
- ✅ Touchpad dois dedos (acumulador de delta para smooth scroll)
Clipboard
- ✅ Ctrl+V (ou Shift+Ins) em modo cliente envia texto do host como digitação
- ✅ Limite de 300 caracteres
- ✅ Suporte a layout PT-BR ABNT2 (remapeamento de pontuação)
- ✅ ReleaseAll antes de digitar (evita Ctrl+letra indesejado)
Layout de teclado (clipboard)
| Layout | Chars problemáticos corrigidos |
|---|---|
| US / Internacional | — (padrão) |
| PT-BR ABNT2 | ; : [ ] { } mapeados corretamente |
Chars não mapeáveis em PT-BR (ignorados no paste): / ? \ | @
Arquitetura do código C#
Principal.cs — seções
- P/Invoke — SetWindowsHookEx, ClipCursor, SetCursorPos
- Auto-detect — ProbePorts, PONG handshake
- Position selector — botões Acima/Esquerda/Direita/Abaixo
- Connect/Disconnect — abertura de porta, timers, hooks
- Port management — OpenPort, ClosePort, OnDataReceived
- Watchdog + Heartbeat + Reconnect — saúde da conexão
- Global Hooks — instala/remove WH_MOUSE_LL e WH_KEYBOARD_LL
- Mouse Hook Callback — edge detection, warp, virtual coords, scroll
- Keyboard Hook Callback — Ctrl+V intercept, P/U por VK code
- VK → Arduino keycode mapping — tabela + ranges (a-z, 0-9, numpad)
- Send methods — Send (blocking+lock), SendMouse (lossy TryEnter)
- Utilities — SetStatus, SetPortInfo, Log
- Clipboard send + layout — TranslateChar, SendClipboardToClient
Técnica de mouse (FPS warp)
ClipCursornão é usado — causava problemas- Em vez disso: cursor fica em posição fixa no centro (
_lastRawPos) - A cada WM_MOUSEMOVE: calcula delta, acumula em
_pendingDX/_pendingDY, faz warp de volta - Throttle de 50ms antes de enviar ao Arduino
Decisões de projeto
| Decisão | Alternativa considerada | Motivo |
|---|---|---|
| Arduino Leonardo | Arduino Uno | Uno não tem HID nativo |
| 9600 baud | 115200 baud | HC-06 padrão de fábrica, simples |
| WH_MOUSE_LL hook | Raw Input API | Mais simples, suficiente |
| Monitor.TryEnter para mouse | Queue assíncrona | Lossy é OK para mouse, não bloqueia |
| Coordenadas virtuais para retorno | Timer de inatividade | Mais natural, sem delay artificial |
| AutoScaleMode.Dpi | AutoScaleMode.None | None quebrava em telas de alta resolução |
| TCP não usado | TCP local seria mais rápido | Corporativo bloqueia portas |
Limitações conhecidas
- Velocidade: 9600 baud limita a ~50 teclas/s no clipboard; mouse trava durante paste
- Chars acentuados:
é,ã,çetc. não enviáveis via clipboard (não-ASCII) - Monitor único: sem suporte a multi-monitor no host
- Um cliente: arquitetura 1:1
- PT-BR parcial:
/,?,\,|,@não mapeáveis via Keyboard.write() - Tela do cliente: não capturada (KV sem o V — só K e M)
Roadmap
Clipboard Bridge (próximo projeto)
App separado para compartilhar clipboard entre host e cliente. Transporte via:
- OneDrive pasta compartilhada — funciona em corporativo (Microsoft 365 whitelisted)
- TCP/IP local — rápido, para redes domésticas
- Bluetooth RFCOMM — PC a PC direto, sem rede
Suporte planejado: texto (qualquer tamanho), imagens PNG (comprimidas), não arquivos.
Melhorias futuras
- Baud rate configurável (AT commands HC-06)
- Multi-monitor
- Layout US-International completo com dead keys
- Indicador visual de latência BT
Como gerar o executável portable
# Na pasta do projeto:
# Self-contained (~70MB) — roda sem .NET instalado
dotnet publish -c Release -r win-x64 --self-contained true -p:PublishSingleFile=true -p:IncludeNativeLibrariesForSelfExtract=true
# Dependente do runtime (~2MB) — requer .NET 8 Desktop Runtime
dotnet publish -c Release -r win-x64 --self-contained false -p:PublishSingleFile=true
Saída: bin\Release\net8.0-windows\win-x64\publish\KVMote.exe
⚠️ Não usar o botão "Publicar" do Visual Studio — gera ClickOnce (múltiplos arquivos).
Troubleshooting
| Sintoma | Causa provável | Solução |
|---|---|---|
| Porta não detectada | HC-06 não pareado | Parear BT no Windows antes |
| Cursor some e não volta | Conexão caiu em modo cliente | Mover mouse — reconexão automática restaura cursor |
| Teclas erradas no cliente | Layout diferente | Ajustar "Layout do cliente" no app |
| Scroll não funciona | Apenas no touchpad? | Acumulador captura, mas pode ser lento |
| Mouse lento no cliente | Throttle 50ms | Normal — limitação do BT 9600 baud |
| Texto colado com chars errados | Layout PT-BR | Selecionar PT-BR ABNT2 no app |
| App muito pequeno no notebook | Tela alta resolução | App já corrigido com AutoScaleMode.Dpi |