# 72. ĐẶC TẢ KIẾN TRÚC KHÓA AN TOÀN PHẦN CỨNG TIỀN CẢNH & TRIỆT TIÊU RÒ RỈ INPUT DESKTOP (HARDWARE FOCUS INTERLOCK SPECIFICATION)

- **Mã Tài Liệu**: `DOC-72-HARDWARE-FOCUS-INTERLOCK-SAFETY-2026`
- **Mốc Thời Gian Tham Chiếu**: `18/09/2026`
- **Mã Bất Biến Kiến Trúc**: `INV-FOCUS-INTERLOCK-HARDWARE-SAFETY`
- **Phạm Vi**: Hai tầng C++23 Core Engine (Hot Path 120Hz) và Python 3.11 Companion (Cold Path 30Hz)
- **Trạng Thái**: `CANONICAL STANDARD & SSoT (BẮT BUỘC TUÂN THỦ TOÀN DỰ ÁN)`

---

## 1. BỐI CẢNH SỰ CỐ & TRIỆU CHỨNG (INCIDENT DOSSIER)

Trong quá trình vận hành bot kết hợp người dùng làm việc đa nhiệm trên hệ điều hành Windows:
- **Triệu chứng**: Khi người dùng chuyển đổi cửa sổ (Alt+Tab sang trình duyệt web, IDE, Word, Telegram hoặc màn hình chính Windows), xuất hiện hiện tượng các ký tự phím `aswd` bất thường tự động gõ liên tục vào văn bản/trình duyệt đang làm việc.
- **Nguy cơ cấp 1**: Gây gián đoạn công việc người dùng, rò rỉ dữ liệu, nguy cơ gửi tin nhắn hoặc thao tác nhầm trên hệ thống, và vi phạm nguyên lý tàng hình phòng thủ (Defensive Anti-Cheat).

---

## 2. PHÂN TÍCH NGUYÊN NHÂN GỐC RỄ 4 BƯỚC (4-STEP RCA)

### 2.1. Bước 1: Tái Hiện & Truy Vết (Trace Call Graph)
1. **Lỗ hổng "Khóa Kẹt Phím Phần Cứng" (Hardware Key Latch Defect)**:
   - Trong `src/core/input/kmbox_net.cpp`, hàm `KeyUp(hidScanCode)` và `KeyUpVk(vkCode)` trước đây chứa dòng kiểm tra:
     ```cpp
     if (!IsGameWindowFocused()) {
         return false; // SAI LẦM: Chặn KeyUp khi mất focus!
     }
     ```
   - Khi nhân vật đang di chuyển bằng WASD (`KeyDownVk(0x57)`), người dùng bất ngờ Alt+Tab ra Desktop.
   - `IsGameWindowFocused()` lập tức chuyển sang `false`.
   - Lệnh `KeyUpVk(0x57)` dự kiến gửi từ `MovementController::Stop()` hoặc `NonBlockingActuator::ProcessPendingReleases()` bị `KMBoxNet` **TỪ CHỐI THỰC THI** (`return false`).
   - Kết quả: Vi điều khiển phần cứng KMBox Net (thiết bị USB HID độc lập) vẫn duy trì trạng thái đè phím 'W' / 'A' / 'S' / 'D' trong báo cáo USB HID Descriptor. Windows nhận diện phím WASD tiếp tục được gõ liên tục vào cửa sổ mới active (Desktop của người dùng).

2. **Lỗ hổng "Nhận diện cửa sổ bằng Substring Title" (Browser False Positive)**:
   - `IsGameWindowFocused()` dùng `wcsstr(title, L"Path of Exile")`.
   - Nếu người dùng mở trình duyệt tra cứu POE Trade ("Path of Exile - Trade") hoặc POE Wiki ("Path of Exile 2 Wiki"), hàm ngộ nhận trình duyệt là game POE2 và tiếp tục phát lệnh chuột/phím vào trình duyệt.

