+ Completed documentation

This commit is contained in:
michael 2001-10-03 21:38:08 +00:00
parent db1b530e29
commit 9964ead534

View File

@ -1,3 +1,25 @@
%
% $Id$
% This file is part of the FPC documentation.
% Copyright (C) 2001, by Michael Van Canneyt
%
% The FPC documentation is free text; you can redistribute it and/or
% modify it under the terms of the GNU Library General Public License as
% published by the Free Software Foundation; either version 2 of the
% License, or (at your option) any later version.
%
% The FPC Documentation is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
% Library General Public License for more details.
%
% You should have received a copy of the GNU Library General Public
% License along with the FPC documentation; see the file COPYING.LIB. If not,
% write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
% Boston, MA 02111-1307, USA.
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% The Keyboard unit
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -77,19 +99,45 @@ They can be used to check And the following shift-state flags:
kbCtrl = 4;
kbAlt = 8;
\end{verbatim}
The following constant strings are used in the key name functions
\seef{FunctionKeyName} and \seef{KeyEventToString}:
\begin{verbatim}
SShift : Array [1..3] of string[5] = ('SHIFT','CTRL','ALT');
LeftRight : Array [1..2] of string[5] = ('LEFT','RIGHT');
UnicodeChar : String = 'Unicode character ';
SScanCode : String = 'Key with scancode ';
SUnknownFunctionKey : String = 'Unknown function key : ';
SAnd : String = 'AND';
SKeyPad : Array [0..($FF2F-kbdHome)] of string[6] =
('Home','Up','PgUp','Left',
'Middle','Right','End','Down',
'PgDn','Insert','Delete','',
'','','','');
\end{verbatim}
They can be changed to localize the key names when needed.
\subsection{Types}
The \var{TKeyEvent} type is the base type for all keyboard events:
\begin{verbatim}
TKeyEvent = Longint;
\end{verbatim}
The structure of a \var{TKeyEvent} is explained in \seet{keyevent}.
The key stroke is encoded in the 4 bytes of the \var{TKeyEvent} type.
The various fields of the key stroke encoding can be obtained by typecasting
the \var{TKeyEvent} type to the \var{TKeyRecord} type:
\begin{verbatim}
TKeyRecord = packed record
KeyCode : Word;
ShiftState, Flags : Byte;
end;
\end{verbatim}
The structure of a \var{TKeyRecord} structure is explained in \seet{keyevent}.
\begin{FPCltable}{ll}{Structure of TKeyEvent}{keyevent}
Bytes & Meaning \\ \hline
2 bytes & Depending on \var{flags} either the physical representation of a key
Field & Meaning \\ \hline
KeyCode & Depending on \var{flags} either the physical representation of a key
(under DOS scancode, ascii code pair), or the translated
ASCII/unicode character.\\
1 byte & shift-state when this key was pressed (or shortly after) \\
1 byte & \var{flags}, determining how to read the first two bytes \\ \hline.
ShiftState & shift-state when this key was pressed (or shortly after) \\
Flags & Determine how to interpret \var{KeyCode} \\ \hline.
\end{FPCltable}
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
@ -100,13 +148,23 @@ 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).
\subsection{Variables}
The following variable contains any pending (i.e. not yet consumed) keyboard
event:
The \var{TKeyboardDriver} record can be used to install a custom keyboard
driver with the \seef{SetKeyboardDriver} function:
\begin{verbatim}
var
PendingKeyEvent : TKeyEvent;
Type
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;
\end{verbatim}
The various correspond to the different functions of the keyboard unit
interface. For more information about this record see \sees{kbddriver}
\section{Functions and Procedures}
@ -114,9 +172,13 @@ var
\Declaration
Procedure DoneKeyboard;
\Description
\var{DoneKeyboard} de-initializes the keyboard interface.
It clears up any allocated memory, or restores the console or terminal
the program was running in to its initial state. This function should
\var{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 \seep{InitKeyBoard}. 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.
@ -128,6 +190,40 @@ None.
For an example, see most other functions.
\begin{function}{FunctionKeyName}
\Declaration
Function FunctionKeyName (KeyCode : Word) : String;
\Description
\var{FunctionKeyName} returns a string representation of the function key
with code \var{KeyCode}. This can be an actual function key, or one of the
cursor movement keys.
\Errors
In case \var{KeyCode} does not contain a function code, the
\var{SUnknownFunctionKey} string is returned, appended with the
\var{KeyCode}.
\SeeAlso
\seef{ShiftStateToString}
\seef{KeyEventToString}
\end{function}
\FPCexample{ex8}
\begin{procedure}{GetKeyboardDriver}
\Declaration
Procedure GetKeyboardDriver (Var Driver : TKeyboardDriver);
\Description
\var{GetKeyBoardDriver} returns in \var{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
\sees{kbddriver}.
\Errors
None.
\SeeAlso
\seef{SetKeyboardDriver}
\end{procedure}
\begin{function}{GetKeyEvent}
\Declaration
function GetKeyEvent: TKeyEvent;
@ -257,16 +353,19 @@ No example available yet.
\Declaration
procedure InitKeyboard;
\Description
\var{InitKeyboard} initializes the keyboard interface, any
additional platform specific parameters should be passed by
setting platform-specific global variables.
\var{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.
keyboard functions. When it is called, the \seep{DoneKeyboard} function
should also be called before exiting the program or changing the keyboard
driver with \seef{SetKeyboardDriver}.
\Errors
None.
\SeeAlso
\seep{DoneKeyboard}
\seep{DoneKeyboard}, \seef{SetKeyboardDriver}
\end{procedure}
For an example, see most other functions.
@ -285,6 +384,22 @@ None.
\FPCexample{ex7}
\begin{function}{KeyEventToString}
\Declaration
Function KeyEventToString(KeyEvent : TKeyEvent) : String;
\Description
\var{KeyEventToString} translates the key event in \var{KeyEvent} to a
human-readable description of the pressed key. It will use the constants
described in the constants section to do so.
\Errors
if an unknown key is passed, the scancode is returned, prefixed with the
\var{SScanCode} string.
\SeeAlso
\seef{FunctionKeyName}, \seef{ShiftStateToString}
\end{function}
For an example, see most other functions.
\begin{function}{PollKeyEvent}
\Declaration
function PollKeyEvent: TKeyEvent;
@ -334,6 +449,41 @@ None
\FPCexample{ex5}
\begin{function}{SetKeyboardDriver}
\Declaration
Function SetKeyboardDriver (Const Driver : TKeyboardDriver) : Boolean;
\Description
\var{SetKeyBoardDriver} sets the keyboard driver to \var{Driver}, if the
current keyboard driver is not yet initialized. If the current
keyboard driver is initialized, then \var{SetKeyboardDriver} does
nothing. Before setting the driver, the currently active driver should
be disabled with a call to \seep{DoneKeyboard}.
The function returns \var{True} if the driver was set, \var{False} if not.
For more information on setting the keyboard driver, see \sees{kbddriver}.
\Errors
None.
\SeeAlso
\seep{GetKeyboardDriver}, \seep{DoneKeyboard}.
\end{function}
\begin{function}{ShiftStateToString}
\Declaration
Function ShiftStateToString(KeyEvent : TKeyEvent; UseLeftRight : Boolean) : String;
\Description
\var{ShiftStateToString} returns a string description of the shift state
of the key event \var{KeyEvent}. This can be an empty string.
The shift state is described using the strings in the \var{SShift} constant.
\Errors
None.
\SeeAlso
\seef{FunctionKeyName}, \seef{KeyEventToString}
\end{function}
For an example, see \seef{PollShiftStateEvent}.
\begin{function}{TranslateKeyEvent}
\Declaration
function TranslateKeyEvent(KeyEvent: TKeyEvent): TKeyEvent;
@ -368,16 +518,19 @@ No example available yet.
\section{Keyboard scan codes}
Special physical keys are encoded with the DOS scan codes for these keys
in the second byte of the \var{TKeyEvent} type.
A complete list of scan codes can be found in \seet{keyscans}.
A list of scan codes for special keys and combinations with the SHIFT, ALT
and CTRl keys can be found in \seet{speckeys}.
A complete list of scan codes can be found in \seet{keyscans}. 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 \var{TranslateKeyEvent} hook
should be implemented by the driver.
\begin{FPCltable}{llllll}{Physical keys scan codes}{keyscans}
Code & Key & Code & Key & Code & Key\\ \hline
\input{keys.tex}
\hline
\end{FPCltable}
A list of scan codes for special keys and combinations with the SHIFT, ALT
and CTRl keys can be found in \seet{speckeys}; They are for quick reference
only.
\begin{FPCltable}{llccc}{Special keys scan codes}{speckeys}
Key & Code & SHIFT-Key & CTRL-Key & Alt-Key \\ \hline
NoKey & 00 & & & \\
@ -408,4 +561,178 @@ Tab & 8 & 0F & 94 & A5 \\
GreyPlus & & & 90 & 4E \\
\hline
\end{FPCltable}
\section{Writing a keyboard driver}
\label{se:kbddriver}
Writing a keyboard driver means that hooks must be created for most of the
keyboard unit functions. The \var{TKeyBoardDriver} record contains a field
for each of the possible hooks:
\begin{verbatim}
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;
\end{verbatim}
The meaning of these hooks is explained below:
\begin{description}
\item[InitDriver] Called to initialize and enable the driver.
Guaranteed to be called only once. This should initialize all needed things
for the driver.
\item[DoneDriver] Called to disable and clean up the driver. Guaranteed to be
called after a call to \var{initDriver}. This should clean up all
things initialized by \var{InitDriver}.
\item[GetKeyEvent] Called by \seef{GetKeyEvent}. Must wait for and return the
next key event. It should NOT store keys.
\item[PollKeyEvent] Called by \seef{PollKeyEvent}. It must return the next key
event if there is one. Should not store keys.
\item[GetShiftState] Called by \seef{PollShiftStateEvent}. Must return the current
shift state.
\item[TranslateKeyEvent] Should translate a raw key event to a currect
key event, i.e. should fill in the shiftstate and convert function key
scancodes to function key keycodes. If the
\var{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.
\item[TranslateKeyEventUniCode] Should translate a key event to a unicode key
representation.
\end{description}
Strictly speaking, only the \var{GetKeyEvent} and \var{PollKeyEvent}
hooks must be implemented for the driver to function correctly.
The following unit demonstrates how a keyboard driver can be installed.
It takes the installed driver, and hooks into the \var{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
\var{uses} clause {\em after} the real driver unit, and the real driver unit
should set the driver record in its initialization section.
\begin{verbatim}
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);
Writeln(KeyLog,': Key event: ',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.
\end{verbatim}
The following program demonstrates the use of the unit:
\begin{verbatim}
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.
\end{verbatim}