When Windows calls the InquireEx function with the INQEX_NLCID flag, the driver must return the number of keyboard layouts that it supports. The driver fills a buffer with a list of the keyboard layouts when the INQEX_LPLCID flag is specified.
The format of a keyboard layout file is as follows.
// Header block
typedef struct {
BYTE KbdDesc[2]; // set to 'DS'
DWORD DefaultLCID; // base language locale identifier
WORD Version; // set to zero
DWORD pKbdStart; // start of the layout data
WORD kbdSize; // number of bytes in the data
DWORD pDibData; // must be zero
WORD dibSize; // must be zero
DWORD pUnicode // must be zero
DWORD nUnicode // must be zero
} HeaderBlock;
The keyboard layout data begins at the location indicated by the pKbdStart field; typically, it follows immediately after the header. The KBDOFFSET values are offsets from the start of the header block, not the start of the file.
typedef struct {
WORD Flags;
WORD nStateKeys;
WORD nStates;
WORD nDeadKeys;
WORD nLigKeys
KBDOFFSET pkbdxxStates; // STATE_LIST
KBDOFFSET pkbdxxToAscStates; // TOASC_STATES
KBDOFFSET pkbdxxToAscStateTables; // STATETABLES
KBDOFFSET pkbdxxToAscVkeyList; // VKEY_LISTS
KBDOFFSET pkbdxxToAscVKeyListLens; // VKEY_LIST_LENS
KBDOFFSET pkbdxxVKShiftStates; // VK_STATES
KBDOFFSET pkbdxxScanToIdx; // SCANTOIDX
KBDOFFSET pkbdxxVKeyToIdx; // VKEYTOIDX
WORD ScanSize; // SCAN_SIZE
KBDOFFSET pkbdxxVKeyToAnsi; // VKEYTOANSI
KBDOFFSET pkbdxxDeadKeyTable; // DEAD_KEYS
KBDOFFSET pkbdxxDeadTrans; // DEAD_KEYTRANS
KBDOFFSET pkbdxxLigKeys; // LIG_KEYS KBDOFFSET
KBDOFFSET pkbdxxCapsBits; // VKEY CAPSLOCK Table
KBDOFFSET pkbdxxKanaNormal; // DBCS platforms (optional)
} KbdDataHeader;
The entries in the Vkey and character table pairs must be in the same order. Also the scancode table (pkbdxxScanToIdx) is in the same order as the main Vkey table (pkbdxxVKeyToIdx).
The wFlags field can have one of these values:
Value | Meaning |
---|---|
ALTGRUSED | The keyboard layout has ALTGR keys (normal, shifted or both). CAPS LOCK here uses the same CAPS LOCK bitmap as the normal and shifted (non-ALTGR) layout layers. |
CAPSNORMAL | The CAPS LOCK key assumes its normal function; that is, it converts alphabetic characters to upper or lower case. Only those keys which are enabled in the CAPS LOCK bitmap will be operated on. |
SHIFTLOCKUSED | The keyboard layout does not have a CAPS LOCK key, but does have a SHIFT LOCK key. In the SHIFTLOCKED state all keys are placed in the shifted state, unlike the CAPS LOCK key which would operate only on specific keys. |
DEADCOMBOS | Declares that the alternative deadkey list is being used, which allows specification of VKEY and shift states for each deadkey entry in the list. |
The CAPSNORMAL and SHIFTLOCKUSED flags are mutually exclusive.
The pKbdCapsBits field points to an array of 32 bytes (consisting of 256 bits) where each bit is indexed by the VKEY. If a VKEY's corresponding bit is not set in this CAPS LOCK bitmap, then the CAPS LOCK function will not operate on that VKEY. The CAPSNORMAL flag must be set to enable this bitmap. If the CAPSNORMAL flag is not set then a separate capitalization VKEY and ANSI table must be used. The standard US bitmap is shown in the following, where only the A through Z keys are capitalized.
pkbdxxCapsBits label byte ; CAPSNORMAL flag must be = 1
db 0,0,0,0,0,0,0,0 ; Controls & Numerals
db 0FEh,0FFh,0FFh,07h,0,0,0,0 ; VK_A -> VK_Z & Numpad & Function Keys
db 0,0,0,0,0,0,0,0 ; Function Keys & OEM Keys
db 0,0,0,0,0,0,0,0 ; OEM Keys, OEM Controls
Note A CAPS LOCK enabled VKEY is operated on by the CAPS LOCK function even in the ALTGR states, so that ALTGR keys will appear as ALTGR-SHIFT keys when operated on by the CAPS LOCK function.
The State list table indicates which basic states are enabled. Only the VK_CAPITAL state is optional (used only when CAPSNORMAL = 0, when the CAPS LOCK bitmap is not used).
pkbdxxStates label byte
db VK_MENU, 080H ; 1 - Alt state
db VK_SHIFT, 080H ; 2 - Shift state
db VK_CONTROL, 080H ; 4 - Control state
db VK_CAPITAL, 001H ; 8 - CapsLock state (optional)
NSTATEKEYS equ ($ - pkbdxxStates) shr 1
The following two state tables are associated with the state list. The first table provides a list of the state indices. The second table provides the states themselves. State indices 8 through 15 are rarely used because the CAPS LOCK bitmap is usually adequate to provide character capitalization options.
db 0 ; Normal (must be outside the label)
pkbdxxToAscStates label byte
db 1 ; Alt
db 2 ; Shift
db 3 ; Alt+Shift
db 4 ; Control
db 6 ; Control+Shift
db 5 ; AltGr
db 7 ; AltGr+Shift
db 8 ; CapsLock
db 9 ; CapsLock + Alt
db 10 ; CapsLock + Shift
db 11 ; CapsLock + Alt + Shift
db 12 ; CapsLock + Control
db 14 ; CapsLock + Control + Shift
db 13 ; CapsLock + AltGr
db 15 ; CapsLock + AltGr + Shift
kbdxx_NSTATES equ $-pkbdxxToAscStates (total states - 1)
pkbdxxVKShiftStates label byte
db 0 ; unshifted
db 0 ; alt - (same as unshifted)
db 1 ; shifted
db 1 ; alt+shift - (same as shifted)
db 2 ; Control
db 3 ; Control + Shift
db 6 ; AltGr - \ Alternative characters
db 7 ; AltGr+Shift - /
db 4 ; CapsLock - (selective keys shifted)
db 4 ; CapsLock + Alt - (same as capslock)
db 5 ; CapsLock + Shift - (same as unshifted)
db 5 ; CapsLock + Alt + Shift - (same as AltGr)
db 2 ; CapsLock + Control - (capslock not applicable)
db 3 ; CapsLock + Control + Shift - (capslock not applicable)
db 6 ; CapsLock + AltGr - (same as shifted AltGr)
db 7 ; CapsLock + AltGr + Shift - (same as unshifted AltGr)
This allows a ligature codepoint to be unravelled into it's component parts by the keyboard driver prior to being sent to the application.
The format of each entry is shown in the following, where the first four bytes holds the base defining element feature, followed by a count and 16-bit words holding the subsequent characters. There is no limit to the extent of ligatures. The table must be terminated with two zero bytes.
"1st-codepoint|VKEY|SHIFTSTATE|0|WLength|2nd-codepoint|0|...."
pkbdxxLigKeys label byte
db 0E1H, VK_A, 0, 0, 1, 0C7H, 0 ;
db 0E1H, VK_A, 2, 0, 1, 0C2H, 0 ;
db 0F8H, VK_Q, 5, 0, 1, 0F3H, 0 ;
db 0,0 ;table terminator
The ligature itself is identified by the VKEY, associated shiftstate, and the initial character forming the ligature.
Non-spacing diacritics are supported with two tables: the first table offers a list of diacritics in one of two forms. The second table offers the combination and resultant tables back-to-back.
pkbdxxDeadKeyTable | a list of diacritic keys. Where there is no ambiguity the first table form is used. Where multiple keys are used for the same diacritic then the VKEYs and their associated shift states must be shown in the second form of the deadkey table. The DEADCOMBOS bit must be set in the wFlags field to signal use of the second table form.
|
The deadKey table with shift state, where each DWORD entry is as follows:
|
|
Legal Shift states are: Normal=0, Shifted=2, AltGr=5, AltGrShift=7 | |
pkbdxxDeadTrans | A pair of tables back-to-back. The first table gives the legal diacritic and letter codepoint value combinations. The second table provides the resultant codepoint. The tables must have the same order, and pkbdxxDeadList1 and pkbdxxDeadList2 must be back-to-back.
|