13

尽管我进行了很多搜索,但我仍然不清楚“钩子”到底是什么。例如,我在wiki answers上阅读了这篇文章:

钩子是一种在另一段代码之前插入一段代码的方法,以便第一段代码在第二段代码之前执行,从而使第一段代码有机会监视和/或过滤行为第二段代码。一个例子可能是鼠标钩子,它允许钩子代码监视鼠标,同时保留原始鼠标事件处理例程的功能。

我也读过这篇文章,但我仍然不明白“钩子”到底是什么。有人可以用外行的话解释什么是“钩子”吗?为什么有些人会写一个“钩子”?另外,是否可以用 Java 编写“钩子”?

笔记:

我想用java写一个键盘记录器,我的一个朋友说你必须用C写一个“钩子”。我不能用Java写整个键盘记录器(只能在windows上操作)吗?

编辑

请给出答案 wrt 键盘记录器。我如何要求kernel使用挂钩将有关按下的键的信息提供给我的应用程序?或者我如何使用 JNI 向操作系统注册我的应用程序?我希望我的应用程序记录用户按下的键。

4

8 回答 8

6

挂钩 - 维基百科

在计算机编程中,挂钩一词涵盖了一系列技术,用于通过拦截软件组件之间传递的函数调用或消息或事件来改变或增强操作系统、应用程序或其他软件组件的行为。处理此类截获的函数调用、事件或消息的代码称为“挂钩”。

Java 内置的一个很好的例子是Runtime.addShutdownHook. 关闭挂钩只是一个已初始化但未启动的线程。当虚拟机开始其关闭序列时,它将以某种未指定的顺序启动所有已注册的关闭挂钩并让它们同时运行。

Runtime.addShutdownHook(new Thread(){
    @Override
    public void run(){
        // do something before application terminates
    }
});
于 2011-09-02T15:24:33.117 回答
6

我会将钩子这个词与至少两个不同的概念相关联:

a) 观察者模式,其中一个类允许您添加一个侦听器,该侦听器将在某些事件上得到通知。您可以在 Swing、Servlet API 和许多第 3 方框架中找到这一点。

b) 模板方法模式。抽象类定义了以什么顺序调用哪些方法,实现类可以覆盖这些方法。这样的例子并不常见,但你偶尔会看到它们。

于 2011-09-02T15:19:51.897 回答
1

至于键盘记录器:是的,你可以用 Java 编写大部分内容,但一小部分必须进入 JNI 模块,因为例如使用全局钩子,DLL/线程/任何东西都被“注入”到其他进程中......因为并非所有进程都托管 JVM 等。这在 Java 中不起作用...因此您需要使用 JNI 和一些 C 为您的键盘记录器的该部分编写 DLL...

编辑 - 根据评论:

本文深入描述了全局钩子的作用以及注入等的含义......

于 2011-09-02T15:46:25.630 回答
1

其他名称可能是委托或回调。

在 Java 中的一个例子是 MouseListener (http://download.oracle.com/javase/tutorial/uiswing/events/mouselistener.html)。MouseListener是一个带有方法的接口,例如mouseClicked(MouseEvent e). 为了响应用户的鼠标操作,您将实现MouseListener当用户单击时,Java Swing 库将调用您的侦听器类(在您通过调用addMouseListener.

于 2011-09-02T15:20:16.670 回答
1

这是一个简单的例子:

public void hookableMethod(HookObject hook, String param) { 
String innerParam = param;
if(hook != null) { 
 innerParam = hook.someHookMethod(innerParam);  
}

//rest of the code is working with inner param
}

在这个过于简单的示例中,hookableMethod 为外部实体提供了一种挂钩它的方法——即传递外部对象引用,并且这个外部对象将首先被执行。因此,如果您需要进行某种不属于原始实现的处理,您可以简单地通过传递引用而不是修补原始源来完成。

于 2011-09-02T15:21:00.570 回答
1

在您的情况下,挂钩是一种在操作系统中注册侦听器(处理程序)的软件机制。当触发按键事件(按键按下)时,操作系统将通知此处理程序(例如,您的应用程序中的一个方法)。

这只是观察者模式的一个应用。

一个虚构的例子:

    class MyKBHandler implements ISomeKeyboardListener {
        public void onKeyDown(<params containing key info here>){
            //Your code here, doing something with the params.
        }
    }

    MyKBHandler handler = new MyKBHandler();
    <someOSLibrary>.register(handler);

正如他们在其他答案中告诉您的那样,如果不依赖某些本机代码,就无法在 Java 中执行此操作。我认为最简单的方法是选择与您所针对的操作系统相关的语言。对于windows,我会用C#来做。

检查此链接:

http://msdn.microsoft.com/en-us/library/ms632589%28VS.85%29.aspx

于 2011-09-05T10:49:03.527 回答
1

捕获低级设备事件需要运行本机代码(JNI、JNA 等)并且高度依赖于系统。在 Linux 上,您可能不需要与内核通信,很可能与 X11 服务器通信。

于 2011-09-08T16:45:43.767 回答
0

首先,您必须定义一个管理器类,类似于:

package foo.bar

public class SomeHookManager {
    public static void initialize (...) {
        // <pre-initialization-routing>
        _native_init_();
        // <post-initialization-routing>
    }

    public static void registerCallback (IHookCallback callback)
    { /* save this callback */ }

    // this method will be invoked in your C code.
    protected static void invokeCallback () { /* invoke the saved callback */ }

    // this is a native method, the native modifier tells the compiler this method
    // is implemented in C, and linked at runtime.
    protected native static void _native_init_ ();
}

然后javah用来生成一个 C 头文件,结果是这样的(我实际上并没有编译这段代码,所以这是假设的):

/*
 * Class:     Win32
 * Method:    _native_init_
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_foo_bar_Win32_native_init_
    (JNIEnv * env, jobject obj);

创建一个 C 项目,包含此文件并实现此方法。确保在触发实际挂钩时,调用invokeCallback您的 C 代码:

jclass cls = (*env)->GetObjectClass(env, obj);
jmethodID mId = (*env)->GetStaticMethodID(env, cls, "invokeCallback", "()V");
if (mId == 0) { /* error handling */ }
(*env)->CallStaticVoidMethod(env, cls, mId);

将 C 项目编译成 DLL 文件,例如hookimpl_win32.dll,然后在 Java 代码中的某个位置动态链接它:

static {
    System.loadLibrary("hookimpl_win32"); // no need of .dll or .so in Unix alike OS's
}

确保 dll 与您的 jar 位于同一文件夹中。或-Djava.library.path=/path/to/your/dlls在 VM 参数中指定。

至于如何记录每个按键,操作系统通常会提供一些 API 来拦截按键事件。对于 Windows 系统,您可以通过拦截全局密钥消息来实现此目的。我在其他系统上没有任何经验。无论如何,您可以设置适当的中断,这是安静的低级。你可以随时用谷歌搜索你的答案。:)

于 2011-09-09T04:55:37.927 回答