In Windows NT (as in Windows 3.1), keyboard support is 
divided into two logical modules: a driver portion handling the 
hardware and a set of layout DLLs providing national language 
support. The driver transforms the scan code obtained at 
interrupt time from the physical keyboard to a virtual key code. 
A Windows-based application sees the virtual keycode in the 
wParam of the WM_KEYDOWN and WM_KEYUP messages. 
Then the layout DLL translates the keycode into a character 
code, if one exists, and the application receives the result in 
wParam in a subsequent WM_CHAR or WM_DEADCHAR 
message. In Far Eastern keyboards, the message flow differs 
somewhat, but here I'll confine my discussion to European 
keyboards and layouts.

Keyboard Hardware
Though Windows NT driver modules can support a range of 
keyboards, the general PC standard is the IBM 101/102-key 
enhanced keyboard. The 101-key version is found primarily in the 
U.S., whereas in Europe the 102-key model is standard. The 102nd 
key is found just to the right of the left Shift key, which has been 
to accommodate the addition. Another difference is in the shape 
of the Enter key: on European keyboards, it is wider at the top 
and extends over two rows; on U.S. keyboards, this key may be 
only one row high, or if two rows, have its wider part at the 
bottom. This design causes other minor key displacements, and 
generally the number of keys on the second and third letter key 
rows tend to differ between 101-and 102-key models.
Two functions return information about the current keyboard. 
GetKBCodePage is supplied mainly for compatibility with 
Windows-based applications. The value returned is the same 
result as that when calling GetOEMCP. The second function, 
GetKeyboardType, gets hardware features. The types of 
keyboards and number of function keys for each supported 
keyboard type is shown below. The subtype is OEM dependent;  it 
usually indicates a minor variation.

Type       Keyboard                               Function keys
1          IBM PC/XT 83-key keyboard              10
2          Olivetti ICO 102-key keyboard          12 or 18
3          IBM AT 84-key keyboard                 10
4          IBM Enhanced 101/102-key keyboard      12
5          Nokia 1050 and similar models          10
6          Nokia 9140 and similar models          24
7          Japanese keyboard                      OEM dependent



Layouts
Windows NT comes with support for nearly 30 keyboard 
layouts.

Identifier        Name                                DOS id
00000405          Czech                                 cz
00000406          Danish                                dk
00000407          German                                gr
00000408          Greek                                  ?
00000409          US                                    us
0000040A          Spanish                               sp
0000040B          Finnish                               su
0000040C          French                                fr
0000040E          Hungarian                             hu
0000040F          Icelandic                             us
00000410          Italian                               it
00000413          Dutch                                 nl
00000414          Norwegian                             no
00000415          Polish                                pl
00000419          Russian                               ru
0000041A          Yugoslavia*                           yu
0000041B          Slovak*                               sl
0000041D          Swedish                               sv
00000807          Swiss German                          sg
00000809          British                               uk
0000080A          Latin American                        la
0000080C          Belgian French                        be
00000813          Belgian Dutch                         be
00000816          Portuguese                            po
00000C0C          Canadian French                       cf
00001009          Canadian English (Multilingual)       us
0000100C          Swiss French                          sf
00010409          US-Dvorak                             dv
0001040A          Spanish variation                     sp
00010C0C          Canadian French (Multilingual)        cf
00020409          US-International                      us

The identifier numbers should look familiar--                     they 
are simply the Language IDs supplemented when necessary by an 
extra value when there is more than one keyboard layout for that 
language. For example, the standard Canadian French keyboard 
has identifier 0x00000C0C, but the multilingual variant is named 
0x00010C0C. And by the way, the identifier as a string is often 
called the keyboard name; the function

GetKeyboardLayoutName(LPTSTR lpsxKLNName)

