Прерывание 21h: функции DOS для работы с буфером клавиатуры

воскресенье, 25 апреля 2010 г. Автор: Vadim 0 коммент.

Различные служебные функции DOS для работы с буфером клавиатуры (функции 01h, 06h, 07h, 08h, 0Ah, 0Bh и 0Ch) классифицируются прежде всего по трем критериям: ожидают ли они ввода или же, когда символ не получен, сообщают, что ввода нет; выдают ли они на экран дисплея эхо (введенный символ); и реагирует ли функция на ввод стандартного символа прерывания во время ее исполнения. (Напомним, что нажатие комбинации клавиш Ctrl-Break или Ctrl-C рассматривается как прерывание ограниченным числом стандартных функций DOS. Однако, начиная с версии 2.00, в DOS введена команда BREAK ON, которая дает указание DOS реагировать на ввод символа прерывания при всех обстоятельствах.)

Все функции ввода с клавиатуры получают введенный символ из буфера клавиатуры, размещенного в памяти компьютера, а не непосредственно из порта 60h интерфейса клавиатуры (из порта 60h скан-коды считываются прерыванием 09h, переводятся в коды символов и помещаются в буфер клавиатуры).

Функция 1 прерывания 21h: ввод символа с эхопечатью

Функция 01h ждет появления символа в буфере клавиатуры со стандартного устройства ввода и после приема символа помещает его в регистр AL. Другие функции, относящиеся к вводу символов с клавиатуры: 06h, 07h и 08h.

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

Работа функции 01h происходит следующим образом. Нажатие клавиши, соответствующей одному из символов кода ASCII, приводит к записи соответствующего байта в регистр AL и немедленной выдаче символа данной функцией на экран (в позицию курсора). Нажатие клавиши, формирующей сигнал, не относящийся к оду ASCII, приводит к формированию двух байтов, которые могут быть получены путем двух последовательных обращений к данной функции.

Обычно функция 01h применяется для проверки принадлежности символа, соответствующего нажатой клавише, коду ASCII. Для этого производится проверка регистра AL. Если AL не равно 00h, то это символ кода ASCII. Если же AL=00h, то вы имеете дело с символом, не относящимся к коду ASCII; в этом случае следует повторить обращение к данной функции для получения псевдокода, соответствующего специальному действию клавиши. Как и в случае применения других средств DOS, предназначенных для ввода символов с клавиатуры, при использовании данной функции развернутый код символов набора ASCII оказывается недоступным, даже если соответствующие средства обслуживания клавиатуры системы ROM BIOS позволяют осуществить доступ к нему.

Функция 6 прерывания 21h: непосредственный ввод

и вывод с консоли

Функция 06h - это универсальная функция, объединяющая операции ввода с клавиатуры и вывода на дисплей. В версиях DOS, начиная со второй и выше, эта функция, как и другие, действует по отношению уже не к клавиатуре и дисплею, а к стандартным устройствам ввода и вывода (в качестве которых по умолчанию принимаются клавиатура и дисплей).

При реализации данной функции регистр AL используется для ввода, а регистр DL - для вывода. Если при вызове функции 06h в регистре DL находится значение FFh (в десятичной нотации 255), то при нажатии какой-либо клавиши эта функция поместит соответствующий ASCII-код в регистр AL и сбросит нулевой флаг; при отсутствии нажатия клавиши она установит нулевой флаг.

Если же вызвать функцию 06h при любом другом значении регистра DL, то будет выполнен вывод символа, соответствующего данному значению, на стандартное устройство вывода.

Функция 06h не ожидает ввода символа с клавиатуры и не осуществляет его эхопечати на экране. Кроме того, функция 06h не воспринимает сочетание клавиш Ctrl-C как прерывание программы (при использовании данного сочетания она помещает в регистр AL значение 03h, т.е. соответствующий данному значению ASCII-код).

Функция 7 прерывания 21h: непосредственный ввод

с консоли без эхопечати

Функция 07h ожидает ввода символа со стандартного устройства ввода и после ввода символа помещает его в регистр AL. Она не осуществляет эхопечати символа на экране и не воспринимает сочетание клавиш Ctrl-C как прерывание программы.

Функция 07h действует точно так же, как функция 01h: нажатие клавиши, относящейся к коду ASCII, приводит к немедленному занесению в регистр AL соответствующего байта; нажатие клавиши, не относящейся к коду ASCII, приводит к формированию двух байтов, которые могут быть получены двумя последовательными обращениями к функции 07h.

Функция 8 прерывания 21h:

ввод с консоли без эхопечати

Функция 08h ожидает ввода символа, не осуществляя эхопечати и прерывает программу при нажатии Ctrl-C.

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

