kbddriver topic
Writing a keyboard driver.
Declaration
kbddriverDescription
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 byInitDriver. - 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
TranslateKeyEventis 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: logkeys
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: ex9
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.An experiment, built from development snapshots. Not the official Free Pascal or Lazarus documentation.
