关于 handle-input
为 Even Hub G2 应用开发者提供输入、手势和生命周期事件处理指南,涵盖容器事件路由、零值省略及退出清理。
主要功能
- 01说明触控手势的事件路由
- 02列出系统与生命周期事件
- 03解释 Protobuf 零值省略
- 04提供事件处理与退出模式
适用场景
- 01排查文本容器点击事件
- 02处理列表选择和滚动
- 03实现应用退出与资源清理
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ even-realities/ everything-evenhub --skill handle-input安装后在 Claude Code 中输入/handle-input确认已加载。
详细介绍
处理输入
Even Hub G2 应用中处理用户输入、手势和生命周期事件的指南。
输入来源
| 来源 | 手势 | 备注 |
|---|---|---|
| G2 触摸板(镜腿) | 按下、双击、向上滑动、向下滑动 | 主要输入方式 |
| R1 触摸板(戒指) | 按下、双击、向上滑动、向下滑动 | 可选配件,手势集相同 |
| IMU(加速度计/陀螺仪) | 头部方向、运动数据 | 参见 device-features 技能 |
事件路由规则
事件的路由方式取决于当前激活的容器类型(即 isEventCapture: 1 的容器)。每个页面只能有一个容器捕获事件。
文本容器处于激活状态
| 手势 | 事件字段 | eventType |
|---|---|---|
| 向上滑动 | event.textEvent | 1 (SCROLL_TOP_EVENT) |
| 向下滑动 | event.textEvent | 2 (SCROLL_BOTTOM_EVENT) |
| 单击 | event.sysEvent | undefined / 0 |
| 双击 | event.sysEvent | 3 (DOUBLE_CLICK_EVENT) |
要点:文本容器上的单击和双击会作为 sysEvent 触发,而非 textEvent。只有滚动手势会作为 textEvent 触发。
列表容器处于激活状态
| 手势 | 事件字段 | 详情 |
|---|---|---|
| 向上/向下滑动 | (内部处理) | SDK 在内部滚动列表,不会触发事件 |
| 单击 | event.listEvent | .currentSelectItemIndex = 所选项目的索引 |
| 双击 | event.sysEvent | .eventType = 3 |
系统事件(始终可用)
| 手势 | 事件字段 | eventType |
|---|---|---|
| 进入前台 | event.sysEvent | 4 (FOREGROUND_ENTER_EVENT) |
| 退出前台 | event.sysEvent | 5 (FOREGROUND_EXIT_EVENT) |
| 异常退出 | event.sysEvent | 6 (ABNORMAL_EXIT_EVENT) |
| 系统退出 | event.sysEvent | 7 (SYSTEM_EXIT_EVENT) |
OsEventTypeList 枚举值
| 值 | 名称 | 描述 |
|---|---|---|
| 0 | CLICK_EVENT | 单击(G2 或 R1) |
| 1 | SCROLL_TOP_EVENT | 向上滑动 |
| 2 | SCROLL_BOTTOM_EVENT | 向下滑动 |
| 3 | DOUBLE_CLICK_EVENT | 双击(G2 或 R1) |
| 4 | FOREGROUND_ENTER_EVENT | 应用进入前台 |
| 5 | FOREGROUND_EXIT_EVENT | 应用进入后台 |
| 6 | ABNORMAL_EXIT_EVENT | 意外断开连接 |
| 7 | SYSTEM_EXIT_EVENT | 系统级退出(例如,用户确认退出对话框) |
| 8 | IMU_DATA_REPORT | IMU 数据样本 |
事件模型
interface Text_ItemEvent {
containerID?: number
containerName?: string
eventType?: number // 1 = scroll up, 2 = scroll down
}
interface List_ItemEvent {
containerID?: number
containerName?: string
currentSelectItemName?: string
currentSelectItemIndex?: number // 0-based; undefined when 0 (protobuf)
eventType?: number
}
interface Sys_ItemEvent {
eventType?: number // undefined/0 = single click, 3 = double click
eventSource?: EventSourceType // 0=null, 1=glasses right, 2=ring, 3=glasses left
imuData?: IMU_Report_Data
systemExitReasonCode?: number
}
Protobuf 零值省略
SDK 在底层使用 protobuf。任何值为零/默认值(0、false、空字符串)的字段都会是 undefined,而非零值。这会影响:
sysEvent.eventType— 单击的值为0,但接收到时是undefinedlistEvent.currentSelectItemIndex— 第一项的索引为0,但接收到时是undefined- 任何其他值为
0的数值字段
始终使用空值合并运算符:event.sysEvent.eventType ?? 0、event.listEvent.currentSelectItemIndex ?? 0。
完整事件处理模板
import { waitForEvenAppBridge } from '@evenrealities/even_hub_sdk'
const bridge = await waitForEvenAppBridge()
const unsubscribe = bridge.onEvenHubEvent(event => {
if (event.listEvent) {
// List item selected (single press on list container)
const idx = event.listEvent.currentSelectItemIndex ?? 0
console.log('Selected index:', idx)
return
}
if (event.textEvent) {
// Scroll on text container (NOT clicks — those come via sysEvent)
const type = event.textEvent.eventType ?? 0
if (type === 1) {
// Swipe up / scroll up
} else if (type === 2) {
// Swipe down / scroll down
}
return
}
if (event.sysEvent) {
const type = event.sysEvent.eventType ?? 0
if (type === 0) {
// Single press (on text container, or system-level)
} else if (type === 3) {
// Double press
} else if (type === 4) {
// App resumed (foreground enter)
} else if (type === 5) {
// App backgrounded (foreground exit)
}
return
}
})
// Always clean up on teardown
// unsubscribe()
G2 与 R1 的区别
G2(镜腿触摸板)和 R1(戒指触摸板)使用相同的手势集。要区分两者,请检查 Sys_ItemEvent 中的 eventSource。EventSourceType 的值会指明输入来自左臂、右臂还是戒指配件。
退出机制
每个应用都应提供通过眼镜/戒指交互退出的方式。请使用 SDK 内置的系统退出对话框,而不要自行构建确认界面。
标准模式——双击以显示系统退出对话框:
if (eventType === 3) { // DOUBLE_CLICK_EVENT
// Show the system exit dialog. Don't clean up resources here —
// the user can still cancel. If they confirm, the SDK fires
// SYSTEM_EXIT_EVENT (7) and you clean up in that handler.
bridge.shutDownPageContainer(1)
return
}
shutDownPageContainer 模式:
shutDownPageContainer(0)— 立即退出,不进行确认shutDownPageContainer(1)— 系统退出确认对话框(推荐)
在调用 shutDownPageContainer(1) 之前,不要调用 unsubscribe()、停止硬件或刷新状态。如果这样做后用户点按取消,应用仍会显示在屏幕上,但不再监听事件。请在 ABNORMAL_EXIT_EVENT / SYSTEM_EXIT_EVENT 处理程序中进行清理。
生命周期事件
为应用正确处理全部四种生命周期事件:
| 事件 | 使用场景 |
|---|---|
FOREGROUND_ENTER_EVENT (4) | 重新渲染当前状态,恢复计时器/IMU |
FOREGROUND_EXIT_EVENT (5) | 将待处理状态写入 setLocalStorage,暂停计时器 |
ABNORMAL_EXIT_EVENT (6) | 停止硬件(imuControl(false)、audioControl(false)),取消订阅,写入状态 |
SYSTEM_EXIT_EVENT (7) | 执行与 ABNORMAL_EXIT 相同的清理操作——用户已在系统对话框中确认退出 |
重要说明
- 点击文本容器会触发
sysEvent,而不是textEvent。只有滚动手势才会触发textEvent。这是事件处理错误最常见的来源。 - 清理:
bridge.onEvenHubEvent()会返回一个取消订阅函数。组件销毁时务必调用。 - 每个页面只允许一个事件监听器:只有设置了
isEventCapture: 1的容器才会接收输入事件。如果多个容器都设置了isEventCapture: 1,SDK 会因验证错误而拒绝该页面。
任务
$ARGUMENTS