[JNI]用JAVA实现全局快捷键

来源:互联网 发布:apache是什么 编辑:程序博客网 时间:2024/04/30 12:52


基本思路:使用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 __cplusplusextern "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;LONGg_mouseLocX = -1;// x-location of mouse positionLONGg_mouseLocY = -1;// y-location of mouse positionextern "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();}


 

原创粉丝点击