Several times, a question came up how to synthesize keyboard input to a remote system given a text string. The remote system is typically but not necessarily a VM. That sounds like something which should be trivial, yet it is anything but.
The basic problem is that keyboards send scan codes which reflect the position of the key on the keyboard, not the character which a key press generates. The compounding problem is that there is a nearly infinite number of key to character mappings, also known as keyboard layouts.
And even for the most basic alphanumeric input, the keyboard layouts are crucial, because entering something as simple as ‘abc123’ requires a different sequence of keystrokes on US, German, and French keyboards.
If the sending system runs a Windows OS, the problem scope can be greatly reduced through several APIs: OemKeyScan, VkKeyScan, VkKeyScanEx, MapVirtualKey, and MapVirtualKeyEx. These all translate characters or virtual key codes into scan codes, either using the current keyboard layout or given a specific keyboard layout. Sounds great, right? Not so fast…
The intermediate problem is that there is no link between a physical keyboard and the keyboard layout used to translate the keystrokes. But for now let us assume that the layout is known and supported by Windows.
If the host OS isn’t Windows, then those APIs mentioned above are of course no good. But even on Windows, they aren’t always usable because they can’t handle dead key sequences, for example. In other words, the reverse translation does not work if typing a character requires more than one keystroke (other than modifier keys like Shift). It also doesn’t work if the keyboard layout cannot produce the given character.
For that eventuality, Microsoft offers sage advice: This function does not provide translations for characters that require CTRL+ALT or dead keys. Characters not translated by this function must be copied by simulating input using the ALT+ keypad mechanism.
As all readers of this blog know, DOS, OS/2, and Windows all support the Alt + keypad input method. This mechanism was originally implemented in the IBM PC BIOS so that users could easily input national and graphical characters not accessible through the keyboard. The Alt input method uses ASCII codes and it is thus independent of the keyboard layout used (though for non-ASCII characters, it does depend on the code page used).
By virtue of using the BIOS for keyboard input, DOS supports this method naturally. By the time OS/2 and Windows were conceived, the Alt input method was popular enough that it was supported by the native keyboard subsystems of the newer operating systems. Recent Windows versions also extended it to support Unicode.
So that sounds totally great, right? If ASCII/Unicode characters can be synthesized directly, there is no need to worry about keyboard layouts or anything like that, it’s just going to work.
Well… one problem is that the Alt input method is not supported by all operating systems. But an even bigger problem is that to a large extent Microsoft broke it in Windows Vista and all later Windows versions!
That sounds crazy, but unfortunately it’s not. On Windows XP, the Alt input method works consistently: Command prompt, renaming desktop icons, file open dialogs, Explorer and IE location bars, browser entry fields.
On Windows 7 and Windows 10, it still works in the command prompt and also for renaming desktop icons. But it does not work in file open dialogs, Explorer or IE, or the Cortana search bar. Using the Alt num pad input either produces nothing or only garbage characters.
The Command Prompt can perhaps be considered a separate case. But why does Alt+65 produce ‘A’ when renaming an icon on the desktop, but ‘♣’ when doing the same thing in an Explorer window? Only Microsoft can answer that, but it seems nowadays that Microsoft doesn’t understand Windows much better than anyone else.
At any rate, using Alt input is unfortunately not a viable method of synthesizing keyboard input to newer versions of Windows, even though it used to work well in the pre-Vista era.