Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
199 views
in Technique[技术] by (71.8m points)

hotkeys - How to emulate pressing media keys in Java?

How can I emulate pressing media keys in Java? Such as play/pause, next/previous, volume control.

C# has VK_MEDIA_PLAY_PAUSE, VK_MEDIA_NEXT_TRACK and so on.

Java has class Robot for working with keys, but there are no media keys.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I used the JNI Library to simulate the key presses using code written in C. I've created a .dll file and .java file for hitting the "Volume Down", "Volume Up", "Volume Mute", "Previous Track", "Next Track", and "Play/Pause Track" media keys.

Here is a link to the full repository, however, I will explain it in more detail below.

MediaKeys.java must be in a package named "commands" to work.

MediaKeys.dll must be in same path as the "src" folder or in the same path as the .class file when compiled.

MediaKeys.java file contains the following:

package commands

public class MediaKeys {

    //loads library from "MediaKeys.dll"
    static {
        System.loadLibrary("MediaKeys");
    }



    public static native void volumeMute();

    public static native void volumeDown();

    public static native void volumeUp();


    public static native void songPrevious();

    public static native void songNext();

    public static native void songPlayPause();



    //test driver
    public static void main(String[] args) {

        //volumeMute();

    }

}

The static block loads the .dll file and then the functions programmed in C are declared using the native keyword.

If you only need the functions, then you can use the .dll file for Windows. If you require the source code for the .dll it is included in the link above and I will explain it in more detail below.

The .dll is made from two files, a C file for the functions' source code and a header file. (Named MediaKeys.c and MediaKeys.h)

The MediaKeys.c contains the code that presses the desired keys. In order to preserve space, the following code blocks for the C and header files are formatted only for "Next Track", "Previous Track", and "Pause/Play Track" functions.

The header file: MediaKeys.h

/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class MediaKeys */

#ifndef _Included_MediaKeys
#define _Included_MediaKeys
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     MediaKeys
 * Method:    songPrevious
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_commands_MediaKeys_songPrevious
  (JNIEnv *, jclass);

/*
 * Class:     MediaKeys
 * Method:    songNext
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_commands_MediaKeys_songNext
  (JNIEnv *, jclass);

/*
 * Class:     MediaKeys
 * Method:    songPlayPause
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_commands_MediaKeys_songPlayPause
  (JNIEnv *, jclass);

#ifdef __cplusplus
}
#endif
#endif

The header file contains a statement for each method needed in the following format:

JNIEXPORT void JNICALL Java_{package_name}_{class_name}_{method_name}
  (JNIEnv *, jclass);

The C file must then correspond to the header file. MediaKeys.c

//standard dependencies for C and the JNI Library
#include <jni.h>
#include <stdio.h>
#include "MediaKeys.h"

//dependencies required to hit the media keys
#define WINVER 0x0500
#include <windows.h>


//hits the previous track key
JNIEXPORT void JNICALL Java_commands_MediaKeys_songPrevious (JNIEnv *env, jobject thisObj) {

    KEYBDINPUT kbi;

    //specific keycode
    kbi.wVk = VK_MEDIA_PREV_TRACK; //this can be changed depending on the key

    kbi.wScan = 0;
    kbi.dwFlags = 0;
    kbi.time = 0;
    kbi.dwExtraInfo = (ULONG_PTR) GetMessageExtraInfo();

    INPUT input;
    input.type = INPUT_KEYBOARD;
    input.ki   = kbi;

    SendInput(1, &input, sizeof(INPUT));

    return;

}


//hits the next track key
JNIEXPORT void JNICALL Java_commands_MediaKeys_songNext (JNIEnv *env, jobject thisObj) {

    KEYBDINPUT kbi;

    //specific keycode
    kbi.wVk = VK_MEDIA_NEXT_TRACK;

    kbi.wScan = 0;
    kbi.dwFlags = 0;
    kbi.time = 0;
    kbi.dwExtraInfo = (ULONG_PTR) GetMessageExtraInfo();

    INPUT input;
    input.type = INPUT_KEYBOARD;
    input.ki   = kbi;

    SendInput(1, &input, sizeof(INPUT));

    return;

}


//hits the play/pause key
JNIEXPORT void JNICALL Java_commands_MediaKeys_songPlayPause (JNIEnv *env, jobject thisObj) {

    KEYBDINPUT kbi;

    //specific keycode
    kbi.wVk = VK_MEDIA_PLAY_PAUSE;

    kbi.wScan = 0;
    kbi.dwFlags = 0;
    kbi.time = 0;
    kbi.dwExtraInfo = (ULONG_PTR) GetMessageExtraInfo();

    INPUT input;
    input.type = INPUT_KEYBOARD;
    input.ki   = kbi;

    SendInput(1, &input, sizeof(INPUT));

    return;

}

The C file contains a corresponding function for each header statement following the format below:

JNIEXPORT void JNICALL Java_{package_name}_{class_name}_{method_name} (JNIEnv *env, jobject thisObj) {

    //specific code goes here
    return;

}

And as noted in the code, you can change the specific key by changing: kbi.wVk = specific_key_goes_here;. A list of available keys can be found here.

Once the C and header files are created, they can then be compiled into a dll file. To do this, I used Code::Blocks to create a new Dynamic Link Library project, added the MediaKeys.c and MediaKeys.h files, and clicked build.

Since my JVM is 64-bit and Code::Blocks default compiler is 32-bit, I had to install a 64-bit compiler into Code::Blocks.

You also must add links to the jni.h libraries. To do this in Code::Blocks go to Settings>Compiler>Search Directories and add the directories C:Program FilesJavajdk1.8.0_171include and C:Program FilesJavajdk1.8.0_171includewin32. You will most likely have to change the file paths depending on your jdk version.

Once built, then copy the dll file to the required location for the java program.

For more information about setting up the Java Native Interface, I found this link exceptionally helpful.

I know this post is a bit old but I figured this information might help others.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...