如何在 Java 中模拟按下媒体键?如播放/暂停、下一个/上一个、音量控制。
C# 有VK_MEDIA_PLAY_PAUSE
,VK_MEDIA_NEXT_TRACK
等等。
Java 有Robot
使用密钥的类,但没有媒体密钥。
如何在 Java 中模拟按下媒体键?如播放/暂停、下一个/上一个、音量控制。
C# 有VK_MEDIA_PLAY_PAUSE
,VK_MEDIA_NEXT_TRACK
等等。
Java 有Robot
使用密钥的类,但没有媒体密钥。
我使用 JNI 库使用用 C 编写的代码模拟按键。我创建了一个 .dll 文件和 .java 文件,用于点击“降低音量”、“提高音量”、“静音”、“上一首曲目” 、“下一曲目”和“播放/暂停曲目”媒体键。
这是完整存储库的链接,但是,我将在下面更详细地解释它。
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 的源代码,它包含在上面的链接中,我将在下面更详细地解释它。
.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 文件必须与头文件相对应。媒体密钥.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;
。可以在此处找到可用密钥的列表。
一旦创建了 C 和头文件,就可以将它们编译成 dll 文件。为此,我使用 Code::Blocks 创建了一个新的动态链接库项目,添加了 MediaKeys.c 和 MediaKeys.h 文件,然后单击了构建。
由于我的 JVM 是 64 位,而 Code::Blocks 默认编译器是 32 位,因此我必须在 Code::Blocks 中安装一个 64 位编译器。
您还必须添加到jni.h
库的链接。要在 Code::Blocks 中执行此操作,请转到Settings>Compiler>Search Directories
并添加目录C:\Program Files\Java\jdk1.8.0_171\include
和C:\Program Files\Java\jdk1.8.0_171\include\win32
. 您很可能必须根据您的 jdk 版本更改文件路径。
构建完成后,将 dll 文件复制到 java 程序所需的位置。
有关设置 Java 本机接口的更多信息,我发现此链接非常有用。
我知道这篇文章有点旧,但我认为这些信息可能对其他人有所帮助。
您可以使用https://github.com/kwhat/jnativehook实现它,然后监视密钥。在我的问题中,我编写了一些示例方法:
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));
}
要做的就是将库包含到您的项目中。可以在此处找到有关如何监视键并获取必要参数以创建键事件的示例。
创建您自己的 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 - 所以使用它。
我改进了Alex 的 KeySpy 应用程序。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);
}
}
}