Unity|利用Hook实现Unity窗口小化后的键盘输入监听

钩子(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 InterceptKeys : 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);
            if (vkCode == 65 && System.Windows.Forms.Control.ModifierKeys == Keys.Shift)
            {
                CutImage.button1_Click();//按下快捷键Shift+A,开始截图
            }

        }
        return CallNextHookEx(_hookID, nCode, wParam, lParam);//传给下一个钩子
    }
}

 

发布了162 篇原创文章 · 获赞 20 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/weixin_39766005/article/details/100994258
今日推荐