Для более полного понимания особенностей данной функции обратитесь к описанию функции 01h. Сравните данную функцию с функциями 01h, 06h и 07h. Если вы хотите использовать функцию 08h, но не желаете ждать ввода символа, изучите функцию 0Bh, которая сообщает о готовности ввода. Изучите также функцию 0Ch, которая является модификацией данной функции.

Ярлыки: , ,

Буфер клавиатуры

Автор: Vadim 0 коммент.

 

Буфер клавиатуры имеет объем 32 байта и располагается в памяти начиная с адреса 0040:001E. Он может накапливать до 15 нажатий на клавишу, независимо от того, являются ли они однобайтными кодами ASCII или двухбайтными расширенными кодами - буфер отводит по два байта для каждого нажатия клавиши (последнее нажатие, которое может быть максимально 16-м по счету, зарезервировано для клавиши <Enter>, которая разрешает исполнение введенной с клавиатуры команды для командного процессора COMMAND.COM). Для однобайтных кодов первый байт содержит код ASCII, а второй - скан-код клавиши. Для расширенных кодов первый байт содержит 0, а второй номер расширенного кода. Этот номер обычно совпадает со скан-кодом клавиши, но не всегда, поскольку некоторые клавиши могут комбинироваться с клавишами сдвига для генерации различных кодов.

Буфер устроен как циклическая очередь, которую называют также буфером FIFO (первый вошел - первым ушел). Однако не имеется определенной ячейки памяти, в которой находилось бы всегда начало строки в буфере. Вместо этого два указателя хранят позиции головы и хвоста строки символов, находящейся в буфере в текущий момент. Указатель головы указывает на позицию, занятую первым символом в буфере, а указатель хвоста - на позицию, следующую за последним символом (т.е. на первую свободную). Новые нажатия клавиш запасаются в позициях, на которые указывает указатель хвоста (в более старших адресах памяти), и соответственно обновляется указатель хвоста. После того, как израсходованы старшие адреса в буфере, новые символы начинают вставляться в самые младшие ячейки буфера; поэтому возможны ситуации, когда хвост буфера имеет меньший адрес, чем голова. После того как буфер заполнен, новые вводимые символы игнорируются, при этом обработчик прерываний клавиатуры выдает гудок через динамик. В этот момент указатель хвоста указывает на ячейку перед головой в циклической очереди буфера (куда можно занести нажатие <Enter>). Наконец, когда оба указателя равны, то буфер пуст. Поэтому чтобы очистить буфер клавиатуры, достаточно установить указатели но одно и тоже значение. На рис.2 показаны некоторые возможные конфигурации данных в буфере.

Указатели на голову и хвост расположены по адресам 0040:001A и 0040:001C, соответственно. Хотя под указатели отведено 2 байта, используется только младший байт. Значения указателей меняются от 1Eh до 3Ch, что соответствует позициям буфера в области данных BIOS.

Чтобы разрешить ввод 15 символов требуется, как уже было сказано, 16-я пустая позиция, 2 байта которой всегда содержат код возврата каретки (ASCII 13) и скан-код клавиши <Enter>, равный 28. Они поступают в буфер по нажатию клавиши <Enter>. Эта пустая позиция непосредственно предшествует голове строки символов.

Ввод данных с клавиатуры

Автор: Vadim 0 коммент.

 

Ввод данных с клавиатуры реализован с использованием промежуточного буфера ввода - "буфера клавиатуры" (специальной области памяти): все набираемые на клавиатуре символы сначала попадают в этот буфер, и уже отсюда они затем будут считываться программами DOS. Это означает, что можно досрочно ввести много данных и они не пропадут. Например, если в программе осуществляется ввод по одному символу, то все равно можно сразу набрать много символов - затем они будут считываться из буфера по одному. Кроме того, при вводе допускается редактирование вводимого текста: при нажатии клавиши "стрелка влево" или Backspase уничтожается последний набранный символ, а при нажатии Esc уничтожается весь набранный текст (при работе COMMAND.COM редактирование возможно пока не нажата клавиша Enter; при нажатии Enter командный процессор исполняет введенную команду). Рассмотрим путь символов от клавиатуры до буфера ввода подробнее.

