2010-06-20 5 views
13

J'ai assemblé un code JNA pour installer le crochet de clavier dans Windows (en utilisant les exemples JNA). Le code compile et tout, et je reçois le hook installé (je reçois le handle du hook avec succès), aussi je peux désinstaller le hook avec succès. Toutefois, le rappel n'est jamais appelé lorsque j'appuie sur une touche du clavier. Voici mon code (la plupart sont des définitions de type obtenu à partir des exemples de la JNA, aller à la « principale » directement pour ma part)Crochet de clavier JNA dans Windows

import com.sun.jna.IntegerType; 
import com.sun.jna.Pointer; 
import com.sun.jna.PointerType; 
import com.sun.jna.Structure; 
import com.sun.jna.FromNativeContext; 
import com.sun.jna.ptr.IntByReference; 
import com.sun.jna.ptr.PointerByReference; 
import com.sun.jna.win32.StdCallLibrary; 
import com.sun.jna.win32.StdCallLibrary.StdCallCallback; 
import com.sun.jna.Native; 
import com.sun.jna.Platform; 
import com.sun.jna.Library; 
import com.sun.jna.win32.W32APITypeMapper; 
import com.sun.jna.win32.W32APIFunctionMapper; 

import java.util.Map; 
import java.util.HashMap; 

public class HelloWorld { 
    static Map UNICODE_OPTIONS = new HashMap() { 
     { 
      put("type-mapper", W32APITypeMapper.UNICODE); 
      put("function-mapper", W32APIFunctionMapper.UNICODE); 
     } 
    }; 

    public static class LONG_PTR extends IntegerType { 
     public LONG_PTR() { this(0); } 
     public LONG_PTR(long value) { super(Pointer.SIZE, value); } 
    } 

    public static class UINT_PTR extends IntegerType { 
     public UINT_PTR() { super(Pointer.SIZE); } 
     public UINT_PTR(long value) { super(Pointer.SIZE, value); } 
     public Pointer toPointer() { return Pointer.createConstant(longValue()); } 
    } 

    public static class ULONG_PTR extends IntegerType { 
     public ULONG_PTR() { this(0); } 
     public ULONG_PTR(long value) { super(Pointer.SIZE, value); } 
    } 

    public static class LRESULT extends LONG_PTR { 
     public LRESULT() { this(0); } 
     public LRESULT(long value) { super(value); } 
    } 

    public static class WPARAM extends UINT_PTR { 
     public WPARAM() { this(0); } 
     public WPARAM(long value) { super(value); } 
    } 

    public static class LPARAM extends LONG_PTR { 
     public LPARAM() { this(0); } 
     public LPARAM(long value) { super(value); } 
    } 

    public static class KBDLLHOOKSTRUCT extends Structure { 
     public int vkCode; 
     public int scanCode; 
     public int flags; 
     public int time; 
     public ULONG_PTR dwExtraInfo; 
    } 

    static HANDLE INVALID_HANDLE_VALUE = new HANDLE() { 
     { super.setPointer(Pointer.createConstant(-1)); } 
     public void setPointer(Pointer p) { 
      throw new UnsupportedOperationException("Immutable reference"); 
     } 
    }; 

    public static class HANDLE extends PointerType { 
     public Object fromNative(Object nativeValue, FromNativeContext context) { 
      Object o = super.fromNative(nativeValue, context); 
      if (INVALID_HANDLE_VALUE.equals(o)) 
       return INVALID_HANDLE_VALUE; 
      return o; 
     } 
    } 

    public static class HHOOK extends HANDLE { } 
    public static class HINSTANCE extends HANDLE { } 
    public static class HMODULE extends HINSTANCE { } 

    public interface User32 extends StdCallLibrary { 
     User32 INSTANCE = (User32)Native.loadLibrary("user32", User32.class, UNICODE_OPTIONS); 

     static final int WH_KEYBOARD_LL = 13; 

     public static interface HOOKPROC extends StdCallCallback { 
      LRESULT callback(int nCode, WPARAM wParam, KBDLLHOOKSTRUCT lParam); 
     } 

     HHOOK SetWindowsHookEx(int idHook, HOOKPROC lpfn, HMODULE hMod, int dwThreadId); 
     LRESULT CallNextHookEx(HHOOK idHook, int nCode, WPARAM wParam, LPARAM lParam); 
     LRESULT CallNextHookEx(HHOOK idHook, int nCode, WPARAM wParam, Pointer lParam); 

     boolean UnhookWindowsHookEx(HHOOK idHook); 
    } 

    public interface Kernel32 extends StdCallLibrary { 
     Kernel32 INSTANCE = (Kernel32)Native.loadLibrary("kernel32", Kernel32.class, UNICODE_OPTIONS); 

     HMODULE GetModuleHandle(String name); 
    } 

    public static HHOOK hHook; 
    public static User32.HOOKPROC lpfn; 
    public static volatile boolean quit = false; 

