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

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

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.

How to send the left shift key?

I am trying to send a key into another open process in Firefox.
I am supposed to send the Left Shift key, but this is without any luck.
I tried googling these answers but all I end up with were extern methods using nuggets or people using the regular shift. I tried many ways of sending the Left Shift using Enum of the Left Shift or Sendkey.Send("{LSHIFT}") and much more but none are working for me. I wish to know if there is any suitable way for me to send the Left Shift key.
This is my code so far:
public static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
{
int vkCode = Marshal.ReadInt32(lParam);
Keys pressed = (Keys)vkCode;
MessageBox.Show(pressed.ToString());
switch (pressed)
{
case Keys.Insert:
{
SendKeys.Send("{LSHIFT}");
}
break;
}
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
I have seen lists with and lists without the left shift key, but either way they pop up as error 'invalid key'.
Thank you.
Use keybd_event API with "VK_LSHIFT" virtual key code :
const byte VK_LSHIFT = 0xA0;
const uint KEYEVENTF_KEYUP = 0x0002;
[DllImport("user32.dll")]
private static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, int dwExtraInfo);
static void Main(string[] args)
{
keybd_event(VK_LSHIFT, 0, 0, 0);
Thread.Sleep(100);
keybd_event(VK_LSHIFT, 0, KEYEVENTF_KEYUP, 0);
}

send keydown and keyup separately

I am currently using this code:
else if (y2 > 0 && x2 < 0) {
SendKeys.SendWait("wa");
completion = completion + 0.1;
System.Threading.Thread.Sleep(2);
if (completion > y2) {
break;
}
}
However, instead of doing SendKeys.SendWait, I would like to only press those down, instead of downupdownup.
From this Stackoverflow question, SendMessage, When To Use KEYDOWN, SYSKEYDOWN, etc?, it appears that the way to send key-down messages requires using the user32.dll library:
[DllImport("user32.dll")]
public static extern int SendMessage(IntPtr hWnd, int Msg, uint wParam, uint lParam);
The parameter, Msg, has an option that allows the sending of KeyDown events:
private static ushort WM_KEYDOWN = 0x0100;
If you have the flexibility to implement your solution in other environments outside of .NET, AutoHotkey offers a rich set of functionality for sending input.

VSTO Windows Hook keydown event called 10 times