Клавиатура содержит встроенный микропроцессор, который воспринимает каждое нажатие или отпускание клавиши и выдает скан-код в порт A (60h) микросхемы контроллера клавиатуры, расположенной на системной плате. Скан-код - это однобайтное число (в определенных случаях - последовательность однобайтных чисел), однозначно определяющее нажатую вами клавишу. Клавиатура вырабатывает различные сканируемые коды в зависимости от того, нажимается или отпускается клавиша. Младшие 7 битов скан-кода представляют идентификационный номер, присвоенный каждой клавише, а старший бит говорит о том, была ли клавиша нажата или отпущена: при нажатии старший бит (бит 7) содержит 1, при отпускании - 0. Например, 7-битный скан-код клавиши B - 48, или 0110000 в двоичной системе. Когда эта клавиша нажимается, то в порт A интерфейса посылается код 10110000, а когда ее освободили - код 00110000. AT работает немного по-другому, посылая в обоих случаях один и тот же скан-код, но предваряя его кодом F0h, когда клавиша отпускается. Отличие "кодов нажатия" и "кодов освобождения" позволяет компьютеру различать комбинации из нескольких клавиш, т.е. когда при удержании одной клавиши одновременно нажимается другая. В этом случае код освобождения от первой клавиши не поступает, и компьютер таким образом "знает", что она не освобождалась, т.е. что вводится комбинация, и правильно распознает ее. Комбинации используются при смене регистра клавиатуры (например, "a" и "Shift-a", т.е. "A"), реализации ввода "горячих клавиш" и т.д.

Дублируемые клавиши дифференцируются клавиатурой путем использования для них более длинных скан-кодов, состоящих из нескольких байтов. Например, две клавиши смены регистра Alt имеют различные сканируемые коды: левая клавиша Alt имеет сканируемый код, равный 38h, в то время как правая клавиша Alt имеет 2-байтовый сканируемый код E0h 38h.

Если какая-либо клавиша остается нажатой больше половины секунды, то контроллер посылает сигналы через заданные интервалы времени.

Микросхема контроллера клавиатуры управляет вводом информации с клавиатуры в процессор. Всякий раз, когда вы нажимаете или отпускаете ту или иную клавишу, контроллер клавиатуры формирует ее скан-код (очередной его байт) в порте A и генерирует прерывание 9 (запрос на процессор поступает по линии IRQ1). Процессор моментально прекращает свою работу и переключается на выполнение подпрограммы обработчика прерывания 9, содержащуюся в ROM BIOS. Обработчик считывает байт из порта A и осуществляет его обработку. Когда поступает код от клавиши сдвига или переключателя, то изменение статуса записывается в память (по адресам 0040:0011 и 0040:0012). Во всех остальных случаях скан-код трансформируется в код символа ASCII, при условии, что он подается при нажатии клавиши (в противном случае скан-код отбрасывается). Конечно, процедура сначала определяет установку клавиш сдвига и переключателей, чтобы правильно получить вводимый код (это "a" или "A" ?). После этого введенный код помещается в буфер клавиатуры. На рис.1 показан путь, который проходит нажатие на клавишу перед тем, как попасть в Вашу программу.

Имеется два типа кодов символов: коды ASCII и расширенные коды. Коды ASCII - это байтные числа, используемые для представления символов внешнего алфавита ЭВМ. Этот набор включает обычные символы пишущей машинки, а также ряд специальных букв и символов псевдографики. ASCII коды включают также 32 управляющих кода, которые обычно используются для передачи команд периферийным устройствам, а не выводятся как символы на экране; правда, каждый из них имеет соответствующее символьное представление, которое может быть выведено на дисплей с использованием прямой адресации дисплейной (видео) памяти.

Второй набор кодов, расширенные коды, присвоен клавишам или комбинациям клавиш, которые не имеют представляющего их символа ASCII, таким как функциональные клавиши или комбинации с клавишей Alt. Расширенные коды имеют длину 2 байта, причем первый байт всегда 0. Второй байт - определенный номер расширенного кода. Например, код 0:30 представляет Alt-A. Начальный номер позволяет программе определить, принадлежит ли данный код набору ASCII или расширенному набору.

Имеется несколько комбинаций клавиш, которые выполняют специальные функции и не генерируют скан-коды. Эти комбинации включают Ctrl-Break, Ctrl-Alt-Del и PrtSc, плюс SysReq для AT. Эти исключения приводят к заранее предопределенным результатам. Все остальные нажатия клавиш должны интерпретироваться Вашей программой, и если они имеют специальное назначение, скажем сдвинуть курсор влево, то Ваша программа должна содержать машинные команды, обеспечивающие достижение этого эффекта.

К счастью, операционная система предоставляет различные процедуры (служебные функции DOS 01h, 06h, 07h, 08h, 0Ah, 0Bh и 0Ch прерывания 21h ) для чтения кодов из буфера клавиатуры, включая средства для получения сразу целой строки. Поскольку эти процедуры позволяют делать практически все, что Вы можете пожелать, то практически бессмысленно писать свои процедуры обработки ввода с клавиатуры и можно пользоваться готовыми функциями DOS.

