Directly sending keystrokes to another process via hooking - c#

I'm wondering, after fiddling with all sorts of issues with SendInput, SendKeys, PostMessage, SendMessage, SendNotifyMessage, keybd_event, etc and so forth. To find that well... trying to send a keyboard input to another non-foreground process is quite finicky and unreliable.
I tried a method of SendInput where I trick the Z-order (to keep the current window on top) and quickly foreground the 3rd party window, send the input, and re-foreground my window. Of which ultimately failed, and also, somehow, not sure why, managed to also proc the keystrokes on my window as well while not foreground (causing an infinite loop of sending and receiving between two windows until I managed to close the process).
I've tried different combinations of SendMessage and PostMessage. One for down, one for up, as using both for down and up leads to issues, like with PostMessage for both, causing the key to duplicate on the receiving window. or SendMessage for both, which caused issues with text entry, but other functions worked ok. SendMessage for keydown and PostMessage for keyUp worked for all functions, but the reliability rate dropped dramatically, as well as adding latency into key events. Only a combination of PostMessage for keydown, and SendMessage for keyup managed to do anything useful, with a maybe 5-10% fail rate of keyup registering. Same goes for SentNotifyMessage (behaves basically in the same fashion as SendMessage as far as reliability goes).
So essentially, I'm at whit's end, and I wanted to know about directly injecting a hook into the target window, and doing some voodoo to send keystrokes to it that way, bypassing the message queue etc. Doing so in a way that will not proc global key events, and only affect the target window. Only thing is I'm pretty unknowledgeable when it comes to injecting/hooking, etc. So I turn to you, community.
Wut do?

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);
}
}
}

You might have to mess around with this but you can send data via process. This might not work for your situation but it is a thought.
using System;
using System.Runtime.InteropServices;
using System.Diagnostics;
[DllImport("user32.dll", EntryPoint = "FindWindowEx")]
public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
[DllImport("User32.dll")]
public static extern int SendMessage(IntPtr hWnd, int uMsg, int wParam, string lParam);
static void Send(string message)
{
Process[] notepads = Process.GetProcessesByName("notepad");
if (notepads.Length == 0)
return;
if (notepads[0] != null)
{
IntPtr child = FindWindowEx(notepads[0].MainWindowHandle,
new IntPtr(0), "Edit", null);
SendMessage(child, 0x000C, 0, message);
}
}
If that doesn't work you can always do:
System.Threading.Thread.Sleep(1000);
//User clicks on active form.
System.Windows.Forms.Sendkeys.Sendwait("<Message>");

Related

Looking to force Alt + Enter full screen and a forced zoom (Ctrl + Scroll) Inside of a console application in C#

Essentially cannot find and answer to this question, or if it is even possible.
I have a game I am creating for a class, and it simply looks better when forced full screen and when the zoom is set to a particular size. I was wonder if I could recreate this without the player being necessary to change it themselves.
ALT + ENTER Full screen
And
CTRL + Scroll wheel zoom
For a literal answer to your question on how to:
Send keys to go Fullscreen, and
Send a Ctrl+MouseWheel
You want some help from the Win32 interop to send keyboard & mouse messages to your console window.
using System.Runtime.InteropServices;
public class Win32
{
public const int VK_F11 = 0x7A;
public const int SW_MAXIMIZE = 3;
public const uint WM_KEYDOWN = 0x100;
public const uint WM_MOUSEWHEEL = 0x20A;
public const uint WHEEL_DELTA = 120;
public const uint MK_CONTROL = 0x00008 << 16;
[DllImport("kernel32.dll")]
public static extern IntPtr GetConsoleWindow();
[DllImport("user32.dll")]
public static extern IntPtr PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll")]
public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
}
As reference the magic numbers are from:
Virtual Keys (VK_*)
Window input messages (WM_*)
Mousewheel params (WHEEL_DELTA & MK_*)
and the ShowWindow params (SW_*)
You could then simply send your keypress and mousewheel like so:
using static Win32;
// Get window handle of the console
var hwnd = GetConsoleWindow();
// Go fullscreen by sending the F11 keydown message.
PostMessage(hwnd, WM_KEYDOWN, (IntPtr)VK_F11, IntPtr.Zero);
// Or maximize the window instead. Your users may not know how to get out of fullscreen...
/// ShowWindow(hwnd, SW_MAXIMIZE);
// Send mouse wheel message.
// MK_CONTROL: Holds the Ctrl key. WHEEL_DELTA: Positive=Up, Negative=Down.
PostMessage(hwnd, WM_MOUSEWHEEL, (IntPtr)(MK_CONTROL | WHEEL_DELTA), IntPtr.Zero);
Alternatively, as #JeremyLakerman mentioned in a comment to your question, you could set the console font to a larger size; which is a lot better, but also a bit more involved than sending Ctrl+MouseWheel.

