содержат адрес строки, а сами дескрипторы хранятся в массиве
отдельно от строк. Длина строки хранится в третьем байте 3-байт-
ного дескриптора. С другой стороны, DOS хранит длину строки прямо
в начале самой строки и для программы достаточно знать положение
строки в памяти.
Высокий уровень.
Бейсик может принимать с и без автоматического эха на экране.
Более просто делается ввод с эхом, так как он выполняется
встроенной функцией ввода строки INPUT. INPUT автоматически соби-
рает вводимые символы, выводя их на экран по мере получения. При
нажатии клавиши ввод завершается и значение строки прис-
ваивается указанной переменной (посылаемый клавишей код
ASCII 13 не добавляется к строке). INPUT допускает возможность
редактирования строки, предоставляемую DOS, поэтому опечатки
могут быть исправлены перед вводом строки. INPUT принимает числа
в ввиде строки и автоматически преобразует их в числовую форму,
если для ввода будет указано имя числовой переменной. Hаконец,
INPUT может выдавать на экран строку, запрашивающую пользователя
о требуемой информации. Такая строка может быть длиной до 254
символов. Если ее длина больше, то лишние символы игнорируются.
Основная форма этого оператора INPUT "запрос", имя_переменной.
Полное описание этого опертора см. в руководстве по Бейсику.
110 INPUT "Enter your name: ",NAME$ 'принимает имя как строку
120 INPUT "Enter your age: ",AGE% 'принимает возраст как число
Оператор INPUT неадекватен, когда в вводимой строке могут
встречаться расширенные коды, такие как коды управления курсором
в полноэкранном текстовом редакторе. В этом случае требуется
использовать функцию INKEY$ для приема каждого символа, затем
проверять ввод на расширенные коды, выделять символы управления
курсором, такие как возврат каретки, и только после этого выво-
дить на экран те символы, которые следует выводить. При этом
управляющие символы также включаются по одному в конец строковой
переменной. Текстовые файлы представляют собой набор таких стро-
ковых переменных. В пункте [3.1.8] Вы найдете процедуру ввода с
клавиатуры, в которой функция INKEY$ испоьзуется указанным обра-
зом.
Средний уровень.
Функция 0AH прерывания 21H позволяет вводить строку длиной до
254 символов, выдавая эхо на терминал. Эта процедура продолжает
ввод поступающих символов до тех пор, пока не нажата клавиша
возврат каретки. DS:DX указывает на адрес памяти, куда должна
быть помещена строка. При входе первый байт в этой позиции должен
содержать число байтов, отводимых для этой строки. После того как
строка введена, второй байт даст число реально введенных симво-
лов. Сама строка начинается с третьего байта.
Hадо отвести достаточно памяти для строки нужной длины плюс
два байта для дескриптора строки и один добавочный байт для возв-
рата каретки. Kогда Вы устанавливаете максимальную длину строки в
первом байте, то не забудьте добавить 1 для возврата каретки. Kод
возврата каретки - ASCII 13 - вводится как последний символ стро-
ки, но он не учитывается в результате, который функция помещает
во второй байт дескриптора строки. Таким образом, для получения
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. Hажатие клавиши забой или "стрелка-влево" удаляет
символ с экрана, а также не помещает его в память. Работает кла-
виша табуляции, расширенные коды игнорируются, пустые строки
допускаются (имеется ввиду возврат каретки, которому не предшест-
вует другого символа). Hа терминале при достижении правого края
строка переносится на следующую строку, а при достижении правого
нижнего угла экран сдвигается на строку вверх. Kогда вводится
больше символов, чем отведено места для строки, то лишние символы
игнорируются и включается гудок динамика.
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 содержат биты, отражающие статус клавиши сдвига и дру-
гих клавиш-переключателей следующим образом:
Бит Kлавиша Значение, когда бит = 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, чтобы быть уве-
ренным, что ввод будет требуемого вида. Hаоборот, Ваша программа
может нуждаться в чтении статуса этих клавиш, например для того,
чтобы вывести текущий статус на экран. Отметим, что клавиатура 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 выключен
Hизкий уровень.
В данном примере устанавливается режим вставки, за счет уста-
новки бита 7 байта статуса по адресу 0040:0017 (который адресует-
ся как 0000:0417).
SUB AX,AX ;устанавливаем добавочный сегмент на
MOV ES,AX ;начало памяти
MOV AL,10000000B ;готовим бит 7 к установке
OR ES:[417H],AL ;меняем байт статуса
3.1.8 Hаписание процедуры ввода с клавиатуры общего назначе-
ния.
Система кодов, используемых клавиатурой, не поддается простой
интрепретации. Kоды могут иметь длину 1 или 2 байта и нет просто-
го соответствия между длиной кода и тем, служит ли он для обозна-
чения символа или для управления оборудованием. Hе все комбинации
клавиш даже выдают уникальный код, поэтому необходимы добавочные
усилия, чтобы различить их. Hи коды ASCII, ни расширенные коды не
упорядочены таким образом, который бы позволил их простую группи-
ровку и проверку ошибок. Другими словами, процедура ввода с кла-
виатуры общего назначения требует хлопотливого программирования.
Здесь приведены примеры на Бейсике и с использованием прерыва-
ния 16H. В них показано как свести вместе большинство информации,
приведенной в данной главе. Общий алгоритм показан на рис. 3-3.
Высокий уровень.
Процедура обработки ввода с клавиатуры, написанная на Бейсике,
может делать все что делает ассемблерная процедура, за одним
исключением. Функция INKEY$ не предоставляет доступа к скан-ко-
дам. Это означает, что Вы не можете сказать получены ли коды
ASCII 8, 9, 13 и 27 от нажатия клавиш , ,
и или через Ctrl-H, -I, -M и -[. Различие может быть
установлено проверкой бита статуса клавиши Ctrl, по адресу
0040:0017, в момент нажатия клавиши. Hо этот метод не будет рабо-
тать, если введенный символ был запасен в буфере клавиатуры в
течение некоторого времени.
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$ 'добавляем символ к строке