基本思路:使用WIN API实现一个底层键盘钩子,监听按键事件。如果需要的快捷键被触发,则弹出相应的窗口。
找到了http://www.jotschi.de/?p=90
这个代码基本上实现了我的要求。可惜一运行老崩溃。
更改后的代码如下:
src_media_SysHook.h
/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header for class src_media_SysHook */ #ifndef _Included_src_media_SysHook #define _Included_src_media_SysHook #ifdef __cplusplus extern "C" { #endif /* * Class: src_media_SysHook * Method: registerHook * Signature: (Lsrc/media/GlobalEventListener;)V */ JNIEXPORT void JNICALL Java_src_media_SysHook_registerHookl (JNIEnv *, jobject, jobject); /* * Class: src_media_SysHook * Method: unRegisterHook * Signature: ()V */ JNIEXPORT void JNICALL Java_src_media_SysHook_unRegisterHookl (JNIEnv *, jobject); #ifdef __cplusplus } #endif #endif
dllmain.cpp
// dllmain.cpp : Defines the entry point for the DLL application. #include "stdafx.h" #include <windows.h> HMODULE hInst = NULL; BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: hInst = hModule; break; case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; }
SysHook.cpp
// SysHook.cpp : Defines the exported functions for the DLL application. // #include "stdafx.h" #include "src_media_SysHook.h" #include <windows.h> extern HMODULE hInst ; JavaVM * jvm = NULL; jobject hookObj_kb = NULL; jobject g_kl = NULL; jmethodID processKeyID_kb = NULL; DWORD hookThreadId = 0; LONG g_mouseLocX = -1; // x-location of mouse position LONG g_mouseLocY = -1; // y-location of mouse position extern "C" 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, (jint)(p->vkCode),g_kl); break; case WM_KEYUP: case WM_SYSKEYUP: env->CallVoidMethod(hookObj_kb, processKeyID_kb, (jboolean)FALSE, (jint)(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; BOOL bRet; while ((bRet = GetMessage(&message, NULL, 0, 0))!=0) { if(bRet == -1){ } else { TranslateMessage(&message); DispatchMessage(&message); } } } JNIEXPORT void JNICALL Java_src_media_SysHook_registerHookl(JNIEnv * env, jobject obj,jobject kl) { HHOOK hookHandle_kb = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, hInst, 0); g_kl = kl; 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","(ZILsrc/media/GlobalEventListener;)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"); } } JNIEXPORT void JNICALL Java_src_media_SysHook_unRegisterHookl(JNIEnv *env, jobject object) { if (hookThreadId == 0) return; printf("C++: Java_SysHook_unRegisterKeyHook - call PostThreadMessage.\n"); PostThreadMessage(hookThreadId, WM_QUIT, 0, 0L); }
这个JNI有两个给C调用的接口。有两处调用C的地方。
原来的代码导致程序死掉的地方:
processKeyID_kb = env->GetMethodID(cls_kb, "processKey", "(ZILGlobalEventListener;)V");
这句代码是调用JAVA代码中的processKey这个函数,参数和返回值是(ZILGlobalEventListener;)V
这个根据我们代码的实际情况需要更改的。例如我改成了:
processKeyID_kb = env->GetMethodID(cls_kb,"processKey","(ZILsrc/media/GlobalEventListener;)V");
括号里的是参数,方法的签名,可以自动生成的。
使用cmd工具,切换到编译后的文件路径使用下面命令生成:
Javap –s 包名.类名
GlobalEventListener.java
package src.media; /* * To change this template, choose Tools | Templates * and open the template in the editor. */ /** * * @author issuser */ 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 ); } 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 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 ); } } } }
KeyCtrl.java
package src.media; import javafx.reflect.FXClassType; import javafx.reflect.FXLocal; import javafx.reflect.FXLocal.Context; import javafx.reflect.FXLocal.ObjectValue; import src.SCInterface; import src.media.GlobalEventListener; /* * To change this template, choose Tools | Templates * and open the template in the editor. */ /** * * @author issuser */ public class KeyCtrl implements KeyboardEventListener{ static GlobalEventListener gl; Boolean ctrlPress = false; Boolean altPress = false; public static void globalKeyEvent() throws Exception { KeyCtrl inst = new KeyCtrl(); gl = new GlobalEventListener(); gl.addKeyboardEventListener(inst); } public void shortCutPress(String cmd){ Context context = FXLocal.getContext(); FXClassType instance = context.findClass("src.ShortCutInterface"); ObjectValue obj = (ObjectValue)instance.newInstance(); SCInterface ji = (SCInterface)obj.asObject(); ji.shortCutInterface(cmd); } public String shortCut(Boolean press,long code){ if(code == 162){ if(press == true){ ctrlPress = true; }else{ ctrlPress = false; } } if(ctrlPress == true){ if(code == 164){ if(press == true){ altPress = true; }else{ altPress = false; } } } if(ctrlPress == true && altPress == true){ if(code >=48 && code <= 57 ){ long num = code - 48; return "ctrl alt " + num; } if(code >=96 && code <=105 ){ long num = code - 96; return "ctrl alt " + num; } if(code == 191 ){ return "ctrl alt ?"; } if(code == 114 ) { return "ctrl alt F3"; } if(code == 115 ){ return "ctrl alt F4"; } if(code == 117 ){ return "ctrl alt F6"; } if(code == 118 ){ return "ctrl alt F7"; } if(code == 119 ){ return "ctrl alt F8"; } } return ""; } @Override public void GlobalKeyPressed(KeyboardEvent event) { //System.out.println( "Key Pressed: " + event.getVirtualKeyCode() ); String cmd = shortCut(true,event.getVirtualKeyCode()); if(!cmd.equals("")){ shortCutPress(cmd); } throw new UnsupportedOperationException("Not supported yet."); } @Override public void GlobalKeyReleased(KeyboardEvent event) { shortCut(false,event.getVirtualKeyCode()); throw new UnsupportedOperationException("Not supported yet."); } }
KeyboardEventListener.java
package src.media; /* * To change this template, choose Tools | Templates * and open the template in the editor. */ import java.util.*; /** * * @author issuser */ 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 long getVirtualKeyCode() { return vk; } }
SysHook.java
package src.media; import src.media.GlobalEventListener; /* * To change this template, choose Tools | Templates * and open the template in the editor. */ /** * * @author issuser */ class PoolHook extends Thread { SysHook hook; GlobalEventListener g_gl; PoolHook(GlobalEventListener gl) { g_gl = gl; } public void run() { hook = new SysHook(); hook.rgHook(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); if (ts == true) { gl.keyPressed(event); } else { gl.keyReleased(event); } } public void rgHook(GlobalEventListener gl) { registerHookl(gl); } public void unRgHook() { unRegisterHookl(); } private native void registerHookl(GlobalEventListener gl); private native void unRegisterHookl(); }