【问题标题】:How to emulate pressing media keys in Java?如何在 Java 中模拟按下媒体键?
【发布时间】:2017-07-07 15:30:55
【问题描述】:

如何在 Java 中模拟按下媒体键?如播放/暂停、下一个/上一个、音量控制。

C#有VK_MEDIA_PLAY_PAUSEVK_MEDIA_NEXT_TRACK等等。

Java 有类Robot 用于处理密钥,但没有媒体密钥。

【问题讨论】:

标签: java hotkeys awtrobot media-keys


【解决方案1】:

我使用 JNI 库使用 C 编写的代码模拟按键。我创建了一个 .dll 文件和 .java 文件来点击“降低音量”、“提高音量”、“静音”、“ Previous Track”、“Next Track”和“Play/Pause Track”媒体键。

这是完整存储库的link,但是,我将在下面更详细地解释它。

MediaKeys.java 必须在名为“commands”的包中才能工作。

MediaKeys.dll 必须与“src”文件夹位于同一路径,或编译时与.class 文件位于同一路径。

MediaKeys.java 文件包含以下内容:

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

    }

}

静态块加载 .dll 文件,然后使用 native 关键字声明用 C 编写的函数。

如果您只需要这些功能,那么您可以使用适用于 Windows 的 .dll 文件。如果您需要.dll 的源代码,它包含在上面的link 中,我将在下面更详细地解释它。

.dll 由两个文件组成,一个用于函数源代码的 C 文件和一个头文件。 (命名为 MediaKeys.c 和 MediaKeys.h)

MediaKeys.c 包含按下所需键的代码。为了节省空间,C 和头文件的以下代码块仅针对“下一曲目”、“上一曲目”和“暂停/播放曲目”功能进行了格式化。

头文件: 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

头文件包含每个方法所需的声明,格式如下:

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

C 文件必须与头文件相对应。 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;

}

C 文件包含每个标题语句的对应函数,格式如下:

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

    //specific code goes here
    return;

}

如代码中所述,您可以通过更改:kbi.wVk = specific_key_goes_here; 来更改特定键。可以找到可用密钥列表here

一旦创建了 C 和头文件,就可以将它们编译成 dll 文件。为此,我使用 Code::Blocks 创建了一个新的动态链接库项目,添加了 MediaKeys.c 和 MediaKeys.h 文件,然后单击了构建。

由于我的 JVM 是 64 位并且 Code::Blocks 默认编译器是 32 位,我不得不将 install a 64-bit compiler 转换为 Code::Blocks。

您还必须添加指向jni.h 库的链接。要在 Code::Blocks 中执行此操作,请转到 Settings&gt;Compiler&gt;Search Directories 并添加目录 C:\Program Files\Java\jdk1.8.0_171\includeC:\Program Files\Java\jdk1.8.0_171\include\win32。您很可能必须根据您的 jdk 版本更改文件路径。

构建完成后,将 dll 文件复制到 java 程序所需的位置。

有关设置 Java 原生接口的更多信息,我发现 this link 非常有用。

我知道这篇文章有点旧,但我认为这些信息可能对其他人有所帮助。

【讨论】:

  • 您可能需要在此处添加代码而不是提供链接
  • 您提供了完全相同的答案here。显然没有关键部分(MediaKeys.dll)的源代码,显然这样的 DLL 只能在 Windows 下工作。
  • 感谢您的帮助,我会适当地更新我的答案。
  • 这是一个很棒的真实答案。终于!
【解决方案2】:

您可以使用https://github.com/kwhat/jnativehook 实现它,然后监视密钥。在my question我写了一些示例方法:

public static void MediaKeyForward(){
    GlobalScreen.postNativeEvent(new NativeKeyEvent(2401,0,176,57369,org.jnativehook.keyboard.NativeKeyEvent.CHAR_UNDEFINED));

}
public static void MediaKeyBack(){
    GlobalScreen.postNativeEvent(new NativeKeyEvent(2401,0,177,57360,org.jnativehook.keyboard.NativeKeyEvent.CHAR_UNDEFINED));

}
public static void MediaKeyPause(){
 GlobalScreen.postNativeEvent(new NativeKeyEvent(2401,0,179,57378,org.jnativehook.keyboard.NativeKeyEvent.CHAR_UNDEFINED));

}

