All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.mosip.registration.controller.VirtualKeyboard Maven / Gradle / Ivy

There is a newer version: 1.2.0.2
Show newest version
package io.mosip.registration.controller;

import static io.mosip.registration.constants.RegistrationConstants.APPLICATION_NAME;

import java.util.HashSet;
import java.util.Locale;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.Set;

import com.neovisionaries.i18n.LanguageAlpha3Code;

import io.mosip.kernel.core.logger.spi.Logger;
import io.mosip.registration.config.AppConfig;
import io.mosip.registration.constants.RegistrationConstants;
import io.mosip.registration.constants.VirtualKeyboardKeys;
import io.mosip.registration.controller.reg.RegistrationController;
import javafx.application.Platform;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.StringBinding;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ReadOnlyBooleanProperty;
import javafx.beans.property.ReadOnlyObjectProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableStringValue;
import javafx.beans.value.ObservableValue;
import javafx.event.ActionEvent;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.event.EventTarget;
import javafx.event.EventType;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.TextField;
import javafx.scene.control.ToggleButton;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.scene.shape.Polygon;
import javafx.stage.Stage;

public class VirtualKeyboard {

	/**
	 * Instance of {@link Logger}
	 */
	private static final Logger LOGGER = AppConfig.getLogger(RegistrationController.class);

	private static Set KEY_LENGTHS = new HashSet<>();

	private VBox root;

	private boolean capsLock;

	private StringBuilder vkType = new StringBuilder();

	private ResourceBundle keyboard = null;
	
	private KeyEvent keyEvent;

	private Stage parentStage;
	
	public VirtualKeyboard(String langCode) {
		this(null, langCode);
	}

	private String getKey(String keyCode) {
		return keyboard != null ? keyboard.getString(keyCode) : null;
	}
	
	public Stage getParentStage() {
		return parentStage;
	}
	
	public void setParentStage(Stage parentStage) {
		this.parentStage = parentStage;
	}

	/**
	 * Creates a Virtual Keyboard.
	 * 
	 * @param target The node that will receive KeyEvents from this keyboard. If
	 *               target is null, KeyEvents will be dynamically forwarded to the
	 *               focus owner in the Scene containing this keyboard.
	 * @param langCode 
	 */

