Access to low-level keyboard functions

The KeyBoard unit implements a keyboard access layer which is system independent. It can be used to poll the keyboard state and wait for certain events. Waiting for a keyboard event can be done with the function, which will return a driver-dependent key event. This key event can be translated to a interpretable event by the function. The result of this function can be used in the other event examining functions.

A custom keyboard driver can be installed using the function. The current keyboard driver can be retrieved using the function. The last section of this chapter demonstrates how to make a keyboard driver.

Base of keyboard routine error reporting constants.
Failed to initialize keyboard driver
Keyboard driver not implemented.
F1 function key pressed.
F2 function key pressed.
F3 function key pressed.
F4 function key pressed.
F5 function key pressed.
F6 function key pressed.
F7 function key pressed.
F8 function key pressed.
F9 function key pressed.
F10 function key pressed.
F12 function key pressed.
F12 function key pressed.
F13 function key pressed.
F14 function key pressed.
F15 function key pressed.
F16 function key pressed.
F17 function key pressed.
F18 function key pressed.
F19 function key pressed.
F20 function key pressed.
function key pressed.
Shift key name index.
Alt key name index.
Alt key name index.
Shift key name index.
Home key pressed
Arrow up key pressed
Arrow down key pressed
Page Up key pressed
Arrow left key pressed
Middle key pad key pressed (numerical 5)
Arrow right key pressed
End key pressed
Page down key pressed
Insert key pressed
Delete key pressed
Ascii code key event
Unicode code key event
Physical key code event
Key release event
Left shift key modifier
Right shift key modifier
Shift key modifier
Control key modifier
Alt key modifier
Names of modifier keys
This constant describes the various modifier keys. This constant is used by the key event description routines. It can be changed to localize the key descriptions when needed.
Names for left-right keys
This constant contains strings to describe left and right keys. This constant is used by the key event description routines. It can be changed to localize the key descriptions when needed.
Unicode character string.
This constant contains a string to denote a unicode key event. This constant is used by the key event description routines. It can be changed to localize the key descriptions when needed.
Scancode key
This constant contains a string to denote a scancode key event. This constant is used by the key event description routines. It can be changed to localize the key descriptions when needed.
Unknown function key
This constant contains a string to denote that an unknown function key was found. This constant is used by the key event description routines. It can be changed to localize the key descriptions when needed.
'And' description string
This constant is used as the 'And' word in key descriptions. This constant is used by the key event description routines. It can be changed to localize the key descriptions when needed.
Names of keypad keys
This constant describes all keypad keys. This constant is used by the key event description routines. It can be changed to localize the key descriptions when needed.
Base type to describe all key events.

The TKeyEvent type is the base type for all keyboard events.

The key stroke is encoded in the 4 bytes of the TKeyEvent type. The various fields of the key stroke encoding can be obtained by typecasting the TKeyEvent type to the type.

Key event decoding type.

The structure of a TKeyRecord structure is explained in the following table:

Structure of TKeyRecord
| Field | Meaning
KeyCode | Depending on flags either the physical representation of a key (under DOS scancode, ascii code pair), or the translated ASCII/unicode character.
ShiftState | Shift-state when this key was pressed (or shortly after)
Flags | Determine how to interpret KeyCode

The shift-state can be checked using the various shift-state constants, and the flags in the last byte can be checked using one of the kbASCII, kbUniCode, kbFnKey, kbPhys, kbReleased constants.

If there are two keys returning the same char-code, there's no way to find out which one was pressed (Gray+ and Simple+). If it needs to be known which was pressed, the untranslated keycodes must be used, but these are system dependent. System dependent constants may be defined to cover those, with possibily having the same name (but different value).

Keyboard driver structure

The TKeyboardDriver record can be used to install a custom keyboard driver with the function.

The various fields correspond to the different functions of the keyboard unit interface. For more information about this record see

Deactivate keyboard driver.

DoneKeyboard de-initializes the keyboard interface if the keyboard driver is active. If the keyboard driver is not active, the function does nothing.

This will cause the keyboard driver to clear up any allocated memory, or restores the console or terminal the program was running in to its initial state before the call to . This function should be called on program exit. Failing to do so may leave the terminal or console window in an unusable state. Its exact action depends on the platform on which the program is running.

