kwhat / jnativehook

Global keyboard and mouse listeners for Java.
Other
1.75k stars 348 forks source link

Block user input and postNativeEvent #407

Closed Zhemaitis closed 2 years ago

Zhemaitis commented 2 years ago

Hello, I don't know if this is the right place to ask questions, but I am stuck. Currently, I am working on a keybinding program. The program should work like this - if a user presses a specific keyboard button it should output something else. In my sample code, if the user presses the keyboard button G it should output 9. The problem now is that it outputs G9, so the question is if there is a way to block that user pressed the keyboard button to be outputed (in this case letter G)?

Thank you for your help and tips

public class GlobalKeyListenerExample implements NativeKeyListener {

    public void nativeKeyPressed(NativeKeyEvent e) {

        System.out.println("Key Pressed: " + NativeKeyEvent.getKeyText(e.getKeyCode()) + " " + NativeKeyEvent.getKeyText(e.getRawCode()));

        int someKeyCode = KeyEvent.VK_G;
        Object someKeyCodeObject = new Integer(someKeyCode);
        String keyString = KeyEvent.getKeyText((Integer) someKeyCodeObject);

        System.out.println(NativeKeyEvent.getKeyText(e.getKeyCode()));

        if (NativeKeyEvent.getKeyText(e.getKeyCode()).equalsIgnoreCase(keyString)) {
            NativeKeyEvent ev = new NativeKeyEvent(
                NativeKeyEvent.NATIVE_KEY_PRESSED,
                0x00,
                0x00,
                NativeKeyEvent.VC_9,
                NativeKeyEvent.CHAR_UNDEFINED);

            GlobalScreen.postNativeEvent(ev);
        }
        if (e.getKeyCode() == NativeKeyEvent.VC_ESCAPE) {
            try {
                GlobalScreen.unregisterNativeHook();
            } catch (NativeHookException nativeHookException) {
                nativeHookException.printStackTrace();
            }
        }
    }
    public void nativeKeyReleased(NativeKeyEvent e) {
        System.out.println("Key Released: " + NativeKeyEvent.getKeyText(e.getKeyCode()));
    }

    public void nativeKeyTyped(NativeKeyEvent e) {
        System.out.println("Key Typed: " + e.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);
        }

        GlobalScreen.addNativeKeyListener(new GlobalKeyListenerExample());
    }
}

Best regards, -zhemaitis

kwhat commented 2 years ago

so the question is if there is a way to block that user pressed the keyboard button to be outputed (in this case letter G)?

If you are using this on Windows or Mac OS, you can prevent event propagation is most cases. Notice, you must use a VoidDispatchService, one currently exists in the 2.2 codebase so the docs need updating.

Zhemaitis commented 2 years ago

After code execution, an exception appears. Googled this problem and it sounds like illegal action was performed. Is there a way to solve this problem right now?

java.lang.reflect.InaccessibleObjectException: Unable to make field private short com.github.kwhat.jnativehook.NativeInputEvent.reserved accessible: module com.github.kwhat.jnativehook does not "opens com.github.kwhat.jnativehook" to module NativeKeyListener

kwhat commented 2 years ago

IDK what you did, the example compiles on works for me. I updated the markdown file to use the inertial void dispatcher.

import com.github.kwhat.jnativehook.GlobalScreen;
import com.github.kwhat.jnativehook.NativeHookException;
import com.github.kwhat.jnativehook.NativeInputEvent;
import com.github.kwhat.jnativehook.dispatcher.VoidDispatchService;
import com.github.kwhat.jnativehook.keyboard.NativeKeyEvent;
import com.github.kwhat.jnativehook.keyboard.NativeKeyListener;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.AbstractExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;

public class ConsumeEvent implements NativeKeyListener {
    public ConsumeEvent() throws NativeHookException {
        // Create custom logger and level.
        Logger logger = Logger.getLogger(GlobalScreen.class.getPackage().getName());
        logger.setLevel(Level.WARNING);

        GlobalScreen.setEventDispatcher(new VoidDispatchService());
        GlobalScreen.registerNativeHook();

        GlobalScreen.addNativeKeyListener(this);
    }

    public void nativeKeyPressed(NativeKeyEvent e) {
        if (e.getKeyCode() == NativeKeyEvent.VC_B) {
            System.out.print("Attempting to consume B event...\t");
            try {
                Field f = NativeInputEvent.class.getDeclaredField("reserved");
                f.setAccessible(true);
                f.setShort(e, (short) 0x01);

                System.out.print("[ OK ]\n");

                NativeKeyEvent ev = new NativeKeyEvent(
                    NativeKeyEvent.NATIVE_KEY_PRESSED,
                    0x00,
                    0x00,
                    NativeKeyEvent.VC_9,
                    NativeKeyEvent.CHAR_UNDEFINED);

                GlobalScreen.postNativeEvent(ev);
            }
            catch (Exception ex) {
                System.out.print("[ !! ]\n");
                ex.printStackTrace();
            }
        }
    }

    public void nativeKeyReleased(NativeKeyEvent e) {
        if (e.getKeyCode() == NativeKeyEvent.VC_B) {
            System.out.print("Attempting to consume B event...\t");
            try {
                Field f = NativeInputEvent.class.getDeclaredField("reserved");
                f.setAccessible(true);
                f.setShort(e, (short) 0x01);

                System.out.print("[ OK ]\n");

                NativeKeyEvent ev = new NativeKeyEvent(
                    NativeKeyEvent.NATIVE_KEY_RELEASED,
                    0x00,
                    0x00,
                    NativeKeyEvent.VC_9,
                    NativeKeyEvent.CHAR_UNDEFINED);

                GlobalScreen.postNativeEvent(ev);
            }
            catch (Exception ex) {
                System.out.print("[ !! ]\n");
                ex.printStackTrace();
            }
        }
    }

    public void nativeKeyTyped(NativeKeyEvent e) { /* Unimplemented */ }

    public static void main(String [] args) throws NativeHookException {
        new ConsumeEvent();
    }
}
sghpjuikit commented 2 years ago

After code execution, an exception appears. Googled this problem and it sounds like illegal action was performed. Is there a way to solve this problem right now?

java.lang.reflect.InaccessibleObjectException: Unable to make field private short com.github.kwhat.jnativehook.NativeInputEvent.reserved accessible: module com.github.kwhat.jnativehook does not "opens com.github.kwhat.jnativehook" to module NativeKeyListener

You are using Java modules and/or run Java with forbidden illegal access. Look into module system. You can fix this by adding the appropriate add-opens JVM argument.