	private VirtualKeyboard(ReadOnlyObjectProperty target, String langCode) {
		LOGGER.info(RegistrationConstants.REGISTRATION_CONTROLLER, APPLICATION_NAME,
				RegistrationConstants.APPLICATION_ID, "Opening virtual keyboard");

		String localeCode = LanguageAlpha3Code.getByCodeIgnoreCase(langCode) != null ? LanguageAlpha3Code.getByCodeIgnoreCase(langCode).getAlpha2().name() : null;
		Locale locale = new Locale(localeCode != null ? localeCode : langCode.substring(0, 2));
		
		this.keyboard = ResourceBundle.getBundle("keyboards.keyboard", locale);
		
		this.root = new VBox(5);
		root.setPadding(new Insets(10));
		root.setId("virtualKeyboard");
		final Modifiers modifiers = new Modifiers();
		KEY_LENGTHS.add(1);
		KEY_LENGTHS.add(2);
		String[][] unshifted = null;
		try {
			unshifted = new String[][] {
					{ getKey(VirtualKeyboardKeys.unshift_BackQuote), getKey(VirtualKeyboardKeys.unshift_One),
							getKey(VirtualKeyboardKeys.unshift_Two), getKey(VirtualKeyboardKeys.unshift_Three),
							getKey(VirtualKeyboardKeys.unshift_Four), getKey(VirtualKeyboardKeys.unshift_Five),
							getKey(VirtualKeyboardKeys.unshift_Six), getKey(VirtualKeyboardKeys.unshift_Seven),
							getKey(VirtualKeyboardKeys.unshift_Eight), getKey(VirtualKeyboardKeys.unshift_Nine),
							getKey(VirtualKeyboardKeys.unshift_Zero), getKey(VirtualKeyboardKeys.unshift_Minus),
							getKey(VirtualKeyboardKeys.unshift_Equals) },
					{ getKey(VirtualKeyboardKeys.unshift_Q), getKey(VirtualKeyboardKeys.unshift_W),
							getKey(VirtualKeyboardKeys.unshift_E), getKey(VirtualKeyboardKeys.unshift_R),
							getKey(VirtualKeyboardKeys.unshift_T), getKey(VirtualKeyboardKeys.unshift_Y),
							getKey(VirtualKeyboardKeys.unshift_U), getKey(VirtualKeyboardKeys.unshift_I),
							getKey(VirtualKeyboardKeys.unshift_O), getKey(VirtualKeyboardKeys.unshift_P),
							getKey(VirtualKeyboardKeys.unshift_OpenBracket),
							getKey(VirtualKeyboardKeys.unshift_CloseBracket),
							getKey(VirtualKeyboardKeys.unshift_BackSlash) },
					{ getKey(VirtualKeyboardKeys.unshift_A), getKey(VirtualKeyboardKeys.unshift_S),
							getKey(VirtualKeyboardKeys.unshift_D), getKey(VirtualKeyboardKeys.unshift_F),
							getKey(VirtualKeyboardKeys.unshift_G), getKey(VirtualKeyboardKeys.unshift_H),
							getKey(VirtualKeyboardKeys.unshift_J), getKey(VirtualKeyboardKeys.unshift_K),
							getKey(VirtualKeyboardKeys.unshift_L), getKey(VirtualKeyboardKeys.unshift_SemiColon),
							getKey(VirtualKeyboardKeys.unshift_Quote) },
					{ getKey(VirtualKeyboardKeys.unshift_Z), getKey(VirtualKeyboardKeys.unshift_X),
							getKey(VirtualKeyboardKeys.unshift_C), getKey(VirtualKeyboardKeys.unshift_V),
							getKey(VirtualKeyboardKeys.unshift_B), getKey(VirtualKeyboardKeys.unshift_N),
							getKey(VirtualKeyboardKeys.unshift_M), getKey(VirtualKeyboardKeys.unshift_Comma),
							getKey(VirtualKeyboardKeys.unshift_Period), getKey(VirtualKeyboardKeys.unshift_Slash) } };
		} catch (MissingResourceException exception) {
			LOGGER.error("Virtual Keyboard", APPLICATION_NAME, RegistrationConstants.APPLICATION_ID,
					exception.getMessage());
		}
		String[][] shifted = null;
		try {
			shifted = new String[][] {
					{ getKey(VirtualKeyboardKeys.shift_BackQuote), getKey(VirtualKeyboardKeys.shift_One),
							getKey(VirtualKeyboardKeys.shift_Two), getKey(VirtualKeyboardKeys.shift_Three),
							getKey(VirtualKeyboardKeys.shift_Four), getKey(VirtualKeyboardKeys.shift_Five),
							getKey(VirtualKeyboardKeys.shift_Six), getKey(VirtualKeyboardKeys.shift_Seven),
							getKey(VirtualKeyboardKeys.shift_Eight), getKey(VirtualKeyboardKeys.shift_Nine),
							getKey(VirtualKeyboardKeys.shift_Zero), getKey(VirtualKeyboardKeys.shift_Minus),
							getKey(VirtualKeyboardKeys.shift_Equals) },
					{ getKey(VirtualKeyboardKeys.shift_Q), getKey(VirtualKeyboardKeys.shift_W),
							getKey(VirtualKeyboardKeys.shift_E), getKey(VirtualKeyboardKeys.shift_R),
							getKey(VirtualKeyboardKeys.shift_T), getKey(VirtualKeyboardKeys.shift_Y),
							getKey(VirtualKeyboardKeys.shift_U), getKey(VirtualKeyboardKeys.shift_I),
							getKey(VirtualKeyboardKeys.shift_O), getKey(VirtualKeyboardKeys.shift_P),
							getKey(VirtualKeyboardKeys.shift_OpenBracket),
							getKey(VirtualKeyboardKeys.shift_CloseBracket),
							getKey(VirtualKeyboardKeys.shift_BackSlash) },
					{ getKey(VirtualKeyboardKeys.shift_A), getKey(VirtualKeyboardKeys.shift_S),
							getKey(VirtualKeyboardKeys.shift_D), getKey(VirtualKeyboardKeys.shift_F),
							getKey(VirtualKeyboardKeys.shift_G), getKey(VirtualKeyboardKeys.shift_H),
							getKey(VirtualKeyboardKeys.shift_J), getKey(VirtualKeyboardKeys.shift_K),
							getKey(VirtualKeyboardKeys.shift_L), getKey(VirtualKeyboardKeys.shift_SemiColon),
							getKey(VirtualKeyboardKeys.shift_Quote) },
					{ getKey(VirtualKeyboardKeys.shift_Z), getKey(VirtualKeyboardKeys.shift_X),
							getKey(VirtualKeyboardKeys.shift_C), getKey(VirtualKeyboardKeys.shift_V),
							getKey(VirtualKeyboardKeys.shift_B), getKey(VirtualKeyboardKeys.shift_N),
							getKey(VirtualKeyboardKeys.shift_M), getKey(VirtualKeyboardKeys.shift_Comma),
							getKey(VirtualKeyboardKeys.shift_Period), getKey(VirtualKeyboardKeys.shift_Slash) } };
		} catch (MissingResourceException exception) {
			LOGGER.error("Virtual Keyboard", APPLICATION_NAME, RegistrationConstants.APPLICATION_ID,
					exception.getMessage());
		}

		final KeyCode[][] codes = new KeyCode[][] {
				{ KeyCode.BACK_QUOTE, KeyCode.DIGIT1, KeyCode.DIGIT2, KeyCode.DIGIT3, KeyCode.DIGIT4, KeyCode.DIGIT5,
						KeyCode.DIGIT6, KeyCode.DIGIT7, KeyCode.DIGIT8, KeyCode.DIGIT9, KeyCode.DIGIT0,
						KeyCode.SUBTRACT, KeyCode.EQUALS },
				{ KeyCode.Q, KeyCode.W, KeyCode.E, KeyCode.R, KeyCode.T, KeyCode.Y, KeyCode.U, KeyCode.I, KeyCode.O,
						KeyCode.P, KeyCode.OPEN_BRACKET, KeyCode.CLOSE_BRACKET, KeyCode.BACK_SLASH },
				{ KeyCode.A, KeyCode.S, KeyCode.D, KeyCode.F, KeyCode.G, KeyCode.H, KeyCode.J, KeyCode.K, KeyCode.L,
						KeyCode.SEMICOLON, KeyCode.QUOTE },
				{ KeyCode.Z, KeyCode.X, KeyCode.C, KeyCode.V, KeyCode.B, KeyCode.N, KeyCode.M, KeyCode.COMMA,
						KeyCode.PERIOD, KeyCode.SLASH } };

		final Button escape = createNonshiftableButton("Esc", KeyCode.ESCAPE, modifiers, target);
		final Button backspace = createNonshiftableButton("Backspace", KeyCode.BACK_SPACE, modifiers, target);
		final Button delete = createNonshiftableButton("Del", KeyCode.DELETE, modifiers, target);
		final Button enter = createNonshiftableButton("Enter", KeyCode.ENTER, modifiers, target);
		final Button tab = createNonshiftableButton("Tab", KeyCode.TAB, modifiers, target);

		final double[] left = { 15.0, 5.0, 15.0, 15.0, 5.0, 10.0 };
		final double[] right = { 5.0, 5.0, 5.0, 15.0, 15.0, 10.0 };
		final double[] up = { 10.0, 0.0, 15.0, 10.0, 5.0, 10.0 };
		final double[] down = { 10.0, 10.0, 15.0, 0.0, 5.0, 0.0 };

		final Button cursorLeft = createCursorKey(KeyCode.LEFT, modifiers, target, left);
		final Button cursorRight = createCursorKey(KeyCode.RIGHT, modifiers, target, right);
		final Button cursorUp = createCursorKey(KeyCode.UP, modifiers, target, up);
		final Button cursorDown = createCursorKey(KeyCode.DOWN, modifiers, target, down);
		final VBox cursorUpDown = new VBox(2);
		cursorUpDown.getChildren().addAll(cursorUp, cursorDown);

		final Node[][] extraLeftButtons = new Node[][] { { escape }, { tab }, { modifiers.capsLockKey() },
				{ modifiers.shiftKey() } };
		final Node[][] extraRightButtons = new Node[][] { { backspace }, { delete }, { enter },
				{ modifiers.secondShiftKey() } };

		try {
			for (int buttonRow = 0; buttonRow < unshifted.length; buttonRow++) {
				HBox hbox = new HBox(5);
				hbox.setAlignment(Pos.CENTER);
				root.getChildren().add(hbox);

				hbox.getChildren().addAll(extraLeftButtons[buttonRow]);
				for (int buttonColumn = 0; buttonColumn < unshifted[buttonRow].length; buttonColumn++) {
					hbox.getChildren().add(createShiftableButton(unshifted[buttonRow][buttonColumn],
							shifted[buttonRow][buttonColumn], codes[buttonRow][buttonColumn], modifiers, target));
				}
				hbox.getChildren().addAll(extraRightButtons[buttonRow]);
			}
		} catch (NullPointerException exception) {
			root = null;
			LOGGER.error("Virtual Keyboard ", APPLICATION_NAME, RegistrationConstants.APPLICATION_ID,
					exception.getMessage());
		}

		final Button spaceBar = createNonshiftableButton(" ", KeyCode.SPACE, modifiers, target);
		spaceBar.setMaxWidth(Double.POSITIVE_INFINITY);
		HBox.setHgrow(spaceBar, Priority.ALWAYS);

		final HBox bottomRow = new HBox(5);
		bottomRow.setAlignment(Pos.CENTER);
		bottomRow.getChildren().addAll(modifiers.ctrlKey(), modifiers.altKey(), modifiers.metaKey(), spaceBar,
				cursorLeft, cursorUpDown, cursorRight);
		root.getChildren().add(bottomRow);
	}