For an example, see most other functions.

None.
Return string representation of a function key code.
FunctionKeyName
returns a string representation of the function key with code KeyCode. This can be an actual function key, or one of the cursor movement keys.
In case KeyCode does not contain a function code, the SUnknownFunctionKey string is returned, appended with the KeyCode.
Return the current keyboard driver record.

GetKeyBoardDriver returns in Driver the currently active keyboard driver. This function can be used to enhance an existing keyboarddriver.

For more information on getting and setting the keyboard driver .

None.
Get the next raw key event, wait if needed.

GetKeyEvent returns the last keyevent if one was stored in PendingKeyEvent, or waits for one if none is available. A non-blocking version is available in .

The returned key is encoded as a TKeyEvent type variable, and is normally the physical key scan code, (the scan code is driver dependent) which can be translated with one of the translation functions or . See the types section for a description of how the key is described.

If no key became available, 0 is returned.
,
Get the character key part of a key event.

GetKeyEventChar returns the charcode part of the given KeyEvent, if it contains a translated character key keycode. The charcode is simply the ascii code of the character key that was pressed.

It returns the null character if the key was not a character key, but e.g. a function key.

For an example, see

None.
, , , ,
Translate function key part of a key event code.

GetKeyEventCode returns the translated function keycode part of the given KeyEvent, if it contains a translated function key.

If the key pressed was not a function key, the null character is returned.

None.
, , , ,
Extract the flags from a key event.

GetKeyEventFlags returns the flags part of the given KeyEvent.

For an example, see

None.
, , , ,
Return the current state of the shift keys.

GetKeyEventShiftState returns the shift-state values of the given KeyEvent. This can be used to detect which of the modifier keys Shift, Alt or Ctrl were pressed. If none were pressed, zero is returned.

Note that this function does not always return expected results; In a unix X-Term, the modifier keys do not always work.

None.
, , , ,
Return the unicode key event.
GetKeyEventUniCode
returns the unicode part of the given KeyEvent if it contains a translated unicode character.
None.
, , , ,
Initialize the keyboard driver.

InitKeyboard initializes the keyboard driver. If the driver is already active, it does nothing. When the driver is initialized, it will do everything necessary to ensure the functioning of the keyboard, including allocating memory, initializing the terminal etc.

This function should be called once, before using any of the keyboard functions. When it is called, the function should also be called before exiting the program or changing the keyboard driver with .

For an example, see most other functions.

None.
Check whether a given event is a function key event.
IsFunctionKey
returns True if the given key event in KeyEvent was a function key or not.
None.
Return a string describing the key event.

KeyEventToString translates the key event in KeyEvent to a human-readable description of the pressed key. It will use the constants described in the constants section to do so.

For an example, see most other functions.

If an unknown key is passed, the scancode is returned, prefixed with the SScanCode string.
Check event queue for key press
KeyPressed
checks the keyboard event queue to see whether a key event is present, and returns True if a key event is available. This function simply calls and checks for a valid result.
None.
Get next key event, but does not wait.

PollKeyEvent checks whether a key event is available, and returns it if one is found. If no event is pending, it returns 0.

Note that this does not remove the key from the pending keys. The key should still be retrieved from the pending key events list with the function.

None.
Check current shift state.
PollShiftStateEvent
returns the current shiftstate in a keyevent. This will return 0 if there is no key event pending.
None.
Put a key event in the event queue.
PutKeyEvent
adds the given KeyEvent to the input queue. Please note that depending on the implementation this can hold only one value, i.e. when calling PutKeyEvent multiple times, only the last pushed key will be remembered.
None
Set a new keyboard driver.

SetKeyBoardDriver sets the keyboard driver to Driver, if the current keyboard driver is not yet initialized. If the current keyboard driver is initialized, then SetKeyboardDriver does nothing. Before setting the driver, the currently active driver should be disabled with a call to .

The function returns True if the driver was set, False if not.

For more information on setting the keyboard driver, see .

None.
.
Return description of key event shift state

ShiftStateToString returns a string description of the shift state of the key event KeyEvent. This can be an empty string.

The shift state is described using the strings in the SShift constant.

