Send fast textinput to another process (Window) - c#

I am writing a C# WPF program which sends text messages to another program's window. I have a macro program as part of my keyboard drivers (Logitech g15) which already does this, though it does not send keystrokes directly to the process, but to the currently focused window. It works well but i need to be able to send inputs from my program as well. There are other people using the process so the input text messages from my program needs to be fast enough so that my text does not interfere with their input.
The problem is that when I try to do this with a c# program I get too much delay. The macro program (Logitech G-Series Profiler) sends a command instantly. I have tried the following three commands for sending messages to process. (Listed by order of slowest to fastest)
SetForegroundWindow(_hWnd);
SendKeys.SendWait("{Enter}This is a keystroke input.{Enter}");
It is probably in the name, but this performs the command so slowly that I can actually follow with my eyes the text as it is input letter by letter. I have tried using the “SendKeys.Send” method but I get an error saying: “SendKeys cannot run inside this application because the application is not handling Windows messages.”
PostMessage((IntPtr)_hWnd, (uint)WMessages.WM_KEYUP, (int)key, (int)key);
PostMessage is a bit faster but still not fast enough for the purpose of my program. Besides the method returns before the message has been read by the process, which means two sequential PostMessage calls may not send sequential messages.
SendMessage(_hWnd, 0x100, (int) VKeys.VK_2, (int) VKeys.VK_2);
This is faster than the PostMessage but not nearly as fast as the macro program from Logitech. Also, the receiving program handles the input strangely, apparently not treating it the same way it does "genuine" input from the keyboard.
SetForegroundWindow(_hWnd);
const string text = "This is a keystroke input.";
IInputElement target = Keyboard.FocusedElement;
IInputElement target = InputManager.Current.PrimaryKeyboardDevice.FocusedElement;
var routedEvent = TextCompositionManager.TextInputEvent;
target.RaiseEvent(new TextCompositionEventArgs(InputManager.Current.PrimaryKeyboardDevice, new TextComposition(InputManager.Current, target, text)) { RoutedEvent = routedEvent });
This is the last thing I have tried. It seems instant with the way the text is sent to a process. However, I have only been able to send this to my own program since Keyboard.FocusedElement returns null when I have another program set as foreground window.
If someone can tell me how to get an IInputElement of another window I would sure like to know. Alternatively, if someone has a suggestion for a better method of sending input, I would dearly like to hear it.
Specs: Windows 7, 64bit
Visual Studio 2010, Framework 4

First of all, are you intentionally using WM_KEYDOWN (0x0100) instead of WM_KEYUP (0x0101) in your SendMessage example? This would just press the keys, and never release them, so the application would not process them properly.
Another way worth trying would be to send WM_SETTEXT, assuming the control interprets it correctly (like edit controls or combo boxes).
A last option would be to use SendInput which synthesizes keyboard and mouse input on a very low level, but similarly to you keyboard's macro program, this requires you to activate the correct window and set the focus, which can be quite painful.

Depending on your other's program window type, you could use UI Automation. See this example here:
Add Content to a Text Box Using UI Automation

Related

Keyboard input lost when using cross-process parent/child windows

