[Previous][Up][Next] | Reference for unit 'keyboard' (#rtl)

## 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 GetKeyEvent. Must wait for and return the next key event. It should NOT store keys.
PollKeyEvent
  Called by PollKeyEvent. It must return the next key event if there is one. Should not store keys.
GetShiftState
  Called by PollShiftStateEvent. 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.

## Example

    unit logkeys;

    interface

    Procedure StartKeyLogging;
    Procedure StopKeyLogging;
    Function  IsKeyLogging : Boolean;
    Procedure  SetKeyLogFileName(FileName : String);

    implementation

    uses sysutils,keyboard;

    var
      NewKeyBoardDriver,
      OldKeyBoardDriver : TKeyboardDriver;
      Active,Logging : Boolean;
      LogFileName : String;
      KeyLog : Text;

    Function TimeStamp : String;

    begin
      TimeStamp:=FormatDateTime('hh:nn:ss',Time());
    end;

    Procedure StartKeyLogging;

    begin
      Logging:=True;
      Writeln(KeyLog,'Start logging keystrokes at: ',TimeStamp);
    end;

    Procedure StopKeyLogging;

    begin
      Writeln(KeyLog,'Stop logging keystrokes at: ',TimeStamp);
      Logging:=False;
    end;

    Function IsKeyLogging : Boolean;

    begin
      IsKeyLogging:=Logging;
    end;

    Function LogGetKeyEvent : TKeyEvent;

    Var
      K : TKeyEvent;

    begin
      K:=OldkeyboardDriver.GetKeyEvent();
      If Logging then
        begin
        Write(KeyLog,TimeStamp,': Key event: ');
        Writeln(KeyLog,KeyEventToString(TranslateKeyEvent(K)));
        end;
      LogGetKeyEvent:=K;
    end;

    Procedure LogInitKeyBoard;

    begin
      OldKeyBoardDriver.InitDriver();
      Assign(KeyLog,logFileName);
      Rewrite(KeyLog);
      Active:=True;
      StartKeyLogging;
    end;

    Procedure LogDoneKeyBoard;

    begin
      StopKeyLogging;
      Close(KeyLog);
      Active:=False;
      OldKeyBoardDriver.DoneDriver();
    end;

    Procedure SetKeyLogFileName(FileName : String);

    begin
      If Not Active then
        LogFileName:=FileName;
    end;

    Initialization
      GetKeyBoardDriver(OldKeyBoardDriver);
      NewKeyBoardDriver:=OldKeyBoardDriver;
      NewKeyBoardDriver.GetKeyEvent:=@LogGetKeyEvent;
      NewKeyBoardDriver.InitDriver:=@LogInitKeyboard;
      NewKeyBoardDriver.DoneDriver:=@LogDoneKeyboard;
      LogFileName:='keyboard.log';
      Logging:=False;
      SetKeyboardDriver(NewKeyBoardDriver);
    end.

## Example

    program example9;

    { This program demonstrates the logkeys unit }

    uses keyboard,logkeys;

    Var
      K : TKeyEvent;

    begin
      InitKeyBoard;
      Writeln('Press keys, press "q" to end, "s" toggles logging.');
      Repeat
        K:=GetKeyEvent;
        K:=TranslateKeyEvent(K);
        Writeln('Got key : ',KeyEventToString(K));
        if GetKeyEventChar(K)='s' then
          if IsKeyLogging then
            StopKeyLogging
          else
            StartKeyLogging;
      Until (GetKeyEventChar(K)='q');
      DoneKeyBoard;
    end.

Documentation generated on: May 14 2021