For an example, see .

None.
Translate raw event to ascii key event

TranslateKeyEvent performs ASCII translation of the KeyEvent. It translates a physical key to a function key if the key is a function key, and translates the physical key to the ordinal of the ascii character if there is an equivalent character key.

For an example, see

None.
Translate raw event to UNICode key event
TranslateKeyEventUniCode
performs Unicode translation of the KeyEvent. It is not yet implemented for all platforms.
If the function is not yet implemented, then the ErrorCode of the system unit will be set to errKbdNotImplemented
Keyboard scan codes

Special physical keys are encoded with the DOS scan codes for these keys in the second byte of the type. A complete list of scan codes can be found in the below table. This is the list of keys that is used by the default key event translation mechanism. When writing a keyboard driver, either these constants should be returned by the various key event functions, or the TranslateKeyEvent hook should be implemented by the driver.

Key Scancodes
| Code | Key | Code | Key | Code | Key
00 | NoKey | 3D | F3 | 70 | ALT-F9
01 | ALT-Esc | 3E | F4 | 71 | ALT-F10
02 | ALT-Space | 3F | F5 | 72 | CTRL-PrtSc
04 | CTRL-Ins | 40 | F6 | 73 | CTRL-Left
05 | SHIFT-Ins | 41 | F7 | 74 | CTRL-Right
06 | CTRL-Del | 42 | F8 | 75 | CTRL-end
07 | SHIFT-Del | 43 | F9 | 76 | CTRL-PgDn
08 | ALT-Back | 44 | F10 | 77 | CTRL-Home
09 | ALT-SHIFT-Back | 47 | Home | 78 | ALT-1
0F | SHIFT-Tab | 48 | Up | 79 | ALT-2
10 | ALT-Q | 49 | PgUp | 7A | ALT-3
11 | ALT-W | 4B | Left | 7B | ALT-4
12 | ALT-E | 4C | Center | 7C | ALT-5
13 | ALT-R | 4D | Right | 7D | ALT-6
14 | ALT-T | 4E | ALT-GrayPlus | 7E | ALT-7
15 | ALT-Y | 4F | end | 7F | ALT-8
16 | ALT-U | 50 | Down | 80 | ALT-9
17 | ALT-I | 51 | PgDn | 81 | ALT-0
18 | ALT-O | 52 | Ins | 82 | ALT-Minus
19 | ALT-P | 53 | Del | 83 | ALT-Equal
1A | ALT-LftBrack | 54 | SHIFT-F1 | 84 | CTRL-PgUp
1B | ALT-RgtBrack | 55 | SHIFT-F2 | 85 | F11
1E | ALT-A | 56 | SHIFT-F3 | 86 | F12
1F | ALT-S | 57 | SHIFT-F4 | 87 | SHIFT-F11
20 | ALT-D | 58 | SHIFT-F5 | 88 | SHIFT-F12
21 | ALT-F | 59 | SHIFT-F6 | 89 | CTRL-F11
22 | ALT-G | 5A | SHIFT-F7 | 8A | CTRL-F12
23 | ALT-H | 5B | SHIFT-F8 | 8B | ALT-F11
24 | ALT-J | 5C | SHIFT-F9 | 8C | ALT-F12
25 | ALT-K | 5D | SHIFT-F10 | 8D | CTRL-Up
26 | ALT-L | 5E | CTRL-F1 | 8E | CTRL-Minus
27 | ALT-SemiCol | 5F | CTRL-F2 | 8F | CTRL-Center
28 | ALT-Quote | 60 | CTRL-F3 | 90 | CTRL-GreyPlus
29 | ALT-OpQuote | 61 | CTRL-F4 | 91 | CTRL-Down
2B | ALT-BkSlash | 62 | CTRL-F5 | 94 | CTRL-Tab
2C | ALT-Z | 63 | CTRL-F6 | 97 | ALT-Home
2D | ALT-X | 64 | CTRL-F7 | 98 | ALT-Up
2E | ALT-C | 65 | CTRL-F8 | 99 | ALT-PgUp
2F | ALT-V | 66 | CTRL-F9 | 9B | ALT-Left
30 | ALT-B | 67 | CTRL-F10 | 9D | ALT-Right
31 | ALT-N | 68 | ALT-F1 | 9F | ALT-end
32 | ALT-M | 69 | ALT-F2 | A0 | ALT-Down
33 | ALT-Comma | 6A | ALT-F3 | A1 | ALT-PgDn
34 | ALT-Period | 6B | ALT-F4 | A2 | ALT-Ins
35 | ALT-Slash | 6C | ALT-F5 | A3 | ALT-Del
37 | ALT-GreyAst | 6D | ALT-F6 | A5 | ALT-Tab
3B | F1 | 6E | ALT-F7 |  |
3C | F2 | 6F | ALT-F8 |  |

