見出し画像

monaco editor(VS CODEの中のエディタ)のIME不具合を直す

先日ベータ版をリリースしたマークダウンエディタ simple MD

一応ベータ版ができて友人に使ってもらっていたんだけど
バグを発見したということで詳しく聞いてみると・・・

monaco editorの不具合っぽい。
試しに今使っているVS CODEでも再現できるか試したところがっつり再現。

確認したーバージョンは以下の通りです。
VS CODE: 1.107.1
monaco editor: 0.55.1

内容はこうです。
IMEで日本語入力時変換候補がない状態かつ未確定の場合にカーソルキーを押すと、入力項目がずれてしまい、本来の位置とは別に移動した位置にも上書きで文字が入力されてしまう不具合です。


画像
「ちきゅうおんだんか」と入力します


画像
ESCを押して変換候補を消します。この状態で・・・


画像
カーソルの「↑」をおすと変換中の文字列が移動し、エンターキーを押すとその位置に上書きで確定してしまう。(元の位置も入力される)

ということでライブラリ側で直すのが正しいとは思いますが、いつ修正がはいるかわからないので
アプリ側で直せるかどうか色々調べてみました。

  • monaco editorにIMEでの入力の開始、終了のイベントはある(onDidCompositionStart,onDidCompositionEnd)

  • IME入力中(未確定の文字)は取得できない(=文字列の長さも取得できない)

  • IME入力中(変換候補でてきる間)はキーイベントも取れない(monaco editor側の)

  • カーソル位置はとれるっぽいがIME変換中かどうか判断できない

  • カーソル移動のイベントは取れるがどのキーで移動したかまではわからない

  • document側のIMEイベントもうまく取れない


はい。はっきりいってかなり詰んでます。


が、行の文字列は変換中の文字列も含んで取れるのでここからどうにかできないか考えたのが以下の方法です。

  1. IME入力前のカーソル位置を取得しておく

  2. IMEの入力が始まったらその行の文字数の長さを取得

  3. IME入力中の行の文字列の長さを取得して2との差で文字列の長さを取得

  4. 3の長さからIMEの入力中の終点のカーソル位置を割り出す

  5. IMEカーソルの始点・終点のカーソル範囲から移動しようとしたら元の位置にカーソルを戻す

以上で(一応ですが)対応できました。

simple MDのソースの一部を抜粋

//typescript

editor = monaco.editor.create(this.#containerElement, this.#options);
this.#session = monaco.editor.createModel(this.#textContent ,this.#language);
editor.setModel(this.#session);


//IME入力開始のイベント
editor.onDidCompositionStart(() => {
    //IMEの入力中かのフラグ
    isComposing = true;
    //文字列の長さの取得
    this.#isCommingStartLineLength =  
         this.#session.getLineMaxColumn(editor.getPosition()?.lineNumber || 1);
    //IME入力開始のカーソル位置取得
    preeditStartPos= this.#beforePosition?.clone() || null; 
    //前回のカーソル位置保存
    this.#isComminBeforePosition = this.#beforePosition?.clone() || null;
});

// カーソル位置が変更されたときのイベント
editor.onDidChangeCursorPosition((event) => {

    preeditStartPos = preeditStartPos as monaco.Position;

    let isRangeOutside = false;
    if(isComposing){
        //1行の文字列を取得
        const lineMaxColumn = this.#session.getLineMaxColumn(event.position.lineNumber);
        const rageCheckPos  = {
            lineNumber: event.position.lineNumber,
            column: preeditStartPos.column + (lineMaxColumn - this.#isCommingStartLineLength!)
            
        };
            
        //範囲外かどうかの判定
        if(preeditStartPos.lineNumber !== rageCheckPos.lineNumber){
            isRangeOutside = true;
        }else if(preeditStartPos.column > event.position.column || event.position.column > rageCheckPos?.column){
            isRangeOutside = true;
        }

        if(isRangeOutside){
            //範囲外にでたら1つ前のカーソル位置に戻す
            editor.setPosition({
                    lineNumber: preeditStartPos.lineNumber,
                    column: this.#isComminBeforePosition!.column
                  });
        }
    }


    //前回のカーソル位置(IME入力中の)を取得する
    this.#beforePosition = event.position.clone();
    if(isComposing){
        if(!isRangeOutside) this.#isComminBeforePosition = event.position.clone();
    }
});


とうかこのあたりのバグはIME使う言語の人たちしか気づかないよな~

いいなと思ったら応援しよう!

コメント

コメントするには、 ログイン または 会員登録 をお願いします。
SE?プログラマ? 上流~下流までバックサイド&フロントと行ったり来たりどっちつかずの仕事してます。 アプリは半分趣味の半分仕事用。
monaco editor(VS CODEの中のエディタ)のIME不具合を直す|yodamasa
word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word word

mmMwWLliI0fiflO&1
mmMwWLliI0fiflO&1
mmMwWLliI0fiflO&1
mmMwWLliI0fiflO&1
mmMwWLliI0fiflO&1
mmMwWLliI0fiflO&1
mmMwWLliI0fiflO&1