I am investigating a bug that results in key-presses being 'lost' when users are providing rapid keyboard input to our application. It seems to happen randomly. If a user writes e.g. "I am writing this text fast on my keyboard" the actual text that ends up in the application's text box looks something like "Ia wrting thistext fstn mykeybrd."
We have managed to find out that the issue seems to be related to how we integrate the text-input component into our main application. Our main app is a .NET Framework 4.8 WinForms process. The text-input component is running as a .NET 4.8 WPF app in a separate process. The WinForms app is responsible for launching the WPF process, passing the window handle of its own main window as an argument to the new process. Once launched, the WPF process uses the provided window handle to reparent itself as a child window of the WinForms app. This is done using Win32 API calls through P/Invoke.
private void Reparent() {
ChangeStyle(this.myHandle);
Win32.SetParent(this.myHandle, this.hostHandle);
}
private static void ChangeStyle(IntPtr myHandle) {
const int GWL_STYLE = -16;
const uint WS_POPUP = 0x80000000;
const uint WS_CHILD = 0x40000000;
uint style = Win32.GetWindowLong(myHandle, GWL_STYLE);
style |= WS_CHILD;
style &= ~WS_POPUP;
Win32.SetWindowLong(myHandle, GWL_STYLE, style);
}
According to MSDN this seems to be legal.
For compatibility reasons, SetParent does not modify the WS_CHILD or WS_POPUP window styles of the window whose parent is being changed. Therefore, if hWndNewParent is NULL, you should also clear the WS_CHILD bit and set the WS_POPUP style after calling SetParent. Conversely, if hWndNewParent is not NULL and the window was previously a child of the desktop, you should clear the WS_POPUP style and set the WS_CHILD style before calling SetParent.
We understand that this is a bit erm... 'unorthodox', but the design has been like this for a long time without any other issues.
Interestingly, removing the code that sets the WS_CHILD flag fixes the lost keys problem, but causes a bunch of other issues instead.
According to Raymond Chen
Creating a cross-thread parent/child or owner/owned window relationship implicitly attaches the input queues of the threads which those windows belong to...
We interpret this like AttachThreadInput is called 'under the hood', but do not fully understand what causes keypresses to be lost. Is it some sort of thread-safety issue? A race condition?
By using the AttachThreadInput function, a thread can share its input states (such as keyboard states and the current focus window) with another thread. Keyboard and mouse events received by both threads are processed in the order they were received until the threads are detached by calling AttachThreadInput a second time and specifying FALSE for the fAttach parameter.
We have used Spy++ to monitor the Windows messages that gets sent to the WPF process and it seems that when you type slowly, WM_KEYDOWN is sent together with WM_CHAR. When the input is lost, we still receive the WM_KEYDOWN messages, but no WM_CHAR. This led us to start investigating the .NET framework source. Among other things, we found the following code in HwndSource.cs
switch ((WindowMessage)msgdata.msg.message)
{
case WindowMessage.WM_SYSKEYDOWN:
case WindowMessage.WM_KEYDOWN:
// MITIGATION: HANDLED_KEYDOWN_STILL_GENERATES_CHARS
// In case a nested message pump is used before we return
// from processing this message, we disable processing the
// next WM_CHAR message because if the code pumps messages
// it should really mark the message as handled.
_eatCharMessages = true;
DispatcherOperation restoreCharMessages = Dispatcher.BeginInvoke(DispatcherPriority.Normal, new DispatcherOperationCallback(RestoreCharMessages), null);
// Force the Dispatcher to post a new message to service any
// pending operations, so that the operation we just posted
// is guaranteed to get dispatched after any pending WM_CHAR
// messages are dispatched.
Dispatcher.CriticalRequestProcessing(true);
The variable named _eatCharMessages could perhaps be related, although debugging this code using dnSpy has not made us any wiser.
We're looking for a Win32-wizard to shed some more light on this. Anything that can point us in the right direction would be greatly appreciated. We need to figure out the root cause of the problem in order to decide how to fix it.

C# how to detect which keyboard is pressed? [duplicate]

I have a barcode scanner (which acts like a keyboard) and of course I have a keyboard too hooked up to a computer. The software is accepting input from both the scanner and the keyboard. I need to accept only the scanner's input. The code is written in C#. Is there a way to "disable" input from the keyboard and only accept input from the scanner?
Note:
Keyboard is part of a laptop...so it cannot be unplugged. Also, I tried putting the following code
protected override Boolean ProcessDialogKey(System.Windows.Forms.Keys keyData)
{
return true;
}
But then along with ignoring the keystrokes from the keyboard, the barcode scanner input is also ignored.
I cannot have the scanner send sentinal characters as, the scanner is being used by other applications and adding a sentinal character stream would mean modifying other code.
Also, I cannot use the timing method of determining if the input came from a barcode scanner (if its a bunch of characters followed by a pause) since the barcodes scanned could potentially be single character barcodes.
Yes, I am reading data from a stream.
I am trying to follow along with the article: Distinguishing Barcode Scanners from the Keyboard in WinForms. However I have the following questions:
I get an error NativeMethods is inaccessible due to its protection level. It seems as though I need to import a dll; is this correct? If so, how do I do it?
Which protected override void WndProc(ref Message m) definition should I use, there are two implementations in the article?
Am getting an error related to [SecurityPermission( SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)] error CS0246: The type or namespace name 'SecurityPermission' could not be found (are you missing a using directive or an assembly reference?). How do I resolve this error?
There is also an error on the line containing: if ((from hardwareId in hardwareIds where deviceName.Contains(hardwareId) select hardwareId).Count() > 0) Error is error CS1026: ) expected.
Should I be placing all the code in the article in one .cs file called BarcodeScannerListener.cs?
Followup questions about C# solution source code posted by Nicholas Piasecki on http://nicholas.piasecki.name/blog/2009/02/distinguishing-barcode-scanners-from-the-keyboard-in-winforms/:
I was not able to open the solution in VS 2005, so I downloaded Visual C# 2008 Express Edition, and the code ran. However, after hooking up my barcode scanner and scanning a barcode, the program did not recognize the scan. I put a break point in OnBarcodeScanned method but it never got hit. I did change the App.config with the id of my Barcode scanner obtained using Device Manager. There seems to be 2 deviceNames with HID#Vid_0536&Pid_01c1 (which is obtained from Device Manager when the scanner is hooked up). I don't know if this is causing the scanning not to work. When iterating over the deviceNames, here is the list of devices I found (using the debugger):
"\??\HID#Vid_0536&Pid_01c1&MI_01#9&25ca5370&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}"
"\??\HID#Vid_0536&Pid_01c1&MI_00#9&38e10b9&0&0000#{884b96c3-56ef-11d1-bc8c-00a0c91405dd}"
"\??\HID#Vid_413c&Pid_2101&MI_00#8&1966e83d&0&0000#{884b96c3-56ef-11d1-bc8c-00a0c91405dd}"
"\??\HID#Vid_413c&Pid_3012#7&960fae0&0&0000#{378de44c-56ef-11d1-bc8c-00a0c91405dd}"
"\??\Root#RDP_KBD#0000#{884b96c3-56ef-11d1-bc8c-00a0c91405dd}"
"\??\ACPI#PNP0303#4&2f94427b&0#{884b96c3-56ef-11d1-bc8c-00a0c91405dd}"
"\??\Root#RDP_MOU#0000#{378de44c-56ef-11d1-bc8c-00a0c91405dd}"
"\??\ACPI#PNP0F13#4&2f94427b&0#{378de44c-56ef-11d1-bc8c-00a0c91405dd}"
So there are 2 entries for HID#Vid_0536&Pid_01c1; could that be causing the scanning not to work?
OK so it seems that I had to figure out a way to not depend on the ASCII 0x04 character being sent by the scanner...since my scanner does not send that character. After that, the barcode scanned event is fired and the popup with the barcode is shown. So thanks Nicholas for your help.
You could use the Raw Input API to distinguish between the keyboard and the scanner like I did recently. It doesn't matter how many keyboard or keyboard-like devices you have hooked up; you will see a WM_INPUT before the keystroke is mapped to a device-independent virtual key that you typically see in a KeyDown event.
Far easier is to do what others have recommended and configure the scanner to send sentinel characters before and after the barcode. (You usually do this by scanning special barcodes in the back of the scanner's user manual.) Then, your main form's KeyPreview event can watch those roll end and swallow the key events for any child control if it's in the middle of a barcode read. Or, if you wanted to be fancier, you could use a low-level keyboard hook with SetWindowsHookEx() to watch for those sentinels and swallow them there (advantage of this is you could still get the event even if your app didn't have focus).
I couldn't change the sentinel values on our barcode scanners among other things so I had to go the complicated route. Was definitely painful. Keep it simple if you can!
--
Your update, seven years later: If your use case is reading from a USB barcode scanner, Windows 10 has a nice, friendly API for this built-in in Windows.Devices.PointOfService.BarcodeScanner. It's a UWP/WinRT API, but you can use it from a regular desktop app as well; that's what I'm doing now. Here's some example code for it, straight from my app, to give you the gist:
{
using System;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using Windows.Devices.Enumeration;
using Windows.Devices.PointOfService;
using Windows.Storage.Streams;
using PosBarcodeScanner = Windows.Devices.PointOfService.BarcodeScanner;
public class BarcodeScanner : IBarcodeScanner, IDisposable
{
private ClaimedBarcodeScanner scanner;
public event EventHandler<BarcodeScannedEventArgs> BarcodeScanned;
~BarcodeScanner()
{
this.Dispose(false);
}
public bool Exists
{
get
{
return this.scanner != null;
}
}
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
public async Task StartAsync()
{
if (this.scanner == null)
{
var collection = await DeviceInformation.FindAllAsync(PosBarcodeScanner.GetDeviceSelector());
if (collection != null && collection.Count > 0)
{
var identity = collection.First().Id;
var device = await PosBarcodeScanner.FromIdAsync(identity);
if (device != null)
{
this.scanner = await device.ClaimScannerAsync();
if (this.scanner != null)
{
this.scanner.IsDecodeDataEnabled = true;
this.scanner.ReleaseDeviceRequested += WhenScannerReleaseDeviceRequested;
this.scanner.DataReceived += WhenScannerDataReceived;
await this.scanner.EnableAsync();
}
}
}
}
}
private void WhenScannerDataReceived(object sender, BarcodeScannerDataReceivedEventArgs args)
{
var data = args.Report.ScanDataLabel;
using (var reader = DataReader.FromBuffer(data))
{
var text = reader.ReadString(data.Length);
var bsea = new BarcodeScannedEventArgs(text);
this.BarcodeScanned?.Invoke(this, bsea);
}
}
private void WhenScannerReleaseDeviceRequested(object sender, ClaimedBarcodeScanner args)
{
args.RetainDevice();
}
private void Dispose(bool disposing)
{
if (disposing)
{
this.scanner = null;
}
}
}
}
Granted, you'll need a barcode scanner that supports the USB HID POS and isn't just a keyboard wedge. If your scanner is just a keyboard wedge, I recommend picking up something like a used Honeywell 4600G off eBay for like $25. Trust me, your sanity will be worth it.
What I did in a similar situation is distinguish between a scan and a user typing by looking at the speed of the input.
Lots of characters very close together then a pause is a scan. Anything else is keyboard input.
I don't know exactly your requirements, so maybe that won't do for you, but it's the best I've got :)
It depends on the way you are interacting with the device. Anyway it wont be a C# solution, it will be some other library. Are you reading data from a stream? If you are just taking keystrokes, there may be nothing you can do about it.
I know this is an old thread, found it by searching barcode scanning in WIN10.
Just a few notes in case someone needs it.
These scanners from Honeywell have several USB interfaces.
One is a keyboard + Hid Point of sales (composite device).
Also there are CDC-ACM (ComPort emulation) and Hid Point of sales (alone) + more.
By default the scanners expose a serial number, so the host can distinguish between many devices (I had once +20 connected). There is a command to disable the serial number though!
The newer models behave the same in this regard.
If you want to see it live, try my terminal program yat3 (free on my site).
It can open all the interfaces mentioned above and is tailored for such devices.
A word to use keyboard interfaces:
Only use them as a last resort. They are slow, less reliable when it comes to exotic characters. The only good use is if you want to enter data into existing applications. If you code anyway, then reading from ComPort/HidPos-Device is easier.
look at this: http://nate.dynalias.net/dev/keyboardredirector.rails (NOT AVAILABLE ANYMORE) works great!
Specify the keyboard and the keys you want to block, and it works like a charm!
Also take a look at this: http://www.oblita.com/interception.html
You can create a C# wrapper for it - it also works like a charm..
I think you might be able to distinguish multiple keyboards through DirectX API, or if that doesn't work, through raw input API.
I have successfully accomplished what you folks are looking for here. I have an application that receives all barcode character data from a Honeywell/Metrologic barcode scanner. No other application on the system receives the data from the scanner, and the keyboard continues to function normally.
My application uses a combination of raw input and the dreaded low-level keyboard hook system. Contrary to what is written here, I found that the wm_input message is received before the keyboard hook function is called. My code to process the wm_input message basically sets a boolean variable to specify whether or not the received character is from the scanner. The keyboard hook function, called immediately after the wm_input is processed, swallows the scanner’s pseudo-keyboard data, preventing the data from being received by other applications.
The keyboard hook function has to be placed in an dll since you want to intercept all system keyboard messages. Also, a memory mapped file has to be used for the wm_input processing code to communicate with the dll.