can be used to return the identifier of the currently active 
keyboard layout.
Two layouts, Slovak and Yugoslavia (marked with asterisks in 
Figure 48), are not supplied with Windows NT but have two-letter 
MS-DOS codes in the Registry. A Greek keyboard is provided, but 
its code is not listed in the Registry. The us code for Iceland is 
interesting. From the MS-DOS side you cannot select a uniquely 
Icelandic layout, though there is a separate layout provided from 
the Windows 3.1 Control Panel. The Russian two-letter code is 
treated by MS-DOS as illegal, though there is a Russian keyboard 
driver present, but it can only be installed from Windows. The 
Russian, Greek, Hungarian, and Polish layouts can be used in the 
Unipad program, or any program fully supporting Unicode.

The general organization of the keys is familiar typical Western 
European keyboard layout. Differences from a U.S. keyboard 
include the positions of letters Y and Z, and the replacement of 
several symbols and punctuation characters by letters required in 
the languages of Switzerland. Another difference is that some 
keys have three characters; the ones on the right are accessed by 
using the right Alt key (Alt-gr, or alternate graphics). A few keys 
are called nonescaping or dead keys; allow entry of accented 
letters not directly accessible from the keyboard. For example, to 
enter  from the Swiss-German keyboard, the sequence Alt-gr + 
~+ n will do the job. Alt-gr, by the way, is equivalent to Alt-Ctrl, 
so if you define a hot key in your application with Alt-Ctrl as a 
prefix, you can interfere with the proper operation of many 
European keyboards. 
It's possible to use a European keyboard layout with a U.S. 101-
key keyboard, but it can be inconvenient not having the extra key. 
Also, you have to use the numeric pad to enter the missing 
characters (thus Alt + 0244 generates the character at code point 
244 in your current ANSI character set. Without the leading zero, 
you get the character at 244 from the OEM character set, or 
something similar if the conversion between ANSI and MS-DOS 
is not 1:1). Little effort has been made in either MS-DOS or 
Windows to add the characters found on key 102 that would make 
a European keyboard easier to use with U.S. hardware, though it's 
simple  to add the extra code in the layout DLLs. An exception is 
in the keyboards for Eastern Europe, where the characters on key 
102 have also been placed in locations that can be reached from a 
101-key keyboard.
In addition to National Language keyboards, Windows NT 
makes provisions for handicapped users by means of layouts 
based on the Dvorak model. There are three Dvorak layouts: one 
for two-handed users, one for people who type only with left hand, 
and one for people who type only with right hand. The left- or 
right-hand keyboard layouts can also be used by those who type 
with a single finger or with a wand. You don't need to purchase 
special equipment to use these features. The two-handed Dvorak 
is included with Windows NT; the others can be downloaded from 
various bulletin boards or obtained directly from Microsoft.

Changing layouts
A user simply goes to the Control Panel's International 
command to change the keyboard layout. The procedure is similar 
to changing the language module or country settings. If the 
required keyboard layout module is already in the Windows NT 
system32 directory, it is activated and becomes the current 
keyboard. If the module is not present, it must be copied from the 
Setup CD-ROM Each addition is added to a list maintained in the 
Registry under this key:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard
\Layout

From this list, an application can load new keyboard layouts 
dynamically using a new set of APIs.
You can also change the keyboard from an MS-DOS command 
shell by using the KEYB command

KEYB [xx[,[yyy][,[drive:][path]filename]]] [/E] [/ID:nnn]

Here xx is one of the two-letter keyboard codes listed above and 
yyy is a console code page. The other fields are present for 
compatibility with older systems and are ignored in Windows NT.
Note that in Windows NT the layouts are common between the 
console and the Windows side. Hence when you change the layout 
in MS-DOS, you also change the Windows layout, and vice-versa. 
Compare this situation to Windows 3.1 where it is quite possible 
to have one layout in an MS-DOS shell and another on the 
Windows 3.1 side.

Keyboard Layout Functions
Layouts can also be changed from a program, and in Windows 
NT the effect is global. Three APIs support this feature; the core 
function is

HKL LoadKeyboardLayout(LPCTSTR lpszKLName, UINT fuFlags)

