Блог → Секреты Turbo Pascal: текст в графическом режиме. Часть 2

В прошлой части статьи о программировании вывода текста в графических режимах EGA/VGA на Турбо-Паскале, я остановится на описании процедур вывода, и дал краткие их описания. Был и пример кода, в котором мы попробовали вывести на экран текст, используя графический подрежим адаптера VGA. Если вы не успели ознакомиться с первой частью заметки, вы можете сделать это прямо сейчас, а для остальных - я продолжаю углубляться в тему.

Мигающий текстовый курсор в графическом режиме

Создание мигающего текстового курсора - непростая и довольно трудоёмкая задача, подразумевающая умение программировать видеоадаптеры и контроллер прерываний 8259A. Решить её можно только путем создания подпрограммы, называемой обработчиком кадровых прерываний (ОКП), которая загружается по вектору прерывания 0AH, и выполняется независимо от основной программы в начале каждого обратного хода луча по кадру.

Работа ОКП основана на способности контроллера электронно-лучевой трубки (КЭЛТ) на адаптерах EGA и VGA (а также MCGA) генерировать аппаратное прерывание во время начала интервала затемнения по кадру, т.е. после прохождения лучом нижней линии развертки, на которой высвечиваются данные из видеопамяти. В то время, когда погашенный луч возвращается в левый верхний угол экрана, ОКП может изменить содержимое видеопамяти или запрограммировать видеоаппаратуру, не вступая в конфликт с дисплеем.

Прерывание генерируется по второй линии запроса на прерывание (IRQ2 - interrupt request line 2). Контроллер прерываний программируется во время холодного старта таким образом, что устанавливается соответствие IRQ2 вектору прерывания OAH, поэтому ОКП должен быть спроектирован для обработки прерывания OAH. Биты 4 и 5 регистра КЭЛТ Конец Обратного Хода Луча по Кадру (КОХЛК) контролируют, было ли (и если было, то когда) сообщение КЭЛТ о кадровом прерывании. Бит 5 устанавливается в нуль, чтобы дать возможность КЭЛТ сгенерировать прерывание. Бит 4 контролирует однобитовый шлюз, статус которого появляется в бите 7 Нулевого регистра входного состояния (НРВС). Вы должны обнулить бит 4, чтобы очистить шлюз. Когда бит 4 устанавливается в единицу, при следующем кадровом прерывании бит состояния шлюза изменяется с нуля на единицу и остается равным ей до тех пор, пока вы снова не очистите шлюз.

Все процедуры, обеспечивающие создание текстового курсора, собраны в отдельный модуль TextCurs. Процедура SetTextCursor определяет координаты, форму и частоту мигания курсора. Координаты курсора соответствуют его верхнему левому углу при условии, что он заполняет матрицу символа размером 8xCharH, где CharH - высота символа используемого шрифта. В пределах этой матрицы курсор может иметь любые размеры, задаваемые переменными Linel, Line2, Coll и Со12.

Разумеется, частота мигания зависит от кадровой частоты монитора (50-60 Гц) и при Count = 100-120 она составит 1 раз в секунду. Затем SetTextCursor вызывает загрузчик ОКП EnableIntrVROA, которому в качестве параметра передается имя процедуры BlinkTextCursor, создающей на экране монитора мигающий текстовый курсор во время обратного хода луча по кадру. Такая передача удобна тем, что не надо переписывать модуль, если вместо мигающего курсора вы пожелаете использовать ОКП для других целей, например для прокрутки или плавного перемещения объектов по экрану (изменение содержимого видеопамяти во время обратного хода луча по кадру позволяет избавиться от эффекта мерцания). Достаточно написать новую процедуру (не забудьте откомпилировать её с опцией {$F+}) и передать её имя в качестве параметра процедуре EnableIntrOA. EnableIntrOA сохраняет вектор прерывания ОАН, чтобы обработчик прерывания при необходимости мог вызвать предыдущий обработчик (процедуру OldIntrOA) и, в конечном счете, когда в обработчике отпадет необходимость, восстановить вектор предыдущего прерывания. Затем она устанавливает вектор прерывания ОАН на обработчик кадрового прерывания (процедура NewIntrOA) и поочередно разрешает IRQ2 и кадровое прерывание.

В процедуре NewProcOA проводится проверка на наличие аппаратного прерывания ОАН. Чтобы отличить аппаратное кадровое прерывание от возможного программного прерывания ОАН, обработчик проверяет бит 7 HPBC. Равенство этого бита единице означает, что кадровое прерывание было, и обработчик продолжает свою работу. Если же бит равен нулю - прерывания не было, и обработчик вызывает предыдущий обработчик прерывания ОАН.

Необходимо отметить недостаток применения кадрового прерывания: любое аппаратное прерывание по IRQ2 устанавливает бит состояния в HPBC. Таким образом, хотя бит состояния может быть использован для обнаружения программного прерывания ОАН, обработчик прерывания не в состоянии отличить кадровые прерывания от прерываний IRQ2, сгенерированных другой аппаратурой, если эта аппаратура не подлежит однозначной идентификации. Так как некоторые другие адаптеры могут использовать IRQ2, то можно уверенно эксплуатировать кадровое прерывание только тогда, когда точно известна аппаратная конфигурация компьютера, на котором вы запускаете свою программу.

Когда обработчик фиксирует кадровое прерывание (т.е. бит 7 HPBC равен единице), он выдает инструкцию конца прерывания (EOI - end-of-interrupt) контроллеру прерываний пересылкой значения 20H в порт 20H, благодаря чему могут обрабатываться последующие прерывания IRQ2 (на компьютерах PS/2 такая пересылка не требуется). Однако дополнительные кадровые прерывания не будут выдавать сигналы до тех пор, пока обработчик не очистит и не восстановит шлюз.

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

Аппаратная поддержка кадровых прерываний может варьироваться в деталях. Например, адаптер VGA IBM вообще не использует кадровое прерывание. На некоторых разновидностях адаптера EGA значение бита 7 НРВС обратно значению эквивалентного бита адаптера EGA, (т.е. когда происходит кадровое прерывание, бит 7 устанавливается в нуль). Чтобы обеспечить корректную работу Вашего ОКП на других адаптерах EGA, определите значение бита после кадрового прерывания и в соответствии с результатом придумайте свой тест для кадрового прерывания.

Для управления курсором в модуль TextCurs включены простые процедуры HideTextCursor, ShowTextCursor, GotoCursorXY, WhereCursorX и WhereCursorY, которые не нуждаются в комментариях. В коде ниже, приведен пример модуля с процедурами для создания мигающего текстового курсора в графическом режиме.

Unit TextCurs;
interface
uses Crt.Dos.Graph;
Type
TypeProcIntr - procedure;
Const