当 Unity 没有输入焦点时在 Unity 中捕获按键
Capture keypress in Unity when Unity doesn't have the input focus
我需要 Unity 捕捉所有按键,即使 Unity 没有焦点。
我试过使用:
Input.KeyPress()
但这似乎只有在 Unity 具有用户输入的焦点时才有效。我需要它在没有焦点时工作,例如当我正在查看/使用另一个 Windows 程序时。
PS: 我已经在播放器首选项中打开了 "Run in Background" 选项。
这完全有可能!虽然,仅使用 Unity3D 中内置的工具是无法做到这一点的。您将不得不使用本机库来执行此操作。
下面的例子用钩子类型WH_KEYBOARD钩住钩子链,它对应于消息级键盘钩子。您可以在 SetWindowsHookEx
和不同类型 [此处][1].
阅读更多内容
您可以检查挂钩此类消息类型 (WH_KEYBOARD
) 时收到的参数[此处][2]
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);
// Hook types. To hook the keyboard we only need WH_KEYBOARD
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);
//We install the hook and hold on to the hook handle.
//The handle will be need to unhook.
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();
}
}
这个例子来自[这个博客][3]。
这种挂钩方式 仅 在 Windows 系统上工作。如果您需要在 OS X 或 Linux 上创建一个单独的挂钩,您需要在该操作系统中以本机方式进行。
我不能 post 超过 1 link 因为我在 SO 上缺乏声誉。我希望其中一个 mod 会相应地编辑我的 post。
[1]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms644990(v=vs.85).aspx
[2]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms644984(v=vs.85).aspx
[3]: http://phardera.blogspot.com.es/2010/12/windows-hooks-in-unity3d.html
我已经根据 @boris-makogonyuk 的回答组装了一个 Unity 包,并进行了一些可用性改进。
该软件包在 GitHub(MIT 许可证)上可用:https://github.com/Elringus/UnityRawInput
您可以按如下方式使用:
包括包命名空间。
using UnityRawInput;
初始化输入服务以开始处理本机输入消息。
RawKeyInput.Start();
您可以选择指定当应用程序未处于焦点时是否应处理输入消息(默认情况下禁用)。
var workInBackground = true;
RawKeyInput.Start(workInBackground);
为输入事件添加侦听器。
RawKeyInput.OnKeyUp += HandleKeyUp;
RawKeyInput.OnKeyDown += HandleKeyDown;
private void HandleKeyUp (RawKey key) { ... }
private void HandleKeyDown (RawKey key) { ... }
您还可以检查当前是否按下了特定的键。
if (RawKeyInput.IsKeyDown(key)) { ... }
您可以随时停止服务。
RawKeyInput.Stop();
不要忘记在不再需要时删除侦听器。
private void OnDisable ()
{
RawKeyInput.OnKeyUp -= HandleKeyUp;
RawKeyInput.OnKeyDown -= HandleKeyDown;
}
我需要 Unity 捕捉所有按键,即使 Unity 没有焦点。
我试过使用:
Input.KeyPress()
但这似乎只有在 Unity 具有用户输入的焦点时才有效。我需要它在没有焦点时工作,例如当我正在查看/使用另一个 Windows 程序时。
PS: 我已经在播放器首选项中打开了 "Run in Background" 选项。
这完全有可能!虽然,仅使用 Unity3D 中内置的工具是无法做到这一点的。您将不得不使用本机库来执行此操作。
下面的例子用钩子类型WH_KEYBOARD钩住钩子链,它对应于消息级键盘钩子。您可以在 SetWindowsHookEx
和不同类型 [此处][1].
您可以检查挂钩此类消息类型 (WH_KEYBOARD
) 时收到的参数[此处][2]
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);
// Hook types. To hook the keyboard we only need WH_KEYBOARD
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);
//We install the hook and hold on to the hook handle.
//The handle will be need to unhook.
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();
}
}
这个例子来自[这个博客][3]。
这种挂钩方式 仅 在 Windows 系统上工作。如果您需要在 OS X 或 Linux 上创建一个单独的挂钩,您需要在该操作系统中以本机方式进行。
我不能 post 超过 1 link 因为我在 SO 上缺乏声誉。我希望其中一个 mod 会相应地编辑我的 post。
[1]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms644990(v=vs.85).aspx
[2]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms644984(v=vs.85).aspx
[3]: http://phardera.blogspot.com.es/2010/12/windows-hooks-in-unity3d.html
我已经根据 @boris-makogonyuk 的回答组装了一个 Unity 包,并进行了一些可用性改进。 该软件包在 GitHub(MIT 许可证)上可用:https://github.com/Elringus/UnityRawInput
您可以按如下方式使用:
包括包命名空间。
using UnityRawInput;
初始化输入服务以开始处理本机输入消息。
RawKeyInput.Start();
您可以选择指定当应用程序未处于焦点时是否应处理输入消息(默认情况下禁用)。
var workInBackground = true;
RawKeyInput.Start(workInBackground);
为输入事件添加侦听器。
RawKeyInput.OnKeyUp += HandleKeyUp;
RawKeyInput.OnKeyDown += HandleKeyDown;
private void HandleKeyUp (RawKey key) { ... }
private void HandleKeyDown (RawKey key) { ... }
您还可以检查当前是否按下了特定的键。
if (RawKeyInput.IsKeyDown(key)) { ... }
您可以随时停止服务。
RawKeyInput.Stop();
不要忘记在不再需要时删除侦听器。
private void OnDisable ()
{
RawKeyInput.OnKeyUp -= HandleKeyUp;
RawKeyInput.OnKeyDown -= HandleKeyDown;
}