Mapping VirtualKey to char in UWP app, independent of layout - c#

I'm writing a VNC client for HoloLens using C# and I'm having a tough time figuring out how to handle keyboard input. KeyUp/KeyDown give me a Windows.System.VirtualKey object, but there doesn't appear to be an API to map these VirtualKeys (along with modifiers, e.g. shift) to the characters they represent on a given layout. E.g. VirtualKey.Shift + VirtualKey.F == 'F' versus 'f' when it's simply VirtualKey.F. Or Shift + 5 to give % on a US keyboard.
In win32 apps you'd use MapVirtualKey to handle the keyboard layout for you -- how does this get handled in UWP?

It is not possible to get the translated character in KeyUp/KeyDown events. But it is possible when using CoreWindow.CharacterReceived event to get the translated character.
You can register the event by the following codes:
Window.Current.CoreWindow.CharacterReceived += CoreWindow_CharacterReceived;
And you will get a KeyCode of the translated input character(e.g. for shift+5 it gets 37, while for 5 it gets 53) through the CharacterReceivedEventArgs:
private void CoreWindow_CharacterReceived(CoreWindow sender, CharacterReceivedEventArgs args)
{
uint keyCode=args.KeyCode;
}

Related

UWP - InjectedInputKeyboardInfo how to send non-English keystrokes

I have a UWP app in Visual Studio 2017. I'm trying to make a multi-language on-screen keyboard.
Currently the English keystrokes are working fine, however any letter from other languages throws System.ArgumentException: 'Value does not fall within the expected range.'
Here is the code that sends the keystrokes:
public void SendKey(ushort keyCode)
{
List<InjectedInputKeyboardInfo> inputs = new List<InjectedInputKeyboardInfo>();
InjectedInputKeyboardInfo myinput = new InjectedInputKeyboardInfo();
myinput.VirtualKey = keyCode;
inputs.Add(myinput);
var injector = InputInjector.TryCreate();
WebViewDemo.Focus(FocusState.Keyboard);
injector.InjectKeyboardInput(inputs); // exception throws here
}
How would I inject letters from other languages?
The trick is that InputInjector isn't injecting text (characters), but actually it is injecting key strokes on the keyboard. That means the input will be not what the VirtualKey value contains as the name value, but what the given key represents on the keyboard the user is currently using.
For example in Czech language we use the top numeric row to write characters like "ě", "š" and so on. So when you press number 3 on the keyboard, Czech keyboard writes "š".
If I use your code with Number3 value:
SendKey( (ushort)VirtualKey.Number3 );
I get "š" as the output. The same thing holds for Japanese for example where VirtualKey.A will actually map to ”あ”.
That makes InputInjector for keyboard a bit inconvenient to use, because you cannot predict which language the user is actually using a which keyboard key mapping is taking place, but after reflection it makes sense it is implemented this way, because it is not injection of text, but simulation of actual keyboard keystrokes.
The answer given by Martin Zikmund is not true. You can send any unicode character.
InputInjector inputInjector = InputInjector.TryCreate();
var key = new InjectedInputKeyboardInfo();
key.ScanCode = (ushort)'Ä';
key.KeyOptions = InjectedInputKeyOptions.Unicode;
inputInjector.InjectKeyboardInput(new[] { key });
The InjectKeyboardInput method is using this function behind the scenes. Please note the that you require the inputInjectionBrokered capability in your app.

Translating Windows.forms.Keys to real local keyboard value

