Электронная библиотека книг Александра Фролова и Григория Фролова.
Shop2You.ru Создайте свой интернет-магазин
Библиотека
Братьев
Фроловых

Аппаратное обеспечение IBM PC

© Александр Фролов, Григорий Фролов
Том 2, книга 1, М.: Диалог-МИФИ, 1992.

[Назад] [Содеожание] [Дальше]

2.4. Средства BIOS для работы с клавиатурой

Набор функций для работы с клавиатурой, предоставляемый в распоряжение программиста прерыванием BIOS INT 16h, включает в себя функции для выборки кода нажатого символа из буфера с ожиданием нажатия, функции для проверки содержимого буфера и для управления содержимым буфера, функции для изменения скоростных характеристик клавиатуры.

2.4.1. Чтение символа с ожиданием

Функция 00h выполняет чтение кода символа из буфера клавиатуры, если он там есть. Если буфер клавиатуры пуст, программа переводится в состояние ожидания до тех пор, пока не будет нажата какая-нибудь клавиша. Скан-код и ASCII-код нажатой клавиши передаются программе.

Приведем формат вызова функции:

На входе:       AH = 00h
        
На выходе:      AL = ASCII-код символа или 0, если AH содержит
                расширенный ASCII-код символа;

                AH = скан-код или расширенный ASCII-код
                символа, если AL=0;



Приведем таблицу скан-кодов для клавиатуры IBM PC/XT:

