I have a button on which I press it sends F5 to the application "Tibia". Tibia is not focused, and it sends the F5 in the background without a problem.
I wonder how can I send a string of text like "hello world".
Or send a CTRL+V. That way I could set my clipboard text to "hello world" first, and then send it.
It seems like I can only press 1 key at a time no matter what I do.
Please help me. Here's my code:
const UInt32 WM_KEYDOWN = 0x0100;
[DllImport("user32.dll")]
static extern bool PostMessage(IntPtr hWnd, UInt32 Msg, int wParam, int lParam);
public Form1()
{
InitializeComponent();
}
// Sends F5 to Tibia
private void button1_Click(object sender, EventArgs e)
{
Process[] processes = Process.GetProcessesByName("Tibia");
foreach (Process proc in processes)
{
PostMessage(proc.MainWindowHandle, WM_KEYDOWN, (int)System.Windows.Forms.Keys.F5, 0);
}
}
Note: I do NOT want to focus on the Tibia window when I do this. It should be done "in the background" like now with the F5 press.
Related
While working on the main screen, I want to send a right click command to Firefox, which is opened on the second vertical screen. But I don't want Firefox to become active when I send commands. I tried this but it didn't work:
const uint WM_KEYDOWN = 0x0100;
[DllImport("user32.dll")]
static extern bool PostMessage(IntPtr hWnd, uint Msg, int wParam, int lParam);
private void button1_Click(object sender, EventArgs e)
{
var processes = Process.GetProcessesByName("firefox");
foreach (var proc in processes)
{
PostMessage(proc.MainWindowHandle, WM_KEYDOWN, (int)Keys.Right, 0);
// I have to use SendKeys.SendWait for the messages to be processed.
SendKeys.SendWait("{RIGHT}");
}
}
And this works, but every time I send a command, Firefox becomes active. It doesn't work when I disable the SetForegroundWindow method.
[DllImport("User32.dll")]
private static extern int SetForegroundWindow(IntPtr ptr);
private void button1_Click(object sender, EventArgs e)
{
var p = Process.GetProcessesByName("firefox").FirstOrDefault();
if (p != null)
{
IntPtr h = p.MainWindowHandle;
SetForegroundWindow(h);
SendKeys.SendWait("{RIGHT}");
}
}
A Click is a WM_KEYDOWN and WM_KEYUP. Can you try calling the functions using the first method like so
foreach (var proc in processes)
{
PostMessage(proc.MainWindowHandle, WM_KEYDOWN, (int)Keys.RButton, (IntPtr)0x001E0001);
PostMessage(proc.MainWindowHandle, WM_KEYUP, (int)Keys.RButton, (IntPtr)0xC01E0001);
// I have to use SendKeys.SendWait for the messages to be processed.
SendKeys.SendWait("{RIGHT}"); //I dont believe you need this with the above approach
}
You can also try sending the WM_CONTEXTMENU message if that is what you are after
I must also point out that Keys.Right is for the Right arrow key and not the right mouse click, you should use Keys.RButton instead
Here is the List of KeyCodes and more info on KeyStrokes in win32
I found command System.Windows.Forms.SendKeys.Send() for sending keypress some key. This function work if open external app like a notepad and set focus and I will be see that my Key printed in this text field. How do same but with key down event, System.Windows.Forms.SendKeys.SendDown("A");, for example?
I tried call in Timer this command System.Windows.Forms.SendKeys.Send() but have runtime error associated with very fast taped.
You can't use the SendKeys class for that, unfortunately. You will need to go to a lower level API.
Poking a window with a keydown message
In Windows, keyboard events are sent to windows and controls via the Windows message pump. A piece of code using PostMessage should do the trick:
[DllImport("user32.dll")]
static extern bool PostMessage(IntPtr hWnd, uint Msg, int wParam, int lParam);
const uint WM_KEYDOWN = 0x0100;
void SendKeyDownToProcess(string processName, System.Windows.Forms.Keys key)
{
Process p = Process.GetProcessesByName(processName).FirstOrDefault();
if (p != null)
{
PostMessage(p.MainWindowHandle, WM_KEYDOWN, (int)key, 0);
}
}
Note that the application receiving these events may not do anything with it until a corresponding WM_KEYUP is received. You can get other message constants from here.
Poking a control other than the main window
The above code will send a keydown to the "MainWindowHandle." If you need to send it to something else (e.g. the active control) you will need to call PostMessage with a handle other than p.MainWindowHandle. The question is... how do you get that handle?
This is actually very involved... you will need to temporarily attach your thread to the window's message input and poke it to figure out what the handle is. This can only work if the current thread exists in a Windows Forms application and has an active message loop.
An explanation can be found here, as well as this example:
using System.Runtime.InteropServices;
public partial class FormMain : Form
{
[DllImport("user32.dll")]
static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
static extern IntPtr GetWindowThreadProcessId(IntPtr hWnd, IntPtr ProcessId);
[DllImport("user32.dll")]
static extern IntPtr AttachThreadInput(IntPtr idAttach,
IntPtr idAttachTo, bool fAttach);
[DllImport("user32.dll")]
static extern IntPtr GetFocus();
public FormMain()
{
InitializeComponent();
}
private void timerUpdate_Tick(object sender, EventArgs e)
{
labelHandle.Text = "hWnd: " +
FocusedControlInActiveWindow().ToString();
}
private IntPtr FocusedControlInActiveWindow()
{
IntPtr activeWindowHandle = GetForegroundWindow();
IntPtr activeWindowThread =
GetWindowThreadProcessId(activeWindowHandle, IntPtr.Zero);
IntPtr thisWindowThread = GetWindowThreadProcessId(this.Handle, IntPtr.Zero);
AttachThreadInput(activeWindowThread, thisWindowThread, true);
IntPtr focusedControlHandle = GetFocus();
AttachThreadInput(activeWindowThread, thisWindowThread, false);
return focusedControlHandle;
}
}
The good news-- if SendKeys worked for you, then you might not need to do all this-- SendKeys also sends messages to the main window handle.
I am trying to use sendkeys, but send it to a non focused program. For example, I want to use sendkeys to Notepad - Untitled, without it being focused. Sorry if it's unclear, I will elaborate. My current code is this:
string txt = Regex.Replace(richTextBox3.Text, "[+^%~()]", "{$0}");
System.Threading.Thread.Sleep(1000);
SendKeys.Send(txt + "{ENTER}");
If I use SendMessage, would anyone care to show me an example of what I should do? I don't find anything I found online very useful for my issue.
The following code I found from a previous SO answer. The PostMessage API will send a Windows message to a specific Windows handle. The code below will cause the key down event to fire for all instances of Internet Explorer, without giving focus, simulating that the F5 key was pressed. A list of additional key codes can be found here.
static class Program
{
const UInt32 WM_KEYDOWN = 0x0100;
const int VK_F5 = 0x74;
[DllImport("user32.dll")]
static extern bool PostMessage(IntPtr hWnd, UInt32 Msg, int wParam, int lParam);
[STAThread]
static void Main()
{
while(true)
{
Process [] processes = Process.GetProcessesByName("iexplore");
foreach(Process proc in processes)
PostMessage(proc.MainWindowHandle, WM_KEYDOWN, VK_F5, 0);
Thread.Sleep(5000);
}
}
}
It took me a while to figure it out for myself
Also here a usefull list of Virtual Key Codes
[DllImport("user32.dll")]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
public static extern bool PostMessage(int hWnd, uint Msg, int wParam, int lParam);
private void button1_Click(object sender, EventArgs e)
{
const int WM_SYSKEYDOWN = 0x0104;
const int VK_RETURN = 0x0D;
IntPtr WindowToFind = FindWindow(null, "Notepad - Untitled"); // Window Titel
PostMessage(WindowToFind, WM_SYSKEYDOWN, VK_RETURN, 0);
}
I want to create a software like a virtualkeyboard, you have a AlwaysTop Window and use this to put some data on another process/windows. In this case I will record all data on clipboard and compare if this data is compatible with a pattern (A### is the patern and A123 is compatible with the patern), if yes the application will put it in a listbox and the user can paste it on another process/windows (already open) clicking on item on list.
My question is about how to put this information on the last application/process used, I already started a prototype of code but the line indicated is wrong, on my code it's the currentprocess and need to be the last used before click on my form.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
[DllImport("user32.dll")]
static extern IntPtr SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
internal static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
[DllImport("User32.dll")]
static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
private void button2_Click(object sender, EventArgs e)
{
Process currentProcess = Process.GetCurrentProcess(); //this line is wrong
IntPtr hWnd = currentProcess.MainWindowHandle; //this line is wrong
if (hWnd != IntPtr.Zero)
{
SetForegroundWindow(hWnd);
ShowWindow(hWnd, 9);
SendKeys.Send("A123");
}
}
}
}
I get on simple solution, instead of get the process I just send the combination ALT+TAB and work for all cases that I need. Below the solution if anyone need in the future:
string old_clipboard = Clipboard.GetText();
Clipboard.SetText("A123");
SendKeys.SendWait("%{Tab}");
SendKeys.SendWait("^V");
Thread.Sleep(100);
Clipboard.SetText(old_clipboard);
Ps.: I put one delay because the SendWait works only on caller windows, as the target of ^V is another process it´s don´t work well.
Best regards. =)
I have an odd problem with Sendkeys, what my application basically should do is that, when I press ALT+ J, it'll simulate a CTRL+C operation (on any windows) to copy some highlighted text, however the CTRL+C simulation is not working.
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint vk);
private void Form1_Load(object sender, EventArgs e)
{
RegisterHotKey(this.Handle,
this.GetType().GetHashCode(), 1, (int)'J'); // Here it's waiting for the ALT+J
}
protected override void WndProc(ref Message m) // Function to c
{
if (m.Msg == 0x0312) // If ALT+J pressed
{
Copier(); // .. Simulate CTRL+C (but doesn't work)
}
base.WndProc(ref m);
}
public void Copier() // Function to simulate the CTRL+C
{
Debug.WriteLine("Ok ");
InputSimulator.SimulateModifiedKeyStroke(VirtualKeyCode.CONTROL, VirtualKeyCode.VK_C); // First way
SendKeys.Send("^(c)"); // Second way
}
I think this is happening because when you send CTRL+C you already have pressed the ALT modifier of ALT+J.
If you put
Thread.Sleep(1000);
just before send keys, you'll have time to release ALT+J and then CTRL+C will work.
Also, if you plan to check when your hotkey is released, check this.