
			Win32 Keyboard Support


This document describes the keyboard input support that will be
provided in 32-bit windows.  I have attempted as much as possible
to avoid a discussion of National Language Support (NLS) issues
here.  These issues are discussed in the document written by
Asmus Freytag, "NLS and the 32-bit API: an overview," hereafter
referred to as the NLS document.  However, many of the design
decisions made for keyboard support were made with NLS issues in
mind.  Where necessary brief explanations and cross references
are made.


Goals
=====

Exactly why are we redesigning the input support?  There are several
major reasons for this.

	o Product localization: currently it takes several months
	  (in the best case) from the time we release a system until
	  the first localized versions are released internationally.
	  We need to make it possible to release all of these systems
	  effectively simultaneously.

	o Multilingual applications: Windows currently only supports
	  one locale system-wide.  In todays computing environment we
	  need to support simultaneous execution of applications that
	  run in different languages, as well as those applications
	  that will support multiple languages (such as a multilingual
	  word processor).

	o Portability: this  really counts as two goals.  First, we want
	  to run on multiple hardware platforms using the as much of the
	  same code as possible.  But another very important 'port'ability 
	  concern is to make it as easy as possible for OEMs to add support
	  for their own keyboard hardware.

	o Maintainability: by simplifying the amount of work the keyboard
	  hardware driver does and moving all of the special processing
	  out into a separate module the code will be much easier to 
	  understand, modify, and fix.

	o Unicode:  using Unicode internally provides a solid base for
	  support of multiple locales.  We also want to support Unicode
	  applications as they are written.  Another benefit to Unicode
	  is that it allows us to do away with code pages (although
	  translation tables will exist to translate data from a given
	  code page to Unicode and back).




Division of Labor
=================

The following diagrams show the various modules described in this
document.  The terminology used throughout the rest of this document
follows the diagram.


		...........................
		.                         .
		. Keyboard device driver  .
		.                         .
		...........................
			    .
			    .
			    .
		............V..............
		.                         .
		.       HSC -> VSC        .
		.                         .
		...........................
			    .
			    .
			    .
		............V..............
		.                         . 
		.          RIT            .
		.                         .
		...........................
			

   Server
..............................................................
   Client



	  ........................................
	  .           ..           ..            .
	  .    MIT    ..Application..     AIT    .
	  .           ..           ..            .
	  ..........A.........A.........A.........
                  . .       . .       . .
                  . .       . .       . .
                  . .       . .       . .
                  . .       . .       . .
                  . .       . .       . .
		..V.........V.........V....
		.                         .
		.       Translation       .
		.                         .
		...........................


  Note: the RIT, MIT and AIT modules are described in the new input
  model document.


Terminology
===========

Keyboard Device Driver : this is the keyboard hardware device
	driver.  This driver is responsible for controlling the
	hardware; acknowledging interrupts, reading hardware scan
	codes, issueing keyboard commands (such as reset), setting
	LEDs, etc.

HSC : Hardware Scan Code : this is the scan code generated by the
	keyboard hardware.

VSC : Virtual Scan Code : each key will be assigned a unique
 	virtual scan code.  The intent of this code will be to
	remove hardware dependencies and assign a mapping of the
	physical position of the key on the keyboard.  More about
	this later.

Translation : this is the module responsible for all of the various
	translations.  Examples include:

		VSC -> Virtual Key (VKEY)
		VKEY -> Char (Unicode, Windows ANSI, OEM)
		OEM -> Unicode -> OEM



Keyboard Device Driver Interface
================================

The keyboard device driver (KDD) controls the keyboard hardware.
All hardware dependencies will be contained at this level.  The
KDD is responsible for providing a standard view of input (e.g.,
deal with keys that do not generate both *make* and *break*
codes).

No interpretation of the scan codes will be performed by the KDD.
Any decisions based on the input will be made at a higher level
(some at the RIT, some at the AIT/MIT).  For example, the KDD will
no longer examine the input to decide whether to toggle an LED.  The
command to toggle an LED will be issued to the KDD by the higher
level software.  This keeps the KDD simple and fast.  The absolute
minimum amount of work should be performed at interrupt time.  Also,
this avoids the problem of having multiple #ifdef's throughout the
code to support different keyboards as we have now.

