Click here to Skip to main content
15,886,362 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Dear all,

Thank you for taking the time to read my question.

I hate asking questions without any context or explanation, but I do not wish to scare users and prospect answers away, so please find the TL;DR question below and more detail underneath.

I need to inject the exact keys pressed on one computer on another computer (regardless of the difference in region and keyboard layout). For example the # character (on EN-UK) ends up as \ (on EN-US). How can I project the exact same intended character?


=========================


[Additional detail below]

Basically I had once created a remote assistance tool (RAT) that used to work averagely well. Recently I checked it out again and it still seems to be working fine, so I thought about improving it. One of the obvious problems is (as described above) that difference keyboard layouts and region settings seem to interfere with the actual keys being injected on the remote computer.

In my implementation I had used the SendKeys method that was able to achieve this (even if pretty badly). However now I have developed a sample tool to help me better analyse the actual Scan Codes and Virtual Key Codes.

To test this I used the following procedure:

1. Open up a Notepad instance
2. Change from English-UK to English-US
3. Open up another instance of Notepad (with the new keyboard layout applied)

On the EN-UK layout I pressed the # key which C# detects as

Character: Oem7
Scan Code: 43
Virtual Key Code: 222

On the EN-US layout, the same key (now interpreted as \) is detected as:

Character: Oem5
Scan Code: 43
Virtual Key Code: 220

So basically the character and Virtual Key codes change but the Scan code remains the same. So I thought I could rely on this. However (on the same sample application I built), I tested injecting the Scan Code 43 on the EN-UK layout which as expected brought the # character, while on the EN-US layout it brought the \ character.

Using the 222 Virtual Key Code brought the # character on the EN-UK but it showed the ' character on the EN-US layout. So I wonder which approach I can take to ensure that the # character shows up as # on the remote computer regardless of region and so on.

(P.S. I have noted that the sample application which monitors they key presses detects an LControlKey Released as soon as I click or focus on the second instance of Notepad (with the EN-US culture) with Scan Code 541 and Virtual Key Code 162. Should I press the Left Control Key myself on the second instance of Notepad, it is detected as an LControlKey with Scan Code 29 (instead of 541) and Virtual Key Code 162). What's going on here?

Thank you so much for your time, and sorry for asking such a lengthy question.
Posted
Updated 29-Jan-13 11:24am
v3

1 solution

If you need to send raw keyboard input, you need to do it before it was interpreted as character. That is, the only thing you can use is the Windows API function SendInput:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms646310%28v=vs.85%29.aspx[^].

With .NET, you can use it through P/Invoke, as this work is already done for you: http://www.pinvoke.net/default.aspx/user32.sendinput[^].

You should remember that using P/Invoke, at least for this API, is platform-specific, so by using it you will totally kill platform compatibility of your code. For example, under Mono, you can execute your BCL-based code, and also Forms applications (and a lot more) on Linux, Mac OS X and other platforms without recompilation, but using this Windows-specific API will break such compatibility.

Besides, I just want to warn you: using such things for "regular" UI development and is not really required, and would be a big abuse. This functionality is used for some special effects; one such problem is playing keyboard (and mouse) macros.

—SA
 
Share this answer
 
Comments
Trapper-Hell 29-Jan-13 17:47pm    
Dear Sergey,

That's actually what I'm using at the moment. I had used the SendKeys method in C# earlier, however this sample app I am using to monitor the keys being pressed and simulate them again uses the SendInput entry point in the user32.dll and I have tried passing in both the captured Scan Codes and Virtual Key Codes / the Scan Code only / the Virtual Key Code only, but the resultant character being displayed is not the original character. The demonstration I have mentioned above of the # and the / characters were simulated using the SendInput method.

Thank you for the note with regards to P/Invoke and APIs being platform-specific, but I have no problems running this on Windows only. Ideally I could do without having to use P/Invokes and stuff, but if that's the way to do it, so be it. I just want the pressed characters to appear exactly as pressed on the remote computer.

Thanks again.
Sergey Alexandrovich Kryukov 29-Jan-13 17:54pm    
You should understand what you really want. With SendInput, there are no characters at all. I don't know what do you need to get as resultant characters, but you cannot deny that everything works out quite logically. You can think of the code using SendInput as of alternative software: it "presses" raw keyboard keys. What is exactly the problem then?
Of course you won't have problems on Windows only. After all, I agree to use such stuff myself (for those very keyboard macro), because in WPF there is no a way.
—SA
Trapper-Hell 29-Jan-13 18:01pm    
Maybe I did not explain myself well enough or maybe SendInput is not the way to go.

Imagine this, you are using this application I made to remote-control another computer. Now you are pressing keys on your computer (through this application) so that these are then sent to the remote computer (and another application running remotely) which is able to simulate these key presses.

Therefore if I was to press "This is a test", I would see "This is a test" on the remote computer. This works fine. The problem is with certain keys that vary according to keyboard layouts / regions, such that if I were to type "C# is great!", it would appear as "C\ is great!" on the remote computer. This is not a chat application, so I do not want to send strings, I want to send commands so that these keys are then simulated on the remote computer to emulate the actual keys / characters.
Sergey Alexandrovich Kryukov 29-Jan-13 18:16pm    
I understand it perfectly. This is not a chat, but this is a kind of remote terminal. You can work with characters, and use SendKeys class, or something, for this purpose; and then you have a remote "character terminal".

Alternatively, you can use SendKey, then you have a "remote keyboard". Choose what you want. If you do everything correctly, the remote computer should work as you have your keyboard attached to it directly. If not, you are missing something. You just to do everything in a fully transparent and consistent way.

So, there is no such thing as "SendInput is not the way to go" or it is, it all depends on your (consistent) approach. Let's continue with SendKey. At the same time, you should not expect that the result of input on remote computer is identical to the local. This is because you may have installed different keyboard layouts, and alsо — attention here! — because, by the moment of start of your communication keyboard states are different. Let's, say, on one computer you have CAPS ON (who needs this key, by the way?), and OFF on another. The same press on CapsLock will switch the mode in opposite ways. Also, remember that part of state is system-wide, but, say, switch of input language is per application. Do you see the point?

So, you can either use SendInput as a pure "remove keyboard" and work with pure "hardware" scan codes, or you should also pass keyboard state. This is a couple of other raw Windows API...

Hope I made it more clear...
—SA
Trapper-Hell 29-Jan-13 18:28pm    
I'm glad you understand my point, and yes you mention some valid points about the keyboard layouts and keyboard states. Let us assume that I am able to set both keyboard states as identical (ensuring that Caps Lock is off on both computers and Num Lock is on on both etc etc) and that these won't change while the process is running, how can I go about ensuring that the output on the remote computer is the same as the character input on the local computer? (Even if the keyboard layouts are different). I can set the remote keyboard layout the same as the local keyboard layout, but I was hoping for a less dirty approach.

Another idea that during startup, the server simulates some key codes (and determines the actual output character) and then sends these results to the client so that it may be able to perform some mapping of these key codes to its key codes that can match the original output characters). So, for example if the server was able to generate # with Virtual Key Code 222, the Client also generates a number of Virtual Key Codes and checks which one of those was able to produce #, so that it may then interpret the 222 Virtual Key Code as necessary for it to produce #. (I hope I have been able to explain myself well - although this feels like overkill).

[P.S. I am going to sleep, so I will see your response first thing in the morning, and reply accordingly]

Thanks and good night.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900