Capturing a key without focusing the window - c#

I have a application that always checks if a key like F12 is pressed. It doesn't need to have in focus of my main window of my app. I tried this code:
public int a = 1;
// DLL libraries used to manage hotkeys
[DllImport("user32.dll")]
public static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vlc);
[DllImport("user32.dll")]
public static extern bool UnregisterHotKey(IntPtr hWnd, int id);
const int MYACTION_HOTKEY_ID = 1;
public Form1()
{
InitializeComponent();
// Modifier keys codes: Alt = 1, Ctrl = 2, Shift = 4, Win = 8
// Compute the addition of each combination of the keys you want to be pressed
// ALT+CTRL = 1 + 2 = 3 , CTRL+SHIFT = 2 + 4 = 6...
RegisterHotKey(this.Handle, MYACTION_HOTKEY_ID, 0, (int) Keys.F12);
}
protected override void WndProc(ref Message m)
{
if (m.Msg == 0x0312 && m.WParam.ToInt32() == MYACTION_HOTKEY_ID)
{
a++;
MessageBox.Show(a.ToString());
}
base.WndProc(ref m);
}
I put 0 to this line RegisterHotKey(this.Handle, MYACTION_HOTKEY_ID, 0, (int) Keys.F12); so that only if F12 is pressed it will capture.
But it didn't work. How can I solve this?
Here I couldn't understand some lines like:
const int MYACTION_HOTKEY_ID = 1;
m.Msg == 0x0312 && m.WParam.ToInt32() == MYACTION_HOTKEY_ID
base.WndProc(ref m);
Can anyone help me to understand these lines?

But it didn't work. How can I solve this?
What do you mean "it didn't work"? The code in your question looks correct to me.
The only reason it might not be working is because the RegisterHotKey function is returning an error and you're not checking for it. To make this work, you need to add the SetLastError attribute to its declaration, which causes the runtime to cache the Win32 error code that it sets. Once this is done, you can check that error code (if the function returns false) by calling the GetLastWin32Error function. I recommend using the result of this function to generate and throw a Win32Exception.
Modify your declaration of RegisterHotKey as follows:
[DllImport("user32.dll", PreserveSig = false)]
public static extern bool RegisterHotKey(IntPtr hWnd,
int id,
uint fsModifiers,
Keys key);
And your call to the function as follows:
if (!RegisterHotKey(this.Handle, MYACTION_HOTKEY_ID, 0, Keys.F12))
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
Once that's done, I suspect you'll see an exception getting thrown with the error message:
Hot key is already registered
Well, that makes debugging the problem much simpler, now doesn't it! Chances are you'll need to select a different hot key, since the RegisterHotKey function documentation tells us explicitly that:
The F12 key is reserved for use by the debugger at all times, so it should not be registered as a hot key. Even when you are not debugging an application, F12 is reserved in case a kernel-mode debugger or a just-in-time debugger is resident.
When I run the code and register F11 as a hotkey, it works just fine for me.
Here I couldn't understand some lines like:
const int MYACTION_HOTKEY_ID = 1;
m.Msg == 0x0312 && m.WParam.ToInt32() == MYACTION_HOTKEY_ID
base.WndProc(ref m);
Can anyone help me to understand these lines?
Sure:
The first line declares a constant value that uniquely identifies the hotkey that you installed using the RegisterHotKey function. More specifically, it corresponds to the id parameter of the function. You passed it in on the initial call.
This checks in the window procedure (WndProc) to see if the message (Msg) that is being processed is the WM_HOTKEY message. The WM_HOTKEY message is posted automatically to your window whenever the hot key you registered with the RegisterHotKey function is pressed.
You shouldn't really be using the magic number 0x0312 directly, though, because you're not the only one who is unsure what it means. Instead, define a constant and use that instead:
const int WM_HOTKEY = 0x0312;
m.Msg == WM_HOTKEY
The second part of that conditional test (the part after the &&) checks the wParam field of the message to see if the hot key that was pressed was the one you registered. Remember that MYACTION_HOTKEY_ID is the unique ID of your hot key. The WM_HOTKEY message documentation tells us that checking the wParam is how we determine which hot key was pressed.
This calls the base class's window procedure. In other words, what you've done is overridden the virtual WndProc method, allowing you to add some additional code (your processing of WM_HOTKEY). When you're done with your additional logic, you want to continue with the logic of the base class, so you forward the message on.

Your code has no wrong . But it doesn't work here because the F12 key is reserved you may try with another key like F10, F11 etc .

