Search code examples
unity-game-enginefocuskeypress

Capture keypress in Unity when Unity doesn't have the input focus


I need Unity to capture ALL key presses, even if Unity doesn't have the focus.

I've tried to use:

Input.KeyPress()

But this seems to only work if Unity has the focus of the user's input. I need it to work when it doesn't have the focus, such as when I'm looking at / working with another Windows program.

PS: I already turned on the "Run in Background" option in player preferences.


Solution

  • This is totally possible! Although, there is no way to do it by using only the tools in-built into Unity3D. You will have to use native libraries to do that.

    The example below hooks the hook chain with a hook type of WH_KEYBOARD, which corresponds to a message-level keyboard hook. You can read more on SetWindowsHookEx and different types [ here][1].

    You can check the parameters that are being received on hooking such a message type (WH_KEYBOARD) [here][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 example comes from [this blog][3].

    Such a way of hooking will only work on Windows systems. If you need to make a separate hook on OS X or Linux you would need to do it in a native way in that operating system.

    I cannot post more than 1 link because I lack reputation on SO. I hope one of the mods will edit my post accordingly.

     [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