/*******************************************************************************
* Copyright (c) 2016 comtel inc.
*
* Licensed under the Apache License, version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*******************************************************************************/
package org.jfxvnc.ui;
import org.jfxvnc.net.rfb.codec.encoder.InputEventListener;
import org.jfxvnc.net.rfb.codec.encoder.KeyButtonEvent;
import org.jfxvnc.net.rfb.codec.encoder.KeyButtonMap;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
public class KeyButtonEventHandler implements KeyButtonMap {
private InputEventListener listener;
private final BooleanProperty enabled = new SimpleBooleanProperty(false);
private final EventHandler<KeyEvent> keyEventHandler;
private boolean lastCodePointRelease;
private int lastCodePoint;
public KeyButtonEventHandler() {
keyEventHandler = (e) -> {
if (enabled.get()) {
sendKeyEvents(e);
e.consume();
}
};
}
public void setInputEventListener(InputEventListener listener) {
this.listener = listener;
}
public BooleanProperty enabledProperty() {
return enabled;
}
public void register(Scene scene) {
scene.addEventFilter(KeyEvent.KEY_PRESSED, keyEventHandler);
scene.addEventFilter(KeyEvent.KEY_TYPED, keyEventHandler);
scene.addEventFilter(KeyEvent.KEY_RELEASED, keyEventHandler);
}
public void unregister(Scene scene) {
scene.removeEventFilter(KeyEvent.KEY_PRESSED, keyEventHandler);
scene.removeEventFilter(KeyEvent.KEY_TYPED, keyEventHandler);
scene.removeEventFilter(KeyEvent.KEY_RELEASED, keyEventHandler);
}
private static boolean isModifierPressed(KeyEvent event) {
return event.isAltDown() || event.isControlDown() || event.isMetaDown() || event.isShortcutDown();
}
public void sendKeyEvents(KeyEvent event) {
if (event.isConsumed()) {
return;
}
if (event.getEventType() == KeyEvent.KEY_TYPED) {
if (!isModifierPressed(event) && event.getCode() == KeyCode.UNDEFINED) {
int codePoint = event.getCharacter().codePointAt(0);
// space was triggered twice
if (!Character.isWhitespace(codePoint) && !Character.isISOControl(codePoint)) {
lastCodePoint = codePoint;
lastCodePointRelease = true;
fire(new KeyButtonEvent(true, codePoint));
}
}
return;
}
if (event.getCode().isFunctionKey()) {
sendFunctionKeyEvents(event, event.getEventType() == KeyEvent.KEY_PRESSED);
return;
}
if (event.getCode().isModifierKey()) {
sendModifierKeyEvents(event, event.getEventType() == KeyEvent.KEY_PRESSED);
return;
}
if (event.getCode().isNavigationKey()) {
sendNavigationKeyEvents(event, event.getEventType() == KeyEvent.KEY_PRESSED);
return;
}
if (sendSpecialKeyEvents(event, event.getEventType() == KeyEvent.KEY_PRESSED)) {
return;
}
if (event.isShortcutDown() || event.isControlDown()) {
int codePoint = event.getText().codePointAt(0);
fire(new KeyButtonEvent(event.getEventType() == KeyEvent.KEY_PRESSED, codePoint));
return;
}
if (event.getEventType() == KeyEvent.KEY_RELEASED) {
if (lastCodePointRelease) {
lastCodePointRelease = false;
fire(new KeyButtonEvent(false, lastCodePoint));
} else {
int codePoint = event.getText().codePointAt(0);
fire(new KeyButtonEvent(false, codePoint));
}
return;
}
}
private boolean sendSpecialKeyEvents(KeyEvent event, boolean isDown) {
switch (event.getCode()) {
case PRINTSCREEN:
fire(new KeyButtonEvent(isDown, RFB_Print));
return true;
case INSERT:
fire(new KeyButtonEvent(isDown, RFB_Insert));
return true;
case UNDO:
fire(new KeyButtonEvent(isDown, RFB_Undo));
return true;
case AGAIN:
fire(new KeyButtonEvent(isDown, RFB_Redo));
return true;
case FIND:
fire(new KeyButtonEvent(isDown, RFB_Find));
return true;
case CANCEL:
fire(new KeyButtonEvent(isDown, RFB_Cancel));
return true;
case HELP:
fire(new KeyButtonEvent(isDown, RFB_Help));
return true;
case STOP:
fire(new KeyButtonEvent(isDown, RFB_Break));
return true;
case MODECHANGE:
fire(new KeyButtonEvent(isDown, RFB_Mode_switch));
return true;
case NUM_LOCK:
fire(new KeyButtonEvent(isDown, RFB_Num_Lock));
return true;
case BACK_SPACE:
fire(new KeyButtonEvent(isDown, RFB_BackSpace));
return true;
case TAB:
fire(new KeyButtonEvent(isDown, RFB_Tab));
return true;
case CLEAR:
fire(new KeyButtonEvent(isDown, RFB_Clear));
return true;
case ENTER:
fire(new KeyButtonEvent(isDown, RFB_Return));
return true;
case PAUSE:
fire(new KeyButtonEvent(isDown, RFB_Pause));
return true;
case SCROLL_LOCK:
fire(new KeyButtonEvent(isDown, RFB_Scroll_Lock));
return true;
case ESCAPE:
fire(new KeyButtonEvent(isDown, RFB_Escape));
return true;
case DELETE:
fire(new KeyButtonEvent(isDown, RFB_Delete));
return true;
case SPACE:
fire(new KeyButtonEvent(isDown, RFB_space));
return true;
case CAPS:
fire(new KeyButtonEvent(isDown, RFB_Caps_Lock));
return true;
case CHANNEL_DOWN:
fire(new KeyButtonEvent(isDown, RFB_N));
return true;
case NUMPAD0:
fire(new KeyButtonEvent(isDown, RFB_KP_0));
return true;
case NUMPAD1:
fire(new KeyButtonEvent(isDown, RFB_KP_1));
return true;
case NUMPAD2:
fire(new KeyButtonEvent(isDown, RFB_KP_2));
return true;
case NUMPAD3:
fire(new KeyButtonEvent(isDown, RFB_KP_3));
return true;
case NUMPAD4:
fire(new KeyButtonEvent(isDown, RFB_KP_4));
return true;
case NUMPAD5:
fire(new KeyButtonEvent(isDown, RFB_KP_5));
return true;
case NUMPAD6:
fire(new KeyButtonEvent(isDown, RFB_KP_6));
return true;
case NUMPAD7:
fire(new KeyButtonEvent(isDown, RFB_KP_7));
return true;
case NUMPAD8:
fire(new KeyButtonEvent(isDown, RFB_KP_8));
return true;
case NUMPAD9:
fire(new KeyButtonEvent(isDown, RFB_KP_9));
return true;
default:
return false;
}
}
private void sendNavigationKeyEvents(KeyEvent event, boolean isDown) {
switch (event.getCode()) {
case HOME:
fire(new KeyButtonEvent(isDown, RFB_Home));
break;
case KP_UP:
fire(new KeyButtonEvent(isDown, RFB_KP_Up));
break;
case KP_RIGHT:
fire(new KeyButtonEvent(isDown, RFB_KP_Right));
break;
case KP_DOWN:
fire(new KeyButtonEvent(isDown, RFB_KP_Down));
break;
case KP_LEFT:
fire(new KeyButtonEvent(isDown, RFB_KP_Left));
break;
case UP:
fire(new KeyButtonEvent(isDown, RFB_Up));
break;
case RIGHT:
fire(new KeyButtonEvent(isDown, RFB_Right));
break;
case DOWN:
fire(new KeyButtonEvent(isDown, RFB_Down));
break;
case LEFT:
fire(new KeyButtonEvent(isDown, RFB_Left));
break;
case TRACK_PREV:
fire(new KeyButtonEvent(isDown, RFB_PreviousCandidate));
break;
case PAGE_UP:
fire(new KeyButtonEvent(isDown, RFB_Page_Up));
break;
case TRACK_NEXT:
fire(new KeyButtonEvent(isDown, RFB_Next));
break;
case PAGE_DOWN:
fire(new KeyButtonEvent(isDown, RFB_Page_Down));
break;
case END:
fire(new KeyButtonEvent(isDown, RFB_End));
break;
case BEGIN:
fire(new KeyButtonEvent(isDown, RFB_Begin));
break;
default:
break;
}
}
private void sendFunctionKeyEvents(KeyEvent event, boolean isDown) {
switch (event.getCode()) {
case F1:
fire(new KeyButtonEvent(isDown, RFB_F1));
break;
case F2:
fire(new KeyButtonEvent(isDown, RFB_F2));
break;
case F3:
fire(new KeyButtonEvent(isDown, RFB_F3));
break;
case F4:
fire(new KeyButtonEvent(isDown, RFB_F4));
break;
case F5:
fire(new KeyButtonEvent(isDown, RFB_F5));
break;
case F6:
fire(new KeyButtonEvent(isDown, RFB_F6));
break;
case F7:
fire(new KeyButtonEvent(isDown, RFB_F7));
break;
case F8:
fire(new KeyButtonEvent(isDown, RFB_F8));
break;
case F9:
fire(new KeyButtonEvent(isDown, RFB_F9));
break;
case F10:
fire(new KeyButtonEvent(isDown, RFB_F10));
break;
case F11:
fire(new KeyButtonEvent(isDown, RFB_F11));
break;
case F12:
fire(new KeyButtonEvent(isDown, RFB_F12));
break;
default:
break;
}
}
private void sendModifierKeyEvents(KeyEvent event, boolean isDown) {
switch (event.getCode()) {
case SHIFT:
fire(new KeyButtonEvent(isDown, RFB_Shift_L));
break;
case CONTROL:
fire(new KeyButtonEvent(isDown, RFB_Control_L));
break;
case META:
fire(new KeyButtonEvent(isDown, RFB_Meta_L));
break;
case ALT:
fire(new KeyButtonEvent(isDown, RFB_Alt_L));
break;
case ALT_GRAPH:
fire(new KeyButtonEvent(isDown, RFB_Alt_R));
break;
default:
break;
}
}
private synchronized void fire(KeyButtonEvent msg) {
if (listener != null) {
listener.sendInputEvent(msg);
}
}
}