Navigation Menu

Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

8259680: Need API to query states of CAPS LOCK and NUM LOCK keys #4

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -66,6 +66,13 @@ public class KeyEvent {
@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.
*/
Expand Down
Expand Up @@ -36,6 +36,7 @@
import java.util.List;
import java.util.Map;
import java.util.LinkedList;
import java.util.Optional;

public abstract class Application {

Expand Down Expand Up @@ -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();
}
}
}
Expand Up @@ -478,4 +478,7 @@ protected boolean _supportsInputMethods() {
@Override
protected native int _getKeyCodeForChar(char c);

@Override
protected native int _isKeyLocked(int keyCode);

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

@Override
protected native int _getKeyCodeForChar(char c);

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

@Override
protected native int _getKeyCodeForChar(char c);

@Override
protected native int _isKeyLocked(int keyCode);
}
Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand Down
Expand Up @@ -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 {
Expand Down Expand Up @@ -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,
Expand Down
Expand Up @@ -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;
Expand Down Expand Up @@ -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:
Expand Down
Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down
60 changes: 60 additions & 0 deletions modules/javafx.graphics/src/main/native-glass/gtk/glass_key.cpp
Expand Up @@ -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;
Expand Down Expand Up @@ -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"
22 changes: 22 additions & 0 deletions modules/javafx.graphics/src/main/native-glass/mac/GlassKey.m
Expand Up @@ -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;
}
22 changes: 22 additions & 0 deletions modules/javafx.graphics/src/main/native-glass/win/KeyTable.cpp
Expand Up @@ -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;
}
Expand Up @@ -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;
Expand Down