Страница 2 из 26
3.1.1 Очистка буфера клавиатуры. Программа должна очистить буфер клавиатуры, перед тем, как выдать запрос на ввод, исключая тем самым посторонние нажатия клавиш, которые могут к тому времени накопиться в буфере. Буфер может накапливать до 15 нажатий на клавишу, независимо от того, являются ли они однобайтными кодами ASCII или двухбайтными расши- ренными кодами. Таким образом, буфер должен отвести два байта памяти для каждого нажатия на клавишу. Для однобайтных кодов первый байт содержит код ASCII, а второй - скан-код клавиши. Для расширенных кодов первый байт содержит ASCII 0, а второй номер расширенного кода. Этот код обычно совпадает со скан-кодом клави- ши, но не всегда, поскольку некоторые клавиши могут комбиниро- ваться с клавишами сдвига для генерации различных кодов. Буфер устроен как циклическая очередь, которую называют также буфером FIFO (первый вошел - первый ушел). Как и любой буфер он занимает непрерывную область адресов памяти. Однако не имеется определенной ячейки памяти, которая хранит "начало строки" в буфере. Вместо этого два указателя хранят позиции головы и хвоста строки символов, находящейся в буфере в текущий момент. Новые нажатия клавиш запасаются в позициях, следующих за хвостом (в более старших адресах памяти) и соответственно обновляется указа- тель хвоста буфера. После того, как израсходовано все буферное пространство, новые символы продолжают вставляться, начиная с самого начала буферной области; поэтому возможны ситуации, когда голова строки в буфере имеет больший адрес, чем хвост. После того как буфер заполнен, новые вводимые символы игнорируются, при этом прерывание клавиатуры выдает гудок через динамик. На рис. 3-2 показаны некоторые возможные конфигурации данных в буфере. В то время как указатель на голову установлен на первый вве- денный символ, указатель на хвост установлен на позицию за пос- ледним введенным символом. Когда оба указателя равны, то буфер пуст. Чтобы разрешить ввод 15 символов требуется 16-я пустая позиция, 2 байта которой всегда содержат код возврата каретки (ASCII 13) и скан-код клавиши <Enter>, равный 28. Эта пустая позиция непосредственно предшествует голове строки символов. 32 байта буфера начинаются с адреса 0040:001E. Указатели на голову и хвост расположены по адресам 0040:001A и 0040:001C, соответствен- но. Хотя под указатели отведено 2 байта, используется только младший байт. Значения указателей меняются от 30 до 60, что соот- ветствует позициям в области данных BIOS. Для очистки буфера надо просто установить значение ячейки 0040:001A равным значению ячей- ки 0040:001C. Отметим, что программа имеет возможность вставлять символы в буфер, завершая строку символом возврата каретки и соответственно меняя значения указателей. Если это проделать правильным образом перед завершением программы, то при возврате управления в MS DOS эти символы будут считаны и может быть автоматически загружена другая программа.
Низкий уровень. В Бейсике для получения и изменения значений указателей буфера используются операторы PEEK и POKE:
100 DEF SEG = &H40 'устанавливаем значение сегмента 110 POKE &H1C, PEEK(&H1A) 'выравниваем указатели
Этот метод не самый лучший. Некоторые программы могут создавать буфер где-нибудь в другом месте памяти, а кроме того, всегда существует возможность, что посреди строки 110 произойдет преры- вание клавиатуры, которое изменит указатель хвоста. По этим при- чинам лучше оставить указатели буфера в покое. Вместо этого, лучше читать из буфера до тех пор, пока не будет возвращен символ ASCII 0, показывающий, что буфер пуст:
100 IF INKEY$<>"" THEN 100 'берем следующее если не нуль
Средний уровень. Функция 0C прерывания 21H выполняет любую из функций ввода с клавиатуры 1, 6, 7, 8 и A (описанных в этой главе), но перед этим чистит буфер клавиатуры. Надо просто поместить номер функции ввода в AL (в этом примере - 1):
;---очистка буфера перед ожиданием нажатия клавиши MOV AH,0CH ;выбираем функцию DOS 0CH MOV AL,1 ;выбираем функцию ввода символа INT 21H ;чистим буфер, ждем ввода
Низкий уровень. Как и в примере высокого уровня делаем значение указателя на хвост равным значению указателя на голову. Для избежания влияния прерывания клавиатуры запрещаем прерывания на время модификации указателя:
;---выравниваем значения указателей на голову и хвост CLI ;запрещаем прерывания SUB AX,AX ;обнуляем регистр MOV ES,AX ;добавочный сегмент - с начала памяти MOV AL,ES:[41AH] ;берем указатель на голову буфера MOV ES:[41CH],AL ;посылаем его в указатель хвоста STI ;разрешаем прерывания
|