Skip to content

Commit c4961b1

Browse files
Use XkbGetNamedIndicator on Linux instead of relying on the (unreliable) GDK method.
1 parent cb0e10a commit c4961b1

File tree

2 files changed

+46
-19
lines changed

2 files changed

+46
-19
lines changed

modules/javafx.graphics/src/main/native-glass/gtk/glass_key.cpp

+41-13
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
#include <glib.h>
3030
#include "glass_general.h"
3131
#include <gdk/gdkkeysyms.h>
32+
#include <X11/XKBlib.h>
3233

3334
static gboolean key_initialized = FALSE;
3435
static GHashTable *keymap;
@@ -345,6 +346,25 @@ JNIEXPORT jint JNICALL Java_com_sun_glass_ui_gtk_GtkApplication__1getKeyCodeForC
345346
return gdk_keyval_to_glass(keyval);
346347
}
347348

349+
/*
350+
* Function to determine whether the Xkb extention is available. This is a
351+
* precaution against X protocol errors, although it should be available on all
352+
* Linux systems.
353+
*/
354+
355+
static Bool xkbInitialized = False;
356+
static Bool xkbAvailable = False;
357+
358+
static Bool isXkbAvailable(Display *display) {
359+
if (!xkbInitialized) {
360+
int xkbMajor = XkbMajorVersion;
361+
int xkbMinor = XkbMinorVersion;
362+
xkbAvailable = XkbQueryExtension(display, NULL, NULL, NULL, &xkbMajor, &xkbMinor);
363+
xkbInitialized = True;
364+
}
365+
return xkbAvailable;
366+
}
367+
348368
/*
349369
* Class: com_sun_glass_ui_gtk_GtkApplication
350370
* Method: _isKeyLocked
@@ -353,28 +373,36 @@ JNIEXPORT jint JNICALL Java_com_sun_glass_ui_gtk_GtkApplication__1getKeyCodeForC
353373
JNIEXPORT jint JNICALL Java_com_sun_glass_ui_gtk_GtkApplication__1isKeyLocked
354374
(JNIEnv * env, jobject obj, jint keyCode)
355375
{
356-
#ifdef GLASS_GTK3
357-
GdkKeymap *keyMap = gdk_keymap_get_default();
358-
gboolean lockState = FALSE;
376+
Display* display = gdk_x11_display_get_xdisplay(gdk_display_get_default());
377+
if (!isXkbAvailable(display)) {
378+
return com_sun_glass_events_KeyEvent_KEY_LOCK_UNKNOWN;
379+
}
380+
381+
Atom atom = None;
359382
switch (keyCode) {
360383
case com_sun_glass_events_KeyEvent_VK_CAPS_LOCK:
361-
lockState = gdk_keymap_get_caps_lock_state(keyMap);
384+
atom = XInternAtom(display, "Caps Lock", True);
362385
break;
363386

364387
case com_sun_glass_events_KeyEvent_VK_NUM_LOCK:
365-
lockState = gdk_keymap_get_num_lock_state(keyMap);
388+
atom = XInternAtom(display, "Num Lock", True);
366389
break;
390+
}
367391

368-
default:
369-
return com_sun_glass_events_KeyEvent_KEY_LOCK_UNKNOWN;
392+
if (atom == None) {
393+
return com_sun_glass_events_KeyEvent_KEY_LOCK_UNKNOWN;
370394
}
371-
return lockState ? com_sun_glass_events_KeyEvent_KEY_LOCK_ON
372-
: com_sun_glass_events_KeyEvent_KEY_LOCK_OFF;
373-
#else /* GLASS_GTK3 */
374-
// Caps Lock detection is not reliable in GTK 2, and Num Lock detection is
375-
// only available in GTK 3.
395+
396+
Bool isLocked = False;
397+
if (XkbGetNamedIndicator(display, atom, NULL, &isLocked, NULL, NULL)) {
398+
if (isLocked) {
399+
return com_sun_glass_events_KeyEvent_KEY_LOCK_ON;
400+
} else {
401+
return com_sun_glass_events_KeyEvent_KEY_LOCK_OFF;
402+
}
403+
}
404+
376405
return com_sun_glass_events_KeyEvent_KEY_LOCK_UNKNOWN;
377-
#endif /* GLASS_GTK3 */
378406
}
379407

380408
} // extern "C"

tests/system/src/test/java/test/robot/javafx/application/KeyLockedTest.java

+5-6
Original file line numberDiff line numberDiff line change
@@ -100,10 +100,8 @@ public void testCanReadCapsLockState() {
100100
// Check that we don't get an exception or a null optional.
101101
Optional<Boolean> capsLockState = Platform.isKeyLocked(KeyCode.CAPS);
102102
assertNotNull(capsLockState);
103-
// A result should always be present on Windows and Mac
104-
if (PlatformUtil.isWindows() || PlatformUtil.isMac()) {
105-
assertTrue(capsLockState.isPresent());
106-
}
103+
// A result should always be present
104+
assertTrue(capsLockState.isPresent());
107105
});
108106
}
109107

@@ -113,10 +111,11 @@ public void testCanReadNumLockState() {
113111
// Check that we don't get an exception or a null optional.
114112
Optional<Boolean> numLockState = Platform.isKeyLocked(KeyCode.NUM_LOCK);
115113
assertNotNull(numLockState);
116-
// A result should always be present on Windows and never on Mac
117-
if (PlatformUtil.isWindows()) {
114+
// A result should always be present on Windows and Linux
115+
if (PlatformUtil.isWindows() || PlatformUtil.isLinux()) {
118116
assertTrue(numLockState.isPresent());
119117
}
118+
// A result should never be present on Mac
120119
if (PlatformUtil.isMac()) {
121120
assertFalse(numLockState.isPresent());
122121
}

0 commit comments

Comments
 (0)