I use the namespace Windows.Forms.Keys
I would like to be able to catch and use some special like characters like é,è,à,ç, but when the program fire the event KeyDown, the KeyEventArg just return me the value "D1" to "D9".
What could I do to get the real char associated to these keys ?
Short answer: use KeyPress instead of KeyDown.
KeyDown is really designed to work with the physical layout of the keyboard (well, the logical layout of the physica... forget it :D). This is very different from the character that given physical key represents.
On the other hand KeyPress is all about characters being input from the keyboard, rather than keys being pressed, really. Note how KeyPress supports features like AltGr + someKey and char repetition etc.
If you really need to use KeyDown/KeyUp, you'll have to emulate the way windows keyboard system works to determine the char to output (for example, if you're making a keyboard mapping screen for a game or something like that). You can use the ToAscii WinAPI method (https://msdn.microsoft.com/en-us/library/ms646316.aspx).
Apart from that, you still have to understand the meaning of the key combinations - for example, on my keyboard, if I press 1, I get +. If I press Shift+1, I get 1. If I press AltGr + 1, I get !. Which of those do you care about? Maybe Shift + 1 should be interpreted as 1 (what KeyPress does). Maybe it should be interpreted as Shift + 1 (the easiest, you already have that). And maybe it should be interpreted as Shift + +, the way it's usually used for hotkey bindings or keyboard mappings in games.
It should be pretty obvious by now that this is actually far from trivial. You need some mechanism to interpret the "raw" input data - and different interpretations make different sense for different initial conditions. You're basically asking for a mixed approach between the two obvious options - you're mixing virtual keys and "real" characters.

Odd enum values in Windows.Forms.MouseButtons

I found this gem (IMO) in System.Windows.Forms namespace. I'm struggling to figure out why is it set like this.
[Flags]
public enum MouseButtons
{
None = 0,
Left = 1048576,
Right = 2097152,
Middle = 4194304,
XButton1 = 8388608,
XButton2 = 16777216,
}
Can somebody explain why it uses these values (power of 2^20 to 2^24) instead of this:
public enum MouseButtons
{
None = 0,
Left = 1, // 2^0
Right = 2, // 2^1
Middle = 4, // 2^2
XButton1 = 8, // 2^3
XButton2 = 16, // 2^4
}
The first value is 100000000000000000000 in binary, which leaves space for another 20 bits! Why do we need such space and why is it preserved like this?
Enum values used in Winforms do tend to match corresponding bits in the winapi but that's not the case at all for mouse buttons. Explaining this one requires a pretty wild guess.
I do have one, the way you retrieve the state of the mouse buttons without relying on a Windows message is very strange. You call GetAsyncKeyState(), passing VK_LBUTTON through VK_XBUTTON2. Fake virtual keys that actually represent mouse keys and not keyboard keys. This happened way too long ago for me to guess why they did it this way instead of providing a proper GetMouseButtonState() winapi function.
The Keys enumeration has those values as well, like Keys.LButton etcetera. Something else that's special about Keys is that it can also encode the state of a modifier key. There are for example Keys.Control and Keys.ControlKey. And Keys.Shift vs Keys.ShiftKey, etcetera. The first one indicates the state of the key, the second one indicates the actual key. Which permits friendly code like keydata == (Keys.Control | Keys.F) to check if Ctrl+F was pressed.
The significance of these MouseButtons enum values is then that they fit in a Keys enum value to indicate the state of the mouse buttons. Leaving 20 bits available for the bits that encode the key.
Sounds good, doesn't it? The only hiccup is that it is never combined that way within the Winforms object model. But could be in your own code to define a shortcut that also uses the mouse state.
My guess is that it has to do with how the underlying Windows API is passing mouse information to .NET.
Windows packages up which mouse buttons are clicked as well as pointer position in a block of information (think of the old MOUSE_EVENT structure). The enums in .NET are setup the way they are to be efficient, so they probably line up nicely with how the underlying Windows message.
So, instead of getting the lower-level message and having to convert it into a new set of values, .NET just targets the bits in the lower-level message that it is interested in - no conversion, no math, just efficiency.

C# - Converting KeyPress to scancode/scancode to key name

I have a WinForm application where I need to capture a KeyPress and fetch the scancode for it. Along with that I need to convert existing scancodes int key names (by converting to virtual keys beforehand perhaps?) Is there any way to accomplish this?
The first part is possible, but tricky, because multiple Virtual Key (VK) codes will map to the same scancode (depending on the keyboard shift/ctrl/alt state).
I'm not sure what you mean by "key name," but if you're referring to the physical keyboard layout then, for your next step, you will need to make some assumptions about the key's location based on standard physical keyboard layouts (101-key, 102-key etc).
See my answer to this question for some sample code and a more detailed description.
If you still need it, you can use Reflection for private members access. I know it's not good idea and interfaces can change in next versions, but it works for .Net Framework 4.6
private void OnKeyDown(object sender, KeyEventArgs e)
{
MSG l_Msg;
ushort l_Scancode;
PresentationSource source = e.InputSource;
var l_MSGField = source.GetType().GetField("_lastKeyboardMessage", BindingFlags.NonPublic | BindingFlags.Instance);
l_Msg = (MSG)l_MSGField.GetValue(source);
l_Scancode = (ushort)(l_Msg.lParam.ToInt32() >> 16);
//Use scancode
}

Keyboard Type (Qwerty or Dvorak) detection

I was asked this question by a friend, and it piqued my curiosity, and I've been unable to find a solution to it yet, so I'm hoping someone will know.
Is there any way to programatically detect what type of keyboard a user is using? My understanding of the keyboard is that the signal sent to the computer for 'A' on a DVORAK keyboard is the same as the signal sent to the computer for an 'A' in a QUERTY keyboard. However, I've read about ways to switch to/from dvorak, that highlight registry tweaking, but I'm hoping there is a machine setting or some other thing that I can query.
Any ideas?
You can do this by calling the GetKeyboardLayoutName() Win32 API method.
Dvorak keyboards have specific names. For example, the U.S. Dvorak layout has a name of 00010409.
Code snippet:
public class Program
{
const int KL_NAMELENGTH = 9;
[DllImport("user32.dll")]
private static extern long GetKeyboardLayoutName(
System.Text.StringBuilder pwszKLID);
static void Main(string[] args)
{
StringBuilder name = new StringBuilder(KL_NAMELENGTH);
GetKeyboardLayoutName(name);
Console.WriteLine(name);
}
}
that probably depends on the OS. I'm sure that there is an operatingsystem setting somewhere that registers the nationality of the keyboard. (Dvorak is considered a nationality because French keyboards are different from US keyboards are different from ...)
Also, just a side note: 'A' was a bad example, as 'A' happens to be the same key in dvorak and qwerty... B-)
You might be able to do it via DirectInput, or whatever the current DirectX-equivalent is. I type on a Dvorak keyboard, and about 50% of the games I buy detect my keyboard and reconfigure the default keymappings to support it (using ,aoe instead of wasd, for instance)
And yes, as Brian mentioned, 'A' is the same on both keyboards.
Why would it matter? Depending on some special implementation of a keyboard is no good idea at all. We use barcode scanners all over the place that emulate keyboard inputs. What would your program do with these devices? :)
PS: the mentioned registry entry arranges the keys of a regular keyboard into dvorak layout.

Categories