so, I've been developing a class to handle Kwyboard input in a VSTO add-in, so far I've been using Windows hooks to do so with relative success.
Having this code:
//.....
private const int WH_KEYBOARD = 2;
private const int WH_MOUSE = 7;
private enum WM : uint {
KEYDOWN = 0x0100,
KEYFIRST = 0x0100,
KEYLAST = 0x0108,
KEYUP = 0x0101,
MOUSELEFTDBLCLICK = 0x0203,
MOUSELEFTBTNDOWN = 0x0201,
MOUSELEFTBTNUP = 0x0202,
MOUSEMIDDBLCLICK = 0x0209,
MOUSEMIDBTNDOWN = 0x0207,
MOUSEMIDBTNUP = 0x0208,
MOUSERIGHTDBLCLK = 0x0206,
MOUSERIGHTBTNDOWN = 0x0204,
MOUSERIGHTBTNUP = 0x0205
}
private hookProcedure proc;
private static IntPtr hookID = IntPtr.Zero;
//Enganches
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
private static extern IntPtr SetWindowsHookEx(int hookId, hookProcedure proc, IntPtr hInstance, uint thread);
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
private static extern bool unHookWindowsHookEx(int hookId);
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
private static extern IntPtr CallNextHookEx(IntPtr hookId, int ncode, IntPtr wparam, IntPtr lparam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string name);
[DllImport("kernel32", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int GetCurrentThreadId();
public CPInputListener() {
proc = keyBoardCallback;
hookID = setHook(proc);
}
private IntPtr setHook(hookProcedure procedure){
ProcessModule module = Process.GetCurrentProcess().MainModule;
uint threadId = (uint)GetCurrentThreadId();
return SetWindowsHookEx(WH_KEYBOARD, procedure, IntPtr.Zero, threadId);
}
public void stopListeningAll() {
unHookWindowsHookEx(WH_KEYBOARD);//For now
}
private IntPtr keyBoardCallback(int ncode, IntPtr wParam, IntPtr lParam) {
if (ncode >= 0) {
//LPARAM pretty useless
Keys key = (Keys)wParam;
KeyEventArgs args = new KeyEventArgs(key);
onKeyDown(args);//for now
}
return CallNextHookEx(hookID, ncode, wParam, lParam);
}
//....
I do successfully receive keyboard input, but here is the big mistery; each time a key is pressed, no matter how fast it was, the event (onKeyDown) is called 10 times exactly, no more no less.
If the key is long pressed, the event keep being called but 10 by 10 times instead of calling just once.
So far I've tried
Using wParam to call the required event on Key Up: Doesn't seem to work, in all codes I've seen dealing with Key down and up events, IntPtr wParam is used, but from that variable I can only retrieve the keycode which doesn't help.
Using lParam or nCode: These vars are giving unconsistent values between those 10 calls, ncode tends to retrieve 0's and 3's and lParam some values which seem to be unmanaged memory adresses...
What do I expect
I do expect for onKeyDown to be called just once when the key is pressed or in the other hand being able to call the method by on key up which i do expect to be called just once per key releasing.
How to bypass this
If I can't find a reasonable answer, I was thinking on using a custom made timer to discard all those callings and use only the last one, would you recommend this if everything else fails?
Thanks a lot! Be happy and be kind! :D
First you have to filter for the correct ncode to get only the keystrokes you are supposed to process. (For example, you are not supposed to process HC_NOREMOVE.)
Then you have to check if it was a KeyDown or KeyUp event using a flag in lParam.
If the key was long-pressed, multiple KeyDown events are already combined to one call by Win32, so you don't have to do anything special here. But if you want to get only the last KeyUp event then you have to check another flag in lParam as well.
So, here's the code you need to change:
private IntPtr keyBoardCallback(int ncode, IntPtr wParam, IntPtr lParam)
{
// Feel free to move the const to a private field.
const int HC_ACTION = 0;
if (ncode == HC_ACTION)
{
Keys key = (Keys)wParam;
KeyEventArgs args = new KeyEventArgs(key);
bool isKeyDown = ((ulong)lParam & 0x40000000) == 0;
if (isKeyDown)
onKeyDown(args);
else
{
bool isLastKeyUp = ((ulong)lParam & 0x80000000) == 0x80000000;
if (isLastKeyUp)
onKeyUp(args);
}
}
return CallNextHookEx(hookID, ncode, wParam, lParam);
}
Edit as requested in the comment:
Unfortunately the documentation of these parameters is pretty sparse.
One "hint" not to process anything other then HC_ACTION can be found here, stating:
if (nCode < 0) // do not process message
return ...;
// ...
switch (nCode)
{
case HC_ACTION:
// ... do something ...
break;
default:
break;
}
// ...
return CallNextHookEx(...);
Another supporting statement is made here:
Why does my keyboard hook receive the same key-up and key-down events multiple times?
The content of the lParam is defined as follows:
typedef struct tagKBDLLHOOKSTRUCT {
DWORD vkCode;
DWORD scanCode;
DWORD flags;
DWORD time;
ULONG_PTR dwExtraInfo;
}
(Just as a reminder: DWORD here is 4 bytes in size on x86 as well as on x64 platforms.)
The documentation of the lParam flags can be found here and here.
In this links it's described that
bit 30 (=0x40000000) is the previous key state
(1 if the key was down and 0 if the key was up before the new key state that caused this call)
bit 31 (=0x80000000) is the transition state
(0 on key press and 1 on key release now)
The term "previous key state" is rather confusing but effectively it's just the opposite of the current state (because there's only up or down and no third state).
The transition state is especially relevant when the "keyboard's automatic repeat feature" is activated, i.e. when the key is pressed down long enough.
Another sample (using VC7) can be found here:
if (HIWORD (lParam) & 0xC000)
// Key up without autorepeat
else
// Key down
Where 0xC000 just is 0x4000 || 0x8000 and defines that the key was released and has created a key up event.
All in all pretty confusing but nonetheless true.
Maybe there are other links out there that can describe this situation better, but I guess in times like these where new app development "should be done" in tiny sandboxes (like UWP) and VSTO is on its sure way to die to make way for newer Office add-ins that are written in HTML and JavaScript, nobody cares all that much about low-level hooks anymore.

Directly sending keystrokes to another process via hooking

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

Categories