	/**
	 * Visual component displaying this keyboard. The returned node has a style
	 * class of "virtual-keyboard". Buttons in the view have a style class of
	 * "virtual-keyboard-button".
	 * 
	 * @return a view of the keyboard.
	 */
	public Node view() {
		return root;
	}

	private Button createShiftableButton(final String unshifted, final String shifted, final KeyCode code,
			Modifiers modifiers, final ReadOnlyObjectProperty target) {
		final ReadOnlyBooleanProperty letter = new SimpleBooleanProperty(
				unshifted.length() == 1 && Character.isLetter(unshifted.charAt(0)));
		final StringBinding text = Bindings.when(modifiers.shiftDown().or(modifiers.capsLockOn().and(letter)))
				.then(shifted).otherwise(unshifted);
		return createButton(text, code, modifiers, target);
	}

	private Button createNonshiftableButton(final String text, final KeyCode code, final Modifiers modifiers,
			final ReadOnlyObjectProperty target) {
		StringProperty textProperty = new SimpleStringProperty(text);
		Button button = createButton(textProperty, code, modifiers, target);
		return button;
	}

	private Button createButton(final ObservableStringValue text, final KeyCode code, final Modifiers modifiers,
			final ReadOnlyObjectProperty target) {
		final Button button = new Button();
		button.textProperty().bind(text);

		button.setFocusTraversable(false);

		button.setOnAction(new EventHandler() {
			@Override
			public void handle(ActionEvent event) {
				vkType.append("vk");
				Node targetNode;
				if (target != null) {
					targetNode = target.get();
				} else {
					targetNode = getParentStage().getScene().getFocusOwner();
				}

				if (targetNode != null) {
					final String character;
					if (KEY_LENGTHS.contains(text.get().length())) {
						character = text.get();
					} else {
						character = KeyEvent.CHAR_UNDEFINED;
					}
					final KeyEvent keyPressEvent = createKeyEvent(button, targetNode, KeyEvent.KEY_PRESSED, character,
							code, modifiers);
					targetNode.fireEvent(keyPressEvent);
					final KeyEvent keyReleasedEvent = createKeyEvent(button, targetNode, KeyEvent.KEY_RELEASED,
							character, code, modifiers);
					targetNode.fireEvent(keyReleasedEvent);
					if (character != KeyEvent.CHAR_UNDEFINED) {
						final KeyEvent keyTypedEvent = createKeyEvent(button, targetNode, KeyEvent.KEY_TYPED, character,
								code, modifiers);
						targetNode.fireEvent(keyTypedEvent);
					}
					modifiers.releaseKeys();
					vkType.delete(0, vkType.length());
				}
			}
		});
		return button;
	}
	
