useImeInput

IME(Input Method Editor)を経由したテキスト入力を壁紙で受け取るためのフックです。日本語・中国語・韓国語など、変換が必要な言語の入力を壁紙のメモ帳・検索ボックス・チャット入力等に流し込めます。

useKeyboard がデスクトップ全体の生キーを購読するのに対し、useImeInput壁紙自身に向けて入力された 文字のみを受信します。内部的には壁紙ごとに極小(1×1 px・透明・非アクティベート)のプロキシウィンドウが用意され、activate() を呼ぶとそのプロキシだけが key window 化され、IME がそこに合成テキストを配送します。壁紙ウィンドウ自体は決して key window にならないため、壁紙らしさ(最背面・フォーカスを取らない)が損なわれません。

permissions 宣言が必須

このフックを使うには fluxlay.yamlime-input permission を宣言する必要があります。未宣言の場合、backend が IME 関連のリクエストを HTTP 403 で拒否します。フック自体は同じ API でマウントされますが、ストリームは流れず、activate() / deactivate() も SDK が受理するだけで効果がありません。

fluxlay.yaml
schemaVersion: 1
name: My Wallpaper
slug: my-wallpaper
version: 1.0.0
permissions:
  - ime-input

permissions 全体の意味は manifest を参照してください。keyboardime-input は権限スコープが異なる別枠です(keyboard はグローバル全打鍵、ime-input は壁紙自身に向けられた入力のみ)。

インポート

import { useImeInput } from "@fluxlay/react";

シグネチャ

function useImeInput(): ImeInputApi;
 
interface ImeInputApi {
  composition: string | null;
  cursor: number;
  activate: (anchor?: HTMLElement | { x: number; y: number; height: number }) => void;
  deactivate: () => void;
  onCommit: (handler: (text: string) => void) => () => void;
}

使い方

import { useImeInput } from "@fluxlay/react";
import { useEffect, useRef, useState } from "react";
 
function NotePad() {
  const ime = useImeInput();
  const inputRef = useRef<HTMLDivElement>(null);
  const [text, setText] = useState("");
 
  useEffect(() => {
    return ime.onCommit(committed => setText(prev => prev + committed));
  }, [ime]);
 
  return (
    <div
      ref={inputRef}
      tabIndex={0}
      onClick={() => ime.activate(inputRef.current ?? undefined)}
      onBlur={ime.deactivate}
    >
      <span>{text}</span>
      {ime.composition !== null && <span style={{ opacity: 0.5 }}>{ime.composition}</span>}
    </div>
  );
}

API

名前説明
compositionstring | null合成中の中間文字列(例: 「漢字」を入力中の "か" "かん" "漢")。未合成中は null
cursornumbercomposition 内のキャレット位置。コードポイント単位。
activate(anchor?: HTMLElement | { x: number; y: number; height: number }) => voidプロキシウィンドウを key 化し、IME 入力受付を開始します。HTMLElement(通常は入力欄の ref)か viewport 相対 CSS ピクセルの { x, y, height } を渡すと、IME 候補ウィンドウをキャレット付近に表示します。引数なしの場合はアクティブスクリーンの中央に表示されます。
deactivate() => voidプロキシウィンドウのキーを返却し、IME 入力受付を停止します。コンポーネントのアンマウント時には自動的に呼ばれます。
onCommit(handler) => () => void確定文字列(例: 「漢字」)を受け取るハンドラを登録します。返り値は登録解除関数です。useEffect の cleanup で呼び出してください。

activate には React の MouseEvent などを直接渡さないでください。受け付けるのは HTMLElement{ x, y, height } のみです。onClick から呼ぶ場合は onClick={ime.activate} ではなく onClick={() => ime.activate(ref.current ?? undefined)} のようにラップしてください。

useKeyboard との関係

activate() 状態の間は当該壁紙への useKeyboard 配信が一時停止されます。これは IME 候補ウィンドウの操作(矢印キー、Enter、Esc)が壁紙ロジックに重複配信されるのを防ぐためです。deactivate() で通常通り再開します。

プラットフォーム要件

  • macOS: アプリ全体の activation を引き起こさない NSPanel.nonactivatingPanel)でプロキシを生成するため、Dock のハイライトやメニューバーは切り替わりません。
  • Windows: WS_EX_NOACTIVATE の不可視 HWND でプロキシを生成し、taskbar の点滅を起こさずにフォーカスを取り直します。

制限事項

  • 確定後の文字列のみ最終的に壁紙に渡るため、変換中の文字列を別途装飾する場合は composition を直接描画してください。
  • activate に渡す座標は viewport 相対 CSS ピクセルです。壁紙ウィンドウのスクリーン位置は backend 側で解決するため、window.screenX / window.screenY を加算しないでください。custom-scheme で動作する壁紙では WebKit の screenX / screenY の値が信頼できません。