Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.sun.javafx.scene.control.skin.FXVKSkin Maven / Gradle / Ivy
/*
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package com.sun.javafx.scene.control.skin;
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javafx.animation.Animation;
import javafx.animation.Interpolator;
import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.application.Platform;
import javafx.beans.InvalidationListener;
import javafx.beans.Observable;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.event.EventTarget;
import javafx.event.EventType;
import javafx.geometry.HPos;
import javafx.geometry.Point2D;
import javafx.geometry.Rectangle2D;
import javafx.geometry.VPos;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.input.InputEvent;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Region;
import javafx.scene.text.Text;
import javafx.stage.Popup;
import javafx.util.Duration;
import com.sun.javafx.css.StyleManager;
import com.sun.javafx.scene.control.behavior.BehaviorBase;
import static javafx.scene.input.MouseEvent.*;
import static javafx.scene.input.TouchEvent.*;
import static javafx.scene.layout.Region.*;
public class FXVKSkin extends BehaviorSkinBase> {
private static final int GAP = 6;
private List> board;
private int numCols;
private boolean capsDown = false;
private boolean shiftDown = false;
private boolean isSymbol = false;
long lastTime = -1L;
void clearShift() {
if (shiftDown && !capsDown) {
shiftDown = false;
updateKeys();
}
lastTime = -1L;
}
void pressShift() {
long time = System.currentTimeMillis();
//potential for a shift lock
if (shiftDown && !capsDown) {
if (lastTime > 0L && time - lastTime < 400L) {
//set caps lock
shiftDown = false;
capsDown = true;
} else {
//set normal
shiftDown = false;
capsDown = false;
}
} else if (!shiftDown && !capsDown) {
// set shift
shiftDown=true;
} else {
//set to normal
shiftDown = false;
capsDown = false;
}
updateKeys();
lastTime = time;
}
void clearSymbolABC() {
isSymbol = false;
updateKeys();
}
void pressSymbolABC() {
isSymbol = !isSymbol;
updateKeys();
}
private void updateKeys() {
for (List row : board) {
for (Key key : row) {
key.update(capsDown, shiftDown, isSymbol);
}
}
}
private final static boolean USE_SECONDARY_POPUP = false;
private static Region oldRoot;
private static Timeline slideRootTimeline;
private static Popup vkPopup;
private static Popup secondaryPopup;
private static FXVK primaryVK;
private static Timeline slideInTimeline = new Timeline();
private static Timeline slideOutTimeline = new Timeline();
private static FXVK secondaryVK;
private static Timeline secondaryVKDelay;
private static CharKey secondaryVKKey;
private Node attachedNode;
private String vkType;
FXVK fxvk;
static final double VK_WIDTH = 640;
static final double VK_HEIGHT = 243;
static final double VK_PORTRAIT_HEIGHT = 326;
static final double VK_SLIDE_MILLIS = 250;
static final double PREF_KEY_WIDTH = 56;
static final double PREF_PORTRAIT_KEY_WIDTH = 40;
static final double PREF_KEY_HEIGHT = 56;
double keyWidth = PREF_KEY_WIDTH;
double keyHeight = PREF_KEY_HEIGHT;
// Proxy for read-only Window.yProperty() so we can animate.
private static DoubleProperty winY = new SimpleDoubleProperty();
static {
winY.addListener(new InvalidationListener() {
@Override public void invalidated(Observable valueModel) {
if (vkPopup != null) {
vkPopup.setY(winY.get());
}
}
});
}
private static void startSlideIn() {
slideOutTimeline.stop();
winY.set(vkPopup.getY());
slideInTimeline.playFromStart();
}
private static void startSlideOut() {
slideInTimeline.stop();
winY.set(vkPopup.getY());
slideOutTimeline.playFromStart();
}
EventHandler unHideEventHandler;
private boolean isVKHidden = false;
private void registerUnhideHandler(final Node node) {
if (unHideEventHandler == null) {
unHideEventHandler = new EventHandler () {
public void handle(InputEvent event) {
if (node != null && isVKHidden) {
double screenHeight = com.sun.javafx.Utils.getScreen(node).getBounds().getHeight();
if (fxvk.getHeight() > 0 && (vkPopup.getY() > screenHeight - fxvk.getHeight())) {
if (slideInTimeline.getStatus() != Animation.Status.RUNNING) {
startSlideIn();
}
}
}
isVKHidden = false;
}
};
}
attachedNode.addEventHandler(TOUCH_PRESSED, unHideEventHandler);
attachedNode.addEventHandler(MOUSE_PRESSED, unHideEventHandler);
}
private void unRegisterUnhideHandler(Node node) {
if (unHideEventHandler != null) {
node.removeEventHandler(TOUCH_PRESSED, unHideEventHandler);
node.removeEventHandler(MOUSE_PRESSED, unHideEventHandler);
}
}
private void updateKeyboardType() {
String oldType = vkType;
int typeIndex = 0;
Object typeValue = attachedNode.getProperties().get(FXVK.VK_TYPE_PROP_KEY);
String typeStr = null;
if (typeValue instanceof String) {
typeStr = ((String)typeValue).toLowerCase();
}
vkType = (typeStr != null ? typeStr : "text");
//VK type changed, rebuild
if ( oldType == null || !vkType.equals(oldType) ) {
rebuild();
}
}
public FXVKSkin(final FXVK fxvk) {
super(fxvk, new BehaviorBase(fxvk));
this.fxvk = fxvk;
StyleManager.getInstance().addUserAgentStylesheet("com/sun/javafx/scene/control/skin/caspian/fxvk.css");
fxvk.setFocusTraversable(false);
if (fxvk != secondaryVK) {
//init secondary VK delay animation
if (secondaryVKDelay == null) {
secondaryVKDelay = new Timeline();
}
KeyFrame kf = new KeyFrame(Duration.millis(500), new EventHandler() {
@Override public void handle(ActionEvent event) {
if (secondaryVKKey != null) {
showSecondaryVK(secondaryVKKey);
}
}
});
secondaryVKDelay.getKeyFrames().setAll(kf);
}
fxvk.attachedNodeProperty().addListener(new InvalidationListener() {
@Override public void invalidated(Observable valueModel) {
Node oldNode = attachedNode;
attachedNode = fxvk.getAttachedNode();
isVKHidden = false;
if (fxvk != FXVK.vk) {
// This is not the current vk, so nothing more to do
return;
}
if (fxvk == secondaryVK) {
return;
}
//close secondary VK if open
if (secondaryVK != null) {
secondaryVK.setAttachedNode(null);
secondaryPopup.hide();
}
if (attachedNode != null) {
if (oldNode != null) {
unRegisterUnhideHandler(oldNode);
}
registerUnhideHandler(attachedNode);
updateKeyboardType();
fxvk.setVisible(true);
if (fxvk != secondaryVK) {
// init popup window and slide animations
if (vkPopup == null) {
vkPopup = new Popup();
vkPopup.setAutoFix(false);
double screenHeight =
com.sun.javafx.Utils.getScreen(attachedNode).getBounds().getHeight();
double screenVisualHeight =
com.sun.javafx.Utils.getScreen(attachedNode).getVisualBounds().getHeight();
screenVisualHeight = Math.min(screenHeight, screenVisualHeight + 4 /*??*/);
slideInTimeline.getKeyFrames().setAll(
new KeyFrame(Duration.millis(VK_SLIDE_MILLIS),
new KeyValue(winY, screenHeight - VK_HEIGHT,
Interpolator.EASE_BOTH)));
slideOutTimeline.getKeyFrames().setAll(
new KeyFrame(Duration.millis(VK_SLIDE_MILLIS),
new KeyValue(winY, screenHeight, Interpolator.EASE_BOTH)));
}
vkPopup.getContent().setAll(fxvk);
//owner window has changed so hide VK and show with new owner
if (oldNode == null || oldNode.getScene() == null || oldNode.getScene().getWindow() != attachedNode.getScene().getWindow()) {
if (vkPopup.isShowing()) {
vkPopup.hide();
}
}
if (!vkPopup.isShowing()) {
Platform.runLater(new Runnable() {
public void run() {
Rectangle2D screenBounds =
com.sun.javafx.Utils.getScreen(attachedNode).getBounds();
vkPopup.show(attachedNode.getScene().getWindow(),
(screenBounds.getWidth() - fxvk.prefWidth(-1)) / 2,
screenBounds.getHeight() - fxvk.prefHeight(-1));
}
});
}
if (oldNode == null || oldNode.getScene() != attachedNode.getScene()) {
double width = com.sun.javafx.Utils.getScreen(attachedNode).getBounds().getWidth();
fxvk.setPrefWidth(width);
fxvk.setMinWidth(USE_PREF_SIZE);
fxvk.setMaxWidth(USE_PREF_SIZE);
fxvk.setPrefHeight(VK_HEIGHT);
fxvk.setMinHeight(USE_PREF_SIZE);
}
if (fxvk.getHeight() > 0 &&
(fxvk.getLayoutY() == 0 || fxvk.getLayoutY() > attachedNode.getScene().getHeight() - fxvk.getHeight())) {
startSlideIn();
}
}
} else {
if (fxvk != secondaryVK) {
if (oldNode != null) {
unRegisterUnhideHandler(oldNode);
}
startSlideOut();
}
if (secondaryVK != null) {
secondaryVK.setAttachedNode(null);
secondaryPopup.hide();
}
return;
}
}
});
}
/**
* Replaces all children of this VirtualKeyboardSkin based on the keyboard
* type set on the VirtualKeyboard.
*/
private void rebuild() {
if (fxvk == secondaryVK) {
//build secondary VK
if (secondaryVK.chars == null) {
} else {
int nKeys = secondaryVK.chars.length;
int nRows = (int)Math.floor(Math.sqrt(Math.max(1, nKeys - 2)));
int nKeysPerRow = (int)Math.ceil(nKeys / (double)nRows);
Key tmpKey;
List> rows = new ArrayList>(2);
for (int i = 0; i < nRows; i++) {
int start = i * nKeysPerRow;
int end = Math.min(start + nKeysPerRow, nKeys);
if (start >= end)
break;
List keys = new ArrayList(nKeysPerRow);
for (int j = start; j < end; j++) {
tmpKey = new CharKey(secondaryVK.chars[j], null, null);
tmpKey.col= (j - start) * 2;
tmpKey.colSpan = 2;
for (String sc : tmpKey.getStyleClass()) {
tmpKey.text.getStyleClass().add(sc + "-text");
tmpKey.altText.getStyleClass().add(sc + "-alttext");
tmpKey.icon.getStyleClass().add(sc + "-icon");
}
if (secondaryVK.chars[j] != null && secondaryVK.chars[j].length() > 1) {
tmpKey.text.getStyleClass().add("multi-char-text");
}
keys.add(tmpKey);
}
rows.add(keys);
}
board = rows;
getChildren().clear();
numCols = 0;
for (List row : board) {
for (Key key : row) {
numCols = Math.max(numCols, key.col + key.colSpan);
}
getChildren().addAll(row);
}
}
} else {
String boardName;
switch (vkType) {
case "text":
boardName = "TextBoard";
break;
case "numeric":
boardName = "NumericBoard";
break;
case "url":
boardName = "UrlBoard";
break;
case "email":
boardName = "EmailBoard";
break;
default:
boardName = "TextBoard";
}
board = loadBoard(boardName);
getChildren().clear();
numCols = 0;
for (List row : board) {
for (Key key : row) {
numCols = Math.max(numCols, key.col + key.colSpan);
}
getChildren().addAll(row);
}
}
}
// This skin is designed such that it gives equal widths to all columns. So
// the pref width is just some hard-coded value (although I could have maybe
// done it based on the pref width of a text node with the right font).
@Override protected double computePrefWidth(double height, double topInset, double rightInset, double bottomInset, double leftInset) {
return leftInset + (56 * numCols) + rightInset;
}
// Pref height is just some value. This isn't overly important.
@Override protected double computePrefHeight(double width, double topInset, double rightInset, double bottomInset, double leftInset) {
return topInset + (80 * 5) + bottomInset;
}
// Lays the buttons comprising the current keyboard out.
@Override
protected void layoutChildren(double contentX, double contentY, double contentWidth, double contentHeight) {
// I have fixed width columns, all the same.
int numRows = board.size();
final double colWidth = ((contentWidth - ((numCols - 1) * GAP)) / numCols);
double rowHeight = ((contentHeight - ((numRows - 1) * GAP)) / numRows);
double rowY = contentY;
for (List row : board) {
for (Key key : row) {
double startX = contentX + (key.col * (colWidth + GAP));
double width = (key.colSpan * (colWidth + GAP)) - GAP;
key.resizeRelocate((int)(startX + .5), (int)(rowY + .5),
width, rowHeight);
}
rowY += rowHeight + GAP;
}
}
/**
* A Key on the virtual keyboard. This is simply a Region. Some information
* about the key relative to other keys on the layout is given by the col
* and colSpan fields.
*/
private class Key extends Region {
int col = 0;
int colSpan = 1;
protected final Text text;
protected final Text altText;
protected final Region icon;
protected Key() {
icon = new Region();
text = new Text();
text.setTextOrigin(VPos.TOP);
altText = new Text();
altText.setTextOrigin(VPos.TOP);
getChildren().setAll(text, altText, icon);
getStyleClass().setAll("key");
addEventHandler(MouseEvent.ANY, new EventHandler() {
@Override public void handle(MouseEvent event) {
if (event.getEventType() == MouseEvent.MOUSE_PRESSED)
press();
else if (event.getEventType() == MouseEvent.MOUSE_RELEASED)
release();
}
});
}
protected void press() { }
protected void release() {
clearShift();
}
public void update(boolean capsDown, boolean shiftDown, boolean isSymbol) { }
@Override protected void layoutChildren() {
final double left = snappedLeftInset();
final double top = snappedTopInset();
final double width = getWidth() - left - snappedRightInset();
final double height = getHeight() - top - snappedBottomInset();
text.setVisible(icon.getBackground() == null);
double contentPrefWidth = text.prefWidth(-1);
double contentPrefHeight = text.prefHeight(-1);
text.resizeRelocate(
(int) (left + ((width - contentPrefWidth) / 2) + .5),
(int) (top + ((height - contentPrefHeight) / 2) + .5),
(int) contentPrefWidth,
(int) contentPrefHeight);
altText.setVisible(icon.getBackground() == null && altText.getText().length() > 0);
contentPrefWidth = altText.prefWidth(-1);
contentPrefHeight = altText.prefHeight(-1);
altText.resizeRelocate(
(int) (left + ((width - contentPrefWidth) / 2) + .5 + width/2),
(int) (top + ((height - contentPrefHeight) / 2) + .5 - height/2),
(int) contentPrefWidth,
(int) contentPrefHeight);
icon.resizeRelocate(left-8, top-8, width+16, height+16);
}
}
/**
* Any key on the keyboard which will send a KeyEvent to the client. This
* class just maintains the state and logic for firing an event, using the
* "chars" and "code" as the values sent in the event. A subclass must set
* these appropriately.
*/
private class TextInputKey extends Key {
String chars = "";
protected void press() {
}
protected void release() {
if (fxvk != secondaryVK && secondaryPopup != null && secondaryPopup.isShowing()) {
return;
}
Node target = fxvk.getAttachedNode();
if (target instanceof EventTarget) {
target.fireEvent(event(KeyEvent.KEY_PRESSED));
target.fireEvent(event(KeyEvent.KEY_TYPED));
target.fireEvent(event(KeyEvent.KEY_RELEASED));
}
if (fxvk == secondaryVK) {
showSecondaryVK(null);
}
super.release();
}
protected KeyEvent event(EventType type) {
return new KeyEvent(type, chars, "", KeyCode.UNDEFINED, shiftDown, false, false, false);
}
}
/**
* A key which has a letter, a number or symbol on it
*
*/
private class CharKey extends TextInputKey {
private final String letterChars;
private final String altChars;
private final String[] moreChars;
private CharKey(String letter, String alt, String[] moreChars) {
setId(letter);
this.letterChars = letter;
this.altChars = alt;
this.moreChars = moreChars;
this.chars = this.letterChars;
text.setText(this.chars);
altText.setText(this.altChars);
if (fxvk != secondaryVK) {
setOnMousePressed(new EventHandler() {
@Override public void handle(MouseEvent event) {
showSecondaryVK(null);
secondaryVKKey = CharKey.this;
secondaryVKDelay.playFromStart();
}
});
setOnMouseReleased(new EventHandler() {
@Override public void handle(MouseEvent event) {
secondaryVKDelay.stop();
}
});
}
}
@Override public void update(boolean capsDown, boolean shiftDown, boolean isSymbol) {
if (isSymbol) {
chars = altChars;
text.setText(chars);
if (moreChars != null && moreChars.length > 0 && !Character.isLetter(moreChars[0].charAt(0))) {
altText.setText(moreChars[0]);
} else {
altText.setText(null);
}
} else {
chars = (capsDown || shiftDown) ? letterChars.toUpperCase() : letterChars.toLowerCase();
text.setText(chars);
altText.setText(altChars);
}
}
}
/**
* One of several TextInputKeys which have super powers, such as "Tab" and
* "Return" and "Backspace". These keys still send events to the client,
* but may also have additional state related functionality on the keyboard
* such as the "Shift" key.
*/
private class SuperKey extends TextInputKey {
private SuperKey(String letter, String code) {
this.chars = code;
text.setText(letter);
getStyleClass().add("special");
setId(letter);
}
}
/**
* Some keys actually do need to use KeyCode for pressed / released events,
* and BackSpace is one of them.
*/
private class KeyCodeKey extends SuperKey {
private KeyCode code;
private KeyCodeKey(String letter, String c, KeyCode code) {
super(letter, c);
this.code = code;
setId(letter);
}
protected KeyEvent event(EventType type) {
if (type == KeyEvent.KEY_PRESSED || type == KeyEvent.KEY_RELEASED) {
return new KeyEvent(type, chars, chars, code, shiftDown, false, false, false);
} else {
return super.event(type);
}
}
}
/**
* These keys only manipulate the state of the keyboard and never
* send key events to the client. For example, "Hide", "Caps Lock",
* etc are all KeyboardStateKeys.
*/
private class KeyboardStateKey extends Key {
private final String defaultText;
private final String toggledText;
private KeyboardStateKey(String defaultText, String toggledText) {
this.defaultText = defaultText;
this.toggledText = toggledText;
text.setText(this.defaultText);
setId(this.defaultText);
getStyleClass().add("special");
}
@Override public void update(boolean capsDown, boolean shiftDown, boolean isSymbol) {
//change icon
if (isSymbol) {
text.setText(this.toggledText);
setId(this.toggledText);
} else {
text.setText(this.defaultText);
setId(this.defaultText);
}
}
}
private void showSecondaryVK(final CharKey key) {
if (key != null) {
primaryVK = fxvk;
final Node textInput = primaryVK.getAttachedNode();
if (secondaryVK == null) {
secondaryVK = new FXVK();
//secondaryVK.getStyleClass().addAll("fxvk-secondary", "fxvk-portrait");
secondaryVK.setSkin(new FXVKSkin(secondaryVK));
secondaryVK.getStyleClass().setAll("fxvk-secondary");
secondaryPopup = new Popup();
secondaryPopup.setAutoHide(true);
secondaryPopup.getContent().add(secondaryVK);
}
secondaryVK.chars=null;
ArrayList secondaryList = new ArrayList();
// Add primary character
if (!isSymbol) {
if (key.letterChars != null && key.letterChars.length() > 0) {
if (shiftDown || capsDown) {
secondaryList.add(key.letterChars.toUpperCase());
} else {
secondaryList.add(key.letterChars);
}
}
}
// Add secondary character
if (key.altChars != null && key.altChars.length() > 0) {
if (shiftDown || capsDown) {
secondaryList.add(key.altChars.toUpperCase());
} else {
secondaryList.add(key.altChars);
}
}
// Add more letters
if (key.moreChars != null && key.moreChars.length > 0) {
if (isSymbol) {
//Add non-letters
for (String ch : key.moreChars) {
if (!Character.isLetter(ch.charAt(0))) {
secondaryList.add(ch);
}
}
} else {
//Add letters
for (String ch : key.moreChars) {
if (Character.isLetter(ch.charAt(0))) {
if (shiftDown || capsDown) {
secondaryList.add(ch.toUpperCase());
} else {
secondaryList.add(ch);
}
}
}
}
}
secondaryVK.chars = secondaryList.toArray(new String[secondaryList.size()]);
if (secondaryVK.chars.length > 1) {
if (secondaryVK.getSkin() != null) {
((FXVKSkin)secondaryVK.getSkin()).rebuild();
}
secondaryVK.setAttachedNode(textInput);
FXVKSkin primarySkin = (FXVKSkin)primaryVK.getSkin();
FXVKSkin secondarySkin = (FXVKSkin)secondaryVK.getSkin();
//Insets insets = secondarySkin.getInsets();
int nKeys = secondaryVK.chars.length;
int nRows = (int)Math.floor(Math.sqrt(Math.max(1, nKeys - 2)));
int nKeysPerRow = (int)Math.ceil(nKeys / (double)nRows);
final double w = snappedLeftInset() + snappedRightInset() +
nKeysPerRow * PREF_PORTRAIT_KEY_WIDTH + (nKeysPerRow - 1) * GAP;
final double h = snappedTopInset() + snappedBottomInset() +
nRows * PREF_KEY_HEIGHT + (nRows-1) * GAP;
secondaryVK.setPrefWidth(w);
secondaryVK.setMinWidth(USE_PREF_SIZE);
secondaryVK.setPrefHeight(h);
secondaryVK.setMinHeight(USE_PREF_SIZE);
Platform.runLater(new Runnable() {
public void run() {
// Position popup on screen
Point2D nodePoint =
com.sun.javafx.Utils.pointRelativeTo(key, w, h, HPos.CENTER, VPos.TOP,
5, -3, true);
double x = nodePoint.getX();
double y = nodePoint.getY();
Scene scene = key.getScene();
x = Math.min(x, scene.getWindow().getX() + scene.getWidth() - w);
secondaryPopup.show(key.getScene().getWindow(), x, y);
}
});
}
} else {
if (secondaryVK != null) {
secondaryVK.setAttachedNode(null);
secondaryPopup.hide();
}
}
}
private List> loadBoard(String boardName) {
try {
List> rows = new ArrayList>(5);
List keys = new ArrayList(20);
InputStream boardFile = FXVKSkin.class.getResourceAsStream(boardName + ".txt");
BufferedReader reader = new BufferedReader(new InputStreamReader(boardFile));
String line;
// A pointer to the current column. This will be incremented for every string
// of text, or space.
int c = 0;
// The col at which the key will be placed
int col = 0;
// The number of columns that the key will span
int colSpan = 1;
// Whether the "chars" is an identifier, like $shift or $SymbolBoard, etc.
boolean identifier = false;
// The textual content of the Key
List charsList = new ArrayList(10);
while ((line = reader.readLine()) != null) {
if (line.length() == 0 || line.charAt(0) == '#') {
continue;
}
// A single line represents a single row of buttons
for (int i=0; i(10);
identifier = false;
} else if (ch == ']') {
String chars = "";
String alt = null;
String[] moreChars = null;
for (int idx = 0; idx < charsList.size(); idx++) {
charsList.set(idx, FXVKCharEntities.get(charsList.get(idx)));
}
int listSize = charsList.size();
if (listSize > 0) {
chars = charsList.get(0);
if (listSize > 1) {
alt = charsList.get(1);
if (listSize > 2) {
moreChars = charsList.subList(2, listSize).toArray(new String[listSize - 2]);
}
}
}
// End of a key
colSpan = c - col;
Key key;
if (identifier) {
if ("$shift".equals(chars)) {
key = new KeyboardStateKey("", null) {
@Override protected void release() {
pressShift();
}
@Override public void update(boolean capsDown, boolean shiftDown, boolean isSymbol) {
if (isSymbol) {
this.setDisable(true);
this.setVisible(false);
} else {
if (capsDown) {
icon.getStyleClass().remove("shift-icon");
icon.getStyleClass().add("capslock-icon");
} else {
icon.getStyleClass().remove("capslock-icon");
icon.getStyleClass().add("shift-icon");
}
this.setDisable(false);
this.setVisible(true);
}
}
};
key.getStyleClass().add("shift");
} else if ("$SymbolABC".equals(chars)) {
key = new KeyboardStateKey("!#123", "ABC") {
@Override protected void release() {
pressSymbolABC();
}
};
} else if ("$backspace".equals(chars)) {
key = new KeyCodeKey("backspace", "\b", KeyCode.BACK_SPACE);
key.getStyleClass().add("backspace");
} else if ("$enter".equals(chars)) {
key = new KeyCodeKey("enter", "\n", KeyCode.ENTER);
key.getStyleClass().add("enter");
} else if ("$tab".equals(chars)) {
key = new KeyCodeKey("tab", "\t", KeyCode.TAB);
} else if ("$space".equals(chars)) {
key = new CharKey(" ", null, null);
} else if ("$clear".equals(chars)) {
key = new SuperKey("clear", "");
} else if ("$.org".equals(chars)) {
key = new SuperKey(".org", ".org");
} else if ("$.com".equals(chars)) {
key = new SuperKey(".com", ".com");
} else if ("$.net".equals(chars)) {
key = new SuperKey(".net", ".net");
} else if ("$oracle.com".equals(chars)) {
key = new SuperKey("oracle.com", "oracle.com");
} else if ("$gmail.com".equals(chars)) {
key = new SuperKey("gmail.com", "gmail.com");
} else if ("$hide".equals(chars)) {
key = new KeyboardStateKey("Hide", null) {
@Override protected void release() {
isVKHidden = true;
startSlideOut();
}
};
key.getStyleClass().add("hide");
} else if ("$undo".equals(chars)) {
key = new SuperKey("undo", "");
} else if ("$redo".equals(chars)) {
key = new SuperKey("redo", "");
} else {
//Unknown Key
key = null;
}
} else {
key = new CharKey(chars, alt, moreChars);
}
if (key != null) {
key.col = col;
key.colSpan = colSpan;
for (String sc : key.getStyleClass()) {
key.text.getStyleClass().add(sc + "-text");
key.altText.getStyleClass().add(sc + "-alttext");
key.icon.getStyleClass().add(sc + "-icon");
}
if (chars != null && chars.length() > 1) {
key.text.getStyleClass().add("multi-char-text");
}
if (alt != null && alt.length() > 1) {
key.altText.getStyleClass().add("multi-char-text");
}
keys.add(key);
}
} else {
// Normal textual characters. Read all the way up to the
// next ] or space
for (int j=i; j(20);
}
reader.close();
return rows;
} catch (Exception e) {
e.printStackTrace();
return Collections.emptyList();
}
}
}