ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 04.07.2020
Просмотров: 3180
Скачиваний: 1
ки, но он не учитывается в результате, который функция помещает
во второй байт дескриптора строки. Таким образом, для получения
50-символьной строки надо отвести 53 байта памяти и поместить в
первый байт ASCII 51. После ввода 50 символов второй байт будет
содержать ASCII 50, а 53-й байт отведенной памяти - ASCII 13.
;---в сегменте данных
STRING DB 53 DUP(?) ;область для строки 50 символов
;---получение строки с клавиатуры
LEA DX,STRING ;DS:DX указывают на адрес строки
MOV BX,DX ;пусть BX тоже указывает на строку
MOV AL,51 ;установка длины строки (+1 для CR)
MOV [BX],AL ;посылаем в 1-й байт дескриптора
MOV AH,0AH ;номер функции
INT 21H ;получаем строку
;---проверка длины строки
MOV AH,[BX]+1 ;теперь длина в AH
В этой процедуре можно использовать возможности редактирования
строки MS DOS. Нажатие клавиши забой или "стрелка-влево" удаляет
символ с экрана, а также не помещает его в память. Работает кла-
виша табуляции, расширенные коды игнорируются, пустые строки
допускаются (имеется ввиду возврат каретки, которому не предшест-
вует другого символа). На терминале при достижении правого края
строка переносится на следующую строку, а при достижении правого
нижнего угла экран сдвигается на строку вверх. Когда вводится
больше символов, чем отведено места для строки, то лишние символы
игнорируются и включается гудок динамика.
MS DOS обеспечивает и другой способ получения строки, при
котором не выводится эхо на терминал. Функция 3FH прерывания 21H
- это функция ввода общего назначения, которая чаще всего исполь-
зуется при дисковых операциях. Она требует предопределенного
дескриптора файла (file handle), который является кодовым числом,
используемым операционной системой для обозначения устройства
ввода/вывода. Для клавитуры используется дескриптор 0 и он должен
быть помещен в BX. Поместите в DS:DX адрес, по которому должна
находиться строка, а в CX - максимальную длину строки и вызовите
функцию:
;---чтение строки без эха
MOV AH,3FH ;номер функции
MOV BX,0 ;номер дескриптора файла
LEA DX,STRING_BUFFER ;указатель на буфер ввода строки
MOV CX,100 ;максимальная длина строки
INT 21H ;ждем ввода
Ввод строки завершается нажатием клавиши возврат каретки и DOS
добавляет в конец строки два символа: возврат каретки и перевод
строки (ASCII 13 и ASCII 10). Из-за этих добавочных символов, при
указании длины строки 100 символов она может занимать до 102 байт
памяти. Длина введенной строки возвращается в AX и это значение
включает два символа-ограничителя.
3.1.7 Проверка/установка статуса клавиш-переключателей.
Два байта, расположенные в ячейках памяти 0040:0017 и
0040:0018 содержат биты, отражающие статус клавиши сдвига и дру-
гих клавиш-переключателей следующим образом:
Бит Клавиша Значение, когда бит = 1
0040:0017 7 Insert режим вставки включен
6 CapsLock режим CapsLock включен
5 NumLock режим NumLock включен
4 ScrollLock режим ScrollLock включен
3 Alt клавиша нажата
2 Ctrl клавиша нажата
1 левый Shift клавиша нажата
0 правый Shift клавиша нажата
0040:0018 7 Insert клавиша нажата
6 CapsLock клавиша нажата
5 NumLock клавиша нажата
4 ScrollLock клавиша нажата
3 Ctrl-NumLock режим Ctrl-NumLock включен
остальные биты не используются
Прерывание клавиатуры немедленно обновляет эти биты статуса,
как только будет нажата одна из клавиш-переключателей, даже если
не было считано ни одного символа из буфера клавиатуры. Это верно
и для клавиши Ins, которая единственная из этих 8 клавиш помещает
код в буфер (установка статуса Ins меняется даже если в буфере
нет места для символа). Отметим, что бит 3 по адресу 0040:0018
устанавливается в 1, когда действует режим задержки Ctrl-NumLock;
поскольку в этом состоянии программа приостановлена, то этот бит
несущественен.
Прерывание клавиатуры проверяет состояние статусных битов
перед тем, как интерпретировать нажатые клавиши, поэтому когда
программа меняет один из этих битов, то эффект такой же, как при
физическом нажатии соответствующей клавиши. Вы можете захотеть
установить состояние клавиш NumLock и CapsLock, чтобы быть уве-
ренным, что ввод будет требуемого вида. Наоборот, Ваша программа
может нуждаться в чтении статуса этих клавиш, например для того,
чтобы вывести текущий статус на экран. Отметим, что клавиатура AT
правильно устанавливает световые индикаторы состояния клавиш,
даже если переключены программно.
Высокий уровень.
В данном примере клавиша NumLock переводится в режим, когда
клавиши дополнительной клавиатуры используются для перемещения
курсора, за счет сбрасывания бита 5 по адресу 0040:0017 в 0. Это
достигается за счет операции логического "И" значения, располо-
женного по этому адресу с числом 223 (цепочка битов 11011111B -
описание логики битовых операций см. в Приложении Б). Результат
помещается в байт статуса. В примере затем восстанавливается
значение этого бита в 1, за счет логического "ИЛИ" с 32
(00100000B).
100 DEF SEG = &H40 'устанавливаем сегмент на область
110 STATUSBYTE=PEEK(&H17) 'BIOS и берем байт статуса
120 NEWBYTE=STATUSBYTE AND 223 'обнуляем бит 5
130 POKE(&H17,NEWBYTE) 'посылаем новое значение статуса
Чтобы, наоборот, включить этот бит:
120 NEWBYTE=STATUSBYTE OR 32 'устанавливаем бит 5
130 POKE(&H17,NEWBYTE) 'посылаем новое значение статуса
Строки 110-130 могут быть уплотнены к виду:
110 POKE(&H417,PEEK(&H417)AND 223)
или
110 POKE(&H417,PEEK(&H417)OR 223)
Средний уровень.
Функция 2 прерывания 16H предоставляет доступ к одному - но
только одному - из байтов статуса. Это байт по адресу 0040:0017,
который содержит больше полезной информации. Байт возвращается в
AL.
;---проверка статуса клавиши вставки
MOV AH,2 ;номер функции
INT 16H ;получаем байт статуса
TEST AL,10000000B ;проверяем бит 7
JZ INSERT_OFF ;если 0, то INSERT выключен
Низкий уровень.
В данном примере устанавливается режим вставки, за счет уста-
новки бита 7 байта статуса по адресу 0040:0017 (который адресует-
ся как 0000:0417).
SUB AX,AX ;устанавливаем добавочный сегмент на
MOV ES,AX ;начало памяти
MOV AL,10000000B ;готовим бит 7 к установке
OR ES:[417H],AL ;меняем байт статуса
3.1.8 Написание процедуры ввода с клавиатуры общего назначения.
Система кодов, используемых клавиатурой, не поддается простой
интрепретации. Коды могут иметь длину 1 или 2 байта и нет просто-
го соответствия между длиной кода и тем, служит ли он для обозна-
чения символа или для управления оборудованием. Не все комбинации
клавиш даже выдают уникальный код, поэтому необходимы добавочные
усилия, чтобы различить их. Ни коды ASCII, ни расширенные коды не
упорядочены таким образом, который бы позволил их простую группи-
ровку и проверку ошибок. Другими словами, процедура ввода с кла-
виатуры общего назначения требует хлопотливого программирования.
Здесь приведены примеры на Бейсике и с использованием прерыва-
ния 16H. В них показано как свести вместе большинство информации,
приведенной в данной главе. Общий алгоритм показан на рис. 3-3.
Высокий уровень.
Процедура обработки ввода с клавиатуры, написанная на Бейсике,
может делать все что делает ассемблерная процедура, за одним
исключением. Функция INKEY$ не предоставляет доступа к скан-ко-
дам. Это означает, что Вы не можете сказать получены ли коды
ASCII 8, 9, 13 и 27 от нажатия клавиш <BackSpace>, <Tab>, <Enter>
и <Escape> или через Ctrl-H, -I, -M и -[. Различие может быть
установлено проверкой бита статуса клавиши Ctrl, по адресу
0040:0017, в момент нажатия клавиши. Но этот метод не будет рабо-
тать, если введенный символ был запасен в буфере клавиатуры в
течение некоторого времени.
100 C$=INKEY$:IF C$="" THEN 100 'получение символа
110 IF LEN(C$)=2 THEN 700 'если расширенный, то на 700
120 C=ASC(C$) 'иначе берем номер кода ASCII
130 IF C<32 THEN 300 'если управляющий, то на 300
140 IF C<65 OR C>123 THEN 100 'принимаем только символы
150 '''пишущей машинки и делаем с ними, что хотим, например:
160 S$=S$+C$ 'добавляем символ к строке
170 PRINT C$; 'выводим его на экран
180 '''... и т.д.
190 GOTO 100 'на ввод следующего символа
.
.
300 '''процедура обработки управляющих кодов ASCII
310 DEF SEG = 0 'указываем на начало памяти
320 REGISTER=PEEK(&H417) 'берем регистр статуса
330 X=REGISTER AND 4 'X=4, когда нажат Ctrl
340 IF X=0 THEN 500 'если не нажат, то на 500
350 '''если это комбинация Ctrl-буква, то делаем что хотим
360 IF C=8 THEN GOSUB 12000 'например, переходим на проце-
370 '''дуру вывода экрана помощи и т.д.
380 GOTO 100 'на ввод следующего символа
.
.
500 '''процедура обработки 4-х клавиш: декодирует коды ASCII 8,
510 '''9, 13 и 27, когда клавиша Ctrl не нажата
520 IF C=8 THEN GOSUB 5000 'обработка <BackSpace>
530 IF C=9 THEN GOSUB 6000 'обработка <Tab>
540 IF C=13 THEN GOSUB 7000 'обработка <CR>
550 IF C=27 THEN GOSUB 8000 'обработка <Esc>
560 GOTO 100 'на ввод следующего символа
.
.
700 '''процедура обработки расширенных кодов
710 C$=RIGHT$(C$,1) 'берем только 2-й байт C$
720 C=ASC(C$) 'переводим в числовую форму
730 '''в C - расширенный код - делаем с ним, что хотим, например
740 IF C<71 OR C>81 THEN 100 'берем только управление курсором
750 IF C=72 THEN GOSUB 3500 'обработка "курсор-вверх"
760 '''... и т.д.
770 GOTO 100 'на ввод следующего символа
Средний уровень.
Этот пример отличается от предыдущего методом распознавания
четырех частных случаев Ctrl-H, -I, -M и -[. Здесь, когда встает
вопрос о том, возник ли указанный код при нажатии одной клавиши,
или в комбинации с клавишей Ctrl, проверяется скан-код. Этот
метод более правилен, чем проверка бита статуса, так как скан-код
запоминается в буфере клавиатуры, а установка бита статуса может
быть изменена.
;---получение кода нажатой клавиши и определение его типа
NEXT: MOV AH,0 ;функция ввода с клавиатуры BIOS
INT 16H ;получаем введенный код
CMP AL,0 ;проверка на расширенный код
JE EXTENDED_CODE ;если да, то на спец. процедуру
CMP AL,32 ;проверка на управляющий символ
JL CONTROL_CODE ;если да, то на спец. процедуру
CMP AL,65 ;если символ не входит в набор пишу-
JL NEXT ;щей машинки, то берем следующий
CMP AL,123 ;
JL NEXT ;
;---теперь обрабатываем символ в AL
STOSB ;запоминаем символ по адресу ES:DI
MOV AH,2 ;функция вывода символа на экран
MOV DL,AL ;помещаем символ в DL перед выводом
INT 21H ;выводим его на экран
.
.
JMP NEXT ;переходим к следующему символу
;---анализируем управляющие коды
CONTROL_CODE: CMP AL,13 ;код ASCII 13?
JNE TAB ;если нет, то след. проверка
CMP AH,28 ;иначе проверяем скан-код <CR>
JNE C_M ;если нет, то было Ctrl-M
CALL CARRIAGE_RET;обработка возврата каретки
JMP NEXT ;переход к следующему символу
C_M: CALL CTRL_M ;обработка Ctrl-M
JMP NEXT ;переход к следующему символу
TAB: CMP AL,9 ;проверка на табуляцию...
.
.
CMP AL,10 ;затем проверка других
.
.
REJECT: JMP NEXT ;переход к следующему символу
;---анализ расширенных кодов (2-й байт кода в AH):
EXTENDED_CODE: CMP AH,71 ;проверка нижней границы
JL REJECT ;если меньше, то след. символ
CMP AH,81 ;проверка верхней границы
JL REJECT ;если больше, то след. символ
;---AH содержит символ управления курсором, анализируем его:
CMP AH,72 ;"курсор-вверх"?
JE C_U ;если да, то на процедуру
CMP AH,80 ;"курсор-вниз"?
JE C_D ;если да, то на процедуру
.
.
C_U: CALL CURSOR_UP ;вызов соответствующей процедуры
JMP NEXT ;переход к следующему символу
C_D: CALL CURSOR_DOWN ;вызов соответствующей процедуры
JMP NEXT ;переход к следующему символу
3.1.9 Перепрограммирование прерывания клавиатуры.
Когда микропроцессор клавиатуры помещает скан-код в порт A
микросхемы 8255 (адрес порта 60H - см. [1.1.1]), то при этом
вызывается прерывание 9. Задача этого прерывания - преобразовать
скан-код символа, основываясь на состоянии клавиш-переключателей,
и поместить его в буфер клавиатуры. (Если скан-код соответствует
клавише-переключателю, то в буфер клавиатуры не пишется ничего,
за исключением случая клавиши <Ins>, а вместо этого прерывание
изменяет байты статуса, расположенные в области данных BIOS
[3.1.7]). Прерывания "ввода с клавиатуры" DOS и BIOS на самом
деле всего лишь прерывания "ввода из буфера клавиатуры". На самом
деле они не распознают нажатия клавиш. Точнее, они читают интерп-
ретацию введенных клавиш, которую обеспечило прерывание 9. Заме-
тим, что PCjr использует специальную процедуру (INT 48H) для
преобразования ввода от его 62 клавиш к 83-клавишному протоколу,
используемому другими IBM PC. Результат этой процедуры передается
прерыванию 9, которое выполняет свою работу как обычно. Прерыва-
нием 49H PCjr обеспечивает специальные неклавишные скан-коды,
которые потенциально могут устанавливаться периферийными уст-
ройствами, использующими инфракрасную (беспроволочную) связь с
клавиатурой.
Требуется весьма необычное применение, чтобы имело смысл пе-
репрограммировать это прерывание, особенно учитывая, что MS DOS
позволяет Вам перепрограммировать любую клавишу клавиатуры
[3.2.6]. Если все же Вам придется перепрограммировать прерывание
9, то эта глава даст Вам основы для старта. Сначала надо прочи-
тать [1.2.3], чтобы понимать как программируются прерывания. В
прерывании клавиатуры можно выделить три основных шага:
1. Прочитать скан-код и послать клавиатуре подтвердающий сиг-
нал.
2. Преобразовать скан-код в номер кода или в установку оегист-
ра статуса клавиш-переключателей.
3. Поместить код клавиши в буфер клавиатуры.
В момент вызова прерывания скан-код будет находиться в порте
A. Поэтому сначала надо этот код прочитать и сохранить на стеке.
Затем используется порт B (адрес 61H), чтобы быстро послать сиг-
нал подтверждения микропроцессору клавиатуры. Надо просто устано-
вить бит 7 в 1, а затем сразу изменить его назад в 0. Заметим,
что бит 6 порта B управляет сигналом часов клавиатуры. Он всегда
должен быть установлен в 1, иначе клавиатура будет выключена. Эти
адреса портов применимы и к AT, хотя он и не имеет микросхемы
интерфейса с периферией 8255.
Сначала скан-код анализируется на предмет того, была ли клави-
ша нажата (код нажатия) или отпущена (код освобождения). На всех
машинах, кроме AT, код освобождения индицируется установкой бита
7 скан-кода в 1. Для AT, у которого бит 7 всегда равен 0, код
освобождения состоит из двух байтов: сначала 0F0H, а затем
скан-код. Все коды освобождения отбрасываются, кроме случая кла-