HotkeyHook -> 引入外部方法
using System;
using System.Runtime.InteropServices;
public class HotkeyHook
{
// 安装钩子
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
// 卸载钩子
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool UnhookWindowsHookEx(IntPtr hhk);
// 传递钩子
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
// 获取模块句柄
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr GetModuleHandle(string lpModuleName);
[DllImport("user32.dll", CharSet = CharSet.Unicode, ExactSpelling = true)]
public static extern int GetAsyncKeyState(int vKey);
[DllImport("user32.dll")]
public static extern bool GetKeyboardState(byte[] lpKeyState);
public delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
}
HookType -> 定义钩子类型,方便使用
public enum HookType : int
{
/// <summary>
/// 记录输入消息。用于日志或重放功能。
/// </summary>
WH_JOURNALRECORD = 0,
/// <summary>
/// 重放由 WH_JOURNALRECORD 钩子记录的消息。
/// </summary>
WH_JOURNALPLAYBACK = 1,
/// <summary>
/// 钩子函数监视键盘消息。
/// </summary>
WH_KEYBOARD = 2,
/// <summary>
/// 钩子函数监视从消息队列中取出的消息。
/// </summary>
WH_GETMESSAGE = 3,
/// <summary>
/// 钩子函数监视发送到窗口过程的消息。
/// </summary>
WH_CALLWNDPROC = 4,
/// <summary>
/// 钩子函数在各种窗口事件之前接收通知。
/// </summary>
WH_CBT = 5,
/// <summary>
/// 钩子函数用于过滤系统消息。
/// </summary>
WH_SYSMSGFILTER = 6,
/// <summary>
/// 钩子函数监视鼠标消息。
/// </summary>
WH_MOUSE = 7,
/// <summary>
/// 钩子函数监视硬件消息。
/// </summary>
WH_HARDWARE = 8,
/// <summary>
/// 用于调试其他钩子过程。
/// </summary>
WH_DEBUG = 9,
/// <summary>
/// 钩子函数监视外壳应用程序事件。
/// </summary>
WH_SHELL = 10,
/// <summary>
/// 钩子函数在前台应用程序空闲时调用。
/// </summary>
WH_FOREGROUNDIDLE = 11,
/// <summary>
/// 钩子函数在窗口过程处理完消息后接收通知。
/// </summary>
WH_CALLWNDPROCRET = 12,
/// <summary>
/// 低级别的键盘钩子函数,用于监视全局键盘输入事件。
/// </summary>
WH_KEYBOARD_LL = 13,
/// <summary>
/// 低级别的鼠标钩子函数,用于监视全局鼠标输入事件。
/// </summary>
WH_MOUSE_LL = 14
}
GlobalInput -> 全局输入监听管理
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using UnityEngine;
using Debug = UnityEngine.Debug;
public class GlobalInput : MonoBehaviour
{
#region SINGLETON
private static GlobalInput _instance;
public static GlobalInput Instance
{
get
{
if (_instance == null)
{
_instance = FindObjectOfType<GlobalInput>();
if (_instance == null)
{
GameObject container = new GameObject("GlobalInputManager");
_instance = container.AddComponent<GlobalInput>();
}
}
return _instance;
}
}
#endregion
private static readonly bool[] KeyStatus = new bool[255];
private const int WM_KEYDOWN = 0x0100;
private const int WM_KEYUP = 0x0101;
private const int WM_SYSKEYDOWN = 0x0104;
private const int WM_SYSKEYUP = 0x0105;
private IntPtr _windowHandle;
private HotkeyHook.LowLevelKeyboardProc _llKbProc;
private IntPtr _hookID = IntPtr.Zero;
private void Awake()
{
SetHook();
_instance = this;
DontDestroyOnLoad(_instance);
}
private void SetHook()
{
_llKbProc ??= HookCallback;
Process curProcess = Process.GetCurrentProcess();
ProcessModule curModule = curProcess.MainModule;
_windowHandle = HotkeyHook.GetModuleHandle(curModule?.ModuleName);
_hookID = HotkeyHook.SetWindowsHookEx((int)HookType.WH_KEYBOARD_LL, _llKbProc, _windowHandle, 0);
if (_hookID == IntPtr.Zero)
{
Debug.Log("Failed to hook");
}
Debug.Log("Hooked successfully");
}
private void UnsetHook()
{
HotkeyHook.UnhookWindowsHookEx(_hookID);
_hookID = IntPtr.Zero;
}
private IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0)
{
int vkCode = Marshal.ReadInt32(lParam);
if (wParam == (IntPtr)WM_KEYDOWN || wParam == (IntPtr)WM_SYSKEYDOWN)
{
SetKeyState(vkCode, true);
}
if (wParam == (IntPtr)WM_KEYUP || wParam == (IntPtr)WM_SYSKEYUP)
{
SetKeyState(vkCode, false);
}
}
return HotkeyHook.CallNextHookEx(_hookID, nCode, wParam, lParam);
}
private void SetKeyState(int key, bool state)
{
KeyStatus[key] = state;
}
/// <summary>
/// 获取按键状态
/// </summary>
/// <param name="key">按键类型</param>
/// <returns>true:按下 | false:抬起</returns>
public bool GetKeyStatus(GlobalKeyCode key)
{
return KeyStatus[(int)key];
}
public bool GetKeyDown(List<GlobalKeyCode> keys)
{
return keys.TrueForAll(key => KeyStatus[(int)key]);
}
public bool GetKeyUp(List<GlobalKeyCode> keys)
{
return keys.TrueForAll(key => !KeyStatus[(int)key]);
}
void OnDisable()
{
UnsetHook();
Debug.Log("Uninstall hook");
}
}
其他方式:
判断 if((HotkeyHook.GetAsyncKeyState((int)GlobalKeyCode.LBUTTON) & 0x8000) != 0){ 则表示按下鼠标左键 }判断是否有任意按键按下:
private bool IsAnyKeyDown() { byte[] keyState = new byte[256]; HotkeyHook.GetKeyboardState(keyState); for (int i = 0; i < keyState.Length; i++) { if ((keyState[i] & 0x80) != 0) // 检查高位字节 { return true; } } return false; }
GlobalKeyCode -> 按键对应的16进制
public enum GlobalKeyCode : int
{
LBUTTON = 0x01,
RBUTTON = 0x02,
CANCEL = 0x03,
MBUTTON = 0x04,
BACK = 0x08,
TAB = 0x09,
CLEAR = 0x0C,
RETURN = 0x0D,
SHIFT = 0x10,
CTRL = 0x11,
MENU = 0x12,
PAUSE = 0x13,
CAPITAL = 0x14,
ESCAPE = 0x1B,
SPACE = 0x20,
PRIOR = 0x21,
NEXT = 0x22,
END = 0x23,
HOME = 0x24,
LEFT = 0x25,
UP = 0x26,
RIGHT = 0x27,
DOWN = 0x28,
SELECT = 0x29,
PRINT = 0x2A,
EXECUTE = 0x2B,
SNAPSHOT = 0x2C,
INSERT = 0x2D,
DELETE = 0x2E,
HELP = 0x2F,
// Number keys
N0 = 0x30,
N1 = 0x31,
N2 = 0x32,
N3 = 0x33,
N4 = 0x34,
N5 = 0x35,
N6 = 0x36,
N7 = 0x37,
N8 = 0x38,
N9 = 0x39,
// Letter keys
A = 0x41,
B = 0x42,
C = 0x43,
D = 0x44,
E = 0x45,
F = 0x46,
G = 0x47,
H = 0x48,
I = 0x49,
J = 0x4A,
K = 0x4B,
L = 0x4C,
M = 0x4D,
N = 0x4E,
O = 0x4F,
P = 0x50,
Q = 0x51,
R = 0x52,
S = 0x53,
T = 0x54,
U = 0x55,
V = 0x56,
W = 0x57,
X = 0x58,
Y = 0x59,
Z = 0x5A,
LWIN = 0x5B,
RWIN = 0x5C,
APPS = 0x5D,
SLEEP = 0x5F,
// Numpad keys
NUMPAD0 = 0x60,
NUMPAD1 = 0x61,
NUMPAD2 = 0x62,
NUMPAD3 = 0x63,
NUMPAD4 = 0x64,
NUMPAD5 = 0x65,
NUMPAD6 = 0x66,
NUMPAD7 = 0x67,
NUMPAD8 = 0x68,
NUMPAD9 = 0x69,
MULTIPLY = 0x6A,
ADD = 0x6B,
SEPARATOR = 0x6C,
SUBTRACT = 0x6D,
DECIMAL = 0x6E,
DIVIDE = 0x6F,
// Function keys
F1 = 0x70,
F2 = 0x71,
F3 = 0x72,
F4 = 0x73,
F5 = 0x74,
F6 = 0x75,
F7 = 0x76,
F8 = 0x77,
F9 = 0x78,
F10 = 0x79,
F11 = 0x7A,
F12 = 0x7B,
F13 = 0x7C,
F14 = 0x7D,
F15 = 0x7E,
F16 = 0x7F,
F17 = 0x80,
F18 = 0x81,
F19 = 0x82,
F20 = 0x83,
F21 = 0x84,
F22 = 0x85,
F23 = 0x86,
F24 = 0x87,
// Lock keys
NUMLOCK = 0x90,
SCROLL = 0x91,
// Modifiers
LSHIFT = 0xA0,
RSHIFT = 0xA1,
LCONTROL = 0xA2,
RCONTROL = 0xA3,
LALT = 0xA4,
RALT = 0xA5,
// Media keys
BROWSER_BACK = 0xA6,
BROWSER_FORWARD = 0xA7,
BROWSER_REFRESH = 0xA8,
BROWSER_STOP = 0xA9,
BROWSER_SEARCH = 0xAA,
BROWSER_FAVORITES = 0xAB,
BROWSER_HOME = 0xAC,
VOLUME_MUTE = 0xAD,
VOLUME_DOWN = 0xAE,
VOLUME_UP = 0xAF,
MEDIA_NEXT_TRACK = 0xB0,
MEDIA_PREV_TRACK = 0xB1,
MEDIA_STOP = 0xB2,
MEDIA_PLAY_PAUSE = 0xB3,
LAUNCH_MAIL = 0xB4,
LAUNCH_MEDIA_SELECT = 0xB5,
LAUNCH_APP1 = 0xB6,
LAUNCH_APP2 = 0xB7,
// Symbols
COLON = 0xBA,
PLUS = 0xBB,
COMMA = 0xBC,
HYPHEN = 0xBD,
PERIOD = 0xBE,
FSLASH = 0xBF,
TILDE = 0xC0,
BACKQUOTE = 0xC0, // duplicate of tilde
LSQUAREBRACKET = 0xDB,
BSLASH = 0xDC,
PIPE = 0xDC, // duplicate of back slash
RSQUAREBRACKET = 0xDD,
QUOTE = 0xDE,
PLAY = 0xFA,
ZOOM = 0xFB,
}
用法示例:
private void Update()
{
if (GlobalInput.Instance.GetKeyDown(new List<GlobalKeyCode>{GlobalKeyCode.LALT,GlobalKeyCode.X}))
{
Debug.Log("按下了左Alt + X");
}
}