基本思路:使用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();
}