Here is the list of the APIs that allow access to the hardware.
For a complete description of the APIs see Appendix A.

	typedef VOID (*PPOS_KEY_HOOK)()
	OSERROR PosInitializeInputThread()
	OSERROR PosResumeInputThread()
	OSERROR PosSuspendInputThread()
	OSERROR PosQueryKeyboardLight()
	OSERROR PosSetKeyboardLight()
	OSERROR PosQueryKeyboardRepeatDelay()
	OSERROR PosSetKeyboardRepeatDelay()
	OSERROR PosQueryKeyboardRepeatRate()
	OSERROR PosSetKeyboardRepeatRate()

A routine, call it KeyInput for now, is registered via the
PosInitializeInputThread routine.  The KeyInput routine will then
be called on receipt of a hardware scan code (one call per HSC).
This routine is called at task time so there is less worry about
how much work can be done at this point.  Clearly sufficient
speed must be maintained so as to provide quick response to the
user (a lot of work can be done between two key strokes!).

As an aside, input interfaces also exist for mouse input.  These
interfaces are sufficient to support Win-H (handwriting for
Windows).


Keyboard Layout vs Keyboard Layer
=================================

As stated above, currently Windows only supports one locale
system wide.  At installation time the user selects the
keyboard layout that matches their physical keyboard (we hope).
Presumably this keyboard is compatible with the locale
they choose.

There are keyboards capable of supporting multiple layers
(e.g., English and Hiragana).  Many of the key caps on these
keyboards have multiple characters on them indicating what
characters can be generated by that key depending upon the
layer selected.

Now we want to go one step further.  We want to support
multiple keyboard layouts.  The difficulty is not from
the programming aspect but from the UI aspect.  The user
will now be able to switch to a keyboard layout that isn't
necessarily reflected by the key caps (for instance, switching
an English keyboard to French which uses the AZERTY layout).
The user either needs to be a touch typist familiar with
the new layout, or they need to have a diagram of the new
keyboard layout sitting in front of them!

The problem that still confronts us is what to do when
a user switches into a keyboard layout that cannot be
completely represented by the physical keyboard installed.
Different keyboards are notorious for having different
numbers of keys.  The 'Enter' key often takes up different
key positions on various keyboards (sometimes oriented
horizontally, sometimes oriented vertically).  This can
lead to a situation in which certain characters cannot
be generated by the non-native keyboard because the
keyboard will not generate the necessary scan code.

[[ There doesn't seem to be much we can do about this.
   We can't go randomly moving keys about.  This is
   a situation where the user needs to be able to remap
   the keyboard.  Clearly remapping needs to be supported
   for any keyboard layout so the user can provide a
   virtual keyboard to physical keyboard mapping.  ARRRGH! ]]


HSC to VSC Translation
======================

The hardware scan code to virtual scan code translation is a
simple table driven translation.

	o One translation table per keyboard (although keyboards
	  that generate the same scan code set can use the same
	  table) per system.  The translation table will be provided
	  by the OEM along with the keyboard DD (for those keyboards
	  and drivers we do not support already).

	o The hardware DD initialization code loads the
	  appropriate HSCtoVSC table based on the current
	  keyboard attached.

	o The HSCtoVSC table does not change once it has been
	  loaded.  Even when the keyboard layer changes this table
	  remains the same.

	o The HSCtoVSC table will live on the server side and is
	  indexed by the HSC.  The table will be 8-bits wide.

	o The HSC to VSC translation will be done by the
	  POS layer.  This translation occurs at task time.

	o The typical size of this table for an enhanced
	  keyboard would be about [[ ??? ]]

	  [[ may need a second table to hold any extended codes
	     for those crazy keyboards that generate two bytes
	     for some scan codes ]]

Each key position will be assigned a unique number.  The following
figure shows how these keys will be numbered.  Note that some
numbers have been skipped (for example, 42).  This happens
when a particular key takes up two key positions.  The key
numbered 43 in the following figure is the "Enter" key which
for this keyboard takes up two positions in the horizontal
position.  On another keyboard the "Enter" key may be oriented
vertically such that there would be no key numbered 29.  However,
there would be a key numbered 42.

[[ Insert keyboard figure here ]]

