# 04 — Module điều khiển input qua Virtual KMBox

## 1. Vì sao dùng KMBox?

KMBox là thiết bị **trung gian giữa chuột/bàn phím vật lý và máy tính**: PC nối vào KMBox,
KMBox nối vào máy chơi game và nhận diện như **HID thật**. Tool gửi lệnh qua mạng/serial tới
KMBox, KMBox chuyển thành tín hiệu USB nguyên bản. Với game chạy trên cùng 1 máy, dùng
chế độ "virtual"/loopback: game nhìn thấy sự kiện như đến từ thiết bị vật lý, không qua
các API điều khiển ảo của Windows (`SendInput`, `keybd_event`, driver điều khiển).

> **"Virtual KMBox"** trong dự án này = lớp trừu tượng `ITransport` có 2 backend:
> **KMBox Net** (UDP, phổ biến nhất) và **Serial/USB** (KMBox B), chọn theo phần cứng.

## 2. Kiến trúc module

```mermaid
flowchart LR
    DEC["DecisionEngine"] -->|ActionCommand| HUM["Humanizer"]
    HUM -->|InputEvent queue| WORKER["InputWorker thread"]
    WORKER --> T1["KMBoxNetTransport\n(asio UDP :9999)"]
    WORKER --> T2["KMBoxSerialTransport\n(serial COM)"]
    T1 --> DEV["Thiết bị KMBox"]
    T2 --> DEV
    DEV -->|HID thật| GAME["Máy game"]
```

## 3. Giao thức KMBox Net (tóm tắt thao tác)

- Mặc định: **UDP, cổng 9999**, gói tin dạng ASCII cố định độ dài (dùng `std::array<char, N>` — không cấp phát).
- Ví dụ câu lệnh (đã phổ biến trong cộng đồng KMBox):
  - `km.move(<x>,<y>)` — di chuyển tương đối chuột
  - `km.left(1)` / `km.left(0)` — nhấn/nhả chuột trái
  - `km.key(<code>,<1|0>)` — nhấn/nhả phím
  - `km.esc(<1|0>)`
- Mỗi packet gửi kèm **heartbeat interval**; InputWorker theo dõi ACK/không ACK để watchdog phát hiện mất thiết bị.
- Chi tiết chuẩn hóa sẽ xác nhận khi cắm thiết bị thật (Phase 2 của [07-roadmap.md](07-roadmap.md)).

## 4. Humanizer — biến lệnh máy thành hành động "người thật"

Đây là phần quyết định bot "real play như pro-player" hay "như bot".

| Hiệu ứng | Cách làm |
|----------|----------|
| **Reaction delay** | DecisionEngine xuất lệnh tại frame T → InputWorker thực thi tại T + N(180ms, σ=60ms), truncate [90, 400]ms |
| **Mouse path** | Di chuyển chuột theo **đường cong Bezier** với vận tốc gauss, không teleport con trỏ |
| **Overshoot** | 20% số lần lật camera/lịch chuột đi quá đích 1–3° rồi kéo lại |
| **Key jitter** | Thời gian giữ phím biến thiên ±15%; giữa 2 phím trong combo có gap 20–60ms |
| **Micro-idle** | Trong idle dài, thỉnh thoảng "nhìn quanh" (di chuyển camera nhỏ ngẫu nhiên) |
| **Fatigue** | Sau 40–60 phút chạy, tăng nhẹ reaction delay và jitter (mô phỏng người mỏi) |

```cpp
struct InputEvent {
    InputKind kind;              // KeyPress, KeyRelease, MouseMoveRel, MouseButton
    std::chrono::steady_clock::time_point execute_at;  // đã cộng reaction delay
    std::array<char, 64> payload;   // packet ascii sẵn sàng cho transport
};

class Humanizer {
public:
    // Nhận ActionCommand → sinh chuỗi InputEvent với timing/path đã "người hóa"
    std::vector<InputEvent> realize(const ActionCommand& cmd, Rng& rng);
private:
    ReactionModel  reaction_;     // gauss delay, fatigue factor
    MousePathGen   path_gen_;     // Bezier + overshoot
    KeyTimingModel key_timing_;   // hold time, inter-key gap
};
```

## 5. Ưu tiên & interrupt

- `ActionCommand` có `Priority`:
  - `P0_Emergency` (Dodge, potion) — **pre-empt** mọi event đang chờ trong queue, flush queue.
  - `P1_Combat` (CastSkill) — xếp hàng, giữ thứ tự combo.
  - `P2_Navigation` (MoveTo) — bị thay thế nếu có command mới cùng loại (chỉ giữ cái mới nhất).
- Humanizer **không bao giờ** tăng tốc vượt giới hạn vật lý: tốc độ quay camera/keystroke đều nằm trong phân bố đo được từ người chơi thật (thu thập dữ liệu tham khảo ở Phase 1).

## 6. Độ trễ end-to-end (ngân sách thiết kế)

| Giai đoạn | Ngân sách |
|-----------|-----------|
| MemoryReader tick | ≤ 16 ms |
| DecisionEngine | ≤ 8 ms |
| Reaction delay (chủ động) | 90–400 ms |
| UDP tới KMBox | < 1 ms LAN |
| Game xử lý input | ~1 frame |
| **Tổng phản ứng với đòn boss** | ~120–430 ms — đủ để né hầu hết telegraphed attack có windup ≥ 0.5s |
