Skip to content
Permalink
Browse files
8259680: Need API to query states of CAPS LOCK and NUM LOCK keys
Reviewed-by: jvos
Backport-of: 217a8cb
  • Loading branch information
kevinrushforth committed May 5, 2021
1 parent 81feeb2 commit ea4f880600f747fc5334504d5ab71c019e45ba61
@@ -66,6 +66,13 @@
@Native public final static int MODIFIER_BUTTON_SECONDARY = 1 << 6;
@Native public final static int MODIFIER_BUTTON_MIDDLE = 1 << 7;

/*
* Key lock state
*/
@Native public static final int KEY_LOCK_OFF = 0;
@Native public static final int KEY_LOCK_ON = 1;
@Native public static final int KEY_LOCK_UNKNOWN = -1;

/*
* Key event key codes.
*/
@@ -36,6 +36,7 @@
import java.util.List;
import java.util.Map;
import java.util.LinkedList;
import java.util.Optional;

public abstract class Application {

@@ -744,4 +745,22 @@ public final boolean supportsSystemMenu() {
public static int getKeyCodeForChar(char c) {
return application._getKeyCodeForChar(c);
}

protected int _isKeyLocked(int keyCode) {
// Overridden in subclasses
return KeyEvent.KEY_LOCK_UNKNOWN;
}

public final Optional<Boolean> isKeyLocked(int keyCode) {
checkEventThread();
int lockState = _isKeyLocked(keyCode);
switch (lockState) {
case KeyEvent.KEY_LOCK_OFF:
return Optional.of(false);
case KeyEvent.KEY_LOCK_ON:
return Optional.of(true);
default:
return Optional.empty();
}
}
}
@@ -478,4 +478,7 @@ protected boolean _supportsInputMethods() {
@Override
protected native int _getKeyCodeForChar(char c);

@Override
protected native int _isKeyLocked(int keyCode);

}
@@ -391,4 +391,7 @@ public String getDataDirectory() {

@Override
protected native int _getKeyCodeForChar(char c);

@Override
protected native int _isKeyLocked(int keyCode);
}
@@ -358,4 +358,7 @@ public String getDataDirectory() {

@Override
protected native int _getKeyCodeForChar(char c);

@Override
protected native int _isKeyLocked(int keyCode);
}
@@ -67,6 +67,7 @@
import com.sun.scenario.animation.AbstractPrimaryTimer;
import com.sun.scenario.effect.FilterContext;
import com.sun.scenario.effect.Filterable;
import java.util.Optional;

/**
* A stubbed out Toolkit that provides no useful implementation. This is used
@@ -371,6 +372,11 @@ public KeyCode getPlatformShortcutKey() {
throw new UnsupportedOperationException("Not supported yet.");
}

@Override
public Optional<Boolean> isKeyLocked(KeyCode keyCode) {
throw new UnsupportedOperationException("Not supported yet.");
}

@Override
public FileChooserResult showFileChooser(TKStage ownerWindow,
String title,
@@ -94,6 +94,7 @@
import com.sun.scenario.effect.Color4f;
import com.sun.scenario.effect.FilterContext;
import com.sun.scenario.effect.Filterable;
import java.util.Optional;


public abstract class Toolkit {
@@ -873,6 +874,13 @@ public KeyCode getPlatformShortcutKey() {
return PlatformUtil.isMac() ? KeyCode.META : KeyCode.CONTROL;
}

/**
* Returns the lock state for the given keyCode.
* @param keyCode the keyCode to check
* @return the lock state for the given keyCode.
*/
public abstract Optional<Boolean> isKeyLocked(KeyCode keyCode);

public abstract FileChooserResult showFileChooser(
TKStage ownerWindow,
String title,
@@ -73,6 +73,7 @@
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Supplier;
import java.util.Optional;
import com.sun.glass.ui.Application;
import com.sun.glass.ui.Clipboard;
import com.sun.glass.ui.ClipboardAssistance;
@@ -1192,6 +1193,24 @@ public boolean isMSAASupported() {
return GraphicsPipeline.getPipeline().isMSAASupported();
}

// Returns the glass keycode for the given JavaFX KeyCode.
// This method only converts lock state KeyCode values
private int toGlassKeyCode(KeyCode keyCode) {
switch (keyCode) {
case CAPS:
return com.sun.glass.events.KeyEvent.VK_CAPS_LOCK;
case NUM_LOCK:
return com.sun.glass.events.KeyEvent.VK_NUM_LOCK;
default:
return com.sun.glass.events.KeyEvent.VK_UNDEFINED;
}
}

@Override
public Optional<Boolean> isKeyLocked(KeyCode keyCode) {
return Application.GetApplication().isKeyLocked(toGlassKeyCode(keyCode));
}

static TransferMode clipboardActionToTransferMode(final int action) {
switch (action) {
case Clipboard.ACTION_NONE:
@@ -25,10 +25,12 @@

package javafx.application;

import com.sun.javafx.application.PlatformImpl;
import com.sun.javafx.tk.Toolkit;
import java.util.Optional;
import javafx.beans.property.ReadOnlyBooleanProperty;
import javafx.beans.property.ReadOnlyBooleanWrapper;
import com.sun.javafx.application.PlatformImpl;
import javafx.scene.input.KeyCode;

/**
* Application platform support class.
@@ -319,6 +321,43 @@ public static void exitNestedEventLoop(Object key, Object rval) {
Toolkit.getToolkit().exitNestedEventLoop(key, rval);
}

/**
* Returns a flag indicating whether the key corresponding to {@code keyCode}
* is in the locked (or "on") state.
* {@code keyCode} must be one of: {@link KeyCode#CAPS} or
* {@link KeyCode#NUM_LOCK}.
* If the underlying system is not able to determine the state of the
* specified {@code keyCode}, an empty {@code Optional} is returned.
* If the keyboard attached to the system doesn't have the specified key,
* an {@code Optional} containing {@code false} is returned.
* This method must be called on the JavaFX Application thread.
*
* @param keyCode the {@code KeyCode} of the lock state to query
*
* @return the lock state of the key corresponding to {@code keyCode},
* or an empty {@code Optional} if the system cannot determine its state
*
* @throws IllegalArgumentException if {@code keyCode} is not one of the
* valid {@code KeyCode} values
*
* @throws IllegalStateException if this method is called on a thread
* other than the JavaFX Application Thread
*
* @since 11.0.12
*/
public static Optional<Boolean> isKeyLocked(KeyCode keyCode) {
Toolkit.getToolkit().checkFxUserThread();

switch (keyCode) {
case CAPS:
case NUM_LOCK:
break;
default:
throw new IllegalArgumentException("Invalid KeyCode");
}
return Toolkit.getToolkit().isKeyLocked(keyCode);
}

/**
* Checks whether a nested event loop is running, returning true to indicate
* that one is, and false if there are no nested event loops currently
@@ -29,6 +29,7 @@
#include <glib.h>
#include "glass_general.h"
#include <gdk/gdkkeysyms.h>
#include <X11/XKBlib.h>

static gboolean key_initialized = FALSE;
static GHashTable *keymap;
@@ -343,4 +344,63 @@ JNIEXPORT jint JNICALL Java_com_sun_glass_ui_gtk_GtkApplication__1getKeyCodeForC
return gdk_keyval_to_glass(keyval);
}

/*
* Function to determine whether the Xkb extention is available. This is a
* precaution against X protocol errors, although it should be available on all
* Linux systems.
*/

static Bool xkbInitialized = False;
static Bool xkbAvailable = False;

static Bool isXkbAvailable(Display *display) {
if (!xkbInitialized) {
int xkbMajor = XkbMajorVersion;
int xkbMinor = XkbMinorVersion;
xkbAvailable = XkbQueryExtension(display, NULL, NULL, NULL, &xkbMajor, &xkbMinor);
xkbInitialized = True;
}
return xkbAvailable;
}

/*
* Class: com_sun_glass_ui_gtk_GtkApplication
* Method: _isKeyLocked
* Signature: (I)I
*/
JNIEXPORT jint JNICALL Java_com_sun_glass_ui_gtk_GtkApplication__1isKeyLocked
(JNIEnv * env, jobject obj, jint keyCode)
{
Display* display = gdk_x11_display_get_xdisplay(gdk_display_get_default());
if (!isXkbAvailable(display)) {
return com_sun_glass_events_KeyEvent_KEY_LOCK_UNKNOWN;
}

Atom keyCodeAtom = None;
switch (keyCode) {
case com_sun_glass_events_KeyEvent_VK_CAPS_LOCK:
keyCodeAtom = XInternAtom(display, "Caps Lock", True);
break;

case com_sun_glass_events_KeyEvent_VK_NUM_LOCK:
keyCodeAtom = XInternAtom(display, "Num Lock", True);
break;
}

if (keyCodeAtom == None) {
return com_sun_glass_events_KeyEvent_KEY_LOCK_UNKNOWN;
}

Bool isLocked = False;
if (XkbGetNamedIndicator(display, keyCodeAtom, NULL, &isLocked, NULL, NULL)) {
if (isLocked) {
return com_sun_glass_events_KeyEvent_KEY_LOCK_ON;
} else {
return com_sun_glass_events_KeyEvent_KEY_LOCK_OFF;
}
}

return com_sun_glass_events_KeyEvent_KEY_LOCK_UNKNOWN;
}

} // extern "C"
@@ -390,3 +390,25 @@ BOOL GetMacKey(jint javaKeyCode, unsigned short *outMacKeyCode)
return [GlassApplication getKeyCodeForChar:c];
}

/*
* Class: com_sun_glass_ui_mac_MacApplication
* Method: _isKeyLocked
* Signature: (I)I
*/
JNIEXPORT jint JNICALL Java_com_sun_glass_ui_mac_MacApplication__1isKeyLocked
(JNIEnv * env, jobject obj, jint keyCode)
{
NSUInteger mask = 0;
switch (keyCode) {
case com_sun_glass_events_KeyEvent_VK_CAPS_LOCK:
mask = NSEventModifierFlagCapsLock;
break;

// Caps lock is the only locking key supported on macOS
default:
return com_sun_glass_events_KeyEvent_KEY_LOCK_UNKNOWN;
}
NSUInteger modifierFlags = [NSEvent modifierFlags];
return (modifierFlags & mask) ? com_sun_glass_events_KeyEvent_KEY_LOCK_ON
: com_sun_glass_events_KeyEvent_KEY_LOCK_OFF;
}
@@ -247,5 +247,27 @@ JNIEXPORT jint JNICALL Java_com_sun_glass_ui_win_WinApplication__1getKeyCodeForC
return WindowsKeyToJavaKey(vkey);
}

/*
* Class: com_sun_glass_ui_win_WinApplication
* Method: _isKeyLocked
* Signature: (I)I
*/
JNIEXPORT jint JNICALL Java_com_sun_glass_ui_win_WinApplication__1isKeyLocked
(JNIEnv * env, jobject obj, jint keyCode)
{
SHORT keyState = 0;
switch (keyCode) {
case com_sun_glass_events_KeyEvent_VK_CAPS_LOCK:
keyState = ::GetKeyState(VK_CAPITAL);
break;

case com_sun_glass_events_KeyEvent_VK_NUM_LOCK:
keyState = ::GetKeyState(VK_NUMLOCK);
break;

default:
return com_sun_glass_events_KeyEvent_KEY_LOCK_UNKNOWN;
}
return (keyState & 0x1) ? com_sun_glass_events_KeyEvent_KEY_LOCK_ON
: com_sun_glass_events_KeyEvent_KEY_LOCK_OFF;
}
@@ -750,6 +750,11 @@ public KeyCode getPlatformShortcutKey() {
return platformShortcutKey;
}

@Override
public Optional<Boolean> isKeyLocked(KeyCode keyCode) {
return Optional.empty();
}

private DndDelegate dndDelegate;
public void setDndDelegate(DndDelegate dndDelegate) {
this.dndDelegate = dndDelegate;

1 comment on commit ea4f880

@openjdk-notifier

This comment has been minimized.

Copy link

@openjdk-notifier openjdk-notifier bot commented on ea4f880 May 5, 2021

Please sign in to comment.