Ввод символов с клавиатуры
Подпрограмма Inline
Текст подпрограммы, выполняющей ввод символов с клавиатуры и простые функции редактирования, приведен в примере 5.28. В разделе данных задачи надо выделить буфер, имеющий метку Linbuf, его размер должен быть достаточен для размещения вводимого текста (не более 80 байтов). В конце текста подпрограмма записывает пустой байт.
Пример 5.28. Ввод символов текста в буфер строки (Linbuf).
Inline: lea si, Linbuf si = адрес буфера строки ; Ввод очередного символа и управление курсором Gs: cli запрещаем прерывания mov CurStat, 03 CurStat = 3 mov Ntick, 09 Ntick =9 (0.5 сек) sti разрешаем прерывание call TglCrsr рисуем изображение курсора mov ah, 00 код запроса ввода символа int 16h ожидание ввода символа cli запрещаем прерывания test CurStat, 02 курсор нарисован? mov CurStat, 00 CurStat = О sti разрешаем прерывания je Prevanl › нет, курсор погашен call TglCrsr гашение курсора; Предварительный анализ введенного кода Prevanl: cmp ah, 35h код ASCII существует? ja Detail › нет, это служебный символ cmp al, 2Oh это управляющий символ? jb Detail › да mov ds:[si], al запись ASCII кода в буфер строки inc si коррекция адреса call outsgn вывод символа на экран jmp SHORT Gs переход на продолжение ввода; Детальный анализ служебных кодов Detail: crap ah, ICh это символ "Enter"? jne Cont_l › нет, продолжение анализа mov byte ptr ds:[di], 00; запись признака конца текста ret возврат из подпрограммы Cont_l: cmp ah, OEh это символ "возврат на шаг"? jne Cont_2 › нет, продолжение анализа call prevpos адрес предыдущего знакоместа mov al, ' ' al = код символа "пробел" call outsgn стираем предыдущий символ dec si и удаляем его из буфера строки call prevpos адрес предыдущего знакоместа jmp short Gs переход на продолжение ввода Cont 2: jmp short Gs здесь можно продолжить анализ ; Вьиисление позиции предыдущего символа Prevpos:sub di, 08 уменьшение адреса видеопамяти jnc @F › смена окна не нужна mov ax, GrUnit ax = единица приращения памяти sub Cur_win, ax Cur_win = Cur_win – GrUnit @@: ret возврат из подпрограммы
В текст примера 5.28 вставлены строки комментария, поясняющего назначение основных групп команд. В каждой из этих групп, кроме подпрограммы Prevpos, выполняются действия, смысл которых описан выше, поэтому здесь мы уточним некоторые особенности реализации.
Прерывания от таймера надо запрещать на время работы с переменными Ntick и CurStat. Напомним, что команда cli запрещает, a sti разрешает маскируемые прерывания. В примере 5.28 они используются дважды при разрешении и запрещении изменения состояния рисунка курсора. Во втором случае между test Curstat, 02 и je Prevani расположены две команды, выполнение которых не изменяет состояние регистра флагов (признаков). Это просто трюк, упрощающий проверку состояния и очистку байта CurStat.
Коды введенного с клавиатуры символа находятся в регистрах ah (scan) и al (ASCII). Если код ASCII существует и его значение больше, чем iFh, то изображение символа выводится на экран и продолжается ввод.
Если обнаружен код служебного символа, то производится его детальный анализ. В примере 5.28 обрабатываются коды только двух символов – Enter и <возврат на шаг>. В других случаях подпрограмма просто игнорирует введенный код и ждет ввода с клавиатуры очередного символа. Если вы захотите дополнить подпрограмму, то вместо команды jmp short GS, имеющей метку Cont_2, вставьте команды, выполняющие анализ и обработку нужных вам кодов.
При обнаружении кода символа Enter в буфер строки записывается пустой байт и происходит возврат из подпрограммы.
Символ <возврат на шаг> обрабатывается так. Устанавливается адрес предыдущего знакоместа, в него выводится символ <пробел>, последний введенный символ удаляется из буфера строки и повторно устанавливается адрес предыдущего знакоместа. Установку адреса предыдущего знакоместа выполняет подпрограмма Prevpos, которая понадобится, если вы добавите обработку клавиши <левая стрелка> для перемещения влево по строке.
Пример вызова Inline
Для иллюстрации использования описанной подпрограммы мы перепишем текст примера 5.23, заменив в нем строку комментария двумя командами. Результат показан в примере 5.29.
Пример 5.29. Вывод текста информационной строки.
Outlnf: push Cur win сохранение исходного значения Cur win mov ax, Inflinw ax = номер окна информационной строки mov Cur_win, ax Cur_win = ax call Savinfo сохранение исходного фона jmp short outstr переход на выборку первого символа outl: call outsgn вывод на экран очередного символа outstr: lodsb al = код очередного символа (al = ds:si) or al, al конец выводимого текста? jne outl › нет, переход на метку outl call Inline ввод строки теста с клавиатуры call Delinfo удаление информационной строки с экрана pop Cur_win восстановление исходного значения Cur_win call setwin восстановление исходного окна ret возврат из подпрограммы
При выполнении примера 5.29 исходный фон будет сохранен на месте информационной строки, на экран будет выведен текст подсказки оператору, введен его ответ с эхо-печатью и записью введенных кодов в массив Linbuf и, после нажатия оператором на клавишу Enter, восстановлен исходный фон на месте информационной строки. Перечисленные действия выполняются с помощью подпрограмм, описанных в данном разделе. Использование данного примера для ввода спецификации файла описано в Приложении А данной книги.
В этой главе автор стремился ответить на основные вопросы, которые приходится решать при программировании вывода текста на экран в графических режимах VESA. Насколько ему это удалось – судить читателю, а мы переходим к рассмотрению следующей, не менее важной темы, связанной с управлением процессом вычислений, выполняемых в задачах.