This function takes an identifier string as described earlier. The 
flags describe how the layout is to be loaded.
Flag                     Meaning
KLF_ACTIVATE             Load (if not already loaded) and activate the 
layout
KLF_REORDER*             Place loaded layout at head of layout circular 
list
KLF_SUBSTITUTES_OK       Load substitute layout
KLF_UNLOADPREVIOUS*      Unload the previously active layout


If the KLF_ACTIVATE flag is set and the layout is not already 
loaded, it becomes the active layout and is inserted into the 
system's circular list of loaded layouts ahead of the previously 
active layout.
If the KLF_ACTIVATE flag is set and the layout is loaded, then 
the arrangement of the circular list depends on the 
KLF_REORDER bit. If the flag is not set, the system's circular 
list of loaded layouts is simply rotated; otherwise the layout is 
removed from its position in the list and placed at the head as the 
active layout.

If the KLF_SUBSTITUTE_OK flag is set, then the Registry is 
consulted to find a preferred substitute. An example of a 
preferred substitute might be a Dvorak keyboard in place of the 
standard U.S. layout. Finally, the KLF_UNLOADPREVIOUS flag 
will unload the previously loaded active layout.
LoadKeyboard layout returns a keyboard handle, which can then 
be used in other keyboard functions. Loading several keyboard 
layouts makes it fast to switch among layouts. Such a feature is 
especially useful in working with multiple scripts, such as Russian 
and English or Greek and English.
Once a keyboard handle is obtained, activation can be more 
conveniently changed with the function

BOOL ActivateKeyboardLayout(HKL hkl, UINT fuFlags)

This API uses the  above flags marked with an asterisk. Instead of 
specifying a keyboard handle, you can use one of two flags to move 
through the list of loaded layouts.

HKL_NEXT    Selects the next layout in the system's circular list of 
loaded layouts. 
HKL_PREV    Selects the previous layout in the system's circular list 
of loaded layouts.


The current documentation incorrectly lists HKL_PREV as 
HKL_PREVIOUS. Also, be sure to cast the flag as a keyboard 
handle to keep the compiler from complaining.
Finally, the function

BOOL UnloadKeyboardLayout(HKL hkl)

can be used to remove a keyboard layout from the current loaded 
list.

When TranslateMessage is called in your Windows message 
loop, the virtual key obtained from WM_KEYDOWN and 
WM_KEYUP is translated to a Unicode character or characters 
by this function:

int ToUnicode(UINT wVirtKey, UINT wScanCode, PBYTE lpKeyState,
	  LPWSTR pwszBuff, int cchBuff, UINT wFlags)

There is a similar function, ToAscii for returning ANSI 
characters. Though not necessary, in most applications, I have 
used both functions in the KEYMAP application to read keyboard 
layouts according to the state of a local-keyboard-state buffer 
pointed to by lpKeyState. As a loop runs through the various 
character scan codes supported by the keyboard, the 
MapVirtualKey function obtains the corresponding virtual key 
codes, and the state of the Shift, Control, and Alt keys are varied 
in the key-state buffer to obtain the characters supported by the 
layout.
MapVirtualKey can also be used to obtain a scan code from a 
virtual key code. To go from character to virtual key code, 
VkKeyScan will do the job according to the shift state of the 
Shift, Control, and Alt keys. This function is used primarily to 
simulate keystrokes using WM_KEYUP and WM_KEYDOWN 
messages. 
An application can also read and set it's own key state with 
GetKeyboardState and SetKeyboardState, or it can read and set 
the status of an individual key with GetKeyState and 
GetAsyncKeyState. These functions can distinguish between left 
and right versions of the Control, Shift, and Alt keys by a new set 
of virtual key codes: VK_LSHIFT, VK_RSHIFT, 
VK_LCONTROL, VK_RCONTROL, VK_LMENU, and 
VK_RMENU. 
Finally, if you need to present a text representation of 
accelerator (hot keys) to your user, you can use GetKeyNameText 
to obtain a string naming the key and having the proper 
translation according to the keyboard. 