----------T----------T------------T-------------T---------------¬
¦01   Esc ¦12   E    ¦23   H      ¦34   . >     ¦45   NumLock   ¦
¦02   1 ! ¦13   R    ¦24   J      ¦35   / ?     ¦46   ScrollLock¦
¦03   2 @ ¦14   T    ¦25   K      ¦36 Shft(прав)¦47   Home [7]  ¦
¦04   3 # ¦15   Y    ¦26   L      ¦37   * PrtSc ¦48   Up   [8]  ¦
¦05   4 $ ¦16   U    ¦27   ; :    ¦38   Alt     ¦49   PgUp [9]  ¦
¦06   5 % ¦17   I    ¦28   " '    ¦39   Пробел  ¦4a   K -       ¦
¦07   6 ^ ¦18   O    ¦29   ` ~    ¦3a   CapsLock¦4b   <-   [4]  ¦
¦08   7 & ¦19   P    ¦2a Shft(лев)¦3b   F1      ¦4c        [5]  ¦
¦09   8 * ¦1a   [ {  ¦2b   \ |    ¦3c   F2      ¦4d   ->   [6]  ¦
¦0a   9 ( ¦1b   ] }  ¦2c   Z      ¦3d   F3      ¦4e   K +       ¦
¦0b   0 ) ¦1c   Enter¦2d   X      ¦3e   F4      ¦4f   End  [1]  ¦
¦0c   - _ ¦1d   Ctrl ¦2e   C      ¦3f   F5      ¦50   Dn   [2]  ¦
¦0d   + = ¦1e   A    ¦2f   V      ¦40   F6      ¦51   PgDn [3]  ¦
¦0e   Bksp¦1f   S    ¦30   B      ¦41   F7      ¦52   Ins  [0]  ¦
¦0f   Tab ¦20   D    ¦31   N      ¦42   F8      ¦53   Del  [.]  ¦
¦10   Q   ¦21   F    ¦32   M      ¦43   F9      ¦               ¦
¦11   W   ¦22   G    ¦33   , <    ¦44   F10     ¦               ¦
L---------¦----------¦------------¦-------------¦----------------



Для остальных клавиш функция 00h прерывания INT 16h возвращает расширенный ASCII-код:

г--------T--------------T--------------T-------------¬
¦ F1   3b¦ Shift-F1   54¦ Ctrl-F1   5e ¦ Alt-F1   68 ¦
¦ F2   3c¦ Shift-F2   55¦ Ctrl-F2   5f ¦ Alt-F2   69 ¦
¦ F3   3d¦ Shift-F3   56¦ Ctrl-F3   60 ¦ Alt-F3   6a ¦
¦ F4   3e¦ Shift-F4   57¦ Ctrl-F4   61 ¦ Alt-F4   6b ¦
¦ F5   3f¦ Shift-F5   58¦ Ctrl-F5   62 ¦ Alt-F5   6c ¦
¦ F6   40¦ Shift-F6   59¦ Ctrl-F6   63 ¦ Alt-F6   6d ¦
¦ F7   41¦ Shift-F7   5a¦ Ctrl-F7   64 ¦ Alt-F7   6e ¦
¦ F8   42¦ Shift-F8   5b¦ Ctrl-F8   65 ¦ Alt-F8   6f ¦
¦ F9   43¦ Shift-F9   5c¦ Ctrl-F9   66 ¦ Alt-F9   70 ¦
¦ F10  44¦ Shift-F10  5d¦ Ctrl-F10  67 ¦ Alt-F10  71 ¦
L--------¦--------------¦--------------¦--------------

г----------T----------T-------------T-------------¬
¦ Alt-A  1e¦ Alt-P  19¦ Alt-3     7a¦ Down  Dn  50¦
¦ Alt-B  30¦ Alt-Q  10¦ Alt-4     7b¦ Left  <-  4b¦
¦ Alt-C  2e¦ Alt-R  13¦ Alt-5     7c¦ Right ->  4d¦
¦ Alt-D  20¦ Alt-S  1f¦ Alt-6     7d¦ Up    Up  48¦
¦ Alt-E  12¦ Alt-T  14¦ Alt-7     7e¦ End       4f¦
¦ Alt-F  21¦ Alt-U  16¦ Alt-8     7f¦ Home      47¦
¦ Alt-G  22¦ Alt-V  2f¦ Alt-9     80¦ PgDn      51¦
¦ Alt-H  23¦ Alt-W  11¦ Alt--     82¦ PgUp      49¦
¦ Alt-I  17¦ Alt-X  2d¦ Alt-=     83¦             ¦
¦ Alt-J  24¦ Alt-Y  15¦             ¦ ^Left     73¦
¦ Alt-K  25¦ Alt-Z  2c¦             ¦ ^Right    74¦
¦ Alt-L  26¦          ¦ Shift-Tab 0f¦ ^End      75¦
¦ Alt-M  32¦ Alt-0  81¦ Ins       52¦ ^Home     77¦
¦ Alt-N  31¦ Alt-1  78¦ Del       53¦ ^PgDn     76¦
¦ Alt-O  18¦ Alt-2  79¦ ^PrtSc    72¦ ^PgUp     84¦
L----------¦----------¦-------------¦--------------



В следующей таблице приведены скан-коды клавиш, имеющихся только на 101-клавишной клавиатуре:

г-------------T------------------T------------------¬
¦ F11       85¦ Alt-Bksp      0e ¦  Alt- Д /      a4¦
¦ F12       86¦ Alt-Enter     1c ¦  Alt- Д *      37¦
¦ Shft-F11  87¦ Alt-Esc       01 ¦  Alt- Д -      4a¦
¦ Shft-F12  88¦ Alt-Tab       a5 ¦  Alt- Д +      4e¦
¦ Ctrl-F11  89¦ Ctrl-Tab      94 ¦  Alt- Д Enter  a6¦
¦ Ctrl-F12  8a¦                  ¦                  ¦
¦ Alt-F11   8b¦ Alt-up     Up 98 ¦ Ctrl- Д /      95¦
¦ Alt-F12   8c¦ Alt-down   Dn a0 ¦ Ctrl- Д *      96¦
¦ Alt-[     1a¦ Alt-left   <- 9b ¦ Ctrl- Д -      8e¦
¦ Alt-]     1b¦ Alt-right  -> 9d ¦ Ctrl- Д +      90¦
¦ Alt-;     27¦                  ¦                  ¦
¦ Alt-'     28¦ Alt-Delete    a3 ¦ Ctrl- Д Up [8] 8d¦
¦ Alt-`     29¦ Alt-End       9f ¦ Ctrl- Д 5  [5] 8f¦
¦ Alt-\     2b¦ Alt-Home      97 ¦ Ctrl- Д Dn [2] 91¦
¦ Alt-,     33¦ Alt-Insert    a2 ¦ Ctrl- Д Ins[0] 92¦
¦ Alt-.     34¦ Alt-PageUp    99 ¦ Ctrl- Д Del[.] 93¦
L-------------¦------------------¦-------------------



