Virtual key codes not working as expected

youki 1,021 Reputation points
2021-01-11T21:20:22.187+00:00

Hello,
I'm programming an application where i use virtual scan codes that i get by virtual key codes (MapVirtualKey) for automating shortcuts.

I've discovered that several key codes doesn't work as expected.

For example:

Tested key combinations with LWIN didn't work but then they work with RWIN
Tested key combinations with VK_CONTROL but then they work with VK_LCONTROL or vice versa?!

Unfortunately i didn't write everything down, what i should have done.
(I also tested it with Extended-Key Flag and without)

  1. I'm using a german keyboard. Is this a normal behaviour?
  2. Will it work with keyboards for different languages automatically?
Developer technologies | C#
{count} votes

2 answers

Sort by: Most helpful
  1. Castorix31 90,686 Reputation points
    2021-01-12T01:32:02.913+00:00

    MapVirtualKey works fine for me with any key
    For example, if I simulate (Ctrl + Win + Shift) + B to reset graphics driver with SendInput, it works
    (left keys, test on french keyboard) =>

    SendKey((short)Keys.LControlKey, 20, false, true, false);
    SendKey((short)Keys.LShiftKey, 20, false, true, false);
    SendKey((short)Keys.LWin, 20, true, true, false);
    
    SendKey((short)Keys.B, 20, false, true, true);
    
    SendKey((short)Keys.LControlKey, 20, false, false, true);
    SendKey((short)Keys.LShiftKey, 20, false, false, true);
    SendKey((short)Keys.LWin, 20, true, false, true); 
    

    Declarations :

    [DllImport("User32.dll", SetLastError = true, CharSet = CharSet.Auto)]
    public static extern uint MapVirtualKey(uint uCode, uint uMapType);
    
    public const int INPUT_KEYBOARD = 1;
    
    public const int KEYEVENTF_EXTENDEDKEY = 0x0001;
    public const int KEYEVENTF_KEYUP = 0x0002;
    public const int KEYEVENTF_UNICODE = 0x0004;
    public const int KEYEVENTF_SCANCODE = 0x0008;
    
    [StructLayout(LayoutKind.Sequential)]
    public struct MOUSEINPUT
    {
        public int dx;
        public int dy;
        public int mouseData;
        public int dwFlags;
        public int time;
        public IntPtr dwExtraInfo;
    }
    
    [StructLayout(LayoutKind.Sequential)]
    public struct KEYBDINPUT
    {
        public short wVk;
        public short wScan;
        public int dwFlags;
        public int time;
        public IntPtr dwExtraInfo;
    }
    
    [StructLayout(LayoutKind.Sequential)]
    public struct HARDWAREINPUT
    {
        public int uMsg;
        public short wParamL;
        public short wParamH;
    }
    
    [StructLayout(LayoutKind.Sequential)]
    public struct INPUT
    {
        public int type;
        public INPUTUNION inputUnion;
    }
    
    [StructLayout(LayoutKind.Explicit)]
    public struct INPUTUNION
    {
        [FieldOffset(0)]
        public MOUSEINPUT mi;
        [FieldOffset(0)]
        public KEYBDINPUT ki;
        [FieldOffset(0)]
        public HARDWAREINPUT hi;
    }
    
    [DllImport("User32.dll", SetLastError = true)]
    public static extern int SendInput(int nInputs, [MarshalAs(UnmanagedType.LPArray)] INPUT[] pInput, int cbSize);
    
    void SendKey(short wVk, int nSleep, bool bExtendedkey, bool bDown, bool bUp)
    {
        INPUT[] input = new INPUT[1];
        if (bDown)
        {
            input[0].inputUnion.ki.wVk = wVk;
            input[0].inputUnion.ki.wScan = (short)MapVirtualKey((uint)wVk, 0);
            input[0].inputUnion.ki.dwFlags = KEYEVENTF_SCANCODE;
            if (bExtendedkey)
                input[0].inputUnion.ki.dwFlags |= KEYEVENTF_EXTENDEDKEY;
            input[0].inputUnion.ki.time = 0;
            input[0].type = INPUT_KEYBOARD;
            SendInput(1, input, Marshal.SizeOf(input[0]));
            System.Threading.Thread.Sleep(nSleep);
        }
    
        if (bUp)
        {
            input[0].inputUnion.ki.wVk = wVk;
            input[0].inputUnion.ki.wScan = (short)MapVirtualKey((uint)wVk, 0);
            input[0].inputUnion.ki.dwFlags = KEYEVENTF_SCANCODE | KEYEVENTF_KEYUP;
            if (bExtendedkey)
                input[0].inputUnion.ki.dwFlags |= KEYEVENTF_EXTENDEDKEY;
            input[0].inputUnion.ki.time = 0;
            input[0].type = INPUT_KEYBOARD;
            SendInput(1, input, Marshal.SizeOf(input[0]));
            System.Threading.Thread.Sleep(nSleep);
        }
    }
    
    1 person found this answer helpful.

  2. youki 1,021 Reputation points
    2021-01-16T23:10:29.473+00:00

    Hi Castorix,
    I'm testing right now a little bit and i've discovered the following: VK_RWIN (extended), VK_SNAPSHOT (Print button, not extended), VK_NUMLOCK/ VK_SCROLL (not extended).

    It's weird because MS says something else (see below). I would like to know what's the reason for it?!
    Do you see the same behaviour?

    https://learn.microsoft.com/en-us/windows/win32/inputdev/about-keyboard-input

    Extended-Key Flag
    The extended-key flag indicates whether the keystroke message originated from one of the additional keys on the enhanced keyboard. The extended keys consist of the ALT and CTRL keys on the right-hand side of the keyboard; the INS, DEL, HOME, END, PAGE UP, PAGE DOWN, and arrow keys in the clusters to the left of the numeric keypad; the NUM LOCK key; the BREAK (CTRL+PAUSE) key; the PRINT SCRN key; and the divide (/) and ENTER keys in the numeric keypad. The extended-key flag is set if the key is an extended key.

    Example (1 of many):

     public static void ActivateLockKeys(LockKeys selection)  
            {  
                var inputs = new Input[2];  
      
                inputs[0].type = (int)InputType.Keyboard;  
                inputs[0].u.ki.wVk = 0;  
                inputs[0].u.ki.wScan = (selection == LockKeys.NUMLOCK) ? GetScanCode(VirtualKeyCode.VK_NUMLOCK) : GetScanCode(VirtualKeyCode.VK_SCROLL);  
                inputs[0].u.ki.dwFlags = (ushort)(KeyEventF.Scancode);  
      
                inputs[1].type = (int)InputType.Keyboard;  
                inputs[1].u.ki.wVk = 0;  
                inputs[1].u.ki.wScan = (selection == LockKeys.NUMLOCK) ? GetScanCode(VirtualKeyCode.VK_NUMLOCK) : GetScanCode(VirtualKeyCode.VK_SCROLL);  
                inputs[1].u.ki.dwFlags = (ushort)(KeyEventF.KeyUp | KeyEventF.Scancode);  
      
                _ = SendInput((uint)inputs.Length, inputs, Marshal.SizeOf(typeof(Input)));  
            }  
    
    
    private static ushort GetScanCode(VirtualKeyCode virtualCode)  
    {  
                return (ushort)NativeMethods.MapVirtualKey((uint)virtualCode, (uint)MapVirtualKeyMapTypes.MAPVK_VK_TO_VSC);  
     }  
    

    PS: Oops, i meant RWIN not RMENU above!

    Regards


Your answer

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