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.
So you would instead use Input. GetButton("Jump") and define in Edit -> Project Settings -> Input that "Jump" is mapped to the positive key "space" (Unity will auto-supply some default keys, and Jump:Space is one). Additionally you can switch your Input. GetKey("a") / Input.
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
I've assembled a Unity package based on the @boris-makogonyuk answer with some usability improvements. The package is available on GitHub (MIT license): https://github.com/Elringus/UnityRawInput
You can use it as follows:
Include package namespace.
using UnityRawInput;
Initialize the input service to start processing native input messages.
RawKeyInput.Start();
Optinally, you can specify whether input messages should be handled when the application is not in focus (disabled by default).
var workInBackground = true;
RawKeyInput.Start(workInBackground);
Add listeners for the input events.
RawKeyInput.OnKeyUp += HandleKeyUp;
RawKeyInput.OnKeyDown += HandleKeyDown;
private void HandleKeyUp (RawKey key) { ... }
private void HandleKeyDown (RawKey key) { ... }
You can also check whether specific key is currently pressed.
if (RawKeyInput.IsKeyDown(key)) { ... }
You can stop the service at any time.
RawKeyInput.Stop();
Don't forget to remove listeners when you no longer need them.
private void OnDisable ()
{
RawKeyInput.OnKeyUp -= HandleKeyUp;
RawKeyInput.OnKeyDown -= HandleKeyDown;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With