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

Java监听键盘鼠标全局事件_第1张图片

直接上代码

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



你可能感兴趣的:(Java监听键盘鼠标全局事件)