- Principal.cs/Designer.cs: WinForms KVM host app (.NET 8) Global mouse/keyboard hooks, edge detection, BT serial protocol, clipboard paste via Ctrl+V, PT-BR ABNT2 layout translation - KVMote.ino: Arduino Leonardo sketch (HC-06 BT, USB HID) Non-blocking state machine, LED RGB feedback, full protocol support - KVMote.csproj/sln: project files with System.IO.Ports NuGet - .gitignore: C#/Visual Studio standard exclusions Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
184 lines
7.1 KiB
C++
184 lines
7.1 KiB
C++
/*
|
|
KVMote — Arduino Leonardo (Serial1 = HC-06)
|
|
|
|
Baud rate: 9600 (padrão de fábrica do HC-06).
|
|
Se você já configurou o HC-06 para outra velocidade via AT commands,
|
|
altere a constante abaixo.
|
|
|
|
Protocolo binário:
|
|
Mouse move → 'M' dx(int8) dy(int8) 3 bytes
|
|
Mouse wheel → 'W' delta(int8) 2 bytes
|
|
Tecla write → 'K' char 2 bytes
|
|
Clique → 'C' 'L'|'R' 2 bytes
|
|
Tecla press → 'P' keycode 2 bytes
|
|
Tecla release → 'U' keycode 2 bytes
|
|
ReleaseAll → 'A' 1 byte
|
|
Mouse press → 'D' 'L'|'R' 2 bytes
|
|
Mouse release → 'E' 'L'|'R' 2 bytes
|
|
LED cliente → 'O' (laranja — entrou no cliente)
|
|
LED host → 'H' (flash verde + volta azul — voltou ao host)
|
|
Ping/Pong → '~' → responde [PONG] 1 byte
|
|
*/
|
|
|
|
#include <Keyboard.h>
|
|
#include <Mouse.h>
|
|
|
|
// ── Pinos do LED RGB ──────────────────────────────────────────────────────────
|
|
#define PIN_R 5
|
|
#define PIN_G 6
|
|
#define PIN_B 9
|
|
|
|
#define BAUD_HC06 9600 // ← altere se necessário
|
|
|
|
// ── Cor base do LED (muda conforme o modo) ────────────────────────────────────
|
|
uint8_t basR = 0, basG = 0, basB = 255; // azul = idle
|
|
|
|
// ── Máquina de estados ────────────────────────────────────────────────────────
|
|
enum Estado : uint8_t {
|
|
AGUARDA_CMD,
|
|
AGUARDA_MOUSE_DX,
|
|
AGUARDA_MOUSE_DY,
|
|
AGUARDA_MOUSE_WHEEL,
|
|
AGUARDA_TECLA,
|
|
AGUARDA_CLIQUE,
|
|
AGUARDA_PRESS_KEY,
|
|
AGUARDA_RELEASE_KEY,
|
|
AGUARDA_MOUSE_PRESS,
|
|
AGUARDA_MOUSE_RELEASE
|
|
};
|
|
|
|
Estado estado = AGUARDA_CMD;
|
|
int8_t pendingDX = 0;
|
|
|
|
// ── Helpers de LED ────────────────────────────────────────────────────────────
|
|
void ledCor(int r, int g, int b) {
|
|
analogWrite(PIN_R, r);
|
|
analogWrite(PIN_G, g);
|
|
analogWrite(PIN_B, b);
|
|
}
|
|
|
|
void piscaVerde() {
|
|
ledCor(0, 200, 0);
|
|
delay(40);
|
|
ledCor(basR, basG, basB); // retorna à cor base atual
|
|
}
|
|
|
|
void piscaCiano() {
|
|
ledCor(0, 200, 200);
|
|
delay(40);
|
|
ledCor(basR, basG, basB); // retorna à cor base atual
|
|
}
|
|
|
|
// ── Setup ─────────────────────────────────────────────────────────────────────
|
|
void setup() {
|
|
Serial1.begin(BAUD_HC06);
|
|
Keyboard.begin();
|
|
Mouse.begin();
|
|
ledCor(basR, basG, basB); // azul = pronto
|
|
}
|
|
|
|
// ── Loop principal (non-blocking) ─────────────────────────────────────────────
|
|
void loop() {
|
|
while (Serial1.available() > 0) {
|
|
byte b = (byte)Serial1.read();
|
|
|
|
switch (estado) {
|
|
|
|
// ── Aguarda o byte de comando ──────────────────────────────────────────
|
|
case AGUARDA_CMD:
|
|
if (b == 'M') estado = AGUARDA_MOUSE_DX;
|
|
else if (b == 'W') estado = AGUARDA_MOUSE_WHEEL;
|
|
else if (b == 'K') estado = AGUARDA_TECLA;
|
|
else if (b == 'C') estado = AGUARDA_CLIQUE;
|
|
else if (b == 'P') estado = AGUARDA_PRESS_KEY;
|
|
else if (b == 'U') estado = AGUARDA_RELEASE_KEY;
|
|
else if (b == 'D') estado = AGUARDA_MOUSE_PRESS;
|
|
else if (b == 'E') estado = AGUARDA_MOUSE_RELEASE;
|
|
else if (b == 'A') {
|
|
Keyboard.releaseAll();
|
|
piscaVerde();
|
|
}
|
|
else if (b == 'O') {
|
|
// Entrou no PC cliente → LED laranja
|
|
basR = 255; basG = 80; basB = 0;
|
|
ledCor(basR, basG, basB);
|
|
}
|
|
else if (b == 'H') {
|
|
// Voltou ao host → flash verde, LED azul
|
|
basR = 0; basG = 0; basB = 255;
|
|
piscaVerde();
|
|
}
|
|
else if (b == '~') {
|
|
Serial1.print("[PONG]");
|
|
piscaCiano();
|
|
}
|
|
// qualquer outro byte é silenciosamente descartado
|
|
break;
|
|
|
|
// ── Mouse: lê DeltaX ──────────────────────────────────────────────────
|
|
case AGUARDA_MOUSE_DX:
|
|
pendingDX = (int8_t)b;
|
|
estado = AGUARDA_MOUSE_DY;
|
|
break;
|
|
|
|
// ── Mouse: lê DeltaY e executa o movimento ────────────────────────────
|
|
case AGUARDA_MOUSE_DY:
|
|
Mouse.move(pendingDX, (int8_t)b, 0);
|
|
estado = AGUARDA_CMD;
|
|
// Sem piscaVerde() aqui — delay(40) bloquearia o processamento serial
|
|
break;
|
|
|
|
// ── Mouse: roda do mouse ──────────────────────────────────────────────
|
|
case AGUARDA_MOUSE_WHEEL:
|
|
Mouse.move(0, 0, (int8_t)b);
|
|
estado = AGUARDA_CMD;
|
|
break;
|
|
|
|
// ── Teclado: lê o caractere e digita (write) ──────────────────────────
|
|
case AGUARDA_TECLA:
|
|
Keyboard.write(b);
|
|
estado = AGUARDA_CMD;
|
|
piscaVerde();
|
|
break;
|
|
|
|
// ── Clique: lê L ou R e clica ─────────────────────────────────────────
|
|
case AGUARDA_CLIQUE:
|
|
if (b == 'L') Mouse.click(MOUSE_LEFT);
|
|
if (b == 'R') Mouse.click(MOUSE_RIGHT);
|
|
estado = AGUARDA_CMD;
|
|
piscaVerde();
|
|
break;
|
|
|
|
// ── Tecla press (mantém pressionada) ─────────────────────────────────
|
|
case AGUARDA_PRESS_KEY:
|
|
Keyboard.press(b);
|
|
estado = AGUARDA_CMD;
|
|
piscaVerde();
|
|
break;
|
|
|
|
// ── Tecla release ─────────────────────────────────────────────────────
|
|
case AGUARDA_RELEASE_KEY:
|
|
Keyboard.release(b);
|
|
estado = AGUARDA_CMD;
|
|
piscaVerde();
|
|
break;
|
|
|
|
// ── Mouse press (botão segurado) ──────────────────────────────────────
|
|
case AGUARDA_MOUSE_PRESS:
|
|
if (b == 'L') Mouse.press(MOUSE_LEFT);
|
|
if (b == 'R') Mouse.press(MOUSE_RIGHT);
|
|
estado = AGUARDA_CMD;
|
|
piscaVerde();
|
|
break;
|
|
|
|
// ── Mouse release ─────────────────────────────────────────────────────
|
|
case AGUARDA_MOUSE_RELEASE:
|
|
if (b == 'L') Mouse.release(MOUSE_LEFT);
|
|
if (b == 'R') Mouse.release(MOUSE_RIGHT);
|
|
estado = AGUARDA_CMD;
|
|
piscaVerde();
|
|
break;
|
|
}
|
|
}
|
|
}
|