Okay, so why bother to do this at all?  For a couple of reasons.

	o Assigning this mapping removes any dependencies on
	  hardware scan codes.  If an OEM should change the
	  scan code of a key or keys only this one table would
	  need to change.  All of the other tables would remain
	  the same.  Can you honestly say that no OEM would do
	  this??  Also, if two keyboards have identical key
	  layouts but generate different scan codes then again
	  only this one table would need to change.

	o All the OEM needs to do when adding support for a
	  new keyboard is provide the keyboard DD and the
	  HSCtoVSC translation table.  The OEM could then
	  just use the remaining translation tables and code
	  as is.

	o This makes it much easier to support user mappable
	  keyboards.


Note: Chorded keyboards, such as the "Oyayubi" keyboard in
Japan, are capable of generating more unique scan codes than
the number of keys on the keyboard.  This is accomplished by
using special thumb shifts which are hit simultaneously to
certain base keys.

[[ Do we assign a unique VSC for each HSC thus having several
   VSCs for the same physical key position? or do we flag the
   VSC for special processing during translation since we
   maintain the HSC as well?  Also, will an 8-bit table hold
   all of the scan codes for this keyboard? ]]


VSC to VKEY translation
=======================

This translation will change with a change in keyboard layout.
The other tables, VKeyToUnicode, UnicodeToAnsi, etc. will change
to the corresponding tables associated with the new keyboard layout.
The VSCtoVKEY table stays the same across a change in keyboard
layer.

[[ an API is required to effect the change ]]


VKEY to CHAR mapping
====================

'CHAR' is used here to represent either ANSI or Unicode
encodings.  Internally the system will translate from
VKEY to Unicode.  For non-Unicode applications the
character will be translated into ANSI (or Kana, or ...)
when returning from TranslateMessage.

This translation may change with a change in keyboard layer.

[[ an API is required to effect the change ]]


Unicode Table
=============

Unicode will be used internally by Windows.  Entries in this
table are 16-bits wide.  The Unicode table is fixed, although
4,095 locations are provided for user defined characters.

[[ this seems to completely contradict data portability! ]]

For more information on Unicode see the "UNICODE" document
written by The Unicode90 Consortium.


Special Processing Keys
=======================

Many keys, or key combinations, have special meaning and require
extra functionality (for instance the 'Print Scrn' key or the
'Shift'-'Print Scrn' combination).  Currently the tests for these
keys and the code to support the necessary functionality exists
in the keyboard driver itself.  This has two major drawbacks:

	1. Code maintainability is greatly decreased.

	2. Extensibility is made more difficult.  We want to
	   make adding new functionality as easy as possible
	   for ourselves and our OEMs.

A much better approach would be to associate individual routines
with these keys and key combinations.  That way when a *special*
key is processed the code that supports the required functionality
can be called directly.  This solves both of the problems stated
above.  Code is compartmentalized and thus easier to understand
and maintain.  Adding support for new *special* keys only takes
adding the necessary entry into the translation table along with
the procedure address.

[[ Associating a separate procedure with each *special* key does
incur space overhead (storing the procedure addresses).  It
might be better to break the keys into several major groupings
based on shift state.  This eliminates the need to store procedure
addresses while still maintaining a better level of separation
of special processing code from the driver. ]]


Remapping the Keyboard
======================

A windows application will be provided that will allow the user
to remap the keyboard.  The application will generate the appropriate
HSC to VSC mapping table (changing this table will cause the
menu accelerator keys to move as well - this is what we want isn't
it).

The keyboards with LEDs (to indicate Caps Lock, Num Lock, etc.)
that are separate from the keys are easy to handle.  The interesting
question is how to handle the remapping of keys with LEDs physically
present on the keys.  For instance, suppose the user remaps the
Caps Lock key with the Ctrl key and vice versa (not an uncommon
situation).  Using this new mapping when the user hit the key on
the keyboard marked Ctrl (now meaning Caps Lock) the LED on the
Caps Lock key should be turned on.  If status lines are being
displayed in the window then the appropriate indicator should also
be set.  The bottom line is that the LEDs should be considered
separate from the key cap at all times.


Physical Locking Keys
=====================

