JDK-8259680 : Need API to query states of CAPS LOCK and NUM LOCK keys
  • Type: Enhancement
  • Component: javafx
  • Sub-Component: scenegraph
  • Affected Version: 8u271,openjfx15
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2021-01-13
  • Updated: 2021-05-05
  • Resolved: 2021-02-01
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 8 Other
8u281Fixed openjfx11.0.12Fixed
Related Reports
Blocks :  
CSR :  
Duplicate :  
Description
We would like to add a JavaFX API to get the state of CAPS LOCK, NUM LOCK, or SCROLL LOCK.

AWT already has an API to do this:

boolean java.awt.ToolKit::getLockingKeyState���(int keyCode)

https://docs.oracle.com/en/java/javase/15/docs/api/java.desktop/java/awt/Toolkit.html#getLockingKeyState%28int%29

We need something similar in JavaFX. Among other things, it would allow an application to inform the user that caps lock was enabled for passwords or other usages where the keyboard input might not be echoed. See JDK-8090732.

A similar FX API would be something like:

boolean java.application.Platform::isKeyLocked(KeyCode keyCode)
Comments
Changeset: 217a8cba Author: Kevin Rushforth <kcr@openjdk.org> Date: 2021-02-01 13:29:10 +0000 URL: https://git.openjdk.java.net/jfx/commit/217a8cba
01-02-2021

After the discussion on the openjfx-dev mailing list, I am going with the suggestion of returning Optional<Boolean> as a better alternative to throwing UnsupportedOperationException to express the condition where the state cannot be determined. So the API will look more like this: * 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, * {@code Boolean.FALSE } is returned. ... public static Optional<Boolean> isKeyLocked(KeyCode keyCode);
19-01-2021

Here is the new javadoc for the change to throw UnsupportedOperationException if we can't determine the state of the key: * If the underlying system is not able to determine the state of the * specified {@code keyCode}, an UnsupportedOperationException is thrown. * If the keyboard attached to the system doesn't have the specified key, * {@code false} is returned. ... * @throws UnsupportedOperationException if the underlying system is not * able to determine the state of the specified {@code keyCode}
15-01-2021

I agree that we don't want the potential case where we might return false when it is active (an exception is definitely better in that case). My quick prototype on Linux suggests that there is a potential problem when using GTK 2 where caps lock isn't tracked properly in some cases (if it is locked one before starting the program it reports off), so it might be best to throw an exception if the platform is unable to read a specific state.
15-01-2021

Hmm.. I just tried a keyboard with NUM_LOCK on macOS and it has no effect anyway. So maybe returning false is consistent with the key no being present in that case. Perhaps it just comes down to the wording. As long as the system isn't behaving as if NumLock is active, then returning false is fine. The wording above suggested to me that there could be cases where you just couldn't tell if NumLock was on when it was. In that case I think throwing the exception rather than returning the potentially incorrect false makes more sense. If that can't ever happen, I have no objection to avoiding the exception and returning false.
15-01-2021

Returning false is more in line with other APIs, although since this isn't a property you can listen to, that argument doesn't really hold. I wouldn't be opposed to throwing UnsupportedOperationException in case the system doesn't support it (e.g., NUM_LOCK on macOS). I don't like the fact that AWT throws an exception if the keyboard in question doesn't have that key, so I wouldn't be in favor of that. If your keyboard doesn't have num-lock, for example, returning false for the state seems perfectly consistent.
15-01-2021

Is there a reason you suggested this: * If the keyboard attached to the system doesn't have the specified key * or if the underlying system does not provide a way to determine its state, * {@code false} is returned. Rather than throw UnsupportedOperationException as the AWT equivalent API does? I don't like the idea that this API might return incorrect information without any way of knowing.
15-01-2021

I note that this was originally filed as JDK-8090882. Since this new issue has more information, I will close the older RFE as a duplicate.
15-01-2021

In addition to a "global" getter for the state, we could consider storing the state as part of each KeyEvent, but that would be a larger API surface, and doesn't seem as natural a fit.
14-01-2021

This is a relatively straight-forward RFE. The API might look something like this: javafx.application.Platform: /** * 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}, * {@link KeyCode.NUM_LOCK}, or {@link KeyCode.SCROLL_LOCK}. * If the keyboard attached to the system doesn't have the specified key * or if the underlying system does not provide a way to determine its state, * {@code false} is returned. * This method must be called on the JavaFX Application thread. * * @param keyCode the KeyCode of the lock state to query * * @throws IllegalArgumentException if {@code keyCode} is not one of the * valid KeyCode values. * * @throws IllegalStateException if this method is called on a thread * other than the JavaFX Application Thread. * * @return {@code true} if the key corresponding to {@code keyCode} * is in the locked or "on" state; {@code false} otherwise * * @since 17 */ public static boolean isKeyLocked(KeyCode keyCode);
14-01-2021