OOIII/

Unity 屏蔽系统快捷键

在某些项目中需要保证程序置顶,并屏蔽系统按键,防止在程序运行时有弹窗出现,比如win、alt+tab。这可以通过windows的键盘钩子实现,代码如下。

在编辑模式时会偶发crash,原因未知,发布后正常使用。

注意的是,SetWindowsHookEx 第三个参数有多种获取方式,可看下代码开头的参考链接。

using UnityEngine;
using System;
using System.Runtime.InteropServices;
using System.Diagnostics;


/// <summary>
/// http://geekswithblogs.net/aghausman/archive/2009/04/26/disable-special-keys-in-win-app-c.aspx
/// https://gist.github.com/Lunchbox4K/291f9c8a2501170221d11d29d1355ee1
/// https://csharp.hotexamples.com/zh/examples/-/KBDLLHOOKSTRUCT/-/php-kbdllhookstruct-class-examples.html
/// https://gist.github.com/Stasonix/3181083
/// https://blog.walterlv.com/post/add-global-windows-hook-in-dotnet.html
/// https://stackoverflow.com/questions/14260522/why-use-loadlibrary-instead-of-just-getting-baseaddress-of-your-program
/// https://answers.unity.com/questions/1398007/how-do-i-disable-the-system-shortcut-key-after-the-1.html
/// </summary>
/// 

public class KeyboardHook : MonoBehaviour
{
    [DllImport("user32.dll")]
    static extern IntPtr SetWindowsHookEx(int idHook, keyboardHookProc callback, IntPtr hInstance, uint threadId);
    [DllImport("user32.dll")]
    static extern bool UnhookWindowsHookEx(IntPtr hInstance);
    [DllImport("user32.dll")]
    static extern int CallNextHookEx(IntPtr idHook, int nCode, int wParam, ref KeyboardHookData lParam);
    [DllImport("kernel32.dll")]
    static extern IntPtr LoadLibrary(string lpFileName);
    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    static extern IntPtr GetModuleHandle(string name);

    // <see cref="https://msdn.microsoft.com/en-us/library/windows/desktop/ms644967(v=vs.85).aspx"/>
    struct KeyboardHookData
    {
        public int vkCode;
        public int scanCode;
        public int flags;
        public int time;
        public int dwExtraInfo;
    }

    delegate int keyboardHookProc(int code, int wParam, ref KeyboardHookData lParam);

    // <see cref="https://msdn.microsoft.com/en-us/library/windows/desktop/ms644959%28v=vs.85%29.aspx#wh_keyboard_llhook"/>
    static readonly int WH_KEYBOARD_LL = 13;
    static readonly int WM_KEYDOWN = 0x100;
    static readonly int WM_KEYUP = 0x101;
    static readonly int WM_SYSKEYDOWN = 0x104;
    static readonly int WM_SYSKEYUP = 0x105;

    static IntPtr hhook = IntPtr.Zero;
    static void Hook()
    {
        //注释的三种方式都可以
        var hModule = LoadLibrary("User32");
        //var hModule = GetModuleHandle(null);
        //var hModule = Process.GetCurrentProcess().MainModule.BaseAddress;
        //var hModule = GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName);

        //Call library hook function
        hhook = SetWindowsHookEx(WH_KEYBOARD_LL, new keyboardHookProc(HookProc), hModule, 0);
    }

    static void Unhook()
    {
        UnhookWindowsHookEx(hhook);
    }

    // <see cref="https://msdn.microsoft.com/en-us/library/windows/desktop/ms644984%28v=vs.85%29.aspx"/>
    static int HookProc(int code, int wParam, ref KeyboardHookData lParam)
    {
        if (code >= 0)
        {
            if (wParam == WM_KEYUP || wParam == WM_SYSKEYUP || wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN)
            {
                UnityEngine.Debug.Log("lParam.vkCode = " + lParam.vkCode + " / lParam.flags = " + lParam.flags);
                bool Suppress = false;

                if (((lParam.flags == 32) && (lParam.vkCode == 0x09)) ||     // Alt+Tab
                    ((lParam.flags == 32) && (lParam.vkCode == 0x1B)) ||      // Alt+Esc
                    ((lParam.flags == 0) && (lParam.vkCode == 0x1B)) ||      // Ctrl+Esc
                    ((lParam.flags == 1) && (lParam.vkCode == 0x5B)) ||      // Left Windows Key
                    ((lParam.flags == 1) && (lParam.vkCode == 0x5C)) ||      // Right Windows Key
                    ((lParam.flags == 32) && (lParam.vkCode == 0x73)) ||      // Alt+F4              
                    ((lParam.flags == 32) && (lParam.vkCode == 0x20)))        //Alt+Space
                    Suppress = true;

                if (Suppress)
                {
                    return 1;
                }
            }
        }

        return CallNextHookEx(hhook, code, wParam, ref lParam);
    }

    void Start()
    {
        Hook();
    }
    void OnDestroy()
    {
        Unhook();
    }
}


留下一条评论

共有 3 条评论

  1. 马内:

    技术文章,学习了。暑期快乐,感谢博主的分享,支持了。

    2021-07-31 17:22 回复
    1. ooiii:

      能帮到你就Ok

      2021-08-16 17:40 回复
  2. Teacher Du:

    过来学习一下!

    2021-09-06 17:24 回复