As if life isn't complicated enough some keyboard manufacturers,
specifically NEC in Japan, produce keyboards that have physically
locking keys (for instance, the Caps key).   These locking keys
must be treated as toggle keys in order to properly support shift
state on a per window basis and support switching away from and
back to IMEs in the middle of a translation.  The physical position
of the key (up or down) becomes unimportant.  Rather, the transition
from up to down, or vice versa, is used as the signal to toggle the
current shift state for the active window.  This shift state MUST be
reflected in a status line for the window.  Otherwise the user could
become very, very confused.


Layer Switching API
===================

The decision of what keyboard layers are valid and how to cycle
through them (hotkeys for direct access is certainly needed) is
the responsibility of higher level software.  The APIs provided
here allow the switching from one layer to another.

[[ The issue of how to divide up the work needs to be decided.
   The PM solution involved a new module called the SSC (Shift
   State Controller).  This module has certain responsibilities
   such as updating the keyboard status area in the frame window,
   updating the keyboard LEDs, and maintaining the translation
   tables for a given frame window.  I think davidpe and I need
   to coordinate on this.  More details can be found in the
   NT OS/2 NLS Keyboard Input Design Workbook written by Asmus
   Freytag, Mike Leu, and Ben Ting. ]]


Translation API
===============

The following 8-bit API that currently exist in Windows will
continue to be supported.  They are:

	AnsiToOem
	AnsiToOemBuffer
	OemToAnsi
	OemToAnsiBuffer
	AnsiNext
	AnsiPrev

[[ I have included a detailed description of these APIs in
   Appendix B.  This description may be more appropriate in
   the NLS document. ]]

As mentioned in the NLS document, we are considering adding
the following for APIs:

	AnsiToUnicode
	AnsiToUnicodeBuffer
	UnicodeToAnsi
	UnicodeToAnsiBuffer

