Reputation: 27
Hello I'm trying to send keys to hidden game and I have 1 problem, when I send the keys to game it press only the first one and it's not ending e.g like it's pressed W for infinity time and cant send the next key. I think the key it's not going up.
My code:
using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace Naura_2._0
{
public partial class Form1 : Form
{
[DllImport("user32.dll")]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
static extern bool PostMessage(IntPtr hWnd, UInt32 Msg, int wParam, int lParam);
public Form1()
{
InitializeComponent();
}
private const UInt32 WM_KEYDOWN = 0x0100;
private const UInt32 WM_KEYUP = 0x0101;
private const int VK_KEY_W = 0x57;
private void button1_Click(object sender, EventArgs e)
{
IntPtr hWnd = FindWindow(null, "Game Title");
if (!hWnd.Equals(IntPtr.Zero))
{
PostMessage(hWnd, WM_KEYDOWN, VK_KEY_W, 0);
PostMessage(hWnd, WM_KEYUP, VK_KEY_W, 5);
}
}
}
}
Upvotes: 1
Views: 725
Reputation: 855
SendInput
instead of PostMessage
as it is designed for this very process. This scenario is quite common with games where they automatically pause if the game window is not focus so sending any keys will likely do nothing.PostMessage
seems like the only way.PostMessage
To "Emulate" a keypress a Virtual Key Codes (the key 'A') and Scan Codes (the location on the keyboard of 'A') and some additional flags, Keystroke Message Flags, are sent.
PostMessage(hWndChild, WM_KEYDOWN, virtualKey, scanCode << 16 | 0x0000001);
PostMessage(hWndChild, WM_KEYUP, virtualKey, scanCode << 16 | 0xC0000001);
You can map between virtualKeys and scanCodes using MapVirtualKey
class Program
{
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
static extern uint MapVirtualKey(uint uCode, uint uMapType);
[DllImport("user32.dll")]
static extern bool PostMessage(IntPtr hWnd, uint Msg, uint wParam, uint lParam);
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll", CharSet = CharSet.Unicode)]
static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string lclassName, string windowTitle);
[DllImport("user32.dll")]
static extern bool SetForegroundWindow(IntPtr hWnd);
const uint WM_KEYDOWN = 0x0100;
const uint WM_KEYUP = 0x0101;
const uint MAPVK_VK_TO_VSC = 0x00;
// virtual key codes
const uint VK_ESCAPE = 0x1B;
const uint VK_LSHIFT = 0xA0;
const uint VK_LCONTROL = 0xA2;
const uint VK_OEM_2 = 0xBF; // For the US standard keyboard, the '/?' key
const uint VK_W = 'W';
const uint VK_A = 'A';
const uint VK_S = 'S';
const uint VK_D = 'D';
// Scan Code for US keyboard layout
const uint VSC_W = 0x11; // MapVirtualKey('W', MAPVK_VK_TO_VSC);
const uint VSC_A = 0x1E; // On QUERY MapVirtualKey('A', MAPVK_VK_TO_VSC);
// On AZERY MapVirtualKey('Q', MAPVK_VK_TO_VSC);
const uint VSC_S = 0x1F;
const uint VSC_D = 0x20;
const uint VSC_LSHIFT = 0x2A;
// Write 'w' (yes lower case) in Notepad.exe (*Untitled - Notepad)
static void Example1()
{
uint keyPress = VK_W;
uint scanCode = MapVirtualKey(keyPress, MAPVK_VK_TO_VSC);
IntPtr hWnd = FindWindow(null, "*Untitled - Notepad");
IntPtr hWndChild = FindWindowEx(hWnd, IntPtr.Zero, "Edit", string.Empty);
PostMessage(hWndChild, WM_KEYDOWN, keyPress, scanCode << 16 | 0x0000001);
Thread.Sleep(42);
PostMessage(hWndChild, WM_KEYUP, keyPress, scanCode << 16 | 0xC0000001);
}
// Write 'help' (yes lower case) in Notepad.exe (*Untitled - Notepad)
static void Example2()
{
string text = "help";
IntPtr hWnd = FindWindow(null, "*Untitled - Notepad");
IntPtr hWndChild = FindWindowEx(hWnd, IntPtr.Zero, "Edit", string.Empty);
foreach (var c in text)
{
uint keyPress = char.ToUpper(c);
uint scanCode = MapVirtualKey(keyPress, MAPVK_VK_TO_VSC);
PostMessage(hWndChild, WM_KEYDOWN, keyPress, scanCode << 16 | 0x0000001);
Thread.Sleep(42);
PostMessage(hWndChild, WM_KEYUP, keyPress, scanCode << 16 | 0xC0000001);
Thread.Sleep(142);
}
}
}
https://handmade.network/forums/t/2011-keyboard_inputs_-_scancodes,_raw_input,_text_input,_key_names
Visual Studio comes with a program called Spy++ which can be used to view the message queue of any window.
C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\Tools\spyxx.exe
C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\Common7\Tools\spyxx_amd64.exe
where spyxx.exe
is used to inspect 32bit processes and spyxx_amd64.exe
is used to inspect 64bit process. Using Spy++ and the documentation, Keystroke Message Flags, I was able to view the WM_KEYDOWN
and WM_KEYUP
and imitate the desired behavior using PostMessage
.
GetKeyboardState
it which case posting messages won't do anything since it queries the keyboard and ignores the messages. Note the there is a SetKeyboardState
which can be used to set which keys are pressed and hence communicate with these programs.Upvotes: 1