using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
namespace ConsoleApplication1
{
internal class EnumWindowsData
{
internal string ClassName { get; set; }
internal IntPtr Handle { get; set; }
}
internal static class Program
{
private static void Main(string[] args)
{
// Récupérer le handle de la fenêtre du notepad
var hWnd = Process.GetProcessesByName("notepad").First().MainWindowHandle;
// Récupérer le handle de l'edit du notepad
var hEdit = GetChildWindow(hWnd, "Edit");
Sender.Send(hEdit, "Test");
Sender.KeyPress(hEdit, Keys.Space);
Sender.KeyDown(hEdit, Keys.H);
Sender.KeyDown(hEdit, Keys.H);
Sender.KeyUp(hEdit, Keys.H);
}
private static IntPtr GetChildWindow(IntPtr parentHandle, string className)
{
EnumChildProc callback = EnumWindowCallback;
var data = new EnumWindowsData {ClassName = className};
EnumChildWindows(parentHandle, callback, ref data);
return data.Handle;
}
private static bool EnumWindowCallback(IntPtr hWnd, ref EnumWindowsData lParam)
{
var sb = new StringBuilder(1024);
GetClassName(hWnd, sb, sb.Capacity);
var className = sb.ToString();
if (className != lParam.ClassName)
return true;
lParam.Handle = hWnd;
return false;
}
#region Win32
private delegate bool EnumChildProc(IntPtr hWnd, ref EnumWindowsData lParam);
[DllImport("user32.dll")]
private static extern bool EnumChildWindows(IntPtr hWndParent, EnumChildProc lpEnumFunc, ref EnumWindowsData lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
#endregion
}
public static class Sender
{
private const int WM_KEYDOWN = 0x100;
private const int WM_KEYUP = 0x101;
private static readonly HashSet<Keys> keysPressed = new HashSet<Keys>();
public static void Send(IntPtr hWnd, string msg)
{
foreach (var k in msg.Select(MapToVirtualKey))
KeyPress(hWnd, k);
}
public static void KeyPress(IntPtr hWnd, Keys key)
{
KeyDown(hWnd, key);
KeyUp(hWnd, key);
}
public static void KeyDown(IntPtr hWnd, Keys key)
{
if (hWnd == IntPtr.Zero)
throw new ArgumentNullException(nameof(hWnd));
var wParam = (uint)(key & Keys.KeyCode); // VK
var lParam = LParam(key, 1, false);
PostMessage(hWnd, WM_KEYDOWN, wParam, lParam);
keysPressed.Add(key);
}
public static void KeyUp(IntPtr hWnd, Keys key)
{
if (hWnd == IntPtr.Zero)
throw new ArgumentNullException(nameof(hWnd));
var wParam = (uint)(key & Keys.KeyCode); // VK
var lParam = LParam(key, 1, true);
PostMessage(hWnd, WM_KEYUP, wParam, lParam);
keysPressed.Remove(key);
}
private static uint LParam(Keys key, uint repeat, bool keyUp)
{
var ret = repeat | (uint)MapToScanCode(key) << 16;
if (keysPressed.Contains(key))
ret |= 0x40000000; // Previous key state flag
if (keyUp)
ret |= 0x80000000; // Transition state flag
return ret;
}
private static byte MapToScanCode(Keys key)
{
var vKey = key & Keys.KeyCode;
return (byte)MapVirtualKey(vKey, MapVirtualKeyMapTypes.MAPVK_VK_TO_VSC);
}
Private static Keys MapToVirtualKey(char c)
{
var vkey = VkKeyScan(c);
var ret = (Keys)(vkey & 0xFF);
var modifiers = vkey >> 8;
if ((modifiers & 1) != 0)
ret |= Keys.Shift;
if ((modifiers & 2) != 0)
ret |= Keys.Control;
if ((modifiers & 4) != 0)
ret |= Keys.Alt;
return ret;
}
#region Win32
private enum MapVirtualKeyMapTypes : uint
{
/// <summary>
/// uCode is a virtual-key code and is translated into a scan code.
/// If it is a virtual-key code that does not distinguish between left- and
/// right-hand keys, the left-hand scan code is returned.
/// If there is no translation, the function returns 0.
/// </summary>
MAPVK_VK_TO_VSC = 0x00,
/// <summary>
/// uCode is a scan code and is translated into a virtual-key code that
/// does not distinguish between left- and right-hand keys. If there is no
/// translation, the function returns 0.
/// </summary>
MAPVK_VSC_TO_VK = 0x01,
/// <summary>
/// uCode is a virtual-key code and is translated into an unshifted
/// character value in the low-order word of the return value. Dead keys (diacritics)
/// are indicated by setting the top bit of the return value. If there is no
/// translation, the function returns 0.
/// </summary>
MAPVK_VK_TO_CHAR = 0x02,
/// <summary>
/// Windows NT/2000/XP: uCode is a scan code and is translated into a
/// virtual-key code that distinguishes between left- and right-hand keys. If
/// there is no translation, the function returns 0.
/// </summary>
MAPVK_VSC_TO_VK_EX = 0x03,
/// <summary>
/// Not currently documented
/// </summary>
MAPVK_VK_TO_VSC_EX = 0x04
}
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr PostMessage(IntPtr hWnd, uint Msg, uint wParam, uint lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern uint MapVirtualKey(Keys uCode, MapVirtualKeyMapTypes uMapType);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern short VkKeyScan(char c);
#endregion
}
}