Java监听键盘鼠标全局事件

转自:http://dengpeng.sensorapp.net/?p=495


标准的Java键盘事件监听器(KeyListener)和鼠标事件监听器(MouseListener)只能在该Java程序聚焦的时候监听事件。要想让你的Java程序能够在系统后台跟踪全局键盘和鼠标事件,那就需要使用JNI(Java Native Interface)来创建一个钩子监听操作系统的事件了。本文只讨论,Java程序与Windows操作系统的交互,如果你知道如何实现Java监听Linux事件,请留言,谢谢。开发运行环境:Windows XP SP3, Java 1.6_15, Eclipse 3.5

直接上代码

SysHook.cpp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
#include <windows.h>
#include "SysHook.h"
#include <jni.h>
 
HINSTANCE hInst = NULL;
 
JavaVM * jvm = NULL;
jobject hookObj_kb = NULL;
jobject hookObj_ms = NULL;
jobject g_kl = NULL;
 
jmethodID processKeyID_kb = NULL;
jmethodID processKeyID_ms = NULL;
DWORD hookThreadId = 0;
 
LONG     g_mouseLocX = -1;     // x-location of mouse position
LONG     g_mouseLocY = -1;     // y-location of mouse position
 
extern "C"
BOOL APIENTRY DllMain( HINSTANCE _hInst, DWORD reason, LPVOID reserved)
{
  switch (reason)
  {
  case DLL_PROCESS_ATTACH:
  printf ( "C++: DllMain - DLL_PROCESS_ATTACH.\n" );
  hInst = _hInst;
  break ;
  default :
  break ;
  }
 
return TRUE;
}
 
LRESULT CALLBACK MouseTracker( int nCode, WPARAM wParam, LPARAM lParam)
{
  JNIEnv * env;
  KBDLLHOOKSTRUCT * p = (KBDLLHOOKSTRUCT *)lParam;
 
  if (jvm->AttachCurrentThread(( void **)&env, NULL) >= 0)
  {
 
  if (nCode==HC_ACTION)
  {
  MOUSEHOOKSTRUCT* pStruct = (MOUSEHOOKSTRUCT*)lParam;
  if (pStruct->pt.x != g_mouseLocX || pStruct->pt.y != g_mouseLocY)
  {
  env->CallVoidMethod(hookObj_ms, processKeyID_ms, (jint)pStruct->pt.x,(jint)pStruct->pt.y, g_kl);
  g_mouseLocX = pStruct->pt.x;
  g_mouseLocY = pStruct->pt.y;
  }
 
  }
 
  }
  else
  {
  printf ( "C++: LowLevelKeyboardProc - Error on the attach current thread.\n" );
  }
 
  return CallNextHookEx(NULL, nCode, wParam, lParam);
}
 
LRESULT CALLBACK LowLevelKeyboardProc( int nCode, WPARAM wParam, LPARAM lParam)
{
  JNIEnv * env;
  KBDLLHOOKSTRUCT * p = (KBDLLHOOKSTRUCT *)lParam;
 
  if (jvm->AttachCurrentThread(( void **)&env, NULL) >= 0)
  {
  switch (wParam)
  {
  case WM_KEYDOWN:
  case WM_SYSKEYDOWN:
  env->CallVoidMethod(hookObj_kb, processKeyID_kb, (jboolean)TRUE, p->vkCode,g_kl);
  break ;
  case WM_KEYUP:
  case WM_SYSKEYUP:
  env->CallVoidMethod(hookObj_kb, processKeyID_kb, (jboolean)FALSE, p->vkCode,g_kl);
  break ;
  default :
  break ;
  }
  }
  else
  {
  printf ( "C++: LowLevelKeyboardProc - Error on the attach current thread.\n" );
  }
 
  return CallNextHookEx(NULL, nCode, wParam, lParam);
}
 
void MsgLoop()
{
  MSG message;
  while (GetMessage(&message, NULL, 0, 0))
  {
  TranslateMessage(&message);
  DispatchMessage(&message);
  }
}
 
