Open15

Ubuntu 24.04 LTS で変換対象がハイライトされない問題の対策

にしにし

原因

waylandの文字入力用プロトコルであるtext-input-v3が入力中の文字列(preeditと呼ばれる)のスタイリングに対応していない。waylandのリポジトリにスタイリングを実現するMRが存在するが、作業中のようでマージされるのは当分先だと思われる。

にしにし

対策1:fcitx5を使う

fcitx5-mozcを使うと変換対象の文字列がハイライトされる。

設定方法

  1. sudo apt install fcitx5-mozc
  2. 言語サポートアプリで「キーボード入力に使うIMシステム」を「Fcitx 5」に設定する。

理由

IMシステムをfcitx5に設定すると以下の環境変数が設定される。

XIM=fcitx
XIM_PROGRAM=/usr/bin/fcitx
XIM_ARGS=""
GTK_IM_MODULE=fcitx
QT_IM_MODULE=fcitx
DEPENDS="fcitx"

設定ファイルは/etc/X11/xinit/xinput.d/fcitxに配置されている。

これらの環境変数に対応するアプリではWaylandを介さず、直接アプリとIMシステムが通信しているのではないか?

にしにし

対策2:GNOME Extensionで変換対象の文字列をポップアップさせる(未実装)

GNOME Extensionの中にはibusの見た目や動作を変更するものがある。そうすると、文節区切りの変更時に変換対象の文字列をポップアップさせることができる可能性がある。勉強がてら実装するかもしれない。

この拡張機能を実装する方法について、思いつく二つの方法

  • 何とかしてibusからpreeditを取得する
  • mozcのunix domain socketを読み取って表示する
にしにし

mozc -> ibus に送信されるプレエディットの情報から変換対象を抽出できた。Looking Glassで実行するとgnome shellのログに表示される。

bhpocid = Main.inputMethod._context.connect("update-preedit-text-with-mode", (_con,text,pos,v,mode) => {
  let text_str = text.get_text();
  let attr_list = text.get_attributes();
  let a;
  for (let i=0; (a=attr_list.get(i)); ++i) {
      console.log("Bunsetu:",text_str, a.get_start_index(), a.get_end_index(), v);
  }
});

ログ確認コマンド

journalctl _COMM=gnome-shell --since "yyyy-m-dd"
にしにし

どういう条件でどんな装飾がつくのか調査するためのコード

function attrtype(type) {
  switch(type) {
    case 1:
      return "UNDERLINE ";
    case 2:
      return "FOREGROUND";
    case 3:
      return "BACKGROUND";
    default:
      return `UNKOWN ${type}`;
  }
}

let bhcontext = Main.inputMethod._context;
bhpocid = bhcontext.connect("update-preedit-text-with-mode", (_con,text,pos,v,mode) => {
  let text_str = text.get_text();
  let text_with_cursor = text_str.slice(0,pos)+"|"+text_str.slice(pos,-1);
  let attr_list = text.get_attributes();
  let a;
  console.log(`Bunsetu: "${text_with_cursor}" visible=${v} mode=${mode}`);
  for (let i=0; (a=attr_list.get(i)); ++i) {
      let start = a.get_start_index();
      let end = a.get_end_index();
      console.log(`Bunsetu:     [*] attr_type=${attrtype(a.get_attr_type())} value=${a.get_value()} start=${start} end=${end} "${text_str.slice(start, end)}"`);
  }
  if (bhcontext != Main.inputMethod._context) {
    console.log("LOST CONNECTION! NEED RELOAD.");
  }
});
console.log("Bunsetu ID:", bhpocid);
にしにし

BoxPointer.BoxPointerについて

resource:///org/gnome/shell/ui/boxpointer.jsBoxPointerは四角い吹き出しを表示するためのもの
BoxPointer.setPosition()で吹き出しの指す先を指定する。

片付けるときはboxpointer.destroy()でよさげ。gnome extensionのdisable()にこれを書いていなかったときはポップアップが残っていたが、書くと消えるようになった。おそらく親クラスのdestroy()が効いている。

https://github.com/wengxt/gnome-shell-extension-kimpanel

ではそうしていた。

また、setPositionの引数にするウィジェットもdestroy()していた。

にしにし

InjectionManagerは使わない方針

https://gjs.guide/extensions/topics/extension.html

InjectionManagerは既存のクラスを変更するという便利なクラス。prototypeを書き換えることで動作を変更するといったもので、理屈はわかる。しかし、サンプルが期待通りに動かない。(GUIでカレンダーや設定をトグルした際にログが出ることを期待した。しかし、実際はGUIからの操作ではログは出ず、lookingGlassから関数を呼び出したときのみログが出た。つまり書き換え自体は成功しているにも関わらず、GUIからの操作には影響がないことになる。)

ややこしいのと、ibusCandidatePopupではうまく使えなさそうな気がするのでこれは使わないことにした。

にしにし

mozcの場合、変換候補選択中のカーソル位置は|の位置にある。

確定文字列 | 変換中の文字列 みへんかんもじれつ

そのため、変換中の文字列の長さが変わってもカーソル位置の値は変化しない。

にしにし

https://zenn.dev/nishi/articles/why-preedit-styles-do-not-work-on-gnome-wayland

記事を書いたが、Waylandに対する誤解が含まれていた。当初、text-input-v3が考え出されたタイミングではハイライトはcursor, anchorの間につければ良いと考えられていたようだ。何も全く考えがなかったわけではないようなのだ。GNOMEの場合ibusがanchor二相当するものを提供しないがためにその考えが機能しなかっただけのようだ。
詳しくはこのIssueを見よ。

https://gitlab.gnome.org/GNOME/gnome-shell/-/issues/7742