белый белый Нормальный режим белый на черном, когда биты 0-2 установлены в 111, а биты 4-6 установлены в 000. Негативное изображение соз- дается обратными значениями битов. Символы выводятся с повышенной яркостью, когда бит 3 установлен в 1; не существует способа при- дать повышенную яркость фону, когда символы выводятся в негатив- ном изображении, а также недоступно подчеркивание в негативе. Во всех случаях, установка в 1 бита 7 дает мигание символов. Всего возможно только 10 комбинаций, когда символы видны. Они могут быть реализованы различными установками битов. Ниже приводятся по одной из возможных установок для каждого случая: Атрибут Цепочка битов Гекс 10-ное нормальный 00000111 7 7 интенсивный 00001111 F 15 нормальный подчеркнутый 00000001 1 1 интенсивный подчеркнутый 00001001 9 9 негативный 01110000 70 112 нормальный мигающий 10000111 87 135 интенсивный мигающий 10001111 8F 143 нормальный мигающий подч. 10000001 81 129 яркий мигающий подчерк. 10001001 89 137 яркий негативный 11110000 F0 240 Высокий уровень. Бейсик устанавливает цвета и атрибуты символов оператором COLOR. Все операторы PRINT и WRITE, которые следуют за данным оператором COLOR, выполняются с атрибутами, указанными в этом операторе. Цвет фона меняется только для выодимых символов, но не для всего экрана. Новый оператор COLOR не влияет на то, что было выведено ранее. Кроме случая монохромного адаптора, COLOR 3,4 устанавливает основной цвет символа циан (#3), а фоновый - красный (#4). Диапа- зон кодов основных цветов 0-31, причем числа 0-15 соответствуют цветам, перечисленным в вышеприведенной таблице, а числа 16-31 получаются прибавлением к любому из этих кодов числа 16, что дает тот же самый цвет, но с миганием символов. (При мигании основной цвет периодически меняется на фоновый, в то время как фоновый цвет остается неизменным.) Операторы PRINT и WRITE могут также выводить символы на графи- ческий экран. При этом цвет символов - это всегда третий цвет текущей палетты, т.е. желтый/коричневый для палетты 0 и белый - для палетты 1. Отметим, что когда Вы начинаете работать в цветном текстовом режиме, то весь экран черно-белый. Чтобы закрасить весь экран в фоновый цвет, необходимо указать оператором COLOR ,2, например, зеленый цвет и затем очистить экран командой CLS. Когда Вы чисти- те экран по ходу выполнения программы, то необходимо, чтобы пос- ледний оператор COLOR установил фоновый цвет таким, каким Вы хотите закрасить весь экран. Для монохромного дисплея атрибуты устанавливаются аналогичным образом. 0 соответствует черному цвету, а любое из чисел 1-7 соответствует белому. Таким образом COLOR 0,7 устанавливает чер- ное изображение на белом фоне (негатив), в то время как COLOR 7,0 дает вывод белых символов на черном фоне (обычная установка). Имеется одно исключение: если в качестве основного цвета исполь- зовать код 1, то будут выводиться подчеркнутые символы. Прибавив 8 к любому из кодов основного цвета, получим яркое изображение. Прибавив 16 к любому из кодов 0-15, получим мигающие символы. Таким образом 7+8+16=31 дает яркое мигающее белое изображение. Для фонового цвета допустимы только значения от 0 до 7. Если Вы используете прямое отображение в память [4.3.1], то оператор COLOR не влияет на вывод. Вместо этого Вы должны выбрать требуемую установку атрибутов из таблиц и прямо присвоить значе- ние соответствующего байта атрибутов оператором POKE. Помните, что байты атрибутов всегда занимают нечетные позиции в видеобуфе- ре. Отображение в память позволяет Вам иметь 16 фоновых цветов в Бейсике (при условии, что Вам не нужны мигающие символы). Для графического адаптора введите OUT &H3D8,8, чтобы старший бит каждого атрибута действовал как бит яркости для фоновых цветов. В следующем примере в центре экрана печатается яркокрасный "!" на светлокрасном фоне. 100 DEF SEG = &HB800 'указываем на буфер цветного дисплея 110 OUT &H3D8,8 'используем 16 фоновых цветов 120 POKE 1000,33 'печатаем ! в центре экрана 130 POKE 1001,196 'красный на светлокрасном (11000100) Как уже говорилось выше PCjr хранит бит мигания в массиве ворот дисплея. Вот та же программа для PCjr (но она не будет работать в режиме двухцветной графики): 100 DEF SEG = &HB800 'указываем на видеобуфер 110 X = INP(&H3AH) 'читаем из массива ворот дисплея 120 OUT &H3AH,3 'требуем доступ к регистру 3 130 OUT &H3AH,0 'сбрасываем все биты этого регистра 140 POKE 1000,33 'печатаем ! в центре экрана 150 POKE 1001,196 'красный на светлокрасном (11000100) Приведем еще пример изменения назначения цвета регистра палетты. Код цвета, который обычно выводится синим (0001) сделаем, чтобы он выводил цвет магента (0101). Номер регистра массива ворот дисплея, соответствующий коду цвета 1 равен 11H. 100 X = INP (&H3AH) 'читаем из массива ворот дисплея 110 OUT &H3AH,&H11 'требуем доступ к регистру 11H 120 OUT &H3AH,5 'помещаем туда код магенты (0101 = 5) Средний уровень. Прерывания DOS и BIOS предоставляют очень бедные возможности для работы с цветным текстом. Только функция 9 прерывания 10H принимает байт атрибутов при выводе символа. Функция A прерывания 10H выводит символ без указания цвета или атрибута; она просто помещает символ в видеобуфер, не трогая байт атрибута, таким образом атрибуты сохраняют свое старое значение. Функция D преры- вания 10H также оставляет нетронутым байт атрибутов. Все эти функции обсуждаются в [4.3.1]. Функции вывода на экран DOS прерывания 21H всегда выводят белое на черном. Даже если для всего экрана установлен некоторый фоновый цвет, то функции DOS устанавливают атрибут в нормальный черный при выводе каждого символа. Однако имеется способ преодо- леть это ограничение. MS DOS предоставляет драйвер устройства ANSI.SYS, который может интерпретировать специальные Esc-последо- вательности. В приложении Д объясняются основы его использования. Esc-последовательности выводятся через функцию 9 прерывания 21H, которые обычно выводят строку символов на экран. В этом случае строка состоит из символа Esc, за которым следует [, а далее одно или более кодовых чисел из нижеприведенного списка. Строка должна кончаться символом m и обычным ограничителем $. Вот кодовые номе- ра: 0 все атрибуты выключены (черный на белом) 1 включена повышенная интенсивность 4 включено подчеркивание 5 включено мигание 7 включено негативное изображение 8 все включено (при этом символы невидимы) 30 черный основной цвет 40 черный фон 31 красный основной цвет 41 красный фон 32 зеленый основной цвет 42 зеленый фон 33 желтый основной цвет 43 желтый фон 34 синий основной цвет 44 синий фон 35 основной цвет магента 45 фон магента 36 основной цвет циан 46 фон циан 37 белый основной цвет 40 белый фон Отметим, что когда функции MS DOS выводят символы в графическом режиме, то они обычно используют код 3 текущей палетты. С помощью Esc-последовательностей можно установить цвет символа соответст- вующим любому из цветов палетты. Надо указывать 30 или 31 для фонового цвета, 32 или 33 - для кода 1, 34 или 35 - для кода 2 и 36 или 37 - для кода 3. В этом случае не надо указывать фоновый цвет. В следующем примере на экран выводятся две строки с помощью функции 9 прерывания 21H. Первая выводится синим на красном, а вторая - мигающим цианом на красном. Не надо переопределять крас- ный в качестве фонового цвета для второй строки, поскольку назна- чения цветов действуют на все последующие команды вывода (включая функции BIOS прерывания 10H), до тех пор, пока не будут сделаны другие назначения. Отметим, как просто перемешивать команды уп- равления цветом с выводом самих строк. ;---в сегменте данных STRING_1 DB 'The rain in Spain',0AH,0DH,'$' STRING_2 DB 'Falls mainly on the plain$' BLUE_RED DB 27,'[34;41m$' BLINK_CYAN DB 27,'[5;36m$' ;---вывод строк MOV AH,9 ;функция вывода строки LEA DX,BLUE_RED ;адрес управляющей строки в DX INT 21H ;все будет выдаваться синим на красном LEA DX,STRING_1 ;указываем на первую строку INT 21H ;печатаем строку LEA DX,BLINK_CYAN ;адрес второй управляющей строки INT 21H ;меняем цвет на мигающий циан LEA DX,STRING_2 ;указываем на вторую строку INT 21H ;печатаем строку Вы всегда должны позаботиться о том, чтобы сбросить атрибуты цвета в нормальное состояние перед завершением программы, пос- кольку в противном случае они будут действовать и на вывод после- дующих программ. В конце следует вывести Esc-последовательность, использующую код номер 0, как указано выше. PCjr и EGA имеют специальную функцию BIOS для установки содер- жимого регистров палетты. Это подфункция 0 функции 10H прерывания 10H. Надо поместить номер регистра палетты (от 0 до 15) в BL, а значение кода цвета (также от 0 до 15) в BH, а затем выполнить прерывание. Подфункция 2 функции 10H устанавливает все регистры палетты, а также цвет границы, используя 17-байтный массив, на который должны указывать ES:DX. Байты 0-15 массива помещаются в регистры палетты 0-15, а байт 16 устанавливает цвет границы. О том, как отдельно установить цвет границы см. [4.1.4]. Низкий уровень. Как уже объяснялось в разделе "Высокий уровень", надо просто поместить требуемое значение байта атрибутов в видеобуфер, за тем символом, к которому эти атрибуты должны относиться. Приведен пример для цветного адаптора или PCjr. В примере устанавливается текстовый экран 80*25 с 16 фоновыми цветами, а затем экран ини- циализируется в красный цвет светлосинем фоне: ;---установка 16 фоновых цветов в текстовом режиме 80*25 MOV AL,00001001B ;установка в 0 бита мигания MOV DX,3D8H ;адрес регистра OUT DX,AL ;посылаем в регистр ;---инициализируем весь экран в красный на светлосинем фоне MOV AX,0B800H ;указываем на видеобуфер MOV ES,AX ; MOV CX,2000 ;записываем атрибут в 2000 ячеек MOV BX,1 ;BX указывает на байт атрибутов MOV AL,10010100B ;значение байта атрибутов NEXT_CHAR: MOV ES:[BX],AL ;посылаем атрибуты в буфер INC BX ;увеличиваем указатель на атрибуты INC BX ; LOOP NEXT_CHAR ;пишем в следующую позицию 4.1.4 Установка цвета границы экрана. Граница символьного экрана может иметь цвет, отличный от фоно- вого цвета центральной части экрана. Может быть использован любой из 16 цветов. С другой стороны, графические экраны технически не имеют области границы. Когда цвет фона устанавливается в графи- ческом режиме, то весь экран, включая область границы, окраши- вается в этот цвет. Однако, операции вывода точек на экран не имеют доступа к области границы; если большую часть адресуемых точек экрана изменить в нефоновый цвет, то будет создана види- мость границы экрана. Высокий уровень. Третий параметр оператора Бейсика COLOR устанавливает цвет границы. Используются те же самые кодовые номера цветов, приве- денные в [4.1.3]. Например, для установки границы в светлосиний цвет, надо написать COLOR ,,8. PCjr кроме того может изменять цвет, за счет изменения установки регистра палетты, соответствую- щего коду цвета, указанного для цвета границы. Полное объяснение см. в [4.1.3]. Средний уровень. Для всех видеосистем фоновый цвет может быть установлен функ- цией BH, прерывания 10H. Эта функция устанавливает также основные цвета. Чтобы указать, что надо изменить фоновый цвет, надо помес- тить 0 в BH, а код цвета в BL и выполнить прерывание. Кроме того, PCjr и EGA имеют специальную функцию для установки фонового цве- та. Это подфункция 1 функции 10H прерывания 10H. Надо поместить 10H в AH, 1 в AL и код цвета в BH. Никаких значений не возвра- щается. Низкий уровень. Для цветного графического адаптора биты 0-3 порта 3D9H (Ре- гистр выбора цвета) устанавливают цвет границы, когда экран на- ходмтся в текстовом режиме. Как обычно, назначение битов в восхо- дящем порядке - синий (B), зеленый (G), красный (R) и интенсив- ность. Поскольку этот адрес предназначен только для записи, все остальные биты этого регистра должны быть правильно установлены. Это бит 4, который, если его установить в 1, приводит к тому, что все фоновые цвета будут выводиться с высокой интенсивностью. ;---установка светлосинего цвета границы MOV AL,00001001B ;атрибут светлосинего цвета MOV DX,3D9H ;адрес регистра выбора цвета OUT DX,AL ;устанавливаем цвет границы Для PCjr массив ворот дисплея [4.1.1] имеет регистр, который устанавливает цвет границы. Это 4-битный регистр, причем биты 0-3 соответствуют синему, зеленому, красному и высокой интенсивности, когда установлены в 1. Для установки светлосинего цвета надо послать в регистр 1001. Регистр цвета границы - это регистр 2 массива ворот дисплея. Чтобы получить доступ к этому регистру надо сначала послать 2 в порт по адресу 3DAH. Затем надо послать данные по тому же адресу. Чтобы быть уверенным, что микросхема готова принять номер регистра, а не данные, надо сначала прочи- тать из порта 3DAH. Следующий пример устанавливает красный цвет границы (бит 2 установлен). MOV DX,3DAH ;адрес порта массива ворот дисплея IN AL,DX ;чтение для подготовки микросхемы MOV AL,2 ;номер требуемого регистра OUT DX,AL ;посылаем в порт MOV AL,4 ;устанавливаемс только бит 2 OUT DX,AL ;устанавливаем цвет границы Для EGA цвет границы устанавливается регистром сканирования (overscan). Это регистр номер 11H порта с адресом 3C0H. Надо сначала прочитать этот порт, чтобы переключить его на адресный регистр, затем послать туда номер 11H в качестве индекса, а затем послать данные. Имеют значение только младшие 4 бита данных, если только EGA не связан с улучшенным цветным дисплеем IBM, а в этом случае имеют значение младшие 6 битов, которые устанавливают цвет границы. 4.1.5 Очистка части/всего экрана. Очистка экрана состоит просто в записи пробела в каждую из позиций экрана (код ASCII - 32). Однако, если при выводе на экран были использованы ненормальные атрибуты, то должны быть также изменены и байты атрибутов. Операционная система обеспечивает простой способ очистки только части экрана. Высокий уровень. Бейсик для очистки экрана использует оператор CLS. При этом 25-я строка внизу экрана становится пустой только если был убран список значений функциональных клавиш с помощью команды KEY OFF. Байты атрибутов устанавливаются равными ASCII 7. В [4.5.1] дана процедура прокрутки, которая может быть использована в Бейсике для очистки окон на экране. Средний уровень. Операционная система предоставляет несколько способов очистки экрана. Какой из них Вы выберете зависит от того, какие средства требуются программе для достижения других целей. Первый метод - это просто сброс режима дисплея, используя функцию 0 прерывания 10H [4.1.2]. Для символьного экрана каждая позиция заполняется пробелом (ASCII 32), а все атрибуты устанавливаются нормальными (ASCII 7). Обычно этот метод хорош только в начале программы, когда все равно надо устанавливать режим работы дисплея. Для цветного графического адаптора и PCjr реинициализация режима дисплея приводит к катавасии на экране. Этот эффект отсутствует у монохромного адаптора и EGA. ;---очистка экрана путем установки нового режима MOV AH,0 ;номер функции установки режима дисплея MOV AL,2 ;код режима 80*25 черно-белого INT 10H ;очистка экрана Второй метод состоит в использовании функций 6 и 7 прерывания 10H, которые сдвигают экран. Число строк, на которое надо сдви- нуть экран помещается в AL и когда это число равно нулю экран очищается. Прерывание позволяет сдвигать только часть экрана, поэтому таким образом можно очистить отдельное окно на экране. Надо поместить координаты левого верхнего угла окна в CX, а коор- динаты правого нижнего угла в DX (номер строки в CH/DH, а номер столбца в CL/DL). Поместите атрибут, с которым должен чиститься экран в BH. Координаты отсчитываются от 0. ;---очистка окна между 3,4 и 13,15 MOV AH,6 ;используем процедуру сдвига MOV AL,0 ;число строк сдвига делаем равным нулю MOV BH,7 ;байт атрибутов для заполнения MOV CH,3 ;строка для верхнего левого угла MOV CL,4 ;столбец для левого верхнего угла MOV DH,13 ;строка для нижнего левого угла MOV DL,15 ;столбец для нижнего левого угла INT 10H ;чистим окно Третий метод заключается в использовании фукнции 9 прерывания 10H; которая выводит символ и атрибуты столько раз, сколько ука- зано в CX. Значение 2000 чистит весь экран, если курсор был уста- новлен в 0,0, используя метод показанный в [4.2.1]. AH должен содержать символ пробела, AL - байт атрибутов, а BH - номер стра- ницы дисплея. ;---установка курсора в левый верхний угол экрана MOV AH,2 ;функция установки курсора MOV BH,0 ;номер страницы MOV DX,0 ;координаты 0,0 INT 10H ;устанавливаем курсор ;---вывод символа пробела 2000 раз MOV AH,9 ;номер функции MOV CX,2000 ;число повторений вывода MOV AL,' ' ;символ пробела в AL MOV BL,7 ;атрибуты в BL INT 10H ;очистка экрана Наконец, DOS обеспечивает очистку экрана с помощью специальных Esc-последовательностей, которые работают с драйвером ANSI.SYS. Основные сведения о нем приведены в приложении Д. Эти последова- тельности - это строки, начинающиеся с символа Esc, а завершаю- щиеся ограничителем $. Такие строки выводятся функцией 9 прерыва- ния 21H, при этом DS:DX должны указывать на первый символ строки. DOS интерпретирует строку не выводя ее на дисплей. Чтобы стереть весь экран строка должна быть [2J. Чтобы стереть конец строки, начиная от позиции курсора (включая эту позицию), строка [K. ;---в сегменте данных CLEAR_LINE DB 27,'[K$' ;---очистка конца строки, начиная от позиции курсора MOV AH,9 ;функция вывода строки LEA DX,CLEAR_LINE ;DX должен указывать на начало строки INT 21H ;стираем конец строки Низкий уровень. На низком уровне надо просто поместить символы пробела и тре- буемый байт атрибутов в память дисплея, используя инструкцию STOSW. Вот пример для монохромного дисплея: MOV AX,0B000H ;указываем на память дисплея MOV ES,AX ; MOV DI,0 ;DI указывает на начало буфера MOV AL,32 ;символ пробела MOV AH,7 ;нормальные атрибуты MOV CX,2000 ;число повторений REP STOSW ;посылаем AX в ES:DI 2000 раз 4.1.6 Переключение между видеоадапторами. Машина может быть оснащена и монохромным и цветным адаптором, или одним из этих адапторов и EGA. Программа может выбирать, какой из мониторов должен быть активным, изменяя значения битов 4 и 5 в ячейке памяти 0000:0410. Установив оба этих бита в 1 мы выбираем монохромный адаптор. Изменив установку битов 5-4 на 10 устанавливаем графический адаптор в режиме 80 символов в строке, а на 01 - 40 символов в строке. И, наконец, изменив биты на 00, выбираем EGA. Во всех случаях Вы должны немедленно подать команду установки режима, поскольку BIOS имеет еще очень много регистров, которые надо изменить, прежде чем дисплей будет работать нормаль- но. Отметим, что хотя операционная система не может управлять одновременно двумя мониторами, программы могут осуществлять вывод на оба дисплея, используя прямое отображение в память [4.3.1] для адресов буфера неактивного монитора. Высокий уровень. В Бейсике надо просто использовать следующий код: 100 'Переключение на монохромный дисплей 110 KEY OFF: CLS 120 WIDTH 40 130 DEF SEG = 0 140 M = PEEK(&H410) 150 POKE &H410,M OR &H30 160 WIDTH 80 170 LOCATE,,1,12,13 180 KEY ON 100 'Переключение на цветной графический дисплей (80 символов) 110 KEY OFF: CLS 120 WIDTH 80 130 DEF SEG = 0 140 M = PEEK(&H410) 150 POKE &H410,(M AND &HCF) OR &H20 160 WIDTH 80 170 SCREEN 0 180 LOCATE,,1,6,7 190 KEY ON 100 'Переключение на EGA (80 символов) 110 KEY OFF: CLS 120 WIDTH 80 130 DEF SEG = 0 140 M = PEEK(&H410) 150 POKE &H410,M AND &HCF 160 WIDTH 80 170 SCREEN 0 180 LOCATE,,1,6,7 190 KEY ON Измените команды WIDTH и SCREEN, чтобы переключиться на другие начальные режимы дисплея. Низкий уровень. В ассемблере, как и в Бейсике, надо прямо изменить биты 4 и 5 по адресу 0000:0410. Надо сбросить режим дисплея сразу вслед за изменением. ;---переключение на монохромный монитор SUB AX,AX ;обнуляем AX MOV ES,AX ;устанавливаем ES на начало памяти MOV DL,ES:[410H] ;получаем байт по адресу 0000:0410 OR DL,00110000B ;устанавливаем биты 4 и 5 MOV ES:[410H],DL ;возвращаем байт MOV AH,0 ;фукция установки режима дисплея MOV AL,0 ;монохромный режим 80*25 INT 10H ;устанавливаем режим ;---переключение на цветной монитор (40 символов) SUB AX,AX ;устанавливаем ES на начало памяти MOV ES,AX ; MOV DL,ES:[410H] ;берем байт по адресу 0000:0410 AND DL,11001111B ;сбрасываем биты 4 и 5 OR DL,00010000B ;устанавливаем бит 4 MOV ES:[410H],DL ;возвращаем байт MOV AH,0 ;функция установки режима дисплея MOV AL,1 ;цветной режим 40*25 INT 10H ;устанавливаем режим ;---переключение на EGA SUB AX,AX ;устанавливаем ES на начало памяти MOV ES,AX ; MOV DL,ES:[410H] ;берем байт по адресу 0000:0410 AND DL,11001111B ;сбрасываем биты 4 и 5 MOV ES:[410H],DL ;возвращаем байт MOV AH,0 ;функция установки режима дисплея MOV AL,1 ;цветной режим 40*25 INT 10H ;устанавливаем режим Раздел 2. Управление курсором. Курсор служит двум целям. Во-первых, он служит указателем места на экране, в которое операторы программы посылают свой вывод. Во-вторых, он обеспечивает видимую точку отсчета на экране для пользователя программы. Только для второго применения курсор должен быть видимым. Когда курсор невидим (выключен), то он все равно указывает на позицию экрана. Это важно, поскольку любой вывод на экран, поддерживаемый операционной системой, начинается с текущей позиции курсора. Курсор генерируется микросхемой контроллера дисплея 6845, описанной в [4.1.1]. Эта микросхема имеет регистры, устанавливаю- щие размер и положение курсора. Микросхема 6845 делает только мерцающий курсор, хотя имеются программные способы создания не- мерцающего курсора [4.2.6]. Частота мерцания курсора не может быть изменена. В графических режимах курсор не выводится, хотя символы позиционируются на экране теми же самыми процедурами установки курсора, что и в текстовых режимах. Когда видеосистема работает в режиме, допускающем несколько дисплейных страниц, то каждая страница имеет свой собственный курсор и при переключении между страницами восстанавливается позиция курсора, которую он занимал, когда было последнее обраще- ние к восстанавливаемой странице. Некоторые режимы дисплея позво- ляют иметь до 8 дисплейных страниц и соответствующие им позиции курсора хранятся в наборе восьми 2-байтных переменных в области данных BIOS, начиная с адреса 0040:0050H. В каждой переменной младший байт содержит номер столбца, отсчитывая от 0, а старший байт содержит номер строки, также отсчитывая от 0. Когда исполь- зуется меньше чем 8 страниц, то используются переменные, располо- женные в более младших адресах памяти. 4.2.1 Установка курсора в абсолютную позицию. Для курсора могут быть установлены абсолютные координаты или координаты относительно его текущей позиции [4.2.2]. Абсолютные координаты могут меняться в пределах 25 строк и 80 (иногда 40) столбцов. Языки высокого уровня обычно отсчитывают координаты экрана, начиная с 1, и таким образом позиция левого верхнего угла 1,1. Язык ассемблера всегда начинает отсчет с нуля и позиция левого верхнего угла 0,0. Высокий уровень. Бейсик нумерует строки от 1 до 25, а столбцы от 1 до 80. Фор- мат оператора LOCATE, который устанавливает позицию курсора та- кой: LOCATE строка,столбец. Если установки курсора не делается, то он переходит в первую позицию строки после ввода возврата каретки, а сдвиг экрана начинается после того, как будет заполне- на 24-я строка. Чтобы вывести в 25-ю строку Вы должны использо- вать LOCATE (предварительно очистив эту строку с помощью KEY OFF). Для отмены автоматического сдвига экрана в строках 24 и 25 надо завершать оператор PRINT точкой с запятой (чтобы отменить сдвиг в позициях 24,80 и 25,80 надо использовать прямое отображе- ние в память [4.3.1]). Ниже приведен пример рисования вертикаль- ной черты с помощью одного из символов псевдографики в центре экрана. 100 FOR N = 1 TO 25 'повтор для каждой строки 110 LOCATE N,40 'установка курсора в середину строки 120 PRINT CHR$(186); 'печатаем вертикальную черту 130 NEXT 'переход к следующей строке Когда используется несколько дисплейных страниц, то оператор LOCATE действует на текущей активной странице памяти. Если стра- ница, выводимая в данный момент на монитор, не активна, то поло- жение курсора на экране не меняется. Отметим, что Бейсик имеет собственную переменную, хранящую текущее положение курсора. Если Вы подключите ассемблерную подпрограмму, которая изменит положе- ние курсора, то Бейсик проигнорирует новую позицию курсора, когда ему будет возвращено управление. Средний уровень. Операционная система предоставляет два способа позиционирова- ния курсора в абсолютную позицию на экране. Функция 2 прерывания 10H устанавливает курсор, относящийся к указанной странице памя- ти. Страницы нумеруются начиная с нуля и для монохромного дисплея номер страницы (находящийся в BH) должен всегда быть равным 0. DH:DL содержат строку и столбец, которые тоже нумеруются с 0. Курсор меняет свое положение на экране только если установка курсора относится к текущей активной странице. ;---установка курсора в строку 13, столбец 39 MOV AH,2 ;номер функции MOV BH,0 ;номер страницы MOV DH,13 ;строка MOV DL,39 ;столбец INT 10H ;позиционируем курсор Второй метод позиционирования курсора состоит в использовании специального драйвера устройства ANSI.SYS, который должен быть загружен при старте системы. В приложении Д даны необходимые сведения. Для вывода строки, содержащей информацию о строке и столбце используется функция 9 прерывания 21H. Строка начинается с символа Esc (ASCII 27), а завершается символом ограничителем $. Формат строки Esc[строка,столбецH$, где строка и столбец нуме- руются от нуля, а Esc обозначает код ASCII 27. Например, строка 27,'10;60H$' устанавливает курсор в строку 10, столбец 60. Хотя такой метод кажется излишне сложным, но он оказывается очень удобным при выводе ряда строк на экран, так как Esc-после- довательность обрабатывается как одна из строк набора. В данном примере три строки сообщения разбросаны по всему экрану. ;---в сегменте данных POSITION_1 DB 27,'[10;30H$' STRING_1 DB 'There are two options:$' POSITION_2 DB 27,'[13;32H$' STRING_2 DB '(1) Review part 1$' POSITION_3 DB 27,'[15;32H$' STRING_3 DB '(2) Move on to part 2$' ;---печать строк MOV AH,9 ;номер функции вывода строки LEA DX,POSITION_1 ;1-я строка позиционирования курсора INT 21H ;позиционируем курсор LEA DX,STRING_1 ;1-я текстовая строка INT 21H ;вывод строки LEA DX,POSITION_2 ;и т.д. INT 21H ; LEA DX,STRING_2 ; INT 21H ; LEA DX,POSITION_3 ; INT 21H ; LEA DX,STRING_3 ; INT 21H ; Низкий уровень. Регистры 14 и 15 микросхемы 6845 хранят положение курсора. Вы можете изменить их значение и курсор передвинется в соответствую- щую позицию экрана, но прерывания вывода на экран DOS и BIOS будут игнорировать Вашу установку и вернут курсор в старое поло- жение. Это происходит потому, что каждый раз при вызове этих прерываний, они восстанавливают регистры курсора, используя 2-байтное значение, хранящееся в области данных BIOS. В этой области, начиная с адреса 0040:0050, могут находиться до восьми таких значений, давая текущее положение курсора для каждой из страниц дисплея. Процедура низкого уровня должна модифицировать и эти значения, чтобы изменить состояние курсора полностью. Позиция курсора хранится в регистрах 14 и 15 как число от 0 до 1999, что соответствует 2000 (25*80) позициям экрана. Не спутайте эту систему нумерации с позициями видеобуфера от 0 до 3999, где каждый символ сопровождается еще байтом атрибутов (для получения эквивалентного указателя на позицию курсора надо сдвинуть указа- тель видеобуфера на 1 бит вправо). Обращаем также Ваше внимание, на то, что не надо менять местами старший и младший байты: в регистре 14 - старший, а 15 - младший. ;---в программе MOV BL,24 ;строка в BL (0-24) MOV BH,79 ;столбец в BH (0-79) CALL SET_CURSOR ;вызов процедуры ;---процедура установки курсора SET_CURSOR PROC ;получаем доступ к регистру младшего байта MOV DX,3B4H ;порт адресного регистра 6845 MOV AL,15 ;выбираем регистр 15 OUT DX,AL ;посылаем запрос ;вычисление позиции курсора MOV AL,80 ;умножаем номер строки на 80 MUL BL ;в AX - номер строки, умноженный на 80 MOV BL,BH ;переносим номер столбца в BL SUB BH,BH ;распространяем BL на BX ADD AX,BX ;вычисляем позицию курсора ;посылаем младший байт результата INC DX ;адресуем управляющий регистр OUT DX,AL ;посылаем младший байт ;получаем доступ к регистру старшего байта MOV AL,14 ;номер требуемого регистра DEC DX ;восстанавливаем порт адресного регистра OUT DX,AL ;посылаем запрос ;посылаем старший байт результата INC DX ;адресуем управляющий регистр MOV AL,AH ;помещаем старший байт в AL OUT DX,AL ;посылаем старший байт RET SET_CURSOR ENDP 4.2.2 Относительное позиционирование курсора Иногда бывает полезным сдвинуть курсор относительно его преды- дущей позиции: на строку вверх, на три столбца вправо, и т.д. Достаточно просто использовать для этой цели уже описанное абсо- лютное позиционирование курсора. Но для удобства MS DOS предос- тавляет некоторые возможности относительного перемещения курсора. Средний уровень. Функции относительного перемещения курсора выполняются Esc-последовательностями. Это строки, которые выводятся на экран с помощью функции 9 прерывания 21H. В приложении Д даны основы их использования. Такие последовательности интерпретируются MS DOS как команды перемещения курсора, а не вывод символов строки. Строка начинается с символа Esc (ASCII 27), затем идет символ [, а символ $ отмечает конец строки. Сама строка состоит из числа позиций, на которое надо сдвинуться, и кода направления. Чтобы сдвинуться на 3 позиции: вверх 3A вниз 3B вправо 3C влево 3D Числа записываются как коды ASCII. Не преобразуйте, например, 33C (33 пробела вправо) в 33,'C'; должно быть '33C'. В нижеприведен- ном примере цифры 1-8 помещаются через определенные интервалы поперек экрана, как метки столбцов данных. Промежутки между циф- рами генерируются Esc-последовательностями, которые сдвигают курсор вправо после вывода каждой цифры. ;---в сегменте данных CURSOR_RIGHT DB 27,'[9C$' ;---установка начальной позиции курсора MOV BH,0 ;ноиер страницы MOV DH,1 ;строка MOV DL,5 ;столбец MOV AH,2 ;функция установки курсора INT 10H ;установка курсора ;---вывод цифр LEA BX,CURSOR_RIGHT ;BX будет обмениваться с DX MOV CX,8 ;число цифр для вывода MOV DL,'0' ;начинаем с 0 NEXT_NUMBER: MOV AH,2 ;функция DOS для вывода символа INT 21H ;выводим символ INC DL ;переходим к следующему коду ASCII XCHG DX,BX ;помещаем указатель на строку в DX MOV AH,9 ;функция вывода строки INT 21H ;сдвигаем курсор на 9 позиций вправо XCHG DX,BX ;возвращаем в DX код ASCII LOOP NEXT_NUMBER ;переходим к следующей цифре Имеется также пара Esc-последовательностей, которые управляют переносом курсора на следующую строку при достижении им конца текущей строки. Когда устанавливается отсутствие переноса, то лишние символы при выводе отбрасываются. Строка, запрещающая перенос - Esc [=7h (или как данные, 27,'[=7h'). Для возврата к режиму автоматического переноса на следующую строку используется строка Esc [=7l (27,'[=7l'). 4.2.3 Включение и выключение курсора. Курсор генерируется микросхемой 6845. Он функционирует совер- шенно независимо от видеопамяти. Это значит, что при прямой адре- сации в память дисплея [4.3.1] программное обеспечение должно координировать перемещения курсора с вставкой нового символа в буфер. Отметим, что микросхема 6845 не может ни создавать немер- цающий курсор, ни изменить частоту его мерцания. В [4.2.6] пока- зано как сконструировать другие "искусственные" типы курсора. Высокий уровень. Интерпретатор Бейсика автоматически выключает курсор при за- пуске программы. Курсор появляется, когда используется оператор INPUT, но не в других случаях. Если Вашей программе необходим курсор, скажем для процедуры INKEY$, то он должен быть включен установкой третьего параметра оператора LOCATE в 1 (0 снова вык- лючит его). Напоминаем, что первые два параметра оператора LOCATE устанавливают строку и столбец, в которых должен выводиться кур- сор. 100 LOCATE 15,40,1 ;включить курсор, его позиция 15,40 или 100 LOCATE ,,1 ;включить курсор в текущей позиции и 100 LOCATE ,,0 ;снова выключить курсор Курсор будет оставаться при последующих появлениях оператора LOCATE без установки каждый раз третьего параметра. Однако надо отметить, что операторы INPUT и INPUT$ выключат его после их выполнения. Средний уровень. Ассемблерные программы оставляют курсор включенным, до тех пор, пока им не указано обратное. Операционная система не предос- тавляет специальных средств выключения курсора, но это легко сделать. Надо просто позиционировать курсор за пределы экрана, с помощью функции 2 прерывания 10H установить его в первую позицию 26-й строки. Помните, что координаты отсчитываются от нуля, так что этой позиции соответствуют координаты 25,0. MOV BH,0 ;номер страницы (всегда 0 для монохромного) MOV DH,25 ;строка MOV DL,0 ;столбец MOV AH,2 ;номер функции INT 10H ;устанавливаем курсор за пределы экрана Низкий уровень. Бит 6 регистра 10 микросхемы 6845 [4.1.1] выключает курсор, когда он установлен в 1, и включает его, когда сброшен в 0. Этот регистр содержит также значение "начальной строки" для курсора, которое вместе со значением "конечной строки" определяет толщину курсора [4.2.4]. Поскольку тип курсора не имеет значения, когда курсор выключен, то надо просто поместить в регистр 10 значение 32, чтобы установить бит 6. Чтобы восстановить курсор Вы должны также вернуть значение "начальной строки" курсора. Для нормаль- ного курсора это значение равно 11. Значение "конечной строки" при этих процедурах не меняется, поскольку оно хранится в другом регистре. ;---выключение курсора MOV DX,3B4H ;номер порта адресного регистра 6845 MOV AL,10 ;выбор регистра 10 OUT DX,AL ;посылаем запрос INC DX ;доступ к регистру через следующий порт MOV AL,32 ;устанавливаем бит 6 для выключения курсора OUT DX,AL ;выключаем курсор ;---обратное включение курсора MOV AL,11 ;значение "начальной строки" OUT DX,AL ;включаем курсор 4.2.4 Изменение формы курсора. Курсор может меняться по толщине от тонкой линии до максималь- ного размера, отводимого под символ. Он строится из коротких горизонтальных отрезков, верхний из которых называется "начальной строкой" курсора, а нижний - "конечной строкой". Для монохромного дисплея под каждый символ отводится 14 строк, пронумерованных от 0 до 13, начиная сверху. Промежутки между символами обеспечивают- ся двумя верхними строками и тремя нижними. Большинство символов распологаются в строках 2-10, хотя хвостики некоторых символов достигают линий 12 и 13, в то время как подчеркивание занимает одну двенадцатую строку. На 200-строчном цветном дисплее для каждого символа отводится только 8 строк, а символ рисуется в верхних семи строках. Эти 8 строк пронумерованы от 0 до 7, начиная сверху, и нормальный кур- сор формируется одной строкой 7. (Отметим, что на цветном дисплее нет подчеркивания, поскольку использование для подчеркивания строки 7 привело бы к тому, что символы сливались бы с располо- женными под ними.) Цветной дисплей высокого разрешения использует 14-строчный монохромный вариант, когда он работает в режиме высо- кого разрешения, а когда он работает в одном из цветных графичес- ких режимов, то он использует 8-строчный режим. Курсор может быть сформирован любой комбинацией прилегающих отрезков. Для монохромного дисплея он занимает все отведенное под символ место, когда "начальная строка" равна 0, а "конечная стро- ка" равна 13 (для графического дисплея надо использовать значение "конечной строки" равное 7). Если значения "начальной" и "конеч- ной" строки совпадают, то возникает однострочный курсор. Если номер "конечной строки" меньше чем "начальной" то возникает кур- сор, состоящий из двух частей, так как происходит перенос в верх- ние строки. Например, если "начальная строка" равна 12, а "конеч- ная" - 1, то сначала заполняется строка 12, затем 13, затем 0 и, наконец, 1. Курсор при этом принимает форму двух параллельных линий, указывающих верхнюю и нижнюю границы ряда, который он занимает. BIOS хранит 2-байтную переменную по адресу 0040:0060, которая содержит текущие значения "начальной" и "конечной" строк. Первый байт содержит значение "конечной строки", а второй - "начальной". Высокий уровень. В Бейсике оператор LOCATE может не только позиционировать курсор и включать или выключать его, но и управлять его формой. Парметры, устанавливающие "начальную" и "конечную" строки - это 4-е и 5-е число, следующие за словом LOCATE. Другие параметры могут быть опущены, если присутствуют разделяющие их запятые. Таким образом, чтобы создать толстый курсор, занимающий строки со 2 по 12, надо записать LOCATE ,,,2,12. Отметим, что Бейсик обычно выключает курсор, когда начинает выполнение программы. Как вклю- чить его обратно см. в [4.2.3]. Средний уровень. Функция 1 прерывания BIOS 10H устанавливает "начальную" и "конечную" строки курсора. В CH должна быть указана "начальная", а в CL - "конечная" строка. ;---установка "начальной" и "конечной" строк курсора MOV AH,1 ;номер функции MOV CH,0 ;начать курсор в верхней строке MOV CL,7 ;окончить курсор в восьмой строке INT 10H ; Низкий уровень. Регистры 10 и 11 контроллера дисплея 6845 содержат значения "начальной" и "конечной" строки, соответственно. Доступ к обоим регистрам осуществляется через порт 3B5H для монохромного адапто- ра и 3D5H - для цветного алаптора и PCjr. Предварительно надо послать номер требуемого регистра в адресный регистр, имеющий адрес порта 3B4H (см. [4.1.1]). Значения занимают младший конец каждого регистра. Однако регистр "начальной" строки (#10) битами 5 и 6 индицирует также должен ли выводиться курсор. Поскольку курсор выводится, когда оба этих бита сброшены в 0, то просто поместив в регистр номер "начал