JNIEXPORT void JNICALL Java_SysHook_registerHook(JNIEnv * env, jobject obj,jobject kl)
{
  HHOOK hookHandle_ms = SetWindowsHookEx(WH_MOUSE_LL, MouseTracker, hInst, 0);
  HHOOK hookHandle_kb = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, hInst, 0);
 
  g_kl = kl;
 
  if (hookHandle_ms == NULL)
  {
  printf ( "C++: Java_SysHook_registerKeyHook - Hook failed!\n" );
  return ;
  }
  else
  {
  printf ( "C++: Java_SysHook_registerKeyHook - Hook successful\n" );
  }
 
  if (hookHandle_kb == NULL)
  {
  printf ( "C++: Java_SysHook_registerKeyHook - Hook failed!\n" );
  return ;
  }
  else
  {
  printf ( "C++: Java_SysHook_registerKeyHook - Hook successful\n" );
  }
 
  hookObj_kb = env->NewGlobalRef(obj);
  jclass cls_kb = env->GetObjectClass(hookObj_kb);
  processKeyID_kb = env->GetMethodID(cls_kb, "processKey" , "(ZILGlobalEventListener;)V" );
 
  hookObj_ms = env->NewGlobalRef(obj);
  jclass cls_ms = env->GetObjectClass(hookObj_ms);
  processKeyID_ms = env->GetMethodID(cls_ms, "mouseMoved" , "(IILGlobalEventListener;)V" );
 
  env->GetJavaVM(&jvm);
  hookThreadId = GetCurrentThreadId();
 
  MsgLoop();
 
  if (!UnhookWindowsHookEx(hookHandle_kb))
  {
  printf ( "C++: Java_SysHook_registerKeyHook - Unhook failed\n" );
  }
  else
  {
  printf ( "C++: Java_SysHook_registerKeyHook - Unhook successful\n" );
  }
 
  if (!UnhookWindowsHookEx(hookHandle_ms))
  {
  printf ( "C++: Java_SysHook_registerKeyHook - Unhook failed\n" );
  }
  else
  {
  printf ( "C++: Java_SysHook_registerKeyHook - Unhook successful\n" );
  }
}
 
JNIEXPORT void JNICALL Java_SysHook_unRegisterHook(JNIEnv *env, jobject object)
{
  if (hookThreadId == 0)
  return ;
 
  printf ( "C++: Java_SysHook_unRegisterKeyHook - call PostThreadMessage.\n" );
  PostThreadMessage(hookThreadId, WM_QUIT, 0, 0L);
}

SysHook.h:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class SysHook */
 
#ifndef _Included_SysHook
#define _Included_SysHook
#ifdef __cplusplus
extern "C" {
#endif
/*
  * Class:     SysHook
  * Method:    registerHook
  * Signature: (LGlobalEventListener;)V
  */
JNIEXPORT void JNICALL Java_SysHook_registerHook  (JNIEnv *, jobject, jobject);
 
/*
  * Class:     SysHook
  * Method:    unRegisterHook
  * Signature: ()V
  */
JNIEXPORT void JNICALL Java_SysHook_unRegisterHook  (JNIEnv *, jobject);
 
#ifdef __cplusplus
}
#endif
#endif

KeyboardEventListener.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
import java.util.*;
 
public interface KeyboardEventListener extends EventListener {
  public void GlobalKeyPressed(KeyboardEvent event);
 
  public void GlobalKeyReleased(KeyboardEvent event);
}
 
class KeyboardEvent extends EventObject {
  private static final long serialVersionUID = 2341653211621224652L;
  boolean ts, ap, ek;
  int vk;
 
  public KeyboardEvent(Object source, boolean ts, int vk, boolean ap,
  boolean ek) {
  super (source);
  this .ts = ts;
  this .vk = vk;
  this .ap = ap;
  this .ek = ek;
  }
 
  public boolean getTransitionState() {
  return ts;
  }
 
  public long getVirtualKeyCode() {
  return vk;
  }
 
  public boolean isAltPressed() {
  return ap;
  }
 
