Getting all you can out of a keyboard layout, Part #1

by Michael S. Kaplan, published on 2006/03/23 04:01 -05:00, original URI: http://blogs.msdn.com/b/michkap/archive/2006/03/23/558674.aspx


(Be sure to grab the KeysEx enumeration from Part #1 of this series; I'll tell you where it needs to go!)

We will start in the most elemental place, with the Scan Codes.

These are the numbers that the keyboard hardware sends to the computer, the ones that are mapped to Virtual Keys, and sometimes even to characters.

We will need the following functions from the Win32 API to start off.

Basically, here is our algorithm:

Nice and simple, right? Ok, here goes:

using System;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace KeyboardLayouts {
    class Class1 {

        //  You'll want to insert that enumeration here!

        internal const uint KLF_NOTELLSHELL  = 0x00000080;

        [DllImport("user32.dll", CharSet=CharSet.Unicode, EntryPoint="MapVirtualKeyExW", ExactSpelling=true)]
        internal static extern uint MapVirtualKeyEx(
            uint uCode,
            uint uMapType,
            IntPtr dwhkl);

        [DllImport("user32.dll", CharSet=CharSet.Unicode, EntryPoint="LoadKeyboardLayoutW", ExactSpelling=true)]
        internal static extern IntPtr LoadKeyboardLayout(string pwszKLID, uint Flags);

        [DllImport("user32.dll", ExactSpelling=true)]
        internal static extern bool UnloadKeyboardLayout(IntPtr hkl);

        [DllImport("user32.dll", CharSet=CharSet.Unicode, ExactSpelling=true)]
        internal static extern int ToUnicodeEx(
            uint wVirtKey,
            uint wScanCode,
            KeysEx[] lpKeyState,
            StringBuilder pwszBuff,
            int cchBuff,
            uint wFlags,
            IntPtr dwhkl);

        [STAThread]
        static void Main(string[] args) {
            IntPtr hkl = LoadKeyboardLayout(args[0], KLF_NOTELLSHELL);
            if(hkl == IntPtr.Zero) {
                Console.WriteLine("Sorry, that keyboard does not seem to be valid.");
            }
            else {
                KeysEx[] lpKeyState = new KeysEx[256];

                for(uint sc = 0x01; sc <= 0x7f; sc++) {
                    uint vk = MapVirtualKeyEx(sc, 1, hkl);
                    if(vk != 0) {
                        StringBuilder sb = new StringBuilder(10);
                        int rc = ToUnicodeEx(vk, sc, lpKeyState, sb, sb.Capacity, 0, hkl);
                        if(rc == 1) {
                            Console.WriteLine("{0:x2}\t{1:x4}\t{2:x2}\t{3}\t{4}",
                                sc, ((ushort)sb.ToString()[0]), vk, ((KeysEx)vk).ToString(), ((Keys)vk).ToString());
                        }
                    }
                }
                UnloadKeyboardLayout(hkl);
            }
        }
    }
}

And here is what it printed out for me:

C:\Sample\KeyboardLayouts\bin\Debug>KeyboardLayouts.exe 0000409
01      001b    1b      VK_ESCAPE       Escape
02      0031    31      VK_1    D1
03      0032    32      VK_2    D2
04      0033    33      VK_3    D3
05      0034    34      VK_4    D4
06      0035    35      VK_5    D5
07      0036    36      VK_6    D6
08      0037    37      VK_7    D7
09      0038    38      VK_8    D8
0a      0039    39      VK_9    D9
0b      0030    30      VK_0    D0
0c      002d    bd      VK_OEM_MINUS    OemMinus
0d      003d    bb      VK_OEM_PLUS     Oemplus
0e      0008    08      VK_BACK Back
0f      0009    09      VK_TAB  Tab
10      0071    51      VK_Q    Q
11      0077    57      VK_W    W
12      0065    45      VK_E    E
13      0072    52      VK_R    R
14      0074    54      VK_T    T
15      0079    59      VK_Y    Y
16      0075    55      VK_U    U
17      0069    49      VK_I    I
18      006f    4f      VK_O    O
19      0070    50      VK_P    P
1a      005b    db      VK_OEM_4        OemOpenBrackets
1b      005d    dd      VK_OEM_6        OemCloseBrackets
1c      000d    0d      VK_RETURN       Enter
1e      0061    41      VK_A    A
1f      0073    53      VK_S    S
20      0064    44      VK_D    D
21      0066    46      VK_F    F
22      0067    47      VK_G    G
23      0068    48      VK_H    H
24      006a    4a      VK_J    J
25      006b    4b      VK_K    K
26      006c    4c      VK_L    L
27      003b    ba      VK_OEM_1        OemSemicolon
28      0027    de      VK_OEM_7        OemQuotes
29      0060    c0      VK_OEM_3        Oemtilde
2b      005c    dc      VK_OEM_5        OemPipe
2c      007a    5a      VK_Z    Z
2d      0078    58      VK_X    X
2e      0063    43      VK_C    C
2f      0076    56      VK_V    V
30      0062    42      VK_B    B
31      006e    4e      VK_N    N
32      006d    4d      VK_M    M
33      002c    bc      VK_OEM_COMMA    Oemcomma
34      002e    be      VK_OEM_PERIOD   OemPeriod
35      002f    bf      VK_OEM_2        OemQuestion
37      002a    6a      VK_MULTIPLY     Multiply
39      0020    20      VK_SPACE        Space
4a      002d    6d      VK_SUBTRACT     Subtract
4e      002b    6b      VK_ADD  Add
56      005c    e2      VK_OEM_102      OemBackslash
7c      0009    09      VK_TAB  Tab

Ok, there is obviously a lot missing here, for example:

But that is what future posts are for, right? :-)

Stay tuned!

 

This post brought to you by "1" (U+0031, DIGIT ONE)
A Unicode character that is in the very small family of those whose VK value is the same as it's code point!


# geoff.appleby on 23 Mar 2006 4:40 AM:

>A Unicode character that is in the very small family
>of those whose VK value is the same as it's code point!

And what are the rest? :)

# Michael S. Kaplan on 23 Mar 2006 4:46 AM:

Actually, they are pretty much all in the output table there, other than the fact that its lowercase letters instead of uppercase ones (until I add shift states to the mix, in a future post!).

Please consider a donation to keep this archive running, maintained and free of advertising.
Donate €20 or more to receive an offline copy of the whole archive including all images.

referenced by

2008/02/11 Who assigns the VK_OEM_* values in keyboards?

2006/04/22 Getting all you can out of a keyboard layout, Part #10a

2006/04/13 Getting all you can out of a keyboard layout, Part #9b

2006/04/12 Getting all you can out of a keyboard layout, Part #9a

2006/04/10 Getting all you can out of a keyboard layout, Part #8

2006/04/06 Getting all you can out of a keyboard layout, Part #7

2006/03/31 Getting all you can out of a keyboard layout, Part #6

2006/03/28 Getting all you can out of a keyboard layout, Part #5

2006/03/27 Getting all you can out of a keyboard layout, Part #4

2006/03/24 Getting all you can out of a keyboard layout, Part #3

2006/03/24 Getting all you can out of a keyboard layout, Part #2

go to newer or older post, or back to index or month or day