I don't know why, but I feel like this is related to this question... so I'm gonna try to explain it once more:
const int MYACTION_HOTKEY_ID = 1;
is where you save the integer that is used to identify the hotkey. If you need to register more than on hotkey, you will have to declare other integer fields identifying the other hotkeys:
const int ANOTHER_ACTION_HOTKEY_ID = 2;
const int AND_ANOTHER_ACTION_HOTKEY_ID = 3;
Then,
m.Msg == 0x0312 && m.WParam.ToInt32() == MYACTION_HOTKEY_ID
is the condition that enables you to know which hotkey has been typed by the user.
0x0312 (also declared as WM_HOTKEY in the documentation you can found here for instance) is to know if a registered hotkey has been pressed:
When a key is pressed, the system looks for a match against all hot keys. Upon finding a match, the system posts the WM_HOTKEY message to the message queue of the window with which the hot key is associated. If the hot key is not associated with a window, then the WM_HOTKEY message is posted to the thread associated with the hot key.
According to the documentation, you cannot use the F12 hotkey:
The F12 key is reserved for use by the debugger at all times, so it should not be registered as a hot key. Even when you are not debugging an application, F12 is reserved in case a kernel-mode debugger or a just-in-time debugger is resident.

To do a similar thing I implemented a low-level keyboard hook using SetWindowsHookEx. That will trap all keyboard messages going through Windows, and allow you to inspect them and if necessary, prevent them going any further.
Take a look at my KeyboardHandling project in my RocketLauncher GitHub hobby project. You can take what you need directly from that. I'm going to make it a nuget package soon, too.

Related

SendKeys with games: with some characters it works, but with some it doesn't

I want to simulate input in games with SendKeys, but I have a hard time.
If I use it with i.e. the letter T, while the cursor in Minecraft is in a textbox (in the main menu), it works, the letter T is written in the textbox.
But with {ESC} it doesn't work. Nothing happens. If I press it manually, it backs to the previous menu. (as it should)
With some applications ESC works:
It works with Discord, Sourcetree, Slack, Chrome, CS2D,
but for some reason it doesn't work with Minecraft, Spelunky, Half-Life.
All of the applications mentioned above were in windowed mode.
Another issue:
If I send 2 to Minecraft while in a text field, it works correctly, 2 is written.
But if I send it while I'm playing, there is no effect. (The character should switch to Item Slot #2)
Same with " " (whitespace). In text fields it works, but the character won't jump in the game.
Code:
[DllImport("USER32.DLL", CharSet = CharSet.Unicode)]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("USER32.DLL")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
public Form1()
{
InitializeComponent();
IntPtr minecraftHandle = FindWindow("GLFW30", "Minecraft* 1.15.2");
if (minecraftHandle == IntPtr.Zero)
{
MessageBox.Show("Minecraft is not running.");
return;
}
SetForegroundWindow(minecraftHandle);
SendKeys.SendWait("{ESC}");
}
I tried it without focus switching: by assigning the SendKey calls to a hotkey, so the target application can be in focus when the SendKeys are called.
The results are the same :\
Do not use SendKeys.Send to messaging between processes working on different runtimes
SendKeys.Send method is from System.Windows.Forms namespace.
This means it is not a Windows Input simulator, but just a little helper for Windows Forms applications. There is no guarantee this method work with another process on different (not .NET) runtime system.
Despite the fact that SendKeys.Send method uses native Windows API, it send key pressing message only of fixed period of time, so game frame handling may not have time to catch this message to manage it. So you may need for separate commands to send message about key down and key up events.
Do not use SendKeys API for messaging with another processes, especially with games.
Also, games can use protection system to rid of automatic bots that can blocks any messages from operation system programming input
So, what you can use?
First, you can try to use PostMessage of user32.dll system library:
const uint WM_KEYDOWN = 0x0100;
const uint WM_KEYUP = 0x0101;
[DllImport("user32.dll")]
static extern bool PostMessage(IntPtr hWnd, uint msg, int wParam, int lParam);
// hWnd - Window handler (can be getted by using GetForegroundWindow/FindWindow methods)
// msg - Key up/down message (WM_KEYUP / WM_KEYDOWN)
// wParam - Virual key code you need to pass to the window
// lParam - Additional parameter for set up key message behaviour.
All virtual key codes can be found on microsoft docs website:
https://learn.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
Don't forget that you need to wait some time before key releasing. This is needed because games cache inputs between frames, and frame has fixed time to catch input. Just write some delay between key down and up messages.
Also you can set up key message behaviour by lParam. See WM_KEYDOWN and WM_KEYUP parameters. Special thing about WM_KEYDOWN message is if you pressing key on real keyboard long time, operation system repeating WM_KEYDOWN message accordingly. Repeating count can be setted up through lParam. Use it if window you messaging does not react on single keydown message.
PostMessage is low-level system command that can be used for messaging between processes. This command has a low probability to be blocked by protection system (but not zero) and high probability to be received by the game/process you working with. Also it provides opportunity to separate key up and key down messages.
What if PostMessage didn't work?
Try to use hardware scan code instead of virtual key code. Detailed explanation how you can do that described in this answer.
If protection system is really good and PostMessage is blocking even if you use hardware scan code, one thing you can try is to use another keyboard input driver or write it yourself. That driver must replace default system keyboard driver. And you can message it to interact with game. This is the 100% guarantee way to interact with other process through keyboard. But if you use public custom keyboard drivers, there is some probability that protection system blocks it. So you need to write your own driver to message between processes.

