21.5. Анализ клавиш регистров и их состояния

К клавишам регистров относятся клавиши Alt, Shift, Ctrl, а также переключатели Ins, CapsLock, NumLock, ScrollLock и т.п. Все они отличаются тем, что, будучи нажаты, сами по себе они не возвращают никаких символов. Это значит, что нельзя определить, нажата ли клавиша регистра или отпущена (если другие клавиши при этом не нажимаются) при помощи стандартных процедур ввода-вывода.

Регистровые клавиши при нажатии устанавливают определенные биты фиксированных байтов системной памяти MS-DOS. В полностью совместимых с IBM PC ПЭВМ таких байтов два. Они имеют адреса $0000:$0417 и $0000:$0418 (адреса даны в шестнадцатеричном формате).

В байте $417 каждый бит имеет свое значение: 1 — если режим включен или комбинация клавиш нажата, и 0 в противном случае. На рис. 21.6 и 21.7 приведены расшифровки битов состояния клавиатуры. Справа от таблиц указаны десятичные значения весов соответствующих битов. Значение байта $417 или $418 равно сумме весов ненулевых битов.

Вес -- Бит -- Байт 0:$417

1 -- 0 -- Нажата правая клавиша Shift

2 -- 1 -- Нажата левая клавиша Shift

4 -- 2 -- Нажата клавиша Ctrl

8 -- 3 -- Нажата клавиша Alt

16 -- 4 -- Отмена прокрутки (ScrollLock)

32 -- 5 -- Регистр цифр (NumLock)

64 -- 6 -- Регистр букв (CapsLock)

128 -- 7 -- Режим вставки/замещения (Ins)

Рис. 21.6

Байт $418 содержит указатели на состояние самих клавиш режимов. Если соответствующий бит содержит 1, то клавиша в момент опроса нажата.

Биты 0...2 имеют смысл только на 101-клавишной клавиатуре. В противном случае они считаются зарезервированными и не используются.

- 503 -

Вес -- Бит -- Байт 0:$418

1 -- 0 -- 1 если нажаты Ctrl + Shift

2 -- 1 -- 1 если нажаты Alt + Shift

4 -- 2 -- Зависит от типа ПЭВМ и клавиатуры

8 -- 3 -- Зависит от типа ПЭВМ и клавиатуры

16 -- 4 -- 1 если нажата ScrollLock

32 -- 5 -- 1 если нажата NumLock

64 -- 6 -- 1 если нажата CapsLock

128 -- 7 -- 1 если нажата Ins

Рис. 21.7

Если же клавиатура имеет специальный контроллер на 101 клавишу, то содержимое бита $418 будет немного другим. Лучше не использовать различающиеся биты, чтобы не терять переносимость программ.

На рис. 21.8 приведен текст программы, с помощью которой можно посмотреть на изменения битов при нажатиях клавиш регистров.

| USES CRT; { ФУНКЦИЯ ПРЕДСТАВЛЕНИЯ ЧИСЛА В ДВОИЧНОМ ВИДЕ}

| FUNCTION Binary(X : Longint; NumOfBits : Byte) : String;

| VAR

| bit, i : Byte; { вспомогательные переменные }

| s : String[32];

| BEGIN

| s:=''; { обязательная чистка строки }

| for i:=0 to 31 do begin { цикл перевода }

| bit := ( X shl i ) shr ( 31 ); { выделение бита }

| s := s + Chr( Ord( '0' ) + bit ) { запись в строку }

| end; (for) { конец цикла }

| { Оставляем в строке лишь NumOfBits битов справа: }

| Delete( s, 1, 32-NumOfBits );

| Binary := s { возвращаемая строка }

| END;

| VAR

| M:Byte absolute $000:$417; { можно изменить на $418 }

| BEGIN

| ClrScr;

| CheckBreak := True; { разрешить прерывание }

| Repeat

| WriteLn( M:10, ' ', Binary( M, 8 ) );

| until False { условие вечного цикла }

| END.

Рис. 21.8

- 504 -

После запуска программы нажимайте на клавиши Shift, Ctrl, Alt, CapsLock, NumLock, Ins и смотрите за состоянием битов. Закончить работу программы можно лишь нажав Ctrl+Break.

Зная значения битов, легко управлять состоянием фиксированных режимов и опрашивать регистры и их клавиши. Библиотека процедур и функций, управляющих регистрами клавиатуры, может иметь вид, показанный на рис. 21.9.

| TYPE { типы клавиш режимов }

| КеуТуре = ( Ins, Caps, Num, Scroll );

| {функция возвращает True, если включен режим xxxLock.}

| FUNCTION GetLockKey( Lock : КеуТуре ) : Boolean;

| VAR Bit : Byte;

| BEGIN

| case Lock of

| Ins : Bit = $60; {128}

| Caps : Bit*$40; { 64}

| Num : Bit = $20; { 32}

| Scroll : Bit = $10 { 16}

| end; {case}

| if ( Mem[0:$417] and Bit ) = Bit { бит включен? }

| then GetLockKey := True { да }

| else GetLockKey := False { нет }

| END;

| PROCEDURE SetLockKey( Lock : КеуТуре; В : Boolean );

| VAR

| M : Byte absolute 0:$417; { байт состояния }

| Bit : Byte;

| BEGIN

| case Lock of

| Ins Bit := $60; {128}

| Caps Bit := $40; { 64}

| Num Bit := $20; { 32}

| Scroll Bit := $10 { 16}

| end; {case}

| case В of

| True : M := M or Bit; { включить xxxLock }

| False : M := M and (255-Bit); { выключить xxxLock }

| end {case}

| END;

Рис. 21.9

- 505 -

| BEGIN { ПРИМЕР ВЫЗОВОВ }

| SetLockKey( Caps, True );

| { включить CapsLock }

| Write( 'Введите любой текст ' );

| ReadLn;

| SetLockKey(Caps, not GetLockKey(Caps));

| { наоборот } Write( 'Режим стал обратным ');

| ReadLn;

| END.

Рис. 21.9 (окончание)

Пример на рис. 21.9 переключает режимы, но не влияет на свечение индикаторов, которое управляется на разных классах ПЭВМ через различные порты.

С помощью подобных функций программа может так управлять вводом, что не будет нужды нажимать клавиши регистров. Сам факт нажатия клавиш регистров Shift, Ctrl и Alt может быть программно проанализирован путем опроса ячеек памяти 0:$417 и 0:$418. Если, например, надо проверить, нажата ли левая клавиша Shift (бит 1 в байте 0:$417 равен 1), то логическая функция должна иметь следующий вид:

if (Mem[0:$417] and 2) = 2 then ... {да, левый Shift нажат}

else ... { нет };

Если надо проверить нажатие правой и левой клавиш Shift одновременно, то условие немного изменится:

if (Mem[0:$417] and (2+1))=(2+1) then {да, обе Shift нажаты}

else { нет };

Подобные опросы можно применять при написании процедур запроса паролей, если паролем доступа к работе с программой делать комбинации типа Alt+Shift и т.п. Но подобная система опроса работает только при длительном нажатии клавиш регистров. Ведь в момент нажатия программа может не анализировать состояние регистров, и тогда информация проскочит «мимо». Четко отловить факт нажатия клавиш регистров можно лишь с помощью анализа скэн-кодов клавиш, перехватывая прерывания от клавиатуры (см. пример на рис. 21.11).