# 实用工具模块

<cite>
**本文引用的文件**
- [logger.js](file://client/src/logger.js)
- [log.ts](file://src/log.ts)
- [memoryhelper.js](file://client/src/memoryhelper.js)
- [charnumber.js](file://client/src/charnumber.js)
- [inputdevice.js](file://client/src/inputdevice.js)
- [pointercorrect.js](file://client/src/pointercorrect.js)
- [pointercorrect.test.js](file://client/test/pointercorrect.test.js)
- [memoryhelper.test.js](file://client/test/memoryhelper.test.js)
- [inputdevice.test.js](file://client/test/inputdevice.test.js)
- [package.json](file://package.json)
</cite>

## 目录
1. [简介](#简介)
2. [项目结构](#项目结构)
3. [核心组件](#核心组件)
4. [架构总览](#架构总览)
5. [详细组件分析](#详细组件分析)
6. [依赖关系分析](#依赖关系分析)
7. [性能考量](#性能考量)
8. [故障排查指南](#故障排查指南)
9. [结论](#结论)
10. [附录](#附录)

## 简介
本文件系统性地文档化了“实用工具模块”，涵盖以下方面：
- 日志系统：前端简易开关式日志与后端结构化日志（含级别、时间戳、前缀格式化）。
- 内存辅助工具：按位写入字节缓冲，支持位级布尔操作与整型大小常量。
- 字符数字转换工具：按键键值映射与字符编码处理，支撑文本事件生成。
- 指针校正工具：坐标变换、黑边填充（Letterbox）补偿、屏幕适配与输入精度优化。

文档同时提供可直接定位到源码位置的路径指引，便于在实际项目中快速集成与验证。

## 项目结构
实用工具模块位于客户端与服务端两处：
- 客户端工具位于 client/src，包含日志开关、内存辅助、字符映射、输入设备状态序列化、指针校正等。
- 服务端日志位于 src/log.ts，提供结构化日志级别与格式化输出。

```mermaid
graph TB
subgraph "客户端(client/src)"
LJS["logger.js<br/>前端简易日志"]
MJS["memoryhelper.js<br/>内存辅助(位写入)"]
CJS["charnumber.js<br/>字符数字映射"]
IDJS["inputdevice.js<br/>输入设备/状态/事件"]
PCJS["pointercorrect.js<br/>指针校正"]
end
subgraph "服务端(src)"
LTS["log.ts<br/>结构化日志"]
end
IDJS --> MJS
IDJS --> CJS
PCJS --> |"使用元素尺寸/布局"| 浏览器DOM["浏览器DOM/HTMLVideoElement"]
LJS -. 可独立使用 .-> 浏览器控制台
LTS -. 输出到 .-> Node控制台
```

图表来源
- [logger.js:1-30](file://client/src/logger.js#L1-L30)
- [memoryhelper.js:1-28](file://client/src/memoryhelper.js#L1-L28)
- [charnumber.js:1-110](file://client/src/charnumber.js#L1-L110)
- [inputdevice.js:1-719](file://client/src/inputdevice.js#L1-L719)
- [pointercorrect.js:1-125](file://client/src/pointercorrect.js#L1-L125)
- [log.ts:1-51](file://src/log.ts#L1-L51)

章节来源
- [logger.js:1-30](file://client/src/logger.js#L1-L30)
- [log.ts:1-51](file://src/log.ts#L1-L51)

## 核心组件
- 前端日志工具（logger.js）
  - 提供启用/禁用与多级别输出函数，基于全局开关控制是否打印至浏览器控制台。
  - 适合开发调试阶段按需开启/关闭日志输出。
- 后端日志工具（log.ts）
  - 定义日志级别枚举与解析函数；统一格式化时间戳与级别前缀；根据级别选择对应 console 方法输出。
  - 支持通过配置设置全局日志级别，实现生产环境精细化日志控制。
- 内存辅助工具（memoryhelper.js）
  - 提供静态方法按位写入 ArrayBuffer 的指定偏移；支持置位/清位；提供整型大小常量。
  - 在输入设备状态序列化中用于紧凑存储布尔标志位。
- 字符数字转换工具（charnumber.js）
  - 提供按键键名到数值的映射表，用于文本事件生成与键盘状态记录。
- 指针校正工具（pointercorrect.js）
  - 将浏览器坐标系映射到视频坐标系，处理黑边（Letterbox）补偿与元素内内容矩形计算。
  - 支持动态重置视频宽高与元素尺寸，适配不同播放场景。

章节来源
- [logger.js:1-30](file://client/src/logger.js#L1-L30)
- [log.ts:1-51](file://src/log.ts#L1-L51)
- [memoryhelper.js:1-28](file://client/src/memoryhelper.js#L1-L28)
- [charnumber.js:1-110](file://client/src/charnumber.js#L1-L110)
- [pointercorrect.js:1-125](file://client/src/pointercorrect.js#L1-L125)

## 架构总览
下图展示了输入设备状态序列化与文本事件生成的整体流程，体现内存辅助与字符映射在其中的关键作用。

```mermaid
sequenceDiagram
participant Dev as "输入设备"
participant State as "键盘状态"
participant Mem as "内存辅助(MemoryHelper)"
participant Text as "文本事件(TextEvent)"
Dev->>State : "按键事件(KeyboardEvent)"
State->>Mem : "按位写入(keys缓冲, 键位索引, 布尔值)"
Mem-->>State : "更新后的keys缓冲"
State-->>Text : "生成文本事件(包含InputEvent头+字符编码)"
Text-->>外部 : "序列化为ArrayBuffer"
```

图表来源
- [inputdevice.js:274-322](file://client/src/inputdevice.js#L274-L322)
- [memoryhelper.js:7-20](file://client/src/memoryhelper.js#L7-L20)
- [charnumber.js:3-109](file://client/src/charnumber.js#L3-L109)
- [inputdevice.js:620-660](file://client/src/inputdevice.js#L620-L660)

## 详细组件分析

### 日志系统（前端与后端）
- 前端简易日志（logger.js）
  - 开关控制：enable/disable 切换 isDebug 标志，后续 debug/info/log/warn/error 仅在开启时输出。
  - 使用建议：开发阶段调用 enable，发布版本调用 disable；或结合构建脚本条件编译。
- 后端结构化日志（log.ts）
  - 级别定义：none/error/warn/log/info 五级；parseLogLevel 支持字符串解析。
  - 输出格式：统一 ISO 时间戳与大写级别前缀；按级别选择 console.error/warn/info/log。
  - 控制策略：setLogLevel 设置全局级别；当级别为 none 时不输出任何内容。

```mermaid
flowchart TD
Start(["开始"]) --> SetLevel["设置日志级别(setLogLevel)"]
SetLevel --> Parse["解析字符串级别(parseLogLevel)"]
Parse --> LogCall["log(级别, 参数...)"]
LogCall --> Check{"级别允许输出?"}
Check --> |否| Exit["结束(不输出)"]
Check --> |是| Format["格式化时间戳与级别前缀"]
Format --> Console["按级别输出(console.*)"]
Console --> Exit
```

图表来源
- [log.ts:11-24](file://src/log.ts#L11-L24)
- [log.ts:30-50](file://src/log.ts#L30-L50)

章节来源
- [logger.js:1-30](file://client/src/logger.js#L1-L30)
- [log.ts:1-51](file://src/log.ts#L1-L51)

### 内存辅助工具（MemoryHelper）
- 功能概述
  - writeSingleBit：对指定 bitOffset 的位进行置位/清位，底层通过 Uint8Array 访问目标字节。
  - sizeOfInt：返回整型字节数常量，用于事件头与数据之间的边界计算。
- 复杂度与性能
  - 单次写入为 O(1)，空间开销极小；适合高频输入事件的布尔标志位压缩存储。
- 典型用法
  - 在键盘/鼠标/手柄状态类中，使用该工具将布尔标志位紧凑写入缓冲区，减少带宽占用。

```mermaid
flowchart TD
S(["进入writeSingleBit"]) --> View["创建Uint8Array视图"]
View --> Index["计算字节索引(index)"]
Index --> Offset["计算位偏移(bitOffset)"]
Offset --> Load["读取原字节值(byte)"]
Load --> Mask["构造掩码(1<<bitOffset)"]
Mask --> Op{"value为真?"}
Op --> |是| Or["按位或置位"]
Op --> |否| And["按位与清位"]
Or --> Store["写回新字节"]
And --> Store
Store --> E(["退出"])
```

图表来源
- [memoryhelper.js:7-20](file://client/src/memoryhelper.js#L7-L20)

章节来源
- [memoryhelper.js:1-28](file://client/src/memoryhelper.js#L1-L28)
- [memoryhelper.test.js:1-67](file://client/test/memoryhelper.test.js#L1-L67)

### 字符数字转换工具（CharNumber 与 Keymap）
- CharNumber
  - 将按键键名映射到数值编码，用于文本事件生成与键盘状态记录。
- Keymap
  - 将 KeyboardEvent.code 映射到内部键位索引，配合 MemoryHelper 写入 keys 缓冲。
- 文本事件生成
  - TextEvent.create 组合 InputEvent 头与字符编码，最终序列化为 ArrayBuffer。

```mermaid
classDiagram
class CharNumber {
+映射表
}
class Keymap {
+映射表
}
class KeyboardState {
+buffer : ArrayBuffer
+format : Number
}
class TextEvent {
+create(deviceId, event, time) TextEvent
+buffer : ArrayBuffer
}
KeyboardState --> Keymap : "键位索引"
KeyboardState --> CharNumber : "字符编码"
TextEvent --> KeyboardState : "组合InputEvent头"
```

图表来源
- [charnumber.js:3-109](file://client/src/charnumber.js#L3-L109)
- [inputdevice.js:274-322](file://client/src/inputdevice.js#L274-L322)
- [inputdevice.js:620-660](file://client/src/inputdevice.js#L620-L660)

章节来源
- [charnumber.js:1-110](file://client/src/charnumber.js#L1-L110)
- [inputdevice.js:274-322](file://client/src/inputdevice.js#L274-L322)
- [inputdevice.js:620-660](file://client/src/inputdevice.js#L620-L660)

### 指针校正工具（PointerCorrector）
- 功能概述
  - 将浏览器坐标系（clientX/Y）转换为视频坐标系，考虑元素内黑边（Letterbox）补偿与视频宽高比。
  - 提供 letterBoxType、letterBoxSize、contentRect 等属性，便于精确映射。
- 关键步骤
  - 原点归零：减去元素左上角偏移。
  - Y轴反转：浏览器坐标系向下为正，视频坐标系向上为正。
  - 黑边补偿：减去 letterbox 的 x/y 偏移。
  - 比例映射：按 contentRect 与 video 尺寸比缩放。
- 适用场景
  - 视频播放器内点击/触摸区域映射、远程输入定位、跨屏适配。

```mermaid
flowchart TD
In(["输入: [clientX, clientY]"]) --> SubOrigin["减去元素左上角偏移"]
SubOrigin --> FlipY["Y轴反转(height - y)"]
FlipY --> AddLB["减去黑边偏移(x,y)"]
AddLB --> Scale["按contentRect与video尺寸比缩放"]
Scale --> Out(["输出: [videoX, videoY]"])
```

图表来源
- [pointercorrect.js:20-40](file://client/src/pointercorrect.js#L20-L40)
- [pointercorrect.js:78-119](file://client/src/pointercorrect.js#L78-L119)

章节来源
- [pointercorrect.js:1-125](file://client/src/pointercorrect.js#L1-L125)
- [pointercorrect.test.js:1-46](file://client/test/pointercorrect.test.js#L1-L46)

## 依赖关系分析
- 输入设备模块（inputdevice.js）依赖：
  - MemoryHelper：用于将布尔标志位写入缓冲。
  - CharNumber：用于文本事件中的字符编码。
  - Keymap：用于将 KeyboardEvent.code 转换为内部键位索引。
  - 其他：MouseButton、GamepadButton、TouchPhase、TouchFlags 等常量与枚举。
- 指针校正工具（pointercorrect.js）依赖：
  - HTMLVideoElement 的 getBoundingClientRect 获取元素尺寸与偏移。
  - LetterBoxType 枚举与 contentRect 计算逻辑。

```mermaid
graph LR
ID["inputdevice.js"] --> MH["memoryhelper.js"]
ID --> CN["charnumber.js"]
ID --> KM["keymap.js"]
ID --> MB["mousebutton.js"]
ID --> GPB["gamepadbutton.js"]
ID --> TP["touchphase.js"]
ID --> TF["touchflags.js"]
PC["pointercorrect.js"] --> DOM["HTMLVideoElement<br/>getBoundingClientRect()"]
```

图表来源
- [inputdevice.js:1-10](file://client/src/inputdevice.js#L1-L10)
- [pointercorrect.js:12-14](file://client/src/pointercorrect.js#L12-L14)

章节来源
- [inputdevice.js:1-719](file://client/src/inputdevice.js#L1-L719)
- [pointercorrect.js:1-125](file://client/src/pointercorrect.js#L1-L125)

## 性能考量
- 内存辅助（MemoryHelper）
  - O(1) 位写入，适合高频输入事件；注意避免频繁创建 ArrayBuffer，复用现有缓冲可降低分配开销。
- 日志输出
  - 前端：isDebug 控制，避免在生产环境输出；建议在打包阶段移除调试日志以减少运行时开销。
  - 后端：通过 setLogLevel 限制输出级别，生产环境建议仅输出 error/warn；格式化字符串与级别前缀为常量，开销可控。
- 指针校正
  - map 为纯数学运算，复杂度低；letterBoxType/letterBoxSize/contentRect 可缓存于实例字段，减少重复计算。

## 故障排查指南
- 日志不输出
  - 前端：确认已调用 enable；检查 isDebug 是否被其他逻辑覆盖。
  - 后端：确认 setLogLevel 已正确设置；若级别为 none，则不会输出任何内容。
- 文本事件字符异常
  - 检查 CharNumber 中是否存在目标键名映射；确保 KeyboardEvent.key 与映射一致。
- 指针映射不准
  - 确认 HTMLVideoElement 的尺寸与样式（如 object-fit）未引入额外缩放；必要时在 PointerCorrector.reset 中传入最新尺寸。
  - 验证 letterBoxType 与 letterBoxSize 计算结果是否符合预期。

章节来源
- [logger.js:1-30](file://client/src/logger.js#L1-L30)
- [log.ts:11-24](file://src/log.ts#L11-L24)
- [pointercorrect.test.js:1-46](file://client/test/pointercorrect.test.js#L1-L46)
- [memoryhelper.test.js:1-67](file://client/test/memoryhelper.test.js#L1-L67)

## 结论
本实用工具模块围绕“日志、内存、字符、指针”四大主题，提供了简洁高效的实现：
- 日志系统兼顾前端与后端，满足开发与生产的差异化需求；
- 内存辅助工具以位级写入为核心，支撑输入事件的紧凑序列化；
- 字符数字转换工具完善了键盘事件到内部表示的映射；
- 指针校正工具解决了视频播放场景下的坐标适配问题。

建议在实际项目中：
- 将日志级别纳入构建配置，按环境自动切换；
- 在输入设备状态序列化中优先使用 MemoryHelper 进行位级压缩；
- 对文本事件生成进行单元测试覆盖，保证字符映射一致性；
- 在视频播放器中使用 PointerCorrector 进行坐标映射与黑边补偿。

## 附录

### 使用示例（路径指引）
- 启用前端调试日志
  - 参考：[logger.js:3-9](file://client/src/logger.js#L3-L9)
- 设置后端日志级别
  - 参考：[log.ts:11-24](file://src/log.ts#L11-L24)
- 生成文本事件
  - 参考：[inputdevice.js:639-646](file://client/src/inputdevice.js#L639-L646)
- 按位写入布尔标志
  - 参考：[memoryhelper.js:7-20](file://client/src/memoryhelper.js#L7-L20)
- 指针坐标映射
  - 参考：[pointercorrect.js:20-40](file://client/src/pointercorrect.js#L20-L40)

### 测试参考
- 指针校正单元测试
  - 参考：[pointercorrect.test.js:1-46](file://client/test/pointercorrect.test.js#L1-L46)
- 内存辅助单元测试
  - 参考：[memoryhelper.test.js:1-67](file://client/test/memoryhelper.test.js#L1-L67)
- 输入设备与文本事件测试
  - 参考：[inputdevice.test.js:135-144](file://client/test/inputdevice.test.js#L135-L144)