SendKeys to inactive application

I am trying to figure out how I can make my C# application to send keys to another application window, without focusing on it.
I have a list of words and 3 notepads files.
Imagine I have all 3 notepad windows opened in order, and my program would take the first word in the listbox and write it in the first Notepad window. The second word in the second Notepad window and third one in the third Notepad window. Then start over and continue.
So I want it to post 1 word in each and continue like that over and over.
But I only figured out how to do it with 1 notepad window (while having it active).
int i = 0;
i = listBox1.SelectedIndex;
i = i + 1;
if (i > listBox1.Items.Count - 1)
i = 0;
listBox1.SelectedIndex = i;
string message = listBox1.SelectedItem.ToString();
SendKeys.Send(message);
SendKeys.Send("{ENTER}");
This would require me to first focus on the notepad window, start the timer and then keep focus on the notepad window. It would then just loop through the list and type the word (1 on each line). And it works fine. But I want to be able to do it on 3 windows.
And then I need to get the window title somehow, not the process name.
I would have 3 processes called Notepad then.
But if they are named Note1, Note2, Note3 how would I do that?
I need help to make some kind of list of what programs to write to:
listofprograms = ["Note1", "Note2", "Note3"];
And it would find the application windows opened with those names,
then somehow write the text into those windows.
Could anyone help me out? Haven't found anything about this so far and trust me I've looked around!
Unfortunately there is no great way to do this. SendKeys is a really simple and desirable API but it only applies to the active window. There is no way to make it work on an inactive window nor is there an API with the same ease of access that works on inactive windows.
Generally when people run up against this problem they have to go one of two routes
Physically active the apps you want to send the keys to one at a time
Drop down to a much lower level of SendMessage or PostMessage to send keyboard events
The second option is generally more reliable but harder to implement.
SendKeys is not made for this type of functionality. To do what you're looking for, you're going to need to use some Win32 API calls in your code. See How to send text to Notepad in C#/Win32? for reference.
If you're looking for a way to send keys to an application, using SendKeys.Send(keys) is an option, but you need to bring the window to the top via the SetForegroundWindow API.
So, if you continue using your approach, you could use FindWindow, SetForegroundWindow to force the Notepad windows to be activated and focused, so that you could send the keys.
[DllImportAttribute("User32.dll")]
private static extern int FindWindow(String ClassName, String WindowName);
[DllImport("user32.dll")]
private static extern IntPtr SetForegroundWindow(int hWnd);
public int Activate(int hWnd)
{
if (hWnd > 0) {
SetForegroundWindow(hWnd);
return hWnd;
}
else {
return -1;
}
}
public int GetWindowHwnd(string className, string windowName) {
int hwnd = 0;
string cls = className == string.Empty ? null : className;
string win = windowName == string.Empty ? null : windowName;
hwnd = FindWindow(cls , win );
return hwnd;
}
Although there is also another solution, which could help you out. Here all Notepad processes are handled:
How to send text to Notepad in C#/Win32?
With some adaptions it should work for your case, too (basically you would iterate and loop through the notepad instances found and place a word in each instance).
You might also want to take a look at the following information about FindWindow:
http://www.pinvoke.net/default.aspx/user32.findwindow
SetKeyboardState:
http://www.pinvoke.net/default.aspx/user32/SetKeyboardState.html
As well as SendMessage:
http://www.pinvoke.net/default.aspx/coredll/SendMessage.html
You should find some useful hints in the examples and descriptions.

How to do "something" when a window that is on background sends a specific message

