28

Is there any way or a library to get a system-wide (global) keyboard shortcut to perform an action in a Java application?

dermoritz
  • 12,519
  • 25
  • 97
  • 185
fabiopedrosa
  • 2,521
  • 7
  • 29
  • 42

7 Answers7

18

I am the author of JIntellitype and I can tell you for a fact this must be done natively in DLL and called from Java JNI just like JIntellitype does it. This is an OS level hook that is not implemented in the JDK so libraries like JIntellitype and jxGrabKey must be used. As far as I know no one has written one for OSX yet.

JIntellitype is open source on Github, so if you want an idea of how it works just check out the source code

ItamarG3
  • 4,092
  • 6
  • 31
  • 44
Melloware
  • 10,435
  • 2
  • 32
  • 62
15

I just found https://github.com/kwhat/jnativehook

Seems to be cross platform.

Here's their sample code for listening for key presses:

import org.jnativehook.GlobalScreen;
import org.jnativehook.NativeHookException;
import org.jnativehook.keyboard.NativeKeyEvent;
import org.jnativehook.keyboard.NativeKeyListener;

public class GlobalKeyListenerExample implements NativeKeyListener {
    public void nativeKeyPressed(NativeKeyEvent e) {
        System.out.println("Key Pressed: " + NativeKeyEvent.getKeyText(e.getKeyCode()));

        if (e.getKeyCode() == NativeKeyEvent.VC_ESCAPE) {
            GlobalScreen.unregisterNativeHook();
        }
    }

    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());
    }
}

Checking for modifiers is based on bit masks (stuff we all should know but always forget :-P):

    boolean isAltPressed = (e.getModifiers() & NativeKeyEvent.ALT_MASK) != 0;
    boolean isShiftPressed = (e.getModifiers() & NativeKeyEvent.SHIFT_MASK) != 0;

This you could combine with KeyCode:

if (e.getKeyCode() == NativeKeyEvent.VK_2 && isShiftPressed && isAltPressed){...}

This is modified example from here

You should also modify the default logging behavior otherwise it will spam the console:

// Get the logger for "org.jnativehook" and set the level to warning.
Logger logger = Logger.getLogger(GlobalScreen.class.getPackage().getName());
logger.setLevel(Level.WARNING);

// Don't forget to disable the parent handlers.
logger.setUseParentHandlers(false);

Code example is from here

dermoritz
  • 12,519
  • 25
  • 97
  • 185
  • I've used this starting 2017, and after a while, I realized that the Tilde key was disabled systemwide. I also observed rare hard crashes that stopped when I stopped using this library. ---- This is not a definitive statement, but my personal consequence was to make the default hotkey feature of my application optional, so that the library would not be activated except if absolutely necessary. I'm now about to try the same thing again with https://github.com/melloware/jintellitype, let's see how I fare. – Dreamspace President Jan 03 '23 at 05:33
  • 1
    @DreamspacePresident i am using this without any problems. i use escape to minimize my application (into sys tray) and a combination with ctrl, alt to bring it up again. other keys in use are normal charatcters. but i never updated the lib - still using 2.1.0 (2.2.2 is current version) – dermoritz Jan 03 '23 at 09:37
13

There is not, but in windows you can use this:

jintellitype

Unfortunately there is nothing I'm aware of for Linux and OSX, probably that's why it doesn't come with java out of the box.

If you find for the other platforms post it here please :)

Just for couriosity, what are you doing with that?

Community
  • 1
  • 1
OscarRyz
  • 196,001
  • 113
  • 385
  • 569
  • thanks for your reply. I wanted this feature, so I the user could bring a popup window from anywhere on the system. Its something very usual in windows apps, but I wanted cross-platform support. – fabiopedrosa Jan 19 '09 at 21:03
  • Yeah, well, I guess we will have to wait. I've heard this is quite easy to do in Linux and OSX, I don't know why a half way platform 3rd party has been coded already. Sure it won't be supported by Sun. – OscarRyz Jan 20 '09 at 16:00
  • 1
    Jintellitype mentions JxGrabKey (http://sourceforge.net/projects/jxgrabkey/) project which offers the same feature for Linux. – Domchi Dec 05 '09 at 14:41
2

UPDATE: I don't know if you can hook events from OUTSIDE the JVM. I think a Swing/AWT component must have focus for this to work.

You'll want to hook in the Java AWT Event Queue to be absolutely sure you can get a global (jvm wide) keypress.

Use

EventQueue ev = Toolkit.getSystemEventQueue();
// MyCustomEventQueue extends EventQueue and processes keyboard events in the dispatch
ev.push(new MyCustomEventQueue());

class MyEventQueue extends EventQueue
{
    protected void dispatchEvent(AWTEvent event)
    {
       // all AWTEvents can be indentified by type, KeyEvent, MouseEvent, etc
       // look for KeyEvents and match against you hotkeys / callbacks
    }
}

I think there may be other ways to accomplish global key presses with action maps. I've actually used the above mether

basszero
  • 29,624
  • 9
  • 57
  • 79
2

For windows you need a keyboard hook dll. You can initialize your dll from java, which will cause it to register the listener. You'll get what you need. Check msdn for dll hooks, or keyboard hooks. One of those should set you up.

For linux I think this should be easier, but I have never done it myself.

http://ubuntuforums.org/showthread.php?t=864566

Google's first result for "linux listen for global key presses" (no quotes) turns up something which I think will help you out for X11 environments

OSX might just be able to use a solution close to this. But in the end, you'll probably need a dll for every platform, unless JNA could do this without issue, then the worst is done.

guyumu
  • 3,457
  • 2
  • 19
  • 18
1

You can use JNA now - see https://github.com/tulskiy/jkeymaster

I've had this working fairly easily on a Windows 10 laptop - I haven't personally tested on other platforms - apparently it also works for MacOS and 'X11-based systems (in theory, only tested on some Linux distros and PCBSD)'.

It's shouldn't be difficult to setup - you will need slf4j to get it to run.

You shouldn't need to build the jar.

As an example, this code effectively disables the 'f' key and logs the fact that you pressed it.

import com.tulskiy.keymaster.common.Provider;
import com.tulskiy.keymaster.common.HotKeyListener;
import com.tulskiy.keymaster.common.HotKey;
import javax.swing.*;

// ...          

Provider provider = Provider.getCurrentProvider(false); 
    provider.register(KeyStroke.getKeyStroke("F"), new HotKeyListener() {
            public void onHotKey(HotKey hotKey) {
                System.out.println(hotKey);
            }
        });

I hope this helps someone

AndyS
  • 725
  • 7
  • 17
1

JDIC (Java Desktop Integration) could help
https://jdic.dev.java.net/

Seems to be a little unmaintained to me. I'm not sure.
If someone know more, please report!
I'm also very interested in this feature.

ivan_ivanovich_ivanoff
  • 19,113
  • 27
  • 81
  • 100