Перевод чисел в ASCII-коды

Автор: Vadim 0 коммент.

Для перевода чисел в их ASCII-коды даже не обязательно знать сами ASCII-коды, т.е. коды внешнего алфавита МЭВМ. Достаточно подготовить в памяти ЭВМ таблицу цифр, но не заполнять ее самому кодами цифр, а поручить эту работу ассемблеру. Этого можно добиться при помощи директивы

Table DB '0123456789ABCDEF'

По этой директиве ассемблер автоматически поместит, начиная с мнемоадреса Table правильные однобайтные ASCII-коды шестнадцатиричных цифр от 0 до F. Здесь '012..F' - это строковая константа, т.е. последовательность символов, заключенная в апострофы. Строковая константа всегда заменяется при ассемблировании на ее ASCII-код. Таким образом, в памяти ЭВМ по метке Table будет открыта таблица ASCII-кодов цифр. Теперь, чтобы перевести какую-то цифру, например 3, в ее ASCII-код, надо просто заменить эту цифру на соответствующий байт из таблицы (в нашем примере - на 3-й байт).

Для работы с таблицей, т.е. извлечения из нее нужных кодов, обычно используется команда XLAT. Она заменяет значение в регистре AL, рассматриваемое как номер элемента в таблице, на байт из таблицы с этим номером (исходное значение в AL служит индексом таблицы). Сама таблица адресуется регистром BX в сегменте данных DS. Таким образом, действие команды XLAT такое:

XLAT ; AL := m(DS:BX + AL)

Предположим, что необходимо преобразовать цифру 7 в ASCII-код. Получается следующий фрагмент:

MOV BX, OFFSET Table ; Поместить смещение таблицы в BX

MOV AL, 7 ; Загрузить 7 в AL

XLAT ; Считать 7-й элемент из таблицы в AL

Ярлыки:

Коды ASCII для чисел

Автор: Vadim 0 коммент.

Среди функций DOS нет такой, которая выводит числа. Такую операцию, если надо, приходится реализовывать на основе функций вывода текста на экран. Поэтому, чтобы вывести число, надо предварительно преобразовать его цифры в ASCII-коды этих цифр и выводить на экран эти коды, а не само число. Если же выводить число на экран непосредственно, то экран воспримет его не как число, а как последовательность ASCII-символов - каждый байт числа будет воспринят как один ASCII-символ - и выведет на экран эти символы, а не наше число. Например, если вывести на экран байт 61h, то на экране отобразится символ (буква) 'a', а не число (две цифры) 61, поскольку байт 61h (в двоичной нотации - 01100001) - это и есть ASCII-код буквы 'a'. Для того чтобы "высветить" на экране цифры '61', надо вывести на экран сначала ASCII-код цифры '6' - он равен 36h (00110110), а потом - ASCII-код цифры '1' - 11h (00010001). Тогда на экране отобразится нужная запись: 61. Кодирование цифр и букв-шестнадцатиричных цифр показано в таблице.

Таблица. Представление 16-ричных цифр в коде ASCII

-----------------------------------------------------------------

Цифра Код ASCII Цифра Код ASCII

двоичный 16-рич. двоичный 16-рич.

-----------------------------------------------------------------

0 0011 0000 30h 8 0011 1000 38h

1 0011 0001 31h 9 0011 1001 39h

2 0011 0010 32h A 0100 0001 41h

3 0011 0011 33h B 0100 0010 42h

4 0011 0100 34h C 0100 0011 43h

5 0011 0101 35h D 0100 0100 44h

6 0011 0110 36h E 0100 0101 45h

7 0011 0111 37h F 0100 0110 46h

-----------------------------------------------------------------

Ярлыки:

Прерывание 10h: службы ROM BIOS для видеодисплея

Автор: Vadim 0 коммент.

 

Все видеослужбы ROM BIOS запрашиваются с помощью прерывания 10h (в десятичной нотации 16). Имеется 25 основных служб, предоставляемых данным прерыванием. Подобно всем другим службам ROM BIOS видеослужбы нумеруются, начиная с 00h, и выбираются с помощью занесения номера службы в регистр AH. Обычно при работе с этими службами требуется задавать дополнительные параметры в регистрах AL, BX, CX или DX.

Служба 0: установить режим выдачи изображения

Служба 0 используется для выбора одного из четырнадцати режимов выдачи, показанных в таблице. Режимы с 0h по 6h применимы для стандартного цветного графического адаптера (CGA); режим 7h применяется для монохромного режима (MDA); режимы с 0Dh по 10h были добавлены для улучшенного графического адаптера (EGA); наконец, режимы 11h - 13h были внедрены на многоцветном графическом массиве (MCGA) (PS/2 моделей 25 и 30) и видеографическом массиве (VGA) (PS/2 моделей 50, 60 и 80).

