Pascal FAQ created by SLY Golovanov, 2:5020/278.13
(slightly corrected by Valery Votintsev 2:5021/22)
==============================================================================
Q:> А как прочитать нажатия клавиш Ctrl, Alt и подобных?
A: Для функции ReadKey эти клавиши не генерируют никаких кодов.
Однако, информация о нажатии подобных клавиш все-таки
имеется и располагается в памяти (область данных BIOS)
по адресу:
Seg0040:$17 - Keyboard Status Flags #1 (основные флаги спец.клавиш)
Ячейка Seg0040:$0017:
<-+---- номера битов
Њ7+6+5+4+3+2+1+0 |
|i|c|n|s|A|^|S|S| Бит Знач. Назначение бита
Іs+s+s+s+-+-+L+R| N
| | | | | | | +-. 0: 01h нажат Right-shift
| | | | | | +---. 1: 02h нажат Left-shift
| | | | | +-----. 2: 04h нажат Ctrl (любой)
| | | | +-------. 3: 08h нажат Alt (любой)
| | | +---------. 4: 10h состяние ScrollLock
| | +-----------. 5: 20h состяние NumLock
| +-------------. 6: 40h состяние CapsLock
+---------------. 7: 80h состяние Insert
В этих ячейках каждый бит отвечает за одну конкретную спец.клавишу -
если бит установлен, то клавиша нажата, если сброшен - то не нажата.
Исключение составляют клавиши ScrollLock, NumLock, CapsLock, Insert -
при первом нажатии соответствующий бит устанавливается в 1, а при
следующем - сбрасывается в 0.
Вот вам функция для вытаскивания этой информации
их байтов Seg040:$17.
Пример вызова: if GetLockKey(Ctrl) then {нажат Ctrl}
Type
Keytype=(Ins, Caps, Num, Scroll, Ctrl, Alt, LShift, RShift);
function GetLockKey(lock:Keytype):Boolean;
{Проверяет, нажата ли спец.клавиша}
var b:word;
begin
case lock of
Ins : b:=$0080;
Caps : b:=$0040;
Num : b:=$0020;
Scroll : b:=$0010;
Alt : b:=$0008;
Ctrl : b:=$0004;
LShift : b:=$0002;
RShift : b:=$0001;
end;
if (mem[0:$417] and b)=b then GetLockKey:=true
else GetLockKey:=false;
end;
Аналогично (домашнее задание! ;-) можно анализировать и байт по адресу
Seg040:$18 (Keyboard Status Flags #2)
Ячейка Seg0040:$0018:
<-+---- номера битов
Њ7+6+5+4+3+2+1+0 |
|i|c|n|s|p|q|A|^| Бит Знач. Назначение бита
Іd+d+d+d+-+d+l+l| N
| | | | | | | +-. 0: 01h нажат левый Ctrl
| | | | | | +---. 1: 02h нажат левый Alt
| | | | | +-----. 2: 04h SysReq DOWN
| | | | +-------. 3: 08h hold/pause state
| | | +---------. 4: 10h нажат ScrollLock
| | +-----------. 5: 20h нажат NumLock
| +-------------. 6: 40h нажат CapsLock
+---------------. 7: 80h нажат Insert
Посмотрите на прилагаемый тест,
попробуйте нажать несколько клавиш сразу,
обратите внимание на то, что статус клавиатуры изменяется
как при нажатии на клавиши, так и при отпускании тоже!
---
* Origin: (2:5020/794.13)
{> Cut here. FileName= GETKEY.PAS }
{From: Valery Votintsev 2:5021/22}
{Alt, Shift, Ctrl test for 0040:0017 keyboard status}
Uses CRT;
Const
RightShift = $0001;
LeftShift = $0002;
AnyCtrl = $0004;
AnyAlt = $0008;
ScrollActive = $0010;
NumLockActive = $0020;
CapsLockActive= $0040;
InsActive = $0080;
LeftCtrl = $0100;
LeftAlt = $0200;
SysReq = $0400;
PauseKey = $0800;
ScrollLock = $1000;
NumLock = $2000;
CapsLock = $4000;
Insert = $8000;
const hex_num:array [0..15] of char='0123456789ABCDEF';
var
key:char; {код нажатой клавиши}
flags:word; {флаги состояния клавиатуры}
newflags:word;
function word2hex(w:word):string;
{перевод в 16-ричное число}
var
b:array[1..2] of byte absolute w;
begin
word2hex:=hex_num[b[2] shr 4]+hex_num[b[2] and $0F] +
hex_num[b[1] shr 4]+hex_num[b[1] and $0F]
end;
function GetFlags:Word;
{Считывает состояние флагов спец.клавиш}
begin
GetFlags:=memW[0:$417];
end;
function AnyKeyEvent:boolean;
begin
AnyKeyEvent:= (KeyPressed or (newflags<>flags));
end;
function Pressed(lock:word):Boolean;
{Проверяет, нажата ли спец.клавиша с кодом LOCK}
begin
if (flags and word(lock))<>0 then Pressed:=true
else Pressed:=false;
end;
Procedure WriteKeyCode;
begin
TextAttr:=White;
If KeyPressed then begin
key:= ReadKey; {читаем код }
if Key = #0 then begin {код оказался расширенным}
Write(Ord(Key):3,','); {печатаем нулевой код }
key:= ReadKey; {читаем расширенный код }
end;
Write(Ord(Key):3); {печатаем основной код }
end
else write(' ');
end;
Procedure WriteFlags;
begin
TextAttr:=LightGray;
Write(' Flags:',word2hex(memW[Seg0040:$17]));
{Теперь печатаем флаги спец.клавиш}
TextAttr:=Cyan;
If Pressed(RightShift) then Write(' RightShift');
If Pressed(LeftShift ) then Write(' LeftShift');
If Pressed(AnyAlt ) then Write(' AnyAlt');
If Pressed(AnyCtrl ) then Write(' AnyCtrl');
If Pressed(LeftCtrl ) then Write(' LeftCtrl');
If Pressed(LeftAlt ) then Write(' LeftAlt');
If Pressed(SysReq ) then Write(' SysReq');
If Pressed(PauseKey ) then Write(' Pause');
If Pressed(ScrollLock) then Write(' ScrollLock');
If Pressed(NumLock ) then Write(' NumLock');
If Pressed(CapsLock ) then Write(' CapsLock');
If Pressed(Insert ) then Write(' Insert');
{Теперь печатаем состояние переключателей}
TextAttr:=Yellow;
If Pressed(ScrollActive ) then Write(' ScrollLockActive');
If Pressed(NumLockActive ) then Write(' NumLockActive');
If Pressed(CapsLockActive) then Write(' CapsLockActive');
If Pressed(InsActive ) then Write(' InsActive');
Writeln;
TextAttr:=LightGray;
end;
begin
while keypressed do readkey; {Очистить буфер клавиатуры}
flags:=GetFlags; {начальное состояние флагов}
repeat
newflags:=GetFlags; {новое состояние флагов}
If AnyKeyEvent then begin {если чего-нибудь нажато}
WriteKeyCode;
flags:=newflags; {запомнить состояние флагов}
WriteFlags;
end;
until Key = #27; {Цикл, пока не нажмем Esc}
while keypressed do readkey; {Очистить буфер клавиатуры}
end.
|