im trying to do something on an app, that I know its name etc...(so I'm alredy casting findwindow and stuff)
For ex. I want to notify user when that window tries to gain focus.
I have mess around with wndproc yet I seem to not get it at all.
for ex. here is a code I found on stackoverflow and failed even executing it
public IntPtr WndProc(int hwnd, int msg, IntPtr wParam, IntPtr lParam)
{
if (msg == WM_NCACTIVATE)
{
SystemSounds.Beep.Play();
SystemSounds.Beep.Play();
SystemSounds.Beep.Play();
SystemSounds.Beep.Play();
SystemSounds.Beep.Play();
}
return IntPtr.Zero;
}
now the thing I dont understand is, there is int msg that I think stands for message. arent wndproc is the one that supposed to get it ? what is the point of giving it to wndproc ?
Second, executing this function. What do I do, check for message every 100 ms or are there event-type thing for it ?
Im really confused here and I'd appreciate little help here.
I'm afraid I don't entirely understand what you're asking here.
That WndProc function definition that you've found is not what it would look like in C#. Instead, you would override the WndProc member function of the Control class. All window messages are routed through this function. You would only override it if you wanted to process a message in an unusual way, to do something that the .NET Framework isn't already doing for you.
For example, for a Form, you would override WndProc like this:
public class MyForm : Form
{
// other code
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case WM_NCACTIVATE:
{
SystemSounds.Beep.Play();
break;
}
base.WndProc(ref m); // proceed with default processing
}
}
}
Notice that the .NET Framework wraps all of the message information up into a Message structure, rather than passing 4 raw parameters to the function like the Win32 API does.
there is int msg that I think stands for message. arent wndproc is the one that supposed to get it ? what is the point of giving it to wndproc ?
The Message.Msg member corresponds to the int msg parameter in your function definition. This is the identifier of the window message that is to be processed. These are all defined inside of the Windows header files, and they generally begin with WM_. You can find the documentation for these messages on MSDN, which will tell you what they mean and when they are received. For example, the WM_NCACTIVATE message is sent to a window when its non-client area is being activated or inactivated.
The WndProc function is going to be called each time any message is received. The way you determine which message was received, and therefore which one you should be processing, is by switching on the value of the Message.Msg member (or, in your original example, the msg parameter).
Second, executing this function. What do I do, check for message every 100 ms or are there event-type thing for it ?
You don't have to check for anything. WndProc is a function, just like any other function, including those that you write yourself, which means that it only gets called when it should execute.
It is not itself an event, although the default processing inside of the WndProc function is what is responsible for raising the events you're familiar with in response to certain messages that it receives.
im trying to do something on an app, that I know its name etc...(so I'm alredy casting findwindow and stuff) For ex. I want to notify user when that window tries to gain focus.
I'm not exactly sure what this means, but you should look into the WM_ACTIVATEAPP message. This message is sent to a window whenever it is being activated and whenever it is being deactivated. In response to that message, you could choose to do whatever you like, including playing a sound. As the linked documentation indicates, the wParam parameter (found in the Message.WParam member) tells you whether your window is being activated or deactivated.
This is pretty much as advanced as it gets. It's extremely rare that you need to override the WndProc method when you're programming in WinForms. By doing so, you can do nearly anything, but there's almost always a better, simpler way to do things.

How can I programmatically generate keypress events in C#?

How can I programmatically create an event that would simulate a key being pressed on the keyboard?
The question is tagged WPF but the answers so far are specific WinForms and Win32.
To do this in WPF, simply construct a KeyEventArgs and call RaiseEvent on the target. For example, to send an Insert key KeyDown event to the currently focused element:
var key = Key.Insert; // Key to send
var target = Keyboard.FocusedElement; // Target element
var routedEvent = Keyboard.KeyDownEvent; // Event to send
target.RaiseEvent(
new KeyEventArgs(
Keyboard.PrimaryDevice,
PresentationSource.FromVisual(target),
0,
key)
{ RoutedEvent=routedEvent }
);
This solution doesn't rely on native calls or Windows internals and should be much more reliable than the others. It also allows you to simulate a keypress on a specific element.
Note that this code is only applicable to PreviewKeyDown, KeyDown, PreviewKeyUp, and KeyUp events. If you want to send TextInput events you'll do this instead:
var text = "Hello";
var target = Keyboard.FocusedElement;
var routedEvent = TextCompositionManager.TextInputEvent;
target.RaiseEvent(
new TextCompositionEventArgs(
InputManager.Current.PrimaryKeyboardDevice,
new TextComposition(InputManager.Current, target, text))
{ RoutedEvent = routedEvent }
);
Also note that:
Controls expect to receive Preview
events, for example PreviewKeyDown
should precede KeyDown
Using target.RaiseEvent(...) sends the event directly to the target
without meta-processing such as
accelerators, text composition and
IME. This is normally what you want.
On the other hand, if you really do
what to simulate actual keyboard keys
for some reason, you would use
InputManager.ProcessInput() instead.
To produce key events without Windows Forms Context,
We can use the following method,
[DllImport("user32.dll")]
public static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, uint dwExtraInfo);
sample code is given below:
const int VK_UP = 0x26; //up key
const int VK_DOWN = 0x28; //down key
const int VK_LEFT = 0x25;
const int VK_RIGHT = 0x27;
const uint KEYEVENTF_KEYUP = 0x0002;
const uint KEYEVENTF_EXTENDEDKEY = 0x0001;
int press()
{
//Press the key
keybd_event((byte)VK_UP, 0, KEYEVENTF_EXTENDEDKEY | 0, 0);
return 0;
}
List of Virtual Keys are defined here.
To get the complete picture, please use the below link,
http://tksinghal.blogspot.in/2011/04/how-to-press-and-hold-keyboard-key.html
I've not used it, but SendKeys may do what you want.
Use SendKeys to send keystrokes and
keystroke combinations to the active
application. This class cannot be
instantiated. To send a keystroke to a
class and immediately continue with
the flow of your program, use Send. To
wait for any processes started by the
keystroke, use SendWait.
System.Windows.Forms.SendKeys.Send("A");
System.Windows.Forms.SendKeys.Send("{ENTER}");
Microsoft has some more usage examples here.
Easily!
(because someone else already did the work for us...)
After spending a lot of time trying to this with the suggested answers I came across this codeplex project Windows Input Simulator which made it simple as can be to simulate a key press:
Install the package, can be done or from the NuGet package manager or from the package manager console like:
Install-Package InputSimulator
Use this 2 lines of code:
inputSimulator = new InputSimulator()
inputSimulator.Keyboard.KeyDown(VirtualKeyCode.RETURN)
And that's it!
-------EDIT--------
The project page on codeplex is flagged for some reason, this is the link to the NuGet gallery.
Windows SendMessage API with send WM_KEYDOWN.

