【问题标题】:Capture keypress in Unity when Unity doesn't have the input focus当 Unity 没有输入焦点时在 Unity 中捕获按键
【发布时间】:2016-03-31 17:07:16
【问题描述】:

我需要 Unity 来捕捉所有按键,即使 Unity 没有焦点。

我试过用:

Input.KeyPress()

但这似乎只有在 Unity 拥有用户输入的焦点时才有效。我需要它在它没有焦点时工作,例如当我正在查看/使用另一个 Windows 程序时。

PS:我已经在播放器偏好设置中开启了“后台运行”选项。

【问题讨论】:

    标签: unity3d focus keypress


    【解决方案1】:

    这完全有可能!虽然,仅使用 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();
        }
    
    }
    

    这个例子来自[this blog][3]。

    这种挂钩方式适用于 Windows 系统。如果您需要在 OS X 或 Linux 上制作单独的挂钩,则需要在该操作系统中以本机方式进行。

    我不能发布超过 1 个链接,因为我在 SO 上缺乏声誉。我希望其中一个模组能相应地编辑我的帖子。

     [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
    

    【讨论】:

      【解决方案2】:

      我已经根据@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;
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-11-12
        • 1970-01-01
        • 1970-01-01
        • 2021-08-20
        • 2016-07-02
        • 2012-06-14
        • 1970-01-01
        • 2014-11-18
        相关资源
        最近更新 更多