Буква "Д" в последней таблице обозначает дополнительную ("калькуляторную") клавиатуру.

Для демонстрации использования функции 00h прерывания INT 16h мы подготовили программу, выводящую на экран скан-коды и ASCII-коды нажимаемых клавиш:

#include <stdio.h>
#include <dos.h>

void main(void);

void main(void) {

        union REGS  rg;

        printf("\nОпределение скан-кода и ASCII-кода клавиш."
          "\nДля завершения работы нажмите клавишу ESC.\n\n");

        for(;;) {

// Вызываем прерывание INT 16h

                rg.h.ah = 0;
                int86(0x16, &rg, &rg);

// Выводим на экран содержимое регистров AH и AL,
// содержащих, соответственно, скан-код и ASCII-код
// нажатой клавиши.

                printf("\nScan = %02.2X Ascii = %02.2X",
                        rg.h.ah,
                        rg.h.al);

// Если была нажата клавиша ESC, завершаем работу программы

                if(rg.h.ah == 1) break;

        }
}


2.4.2. Проверка буфера на наличие в нем символов

На входе:       AH = 01h.

На выходе:      ZF = 0, если в буфере имеется код нажатой
                        на клавиатуре клавиши;

                ZF = 1, если буфер клавиатуры пуст;

                AL = ASCII-код символа или 0, если AH содержит
                      расширенный ASCII-код символа;

                AH = скан-код или расширенный ASCII-код
                      символа, если AL=0.


Функция 01h поможет вам проверить состояние буфера клавиатуры - есть там коды нажатых клавиш или нет. При этом программа не переводится в состояние ожидания, даже если буфер клавиатуры пуст. В этом случае в регистре флагов устанавливается в единицу флаг ZF и управление возвращается программе.

Эту функцию удобно использовать во время выполнения какого-либо длительного процесса (например, форматирования диска или передачи данных по линии связи) для прерывания этого процесса по запросу оператора.

Кроме того, функцию можно использовать вместе с функцией 00h для сброса содержимого клавиатурного буфера. Для этого в цикле повторяют вызов функции 01h, вслед за которым идет вызов функции 00h при условии, что буфер клавиатуры не пуст. Сброс клавиатурного буфера полезно выполнять перед вводом ответственной информации, так как из-за случайного двойного или тройного нажатия на клавишу в буфере клавиатуры могут оказаться лишние символы.

Приведем текст программы, выводящей на экран в цикле символ '*'. При нажатии на любую клавишу, кроме ESC, программа выводит на экран строку текста - инструкцию для завершения работы программы. Если нажать на клавишу ESC, работа программы будет завершена.

#include <stdio.h>
#include <dos.h>

void main(void);

void main(void) {

        union REGS  rg;
        int   i, zflag;


        for(;;) {

// Выводим в цикле символ '*'

                putchar('*');

// Небольшая задержка во времени

                for(i=0; i<1000; i++);

// Вызываем прерывание INT 16h для проверки буфера клавиатуры

// Устанавливаем флаг, который будет сброшен при нажатии на
// любую клавишу

                zflag = 1;

                _asm {

                        mov   ax, 0100h
                        int   16h

// Если нажатия не было,
// продолжаем выполнение программы

                        jz    nokey       

// При нажатии на любую клавишу
// сбрасываем флаг

                        mov   zflag, 0
nokey:

                }

                if(zflag == 0) {

// Если флаг сброшен, читаем код нажатой клавиши из буфера
// при помощи функции 01h прерывания INT 16h

                        rg.h.ah = 0;
                        int86(0x16, &rg, &rg);

// Если была нажата клавиша ESC, завершаем работу программы

                        if(rg.h.ah == 1) {

// Выводим на экран содержимое регистров AH и AL,
// содержащих, соответственно, скан-код и ASCII-код
// нажатой клавиши.

                                printf("\nScan = %02.2X Ascii = %02.2X",
                                        rg.h.ah,
                                        rg.h.al);

                                        break;
                        }
                        else printf("\nДля завершения нажмите ESC\n");
                }
        }
}