Equivalent of PreviewKeyDown of C# needed for native C++/MFC

I used a ActiveXControl in a C# Forms application and had the possibility to implement a PreviewKeyDown event handler for that ActiveXControl. That was needed to specify that, e.g. the [ALT] key, is an input key.
For some reasons or other I have to reimplement the application in native C++/MFC and don't know how to specify that this [ALT] key is an input key and to be handled by the ActiveXControl.
You could use SetTimer to generate a WM_TIMER event 20 times a second or so
SetTimer( NULL, kMyTimer, 50, MyTimerCallback );
Then implement a function as follows.
void CALLBACK MyTimerCallback( HWND hWnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime )
{
static short lastLeftAltPress = 0;
short thisLeftAltPress = GetAsyncKeyState( VK_LMENU );
if ( thisLeftAltPress != 0 && lastLeftAltPress == 0 )
{
CallAltHandlingCode();
}
thisLeftAltPress = lastLestAltPress;
// Handling code for other keys goes here.
}
This will then poll the keyboard every 50ms to find out if the left alt key has just been pressed and then call your handling code. If you want to fire the handler when its released then you would use the following if statement
if ( thisLeftAltPress == 0 && lastLeftAltPress != 0 )
or if you just want to see if it is down then you do
if ( thisLeftAltPress != 0 )
The docs for GetAsyncKeyState do state that you can check whether the lowest bit is set to see if the key has just been pressed but it does also point out that this may fail in unexpected ways in multi-threaded environments. The above scheme should always work.
thanks for all your recommendations.
For my case I finally found some way how to make it work. So far what I have learnt the situation is that a PreviewKeyDown event is triggered before the KeyDown message is sent.
I implemented PreTranslateMessage in the dialog which hosts the ActiveX control and called ::SendMessage(WM_KEYDOWN...) with the handle of the ActiveX control, using pMsg for the arguments.
Cheers,
Ilmari
I think that you can use the GetAsyncKeyState Win32 function (http://msdn.microsoft.com/en-us/library/ms646293%28VS.85%29.aspx) to get the state of all the keys in the system, VK_MENU (http://msdn.microsoft.com/en-us/library/dd375731%28v=vs.85%29.aspx) is the key you should monitor for the [Alt] key.
Haven't tried this, but MSDN doesn't say that you won't get a WM_KEYDOWN for the ALT key -- any other key pressed while ALT is down generates a WM_SYSKEYDOWN, but that doesn't say that you can't handle ALT via WM_KEYDOWN.

Categories

Resources