Forma elegante de manejar la entrada de teclado en JavaFX

Actualmente estoy trabajando en una calculadora en JavaFX y en este momento estoy tratando de implementar el soporte de entrada de teclado.

Para esto, estoy tratando de implementar un EventHandler en el archivo .java principal como este:

@Override
public void start(Stage stage) throws Exception {
    Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));

    Scene scene_main = new Scene(root);

    stage.setScene(scene_main);
    stage.show();

    scene_main.setOnKeyPressed(new EventHandler<KeyEvent>() {
        @Override
        public void handle(KeyEvent keyEvent) {

            switch (keyEvent.getCode()) {
                case ENTER:
                    System.out.println("Enter");
                    break;
                case ADD:
                    System.out.println("Plus");
                    break;
                case SUBTRACT:
                    System.out.println("Minus");
                    break;
                case DIVIDE:
                    System.out.println("Division");
                    break;
                case MULTIPLY:
                    System.out.println("Multiply");
                    break;

            }
        }
    }
    );
}

El FXMLDocumentController.java:

import java.net.URL;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.NumberFormat;
import java.util.Locale;
import java.util.Random;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.stage.Stage;

/**
 *
 * @author ilja
 */
public class FXMLDocumentController implements Initializable {

@FXML
private void handleTestAction(ActionEvent event) throws Exception {
    ((Node) (event.getSource())).getScene().getWindow().hide();
    Parent parent = FXMLLoader.load(getClass().getResource("/calculator/CrashPopup.fxml"));
    Stage stage = new Stage();
    Scene scene = new Scene(parent);
    stage.setScene(scene);
    stage.setTitle("Teeeeest");
    stage.show();
}

private enum State {

    EQUALED, FIRST, SECOND, OPERATOR
}

public static String operator = "+";
private double oldValue = 0;
private double newValue = 0;
private double result = 0;
private String oldText, newText;
private String digit;
private boolean equaled = false;
Random r = new Random();
int i1;

private State state = State.EQUALED;

NumberFormat nf = new DecimalFormat("##.###", new DecimalFormatSymbols(Locale.US));

@FXML
private TextField displayField;

@Override
public void initialize(URL url, ResourceBundle rb) {
    // TODO
    displayField.setText("0");
}

@FXML
private void handleDotAction(ActionEvent event) {

    double result;

    oldText = displayField.getText();

    if (!oldText.isEmpty() && !oldText.contains(".")) {
        newText = oldText + ".";
    } else {
        newText = oldText;
    }

    displayField.setText(newText);
    result = Double.parseDouble(newText);

    if (state == State.EQUALED || state == State.FIRST) {
        oldValue = result;
        state = State.FIRST;
    } else {
        newValue = result;
        state = State.SECOND;
    }
}

@FXML
private void handleDigitAction(ActionEvent event) {

    digit = ((Button) event.getSource()).getText();
    if (state == State.FIRST || state == State.SECOND) {
        oldText = displayField.getText();
    } else {
        oldText = "";
    }

    if ("0".equals(oldText) /*|| "0.0".equals(oldText)*/) {
        displayField.setText(digit);
    } else {
        displayField.setText(oldText + digit);
    }

    if (state == State.EQUALED || state == State.FIRST) {
        oldValue = Double.parseDouble(displayField.getText());
        state = State.FIRST;
    } else {
        newValue = Double.parseDouble(displayField.getText());
        state = State.SECOND;
    }
}

@FXML
private void handleOperator(ActionEvent event) {

    if (state == State.EQUALED) {
        operator = ((Button) event.getSource()).getText();
    }

    if (state == State.SECOND) {
        switch (operator) {
            case "+":
                oldValue += newValue;
                break;
            case "-":
                oldValue -= newValue;
                break;
            case "*":
                oldValue *= newValue;
                break;
            case "/":
                oldValue /= newValue;
                break;
            default:
                break;
        }
        result = oldValue;
        newValue = 0;
        displayField.setText(String.valueOf(nf.format(oldValue)));
    }

    operator = ((Button) event.getSource()).getText();
    state = State.OPERATOR;
}

@FXML
private void handleEqualAction(ActionEvent event) throws Exception{

    i1 = r.nextInt(6 - 0) + 0;

    if (i1 == 1) {
        ((Node) (event.getSource())).getScene().getWindow().hide();
        Parent parent = FXMLLoader.load(getClass().getResource("/calculator/CrashPopup.fxml"));
        Stage stage = new Stage();
        Scene scene = new Scene(parent);
        stage.setScene(scene);
        stage.setTitle("Unerwarteter Fehler");
        stage.show();
    }

    switch (operator) {
        case "+":
            oldValue += newValue;
            break;
        case "-":
            oldValue -= newValue;
            break;
        case "*":
            oldValue *= newValue;
            break;
        case "/":
            oldValue /= newValue;
            break;
        default:
            break;
    }
    result = oldValue;
    displayField.setText(String.valueOf(nf.format(oldValue)));

    state = State.EQUALED;

}

@FXML
private void handleClearAction(ActionEvent event) {
    displayField.setText("0");
    oldValue = 0;
    newValue = 0;
    operator = "+";
    state = State.EQUALED;
}

@FXML
private void handleClearEntryAction(ActionEvent event) {
    displayField.setText("0");
    newValue = 0;
    switch (state) {
        case EQUALED:
            displayField.setText(String.valueOf(nf.format(result)));
            break;
        case FIRST:
            oldValue = 0;
            state = State.EQUALED;
            break;
        case SECOND:
        case OPERATOR:
            newValue = 0;
            state = State.OPERATOR;
            break;
        default:
            break;
    }
}

private void handleZeroAction(ActionEvent event) {
    digit = ((Button) event.getSource()).getText();
    oldText = displayField.getText();
    if ("0".equals(oldText) || "0.0".equals(oldText)) {
        newText = oldText;
    } else {
        newText = oldText + digit;
    }
    displayField.setText(newText);
}
}

Ahora el problema es que cada vez que se presionan esas teclas, deben ocurrir las mismas cosas que cuando hago clic en los botones correspondientes en la GUI.

Todos los botones de dígitos comparten un evento onAction y +, -, /, * también comparten uno, etc. Todos usan variables en el archivo FXMLDocumentController.java.

Así que no estoy seguro de cuál es la mejor manera de manejar esto. ¿Puedo invocar los eventos onAction desde el archivo main.java o debo copiar y pegar (lo que causaría redundancia) el contenido del método en este archivo y hacer que las variables sean públicas / protegidas?

Intenté invocar los métodos desde el archivo principal pero fallé porque no entiendo qué parámetros obtendrá el método, ya que requieren un objeto ActionEvent.

Respuestas a la pregunta(1)

Su respuesta a la pregunta