2.4.3. Получение состояния переключающих клавиш

На входе:       AH = 02h
        
На выходе:      AL = Байт состояния переключающих клавиш



Функция возвращает в регистре AL состояние переключающих клавиш (Shift, Ctrl, Alt, ScrollLock, NumLock, CapsLock, Ins). Формат байта состояния соответствует формату байта, находящегося в области данных BIOS по адресу 0000h:0417h:

Биты    Значение


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

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

2       Нажата комбинация клавиш Ctrl-Shift с любой
        стороны.

3       Нажата комбинация клавиш Alt-Shift с любой
        стороны.

4       Состояние клавиши ScrollLock.

5       Состояние клавиши NumLock.

6       Состояние клавиши CapsLock.

7       Состояние клавиши Insert.


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

Изменим текст предыдущей программы таким образом, чтобы завершение ее работы происходило лишь в том случае, если переключающая клавиша CapsLock находится в выключенном состоянии (соответствующий светодиод не горит):

#include <stdio.h>
#include <dos.h>

void main(void);

void main(void) {

        union REGS  rg;
        int   i, zflag;


        for(;;) {

// Выводим в цикле символ '*'

                putchar('*');

// Небольшая задержка во времени

                for(i=0; i<1000; i++);

// Вызываем прерывание INT 16h для проверки буфера клавиатуры

// Устанавливаем флаг, который будет сброшен при нажатии на
// любую клавишу

                zflag = 1;

                _asm {

                        mov   ax, 0100h
                        int   16h

// Если нажатия не было,
// продолжаем выполнение программы

                        jz    nokey

// При нажатии на любую клавишу
// сбрасываем флаг

                        mov   zflag, 0 
nokey:

                }

                if(zflag == 0) {

// Если флаг сброшен, читаем код нажатой клавиши из буфера
// при помощи функции 01h прерывания INT 16h

                        rg.h.ah = 0;
                        int86(0x16, &rg, &rg);

// Если была нажата клавиша ESC, завершаем работу программы,
// при условии, что переключатель CapsLock выключен

                        if(rg.h.ah == 1) {

// Дополнительно проверяем состояние клавиши CapsLock,
// этой клавише соответствует бит 0x40 в слове состояния

                                rg.h.ah = 2;
                                int86(0x16, &rg, &rg);

                                if((rg.h.al & 0x40) == 0) break;

                                else printf("\nДля завершения нажмите"
                                  " ESC "
                                  "при выключенной клавише CapsLock.\n");
                        }
                        else printf("\nДля завершения нажмите ESC "
                                  "при выключенной клавише CapsLock.\n");
                }
        }
}


2.4.4. Установка временных характеристик клавиатуры

На входе:       AH = 03h;

                AL = 05h;

                BL = Период автоповтора (количество повторов
                     за одну секунду):

                        0 - 30.0;       0Ah - 10.0;
                        1 - 26.7;       0Dh -  9.2;
                        2 - 24.0;       10h -  7.5;
                        4 - 20.0; 14h -  5.0;
                        8 - 15.0;       1Fh -  2.0.

                BH =    Задержка включения режима автоповтора:

                        0 - 250 мс;
                        1 - 500 мс;
                        2 - 750 мс;
                        3 - 1000 мс.
        
На выходе:      Не используются.



Мы уже рассказывали о возможности изменения временных характеристик клавиатуры. Если BIOS, установленная в вашей машине, изготовлена после 15 декабря 1985 года, вы можете воспользоваться этой функцией для ускорения (или замедления) работы клавиатуры.

