Send Keyevent to a Target Window via Process Id

Directly sending keystrokes to another process via hooking

This is a little code that allows you to send message to a backgrounded application. To send the "A" char for example, simply call sendKeystroke(Keys.A), and don't forget to use namespace System.windows.forms to be able to use the Keys object.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace keybound
{
class WindowHook
{
[DllImport("user32.dll")]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("user32.dll")]
public static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll")]
public static extern IntPtr PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

public static void sendKeystroke(ushort k)
{
const uint WM_KEYDOWN = 0x100;
const uint WM_SYSCOMMAND = 0x018;
const uint SC_CLOSE = 0x053;

IntPtr WindowToFind = FindWindow(null, "Untitled1 - Notepad++");

IntPtr result3 = SendMessage(WindowToFind, WM_KEYDOWN, ((IntPtr)k), (IntPtr)0);
//IntPtr result3 = SendMessage(WindowToFind, WM_KEYUP, ((IntPtr)c), (IntPtr)0);
}
}
}

distinguish between different instances or windows of a process and find their PID instead of their owner PID to send input event in macOS?

This activates each window in TextEdit and sends a space keystroke.

activate application "TextEdit"

tell application "System Events"
tell application process "TextEdit"
repeat with theWindow in windows
perform action "AXRaise" of theWindow
keystroke " "
end repeat
end tell
end tell

But to note how this would work without pressing keys, the following appends "A" to all the currently open documents without bringing anything to the foreground or interfering with the user's input.

tell application "TextEdit"
repeat with theDocument in documents
set text of theDocument to (text of theDocument) & "A"
end repeat
end tell

Whenever possible, you want things like this rather than sending keystrokes.

Send keystrokes to a specific window (in background), but do something else in the meantime

In order to send Keystroke to any application window, without activating the application to get input focus. We must get the windows handler first. This requires Windows API FindWindow and FindWindowsEx. First, the handle of Top Level window of application is obtained by FindWindow. Then use FindWindowsEx to get the handle of the child window or control to receive keys.
Because the top window of the application is not always the window that accepts Keystroke (such as notepad.exe, the window that actually accepts Keystroke is the Edit control under the main window of Notepad), it can be found by ClassID or Caption.

Assuming that the handle of the target window has been got(hwnd), the key message will be sent to the window with PostMessage.

For normal character keys, it is simplest to use WM_CHAR message directly, as follows:

PostMessage(hwnd, WM_CHAR, 'a', 0);

For un-normal character keys, such as function keys, direction keys, etc., WM_KEYDOWN and WM_KEYUP messages should be used as follows:

VirtualKey = MapVirtualKeyA(VK_RIGHT, 0);
PostMessage(hwnd, WM_KEYDOWN, VK_RIGHT, 0x0001|VirtualKey<<16);
PostMessage(hwnd, WM_KEYUP, VK_RIGHT, 0x0001|VirtualKey<<16|0xC0<<24);

The details for last parameter (lParam) you can reference to msdn.

For the keys "Shift/Ctrl", sample:

keybd_event(VK_SHIFT, 0, 0, 0);
PostMessage(hwnd, WM_KEYDOWN, 0x41, 0x001E0001);
PostMessage(hwnd, WM_KEYUP, 0x41, 0xC01E0001);
keybd_event(VK_SHIFT, 0, KEYEVENTF_KEYUP, 0);

For the keys "Alt", It belongs to the system button, using WM_SYSKEYDOWN/WM_SYSKEYUP message. sample:

PostMessage(hwnd, WM_SYSKEYDOWN, VK_F4, 0x003E0001 |0x20000000);
PostMessage(hwnd, WM_SYSKEYUP, VK_F4, 0xC03E0001 | 0x20000000);

0x20000000 means context code, the value is 1 if the "Alt" key is down.

Send keystroke to application in c# (sendkeys, postmessage, sendmessage all not working)

There is lot of trial and error with that, to get it working

Here is a bit of code I posted before, you might wanna give a try (and there is some more info attached)...

Pinvoke SetFocus to a particular control

Try setting focus first (using the mechanism mentioned) - and then using SendKeys or SendInput.

Here is some detailed code for SendInput...

How to send a string to other application including Microsoft Word

Send keypress to specific window on Mac

Demo in swift, using

$ swift --version
Apple Swift version 4.2.1 (swiftlang-1000.11.42 clang-1000.11.45.1)
Target: x86_64-apple-darwin17.7.0

simple example code sendspace.swift

import Foundation

let src = CGEventSource(stateID: CGEventSourceStateID.hidSystemState)

let kspd = CGEvent(keyboardEventSource: src, virtualKey: 0x31, keyDown: true) // space-down
let kspu = CGEvent(keyboardEventSource: src, virtualKey: 0x31, keyDown: false) // space-up

let pids = [ 24834, 24894, 24915 ]; // real PID-s from command 'ps -ax' - e.g. for example 3 different processes

for i in 0 ..< pids.count {
print("sending to pid: ", pids[i]);
kspd?.postToPid( pid_t(pids[i]) ); // convert int to pid_t
kspu?.postToPid( pid_t(pids[i]) );
}

After running the code: swift sendspace.swift (from the Terminal) all 3 processes with defined PIDs will get the space keypress, while the Terminal is still the foreground app.



Related Topics



Leave a reply



Submit