Keyboard Mapping DLL Tutorial

A keyboard mapping DLL provides a set of lookup tables that the generic ektran.dll uses to convert scancodes to keycodes. A keyboard mapping DLL is implemented in a base port.

The basic purpose of the tables is to provide a mapping from scancodes to keycodes, so that, given a scancode, the corresponding keycode can be found. The tables are organized so that there is, in effect, one set of lookup tables for each likely combination of modifier key states. ektran.dll compares the modifier keys that have been pressed with the stored modifier key state combinations to decide which set of lookup tables to use.

An outline set of tables is provided in the template port.

The following list outlines the structure of the tables.

  1. The tables are organized in a hierarchical structure. The start of this hierarchy is the root table, defined by a SConvTable struct. This contains:

    • an array of pointers to nodes, where each node is defined by the SConvTableNode struct. Each node corresponds to a specific combination of modifier key states.

    • a field containing the total number of such nodes.

    Figure 1. Keyboard Mapping Table
  2. The combination of modifier key states that each node represents is encapsulated by a TMaskedModifiers object. One of these objects is embedded within each node.

    A TMaskedModifiers object consists of a mask, and a value for comparison. For example, if an instance is set to the following:

    iMask = EModifierShift | EModifierCtrl | EModifierFunc
    iValue = EModifierShift | EModifierFunc

    then a match occurs only for the following combination of modifier key states:

    ctrl + shift + not Fn

    i.e. a match occurs only if ctrl and shift are pressed, and only if Fn is not pressed. Other modifier keys are ignored, i.e. it does not matter whether or not they are pressed.

    In C++ code, this is expressed as:

    inline TBool MatchesMaskedValue(TInt aModifiers,const TMaskedModifiers &aMaskedModifiers)
        {
        return (TBool)((aModifiers & aMaskedModifiers.iMask) == aMaskedModifiers.iValue);
        }

    where aModifiers contains the modifier key combination to be tested.

  3. In principle, each node represents scancode-to-keycode mappings by associating one or more pairs (or range) of scancodes with corresponding blocks of keycodes. Each pair represents an inclusive and contiguous range of scancodes.

    Each pair (or range) of scancodes may be "discontiguous" from the next.

    The association is made through a table defined by the SConvSubTable struct. This has:

    • a SScanCodeBlockList object that contains pointers to a number of SScanCodeBlock objects, each of which contains the start and end values defining a range of scancodes.

    • a pointer to a table containing the target keycodes. The target keycodes are arranged so that successive scancode pairs are associated with successive blocks of keycodes as the following diagram shows.

    Figure 2. Target keycodes

    This means that successive scancodes, for example, from "A1" through to "B1" are represented by the successive keycodes "keycode for A1" through to "keycode for B1"; scancode "A2" is represented by "keycode for A2", which follows "keycode for B1" in the keycode table.

  4. To allow for possible reuse of keycode tables, a node can point to more than one SConvSubTable. The following diagram shows an example of this:

    Figure 3. Reusing keycode tables
  5. If no keycode can be found that matches the scancode, for a given modifier combination, then the algorithm returns the EKeyNull keycode.

See also

Concepts