Обычно при установке режима ROM BIOS чистит буфер памяти экрана, даже если снова и снова устанавливается один и тот же режим. Такая повторная установка того же самого режима может быть использована как простой и эффективный способ очистки экрана. В некоторых версиях DOS команда CLS фактически чистит экран с помощью данного способа. Установка видеорежима приводит также к установке принятых по умолчанию значений цветов цветовой палитры, поэтому при очистке экрана не используйте службу 0, если вы работаете с цветами, вместо этого применяйте видеослужбу 6.

При наличии адаптеров EGA,MCGA и VGA вы можете также дать указание ROM BIOS не очищать экран при установке видеорежима. Для этого к номеру режима, задаваемому вами в регистре AL, прибавьте число 80h (в десятичной нотации 128), что соответствует добавлению 1 в бит 7.

Значения регистров для службы установки видеорежима 0h

Номер службы Параметр

AH = 0 AL = номер режима

Таблица. Видеорежимы, устанавливаемые с помощью

видеослужбы ROM BIOS

--------------------------------------------------------------

Режим Тип Разрешающая Число Видеопод-

способность цветов системы

--------------------------------------------------------------

00h,01h Текстовый 40*25 16 CGA,EGA,

MCGA,VGA

02h,03h Текстовый 80*25 16 CGA,EGA,

MCGA,VGA

04h,05h Графический 320*200 4 CGA,EGA,

MCGA,VGA

06h Графический 640*200 2 CGA,EGA,

MCGA,VGA

07h Текстовый 80*25 Монохромный MDA,

EGA,VGA

08h,09h,0Ah Только для PCjr

0Bh,0Ch Внутренние режимы BIOS

0Dh Графический 320*200 16 EGA,VGA

0Eh Графический 640*200 16 EGA,VGA

0Fh Графический 640*350 Монохромный EGA,VGA

10h Графический 640*350 16 EGA,VGA

11h Графический 640*480 2 MCGA,VGA

12h Графический 640*480 16 VGA

13h Графический 320*200 256 MCGA,VGA

Например, следующий фрагмент очистит экран и установит видеорежим 3:

MOV AX, 0003h

INT 10h

Служба 6: прокрутить окно вверх

Служба 06h (в десятичной нотации 6) и ее напарник служба 07h (в десятичной нотации 7) используются для задания на экране прямоугольной области текстового окна и прокручивания его содержимого вверх или вниз на одну или более строк. Для достижения эффекта прокрутки в нижнюю часть окна службой 06h вставляются пустые строки (служба 07h вставляет пустые строки в верхнюю часть окна); при этом верхние строки окна (нижние - в случае службы 07h) смещаются и исчезают с экрана.

Число строк, подлежащих прокрутке, задается в регистре AL. При AL = 00h окно очищается полностью (то же самое произойдет, если мы прокрутим больше строк, чем позволяет размер окна). Положение и размер окна задается в регистрах CX и DX: CH содержит верхнюю строку, а DH - нижнюю строку; CL - левую колонку, а DL - правую колонку. Атрибуты для новых пустых строк в обеих службах, задаются в регистр BH. Ниже суммируется порядок задания значений регистров для обеих служб (06h и 07h).

Значения регистров для служб прокрутки окон 06h и 07h

Номер службы Параметры

AH = 06h AL = число строк, подлежащих прокрутке

(прокрутка CH = номер строки для верхнего лев. угла

вверх)

AH = 07h CL = номер колонки для верх. левого угла

(прокрутка DH = номер строки для нижнего прав. угла

вниз)

DL = номер колонки для ниж. правого угла

BH = атрибут для выдачи пустых строк

Служба 7: прокрутить окно вниз

Служба 07h (в десятичной нотации 7), как мы уже упоминали, является зеркальным отображением службы 06h. Различие между этими двумя службами состоит в том, как происходит прокрутка. При выполнении службы 07h новые пустые строки появляются в верхней части окна, а старые строки исчезают со стороны его нижней части. (При выполнении службы 06h имеют место противоположные изменения.)

Служба 02h: установить положение курсора

Служба 02h (в десятичной нотации 2) устанавливает позицию курсора, используя координаты строки и колонки экрана. В текстовых режимах, где может быть несколько страниц изображения, каждая из них имеет независимо записываемую позицию курсора. Хотя в графических режимах и нет видимого курсора, в них логическое положение курсора поддерживается тем же способом, что и в текстовых режимах. Эта логическая позиция курсора используется для управления вводом/выводом символов по аналогии с текстовым режимом.

