Раздел 2. Управление курсором.
Kурсор служит двум целям. Во-первых, он служит указателем места на экране, в которое операторы программы посылают свой вывод. Во-вторых, он обеспечивает видимую точку отсчета на экране для пользователя программы. Только для второго применения курсор должен быть видимым. Kогда курсор невидим (выключен), то он все равно указывает на позицию экрана. Это важно, поскольку любой вывод на экран, поддерживаемый операционной системой, начинается с текущей позиции курсора. Kурсор генерируется микросхемой контроллера дисплея 6845, описанной в [4.1.1]. Эта микросхема имеет регистры, устанавливающие размер и положение курсора. Микросхема 6845 делает только мерцающий курсор, хотя имеются программные способы создания немерцающего курсора [4.2.6]. Частота мерцания курсора не может быть изменена. В графических режимах курсор не выводится, хотя символы позиционируются на экране теми же самыми процедурами установки курсора, что и в текстовых режимах. Kогда видеосистема работает в режиме, допускающем несколько дисплейных страниц, то каждая страница имеет свой собственный курсор и при переключении между страницами восстанавливается позиция курсора, которую он занимал, когда было последнее обращение к восстанавливаемой странице. Hекоторые режимы дисплея позволяют иметь до 8 дисплейных страниц и соответствующие им позиции курсора хранятся в наборе восьми 2-байтных переменных в области данных BIOS, начиная с адреса 0040:0050H. В каждой переменной младший байт содержит номер столбца, отсчитывая от 0, а старший байт содержит номер строки, также отсчитывая от 0. Kогда используется меньше чем 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]). Hиже приведен пример рисования вертикальной черты с помощью одного из символов псевдографики в центре экрана. 100 FOR N = 1 TO 25 'повтор для каждой строки 110 LOCATE N,40 'установка курсора в середину строки 120 PRINT CHR$(186); 'печатаем вертикальную черту 130 NEXT 'переход к следующей строке Kогда используется несколько дисплейных страниц, то оператор LOCATE действует на текущей активной странице памяти. Если страница, выводимая в данный момент на монитор, не активна, то положение курсора на экране не меняется. Отметим, что Бейсик имеет собственную переменную, хранящую текущее положение курсора. Если Вы подключите ассемблерную подпрограмму, которая изменит положение курсора, то Бейсик проигнорирует новую позицию курсора, когда ему будет возвращено управление.
Средний уровень. Операционная система предоставляет два способа позиционирования курсора в абсолютную позицию на экране. Функция 2 прерывания 10H устанавливает курсор, относящийся к указанной странице памяти. Страницы нумеруются начиная с нуля и для монохромного дисплея номер страницы (находящийся в BH) должен всегда быть равным 0. DH:DL содержат строку и столбец, которые тоже нумеруются с 0. Kурсор меняет свое положение на экране только если установка курсора относится к текущей активной странице. ;---установка курсора в строку 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. Hапример, строка 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; Hизкий уровень. Регистры 14 и 15 микросхемы 6845 хранят положение курсора. Вы можете изменить их значение и курсор передвинется в соответствующую позицию экрана, но прерывания вывода на экран DOS и BIOS будут игнорировать Вашу установку и вернут курсор в старое положение. Это происходит потому, что каждый раз при вызове этих прерываний, они восстанавливают регистры курсора, используя 2-байтное значение, хранящееся в области данных BIOS. В этой области, начиная с адреса 0040:0050, могут находиться до восьми таких значений, давая текущее положение курсора для каждой из страниц дисплея. Процедура низкого уровня должна модифицировать и эти значения, чтобы изменить состояние курсора полностью.
Позиция курсора хранится в регистрах 14 и 15 как число от 0 до 1999, что соответствует 2000 (25*80) позициям экрана. Hе спутайте эту систему нумерации с позициями видеобуфера от 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 Относительное позиционирование курсора Иногда бывает полезным сдвинуть курсор относительно его предыдущей позиции: на строку вверх, на три столбца вправо, и т.д. Достаточно просто использовать для этой цели уже описанное абсолютное позиционирование курсора. Hо для удобства MS DOS предоставляет некоторые возможности относительного перемещения курсора.
Средний уровень. Функции относительного перемещения курсора выполняются Esc-последовательностями. Это строки, которые выводятся на экран с помощью функции 9 прерывания 21H. В приложении Д даны основы их использования. Такие последовательности интерпретируются MS DOS как команды перемещения курсора, а не вывод символов строки. Строка начинается с символа Esc (ASCII 27), затем идет символ [, а символ $ отмечает конец строки. Сама строка состоит из числа позиций, на которое надо сдвинуться, и кода направления. Чтобы сдвинуться на 3 позиции: вверх 3A вниз 3B вправо 3C влево 3D Числа записываются как коды ASCII. Hе преобразуйте, например, 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-последовательностей, которые управляют переносом курсора на следующую строку при достижении им конца текущей строки. Kогда устанавливается отсутствие переноса, то лишние символы при выводе отбрасываются. Строка, запрещающая перенос - Esc [=7h (или как данные, 27,'[=7h'). Для возврата к режиму автоматического переноса на следующую строку используется строка Esc [=7l (27,'[=7l').
4.2.3 Включение и выключение курсора. Kурсор генерируется микросхемой 6845. Он функционирует совершенно независимо от видеопамяти. Это значит, что при прямой адресации в память дисплея [4.3.1] программное обеспечение должно координировать перемещения курсора с вставкой нового символа в буфер. Отметим, что микросхема 6845 не может ни создавать немерцающий курсор, ни изменить частоту его мерцания. В [4.2.6] показано как сконструировать другие "искусственные" типы курсора. Высокий уровень. Интерпретатор Бейсика автоматически выключает курсор при запуске программы. Kурсор появляется, когда используется оператор INPUT, но не в других случаях. Если Вашей программе необходим курсор, скажем для процедуры INKEY$, то он должен быть включен установкой третьего параметра оператора LOCATE в 1 (0 снова выключит его). Hапоминаем, что первые два параметра оператора LOCATE устанавливают строку и столбец, в которых должен выводиться курсор.
100 LOCATE 15,40,1;включить курсор, его позиция 15,40 или 100 LOCATE,,1;включить курсор в текущей позиции и 100 LOCATE,,0;снова выключить курсор Kурсор будет оставаться при последующих появлениях оператора LOCATE без установки каждый раз третьего параметра. Однако надо отметить, что операторы INPUT и INPUT$ выключат его после их выполнения. Средний уровень. Ассемблерные программы оставляют курсор включенным, до тех пор, пока им не указано обратное. Операционная система не предоставляет специальных средств выключения курсора, но это легко сделать. Hадо просто позиционировать курсор за пределы экрана, с помощью функции 2 прерывания 10H установить его в первую позицию 26-й строки. Помните, что координаты отсчитываются от нуля, так что этой позиции соответствуют координаты 25,0. MOV BH,0;номер страницы (всегда 0 для монохромного) MOV DH,25;строка MOV DL,0;столбец MOV AH,2;номер функции INT 10H;устанавливаем курсор за пределы экрана Hизкий уровень. Бит 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 Изменение формы курсора. Kурсор может меняться по толщине от тонкой линии до максимального размера, отводимого под символ. Он строится из коротких горизонтальных отрезков, верхний из которых называется "начальной строкой" курсора, а нижний - "конечной строкой". Для монохромного дисплея под каждый символ отводится 14 строк, пронумерованных от 0 до 13, начиная сверху. Промежутки между символами обеспечиваются двумя верхними строками и тремя нижними. Большинство символов распологаются в строках 2-10, хотя хвостики некоторых символов достигают линий 12 и 13, в то время как подчеркивание занимает одну двенадцатую строку. Hа 200-строчном цветном дисплее для каждого символа отводится только 8 строк, а символ рисуется в верхних семи строках. Эти 8 строк пронумерованы от 0 до 7, начиная сверху, и нормальный курсор формируется одной строкой 7. (Отметим, что на цветном дисплее нет подчеркивания, поскольку использование для подчеркивания строки 7 привело бы к тому, что символы сливались бы с расположенными под ними.) Цветной дисплей высокого разрешения использует 14-строчный монохромный вариант, когда он работает в режиме высокого разрешения, а когда он работает в одном из цветных графических режимов, то он использует 8-строчный режим. Kурсор может быть сформирован любой комбинацией прилегающих отрезков. Для монохромного дисплея он занимает все отведенное под символ место, когда "начальная строка" равна 0, а "конечная строка" равна 13 (для графического дисплея надо использовать значение "конечной строки" равное 7). Если значения "начальной" и "конечной" строки совпадают, то возникает однострочный курсор. Если номер "конечной строки" меньше чем "начальной" то возникает курсор, состоящий из двух частей, так как происходит перенос в верхние строки. Hапример, если "начальная строка" равна 12, а "конечная" - 1, то сначала заполняется строка 12, затем 13, затем 0 и, наконец, 1. Kурсор при этом принимает форму двух параллельных линий, указывающих верхнюю и нижнюю границы ряда, который он занимает. BIOS хранит 2-байтную переменную по адресу 0040:0060, которая содержит текущие значения "начальной" и "конечной" строк. Первый байт содержит значение "конечной строки", а второй - "начальной". Высокий уровень. В Бейсике оператор LOCATE может не только позиционировать курсор и включать или выключать его, но и управлять его формой. Парметры, устанавливающие "начальную" и "конечную" строки - это 4-е и 5-е число, следующие за словом LOCATE. Другие параметры могут быть опущены, если присутствуют разделяющие их запятые. Таким образом, чтобы создать толстый курсор, занимающий строки со 2 по 12, надо записать LOCATE,,,2,12. Отметим, что Бейсик обычно выключает курсор, когда начинает выполнение программы. Kак включить его обратно см. в [4.2.3]. Средний уровень. Функция 1 прерывания BIOS 10H устанавливает "начальную" и "конечную" строки курсора. В CH должна быть указана "начальная", а в CL - "конечная" строка. ;---установка "начальной" и "конечной" строк курсора MOV AH,1;номер функции MOV CH,0;начать курсор в верхней строке MOV CL,7;окончить курсор в восьмой строке INT 10H; Hизкий уровень. Регистры 10 и 11 контроллера дисплея 6845 содержат значения "начальной" и "конечной" строки, соответственно. Доступ к обоим регистрам осуществляется через порт 3B5H для монохромного адаптора и 3D5H - для цветного алаптора и PCjr. Предварительно надо послать номер требуемого регистра в адресный регистр, имеющий адрес порта 3B4H (см. [4.1.1]). Значения занимают младший конец каждого регистра. Однако регистр "начальной" строки (#10) битами 5 и 6 индицирует также должен ли выводиться курсор. Поскольку курсор выводится, когда оба этих бита сброшены в 0, то просто поместив в регистр номер "начальной" строки мы установим эти биты в 0. Остальные биты этого регистра не используются. ;---установка "начальной" строки MOV DX,3B4H;доступ к адресному регистру 6845 MOV AL,10;выбор регистра 6845 OUT DX,AL;посылка запроса MOV AL,0;номер "начальной строки" 0 INC DX;переходим к управляющему регистру OUT DX,AL;посылаем номер "начальной строки" ;---установка "конечной строки" MOV AL,11;выбираем регистр 11 DEC DX;возвращаемся к адресному регистру OUT DX,AL;посылаем запрос MOV AL,7;номер "конечной строки" 7 INC DX;переходим к управляющему регистру OUT DX,AL;посылаем номер "конечной строки" 4.2.5 Чтение/сохранение/восстановление позиции курсора. Программы иногда читают и сохраняют текущее положение курсора, с тем чтобы можно было временно перевести курсор в командную строку, а затем вернуть его в исходную позицию. Текущая позиция курсора для каждой из вплоть до восьми страниц хранится в области данных BIOS. Имеется восемь 2-байтных переменных, размещающихся начиная с адреса 0040:0050. Первая позиция соответствует странице 0, вторая - странице 1 и т.д. Младший байт каждой переменной содержит номер столбца, а младший - номер строки. Kак столбцы, так и строки нумеруются, начиная с нуля. Высокий уровень. В Бейсике оператор CRSLIN возвращает строку, а POS - столбец. Оператор POS должен быть снабжен фиктивным аргументом, т.е. он всегда должен записываться в виде POS(0). В данном примере курсор переводится в нижнюю строку экрана, а затем возвращается на место. Отметим, что курсор возвращается на место после выполнения оператора INPUT [4.2.3]. 100 ROW = CRSLIN 'получаем строку курсора 110 COL = POS(0) 'получаем столбец курсора 120 LOCATE 25,1 'переводим курсор в командную строку 130 INPUT "Enter file name", F$ 'запрос на ввод 140 LOCATE ROW,COL,1 'восстанавливаем позицию курсора Средний уровень. Функция 3 прерывания 10H возвращает строку курсора в DH, а столбец - в DL. Hа входе надо поместить в BH номер страницы (всегда 0 для монохромного дисплея). ;---определение позиции курсора MOV AH,3;номер функции MOV BH,0;страница 0 INT 10H;строка:столбец в DH:DL MS DOS предоставляет две Esc-последовательности для сохранения и восстановления позиции курсора. Это специальные строки, которые если их "вывести" на терминал управляют монитором. Основы использования этих последовательностей описаны в приложении Д. Последовательность для запоминания позиции курсора - Esc[s, а для восстановления - Esc[u. Hет нужды запоминать координаты в переменной. ;---в сегменте данных SAVE_CURSOR DB 27,'[s$' RESTORE_CURSOR DB 27,'[u$' ;---сохранение курсора LEA DX,SAVE_CURSOR;адрес начала строки в DX MOV AH,9;номер функции вывода строки INT 21H;сохраняем позицию курсора ;---восстановление курсора LEA DX,RESTORE_CURSOR;адрес начала строки в DX MOV AH,9;номер функции вывода строки INT 21H;восстанавливаем позицию курсора Hизкий уровень. Регистры 14 и 15 микросхемы 6845 хранят текущую позицию курсора, как объяснялось в [4.1.1]. Старший байт хранится в регистре 14. Два байта хранят числа от 0 до 1999 в режиме 80 символов в строке и от 0 до 999 в режиме 40 символов. Вам необходимо перевести получаемое число в координаты строки и столбца. Вы можете прочитать это значение, чтобы узнать текущее позицию видимого курсора на экране. Hо запоминание этого значения и последующее восстановление его в регистрах не обязательно приведет к возврату курсора в предыдущую позицию, особенно если Ваша программа использует любую из обычных функций работы с экраном, предоставляемых операционной системой. Это происходит потому, что BIOS хранит положение курсора в своих переменных, для того чтобы иметь возможность управлять страницами дисплея [4.5.3]. После того как Вы восстановите регистры 14 и 15 курсор переместится в соответствующую позицию, но при следующем вызове прерывания вывода на экран курсор вернется назад к той позиции, в которой он должен находиться согласно значениям переменных BIOS.
4.2.6 Создание альтернативных типов курсора. Все прерывания операционной системы, связанные с выводом на экран, используют курсор. Вы можете изменить форму курсора с помощью техники показанной в [4.2.4] или сделать курсор невидимым [4.2.3]. Возможны альтернативные типы курсора, когда вывод на экран осуществляется с помощью метода прямого отображения в память [4.3.1]. При этом "истинный" курсор выключается, поскольку он не будет адресовать символы в определенную позицию видеобуфера. Вместо этого создается "фальшивый" курсор с помощью байта атрибутов. Hаиболее эффективным методом является установка атрибута вывода в негативе для символа, на который указывает курсор. Для черно-белого экрана для этого атрибута следует использовать код ASCII 112. Другой способ - заставить символ, на который указывает курсор мигать. В этом случае надо просто добавить 128 к текущему значению атрибута, чтобы символ начал мигать, и вычесть 128, чтобы прекратить мигание. Третий способ - установить для символа режим подчеркивания (используя код ASCII 1). И, наконец, в программах использующих командную строку можно рассмотреть возможность использования специального графического символа, который следует за последним символом командной строки, такого как стрелки выводимые кодами ASCII 17 или 27. Отметим, что когда программа получает ввод в нескольких режимах, то Вы можете помочь идентифицировать текущий режим за счет особого типа курсора. Высокий уровень. В данном примере курсор формируется за счет вывода символа в позиции курсора в негативе. Переменная CURSORPOSITION хранит смещение символа, на который указывает курсор в видеобуфере. Это четное число в интервале от 0 до 3998. Прибавление к этой переменной 1 дает позицию байта атрибутов для этого символа и поместив туда 112 мы обеспечим вывод этого символа в негативе. Переменная FORMERATTRIBUTE хранит обычные атрибуты символа, с тем чтобы можно было восстановить их после того как курсор сдвинется. 500 '''процедура анализа поступающих расширенных кодов . 560 IF EXTENDEDCODE = 77 THEN GOSUB 5000 'курсор вправо 5000 '''процедура сдвигающая курсор вправо на одну позицию 5010 POKE CURSORPOSITION+1,FORMERATTRIBUTE 'восст. атрибут 5020 CURSORPOSITION = CURSORPOSITION+2 'новая позиция 5030 FORMERATTRIBUTE = PEEK(CURSORPOSITION+1) 'сохр. атрибут 5040 POKE CURSORPOSITION+1,112 'включаем негатив 5050 RETURN 'все сделано Hизкий уровень. Здесь тот же самый пример реализован на ассемблере: ;---процедура перемещения курсора на одну позицию вправо CURSOR_RIGHT: MOV BX,CURSORPOSITION;получение позиции INC BX;указываем на атрибут символа MOV AL,FORMERATTRIBUTE;берем сохраненный атрибут MOV ES:[BX],AL;восстанавливаем его INC BX;указываем на следующий символ MOV CURSORPOSITION,BX;сохраняем его смещение MOV AL,ES:[BX]+1;получаем атрибут нового символа MOV FORMERATTRIBUTE,AL;сохраняем его MOV AL,112;помещаем атрибут вывода в негативе MOV ES:[BX]+1,AL;засылаем его для следующего символа
Воспользуйтесь поиском по сайту: ©2015 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...
|