However, these APIs may be replaced by more general character
set conversion APIs which would provide more extensive support
(convert data to/from OS/2 code pages.

[[ This needs to be finalized ]]

Filenames will remain in 8-bit OEM format for now (refer to
the NLS document for a long term solution).  In order to support
Unicode applications the following APIs will be implemented:

	UnicodeToOem
	UnicodeToOemBuffer
	OemToUnicode
	OemToUnicodeBuffer
	UnicodeNext
	UnicodePrev
	UnicodeFilter

[[ Should these APIs be defined in this document or in the
   NLS document?  At the very least we should be consistent
   with how we handle the AnsiToOem, etc. APIs ]]


Support of Old API
==================

The following is a list of APIs supported by the Win3.0
keyboard driver.

Inquire
Enable
Disable
ToAscii
SetSpeed
ScreenSwitchEnable
GetTableSeg
NewTable
OEMKeyScan
VkKeyScan
GetKeyboardType
MapVirtualKey
GetKBCodePage
GetKeyNameText
EnableKBSysReq

Many of these APIs are no longer appropriate.  Others can be
supported on top of the new keyboard routines if desired.

[[ Which ones, if any should be implemented??  We won't be
   able to get 100% coverage.  For instance, we don't want
   to support Enable as a public API ]]

Note: The functions Inquire, Enable, and Disable are referenced in
Chapter 4: The Keyboard of "Programming Windows" by Charles Petzold
even though MS did not document them as public.

Documentation on these APIs is contained in Appendix C.  This
is provided as reference only and is not to be construed as a
commitment to provide these interfaces.



			APPENDIX A
			==========

Windows Keyboard Input Thread Interface (IT) definitions


The following structure is filled in by the PosInitializeInputThread
function.  This structure describes the capabilities of the input
hardware.  The RepeatRate, RepeatDelay and TimerResolution fields are
in terms of milliseconds.

typedef struct _POS_INPUT_INFORMATION {
    ULONG  Length;
    USHORT NumberOfKeys;
    UCHAR  NumberOfFunctionKeys;
    UCHAR  NumberOfKeyboardLights;
    USHORT MinimumKeyRepeatRate;
    USHORT MaximumKeyRepeatRate;
    USHORT MinimumKeyRepeatDelay;
    USHORT MaximumKeyRepeatDelay;
    UCHAR  MousePresent;
    UCHAR  NumberOfMouseButtons;
    USHORT MouseResolutionInMickeys;
    ULONG  TimerResolution;              // Milliseconds
} POS_INPUT_INFORMATION, *PPOS_INPUT_INFORMATION;



This function is called in the context of the Input Thread for each
key event received from the keyboard hardware.

typedef
VOID (*PPOS_KEY_HOOK)(
    IN ULONG KeyCode,
    IN UCHAR BreakFlag,
    IN ULONG TimeStamp
    );


This function is called in the context of the Input Thread for each
movement event received from the mouse hardware.

typedef
VOID (*PPOS_MOVEMENT_HOOK)(
    IN LONG DeltaX,
    IN LONG DeltaY,
    IN ULONG TimeStamp
    );



This function opens and initializes the input hardware, creates a thread
to wait for events from the hardware and returns information about the
input hardware in the passed InputInfo data structure.  The passed hook
procedures are remembered and will be called whenever the related event
occurs in the context of the input thread.  The input hardware is opened
exclusively, which prevents other processes from accessing the hardware
The thread is created suspended and will not run until PosResumeInputThread
is called with the thread handle returned by this procedure.

OSERROR
PosInitializeInputThread(
    IN OUT PPOS_INPUT_INFORMATION InputInfo,
    IN PPOS_KEY_HOOK KeyHook,
    IN PPOS_BUTTON_HOOK ButtonHook,
    IN PPOS_MOVEMENT_HOOK MovementHook,
    IN PPOS_TIMER_HOOK TimerHook,
    OUT PHANDLE InputThreadHandle
    );


OSERROR
PosResumeInputThread(
    IN HANDLE InputThreadHandle
    );


OSERROR
PosSuspendInputThread(
    IN HANDLE InputThreadHandle
    );


typedef struct _POS_KEY_INFORMATION {
    ULONG Length;
    USHORT Flags;
    CHAR KeyName[1];
} POS_KEY_INFORMATION, *PPOS_KEY_INFORMATION;

#define POS_KEY_SHIFTKEY          0x0001
#define POS_KEY_LIGHTEDKEY        0x0002
#define POS_KEY_GRAPHICKEY        0x0004


OSERROR
PosQueryKeyInfo(
    IN USHORT KeyCode,
    IN OUT PPOS_KEY_INFORMATION KeyInfo
    );


OSERROR
PosQueryKeyboardLight(
    IN USHORT KeyCode,
    OUT PUCHAR State
    );


OSERROR
PosSetKeyboardLight(
    IN USHORT KeyCode,
    IN UCHAR State
    );


OSERROR
PosQueryKeyboardRepeatDelay(
    OUT PUSHORT Delay
    );


OSERROR
PosSetKeyboardRepeatDelay(
    IN USHORT Delay
    );


OSERROR
PosQueryKeyboardRepeatRate(
    OUT PUSHORT Rate
    );


OSERROR
PosSetKeyboardRepeatRate(
    IN USHORT Rate
    );




			Appendix B
			==========

The function AnsiToOem translates the string pointed to by the
lpAnsiStr parameter from the ANSI character set into the OEM-defined
character set. The string can be greater than 64K in length.

int
AnsiToOem
    LPSTR lpAnsiStr,
    LPSTR lpOemStr
    );


Parameter	Description
---------	-----------
lpAnsiStr	Points to a null-terminated string of characters
		from the ANSI character set. 

lpOemStr	Points to the location where the translated string
		is to be copied. The lpOemStr parameter can be the
		same as lpAnsiStr to translate the string in place. 

The return value is always -1.



The function OemToAnsi translates the string pointed to by the
lpOemStr parameter from the OEM-defined character set into the
ANSI character set. The string can be greater than 64K in length.

int
OemToAnsi
    LPSTR lpOemStr,
    LPSTR lpAnsiStr
    );

Parameter	Description
---------	-----------
lpOemStr	Points to a null-terminated string of characters
		from the OEM-defined character set.

lpAnsiStr	Points to the location where the translated string
		is to be copied. The lpAnsiStr parameter can be the
		same as lpOemStr to translate the string in place. 

The return value is always -1.



The function AnsiToOemBuff translates the string in the buffer
pointed to by the lpAnsiStr parameter from the ANSI character
set into the OEM-defined character set.