Для задания позиции курсора номер строки помещается в регистр DH, номер колонки в DL, а номер страницы в BH. Нумерация строк и колонок начинается с координат 0,0 в левом верхнем углу экрана. В графических режимах для идентификации положения курсора используются координаты строки и колонки пикселов вместо координат для знака. Номер страницы - это обычный номер страницы изображения, используемый в Бэйсике: страницы от 0 до 7 в 40-колонных режимах и от 0 до 3 в 80-колонных режимах. В графических режимах номер страницы должен быть установлен в 0.

Сведения о задании регистров даны ниже.

Значения регистров при установке положения курсора

с помощью службы 02h

Номер службы Параметры

AH = 02h DH = номер строки

DL = номер колонки

BH = номер страницы

Прерывание 21h: общие функции DOS

Автор: Vadim 1 коммент.
 

Все функции DOS вызываются с помощью прерывания 21h (в десятичной нотации 33). Первая версия DOS содержала 42 функции. Во второй к ним добавлено еще 33 функции, которые сохраняются во всех последующих версиях. Выбор конкретной функции осуществляется путем записи соответствующего номера в регистр AH.

Функция 02: вывод одного символа на экран

Для вывода одного символа на экран ПК используется

функция 02 прерывания 21h:

mov DL, <код выводимого символа>

mov AH, 2

int 21h

Выводимый символ высвечивается в позиции курсора (что бы там ни было записано), после чего курсор сдвигается на одну позицию вправо. Если курсор находился в конце строки экрана, то он перемещается на начало следующей строки, а если курсор был в конце последней строки экрана, то содержимое экрана сдвигается на одну строку вверх, а внизу появляется пустая строка, в начало которой и устанавливается курсор.

Особым образом осуществляется вывод символов с кодами 7, 8, 9, 10 (0Ah) и 13 (0Dh). Символ с кодом 7 (bell, звонок) на экране не высвечивается (и курсор не сдвигается), а вызывает звуковой сигнал. Символ с кодом 8 (backspase, шаг назад) возвращает курсор на одну позицию влево, если только он не был в самой левой позиции строки. Символ с кодом 9 (tab, табуляция) смещает курсор вправо на ближайшую позицию, кратную 8. Символ с кодом 10 (line feed, перевод строки) перемещает курсор в следующую строку экрана, оставляя его в той же колонке. Символ с кодом 13 (carrige returne, возврат каретки) устанавливает курсор на начало текущей строки; вывод подряд символов с кодами 13 и 10 означает перевод курсора на начало следующей строки.

Функция 9: вывести строку на экран дисплея

Для вывода на экран строки (последовательности символов) можно, конечно, использовать функцию 02, однако сделать это можно и за один прием с помощью функции 09 прерывания 21h:

DS:DX := начальный адрес строки

mov AH, 9

int 21h.

Перед обращением к этой функции в регистр DS должен быть помещен номер того сегмента памяти, в котором находится выводимая строка, а в регистр DX - смещение строки внутри этого сегмента. При этом в конце строки должен находиться символ $ (код 24h), который служит признаком конца строки и сам не выводится.

Хотя эта функция может оказаться намного удобнее функций побайтового вывода на экран (функция 2 и 6), она имеет тот недостаток, что вполне обычный символ $ используется как ограничитель строки. Это еще один побочный продукт совместимости с CP/M.

Расширенные функции операционной системы DOS в качестве ограничителя строки используют CHR$(0). Это соответствует соглашениям, принятым в операционной системе UNIX и языке программирования Си.

Среди функций DOS нет такой, которая выводит числа. Такую операцию, если надо, приходится реализовывать на основе рассмотренных функций.

Функция 4Ch: завершение программы

Завершив все свои действия, программа обязана вернуть управление операционной системе, чтобы пользователь мог продолжить работу на ПК. Такой возврат реализуется функцией 4Ch прерывания 21h, которую помещают в конце программы:

mov AL, <код завершения>

mov AH, 4Ch

int 21h

Каждая программа, вообще говоря, обязана сообщить, успешно или нет она завершила свою работу. Дело в том, что любая программа вызывается из какой-то другой программы (например, из операционной системы), и иногда вызвавшей программе, чтобы правильно продолжить работу, надо знать, выполнила ли вызванная программа все, что надо, или она проработала с ошибкой. Такая информация передается в виде кода завершения программы (некоторого целого числа), который должен быть нулевым, если программа проработала правильно, и ненулевым (каким именно - оговаривается в каждом случае особо) в противном случае. (Узнать код завершения вызванной программы можно с помощью функции 4Dh прерывания 21h.) Потребуется этот код или нет, программа все равно должна выдать его.