3. **Lỗ hổng "Cold Path Không Kiểm Tra Foreground" (Win32 Input Leakage)**:
   - Trong `src/common/win32_input.py`, các hàm `send_wasd_direction`, `press_key`, `click` gọi thẳng `user32.keybd_event` / `mouse_event` mà không qua bất kỳ lớp kiểm tra cửa sổ tiền cảnh nào.

4. **Sự cố ngày 19/09/2026: Lỗ hổng "Đồng nhất Mock Test với Physical Input" (Simulation Leakage Defect)**:
   - **Triệu chứng**: Người dùng phản ánh phím `awawaw...` tự động gõ liên tục vào ứng dụng đang làm việc và chuột bị giật/chiếm quyền điều khiển trên Desktop chính.
   - **Bằng chứng hình ảnh**: Ảnh thực địa [`captures/live_ops/20260919_141618_REPORT_ITER11.png`](captures/live_ops/20260919_141618_REPORT_ITER11.png) và artifact `LIVE_REPORT_ITER11.png` ghi nhận dòng lệnh trong terminal `pwsh.exe` của Antigravity nhận chuỗi ký tự rác `uawawawa... wâ uawawaw`.
   - **Root Cause**: Hàm `_is_focus_allowed()` trước đây có dòng:
     ```python
     if _GLOBAL_SIMULATED_FOCUS is not None:
         return _GLOBAL_SIMULATED_FOCUS
     if is_simulated:
         return True
     ```
     Điều này khiến khi các bài test, simulation harness hoặc coordinator chạy với cờ `is_simulated=True`, hàm cho phép gửi input vật lý ra hệ điều hành!
     Đồng thời, hàm `send_wasd_direction` trước đây có dwell time 350ms nhưng chỉ kiểm tra focus ở đầu chu trình, sau đó `time.sleep(0.35)` mà không kiểm tra liveness focus giữa chu trình. Khi người dùng Alt+Tab giữa lúc sleep, phím WASD vẫn bị đè và nhả ra cửa sổ mới.
     Ngoài ra, các hàm điều khiển chuột `set_cursor_pos` và `hover` không hề kiểm tra Focus Interlock, khiến con trỏ chuột người dùng bị giật về tọa độ game.

---

## 3. KIẾN TRÚC GIẢI PHÁP ĐỒNG BỘ 2 TẦNG (TWO-TIER INTEGRATED ARCHITECTURE)

```mermaid
flowchart TD
    subgraph "Windows OS Event / User Interaction"
        AltTab["Người dùng Alt+Tab ra Desktop / App khác"]
    end

    subgraph "Tier 1: C++23 Hot Path (120Hz)"
        FocusCheck{"IsGameWindowFocused()?<br/>Two-Factor Validation:<br/>ClassName + ProcessExe"}
        FocusCheck -- "True (Game Active)" --> AllowDown["Cho phép KeyDown / MouseDown"]
        FocusCheck -- "Transition True->False" --> AutoRelease["TỰ ĐỘNG GỌI ReleaseAllKeys()!"]
        AutoRelease --> FlushKMBox["Gửi gói tin KeyUp/MouseUp<br/>xả sạch toàn bộ phím phần cứng!"]
        KeyDownCmd["Lệnh KeyDown / MouseDown"] --> Guard{"Focus == True?"}
        Guard -- "No" --> RejectDown["CHẶN TUYỆT ĐỐI (Return false)"]
        Guard -- "Yes" --> SendDown["Gửi tín hiệu xuống KMBox"]
        KeyUpCmd["Lệnh KeyUp / MouseUp"] --> AlwaysSend["LUÔN LUÔN CHO PHÉP (Không bao giờ chặn!)"]
    end

    subgraph "Tier 2: Python 3.11 Cold Path (30Hz)"
        PyInput["win32_input.py / send_wasd_direction()"] --> PyGuard{"is_poe2_window_focused()?"}
        PyGuard -- "No" --> EmergencyRelease["emergency_release_wasd_keys()<br/>Không gửi input"]
        PyGuard -- "Yes" --> SendPy["Gửi win32 keybd_event"]
    end

    AltTab --> FocusCheck
    AltTab --> PyGuard
```

