Fixed, keyboard layout-agnostic virtual key with Win32's WM_KEYDOWN

Rodolphe 1 Reputation point
2021-08-02T09:51:16.523+00:00

I'm looking for a way to reproduce JavaScript's KeyboardEvent.code's behavior with Win32's WM_KEYDOWN:

This ignores the users keyboard layout, so that if the user presses the key at the "Y" position in a QWERTY keyboard layout (near the middle of the row above the home row), this will always return "KeyY", even if the user has a QWERTZ keyboard (which would mean the user expects a "Z" and all the other properties would indicate a "Z") or a Dvorak keyboard layout (where the user would expect an "F").

So far, I've come pretty close to my goal by mapping the scan-code using MapVirtualKeyEx() with the default keyboard layout:

   [UnmanagedCallersOnly(CallConvs = new[] { typeof(CallConvStdcall) })]  
   static unsafe nint WindowProc(HWND hWnd, WindowMessage msg, WPARAM wparam, LPARAM lparam)  
   {  
      if (msg is WindowMessage.WM_KEYDOWN)  
      {  
         var scanCode = (uint) (((nint) lparam) >> 16) & 0xFF;  
         var keyboardLayout = User32.LoadKeyboardLayout("00000409", 0); // "00000409" is supposed to be the default layout.  
         var inputDebug = ((VK) (nuint) wparam).ToString();  
         var mappingDebug = ((Key) User32.MapVirtualKeyEx(scanCode, MapTypes.MAPVK_VSC_TO_VK_EX, keyboardLayout)).ToString();  
         //                    `-> where "Key" is my own "VK" enum, for the sake of naming convensions.  
     
         Console.WriteLine("Input:  " + inputDebug);  
         Console.WriteLine("Mapped: " + mappingDebug);  
      }  
      else if (msg is WindowMessage.WM_CHAR)  
      {  
         Console.WriteLine("Char:   " + (char) (nuint) wparam);  
      }  
   }  

Which gives the following kind of log:

   Input:  VK_UP  
   Mapped: ArrowUp  
     
   Input:  VK_CONTROL  
   Mapped: ControlLeft  
     
   Input:  VK_OEM_7  
   Mapped: Backquote  
   Char:   ²  
     
   Input:  A  
   Mapped: KeyQ  
   Char:   a  

However, LoadKeyboardLayout(), which I use to get an HKL to the default layout, has an annoying propension to update the language input setting of the the entire system, which is defo not what I want...

119856-image.png

And, I'm blocked there...

Is there a way to get an HKL representing the agnostic keyboard layout without actually loading it and changing the system's settings?

Or am I even looking in the right direction here?

Windows development | Windows API - Win32
Developer technologies | C#
Developer technologies | C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
{count} votes

Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.