Last active
October 16, 2018 05:35
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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