void
AnsiToOemBuff(
    LPSTR lpAnsiStr,
    LPSTR lpOemStr,
    WORD nLength
    );

Parameter	Description
---------	-----------
lpAnsiStr	Points to a buffer containing one or more characters
		from the ANSI character set. 

lpOemStr	Points to the location where the translated string is
		to be copied. The lpOemStr parameter can be the same
		as lpAnsiStr to translate the string in place. 

nLength		Specifies the number of characters in the buffer
		identified by the lpAnsiStr parameter. If nLength
		is zero, the length is 64K (65,536).

There is no return value.



The function OemToAnsiBuff translates the string in the buffer pointed
to by the lpOemStr parameter from the OEM-defined character set into the
ANSI character set.

void
OemToAnsiBuff(
    LPSTR lpOemStr,
    LPSTR lpAnsiStr,
    WORD nLength
    );

Parameter	Description
---------	-----------
lpOemStr	Points to a buffer containing one or more characters
		from the OEM- defined character set. 

lpAnsiStr	Points to the location where the translated string is
		to be copied. The lpAnsiStr parameter can be the same
		as lpOemStr to translate the string in place. 

nLength		Specifies the number of characters in the buffer
		identified by the lpOemStr parameter. If nLength
		is zero, the length is 64K (65,536).

There is no return value.



			Appendix C
			==========

The function Inquire copies information about the keyboard hardware
into the area pointed to by lpKbInfo.

int
Inquire(
    lpKbInfo
    );

Parameter	Description
---------	-----------
lpKbInfo	points to a KBINFO structure.  The structure is defined
		as follows:

		struct {
		    BYTE Begin_First_range;  /* Far East support */
		    BYTE End_First_range;
		    BYTE Begin_Second_range;
		    BYTE End_Second_range;
		    int  stateSize;  /* size of ToAscii()'s state block */
		}


The return value specifies the number of bytes copied to the buffer
identified by lpKbInfo.	



The function Enable enables hardware keyboard interrupts.

void
Enable(
    eventProc,
    lpKeyState
    );

Parameter	Description
---------	-----------
eventProc	pointer to the procedure to call when keyboard interrupt
		occurs.

lpKeyState	long pointer to the Windows 256 byte keystate table

There is no return value.



The function Disable restores the previous IBM BIOS keyboard interrupt
handler (address was saved when Enable() was called).

void
Disable()

There is no return value.



The function ToAscii translates the virtual-key code specified by the
wVirtKey parameter and the current keyboard state specified by the
lpKeyState parameter to the corresponding ANSI character or characters.

int
ToAscii(
    WORD wVirtKey,
    WORD wScanCode,
    LPSTR lpKeyState,
    LPVOID lpChar,
    WORD wFlags
    );

Parameter	Description
---------	-----------
wVirtKey	Specifies the virtual-key code to be translated.

wScanCode	Specifies the 'hardware' raw scan code of the key to
		be translated. The high-order bit of this value is set
		if the key is up. 

lpKeyState	Points to an array of 256 bytes, each of which contains
		the state of one key. If the high-order bit of the byte
		is set the key is up.

lpChar		Points to a 32-bit buffer which receives the translated
		ANSI character or characters. 

wFlags		The bit 0 flag's menu display.

The return value specifies the number of characters copied to the buffer
identified by the lpChar parameter. The return value is negative if the
key was a dead key. Otherwise, it is one of the following values:

	Value		Meaning
	-----		-------
	2		Two characters were copied to the buffer. This
			is usually an accent and a dead-key character,
			when the dead key cannot be translated otherwise.

	1		One ANSI character was copied to the buffer.

	0		The specified virtual key has no translation for
			the current state of the keyboard.

The parameters supplied to the ToAscii function might not be sufficient
to translate the virtual-key code because a previous dead key is stored
in the keyboard driver.

Typically, ToAscii performs the translation based on the virtual-key code.
In some cases, however, the wScanCode parameter may be used to distinguish
between a key depression or a key release. The scan code is used for
translating ALT+NUMBER key combinations.



The function SetSpeed sets the typematic rate of the keyboard.

SetSpeed(
    WORD rate_of_speed
    );