МАНИПУЛЯТОР МЫШЬ

Автор: Vadim 0 коммент.

Манипулятор мышь (в дальнейшем, просто мышь) является средством, позволяющим пользователю достаточно удобно осуществлять управление прикладными программами. Как правило, мышь соединена с ПЭВМ через последовательный интерфейс. Прикладные программы, связывающиеся через интерфейс с мышью, делают это через обращение к драйверу Microsoft, например GMOUSE.COM. Все обращения к драйверу происходят через прерывание 33h.

Прерывание 33h имеет ряд функций, которые выбираются с помощью загрузки номера функции в регистр AX. Основные функции будут приведены ниже.

Функция 00h: инициализация мыши. Если мышь инициализирована, то в регистре AX возвращается значение FFFFh, а в регистре BX - число клавиш мыши. Если инициализации не происходит, то в регистре AX возвращается значение 0000h.

Функция 01h: показать указатель мыши.

Функция 02h: спрятать указатель мыши.

Функция 03h: получить текущие координаты указателя мыши и состояние кнопок. Координаты указателя соответствует виртуальному экрану. На практике, обычно, они содержат положение пикселя в графическом режиме или умноженные на 8 координаты в текстовом режиме. Отсчет графических координат начинается от 0. Текстовые координаты отсчитываются от 1. Эта функция возвращает в регистре CX координату x, а в регистре DX координату y, в регистре BX - состояние кнопки (бит 0 - левая кнопка нажата, если установлена; бит 1 - средняя кнопка нажата, если установлена; бит 2 - правая кнопка нажата, если установлена).

Функция 04h: установить позицию указателя. В регистр CX пересылается координата x, а в регистр DX координата y. Установленная позиция указателя будет игнорироваться, если она находится внутри области исключения (см. функцию 07h и 08h). Координаты задаются всегда в пикселях, где (0,0) - координата верхнего левого угла виртуального экрана.

Функция 05h: получить информацию о нажатии клавиши. В регистр BX пересылается номер кнопки (0 - левая кнопка, 1 - правая кнопка, 2 - средняя кнопка). В регистр AX возвращается состояние кнопки (бит 0 - левая кнопка нажата, если установлена; бит 1 - средняя кнопка нажата, если установлена; бит 2 - правая кнопка нажата, если установлена). В регистр BX возвращается счетчик нажатия клавиши, CX - координата x последнего нажатия, DX - координата y последнего нажатия. После обращения к этой функции счетчик нажатия клавиши сбрасывается.

Функция 06h: получить информацию об отжатии клавиши. В регистр BX пересылается номер кнопки (0 - левая кнопка, 1 - правая кнопка, 2 - средняя кнопка). В регистр AX возвращается состояние кнопки (бит 0 - левая кнопка отжата, если установлена; бит 1 - средняя кнопка отжата, если установлена; бит 2 - правая кнопка отжата, если установлена). В регистр BX возвращается счетчик отжатий клавиши, CX - координата x последнего отжатия клавиши мыши, а DX - координата y последнего отжатия клавиши мыши. После обращения к этой функции счетчик отжатия клавиши сбрасывается.

Функция 07h: установить горизонтальное ограничение для указателя мыши. В регистр CX пересылается минимальное значение координаты x, в регистр DX - максимальное значение координаты x.

Функция 08h: установить вертикальное ограничение для указателя мыши. В регистр CX пересылается минимальное значение координаты y, в регистр DX - максимальное значение координаты y.

Функция 09h: установить форму указателя мыши в графическом режиме. По умолчанию используется указатель типа стрелки. В ES:DX пересылают адрес буфера изображения. Длина буфера изображения 64 байта. Байты с 32 по 64 определяют вид курсора, а байты с 0 по 31 определяют прозрачность курсора. Они рассматриваются как битовая маска 16´16 каждый бит которой маскирует пиксели экрана. При создании изображения драйвер предварительно получает информацию о 16´16 пикселях соответствующего места экрана и к каждому пикселю применяется операция AND с маской экрана, а затем к полученному результату - операция XOR с маской изображения. Приведенный ниже пример показывает формирование курсора в графическом режиме в виде прямоугольника с тонкой прозрачной полоской в середине.

program testmouse;

uses dos,graph;

var

reg:registers;

res1,res2,i,res3,res4:byte;

buf : array [0..63] of byte;

gd,gm:integer;

begin

FOR i:=32 TO 64 DO

buf[i]:=255;

FOR i:=0 TO 31 DO

buf[i]:=1;

gd:=detect;

initgraph(gd,gm,'');

reg.AX:=1;

intr($33,reg);