В качестве примера приведем две программы. Первая программа увеличивает быстродействие клавиатуры до его верхнего предела, вторая восстанавливает исходные значения временных характеристик.

#include <stdio.h>
#include <dos.h>

void main(void);

void main(void) {

        union REGS  rg;


                rg.h.al = 5;
                rg.h.ah = 3;

// Устанавливаем максимальное быстродействие клавиатуры

                rg.h.bl = 0;
                rg.h.bh = 0;

                int86(0x16, &rg, &rg);

}
#include <stdio.h>
#include <dos.h>

void main(void);

void main(void) {

        union REGS  rg;


                rg.h.al = 5;
                rg.h.ah = 3;

// Восстанавливаем исходное быстродействие клавиатуры

                rg.h.bl = 0xa;
                rg.h.bh = 1;

                int86(0x16, &rg, &rg);

}


2.4.5. Запись символов в буфер клавиатуры

На входе:       AH = 05h;

                CL = ASCII-код записываемого символа;

                CH = скан-код записываемого символа, или 0.
        

На выходе:      AL = 0  - запись выполнена успешно;
                1       - буфер клавиатуры переполнен.



С помощью этой функции можно вставить символы в буфер клавиатуры, как будто они были введены оператором.

Приведенная программа записывает в буфер клавиатуры пять символов '*'. Запустите ее и посмотрите на системное приглашение. Вы увидите что-нибудь похожее на C:\>*****.

#include <stdio.h>
#include <dos.h>

void main(void);

void main(void) {

        union REGS  rg;
        int   i;

         for(i=0; i<5; i++) {

                rg.h.ah = 5;

                rg.h.cl = '*';
                rg.h.ch = 9;

                int86(0x16, &rg, &rg);

         }
}


2.4.6 Чтение символа с ожиданием для 101-клавишной клавиатуры

Функция 10h полностью аналогична функции 00h, но она предназначена для работы с клавиатурой, имеющей 101 клавишу.

Приведем формат вызова функции:

На входе:       AH = 10h.
        
На выходе:      AL = ASCII-код символа или 0, если AH содержит
                расширенный ASCII-код символа;

                AH = скан-код или расширенный ASCII-код
                символа, если AL=0.


Функция определена для BIOS, изготовленной не раньше 15 декабря 1985 года.

2.4.7. Проверка буфера на наличие в нем символов для 101-клавишной клавиатуры

На входе:       AH = 11h.

На выходе:      ZF = 0, если в буфере имеется код нажатой
                        на клавиатуре клавиши;

                ZF = 1, если буфер клавиатуры пуст;

                AL = ASCII-код символа или 0, если AH содержит
                        расширенный ASCII-код символа;

                AH = скан-код или расширенный ASCII-код
                        символа, если AL=0.


Функция 11h полностью аналогична функции 01h, но она предназначена для работы с клавиатурой, имеющей 101 клавишу.

Эта функция определена для BIOS, изготовленной не раньше 15 декабря 1985 года.

2.4.8. Получение состояния переключающих клавиш для 101-клавишной клавиатуры

На входе:       AH = 12h.
        
На выходе:      AL = Байт состояния переключающих клавиш.



Функция возвращает в регистре AL состояние переключающих клавиш (Shift, Ctrl, Alt, ScrollLock, NumLock, CapsLock, Ins):

Биты    Значение

0       Нажата левая клавиша Shift вместе с Ctrl.
1       Нажата левая клавиша Shift вместе с Alt.
2       Нажата правая клавиша Shift вместе с Ctrl.
3       Нажата правая клавиша Shift вместе с Alt.
4       Нажата клавиша ScrollLock.
5       Нажата клавиша NumLock.
6       Нажата клавиша CapsLock.
7       Нажата клавиша SysReq.


Функция 12h аналогична функции 02h, но она предназначена для работы с клавиатурой, имеющей 101 клавишу и имеет другой формат байта состояния.

Эта функция определена для BIOS, изготовленной не раньше 15 декабря 1985 года.

[Назад] [Содеожание] [Дальше]