Sending a result with EndDialog Win32API in .NET

I am running some automation in a C# program (.Net 4.0). There is an issue with a modal dialog where I want to click the message away and continue testing. I have tried a few options (SendKey and using Win32 to send a click event with code modified from here: http://msdn.microsoft.com/en-us/magazine/gg309183.aspx. Neither of these have proved to be reliable enough to be considered effective.
My next approach will be to try calling the EndDialog() function from my C# program and simply sending the enumeration/return code to the message box.
EndDialog(HWND hDlg, INT_PTR nResult) is the call where hDlg is the handle to the message box being closed and nResult is the result of the dialog.
Where I am running into an issue is how to send the desired result. An example would be that the return code IDCANCEL has a value of 2. How exactly do I send this value? What variables or constants would I need to declare? I'm just looking for how to get the proper pointer declared to send the desired result to the function.
Further information on these result values can be found here http://msdn.microsoft.com/en-us/library/windows/desktop/ms645505(v=VS.85).aspx
just invoke PostMessage. Here is a sample in c/c++:
::PostMessage(hWnd, WM_COMMAND, MAKEWPARAM(IDCANCEL,BN_CLICKED), 0);

Is there a way to get what is clicked in any windows?

I managed to get the position (x,y) of mousse clicked event in windows with C# and Win32 API from the code at http://www.codeproject.com/KB/cs/globalhook.aspx (using Version 1 because I have a problem with version 2)
But I want to know what is clicked not the position on the screen.
For example, click the "Bold Button" in MS Word.
Is there a way to archive this?
Thanks in advance.
You can fetch a window handle from WindowFromPoint or ChildWindowFromPointEx, then query the window handle with GetWindowInfo etc. I don't think there's a trivial way to identify a button from Word, though.
Check out the AutomationElement.FromPoint() that's part of UI Automation - this suite of APIs is often used by automated test and accessibility apps that want to get information about the UI of other processes. For apps that support it (most of the UI in Windows and most MS apps), you can get information about the UI element, not just the outer window. This sample app prints out the name and type (eg 'button') of the item under the cursor.
It's not supported everywhere, may not work in many non-MS apps (though is supported by Firefox); but will at least get you better results than WindowFromPoint etc.
// Compile using: csc ItemAtPoint.cs /r:UIAutomationClient.dll /r:WindowsBase.dll
using System;
using System.Windows.Automation;
using System.Windows.Forms;
class ItemAtPoint
{
public static void Main()
{
Console.WriteLine("Place pointer over item and hit return...");
Console.ReadLine();
// Get the AutomationElement that represents the window handle...
System.Windows.Point point = new System.Windows.Point(Cursor.Position.X, Cursor.Position.Y);
AutomationElement el = AutomationElement.FromPoint(point);
// Print out the type of the item and its name
Console.WriteLine("item is a \"{0}\" with name \"{1}\"", el.Current.LocalizedControlType, el.Current.Name);
}
}