  public boolean isExtendedKey() {
  return ek;
  }
 
  public boolean equals(KeyboardEvent event) {
  if (event.getVirtualKeyCode() == vk) {
  if (event.isExtendedKey() == ek) {
  if (event.isAltPressed() == ap) {
  return true ;
  }
  }
  }
  return false ;
  }
}

MouseEventListenter.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import java.util.*;
 
public interface MouseEventListener extends EventListener {
  public void GlobalMouseX(MouseEvent event);
 
  public void GlobalMouseY(MouseEvent event);
}
 
class MouseEvent extends EventObject {
 
  private static final long serialVersionUID = 14654L;
  int cord_x, cord_y;
 
  public MouseEvent(Object source, int cord_x, int cord_y) {
  super (source);
  this .cord_x = cord_x;
  this .cord_y = cord_y;
  }
 
  public int getMouseX() {
  return cord_x;
  }
 
  public int getMouseY() {
  return cord_y;
  }
 
}

GlobalEventListener.java :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
public class GlobalEventListener {
  PoolHook pt;
 
  public GlobalEventListener() {
  pt = new PoolHook( this );
  pt.start();
 
  }
 
  protected javax.swing.event.EventListenerList listenerList = new javax.swing.event.EventListenerList();
 
  public void addKeyboardEventListener(KeyboardEventListener listener) {
  listenerList.add(KeyboardEventListener. class , listener);
  }
 
  public void removeKeyboardEventListener(KeyboardEventListener listener) {
  listenerList.remove(KeyboardEventListener. class , listener);
  }
 
  public void addMouseEventListener(MouseEventListener listener) {
  listenerList.add(MouseEventListener. class , listener);
  }
 
  public void removeMouseEventListener(MouseEventListener listener) {
  listenerList.remove(MouseEventListener. class , listener);
  }
 
  void keyPressed(KeyboardEvent event) {
  Object[] listeners = listenerList.getListenerList();
  for ( int i = 0 ; i < listeners.length; i += 2 ) {
  if (listeners[i] == KeyboardEventListener. class ) {
  ((KeyboardEventListener) listeners[i + 1 ])
  .GlobalKeyPressed(event);
  }
  }
  }
 
  void mouseMoved(MouseEvent event) {
  Object[] listeners = listenerList.getListenerList();
  for ( int i = 0 ; i < listeners.length; i += 2 ) {
  if (listeners[i] == MouseEventListener. class ) {
  ((MouseEventListener) listeners[i + 1 ]).GlobalMouseX(event);
  ((MouseEventListener) listeners[i + 1 ]).GlobalMouseY(event);
  }
  }
  }
 
  void keyReleased(KeyboardEvent event) {
  Object[] listeners = listenerList.getListenerList();
  for ( int i = 0 ; i < listeners.length; i += 2 ) {
  if (listeners[i] == KeyboardEventListener. class ) {
  ((KeyboardEventListener) listeners[i + 1 ])
  .GlobalKeyReleased(event);
  }
  }
  }
 
}

SysHook.java:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class PoolHook extends Thread {
  SysHook hook;
  GlobalEventListener g_gl;
 
  PoolHook(GlobalEventListener gl) {
  g_gl = gl;
  }
 
  public void run() {
  hook = new SysHook();
  hook.registerHook(g_gl);
  }
 
}
 
class SysHook {
 
  static {
  System.loadLibrary( "SysHook" );
  }
 
  void processKey( boolean ts, int vk, GlobalEventListener gl) {
  KeyboardEvent event = new KeyboardEvent( this , ts, vk, false , false );
  gl.keyPressed(event);
  }
 
  void mouseMoved( int cord_x, int cord_y, GlobalEventListener gl) {
  MouseEvent event = new MouseEvent( this , cord_x, cord_y);
  gl.mouseMoved(event);
  }
 
  native void registerHook(GlobalEventListener gl);
 
  native void unRegisterHook();
 
}

