question

youki avatar image
0 Votes"
youki asked youki commented

Virtual key codes not working as expected

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?



dotnet-csharp
· 1
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

@youki
Just a reminder, MSDN's German forum is still in use. If your test results indicate that the problem is related to the German keyboard, you may be able to get some help there.

0 Votes 0 ·
Castorix31 avatar image
1 Vote"
Castorix31 answered youki commented

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);
     }
 }


· 2
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Oh,
My wVK is wrong.

0 Votes 0 ·

Hmm,
"If specified, wScan identifies the key and wVk is ignored". :)

0 Votes 0 ·
youki avatar image
0 Votes"
youki answered youki commented

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://docs.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

· 2
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

I just did a test with a Low Level Keyboard Hook and I get same results as in MSDN
(test on LLKHF_EXTENDED flag)

I added a Beep in the Hook procedure to test the keys like PrintScreen , '/', etc...:


         KBDLLHOOKSTRUCT pKBDLLHOOKSTRUCT = new KBDLLHOOKSTRUCT();
         pKBDLLHOOKSTRUCT = (KBDLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, pKBDLLHOOKSTRUCT.GetType());

         if ((pKBDLLHOOKSTRUCT.flags & LLKHF_EXTENDED) == 1)
         {
             Beep(8000, 10);
         }





1 Vote 1 ·

Hi,
This was a great idea but it works not really.
It tells me for i.e. that the right shift button is extended but it only works without the extended key flag with SendInput for whatever reasons.

Hmm, I think i would have to test it anyway but an explanation would have been great.

Thank you.

0 Votes 0 ·