A list of scan codes for special keys and combinations with the SHIFT, ALT and CTRL keys can be found in the following table: They are for quick reference only.

Special keys scan codes
| Key | Code | SHIFT-Key | CTRL-Key | Alt-Key
NoKey | 00 |  |  |
F1 | 3B | 54 | 5E | 68
F2 | 3C | 55 | 5F | 69
F3 | 3D | 56 | 60 | 6A
F4 | 3E | 57 | 61 | 6B
F5 | 3F | 58 | 62 | 6C
F6 | 40 | 59 | 63 | 6D
F7 | 41 | 5A | 64 | 6E
F8 | 42 | 5A | 65 | 6F
F9 | 43 | 5B | 66 | 70
F10 | 44 | 5C | 67 | 71
F11 | 85 | 87 | 89 | 8B
F12 | 86 | 88 | 8A | 8C
Home | 47 |  | 77 | 97
Up | 48 |  | 8D | 98
PgUp | 49 |  | 84 | 99
Left | 4B |  | 73 | 9B
Center | 4C |  | 8F |
Right | 4D |  | 74 | 9D
end | 4F |  | 75 | 9F
Down | 50 |  | 91 | A0
PgDn | 51 |  | 76 | A1
Ins | 52 | 05 | 04 | A2
Del | 53 | 07 | 06 | A3
Tab | 8 | 0F | 94 | A5
GreyPlus |  |  | 90 | 4E

Writing a keyboard driver

Writing a keyboard driver means that hooks must be created for most of the keyboard unit functions. The TKeyBoardDriver record contains a field for each of the possible hooks:

TKeyboardDriver = Record InitDriver : Procedure; DoneDriver : Procedure; GetKeyEvent : Function : TKeyEvent; PollKeyEvent : Function : TKeyEvent; GetShiftState : Function : Byte; TranslateKeyEvent : Function (KeyEvent: TKeyEvent): TKeyEvent; TranslateKeyEventUniCode: Function (KeyEvent: TKeyEvent): TKeyEvent; end;

The meaning of these hooks is explained below:

InitDriver
  Called to initialize and enable the driver. Guaranteed to be called only once. This should initialize all needed things for the driver.
DoneDriver
  Called to disable and clean up the driver. Guaranteed to be called after a call to initDriver. This should clean up all things initialized by InitDriver.
GetKeyEvent
  Called by . Must wait for and return the next key event. It should NOT store keys.
PollKeyEvent
  Called by . It must return the next key event if there is one. Should not store keys.
GetShiftState
  Called by . Must return the current shift state.
TranslateKeyEvent
  Should translate a raw key event to a cOrrect key event, i.e. should fill in the shiftstate and convert function key scancodes to function key keycodes. If the TranslateKeyEvent is not filled in, a default translation function will be called which converts the known scancodes from the tables in the previous section to a correct keyevent.
TranslateKeyEventUniCode
  Should translate a key event to a unicode key representation.

Strictly speaking, only the GetKeyEvent and PollKeyEvent hooks must be implemented for the driver to function correctly.

The example unit demonstrates how a keyboard driver can be installed. It takes the installed driver, and hooks into the GetKeyEvent function to register and log the key events in a file. This driver can work on top of any other driver, as long as it is inserted in the uses clause after the real driver unit, and the real driver unit should set the driver record in its initialization section.

Note that with a simple extension of this unit could be used to make a driver that is capable of recording and storing a set of keyboard strokes, and replaying them at a later time, so a 'keyboard macro' capable driver. This driver could sit on top of any other driver.