Parameter	Description
---------	-----------
rate_of_speed	defines the desired rate of repeat, or used to inquire
		about speed-setting capability.

		Value	Meaning
		-----	-------
		-1	query speed-setting capability.

		other	lowest 5 bits define the desired rate of repeat.

If rate_of_speed is -1 the return value is 0 if keyboard is capable
of speed_setting, otherwise the return value is -1.  If rate_of_speed
is not -1 then return value is equal to speed actually set on 
keyboard, or -1 if call failed.



The function ScreenSwitchEnable is called by the display driver to
inform the keyboard driver that the display driver is in a critical 
section and to ignore all OS/2 screen switches until the display driver
leaves its critical section.

void
ScreenSwitchEnable(
    WORD fEnable
    );


Parameter	Description
---------	-----------
fEnable		Set to 0 to disable screen switches, and set to a
		NONZERO value to re-enable them.  At startup screen
		switches are enabled.

There is no return value.



The function GetTableSeg finds the paragraph of the TABS segment
and stores it in TableSeg.

void
GetTableSeg()

There is no return value.



The function NewTable loads a keyboard-table DynaLink Library and
calls the DLL's function (GetKbdTable) for copying pointers and data
to the driver causing a change in the keyboard layout.

void
NewTable()

There is no return value.



The function OemKeyScan maps OEM ASCII codes 0 through 0x0FF into
the OEM scan codes and shift states. It provides information which
allows a program to send OEM text to another program by simulating
keyboard input and is used specifically  for this purpose by Windows
in 386 enhanced mode.

DWORD
OemKeyScan(
    WORD wOemChar
    );

Parameter	Description
---------	-----------
wOemChar	Specifies the ASCII value of the OEM character.

The return value contains in its low-order word the scan code of
the OEM character identified by the wOemChar parameter. The high-order
word of the return value contains flags which indicate the shift state.
The following lists the flag bits and their meanings:

	Bit	Meaning
	---	-------
	2	CTRL key is pressed.
	1	Either SHIFT key is pressed.

If the character is not defined in the OEM character tables, both
the low-order and high-order words of the return value contain -1.

This function does not provide translations for characters which
require CTRL-ALT or dead keys. Characters not translated by this
function must be copied by simulating input using the 'ALT + keypad' 
mechanism. The NUMLOCK key must be off.

This function calls the VkKeyScan function in recent versions of the
keyboard drivers.



The function VkKeyScan translates an ANSI character to the corresponding
virtual-key code and shift state for the current keyboard. Applications
which send character by means of WM_KEYUP and WM_KEYDOWN messages use this
function.

int
VkKeyScan(
    char cChar
    );

Parameter	Description
---------	-----------
cChar		Specifies the character for which the corresponding
		virtual-key code is to be found. 

The VK_ code is returned in the low-order byte and the shift state in
the high-order byte. The shift states are:

	Value	Meaning
	-----	-------
	0	No shift. 
	1	Character is shifted. 
	2	Character is control character. 
	6	Charcter is CONTROL+ALT.
	7	Character is SHIFT+CONTROL+ALT. 
	3, 4, 5	A shift key combination that is not used for characters. 

If no key is found that translates to the passed ANSI code, a -1 is
returned in both the low-order and high-order bytes.

Translations for the numeric keypad (VK_NUMPAD0 through VK_DIVIDE)
are ignored. This function is intended to force a translation for
the main keyboard only.



The function GetKeyboardType retrieves the system-keyboard type.

int
GetKeyboardType(
    int nTypeFlag
    );

Parameter	Description
---------	-----------
nTypeFlag	Determines whether the function returns a value
		indicating the type or subtype of the keyboard.
		It may be one of the following values: 

		Value	Meaning
		-----	-------
		0	Function returns the keyboard type.
		1	Function returns the keyboard subtype.
		2	Function returns the number of function keys
			on the keyboard.

The return value indicates the type or subtype of the system keyboard
or the number of function keys on the keyboard. The subtype is an
OEM-dependent value. The type may be one of the following values:

	Value	Meaning
	-----	-------
	1	IBMr PC/XTO, or compatible (83-key) keyboard
	2	Olivettir M24 'ICO' (102-key) keyboard
	3	IBM ATr (84-key) or similar keyboard
	4	IBM Enhanced (101- or 102-key) keyboard
	5	Nokia 1050 and similar keyboards
	6	Nokia 9140 and similar keyboards

