钩子(Hook),是Windows消息处理机制的一个平台,应用程序可以在上面设置子程以监视指定窗口的某种消息,而且所监视的窗口可以是其他进程所创建的。当消息到达后,在目标窗口处理函数之前处理它。钩子机制允许应用程序截获处理window消息或特定事件。
钩子实际上是一个处理消息的程序段,通过系统调用,把它挂入系统。每当特定的消息发出,在没有到达目的窗口前,钩子程序就先捕获该消息,亦即钩子函数先得到控制权。这时钩子函数即可以加工处理(改变)该消息,也可以不作处理而继续传递该消息,还可以强制结束消息的传递。
在某些情况下应用程序需要实现快捷键执行特定功能,例如Unity最小化后通过快捷键来截取桌面图片(最小化后用户焦点不在Unity上,UnityEngine下的Input.GetKey()也无法监听)。
修改了一下button1_Click(),改为了静态函数。
利用Hook实现全局键盘监听:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
//using System.Windows.Forms;
using UnityEngine;
public class GlobalInput : MonoBehaviour
{
//安装钩子
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
//卸载钩子
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
//向下传递钩子
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
//获取程序集模块的句柄
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
//全局钩子键盘为13
private const int WH_KEYBOARD_LL = 13;
//按下键
private const int WM_KEYDOWN = 0x0100;
private static LowLevelKeyboardProc _proc = HookCallback;
private static IntPtr _hookID = IntPtr.Zero;
void Start()
{
_hookID = SetHook(_proc);
}
void OnApplicationQuit()
{
UnhookWindowsHookEx(_hookID);
}
//安装Hook,用于截获键盘。
private static IntPtr SetHook(LowLevelKeyboardProc proc)
{
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
return SetWindowsHookEx(WH_KEYBOARD_LL, proc, GetModuleHandle(curModule.ModuleName), 0);
}
}
private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
//nCode>0表示此消息已由Hook函数处理了,不会交给Windows窗口过程处理了
//nCode=0则表示消息继续传递给Window消息处理函数
if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
{
int vkCode = Marshal.ReadInt32(lParam);
// UnityEngine.Debug.Log("Keydown:" + vkCode);
// vkCode 44 is PrintScreen Button
if (vkCode == 44 )
{
UnityEngine.Debug.Log("按键44");
}
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);//传给下一个钩子
}
}