Example.java:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class Example implements KeyboardEventListener, MouseEventListener {
 
  static GlobalEventListener gl;
 
  public static void main(String[] args) throws Exception {
  Example inst = new Example();
  gl = new GlobalEventListener();
  gl.addKeyboardEventListener(inst);
  gl.addMouseEventListener(inst);
  }
 
  @Override
  public void GlobalKeyPressed(KeyboardEvent event) {
 
  System.out.println( "Key Pressed: " + event.getVirtualKeyCode());
  }
 
  @Override
  public void GlobalKeyReleased(KeyboardEvent event) {
  }
 
  @Override
  public void GlobalMouseX(MouseEvent event) {
  System.out.println( "Mouse X: " + event.getMouseX());
 
  }
 
  @Override
  public void GlobalMouseY(MouseEvent event) {
  System.out.println( "Mouse Y: " + event.getMouseY());
  }
 
}

C++文件需要用Visual Studio编译为你的目标系统的DLL文件。如果是标准32位Windows XP,可以在这里下载已编译的文件。

在Eclipse创建工程后,需要做的设置是将该DLL所在目录添加到Native library location如图:

本文摘录、翻译并修改自http://www.jotschi.de/?p=90



  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
Java 中可以使用 AWT 和 Swing 提供的事件监听机制来实现全局监听键盘鼠标的功能。 监听键盘事件: ```java import java.awt.event.KeyEvent; import java.awt.event.KeyListener; public class KeyboardListener implements KeyListener { @Override public void keyPressed(KeyEvent e) { // 处理键盘按下事件 // e.getKeyCode() 可以获取按下的键的代码 } @Override public void keyReleased(KeyEvent e) { // 处理键盘释放事件 } @Override public void keyTyped(KeyEvent e) { // 处理键盘输入事件 } } ``` 全局监听键盘事件: ```java import java.awt.Toolkit; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; public class GlobalKeyboardListener implements KeyListener { public GlobalKeyboardListener() { Toolkit.getDefaultToolkit().addAWTEventListener(event -> { if (event instanceof KeyEvent) { KeyEvent keyEvent = (KeyEvent) event; // 处理键盘事件 } }, AWTEvent.KEY_EVENT_MASK); } @Override public void keyPressed(KeyEvent e) { // 处理键盘按下事件 // e.getKeyCode() 可以获取按下的键的代码 } @Override public void keyReleased(KeyEvent e) { // 处理键盘释放事件 } @Override public void keyTyped(KeyEvent e) { // 处理键盘输入事件 } } ``` 监听鼠标事件: ```java import java.awt.event.MouseEvent; import java.awt.event.MouseListener; public class MouseListener implements MouseListener { @Override public void mouseClicked(MouseEvent e) { // 处理鼠标点击事件 // e.getButton() 可以获取点击的鼠标按钮 } @Override public void mousePressed(MouseEvent e) { // 处理鼠标按下事件 } @Override public void mouseReleased(MouseEvent e) { // 处理鼠标释放事件 } @Override public void mouseEntered(MouseEvent e) { // 处理鼠标进入事件 } @Override public void mouseExited(MouseEvent e) { // 处理鼠标离开事件 } } ``` 全局监听鼠标事件: ```java import java.awt.Toolkit; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; public class GlobalMouseListener implements MouseListener { public GlobalMouseListener() { Toolkit.getDefaultToolkit().addAWTEventListener(event -> { if (event instanceof MouseEvent) { MouseEvent mouseEvent = (MouseEvent) event; // 处理鼠标事件 } }, AWTEvent.MOUSE_EVENT_MASK); } @Override public void mouseClicked(MouseEvent e) { // 处理鼠标点击事件 // e.getButton() 可以获取点击的鼠标按钮 } @Override public void mousePressed(MouseEvent e) { // 处理鼠标按下事件 } @Override public void mouseReleased(MouseEvent e) { // 处理鼠标释放事件 } @Override public void mouseEntered(MouseEvent e) { // 处理鼠标进入事件 } @Override public void mouseExited(MouseEvent e) { // 处理鼠标离开事件 } } ``` 注意:全局监听键盘鼠标事件需要在启动程序时添加,否则可能监听不到事件
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值