2011-09-02 10 views
8

雖然我搜索了很多,但我仍然不清楚「鉤子」到底是什麼。例如,我閱讀wiki answers此信息:什麼是「鉤子」以及如何使用Java編寫一個?以及如何與內核通信以瞭解用戶按下的按鍵/註冊到操作系統

鉤是在另一個 一段代碼的前面夾着一塊代碼的方法,從而使代碼的第一塊 第二片的之前執行代碼,給第一段代碼一個機會來監視和/或過濾第二段代碼的行爲。一個 的例子可能是一個鼠標鉤子,允許鉤子代碼監視 鼠標,同時保留原始鼠標事件處理例程的功能。

我也讀了這個post,但我仍然不明白什麼是「鉤子」。有人可以用通俗的話來解釋什麼是「鉤子」?爲什麼有些人寫一個「鉤子」?另外,是否可以在Java中編寫一個「鉤子」?

注:

我想用Java編寫一個鍵盤記錄和我的一個朋友說,你必須寫一個「鉤」在C.我不能用Java編寫的全鍵盤記錄器(只能在Windows上運行)?

編輯

請給w.r.t鍵盤記錄答案。我如何要求kernel提供有關使用掛鉤向我的應用程序提供的按鍵信息?或者我如何使用JNI在OS上註冊我的應用程序?我希望我的應用程序記錄用戶按下的按鍵。

+1

我認爲你的朋友的意思是說你需要使用本地方法。你可以用C編寫一個本地方法,並使用Java Native Interface(JNI)從Java調用它。 – toto2

+0

@ toto2和那個本地方法會做什麼? – saplingPro

+0

這將是一個記錄密鑰的系統函數。事實上,你最好完全拋棄Java來完成這樣的工作。 Java是可移植的,缺點是它不能執行與操作系統有關的東西。我不太瞭解Windows,但可能C#會更合適。 – toto2

回答

2

我將與至少兩個不同的概念字鉤相關聯:

一)觀察者模式,其中一類,您可以添加將某些事件通知監聽器。您可以在Swing,Servlet API和許多第三方框架中找到它。

b)模板方法模式。抽象類定義以什麼順序調用哪些方法,實現類可以重寫這些方法。這個例子不是很常見,但你偶爾會看到它們。

1

其他名稱可能是委託或回調。

Java中的一個例子是MouseListener(http://download.oracle.com/javase/tutorial/uiswing/events/mouselistener.html)。 MouseListener是一個與諸如mouseClicked(MouseEvent e)等方法的接口。爲了響應用戶的鼠標操作,您將實現MouseListener,當用戶單擊時,Java Swing庫將調用您的監聽器類(在您通過調用addMouseListener註冊之後)。

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提供了一種用於外部實體鉤它的方式 - 即通過外部對象的引用和該外部對象將被首先執行。因此,如果您需要進行某種不屬於原始實現的處理,只需傳遞參考而不是修補原始來源即可。

5

Hooking - Wikipedia

在計算機編程的,術語鉤涵蓋用於改變或通過截取函數增加的 應用程序或其它軟件組件的操作系統的行爲,一系列的技術 在軟件組件之間傳遞的調用或消息或事件。處理這種攔截的函數調用,事件或消息的代碼 被稱爲「鉤子」,它被稱爲 。

內置於Java中的一個很好的示例是Runtime.addShutdownHook。 A 關機鉤只是一個初始化但未啓動的線程。當虛擬機開始其關閉序列時,它將以某種未指定的順序啓動所有已註冊的關閉掛鉤,並讓它們同時運行。

Runtime.addShutdownHook(new Thread(){ 
    @Override 
    public void run(){ 
     // do something before application terminates 
    } 
}); 
1

至於鍵盤記錄器:是的,你可以寫大部分Java編寫,但一小部分將要進入一個JNI模塊,因爲例如用全局鉤子一個DLL /線程/不管被「注入」到其他進程......因爲並非所有進程託管一個JVM等,這將無法在Java中工作...因此您需要使用JNI和一些C來爲您的鍵盤記錄器的那部分編寫DLL ...

EDIT - 按照評論:

This article深入描述了全局掛鉤是什麼以及注入等是什麼意思......

+0

@ Yahia'「全局掛鉤一個DLL /線程/任何獲得」注入「到其他進程..」'你可以做得更清楚,幷包括在你的答案 – saplingPro

+0

@grassPro - 請在我的編輯鏈接... – Yahia

1

就你而言,鉤子是一種在OS中註冊監聽器(處理程序)的軟件機制。這個處理程序(例如應用程序中的一個方法)將在操作系統觸發按鍵事件(按鍵)時通知操作系統。

這只是觀察者模式的應用。

虛構的例子:

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中沒有的一些片依託本土code.I想到要走的最簡單方法是選擇一個與你的操作系統相關的語言。對於Windows,我會用C#來完成。

檢查此鏈接:

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

+0

以及我如何與內核通話? – saplingPro

+0

與內核交談?你不需要。只需向操作系統註冊,它會在每次擊鍵時調用你的處理程序。在這個頁面http://en.wikipedia.org/wiki/Hooking你有一個C#鍵盤記錄器的例子,有很多開源代碼以及整個網絡。 –

+0

@ Mister Smith我想用JNI註冊我的應用程序。即我想使用Java和本機代碼,特別是C來執行此操作。就是那個問題。現在我怎樣才能在操作系統上註冊,以便在每次擊鍵時調用我的處理程序。 – saplingPro

1

捕獲需要運行的本地代碼(JNI,JNA等)並且是高度系統依賴低電平設備事件。在Linux上,您可能不需要與內核進行通信,最有可能使用X11服務器。

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項目,包括這個文件並執行此方法。確保當實際掛鉤觸發,在C代碼中調用invokeCallback

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

至於如何記錄每個關鍵事件,操作系統通常會提供一些API來攔截關鍵事件。對於Windows系統,您可以通過攔截全局密鑰消息來實現此目的。我在其他系統上沒有任何經驗。無論如何,你可以設置適當的中斷,這是安靜的低水平。你總是可以將你的答案谷歌。 :)

相關問題