2007-10-25 23:55:32 Kenny

如何使鍵盤、Mouse失效(JournalPlayBack Hook)

來源:cww

我們常見一些導覽系統或教學系統,會自動移動Mouse與Keyin字,而那個時候,我們
不管Keyin或動Mouse都沒有效,直到完成了導覽系統的某個動作後才讓使用者可以移
動Mouse與做Keyin的動作;想做到這個,要借重JournalPlayBack Hook。

JournalPlayBack Hook,它和JournalRecord Hook合稱Journal Hook,它們作用
的範圍是整個System,也就是掛上這個Hook後,影響的層面不單是這個Process,而是
所有的Process,而這兩Hook又不用寫在Dll之中,所以很好用。

首先我們要知道由鍵盤和Mouse輸入等的硬體訊息,會存到一個System Queue而後OS會
到該System Queue看有沒有訊息在其中,若有則擷取出來,看目前Active的Window是誰
而將訊息Post給它。而掛上JournalRecord Hook時,當有訊息被擷取出來時,會先執行
我們所設定的Hook Function(在vb中,一定要放在.BAS檔之中)。這可以做什麼事呢?
例如們可以Check整個系統是否有按了鍵盤或有沒有移動Mouse(一般來說,KeyUp,KeyDown
, MouseMove等Event只有Form在Active 時才收得到,掛上JournalRecord hook後,執行
Hook的thread便能收到所有這些訊息)。再如,它既然能收到Keyboard、Mouse的訊息,那
便可以將收到的訊息記錄起來(記錄於Memory或Disk都可以),之後再依方才的順序重新
將訊息放送出來,可重新執行方才的動作(這不就是巨集的作法嗎),或許
它叫JournalRecord便是這個原因。再來便是播放記錄訊息的問題了,如果一面播放,一
面有其他訊息插隊(如移動Mouse),那就不對了,所以JournalPlayBack這個Hook它會
讓Mouse、Keyboard都失效,當OS 要求讀System Queue時,便會啟動這個Hook,就在此
時,我們可以把方才記錄起來的訊息丟出一個出來,OS再要求讀System Queue時,再丟
下一個訊息,如此達重播的效果(所以才叫JournalPlayBack),正因它會讓鍵盤、Mouse
失效,拿它來做導覽、教學系統的自動Move Mouse或文字顯示是最適合的了。

Mouse的自動導引系統製作方式,可參考如何自動移動Mouse

'以下在.Bas中
Declare Sub Sleep Lib "KERNEL32" (ByVal dwMilliseconds As Long)
Const WM_MOUSELAST = &H209
Const WM_MOUSEFIRST = &H200
Public Const WM_KEYLAST = &H108
Public Const WM_KEYFIRST = &H100
Public Const WH_JOURNALRECORD = 0
Public Const WH_JOURNALPLAYBACK = 1

Type EVENTMSG
        message As Long
        paramL As Long
        paramH As Long
        time As Long
        hwnd As Long
End Type
Declare Function SetWindowsHookEx Lib "user32" Alias _
   "SetWindowsHookExA" (ByVal idHook As Long, ByVal lpfn As Long, _
   ByVal hmod As Long, ByVal dwThreadId As Long) As Long
Declare Function UnhookWindowsHookEx Lib "user32" _
   (ByVal hHook As Long) As Long
Declare Function CallNextHookEx Lib "user32" (ByVal hHook As Long, _
   ByVal nCode As Long, ByVal wParam As Long, lParam As Any) As Long
Public hNxtHook As Long   ' handle of Hook Procedure
Public msg As EVENTMSG

Sub EnableHook()
   hNxtHook = SetWindowsHookEx(WH_JOURNALPLAYBACK, AddressOf HookProc, App.hInstance, 0)
End Sub
Sub FreeHook()
    Dim ret As Long
    ret = UnhookWindowsHookEx(hNxtHook)
End Sub
Function HookProc(ByVal code As Long, ByVal wParam As Long, _
                ByVal lParam As Long) As Long
HookProc = CallNextHookEx(hNxtHook, code, wParam, lParam)
End Function

'以下在Form中,需求:一個Command1, 一個text1
Private Sub Command1_Click()
Dim str5 As String, len5 As Long, i As Long

Call EnableHook
str5 = "這是一個測試JournalPlayBackHook的程式"
len5 = Len(str5)
For i = 1 To len5
    Text1.Text = Mid(str5, 1, i)
    Text1.Refresh
    Sleep (200)
Next
Call FreeHook
End Sub