    public static void main(String[] args) throws Exception { 
     HMODULE hMod = Kernel32.INSTANCE.GetModuleHandle(null); 
     System.out.println(hMod); 

     lpfn = new User32.HOOKPROC() { 
      public LRESULT callback(int nCode, WPARAM wParam, KBDLLHOOKSTRUCT lParam) { 
       System.out.println("here"); 
       quit = true; 
       return User32.INSTANCE.CallNextHookEx(hHook, nCode, wParam, lParam.getPointer()); 
      } 
     }; 

     hHook = User32.INSTANCE.SetWindowsHookEx(User32.WH_KEYBOARD_LL, lpfn, hMod, 0); 
     System.out.println(hHook); 

     if(hHook != null) 
      System.out.println("Keyboard hooked, type anything to quit"); 

     while(!quit) { 
      Thread.sleep(100); 
     } 

     if(User32.INSTANCE.UnhookWindowsHookEx(hHook)) 
      System.out.println("Unhooked"); 

    } 
} 

Je l'ai fait clavier/crochets de souris plusieurs fois en utilisant les deux C++ et C# en le passé. C'est ma première tentative avec Java, et je ne sais pas si j'ai importé et mappé la bibliothèque correctement. Des idées?

Merci.

Répondre

10

Il apparaît que vous devez appeler GetMessage ou PeekMessage, ce qui est étrange - il n'est pas mentionné dans la documentation pour Hooks ou LowLevelKeyboardProc. Je ne connais pas assez cette partie de l'API pour deviner la raison.

Je viens d'utiliser les classes par exemple:

import com.sun.jna.examples.win32.*; 

public class Callback { 
    public static User32.HHOOK hHook; 
    public static User32.LowLevelKeyboardProc lpfn; 
    public static volatile boolean quit = false; 

    public static void main(String[] args) throws Exception { 
    W32API.HMODULE hMod = Kernel32.INSTANCE.GetModuleHandle(null); 
    lpfn = new User32.LowLevelKeyboardProc() { 
     public W32API.LRESULT callback(int nCode, W32API.WPARAM wParam, 
      User32.KBDLLHOOKSTRUCT lParam) { 
     System.out.println("here"); 
     quit = true; 
     return User32.INSTANCE.CallNextHookEx(hHook, nCode, wParam, lParam 
      .getPointer()); 
     } 
    }; 
    hHook = User32.INSTANCE.SetWindowsHookEx(User32.WH_KEYBOARD_LL, lpfn, hMod, 
     0); 
    if (hHook == null) 
     return; 
    User32.MSG msg = new User32.MSG(); 
    while (!quit) { 
     User32.INSTANCE.PeekMessage(msg, null, 0, 0, 0); 
     Thread.sleep(100); 
    } 
    if (User32.INSTANCE.UnhookWindowsHookEx(hHook)) 
     System.out.println("Unhooked"); 
    } 
} 
+0

a vu un autre exemple en utilisant GetMessage/DispatchMessage, mais jamais pensé qu'il n'a rien à voir avec le crochet du clavier lui-même (Je n'ai jamais eu besoin d'eux en C++/C#). Vraiment apprécier votre aide McDowell, j'ai eu ma santé mentale à nouveau :) – temp

+2

comment obtenir com.sun.jna.examples.win32? Je ne peux pas le trouver à partir de jna.jar ou de platform.jar. S'il vous plaît, faites-moi savoir. Je vous remercie. –

+3

@Qiang Li - J'ai écrit ce code contre JNA 3.0.9; les classes d'exemples étaient dans 'examples.jar' – McDowell

0

Un exemple minimaliste:

import com.sun.jna.platform.win32.Kernel32; 
import com.sun.jna.platform.win32.User32; 
import com.sun.jna.platform.win32.WinDef.HINSTANCE; 
import com.sun.jna.platform.win32.WinDef.LPARAM; 
import com.sun.jna.platform.win32.WinDef.LRESULT; 
import com.sun.jna.platform.win32.WinDef.WPARAM; 
import com.sun.jna.platform.win32.WinUser.HOOKPROC; 

public class MainTestKeyHook { 


    public static void main(String[] args) throws Exception { 
     HOOKPROC hookProc = new HOOKPROC_bg(); 
     HINSTANCE hInst = Kernel32.INSTANCE.GetModuleHandle(null); 

     User32.HHOOK hHook = User32.INSTANCE.SetWindowsHookEx(User32.WH_KEYBOARD_LL, hookProc, hInst, 0); 
     if (hHook == null) 
      return; 
     User32.MSG msg = new User32.MSG(); 
     System.err.println("Please press any key ...."); 
     while (true) { 
      User32.INSTANCE.GetMessage(msg, null, 0, 0); 
     } 
    } 
} 

class HOOKPROC_bg implements HOOKPROC { 

    public HOOKPROC_bg() { 
    } 

    public LRESULT callback(int nCode, WPARAM wParam, LPARAM lParam) { 
     System.err.println("callback bbbnhkilhjkibh nCode: " + nCode); 
     return new LRESULT(0); 
    } 
} 
Questions connexes