	private KeyEvent createKeyEvent(Object source, EventTarget target, EventType eventType, String character,
			KeyCode code, Modifiers modifiers) {
		return new KeyEvent(source, target, eventType, character, code.toString(), code, modifiers.shiftDown().get(),
				modifiers.ctrlDown().get(), modifiers.altDown().get(), modifiers.metaDown().get());
	}

	private Button createCursorKey(KeyCode code, Modifiers modifiers, ReadOnlyObjectProperty target,
			double[] points) {
		Button button = createNonshiftableButton("", code, modifiers, target);
		final Node graphic = new Polygon(points);
		graphic.setStyle("-fx-fill: -fx-mark-color;");
		button.setGraphic(graphic);
		button.setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
		return button;
	}

	private static class Modifiers {
		private final ToggleButton shift;
		private final ToggleButton shift2;
		private final ToggleButton ctrl;
		private final ToggleButton alt;
		private final ToggleButton meta;
		private final ToggleButton capsLock;

		Modifiers() {
			this.shift = createToggle("Shift");
			this.shift2 = createToggle("Shift");
			this.ctrl = createToggle("Ctrl");
			this.alt = createToggle("Alt");
			this.meta = createToggle("Meta");
			this.capsLock = createToggle("Caps");

			shift2.selectedProperty().bindBidirectional(shift.selectedProperty());
		}