### 3.1. Bất Biến Khóa An Toàn Phần Cứng (INV-FOCUS-INTERLOCK-HARDWARE-SAFETY)
- **Quy tắc Vàng Cấp Thấp**:
  1. **Chỉ chặn `KeyDown` và `MouseDown` khi unfocused**.
  2. **TUYỆT ĐỐI CẤM chặn `KeyUp` và `MouseUp`**: Mọi yêu cầu nhả phím và nhả chuột bắt buộc phải được chuyển tiếp 100% tới phần cứng KMBox để giải phóng thanh ghi vi điều khiển USB HID.
  3. **Tự động kích hoạt `ReleaseAllKeys()` khi mất Focus**: Khi phát hiện chuyển đổi trạng thái `m_lastGameFocused == true` và `currentlyFocused == false`, KMBoxNet tự động giải phóng toàn bộ phím đang giữ (`m_heldHidKeys`, `m_heldMouseButtons`) và gửi xung nhả danh sách phím cốt lõi (`WASD`, `Move-Only`, `Space`, `Ctrl`, `Shift`, `Alt`, `Q`, `E`, `R`, `1-5`).
  4. **Key Releases không tính vào Rate Limit Quota**: Các hàm `KeyUp` và `MouseUp` không gọi `RecordAction()`, bảo đảm giải phóng phím không bao giờ bị nghẽn bởi Action Gatekeeper.

### 3.2. Xác Thực Cửa Sổ Hai Cấp (Two-Factor Window Validation)
Hàm `common::IsPoe2WindowHwnd(HWND)` và Python `is_poe2_window_focused()` triển khai xác thực 2 yếu tố:
1. **Window Class**: Bắt buộc phải là `POEWindowClass` hoặc `POEC2_MainWindow`. Loại trừ 100% các cửa sổ trình duyệt (Chrome, Edge, Firefox), IDE (VS Code, Visual Studio), hay Desktop.
2. **Process Image Name**: Kiểm tra tiến trình sở hữu HWND có tên tệp là `PathOfExile.exe`, `PathOfExileSteam.exe`, `PathOfExile2.exe`, `PathOfExile_x64.exe` hoặc `PathOfExile_x64Steam.exe`.

### 3.3. Bất Biến Phân Tách Tuyệt Đối Giả Lập Và Phần Cứng Thực Tế (INV-FOCUS-SAFETY-SEPARATION)
- **Nguyên lý cốt lõi**: Trạng thái "Giả lập Focus thành công" (`is_simulated=True` hoặc `_GLOBAL_SIMULATED_FOCUS is not None`) chỉ phục vụ cho việc tiến bước logic trạng thái (FSM) và test logic. Nó **TUYỆT ĐỐI KHÔNG ĐƯỢC ĐỒNG NGHĨA** với việc cho phép gửi tín hiệu Win32 vật lý ra hệ điều hành.
- **Hàm rào chắn 2 lớp tại `src/common/win32_input.py`**:
  ```python
  def _is_focus_allowed(is_simulated: bool = False) -> bool:
      """Kiểm tra xem logic FSM có được phép tiếp tục hay không (chấp nhận simulation)."""
      if _GLOBAL_SIMULATED_FOCUS is not None:
          return _GLOBAL_SIMULATED_FOCUS
      if is_simulated:
          return True
      return is_poe2_window_focused()

  def _is_physical_allowed(is_simulated: bool = False) -> bool:
      """RÀO CHẮN SINH TỬ: Tuyệt đối CẤM gửi tín hiệu vật lý nếu đang ở chế độ Simulation."""
      if _GLOBAL_SIMULATED_FOCUS is not None or is_simulated:
          return False  # CẤM 100% gửi input ra OS trong khi test/sim
      return is_poe2_window_focused()
  ```