The return value is zero if the nTypeFlag parameter is greater than 2
or if the function fails.

An application can determine the number of function keys on a keyboard
from the keyboard type. The following shows the number of function keys
for each keyboard type:

	Type	Number of Function Keys
	----	-----------------------
	1	10
	2	12 (sometimes 18)
	3	10
	4	12
	5	10
	6	24



The function MapVirtualKey accepts a virtual-key code or scan code for
a key and returns the corresponding scan code, virtual-key code, or
ASCII value. The value of the wMapType parameter determines the type
of mapping which this function performs.

WORD
MapVirtualKey(
    WORD wCode,
    WORD wMapType
    );

Parameter	Description
---------	-----------
wCode		Specifies the virtual-key code or scan code for a key. The 
		interpretation of the wCode parameter depends on the value
		of the wMapType parameter.

wMapType	Specifies the type of mapping to be performed. The wMapType 
		parameter can be any of the following values:

		Value	Meaning
		-----	-------
		0	The wCode parameter specifies a virtual-key code,
			and the function returns the corresponding scan code.
		1	The wCode parameter specifies a scan code, and the 
			function returns the corresponding virtual-key code.
		2	The wCode parameter specifies a virtual-key code,
			and the function returns the corresponding unshifted
			ASCII value.

		Other values are reserved.

The return value depends on the value of the wCode and wMapType parameters.
See the description of the wMapType parameter for more information.



The function GetKBCodePage determines which OEM/ANSI tables are loaded
by Windows.

int
GetKBCodePage()

The return value specifies the code page currently loaded by Windows.
It can be one of the following values:

	Value	Meaning
	-----	-------
	437	Default (USA, used by most countries: indicates that
		there is no OEMANSI.BIN in the Windows directory)
	850	International (OEMANSI.BIN = XLAT850.BIN)
	860	Portugal (OEMANSI.BIN = XLAT860.BIN)
	861	Iceland (OEMANSI.BIN = XLAT861.BIN)
	863	French Canadian (OEMANSI.BIN = XLAT863.BIN)
	865	Norway/Denmark (OEMANSI.BIN = XLAT865.BIN)

If the file OEMANSI.BIN is in the Windows directory, Windows reads it
and overwrites the OEM/ANSI translation tables in the keyboard driver.

When the user selects a language within the Setup program and the
language does not use the default code page (437), Setup copies the
appropriate file (such as XLATPO.BIN) to OEMANSI.BIN in the Windows 
system directory. If the language uses the default code page, Setup
deletes OEMANSI.BIN, if it exists, from the Windows system directory.




The function GetKeyNameText retrieves a string which contains the name
of a key.

int
GetKeyNameText(
    DWORD lParam,
    LPSTR lpBuffer,
    WORD nSize
    ); 

The keyboard driver maintains a list of names in the form of character
strings for keys with names longer than a single character. The key name
is translated according to the layout of the currently installed 
keyboard. The translation is performed for the principal language
supported by the keyboard driver.

Parameter	Description
---------	-----------
lParam		Specifies the 32-bit parameter of the keyboard message
		(such as WM_KEYDOWN) which the function is processing.
		Byte 3 (bits 16-23) of the long parameter is a scan code.
		Bit 20 is the extended bit that distinguishes some keys
		on an enhanced keyboard. Bit 21 is a 'don't care' bit; the 
		application calling this function sets this bit to indicate
		that the function should not distinguish between left and
		right control and shift keys, for example. 

lpBuffer	Specifies a buffer to receive the key name. 

nSize		Specifies the maximum length in bytes of the key name,
		not including the terminating NULL character. 

The return value is the actual length of the string copied to lpBuffer.



The function EnableKBSysReq enables and shuttles off NMI interrupt
simulation (trap to debugger) when CTRL-ALT-SysReq is pressed.

WORD
EnableKBSysReq(
    fSysParm
    );

Parameter	Description
---------	-----------
fSysParm

	Value	Meaning
	-----	-------
	1	enable int 2
	2	disable int 2
	4	enable CVWBreak
	8	disable CVWBreak

The return value...