C# .net send keys NOT using SendKey() but rather with hooking mabye

In my specific case, I'm trying to create an application that sends keyboard keystrokes to the DosBox (the dos-games emulator, not the windows command prompt).
I tried doing it using SendKeys but that does not work because DosBox is not an application that processes windows-messages (an exception told me that).
At the moment I'm trying to do that using a keyboard hook, like this:
The first method is the one which receives hooked keystrokes and puts them through to the next application (like in this example)
private IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
return CallNextHookEx(hookId, nCode, wParam, lParam);
}
private void GenerateKeyPress()
{
int vkCode = (int)Keys.Up; //My chosen key to be send to dosbox
IntPtr lParam = new IntPtr(vkCode);
IntPtr wParam = new IntPtr(255);
CallNextHookEx(hookId, 0, wParam, lParam);
}
The CallNextHookEx() function call however throws an access violation exception.
What do I need to think of here?
The access violation is caused by the fact that LPARAM for a low-level keyboard hook, that is, one created with
SetWindowsHookEx(WH_KEYBOARD_LL,...)
is a pointer to a KBDLLHOOKSTRUCT, not a keycode masquerading as a pointer. You're telling the next hook in the hook chain to access an arbitrary memory location. (Also, the WPARAM is supposed to be one of WM_KEYDOWN, WM_KEYUP, WM_SYSKEYDOWN, or WM_SYSKEYUP.)
The example code you linked, uses Marshal.ReadInt32(lParam) to get the key code, which is actually reading the first integer in the structure referenced by the pointer.
As far as what you're trying to accomplish, the way to do it would be to use SendInput which is a topic that's been covered here so many times that it does not bear repeating.
(That's not even all the SendInput questions)
I think you should use "keybd_event" to replace "SendKeys".
public static class Keyboard
{
public static void Press(Keys keys, int sleep = 1)
{
var keyValue = (byte)keys;
NativeMethods.keybd_event(keyValue, 0, 0, UIntPtr.Zero); //key down
Thread.Sleep(sleep);
NativeMethods.keybd_event(keyValue, 0, 0x02, UIntPtr.Zero); //key up
}
}
internal static partial class NativeMethods
{
[DllImport("user32.dll")]
internal static extern void keybd_event(byte bVk, byte bScan, int dwFlags, UIntPtr dwExtraInfo);
}

Detecting a modal dialog box of another process

I want to detect whether another process say process.exe is currently displaying a dialog box ?
Is there a way to do that in C# ?
To see if I could get the handle of the dialog box. I have tried Spy++ 's find window tool, when I try to drag the finder on top of the dialog box, it does not highlight the dialogbox but populates the details and
mentions AppCustomDialogBox and mentions the handle number
Please advise how can I programatically detect that ..
Thanks,
When an application shows a dialog box, the (for me quietly annoying) behaviour of Windows Operating System is to show the newly created window on top of all other. So if I assume that You know which process to watch, a way to detect a new window is to set up a windows hook:
delegate void WinEventDelegate(IntPtr hWinEventHook, uint eventType,
IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime);
[DllImport("user32.dll")]
public static extern IntPtr SetWinEventHook(uint eventMin, uint eventMax, IntPtr
hmodWinEventProc, WinEventDelegate lpfnWinEventProc, uint idProcess,
uint idThread, uint dwFlags);
[DllImport("user32.dll")]
public static extern bool UnhookWinEvent(IntPtr hWinEventHook);
// Constants from winuser.h
public const uint EVENT_SYSTEM_FOREGROUND = 3;
public const uint WINEVENT_OUTOFCONTEXT = 0;
//The GetForegroundWindow function returns a handle to the foreground window.
[DllImport("user32.dll")]
public static extern IntPtr GetForegroundWindow();
// For example, in Main() function
// Listen for foreground window changes across all processes/threads on current desktop
IntPtr hhook = SetWinEventHook(EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_FOREGROUND, IntPtr.Zero,
new WinEventDelegate(WinEventProc), 0, 0, WINEVENT_OUTOFCONTEXT);
void WinEventProc(IntPtr hWinEventHook, uint eventType,
IntPtr hwnd, int idObject, int idChild, uint dwEventThread, uint dwmsEventTime)
{
IntPtr foregroundWinHandle = GetForegroundWindow();
//Do something (f.e check if that is the needed window)
}
//When you Close Your application, remove the hook:
UnhookWinEvent(hhook);
I did not try that code explicitely for dialog boxes, but for separate processes it works well. Please remember that that code cannot work in a windows service or a console application as it requires a message pump (Windows applications have that). You'll have to create an own.
Hope this helps
As modal dialogs normally disable the parent window(s), you can enumerate all top level windows for a process and see if they're enabled using the IsWindowEnabled() function.

How can I disable mouse click event system wide using C#?

I have a laptop with a very sensitive touch pad, and wanted to code a small program that could block the mouse input when I was typing a paper or something.
I didn't think it would be hard to do, considering everything I've seen on low-level hooks, but I was wrong (astounding, right?).
I looked at a few examples, but the examples I've seen either block both keyboard and mouse, or just hide the mouse.
Any help with this would be great.
As you mentioned, you can do this using a low-level mouse hook (WH_MOUSE_LL), albeit somewhat incorrectly. What happens when you set a hook is that you'll receive notifications on each mouse input event (WM_MOUSEMOVE, WM_LBUTTONDOWN, WM_RBUTTONDOWN, WM_MBUTTONDOWN, WM_XBUTTONDOWN, WM_NCXBUTTONDOWN, the equivalent up events for each of those, WM_MOUSEWHEEL, and WM_MOUSEHWHEEL). Once you've finished processing each event, you're supposed to call the CallNextHookEx function, which passes the event information on to the next application in the hook chain. However, if you want to prevent any other program from getting mouse input information, you can just skip calling that function at the end of your hook procedure. The "Remarks" section of the above-linked documentation explains it thusly:
Calling CallNextHookEx is optional,
but it is highly recommended;
otherwise, other applications that
have installed hooks will not receive
hook notifications and may behave
incorrectly as a result. You should
call CallNextHookEx unless you
absolutely need to prevent the
notification from being seen by other
applications.
And as it turns out, low-level mouse hooks aren't actually that difficult in C#. I just coded one up myself, actually. But rather than posting that monstrosity of a library, I'll refer you to the simpler code snippet posted on Stephen Toub's blog, which I've reprinted here with syntax highlighting for convenience:
class InterceptMouse
{
private static LowLevelMouseProc _proc = HookCallback;
private static IntPtr _hookID = IntPtr.Zero;
public static void Main()
{
_hookID = SetHook(_proc);
Application.Run();
UnhookWindowsHookEx(_hookID);
}
private static IntPtr SetHook(LowLevelMouseProc proc)
{
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
return SetWindowsHookEx(WH_MOUSE_LL, proc,
GetModuleHandle(curModule.ModuleName), 0);
}
}
private delegate IntPtr LowLevelMouseProc(int nCode, IntPtr wParam, IntPtr lParam);
private static IntPtr HookCallback(
int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 &&
MouseMessages.WM_LBUTTONDOWN == (MouseMessages)wParam)
{
MSLLHOOKSTRUCT hookStruct = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));
Console.WriteLine(hookStruct.pt.x + ", " + hookStruct.pt.y);
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
private const int WH_MOUSE_LL = 14;
private enum MouseMessages
{
WM_LBUTTONDOWN = 0x0201,
WM_LBUTTONUP = 0x0202,
WM_MOUSEMOVE = 0x0200,
WM_MOUSEWHEEL = 0x020A,
WM_RBUTTONDOWN = 0x0204,
WM_RBUTTONUP = 0x0205
}
[StructLayout(LayoutKind.Sequential)]
private struct POINT
{
public int x;
public int y;
}
[StructLayout(LayoutKind.Sequential)]
private struct MSLLHOOKSTRUCT
{
public POINT pt;
public uint mouseData;
public uint flags;
public uint time;
public IntPtr dwExtraInfo;
}
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook,
LowLevelMouseProc 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);
}
As I explained above, you'll want to modify his HookCallback method not to call CallNextHookEx once you've finished processing the mouse event, but return something like new IntPtr(1) instead.
EDIT: And yeah, as others mentioned, there are probably other easier, cleaner solutions to this problem. Your trackpad drivers are a great place to look for an option like "Ignore accidental mouse input while typing". If you don't have this option, you're probably using the standard Windows mouse drivers. Try to download the drivers from your trackpad's manufacturer from the laptop manufacturer's website (for what it's worth, most of the non-Apple trackpads I've seen are Synaptics).
A lot of touchpad drivers have this as an option. I.e. When you are typing, it ignores touchpad input. You could also turn off the tap-click, relying on the actual touchpad buttons to click.
First try the driver's configuration utility, before you try to write your own.

