5

In my javafx program is a popup which lets user press keys and then it sets label accordingly. My problem is with key combinations that are shortcuts for underlying OS for example if user presses Win+R then Run.exe starts but my program should just set the label to "Win+R". My question is how to stop keyevents from triggering OS shortcuts.

Here is the relevant code.

public void showInput() {
        Set codes = new HashSet();

        Stage inputWindow = new Stage();
        GridPane pane = new GridPane();
        Scene scene = new Scene(pane);
        Label label = new Label("Here comes the pressed keys");

        scene.setOnKeyPressed(e -> {
            e.consume();
            int code = e.getCode().ordinal();

            if (label.getText().equals("Here comes the pressed keys")){
                codes.add(code);
                label.setText(String.valueOf(e.getCode().getName()));

            } else if (!codes.contains(code)){
                codes.add(code);
                label.setText(label.getText() + "+" + e.getCode().getName());
            }
        });

        scene.setOnKeyReleased(e -> {
            e.consume();
            inputWindow.close();
        });

        pane.add(label, 0, 0);

        inputWindow.setScene(scene);
        inputWindow.show();
    }

I tried e.consume() but it did not help.

griips21
  • 125
  • 1
  • 6
  • 6
    Why not just use shortcuts which don't involve the windows key? I mean, these are os-level shortcuts, your app shouldn't try to use or block them. – Andy Turner Jul 16 '17 at 21:00

2 Answers2

3

It's possible with JNA, but is a bad idea. Don't intercept well-known key combinations.

Nevertheless, below is a working example. It basically uses the SetWindowsHookEx Win32 API and then blocks the Win+R key combination in the hook callback.

import com.sun.jna.platform.win32.*;

public class Test {

    public static User32.HHOOK hHook;
    public static User32.LowLevelKeyboardProc lpfn;

    public static void main(String[] args) throws Exception {
        WinDef.HMODULE hMod = Kernel32.INSTANCE.GetModuleHandle(null);
        lpfn = new User32.LowLevelKeyboardProc() {
            boolean winKey = false;
            public WinDef.LRESULT callback(int nCode, WinDef.WPARAM wParam, WinUser.KBDLLHOOKSTRUCT lParam) {
                if (lParam.vkCode == 0x5B)
                    winKey = (lParam.flags & 0x80) == 0;
                if (lParam.flags == 0 && lParam.vkCode == 0x52 && winKey) {
                    System.out.println("Win-R pressed");
                    return new WinDef.LRESULT(-1);
                }
                return User32.INSTANCE.CallNextHookEx(hHook, nCode, wParam, lParam.getPointer());
            }
        };
        hHook = User32.INSTANCE.SetWindowsHookEx(User32.WH_KEYBOARD_LL, lpfn, hMod, 0);
        if (hHook == null) {
            System.out.println("Unable to set hook");
            return;
        }
        User32.MSG msg = new User32.MSG();
        while (User32.INSTANCE.GetMessage(msg, null, 0, 0) != 0) {
        }
        if (User32.INSTANCE.UnhookWindowsHookEx(hHook))
            System.out.println("Unhooked");
    }
}

(The needed JNA JAR dependency is net.java.dev.jna : platform)

rustyx
  • 80,671
  • 25
  • 200
  • 267
1

Not possible, Java layer is above OS layer meaning your code is handled by the JVM and the JVM is handled by the OS. So there is no way to "skip" the OS layer and send your commands directly to Java.

Shell_Leko
  • 512
  • 5
  • 13