LoginSignup
0
0

More than 5 years have passed since last update.

JavaFXにAceを埋め込んだらMacのJapaneseIMがバグったので解消した

Last updated at Posted at 2019-02-24

現在、勉強がてらJavaFxでAsciiDocエディタを製作中です。エディタ部分にJavaScript製のAceを採用しましたが、タイトル通り挙動がおかしくなってしまいました。

なにが起こったか

環境

  • macOS Mojave 10.14.3
  • Intellij IDEA 2018.3.4
  • JavaFX 11
$ java -version
openjdk version "11.0.1" 2018-10-16
OpenJDK Runtime Environment 18.9 (build 11.0.1+13)
OpenJDK 64-Bit Server VM 18.9 (build 11.0.1+13, mixed mode)

そして起こったのがこちら

見ての通り変換して確定すると改行されてしまいます。しかもこの後は日本語入力すらできない...
じゃあGoogle 日本語入力を使ってみよう!

えぇ...
こちらはスペースキーで変換する場合にはいいのですが、方向キーで変換候補を選択してしまうとJapeneseIMと同様日本語が打てなくなります。

コントローラクラスとWebviewがロードするHTMLのソースはこちら

ace.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>Ace Editor</title>
    <style type="text/css" media="screen">
        #editor {
            position: absolute;
            top: 0;
            right: 0;
            bottom: 0;
            left: 0;
        }
    </style>
</head>
<body>
<div id="editor"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.4.2/ace.js" type="text/javascript" charset="utf-8"></script>
<script>
    var editor = ace.edit("editor");
    editor.setTheme("ace/theme/monokai");
</script>
</body>
</html>
SampleController.java
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.web.WebView;

import java.net.URL;
import java.util.ResourceBundle;

public class SampleController implements Initializable {

    @FXML
    WebView aceEditor;

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        aceEditor.getEngine().setJavaScriptEnabled(true);
        aceEditor.getEngine().load(getClass().getResource("/ace.html").toExternalForm());
    }
}

ちなみに、Aceはemacsやvimのキーバインドを用意してくれていて

editor.setKeyboardHandler("ace/keyboard/emacs");

とすれば変えられるのですが、これを使っても少し挙動が変わるだけで実用は無理でした。
加えて、僕はJavaScriptが書けないのでJavaScript側でどうにかするのは諦めました。:innocent:

上記のHTMLをブラウザで見た場合、chrome、safariでは良かったものの、firefoxではうまく動きませんでした(日本語入力ができなくなることはなかった)。JavaFXだけではなくAceの問題もあるのかもしれません。

解決策

じゃあどうしたかというと、IME使用中はJavaFXのKeyEventを無効化しました。

public class SampleController implements Initializable {

    @FXML
    WebView aceEditor;

    private boolean isComposing;

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        aceEditor.getEngine().setJavaScriptEnabled(true);
        aceEditor.getEngine().load(getClass().getResource("/ace.html").toExternalForm());

        aceEditor.addEventFilter(InputMethodEvent.ANY, new EventHandler<InputMethodEvent>() {
            @Override
            public void handle(InputMethodEvent event) {
                isComposing = !(event.getComposed().size() == 0);
            }
        });

        aceEditor.addEventFilter(KeyEvent.ANY, new EventHandler<KeyEvent>() {
            @Override
            public void handle(KeyEvent event) {
                if (isComposing) event.consume();
            }
        });
    }
}

JavaFXのイベント処理の流れはググればいっぱい分かりやすい記事がでできますので割愛させていただきます。

KeyEventにはKEY_PRESSEDKEY_RELEASEDKEY_TYPEDがあります。これらの発生する順番は

KEY_PRESSED -> KEY_TYPED -> KEY_RELEASED

なのですがInputMethodEvent中は基本的にKEY_RELEASEDしか発火しません。
しかし特定のキー(方向キーやshiftキーなど)に限ってはKEY_PRESSEDKEY_TYPEDが発火します。そんなわけで最初のGIFのような動作になっていたのでした。

InputMethodEventgetComposedメソッドはObservableListを返してくれるので、sizeメソッドを使えばIME使用中か否かを判断できます。これで動きます:thumbsup:

改良後

まとめ

Aceは日本語対応が微妙と評判?でしたがなんとかJavaFXで実用できるようになりました。
Aceを使っているJavaFX製AsciiDocエディタAsciidocFXも僕の環境では最初のGIFと同じように動いてしまって困っていました。ちなみにParalles DesktopのWindows 10上でAsciidocFXを動かしても不具合はなかったので、Macだけだと思います。修正したコードがWindowsでどうなるのかはわかりません。

もしかしたらAceやJavaFXのAPIを見落としているのかもしれません。「もっと良い実装があるよ!」、「Aceの使い方間違ってるよ!」という場合はぜひコメントで教えていただけると嬉しいです。

(製作中のAsciiDocエディタも形になったらまた投稿したいと思います)

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0