- Home /
Capturing Keyboard Input While running in background
Hello, I'm trying to create a persistent app for unity which will essentially get green-screened into my stream. The challenge is controlling the app, and allowing for input while the program isn't focused. I've almost gotten everything to work but I'm stuck with a crash.
At the moment I'm using SetWindowsHookEx and WH_KEYBOARD_LL to capture input. I've gathered up this code from all corners of the net, and it's been working very inconsistently. First off, I had to switch the thread ID in SetWindowsHookEx to 0 to get it to work at all, but when I build my app is capable of grabbing input while deselected, yeah!
The problem is, after ten or less keyboard actions, the exe will crash and no crash information is generated in app-data (or if I use a debug player, no information on the crash.) It's certainly linked to the use of WH_KEYBOARD_LL, and will only crash when that is bound and keys are pressed after my application has performed a certain amount of work. If nothing is happening in my scene then no crash, but after playing some sounds and making some game-objects, a full crash occurs.
Are there any work arounds for capturing input? I've heard of Raw-data, but haven't seen any references anywhere for getting that to work in unity and it seems super complicated for such a simple thing. Also, any other ideas on diagnosing this? Getting more information out of unity? I can provide the complied Exe as well
void Start() {
Install(LowLevelKeyboardProc);
Debug.Log("install hook");
}
[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, ref KBDLLHOOKSTRUCT 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
}
static protected IntPtr m_hhook = IntPtr.Zero;
protected HookType m_hookType = HookType.WH_KEYBOARD_LL;
protected delegate int HookProc(int nCode, IntPtr wParam, ref KBDLLHOOKSTRUCT lParam);
protected bool Install(HookProc cbFunc) {
if (m_hhook == IntPtr.Zero)
m_hhook = SetWindowsHookEx( m_hookType, cbFunc, IntPtr.Zero,
0); // <- This works, having thread-ID doesn't
if (m_hhook == IntPtr.Zero)
return false;
return true;
}
protected void Uninstall() {
if (m_hhook != IntPtr.Zero) {
UnhookWindowsHookEx(m_hhook);
m_hhook = IntPtr.Zero;
}
}
public class KBDLLHOOKSTRUCT{
public uint vkCode;
public uint scanCode;
public KBDLLHOOKSTRUCTFlags flags;
public uint time;
public UIntPtr dwExtraInfo;
}
public static int LowLevelKeyboardProc(int nCode, IntPtr wParam, ref KBDLLHOOKSTRUCT lParam){
if (nCode >= 0 && wParam.ToString() == "257") {
Debug.Log("Got: " + lParam.vkCode.ToString());
// -- Code Crashes Here
}
return CallNextHookEx( m_hhook, nCode, wParam, ref lParam);
}
void OnDisable(){
Debug.Log("Uninstall hook");
Uninstall();
}
Answer by WallHackJack · Dec 05, 2017 at 11:23 AM
I was able to find more success replacing the parts of my code above to match this. This basically took hours and hours of trial and error, and grabbing everyone's bits of code, mixing and matching until it didn't crash....
public struct KBDLLHOOKSTRUCT{
public int vkCode;
int scanCode;
public int flags;
int time;
int dwExtraInfo;
}
public static int LowLevelKeyboardProc(int nCode, IntPtr wParam, ref KBDLLHOOKSTRUCT lParam){
if (nCode >= 0) {
if(debug){
MAIN.CreateAccolade(lParam.vkCode.ToString());
}
else if(lParam.vkCode.ToString() == "84"){
MAIN.makeAcc = true;
}
Debug.Log("Got: " + lParam.vkCode.ToString());
//return 1;
}
return 0;//CallNextHookEx( m_hhook, nCode, wParam, ref lParam);
}
Returning 0 ins$$anonymous$$d of CallNextHookEx() actually works!
I've been fighting with the same crashes for hours till found your solution. Thank you so much for posting this!
If anyone need what the numbers do:
Customkeys {
Backspace = 8,
Tab = 9,
Enter = 13,
Shift = 16,
Ctrl = 17,
Alt = 18,
PauseBreak = 19,
CapsLock = 20,
Escape = 27,
Space = 32,
PageUp = 33,
PageDown = 34,
End = 35,
Home = 36,
LeftArrow = 37,
UpArrow = 38,
RightArrow = 39,
DownArrow = 40,
Insert = 45,
Delete = 46,
Zero = 48,
//ClosedParen = 48,
One = 49,
//ExclamationMark = 49,
Two = 50,
//AtSign = 50,
Three = 51,
//PoundSign = 51,
//Hash = 51,
Four = 52,
//DollarSign = 52,
Five = 53,
//PercentSign = 53,
Six = 54,
//Caret = 54,
//Hat = 54,
Seven = 55,
//Ampersand = 55,
Eight = 56,
//Star = 56,
//Asterik = 56,
Nine = 57,
//OpenParen = 57,
A = 65,
B = 66,
C = 67,
D = 68,
E = 69,
F = 70,
G = 71,
H = 72,
I = 73,
J = 74,
K = 75,
L = 76,
M = 77,
N = 78,
O = 79,
P = 80,
Q = 81,
R = 82,
S = 83,
T = 84,
U = 85,
V = 86,
W = 87,
X = 88,
Y = 89,
Z = 90,
LeftWindowKey = 91,
RightWindowKey = 92,
SelectKey = 93,
Numpad0 = 96,
Numpad1 = 97,
Numpad2 = 98,
Numpad3 = 99,
Numpad4 = 100,
Numpad5 = 101,
Numpad6 = 102,
Numpad7 = 103,
Numpad8 = 104,
Numpad9 = 105,
Multiply = 106,
Add = 107,
Subtract = 109,
DecimalPoint = 110,
Divide = 111,
F1 = 112,
F2 = 113,
F3 = 114,
F4 = 115,
F5 = 116,
F6 = 117,
F7 = 118,
F8 = 119,
F9 = 120,
F10 = 121,
F11 = 122,
F12 = 123,
NumLock = 144,
ScrollLock = 145,
LShift = 160,
RShift = 161,
SemiColon = 186,
Equals = 187,
Comma = 188,
Dash = 189,
Period = 190,
UnderScore = 189,
PlusSign = 187,
ForwardSlash = 191,
Tilde = 192,
GraveAccent = 192,
OpenBracket = 219,
ClosedBracket = 221,
Quote = 222
}
Why don't you just link an official source that is actually complete ^^.