Как исправить греческие акцентированные символы в TextField

Проблема, с которой я сталкиваюсь, заключается в том, что когда у меня есть ввод (TextField, TextArea и т.д.), И я пытаюсь вставить некоторые греческие слова, содержащие символы с ударением. Такие слова, как "Γάτα" (кошка) работает отлично. К сожалению, я не могу печатать такие слова, как "Ταϊτή" (Таити). Если я пытаюсь скопировать и вставить его или жестко запрограммировать, он работает нормально, но когда я пытаюсь написать слово, используя комбинацию

Shift + ';' + ι

который должен производить 'ϊ', вместо этого я получаю '¨ι'

Вот пример:

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.TextField;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class Example extends Application {

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage stage) throws Exception {

        VBox mainBox = new VBox(10);
        mainBox.setPadding(new Insets(20));
        mainBox.setAlignment(Pos.CENTER);

        // Ταϊτή = Tahiti
        TextField field1 = new TextField("Ταϊτή");
        TextField field2 = new TextField();

        mainBox.getChildren().add(field1);
        mainBox.getChildren().add(field2);

        field1.setStyle("-fx-font-size:24px");
        field2.setStyle("-fx-font-size:24px");

        stage.setScene(new Scene(mainBox));
        stage.show();
    }
}

А на рисунке ниже показано, что я получаю в результате, когда я сам набираю слово

enter image description here

Установленная JRE: jre1.8.0_221

Установленный JDK: jdk1.8.0_221

Чтобы исключить IDE (Eclipse) как причину проблемы, я протестировал это поведение на SceneBuilder с помощью только AnchorPane и TextField, и у меня там была та же проблема. Но ради аргумента, у меня есть редактор и все настройки в Eclipse для использования кодировки UTF-8.

Поэтому я хотел бы спросить: является ли это ошибкой текущего JRE/JDK и, если да, есть ли известное решение, которое я мог бы использовать, или мне просто нужно использовать Listener, чтобы перехватить ввод и исправить его самостоятельно?

Редактировать: Как указывает Седрик, я мог бы использовать комбинацию alt + 0 2 3 9, но это приведет к другому типу буквы, которая похожа на греческую, но не идентична. Посмотрите изображение ниже. К сожалению, это не то поведение, которое хочет мой клиент, потому что правильный способ его ввода (на греческих клавиатурах) - с помощью: Shift + ';' + ι, где "ι" - английская буква "i".

enter image description here

Редактировать 2: Также я мог бы обойти это, используя приведенный ниже код, но если я решил сделать это, я должен сделать это для всех моих текстовых полей, чего я хотел бы избежать. В противном случае я должен создать "фиктивный" класс CustomTextField, который расширит TextField и осуществит там взлом, а затем я мог бы заменить все ссылки TextField в моем проекте на CustomTextField.

field2.setTextFormatter(new TextFormatter<>(c -> {
    String text = c.getControlNewText();

    if (text.contains("¨ι") || text.contains("¨Ι")) { 

        // In order to "catch" a word with multiple wrong characters
        // for example if someone tries to copy/paste, I will use
        // the replaceAll() method
        text = text.replaceAll("¨ι", "ϊ");
        text = text.replaceAll("¨Ι", "Ϊ"); 

        // update the field 
        field2.setText(text);

        // correct the caret and anchor positions
        c.setCaretPosition(c.getCaretPosition() - 1);
        c.setAnchor(c.getCaretPosition());

        c.setText(""); // consume change because we already update it
    }
    return c;
}));

Ответы

Ответ 1

Я могу воспроизвести поведение. Если вы добавите EventHandler на сцену, вы сможете ясно увидеть проблему.

stage.addEventFilter(KeyEvent.KEY_TYPED, ev -> {
    System.out.println("Key typed: " + ev.getCharacter());
});

Выход:

Key typed: ¨
Key typed: Ι
Key typed: ¨
Key typed: ι

Существует решенный тикет, описывающий эту проблему. Если это проблема Glass Windowing Toolkit, мы ничего не можем с этим поделать, но сообщаем об ошибке.

Я не знаю, сможете ли вы поймать набранные ключи до отправки этих KeyEvents, но вы можете отфильтровать их на уровне стадии.

stage.addEventFilter(KeyEvent.KEY_TYPED, new KeyTypedListener());

Это не очень хороший, но более "глобальный" способ изменить поведение.

public class KeyTypedListener implements EventHandler<KeyEvent> {

    private boolean disabled = false;
    private Map<String, String> charCombinations = new HashMap<>();
    private KeyEvent pendingEvent;

    public KeyTypedListener() {
        charCombinations.put("¨ι", "ϊ");
        charCombinations.put("¨Ι", "Ϊ");
    }

    @Override
    public void handle(final KeyEvent event) {

        if (disabled || event.getCharacter() == null
                || event.getCharacter().length() != 1) {
            return;
        }

        final String typed = event.getCharacter();

        if (pendingEvent == null && isCombiCharacter(typed)) {
            pendingEvent = event.copyFor(event.getSource(), event.getTarget());
            event.consume();

        } else if (pendingEvent != null) {
            String combination =
                    charCombinations.get(pendingEvent.getCharacter() + typed);

            if (combination == null) {
                disabled = true;
                fireEvent(pendingEvent);
                disabled = false;
                pendingEvent = null;
            } else {
                event.consume();
                pendingEvent = null;

                Platform.runLater(() -> {
                    fireEventWithCharacter(event, combination);
                });
            }
        }
    }

    private boolean isCombiCharacter(final String character) {
        return "¨".equals(character);
    }

    private void fireEvent(final KeyEvent event) {
        Event.fireEvent(event.getTarget(), event);
    }

    private void fireEventWithCharacter(final KeyEvent event,
            final String character) {
        fireEvent(new KeyEvent(event.getSource(), event.getTarget(),
                event.getEventType(), character, "", KeyCode.UNDEFINED,
                event.isShiftDown(), event.isControlDown(), event.isAltDown(),
                event.isMetaDown()));
    }
}

Конечно, вы также можете создать новый EventDispatcher.

Ответ 2

Я думаю, что это проблема с греческой клавиатурой. Я попытался использовать другие текстовые поля (панель поиска Opera, панель поиска Google и т.д.) И не смог написать этот символ. Вы можете написать это только комбинацией Alt + 0239. Вы можете попробовать создать комбинации с "field2.setOnKeyPressed()".