问题
I have the below lines of code using which i am trying to read status of scroll lock.
I get the status of scroll lock when my program starts. However i am willing to get the status realtime. Please guide on the below
package assignment;
import java.awt.Toolkit;
import java.awt.event.KeyEvent;
import org.omg.PortableServer.THREAD_POLICY_ID;
public class ScrollLockOnOff {
public static void main(String[] args) throws InterruptedException
{
while(true)
{
Thread.sleep(1000);
Toolkit toolkit=Toolkit.getDefaultToolkit();
System.out.println(toolkit.getLockingKeyState(KeyEvent.VK_SCROLL_LOCK));
}
}
}
回答1:
It’s an interesting behavior, to correctly report the initial state but to depend on subsequent event processing (having a focused top level window or tray icon) for updates.
If we had a way to reset the AWT to its initial state, it should solve the issue. If we don’t find such a possibility, the straight-forward fix is to run a new JVM. Since a new JVM with the same properties will use resources in cache or even shared memory, the overhead is much smaller as it may sound. Performing the action once a second is no problem:
public class ScrollLockOnOff {
public static void main(String[] args)
throws InterruptedException, AWTException, IOException {
if(args.length == 1 && args[0].equals("VK_SCROLL_LOCK")) {
System.exit(Toolkit.getDefaultToolkit()
.getLockingKeyState(KeyEvent.VK_SCROLL_LOCK)? KeyEvent.VK_SCROLL_LOCK: 0);
return;
}
ProcessBuilder b = new ProcessBuilder(
Paths.get(System.getProperty("java.home"), "bin", "java").toString(),
"-classpath", System.getProperty("java.class.path"),
ScrollLockOnOff.class.getName(), "VK_SCROLL_LOCK"
).inheritIO();
while(true) {
Thread.sleep(1000);
int state = b.start().waitFor();
if(state != 0 && state != KeyEvent.VK_SCROLL_LOCK) {
System.err.println("failed");
break;
}
System.out.println(state == KeyEvent.VK_SCROLL_LOCK);
}
}
}
回答2:
If you want to listen for keypresses of scroll-lock implement a key listener looking for KeyEvent.VK_SCROLL_LOCK
.
Typically (and the reason for the getLockingKeyState()
method) you'd be listening for other events (e.g. up/down arrow key presses) and then would query the state of the scroll lock key to decide how to interpret that event. But it should be possible to listen for scroll-lock presses just like any other key.
I don't have a scroll-lock key on my laptop's keyboard, but when I run the KeyEventDemo.java
example from the linked tutorial I see it captures KeyEvent.VK_CAPS_LOCK
events; a "KEY PRESSED" event fires when Caps Lock is turned on, and A "KEY RELEASED" event fires when it's turned off. Scroll Lock should behave similarly.
I added the following line to the end of KeyEventDemo.java
's displayInfo()
method to see the "realtime" Caps Lock state:
displayArea.append("Caps Lock: " +
Toolkit.getDefaultToolkit().getLockingKeyState(KeyEvent.VK_CAPS_LOCK) +
newline);
If you do the same with VK_SCROLL_LOCK
you should see the scroll-lock state turn on and off when the key is pressed.
Whenever you call getLockingKeyState()
you're getting the current, "real-time" status of that key, so just call that method whenever you need to know the key's status.
回答3:
Actually, I have faced something similar and I solved by using a Robot. When you want to know whether scroll lock is on, and get the correct status of it, let the Robot press/release the button 2 times. However, (probably a bug or so), the status is not correct if you do it instantly. You will have to add a delay (not human-noticable) in order to get the proper status. That means, you will have to do it in a background thread, and not in the EDT, since this will cause EDT to freeze (when the threads sleeps, events cannot take place).
See this example (some comments inside code). It always give the correct status of scroll lock, even if window was not in focus. Also, there is a global key listener, so you know whether the scroll lock is pressed (but only fires when window has focus).
public class ScrollLockDetection {
private static final int SCROLL_LOCK = KeyEvent.VK_SCROLL_LOCK;
private JFrame frame;
public ScrollLockDetection() {
frame = new JFrame();
frame.setSize(400, 400);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.addWindowFocusListener(new WindowAdapter() {
@Override
public void windowGainedFocus(WindowEvent e) {
showScrollLockStatus();
}
});
registerGlobalScrollLockListener();
frame.setVisible(true);
}
private void registerGlobalScrollLockListener() {
Toolkit.getDefaultToolkit().addAWTEventListener(event -> {
if (event instanceof KeyEvent) {
KeyEvent keyEvent = (KeyEvent) event;
if (keyEvent.getID() == KeyEvent.KEY_RELEASED && keyEvent.getKeyCode() == KeyEvent.VK_SCROLL_LOCK) {
showScrollLockStatus();
}
}
}, AWTEvent.KEY_EVENT_MASK);
}
private void showScrollLockStatus() {
ScrollLockDetector scrollLockDetector = new ScrollLockDetector(b -> {
System.out.println("Scroll lock ON: " + b);
});
scrollLockDetector.execute();
}
class ScrollLockDetector extends SwingWorker<Boolean, Void> {
private Consumer<Boolean> consumer;
public ScrollLockDetector(Consumer<Boolean> consumer) {
this.consumer = consumer;
}
@Override
protected Boolean doInBackground() throws Exception {
//First we have to remove all global key listeners so the robot does not fire them
Toolkit toolkit = Toolkit.getDefaultToolkit();
AWTEventListener[] globalKeyListeners = toolkit.getAWTEventListeners(AWTEvent.KEY_EVENT_MASK);
while (toolkit.getAWTEventListeners(AWTEvent.KEY_EVENT_MASK).length > 0)
toolkit.removeAWTEventListener(toolkit.getAWTEventListeners(AWTEvent.KEY_EVENT_MASK)[0]);
Robot robot = new Robot();
robot.keyPress(SCROLL_LOCK);
robot.keyRelease(SCROLL_LOCK);
Thread.sleep(3);
robot.keyPress(SCROLL_LOCK);
robot.keyRelease(SCROLL_LOCK);
Thread.sleep(3);
//Re-add the global key listeners
Stream.of(globalKeyListeners).forEach(listener -> toolkit.addAWTEventListener(listener, AWTEvent.KEY_EVENT_MASK));
return toolkit.getLockingKeyState(SCROLL_LOCK);
}
@Override
protected void done() {
try {
Boolean isScrollLockOn = get();
consumer.accept(isScrollLockOn);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
new ScrollLockDetection();
});
}
}
After the declarations in comments (they should exist in question), the best way to achieve whether scroll lock is ON/OFF is to use a global key listener. When your application starts, it takes the scroll lock status from getLockingKeyState
and then everytime scroll lock is pressed, you change it.
See this complete example:
public class GlobalKeyListenerExample implements NativeKeyListener {
private static boolean scrollLock;
@Override
public void nativeKeyPressed(NativeKeyEvent e) {
}
@Override
public void nativeKeyReleased(NativeKeyEvent e) {
if (e.getKeyCode() == NativeKeyEvent.VC_SCROLL_LOCK) {
scrollLock = !scrollLock;
System.out.println("Scroll lock is:" + (scrollLock ? "ON" : "OFF"));
}
}
@Override
public void nativeKeyTyped(NativeKeyEvent e) {
}
public static void main(String[] args) {
try {
scrollLock = Toolkit.getDefaultToolkit().getLockingKeyState(KeyEvent.VK_SCROLL_LOCK);
System.out.println("Initial state of scrollock: " + (scrollLock ? "ON" : "OFF"));
GlobalScreen.registerNativeHook();
Logger logger = Logger.getLogger(GlobalScreen.class.getPackage().getName());
logger.setLevel(Level.WARNING);
// Don't forget to disable the parent handlers.
logger.setUseParentHandlers(false);
// Don't forget to disable the parent handlers.
} catch (NativeHookException ex) {
System.err.println("There was a problem registering the native hook.");
System.err.println(ex.getMessage());
System.exit(1);
}
GlobalScreen.addNativeKeyListener(new GlobalKeyListenerExample());
}
}
Now, to check if scroll lock is on, you just check the scrollLock
variable.
来源:https://stackoverflow.com/questions/61359316/trying-to-read-scroll-lock-status-using-java