v0.1首个正式支持的版本化规范查看版本范围

ime

ime 让自绘文本控件接入系统输入法。宿主代持真实输入元素和合成会话,guest 交换有限的编辑状态、选择范围和光标几何,不获得 DOM。

基本示例

const session = await host.ime.openSession('main', {
  text: '',
  selection: { start: 0, end: 0 },
  inputMode: 'text',
  multiline: false,
  revision: 0n,
});

host.events.on('ime.textUpdate', ({ handle, update }) => {
  if (handle !== session) return;
  editor.apply(update);
  host.ime.updateState(session, editor.snapshot());
});

适用场景

  • 自绘文本框、代码编辑器、终端和画布内表单。
  • 中文、日文、韩文等合成输入。
  • 移动端软键盘、选择范围和候选窗口定位。

只处理按键快捷键时使用 input。富文本数据模型、撤销栈、拼写检查策略和协同编辑属于 guest。

L1 边界

宿主独占的是操作系统输入法、候选窗口、软键盘和与应用焦点绑定的合成会话。guest 不能从按键可靠重建这些系统设施;文档模型、排版、撤销和富文本语义仍由 guest 持有。

能力声明

{
  "capabilities": ["host:ime.openSession"],
  "events": [
    "ime.textUpdate",
    "ime.composition",
    "ime.formatUpdate",
    "ime.characterBoundsRequest",
    "ime.ended"
  ]
}

updateStateupdateGeometrycloseSession 都由 ime-session 句柄的 rw 权限授权,不是独立 capability。

Reference

方法

事件

状态模型

ImeState {
  text: string
  selection: { start: u32, end: u32 }
  composition?: { start: u32, end: u32 }
  inputMode: "text" | "numeric" | "email" | "url" | "search"
  multiline: boolean
  revision: u64
}

Rect { x: f32, y: f32, width: f32, height: f32 }

ImeGeometry {
  revision: u64
  editorBounds: Rect
  caretBounds: Rect
  characterBounds?: Array<{ index: u32, rect: Rect }>
}

所有索引统一按 UTF-16 code unit 计数,起止位置必须位于 Unicode 标量边界,不能切开代理对。原生绑定必须按同一规则转换,不能用 UTF-8 字节或 Unicode 标量序号代替。start <= end,所有范围都必须落在当前 revision 的文本内。

characterBoundsindex 是该 Unicode 标量在 UTF-16 中的起始 offset;数组按 index 严格递增且不重复。对于代理对只给一项。矩形使用 canvas 逻辑像素,宽高非负,所有值有限。

完整工作流

  1. 用户点中自绘文本控件,应用调用 openSession
  2. 宿主建立系统输入会话并送达 textUpdate/composition
  3. guest 应用编辑操作,再以 updateState 确认权威状态。
  4. 布局变化时 guest 调用 updateGeometry
  5. 控件失焦或销毁时调用 closeSession;宿主也可以因失焦主动结束。

原生 WASM 示例

ImeHandle ime = host_ime_open_session(MAIN_CANVAS, initial_state());

void on_ime_text_update(ImeTextUpdate update) {
  editor_apply(update);
  ImeState state = editor_snapshot();
  host_ime_update_state(ime, state);
}

大文本不应在每个按键后整段复制;v0.1 绑定必须为状态大小设上限,未来若真实编辑器证明需要增量快照,应在兼容版本中增加明确结构。

生命周期与竞态

  • 句柄类型为 Handle<ime-session, rw, app-context, focus>
  • 会话随绘图面焦点、应用视图和宿主输入元素共同存活。
  • 每次状态更新带单调 revision,过期更新返回 stale-state
  • openSession 接受任意初始 revision;此后每次成功 updateState 的 revision 必须严格增大。updateGeometry 引用当前 revision 但不推进它。
  • 每个会话同一时间最多有一个尚未由 updateState 确认的 textUpdate;宿主在确认前不得发送下一个文本变更。guest 拒绝过期更新时仍应回传当前权威状态以解除等待。
  • 宿主主动或 guest 显式结束时使句柄失效;若应用声明了 ime.ended,发送一次终止事件。随后 update* 返回 stale-handle
  • 同一绘图面同一时间最多一个活动会话。

安全与预算

  • 信任档位:green;内容属于用户与本应用的直接交互。
  • 宿主不得把密码管理器内部数据、其他输入框内容或全局剪贴板混入事件。
  • v0.1 预算键为 ime.maxSessionsime.maxTextCodeUnitsime.maxCharacterBoundsime.updatesPerSecond
  • 密码输入模式若未来引入,必须独立定义回显、日志和截图限制,不能复用普通 text

错误与测试

特有错误包括 not-focusedstale-stateinvalid-rangestale-handlelimit-exceeded。一致性测试至少覆盖合成开始/更新/提交/取消、代理对边界、严格 revision、单个未确认编辑、选择方向、失焦、绘图面销毁、过期 revision 和事件重入。

Host API 版本与分层概览Host API v0.1版本非正式提议提议canvas API呈现canvas.getInfo()方法canvas.draw()方法canvas.present()方法canvas.measureText()方法canvas.frame event事件canvas.resize event事件asset API呈现asset.read()方法asset.loadFont()方法playback API呈现playback.open()方法playback.write()方法playback.stop()方法playback.ready event事件playback.ended event事件input API输入input.focus()方法input.pointer event事件input.key event事件input.wheel event事件input.focusChange event事件ime API输入ime.openSession()方法ime.updateState()方法ime.updateGeometry()方法ime.closeSession()方法ime.textUpdate event事件ime.composition event事件ime.formatUpdate event事件ime.characterBoundsRequest event事件ime.ended event事件capture API输入capture.requestCamera()方法capture.requestMic()方法capture.frame()方法capture.readAudio()方法capture.stop()方法capture.ended event事件store API数据store.get()方法store.put()方法store.delete()方法store.list()方法store.deletePrefix()方法clipboard API数据clipboard.readText()方法clipboard.writeText()方法env API平台集成env.snapshot()方法env.change event事件开始调用 Host API指南构建交互式绘图应用指南构建自绘文本编辑器指南管理媒体采集与播放指南组织本地数据与同步指南