要做的就是将库包含到您的项目中。可以在here 找到如何监视键并获取必要参数以创建键事件的示例。

【讨论】:

    【解决方案3】:

    创建您自己的 keylistener 和 spy,然后使用这个值。 这是简单的 KeySpy 类:

    import java.awt.event.KeyEvent;
    import java.awt.event.KeyListener;
    
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    
    
    public class KeySpy {
        JLabel label=new JLabel("Enter the key");
        public KeySpy() {
            JFrame frame=new JFrame("KeySpy");
            frame.add(label);
    
            frame.addKeyListener(new KeyListener() {
    
                @Override
                public void keyTyped(KeyEvent e) {
                }
    
                @Override
                public void keyReleased(KeyEvent e) {
                }
    
                @Override
                public void keyPressed(KeyEvent e) {
                    label.setText(e.toString());
                    System.out.println(e.toString());
                }
            });
    
            frame.setSize(200, 200);
            frame.setVisible(true);
        }
    
        public static void main(String[] args) {
            new KeySpy();
    
        }
    
    }
    

    这是我键盘上 2 个按钮的结果

       [Stop] = java.awt.event.KeyEvent[KEY_PRESSED,keyCode=0,keyText=Unknown keyCode: 0x0,keyChar=Undefined keyChar,keyLocation=KEY_LOCATION_STANDARD,rawCode=178,primaryLevelUnicode=0,scancode=36,extendedKeyCode=0x0] on frame0
    
       [Mute] = java.awt.event.KeyEvent[KEY_PRESSED,keyCode=0,keyText=Unknown keyCode: 0x0,keyChar=Undefined keyChar,keyLocation=KEY_LOCATION_STANDARD,rawCode=173,primaryLevelUnicode=0,scancode=32,extendedKeyCode=0x0] on frame0
    

    如您所见,他们没有 keyCode,但他们有 rawCode - 所以使用它。

    【讨论】:

    • 你如何把它变成自动化的媒体密钥?
    【解决方案4】:

    我改进了Alex's KeySpy application。 JFrame 保持焦点,因此您可以最小化或最大化应用程序,并且在应用程序处于焦点时仍然可以按任意键。

    这是图形用户界面。

    我将信息放在标签/值网格中,以便更轻松地找到您感兴趣的值。

    这是代码。这是 GridBagLayout 的一个很好的例子。

    package com.ggl.testing;
    
    import java.awt.Component;
    import java.awt.Container;
    import java.awt.GridBagConstraints;
    import java.awt.GridBagLayout;
    import java.awt.Insets;
    import java.awt.event.KeyAdapter;
    import java.awt.event.KeyEvent;
    import java.awt.event.WindowAdapter;
    import java.awt.event.WindowEvent;
    
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
    import javax.swing.JTextField;
    import javax.swing.SwingUtilities;
    
    public class KeySpy implements Runnable {
    
        private KeySpyPanel keySpyPanel;
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(new KeySpy());
        }
    
        @Override
        public void run() {
            final JFrame frame = new JFrame("Key Spy");
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setLocationByPlatform(true);
            frame.addWindowFocusListener(new WindowAdapter() {
                public void windowGainedFocus(WindowEvent e) {
                    frame.requestFocusInWindow();
                }
            });
    
            keySpyPanel = new KeySpyPanel();
            frame.add(keySpyPanel.getPanel());
            frame.addKeyListener(new KeyPressedListener(this));
    
            frame.pack();
            frame.setVisible(true);
        }
    
        public KeySpyPanel getKeySpyPanel() {
            return keySpyPanel;
        }
    
        public class KeySpyPanel {
    
            private final Insets bottomInsets = new Insets(10, 10, 10, 10);
            private final Insets normalInsets = new Insets(10, 10, 0, 10);
    
            private JPanel panel;
    
            private JTextField keyCodeField;
            private JTextField keyTextField;
            private JTextField keyCharField;
            private JTextField keyLocationField;
            private JTextField modifiersField;
            private JTextField extModifiersField;
            private JTextField rawCodeField;
            private JTextField primaryLevelUnicodeField;
            private JTextField scancodeField;
            private JTextField extendedKeyCodeField;
    
            public KeySpyPanel() {
                createPartControl();
            }
    
            private void createPartControl() {
                panel = new JPanel();
                panel.setLayout(new GridBagLayout());
    
                int gridy = 0;
    
                JLabel anyKeyLabel = new JLabel("Press any key");
                anyKeyLabel.setFont(anyKeyLabel.getFont().deriveFont(36F));
                anyKeyLabel.setHorizontalAlignment(JLabel.CENTER);
                addComponent(panel, anyKeyLabel, 0, gridy++, 2, 1, normalInsets,
                        GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL);
    
                JLabel keyCodeLabel = new JLabel("KeyCode:");
                addComponent(panel, keyCodeLabel, 0, gridy, 1, 1, normalInsets,
                        GridBagConstraints.LINE_START,
                        GridBagConstraints.HORIZONTAL);
    
                keyCodeField = new JTextField(20);
                keyCodeField.setEditable(false);
                addComponent(panel, keyCodeField, 1, gridy++, 1, 1, normalInsets,
                        GridBagConstraints.LINE_START,
                        GridBagConstraints.HORIZONTAL);
    
                JLabel keyTextLabel = new JLabel("KeyText:");
                addComponent(panel, keyTextLabel, 0, gridy, 1, 1, normalInsets,
                        GridBagConstraints.LINE_START,
                        GridBagConstraints.HORIZONTAL);
    
                keyTextField = new JTextField(20);
                keyTextField.setEditable(false);
                addComponent(panel, keyTextField, 1, gridy++, 1, 1, normalInsets,
                        GridBagConstraints.LINE_START,
                        GridBagConstraints.HORIZONTAL);
    
                JLabel keyCharLabel = new JLabel("KeyChar:");
                addComponent(panel, keyCharLabel, 0, gridy, 1, 1, normalInsets,
                        GridBagConstraints.LINE_START,
                        GridBagConstraints.HORIZONTAL);
    
                keyCharField = new JTextField(20);
                keyCharField.setEditable(false);
                addComponent(panel, keyCharField, 1, gridy++, 1, 1, normalInsets,
                        GridBagConstraints.LINE_START,
                        GridBagConstraints.HORIZONTAL);
    
                JLabel keyLocationLabel = new JLabel("KeyLocation:");
                addComponent(panel, keyLocationLabel, 0, gridy, 1, 1, normalInsets,
                        GridBagConstraints.LINE_START,
                        GridBagConstraints.HORIZONTAL);
    
                keyLocationField = new JTextField(20);
                keyLocationField.setEditable(false);
                addComponent(panel, keyLocationField, 1, gridy++, 1, 1,
                        normalInsets, GridBagConstraints.LINE_START,
                        GridBagConstraints.HORIZONTAL);
    
                JLabel modifiersLabel = new JLabel("Modifiers:");
                addComponent(panel, modifiersLabel, 0, gridy, 1, 1, normalInsets,
                        GridBagConstraints.LINE_START,
                        GridBagConstraints.HORIZONTAL);
    
                modifiersField = new JTextField(20);
                modifiersField.setEditable(false);
                addComponent(panel, modifiersField, 1, gridy++, 1, 1, normalInsets,
                        GridBagConstraints.LINE_START,
                        GridBagConstraints.HORIZONTAL);
    
                JLabel extModifiersLabel = new JLabel("ExtModifiers:");
                addComponent(panel, extModifiersLabel, 0, gridy, 1, 1,
                        normalInsets, GridBagConstraints.LINE_START,
                        GridBagConstraints.HORIZONTAL);
    
                extModifiersField = new JTextField(20);
                extModifiersField.setEditable(false);
                addComponent(panel, extModifiersField, 1, gridy++, 1, 1,
                        normalInsets, GridBagConstraints.LINE_START,
                        GridBagConstraints.HORIZONTAL);
    
                JLabel rawCodeLabel = new JLabel("RawCode:");
                addComponent(panel, rawCodeLabel, 0, gridy, 1, 1, normalInsets,
                        GridBagConstraints.LINE_START,
                        GridBagConstraints.HORIZONTAL);
    
                rawCodeField = new JTextField(20);
                rawCodeField.setEditable(false);
                addComponent(panel, rawCodeField, 1, gridy++, 1, 1, normalInsets,
                        GridBagConstraints.LINE_START,
                        GridBagConstraints.HORIZONTAL);
    
                JLabel primaryLevelUnicodeLabel = new JLabel("PrimaryLevelUnicode:");
                addComponent(panel, primaryLevelUnicodeLabel, 0, gridy, 1, 1,
                        normalInsets, GridBagConstraints.LINE_START,
                        GridBagConstraints.HORIZONTAL);
    
                primaryLevelUnicodeField = new JTextField(20);
                primaryLevelUnicodeField.setEditable(false);
                addComponent(panel, primaryLevelUnicodeField, 1, gridy++, 1, 1,
                        normalInsets, GridBagConstraints.LINE_START,
                        GridBagConstraints.HORIZONTAL);
    
                JLabel scancodeLabel = new JLabel("Scancode:");
                addComponent(panel, scancodeLabel, 0, gridy, 1, 1, normalInsets,
                        GridBagConstraints.LINE_START,
                        GridBagConstraints.HORIZONTAL);
    
                scancodeField = new JTextField(20);
                scancodeField.setEditable(false);
                addComponent(panel, scancodeField, 1, gridy++, 1, 1, normalInsets,
                        GridBagConstraints.LINE_START,
                        GridBagConstraints.HORIZONTAL);
    
                JLabel extendedKeyCodeLabel = new JLabel("ExtendedKeyCode:");
                addComponent(panel, extendedKeyCodeLabel, 0, gridy, 1, 1,
                        bottomInsets, GridBagConstraints.LINE_START,
                        GridBagConstraints.HORIZONTAL);
    
                extendedKeyCodeField = new JTextField(20);
                extendedKeyCodeField.setEditable(false);
                addComponent(panel, extendedKeyCodeField, 1, gridy++, 1, 1,
                        bottomInsets, GridBagConstraints.LINE_START,
                        GridBagConstraints.HORIZONTAL);
            }
    
            private void addComponent(Container container, Component component,
                    int gridx, int gridy, int gridwidth, int gridheight,
                    Insets insets, int anchor, int fill) {
                GridBagConstraints gbc = new GridBagConstraints(gridx, gridy,
                        gridwidth, gridheight, 1.0D, 1.0D, anchor, fill, insets, 0,
                        0);
                container.add(component, gbc);
            }
    
            public JPanel getPanel() {
                return panel;
            }
    
            public void setKeyPressed(KeyEvent event) {
                String s = event.toString();
    
                keyCodeField.setText(getValue("keyCode", s));
                keyTextField.setText(getValue("keyText", s));
                keyCharField.setText(getValue("keyChar", s));
                keyLocationField.setText(getValue("keyLocation", s));
                modifiersField.setText(getValue("modifiers", s));
                extModifiersField.setText(getValue("extModifiers", s));
                rawCodeField.setText(getValue("rawCode", s));
                primaryLevelUnicodeField
                        .setText(getValue("primaryLevelUnicode", s));
                scancodeField.setText(getValue("scancode", s));
                extendedKeyCodeField.setText(getValue("extendedKeyCode", s));
            }
    
            private String getValue(String key, String line) {
                int sPos = line.indexOf(key);
                if (sPos >= 0) {
                    int nPos = sPos + key.length() + 1;
                    int ePos = line.indexOf(",", nPos);
                    if (ePos < 0) {
                        ePos = line.indexOf("]", nPos);
                    }
                    if (ePos >= 0) {
                        return line.substring(nPos, ePos);
                    }
                }
    
                return "";
            }
    
        }
    
        public class KeyPressedListener extends KeyAdapter {
    
            private KeySpy keySpyFrame;
    
            public KeyPressedListener(KeySpy keySpyFrame) {
                this.keySpyFrame = keySpyFrame;
            }
    
            @Override
            public void keyPressed(KeyEvent event) {
                keySpyFrame.getKeySpyPanel().setKeyPressed(event);
            }
        }
    
    }
    

    【讨论】:

    • 这似乎根本无法回答问题
    猜你喜欢
    • 2019-09-14
    • 2011-02-27
    • 1970-01-01
    • 2021-05-09
    • 2019-02-23
    • 1970-01-01
    相关资源
    最近更新 更多