Capture Highlighted Text from any window using C#

How to read the highlighted/Selected Text from any window using c#.
i tried 2 approaches.
Send "^c" whenever user selects some thing. But in this case my clipboard is flooded with lots of unnecessary data. Sometime it copied passwords also.
so i switched my approach to 2nd method, send message method.
see this sample code
[DllImport("user32.dll")]
static extern int GetFocus();
[DllImport("user32.dll")]
static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool fAttach);
[DllImport("kernel32.dll")]
static extern uint GetCurrentThreadId();
[DllImport("user32.dll")]
static extern uint GetWindowThreadProcessId(int hWnd, int ProcessId);
[DllImport("user32.dll") ]
static extern int GetForegroundWindow();
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
static extern int SendMessage(int hWnd, int Msg, int wParam, StringBuilder lParam);
// second overload of SendMessage
[DllImport("user32.dll")]
private static extern int SendMessage(IntPtr hWnd, uint Msg, out int wParam, out int lParam);
const int WM_SETTEXT = 12;
const int WM_GETTEXT = 13;
private string PerformCopy()
{
try
{
//Wait 5 seconds to give us a chance to give focus to some edit window,
//notepad for example
System.Threading.Thread.Sleep(5000);
StringBuilder builder = new StringBuilder(500);
int foregroundWindowHandle = GetForegroundWindow();
uint remoteThreadId = GetWindowThreadProcessId(foregroundWindowHandle, 0);
uint currentThreadId = GetCurrentThreadId();
//AttachTrheadInput is needed so we can get the handle of a focused window in another app
AttachThreadInput(remoteThreadId, currentThreadId, true);
//Get the handle of a focused window
int focused = GetFocus();
//Now detach since we got the focused handle
AttachThreadInput(remoteThreadId, currentThreadId, false);
//Get the text from the active window into the stringbuilder
SendMessage(focused, WM_GETTEXT, builder.Capacity, builder);
return builder.ToString();
}
catch (System.Exception oException)
{
throw oException;
}
}
this code working fine in Notepad. But if i try to capture from another applications like Mozilla firefox, or Visual Studio IDE, it's not returning the text.
Can anybody please help me, where i am doing wrong? First of all, i have chosen the right approach?
That's because both Firefox and Visual Studio don't use the built-in Win32 controls for displaying/editing text.
It is not possible in general to be able to get the value of "any" selected text, because of the fact that programs can re-implement their own version of the Win32 controls any way they see fit, and your program cannot possibly expect to work with all of them.
However, you can use the UI Automation APIs which will allow you to interact with the majority of 3rd-party controls (at least, all the good ones - such as Visual Studio and Firefox - will likely work with the UI Automation APIs since it's a requirement for accessibility)

Categories