ShowCaretとSetCaretPos関数の呼び出し順序変更依頼。

  1. こんにちは。日本語に慣れていないため翻訳ツールに頼りました。

    LinuxでWine経由でMeryを使用しています。

    Wineのデバッグメッセージを通じて、Meryでカーソルが移動するときの関数呼び出し順序を見ると、以下の順序で呼び出されていることがわかります。

    DestroyCaret
    CreateCaret
    ShowCaret
    SetCaretPos

    ここで、ShowCaretとSetCaretPosの順序を入れ替えることはできないでしょうか?

    WineではShowCaretとSetCaretPosを通じてIME候補ウィンドウの位置を指定する非標準機能があります。しかし、CreateCaret後のShowCaretは内部的に位置値が(0,0)であるため、続くSetCaretPosと衝突し、IME候補ウィンドウのちらつきや位置ジャンプなどの現象を引き起こします。

    Wineでは簡単にパッチを当てられますが、Wineアップストリームで受け入れられるようにするのは困難です。IME候補ウィンドウに関する他のパッチをアップストリームしようとしているのですが、このパッチが曖昧なため遅延しています。

    私の考えでは、ShowCaretとSetCaretPosの順序を交換しても動作に問題はないと思いますが、いかがでしょうか?

    優れたプログラムを公開していただき感謝しております。良い結果が得られることを願っております。

     |  bsjeon  |  返信
  2. ご愛用いただきありがとうございます。

    そして、Wine での詳しい検証とご提案もありがとうございます。

    まず最初にお伝えしておきたいのですが、Wine での動作はサポート対象外とさせていただいています。

    とはいえ、Wine 上の不具合でも、Windows 環境でも起こりうる問題については、こちらでもできる限り対応を検討しています。

    一方で、Wine 特有の挙動に合わせたカスタマイズは行わない方針です。どうかご理解ください。

    > ここで、ShowCaretとSetCaretPosの順序を入れ替えることはできないでしょうか?

    ご指摘のとおり、現在の Mery ではその順序で呼び出していました。

    Microsoft のドキュメントを確認したところ、CreateCaretSetCaretPosShowCaret の順で呼び出す例が示されていました。

    Windows でもその方が正しいようですので、この部分の修正は対応できそうです。

    そのうえで、私のほうでも Linux Mint + Wine の環境を用意して試してみました。

    ただ、「SetCaretPos を通じて IME 候補ウィンドウの位置を指定する非標準機能」という部分が、どういう仕組みを指しているのかが分かりませんでした。

    こちらの環境では、IME の候補ウィンドウはちらつきや位置のジャンプはなく、画面の左上あたりに固定表示されている状態です。

    また、HKEY_CURRENT_USER\Software\Wine\X11 DriverInputStyle を作成して overthespot に設定する方法も試してみたのですが、効果は確認できませんでした。

    もしよければ、その「非標準機能」を有効にする具体的な方法や、参考になるサイトなどがありましたら教えていただけないでしょうか。

    こちらでももう少し詳しく調べてみたいと思います。

     |  Kuro  |  返信
  3. ご回答ありがとうございます。対応可能とのこと、嬉しく思います。

    MeryはWineでかなり良く動作するプログラムの一つです。問題があるなら、それはWineの問題です。

    Windowsと同様に、IME候補ウィンドウをコンポジション文字列の近くに適切な位置に配置することが目標です。いくつかの異なるパッチがあり、Meryのためには追加のパッチが必要でした。現在、より一般的な形にできないか研究中です。

    非標準機能と表現したのは、WIN32に存在しない機能であることを意味していました。万が一、未公開のwin32 APIを指していると誤解されたなら、私の表現が不適切でした。

    SetCaretPos を通じて IME 候補ウィンドウの位置を指定する非標準機能:

    dlls/win32u/input.c:
    NtUserSetCaretPos, NtUserShowCaret, and set_ime_composition_rect

    dlls/winex11.drv/xim.c:
    X11DRV_SetIMECompositionRect

    dlls/winewayland.drv/wayland_test_input.c:
    WAYLAND_SetIMECompositionRect

    dlls/winemac.drv/event.c:
    macdrv_SetIMECompositionRect

    改めてご回答ありがとうございます。Meryの今後のご発展をお祈り申し上げます。

     |  bsjeon  |  返信
  4. 追伸:念のため申し上げますが、私の考えではこの機能は全く参考になる価値がありません。いくつかの問題が解決されれば削除すべきコードです。

     |  bsjeon  |  返信
  5. ご返信ありがとうございます。

    > 非標準機能と表現したのは、WIN32に存在しない機能であることを意味していました。万が一、未公開のwin32 APIを指していると誤解されたなら、私の表現が不適切でした。

    Win32 に存在しない機能を指しているという点は理解していました。

    ただ、私の環境では IME ウィンドウの位置がずれる現象を確認できなかったため、どのような手順で再現できるのか知りたいと思った次第です。

    > dlls/win32u/input.c:
    > NtUserSetCaretPos, NtUserShowCaret, and set_ime_composition_rect

    情報ありがとうございます。

    wine-10.18 のソースコードで該当箇所を確認したところ、どうやら前回、検証で使用していた Wine が少し古く、上記の修正がまだ適用されていなかったようです。

    改めて wine-10.18 で検証したところ、確かに IME ウィンドウをキャレットの近くに表示する機能が実装されており、前回は動作しなかった InputStyleoverthespot も有効になりました。

    サクラエディタさんでは IME ウィンドウがキャレット位置に正しく追従しましたが、Mery ではウィンドウの左上付近で固定されてしまいますね。

    ご提案いただいたとおり、Mery 側で ShowCaretSetCaretPos の呼び出し順を入れ替えて検証しましたが、残念ながら IME ウィンドウの位置や挙動には変化がありませんでした。

    調べたところ、原因は ShowCaretSetCaretPos の順序ではなく、ImmSetCompositionWindow の呼び出しにあるようです。

    具体的には、Mery のエディターエンジン TNotePad の該当部分 (NotePadView.pas より抜粋) は以下のとおりです。

      H := ImmGetContext(Handle);
      if H <> 0 then begin
        //チラつくのでptCurrentPosだけは変更時対処
        CForm.dwStyle := CFS_POINT;
        ImmGetCompositionWindow(H, @CForm);
        if (CForm.ptCurrentPos.X <> CX) or (CForm.ptCurrentPos.Y <> CY) then begin
          CForm.ptCurrentPos.X := CX;
          CForm.ptCurrentPos.Y := CY;
          ImmSetCompositionWindow(H, @CForm);
        end;
        CForm.dwStyle := CFS_RECT;
        CForm.rcArea.Left := FLeftBarWidth + 6 - 1;
        CForm.rcArea.Top := 0;
        CForm.rcArea.Bottom := ClientHeight;
        CForm.rcArea.Right := Max(0, ClientWidth - FFontWidth);
        ImmSetCompositionWindow(H, @CForm);
    

    【参考】http://mana.ikuto.com/

    このように、CFS_POINT に続けて CFS_RECT を指定して IME ウィンドウの領域を設定しています。

    どうやら、この CFS_RECT の指定があると、Wine では IME ウィンドウの位置が正しく反映されないようです。

    ちなみに、サクラエディタさんでは CFS_POINT のみを使用しており、CFS_RECT の指定はありませんでした。

    Mery でも CFS_RECT の指定を外すと、サクラエディタさんと同じようにキャレット位置に IME ウィンドウが表示されるようになりました。(ShowCaretSetCaretPos の順序はどちらでも問題ありませんでした)

    Wine 向けに CFS_RECT の指定を除外する条件分岐を入れる方法も考えられますが、Mery としては Wine 専用の特別な処理は極力入れたくないので、対応をどうするか悩ましいところです。

     |  Kuro  |  返信
  6. はい、その通りです。その部分について、現在のWineはCForm.rcAreaを誤って解釈しています。私のパッチにはその部分の修正も含まれています。

    また、on-the-spot input styleでも動作するようにパッチを適用する予定です。

    後日、パッチがupstreamに受け入れられた場合は、別途お知らせいたします。

     |  bsjeon  |  返信
  7. なるほど、状況は分かりました。

    Wine における rcArea の解釈が修正されれば、Mery でも IME ウィンドウの位置が正しく表示されるようになる、ということですね。

    そのためには、修正パッチを upstream に受け入れてもらう必要がありますが、現時点では少し時間がかかっている状況なのですね。

    また、Mery 側で ShowCaretSetCaretPos の呼び出し順を変更しておくことで、修正パッチの動作がより安定し、upstream に採用される可能性も高まる、という理解で合っていますでしょうか。

    Mery としては、Wine 向けの特別な対応にはなりますが、条件分岐などで Wine 専用の処理を入れるわけではないので、対応可能な範囲だと思います。

    Windows 10 のサポートも終了しましたし、今後は Windows 11 にアップデートできない PC を Linux + Wine で活用する方も増えそうですよね。

    そんな環境で Mery が正しく動作するようになるのは、私としてもうれしい限りです。

    わかりました。こちらとしても、できる範囲で協力させていただきます。

    次のバージョン (Ver 3.8.0) では、ShowCaretSetCaretPos の呼び出し順の変更を反映しておきますね。

    次のバージョンは今月中のリリースを予定しています。

    > 後日、パッチがupstreamに受け入れられた場合は、別途お知らせいたします。

    楽しみにお待ちしております。

     |  Kuro  |  返信
  8. > また、Mery 側で `ShowCaret` と `SetCaretPos` の呼び出し順を変更しておくことで、修正パッチの動作がより安定し、upstream に採用される可能性も高まる、という理解で合っていますでしょうか。
    >

    はい。そうです。

     |  bsjeon  |  返信
スポンサーリンク