/// /// /// import { textInput } from "../scrapbox-userscript-std/dom.ts"; import { promisify } from "../async-lib/mod.ts"; import { stringify } from "../vim-like-key-notation/mod.ts"; export const KeyWatcher = class { private sequence = ""; private adaptor = promisify< KeyboardEvent | CompositionEvent >({ maxQueued: 0 }); private keyWatcher = this.adaptor[0]; private handleKey = this.adaptor[1]; private handleKeydown = (e: KeyboardEvent) => { if (e.isComposing) return; this.handleKey(e); }; constructor(private dom: HTMLElement | Document | (typeof globalThis) = globalThis) { this.dom.addEventListener("keydown", this.handleKeydown as EventListener); textInput()!.addEventListener("compositionstart", this.handleKey); } public reset(): void { this.sequence = ""; } private dispose (): void { this.dom.removeEventListener("keydown", this.handleKeydown as EventListener); textInput()!.removeEventListener("compositionstart", this.handleKey); }; public async* listen(): AsyncGenerator { while (true) { const event = await this.keyWatcher(); if (event instanceof KeyboardEvent) { this.sequence += stringify(event); } else { // 入力が確定したときのみ取得する const { data } = await new Promise((resolve) => { textInput()!.addEventListener("compositionend", resolve, { once: true }); }); this.sequence += data; } yield this.sequence; } } };