		private ToggleButton createToggle(final String text) {
			final ToggleButton tb = new ToggleButton(text);
			tb.setFocusTraversable(false);
			return tb;
		}

		public Node shiftKey() {
			return shift;
		}

		public Node secondShiftKey() {
			return shift2;
		}

		public Node ctrlKey() {
			return ctrl;
		}

		public Node altKey() {
			return alt;
		}

		public Node metaKey() {
			return meta;
		}

		public Node capsLockKey() {
			return capsLock;
		}

		public BooleanProperty shiftDown() {
			return shift.selectedProperty();
		}

		public BooleanProperty ctrlDown() {
			return ctrl.selectedProperty();
		}

		public BooleanProperty altDown() {
			return alt.selectedProperty();
		}

		public BooleanProperty metaDown() {
			return meta.selectedProperty();
		}

		public BooleanProperty capsLockOn() {
			return capsLock.selectedProperty();
		}

		public void releaseKeys() {
			shift.setSelected(false);
			ctrl.setSelected(false);
			alt.setSelected(false);
			meta.setSelected(false);
		}
	}

	public void changeControlOfKeyboard(TextField textField) {
		textField.setOnKeyPressed(new EventHandler() {
			@Override
			public void handle(Event event) {
				if (!vkType.toString().contains("vk")) {
					KeyEvent e = ((KeyEvent) event);
					if (e.getCode().getName().equals("Caps Lock")) {
						if (capsLock) {
							capsLock = false;
						} else {
							capsLock = true;
						}
					}
					if (e.getCode().getName().equals("Shift")) {
						keyEvent = e;
					}					
					
					textField.setOnKeyReleased(new EventHandler() {
			            @Override
			            public void handle(KeyEvent event) {
			                switch (event.getCode()) {			                   
			                    case SHIFT:
			                    	keyEvent = null;
							default:
								break;
			                }
			            }
			        });
					
					String key;
					if (capsLock || (keyEvent != null ? keyEvent.getCode() != null && keyEvent.getCode().getName() != null && keyEvent.getCode().getName().equals("Shift") : false)) {
						try {
							key = keyboard.getString("shift_" + e.getCode().getName().replaceAll("\\s", ""));
						} catch (MissingResourceException exception) {
							LOGGER.error("Virtual Keyboard", APPLICATION_NAME, RegistrationConstants.APPLICATION_ID,
									exception.getMessage());
							key = null;
						}
						if (key != null) {
							textField.fireEvent(new KeyEvent(KeyEvent.KEY_TYPED, key, e.getCode().getName(),
									e.getCode(), false, false, false, false));
							textField.setEditable(false);
						}
					} else {
						try {
							key = keyboard.getString("unshift_" + e.getCode().getName().replaceAll("\\s", ""));
						} catch (MissingResourceException exception) {
							LOGGER.error("Virtual Keyboard", APPLICATION_NAME, RegistrationConstants.APPLICATION_ID,
									exception.getMessage());
							key = null;
						}
						if (key != null) {
							textField.fireEvent(new KeyEvent(KeyEvent.KEY_TYPED, key, e.getCode().getName(),
									e.getCode(), false, false, false, false));
							textField.setEditable(false);
						}
					}
				}
			}
		});

		textField.textProperty().addListener(new ChangeListener() {
			@Override
			public void changed(final ObservableValue obsVal, final String oldValue,
					final String newValue) {
				Platform.runLater(() -> {
					textField.setEditable(true);
				});

			}
		});

	}

	public void focusListener(TextField field, double y, Node keyboardNode) {
		field.focusedProperty().addListener(new ChangeListener() {
			@Override
			public void changed(ObservableValue arg0, Boolean oldPropertyValue,
					Boolean newPropertyValue) {
				if (newPropertyValue) {
					keyboardNode.setLayoutY(y);
				}
			}
		});
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy