Текстовый курсор в графическом режиме
Подпрограмма TglCrsr
В примере 5.24 приведен текст подпрограммы, изменяющей состояние курсора на противоположное. При первом обращении изображение курсора появляется на экране, а при втором – удаляется с экрана. Оно имеет форму вертикальной линии, расположенной в двух левых столбцах знакоместа. Высота линии равна высоте символа, а ширина составляет две точки.
Подпрограмма рассчитана на то, что для вывода символов на экран используется знакогенератор из примера 5.19. Поэтому адрес видеопамяти, соответствующий верхнему левому углу рисунка курсора, выбирается из регистра di, а код цвета фона и высоту символов задают переменные grndcoi и hsymb (см. пример 5.18). При коррекции адреса видеопамяти используется переменная bperiine, описанная в примере 2.11, она равна значению Horsize, умноженному на размер кода точки в байтах (1-4).
Пример 5.24. Подпрограмма изменения состояния текстового курсора.
TglCrsr: PushReg <ax,ex,di,Cur_win>; сохранение в стеке call Setwin; установка исходного окна mov al, grndcol! i al = код цвета фона mov ex, hsymb ex = высота символов Tcrsr: xor es:[di], al!! изменяем код первой точки xor es:[di+1], al!! изменяем код второй точки add di, bperline коррекция видеоадреса jnc @F › адрес в пределах сегмента call Nxtwin установка следующего окна @@: loop Tcrsr управление циклом PopReg <Cur_win,di,ex,ax>; восстановление из стека ret завершение работы подпрограммы
Выполнение подпрограммы примера 5.24 начинается с сохранения в стеке тех величин, значения которых могут измениться, и установки исходного окна. После этого в регистр al копируется код цвета фона, а в сх – количество строк в символе.
Цикл изменения состояния курсора имеет метку Tcrsr. Его первые две команды изменяют состояние двух первых точек очередной строки рисунка. Затем вычисляется адрес следующей строки, если при этом вырабатывается признак переполнения, то производится смена окна видеопамяти. Команда loop повторяет выполнение цикла, пока не будут изменены все строки. После этого восстанавливаются сохраненные в стеке величины и происходит возврат на вызывающий модуль.
Исходный текст примера 5.24 рассчитан на выполнение в видеорежимах PPG. Комментарий к командам, зависящим от видеорежима, начинается с двух восклицательных знаков. При работе в режимах direct color используйте варианты переменных команд, приведенные в табл. 5.2.
Таблица 5.2. Варианты переменных команд для примера 5.24.
Режимы PPG | Режимы Hi-Color | Режимы True Color |
---|---|---|
mov al, grndcol | mov ax, grndcol | mov eax, grndcol |
xor es:[di], al | xores:[di], ax | xor es:[di], eax |
xor es:[di+1], al | xor es:[di+2], ax | xor es:[di+4], eax |
Мигающий курсор
Текстовый курсор обычно мигает, т. е. его изображение периодически появляется и исчезает. Для получения эффекта мигания надо вызывать подпрограмму TglCrsr через равные промежутки времени, например через 0.5 сек, как это делают Windows и ее приложения.
При управлении курсором высокая точность измерения времени не требуется, поэтому можно использовать таймер, который "тикает" через каждые 55 миллисекунд, или 18.2 раза в секунду. Для выдержки паузы надо дождаться пока от таймера поступит нужное количество.тиков с момента начала паузы. Вопрос лишь в том, как узнать, что таймер "тикнул".
В области данных BIOS, начиная с адреса 0000:046с, зарезервировано 4 байта, содержащих 32-разрядный счетчик количества тиков. BIOS очищает счетчик при первоначальной загрузке, после чего его значение увеличивается на 1 с каждым тиком таймера. Для выдержки паузы надо запомнить исходное значение счетчика, в начале паузы, а затем время от времени сравнивать текущее значение с исходным. Пауза закончится, когда их разность достигнет нужного значения.
Необходимость периодически опрашивать состояние счетчика тиков является недостатком такого способа, поэтому он применяется только в тех случаях, когда задача ничего не делает во время паузы. В общем случае работа с таймером происходит в режиме прерываний. Для этого вам надо составить подпрограмму, которая будет выполняться при каждом тике таймера. О том, как ее составить, мы поговорим особо, а сначала рассмотрим, как сделать, чтобы она выполнялась при каждом тике таймера.