- **Hệ quả**: Bất kỳ bài test nào chạy với `is_simulated=True` hoặc thiết lập mock focus đều hoàn toàn bị cô lập khỏi hệ điều hành. 0 byte input, 0 phím ảo được gửi ra Windows API.

### 3.4. Giám Sát Focus Thời Gian Thực Trong Vòng Lặp WASD & Chuột
1. **Real-Time Polling Trong Dwell Time**:
   - `send_wasd_direction` chia nhỏ khoảng thời gian giữ phím (dwell time 350ms) thành các lát cắt nhỏ 35ms.
   - Tại mỗi nhịp 35ms, hàm gọi kiểm tra `_is_physical_allowed()`.
   - Nếu phát hiện người dùng Alt+Tab, hàm lập tức ngắt vòng lặp (`break`) và gọi ngay `emergency_release_wasd_keys()`.
2. **Khóa Chuột Tiền Cảnh (Mouse Cursor Interlock)**:
   - Các hàm `set_cursor_pos(x, y)` và `hover(x, y)` bắt buộc kiểm tra `_is_physical_allowed()`.
   - Nếu game không ở Foreground, từ chối di chuyển con trỏ chuột (`return False`), bảo vệ 100% quyền điều khiển chuột của người dùng.

---

## 4. BẰNG CHỨNG XÁC MINH THỰC NGHIỆM (EMPIRICAL VERIFICATION)

### 4.1. Bộ Kiểm Thử C++23 Hot Path
- **Tệp kiểm thử**: `tests/test_window_utils.cpp` (`TestFocusInterlockHardwareSafety`)
- **Tình huống kiểm tra**:
  1. HWND giả lập / Desktop / Console bị từ chối 100%.
  2. Khi `forcedFocus = 0` (unfocused): `KeyDown` và `MouseDown` bị chặn hoàn toàn, trong khi `KeyUp` và `MouseUp` được chấp thuận 100%.
  3. Khi game chuyển trạng thái mất focus: Toàn bộ phím WASD và chuột tự động được `ReleaseAllKeys()` giải phóng.
  4. `NonBlockingActuator` tự động xóa sạch các slot đang lên lịch dwell time khi mất focus.
- **Kết quả thực thi**:
  ```text
  [Test WindowUtils] Win32 Window & Process Utilities...
  [Test FocusInterlock] Focus Interlock & KMBox Hardware Safety Invariants...
    -> Focus Interlock & KMBox Hardware Safety Invariants OK
    -> WindowUtils Win32 Helpers & Focus Interlock Invariants OK
  [RESULT] TẤT CẢ 1112 KIỂM TRA ĐỀU ĐẠT (PASS)
  [SUCCESS] Hot Path 120Hz Verified: 1112/1112 tests PASSED (0 failures)!
  ```

### 4.2. Bộ Kiểm Thử Python Cold Path (Cập nhật 19/09/2026)
- **Tệp kiểm thử**: `tests/test_focus_interlock.py`, `tests/test_common.py`, `tests/test_autonomous_mapping_coordinator.py`
- **Kết quả thực thi**:
  ```text
  pytest tests/test_focus_interlock.py -v
  ============================= 17 passed in 1.45s ==============================
  
  pytest tests/test_autonomous_mapping_coordinator.py tests/test_common.py -q
  ......................................................                   [100%]
  ============================= 54 passed in 3.12s ==============================
  ```
- **Kiểm chứng rò rỉ hiện trường**:
  - Chạy mô phỏng 10 chu trình WASD và click chuột liên tục với `_GLOBAL_SIMULATED_FOCUS = True` và `is_simulated = True`.
  - Kết quả: `SendInput`, `keybd_event`, `mouse_event`, `SetCursorPos` được gọi ra OS: **0 lần**.
  - Kiểm tra diff vùng input console trước và sau khi chạy: **0 ký tự rác, 0 pixel chuột suy hao**.
