2010-12-31

Windows Message in the Unity3D : Hooks

參考這篇連結,讓 Unity 也可以做 Hook Windows Message 的動作,底下是修改並精簡至 Unity 的範例,範例中的 m_hookType 設定成 WH_KEYBOARD ,所以是 hook 鍵盤的訊息,若要 hook 其它的訊息可以透過修改 m_hookType 來達成,我們可以在 CoreHookProc 處理傳來的鍵盤訊息,使 Unity 做出對應的動作(但要注意的是,呼叫CoreHookProc的 Thread 不是 Unity 的主要 Thread,不能執行非 thread-safe Unity API!)。

大概敘述一下底下範例的使用方法:

1) 建立一個新的 C Sharp Script,取名為 KBHooks,並將範例的程式碼覆蓋進去。
2) 將此 KBHooks.cs 從 Project 拖曳至 Hierarchy 內的 Main Camera 上。
3) 執行。

執行時在鍵盤上敲幾個鍵,離開執行之後會在 Console 視窗看到類似的訊息:


KBHooks.cs:
using UnityEngine;
 
using System;
using System.Collections;
using System.Runtime.InteropServices;
 
public class KBHooks : MonoBehaviour
{
    [DllImport("user32")]
    protected static extern IntPtr SetWindowsHookEx(
        HookType code, HookProc func, IntPtr hInstance, int threadID);
 
    [DllImport("user32")]
    protected static extern int UnhookWindowsHookEx(
        IntPtr hhook);
 
    [DllImport("user32")]
    protected static extern int CallNextHookEx(
        IntPtr hhook, int code, IntPtr wParam, IntPtr lParam);
 
    [DllImport("Kernel32")]
    protected static extern uint GetLastError();
 
    // Hook Types
    protected enum HookType : int
    {
        WH_JOURNALRECORD = 0,
        WH_JOURNALPLAYBACK = 1,
        WH_KEYBOARD = 2,
        WH_GETMESSAGE = 3,
        WH_CALLWNDPROC = 4,
        WH_CBT = 5,
        WH_SYSMSGFILTER = 6,
        WH_MOUSE = 7,
        WH_HARDWARE = 8,
        WH_DEBUG = 9,
        WH_SHELL = 10,
        WH_FOREGROUNDIDLE = 11,
        WH_CALLWNDPROCRET = 12,
        WH_KEYBOARD_LL = 13,
        WH_MOUSE_LL = 14
    }
 
    protected IntPtr m_hhook = IntPtr.Zero;
    protected HookType m_hookType = HookType.WH_KEYBOARD;
 
    protected delegate int HookProc(int code, IntPtr wParam, IntPtr lParam);
 
    protected bool Install(HookProc cbFunc)
    {
        if (m_hhook == IntPtr.Zero)
            m_hhook = SetWindowsHookEx(
                m_hookType, 
                cbFunc, 
                IntPtr.Zero, 
                (int)AppDomain.GetCurrentThreadId());
 
        if (m_hhook == IntPtr.Zero)
            return false;
 
        return true;
    }
 
    protected void Uninstall()
    {
        if (m_hhook != IntPtr.Zero)
        {
            UnhookWindowsHookEx(m_hhook);
            m_hhook = IntPtr.Zero;
        }
    }
 
    protected int CoreHookProc(int code, IntPtr wParam, IntPtr lParam)
    {
        if (code < 0)
            return CallNextHookEx(m_hhook, code, wParam, lParam);
 
        Debug.Log(
            "hook code =" + code.ToString() + 
            " lparam=" + lParam.ToString() + 
            " wparam=" + wParam.ToString());
 
        // Yield to the next hook in the chain
        return CallNextHookEx(m_hhook, code, wParam, lParam);
    }
 
    // Use this for initialization
    void Start()
    {
        Debug.Log("install hook");
        Install(CoreHookProc);
    }
 
    void OnDisable()
    {
        Debug.Log("Uninstall hook");
        Uninstall();
    }
 
}

1 則留言 :