Balloon not showing up with NotifyIcon.ShowBalloonTip

I'm having trouble with something that I thought would be easy...
I can't get my NotifyIcon to show a balloon tip. The basic code is:
public void ShowSystrayBubble(string msg, int ms)
{
sysTrayIcon.Visible = true;
sysTrayIcon.ShowBalloonTip(20, "Title", "Text", ToolTipIcon.None);
}
Nothing happens when I execute this code. I read that the timeout arg may be in seconds or ms, can't tell, so I tried both and neither works.
I'm using WinXP, .NET 3.5.
I had foiled myself... This turned out to be an issue at the OS level. I had previously disabled all balloons via the registry a few weeks ago.
You can read the information here on how to disable balloon tips in WinXP:
http://support.microsoft.com/kb/307729
To enable them, just set the registry value to 1 instead and logon again/restart.
You should then log the messages for users who have disabled the balloons be able to go review them in case of need. If you can get permissions to read the registry, you could check the value and act accordingly (not to modify the value, but to log or to show the balloon).
Please see this it covers all combinations of mouse clicks with NotifyIcon as well as much more. The code is located in a template and is project setting driven so that you can implement NotifyIcon logic in all your projects with no coding effort at all.
More Here
http://code.msdn.microsoft.com/TheNotifyIconExample

Categories

Resources