reg.ax:=9;

reg.es:=seg(buf);

reg.dx:=ofs(buf);

intr($33,reg);

.

.

.

closegraph;

end.

В регистр BX заносится смещение вправо (в пикселях) из левого верхнего угла указателя, пикселя изображения рассматриваемого драйвером в качестве текущей позиции. В регистр CX заносится смещение вниз (в пикселях) из левого угла указателя, пикселя изображения рассматриваемого драйвером в качестве текущей позиции.

Функция 0Ah: установить вид указателя мыши в текстовом режиме. В регистр BX заносят 0, если выбирают курсор, используемый в программе, и 1, если выбирают стандартный курсор. Если указатель генерируется программой, то в регистр CX заносятся биты определяющие маску AND, а в регистр DX заносятся биты определяющие маску XOR по следующему принципу. Биты 0-7 - код символа; биты 8-10 цвет символа; бит 11 - бит интенсивности; биты 12-14 - цвет фона; бит 15 - бит мерцания.

Функция 10h: установить область исключения указателя. В регистр CX пересылают значение левой верхней координаты x, в DX - значение левой верхней координаты y, в SI - значение правой нижней координаты x, в DI - значение правой нижней координаты y. Эта функция определяет область исключения отображения указателя мыши. Область исключения отменяется обращением к функции 00h или 01h, или другим обращением к этой функции.

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

Функция 15h: получить размер сохраненного буфера состояния мыши. В регистр BX возвращается размер буфера в байтах.

Функция 16h: сохранить состояние драйвера мыши. В ES:DX заносится адрес буфера. Под буфер выделяется 64 байта.

Функция 17h: восстановить состояние драйвера мыши. В ES:DX заносится адрес буфера.

Функция 1Dh: установить текущую видеостраницу для указателя мыши. В регистр BX заносится номер видеостраницы. Допустимые номера страницы зависят от активного режима визуального отображения.

Функция 1Eh: получить текущую видеостраницу для указателя мыши. В регистр BX возвращается номер текущей видеостраницы для указателя мыши.

Функция 1Fh: отключить драйвер мыши. Если отключение драйвера прошло успешно, то в регистр AX заносится значение 001Fh, а в ES:BX - адрес драйвера. Если драйвер не отключен, то в регистр AX возвращается значение FFFFh.

Функция 20h: повторное включение драйвера мыши.

Функция 24h: получить информацию о мыши. Возвращаются следующие значения:

BH - старший номер версии драйвера; BL - младший номер версии драйвера; CH - тип мыши (1 - bus mouse, 2 - serial mouse, 3 - InPort mouse, 4 - PS/2 mouse, 5 - HP mouse); CL - номер аппаратного прерывания.

При работе с мышью было бы неэффективно сводить команды мыши к эмуляции клавиатуры, но обрабатывать сигналы мыши и клавиатуры надо согласованно. Очень часто программа состоит из длительных операций, во время которых ее не интересует мышь и клавиатура, и операций обработки команд пользователя (перемещения курсора или выбор опций меню), выполнение которых должно успевать за частотой получения сигналов. Перемещения мыши при этом надо накапливать, а из буфера клавиатуры достаточно брать последнее слово (и очищать буфер). Все сказанное реализуется в приведенной ниже программе.

Procedure test;

{чтение мыши и клавиатуры}

type signal=record

case mouse:boolean of

true:(left,right:boolean;

{состояние клавиш мыши

dx,dy:word ;{ее перемещение });

false: (asc,ext:byte;

{ ASC- и расширенный коды }

status:word;

{флаги клавиатуры});

end;

{поле mouse показывает, сигнал от мыши или клавиатуры}

var ready:boolean;

begin

ready:=false; {ожидание команды}

with signal_t(signal) do

repeat

if mouse_sig then begin

mouse:=true;

r.ax:=11;intr($33,r);dx:=r.cx;dy:=r.dx;

r.ax:=3; intr($33,r);

left:=r.bx and 1 <>0;

right:=r.bx and 2 <>0;

mouse_sig:=false;

ready:=true; end

else {если мышь не трогали - опрос клавиатуры}

begin r.ah:=$11; intr($16,r);

{если не расширенная клавиатура, вызывайте функцию 1}

if r.flags and 64 = 0 then begin

{если буфер клавиатуры не пуст}

mouse:=false;

status:=memw[$40:$17]; {флаги клавиатуры}

repeat

r.ah:=$10;intr($16,r);

asc:=r.al; ext:=r.ah;

r.ah:=$11; intr($16,r);

ready:=r.flags and 64 <>0;

{очистка буфера и запоминание кода клавиши}

until ready; end;

end

until ready;

end;