Registering multi-button presses with JNativeHook
I've looked at the examples and also tried googling for a few hours, but I can't seem to find a question that covers what I'm asking.
If I wanted to do something like
W + A at the same time, and log this as a separate key event, not just W and A separately, how would I do this with JNativeHook? Is it because I missed a class somewhere that covers this, or is there some workaround to only read one key?
I am trying to do this in the console (so I am using this library, not Swing).
I took their example and wanted to try changing it:
import org.jnativehook.GlobalScreen;
import org.jnativehook.NativeHookException;
import org.jnativehook.keyboard.NativeKeyEvent;
import org.jnativehook.keyboard.NativeKeyListener;
public class GlobalKeyListener implements NativeKeyListener {
@Override
public void nativeKeyPressed(NativeKeyEvent e) {
System.out.println("Key Pressed: " + NativeKeyEvent.getKeyText(e.getKeyCode()));
if (e.getKeyCode() == NativeKeyEvent.VC_ESCAPE) {
GlobalScreen.unregisterNativeHook();
}
}
@Override
public void nativeKeyReleased(NativeKeyEvent e) {
System.out.println("Key Released: " + NativeKeyEvent.getKeyText(e.getKeyCode()));
}
@Override
public void nativeKeyTyped(NativeKeyEvent e) {
System.out.println("Key Typed: " + NativeKeyEvent.getKeyText(e.getKeyCode()));
}
public static void main(String[] args) {
try {
GlobalScreen.registerNativeHook();
} catch (NativeHookException ex) {
System.err.println("There was a problem registering the native hook.");
System.err.println(ex.getMessage());
System.exit(1);
}
//Construct the example object and initialze native hook.
GlobalScreen.getInstance().addNativeKeyListener(new GlobalKeyListener());
}
}
source to share
You need to listen for each individual keypress and unlock event for the desired combination and set some kind of flag as each of the keys is pressed. If after pressing 1 of the desired keys and the flag condition is met, you can do what you need to do when those keys are compressed together. It is not possible to get one event for two keys without creating a custom keyboard driver. If you want to suppress W and A events until both are clicked, check out the unsupported consumption events on the wiki. Note that event suppression is only available for Windows and OS X targets, and suppressed events will not be delivered to other applications.
This is not the prettiest example, but it should do what you are looking for.
private short hotKeyFlag = 0x00;
private static final short MASK_A = 1 << 0;
private static final short MASK_W = 1 << 1;
...
@Override
public void nativeKeyPressed(NativeKeyEvent e) {
if (e.getKeyCode() == NativeKeyEvent.VC_ESCAPE) {
GlobalScreen.unregisterNativeHook();
}
else if (e.getKeyCode() == NativeKeyEvent.VK_A) {
hotKeyFlag &= MASK_A;
// Check the mask and do work.
if (hotKeyFlag == MASK_A & MASK_W) {
// Fire Shortcut.
}
}
else if (e.getKeyCode() == NativeKeyEvent.VK_W) {
hotKeyFlag &= MASK_W;
// Check the mask and do work.
if (hotKeyFlag == MASK_A & MASK_W) {
// Fire Shortcut.
}
}
}
@Override
public void nativeKeyReleased(NativeKeyEvent e) {
if (e.getKeyCode() == NativeKeyEvent.VK_A) {
hotKeyFlag ^= MASK_A;
}
else if (e.getKeyCode() == NativeKeyEvent.VK_W) {
hotKeyFlag ^= MASK_W;
}
}
source to share
This is my answer: -
private boolean a = false, w = false;
@Override
public void nativeKeyPressed(NativeKeyEvent e) {
if (e.getKeyCode() == NativeKeyEvent.VC_A) {
a = true;
if (w) {
System.out.println("W+A");
} else {//remove this else only for testing
System.out.println("Only A");
}
} else if (e.getKeyCode() == NativeKeyEvent.VC_W) {
w = true;
if (a) {
System.out.println("A+W");
} else {//remove this else only for testing
System.out.println("Only W");
}
}
}
@Override
public void nativeKeyReleased(NativeKeyEvent e) {
if (e.getKeyCode() == NativeKeyEvent.VC_A) {
a = false;
} else if (e.getKeyCode() == NativeKeyEvent.VC_W) {
w = false;
}
}
@Override
public void nativeKeyTyped(NativeKeyEvent e) {
//System.out.println("Key Typed: " + e.getKeyText(e.getKeyCode()));
}
source to share