Skip to content

Instantly share code, notes, and snippets.

@AonaSuzutsuki
Last active October 16, 2018 05:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save AonaSuzutsuki/2675519f8b84d041b6ec7adee3757c5f to your computer and use it in GitHub Desktop.
Save AonaSuzutsuki/2675519f8b84d041b6ec7adee3757c5f to your computer and use it in GitHub Desktop.
⚠Warning⚠ All input on keyboard exnchange to [A]. It is not exchanged mouse input.
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows;
namespace ConsoleApp1
{
abstract class AbstractInterceptKeyboard
{
#region Win32 Constants
protected const int WH_KEYBOARD_LL = 0x000D;
protected const int WM_KEYDOWN = 0x0100;
protected const int WM_KEYUP = 0x0101;
protected const int WM_SYSKEYDOWN = 0x0104;
protected const int WM_SYSKEYUP = 0x0105;
#endregion
#region Win32API Structures
[StructLayout(LayoutKind.Sequential)]
public class KBDLLHOOKSTRUCT
{
public uint vkCode;
public uint scanCode;
public KBDLLHOOKSTRUCTFlags flags;
public uint time;
public UIntPtr dwExtraInfo;
}
[Flags]
public enum KBDLLHOOKSTRUCTFlags : uint
{
KEYEVENTF_EXTENDEDKEY = 0x0001,
KEYEVENTF_KEYUP = 0x0002,
KEYEVENTF_SCANCODE = 0x0008,
KEYEVENTF_UNICODE = 0x0004,
}
#endregion
#region Win32 Methods
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook, KeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
#endregion
#region Delegate
private delegate IntPtr KeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
#endregion
#region Fields
private KeyboardProc proc;
private IntPtr hookId = IntPtr.Zero;
#endregion
public void Hook()
{
if (hookId == IntPtr.Zero)
{
proc = HookProcedure;
using (var curProcess = Process.GetCurrentProcess())
{
using (ProcessModule curModule = curProcess.MainModule)
{
hookId = SetWindowsHookEx(WH_KEYBOARD_LL, proc, GetModuleHandle(curModule.ModuleName), 0);
}
}
}
}
public void UnHook()
{
UnhookWindowsHookEx(hookId);
hookId = IntPtr.Zero;
}
public virtual IntPtr HookProcedure(int nCode, IntPtr wParam, IntPtr lParam)
{
return CallNextHookEx(hookId, nCode, wParam, lParam);
}
}
class InterceptKeyboard : AbstractInterceptKeyboard
{
#region InputEvent
public class OriginalKeyEventArg : EventArgs
{
public int KeyCode { get; }
public bool IsCancel { get; set; } = false;
public bool IsVirtualInput { get; }
public OriginalKeyEventArg(int keyCode, bool isVirtualInput)
{
KeyCode = keyCode;
IsVirtualInput = isVirtualInput;
}
}
public delegate void KeyEventHandler(object sender, OriginalKeyEventArg e);
public event KeyEventHandler KeyDownEvent;
public event KeyEventHandler KeyUpEvent;
protected OriginalKeyEventArg OnKeyDownEvent(int keyCode, bool isVirtualInput)
{
var eventArg = new OriginalKeyEventArg(keyCode, isVirtualInput);
KeyDownEvent?.Invoke(this, eventArg);
return eventArg;
}
protected OriginalKeyEventArg OnKeyUpEvent(int keyCode, bool isVirtualInput)
{
var eventArg = new OriginalKeyEventArg(keyCode, isVirtualInput);
KeyUpEvent?.Invoke(this, eventArg);
return eventArg;
}
#endregion
public override IntPtr HookProcedure(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && (wParam == (IntPtr)WM_KEYDOWN || wParam == (IntPtr)WM_SYSKEYDOWN))
{
var kb = (KBDLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));
var vkCode = (int)kb.vkCode;
var eventArg = OnKeyDownEvent(vkCode, kb.dwExtraInfo.ToUInt32() != 0x0);
if (eventArg.IsCancel)
return new IntPtr(1);
}
else if (nCode >= 0 && (wParam == (IntPtr)WM_KEYUP || wParam == (IntPtr)WM_SYSKEYUP))
{
var kb = (KBDLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));
var vkCode = (int)kb.vkCode;
var eventArg = OnKeyUpEvent(vkCode, kb.dwExtraInfo.ToUInt32() != 0x0);
if (eventArg.IsCancel)
return new IntPtr(1);
}
return base.HookProcedure(nCode, wParam, lParam);
}
}
public class InterceptInput
{
#region Win32API Structures
[StructLayout(LayoutKind.Sequential)]
public struct MOUSEINPUT
{
public int dx;
public int dy;
public int mouseData;
public int dwFlags;
public int time;
public int dwExtraInfo;
};
[StructLayout(LayoutKind.Sequential)]
public struct KEYBDINPUT
{
public short wVk;
public short wScan;
public int dwFlags;
public int time;
public int dwExtraInfo;
};
[StructLayout(LayoutKind.Sequential)]
public struct HARDWAREINPUT
{
public int uMsg;
public short wParamL;
public short wParamH;
};
[StructLayout(LayoutKind.Explicit)]
public struct INPUT
{
[FieldOffset(0)]
public int type;
[FieldOffset(4)]
public MOUSEINPUT no;
[FieldOffset(4)]
public KEYBDINPUT ki;
[FieldOffset(4)]
public HARDWAREINPUT hi;
};
#endregion
#region Win32API Methods
[DllImport("user32.dll")]
private static extern void SendInput(int nInputs, ref INPUT pInputs, int cbsize);
[DllImport("user32.dll", EntryPoint = "MapVirtualKeyA")]
private static extern int MapVirtualKey(int wCode, int wMapType);
#endregion
#region Win32API Constants
private const int INPUT_KEYBOARD = 1;
private const int KEYEVENTF_KEYDOWN = 0x0;
private const int KEYEVENTF_KEYUP = 0x2;
private const int KEYEVENTF_EXTENDEDKEY = 0x1;
#endregion
#region Constants
public const int MAGIC_NUMBER = 0x10209;
#endregion
public INPUT KeyDown(int key, bool isExtend = false)
{
INPUT input = new INPUT
{
type = INPUT_KEYBOARD,
ki = new KEYBDINPUT()
{
wVk = (short)key,
wScan = (short)MapVirtualKey((short)key, 0),
dwFlags = ((isExtend) ? (KEYEVENTF_EXTENDEDKEY) : 0x0) | KEYEVENTF_KEYDOWN,
time = 0,
dwExtraInfo = MAGIC_NUMBER
},
};
SendInput(1, ref input, Marshal.SizeOf(input));
return input;
}
public void KeyUp(INPUT input, bool isExtend = false)
{
input.ki.dwFlags = ((isExtend) ? (KEYEVENTF_EXTENDEDKEY) : 0x0) | KEYEVENTF_KEYUP;
SendInput(1, ref input, Marshal.SizeOf(input));
}
}
class Program
{
[STAThread]
static void Main(string[] args)
{
var interceptKeyboard = new InterceptKeyboard();
interceptKeyboard.KeyDownEvent += InterceptKeyboard_KeyDownEvent;
interceptKeyboard.KeyUpEvent += InterceptKeyboard_KeyUpEvent;
interceptKeyboard.Hook();
var application = new Application();
application.Run(new Window()
{
Width = 300,
Height = 300,
});
interceptKeyboard.UnHook();
}
static readonly InterceptInput interceptInput = new InterceptInput();
private static void InterceptKeyboard_KeyUpEvent(object sender, InterceptKeyboard.OriginalKeyEventArg e)
{
Console.WriteLine("Keyup KeyCode {0}", e.KeyCode);
}
private static void InterceptKeyboard_KeyDownEvent(object sender, InterceptKeyboard.OriginalKeyEventArg e)
{
Console.WriteLine("Keydown KeyCode {0}", e.KeyCode);
if (e.IsVirtualInput)
return;
var input = interceptInput.KeyDown(0x41);
interceptInput.KeyUp(input);
e.IsCancel = true;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment