com.sun.glass.ui.monocle.KeyInput Maven / Gradle / Ivy
The newest version!
/*
* Copyright (c) 2014, 2024, 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.glass.ui.monocle;
import com.sun.glass.events.KeyEvent;
import java.security.AccessController;
import java.security.PrivilegedAction;
/**
* Processes key input events based on changes to key state. Not
* thread-safe.
*/
class KeyInput {
private static KeyInput instance = new KeyInput();
private KeyState state = new KeyState();
private IntSet keys = new IntSet();
private boolean numLock = false;
private boolean capsLock = false;
private char[] NO_CHAR = { };
static KeyInput getInstance() {
return instance;
}
/** Copies the current state into the KeyState provided.
*
* @param result target into which to copy the key state
*/
void getState(KeyState result) {
state.copyTo(result);
}
/** Called from the input processor to update the key state and send
* key events.
*
* @param newState The updated key state
*/
void setState(KeyState newState) {
if (MonocleSettings.settings.traceEvents) {
MonocleTrace.traceEvent("Set %s", newState);
}
newState.getWindow(true);
// send release events
state.getKeysPressed().difference(keys, newState.getKeysPressed());
if (!keys.isEmpty()) {
for (int i = 0; i < keys.size(); i++) {
int key = keys.get(i);
dispatchKeyEvent(newState, KeyEvent.RELEASE, key);
}
}
keys.clear();
// send press events
newState.getKeysPressed().difference(keys, state.getKeysPressed());
if (!keys.isEmpty()) {
for (int i = 0; i < keys.size(); i++) {
int key = keys.get(i);
if (key == KeyEvent.VK_CAPS_LOCK) {
capsLock = !capsLock;
} else if (key == KeyEvent.VK_NUM_LOCK) {
numLock = !numLock;
} else if (key == KeyEvent.VK_C && newState.isControlPressed()) {
@SuppressWarnings("removal")
var dummy = AccessController.doPrivileged((PrivilegedAction) () -> {
if ("1".equals(System.getenv("JAVAFX_DEBUG"))) {
System.exit(0);
}
return null;
});
}
dispatchKeyEvent(newState, KeyEvent.PRESS, key);
}
}
keys.clear();
newState.copyTo(state);
}
private void dispatchKeyEvent(KeyState ks, int type, int key) {
MonocleWindow window = ks.getWindow(false);
if (window == null) {
return;
}
MonocleView view = (MonocleView) window.getView();
if (view == null) {
return;
}
char[] chars = getKeyChars(ks, key);
int modifiers = ks.getModifiers();
RunnableProcessor.runLater(() -> {
view.notifyKey(type, key, chars, modifiers);
});
if (type == KeyEvent.PRESS && chars.length > 0) {
RunnableProcessor.runLater(() -> {
view.notifyKey(KeyEvent.TYPED, key, chars, modifiers);
});
}
}
private char[] getKeyChars(KeyState state, int key) {
char c = '\000';
boolean shifted = state.isShiftPressed();
// TODO: implement configurable keyboard mappings.
// The following is only for US keyboards
if (key >= KeyEvent.VK_A && key <= KeyEvent.VK_Z) {
shifted ^= capsLock;
if (shifted) {
c = (char) (key - KeyEvent.VK_A + 'A');
} else {
c = (char) (key - KeyEvent.VK_A + 'a');
}
} else if (key >= KeyEvent.VK_NUMPAD0 && key <= KeyEvent.VK_NUMPAD9) {
if (numLock) {
c = (char) (key - KeyEvent.VK_NUMPAD0 + '0');
}
} else if (key >= KeyEvent.VK_0 && key <= KeyEvent.VK_9) {
if (shifted) {
switch (key) {
case KeyEvent.VK_0: c = ')'; break;
case KeyEvent.VK_1: c = '!'; break;
case KeyEvent.VK_2: c = '@'; break;
case KeyEvent.VK_3: c = '#'; break;
case KeyEvent.VK_4: c = '$'; break;
case KeyEvent.VK_5: c = '%'; break;
case KeyEvent.VK_6: c = '^'; break;
case KeyEvent.VK_7: c = '&'; break;
case KeyEvent.VK_8: c = '*'; break;
case KeyEvent.VK_9: c = '('; break;
}
} else {
c = (char) (key - KeyEvent.VK_0 + '0');
}
} else if (key == KeyEvent.VK_SPACE) {
c = ' ';
} else if (key == KeyEvent.VK_TAB) {
c = '\t';
} else if (key == KeyEvent.VK_ENTER) {
c = '\n';
} else if (key == KeyEvent.VK_MULTIPLY) {
c = '*';
} else if (key == KeyEvent.VK_DIVIDE) {
c = '/';
} else if (shifted) {
switch (key) {
case KeyEvent.VK_BACK_QUOTE: c = '~'; break;
case KeyEvent.VK_COMMA: c = '<'; break;
case KeyEvent.VK_PERIOD: c = '>'; break;
case KeyEvent.VK_SLASH: c = '?'; break;
case KeyEvent.VK_SEMICOLON: c = ':'; break;
case KeyEvent.VK_QUOTE: c = '\"'; break;
case KeyEvent.VK_BRACELEFT: c = '{'; break;
case KeyEvent.VK_BRACERIGHT: c = '}'; break;
case KeyEvent.VK_BACK_SLASH: c = '|'; break;
case KeyEvent.VK_MINUS: c = '_'; break;
case KeyEvent.VK_EQUALS: c = '+'; break;
} } else {
switch (key) {
case KeyEvent.VK_BACK_QUOTE: c = '`'; break;
case KeyEvent.VK_COMMA: c = ','; break;
case KeyEvent.VK_PERIOD: c = '.'; break;
case KeyEvent.VK_SLASH: c = '/'; break;
case KeyEvent.VK_SEMICOLON: c = ';'; break;
case KeyEvent.VK_QUOTE: c = '\''; break;
case KeyEvent.VK_BRACELEFT: c = '['; break;
case KeyEvent.VK_BRACERIGHT: c = ']'; break;
case KeyEvent.VK_BACK_SLASH: c = '\\'; break;
case KeyEvent.VK_MINUS: c = '-'; break;
case KeyEvent.VK_EQUALS: c = '='; break;
}
}
return c == '\000' ? NO_CHAR : new char[] { c };
}
int getKeyCodeForChar(char c, int hint) {
c = Character.toUpperCase(c);
// remove shift modification
switch (c) {
case '!': c = '1'; break;
case '@': c = '2'; break;
case '#': c = '3'; break;
case '$': c = '4'; break;
case '%': c = '5'; break;
case '^': c = '6'; break;
case '&': c = '7'; break;
case '*': c = '8'; break;
case '(': c = '9'; break;
case ')': c = '0'; break;
case '~': c = '`'; break;
case '_': c = '-'; break;
case '+': c = '='; break;
case '{': c = '['; break;
case '}': c = ']'; break;
case '|': c = '\\'; break;
case ':': c = ';'; break;
case '\"': c = '\''; break;
case '<': c = ','; break;
case '>': c = '.'; break;
case '?': c = '/'; break;
}
if (c >= 'A' && c <= 'Z') {
return (c - 'A') + KeyEvent.VK_A;
} else if (c >= '0' && c <= '9') {
return (c - '0') + KeyEvent.VK_0;
}
switch (c) {
case '`': return KeyEvent.VK_BACK_QUOTE;
case '-': return KeyEvent.VK_MINUS;
case '=': return KeyEvent.VK_EQUALS;
case '[': return KeyEvent.VK_BRACELEFT;
case ']': return KeyEvent.VK_BRACERIGHT;
case '\\': return KeyEvent.VK_BACK_SLASH;
case ';': return KeyEvent.VK_SEMICOLON;
case '\'': return KeyEvent.VK_QUOTE;
case ',': return KeyEvent.VK_COMMA;
case '.': return KeyEvent.VK_PERIOD;
case '/': return KeyEvent.VK_SLASH;
default: return KeyEvent.VK_UNDEFINED;
}
}
}