«Мир ПК» , № 08, 1997 144 прочтения
Еще раз об ANSI.SYS для программирующих на QuickBASIC
Наблюдения за книжными прилавками показывают, что в последнее время снова накатила волна повышенного интереса к старым инструментальным средствам, таким как, например, QuickBASIC. Особым вниманием в конференциях сетей The Basic Network (см. врезку "Как найти The Basic Network") и FIDO пользуются работы отечественных авторов Григория Зельднера и Андрея Колесова. В материалах, передаваемых по сетям, много места уделяется программированию на QuickBASIC разнообразных устройств: модемов, звуковых плат и т. д. В данной публикации по программированию на этом замечательном простом и мощном языке высокого уровня мы затронем методы работы с так называемыми ESC-последовательностями, которые можно реализовать в коммуникационных программах при поддержке драйвера ANSI.SYS. Надеемся, что материал будет полезен и интересен как для опытных, так и для начинающих программистов.
ANSI.SYS: что это?
Драйвер ANSI.SYS - программа, значительно расширяющая возможности ввода с клавиатуры и вывода на экран. ANSI.SYS постоянно просматривает информацию, выводимую на экран, и выискивает в ней специальные коды, являющиеся командами для драйвера. Он распознает команды и затем удаляет их, так что на экране дисплея эти коды команд не появляются. ANSI.SYS выполняет разные функции. Но используя его в коммуникационных программах, вы можете представить себе ANSI.SYS как драйвер, который, интерпретируя специальные последовательности символов, называемые ANSI- или ESC-последовательностями, может очищать весь экран или часть его, помещать курсор в заданную позицию, изменять цвет шрифта и фона, выводить на экран данные.
Команды драйвера ANSI идентифицируются специальным кодом: в первом байте находится число 1BH, на Бейсике записывается как CHR$(27), называемое символом ESC (далее <ESC>), а второй байт - 5BH (левая квадратная скобка), на Бейсике - CHR$(91). За этими байтами следуют параметры команды, а в заключение собственно сами команды. Параметры команды - это либо числа (в форме ASCII-символов, интерпретируемых как десятичные цифры), либо строки ASCII-символов, заключенные в кавычки, например: "строка параметров". Если в команде несколько параметров, то они разделяются точкой с запятой. Собственно код команды, завершающий команду драйвера ANSI, это всегда один символ алфавита.
Команды ANSI.SYS
Драйвер ANSI распознает множество команд, но все они распадаются на две категории: команды управления экраном и команды преобразования ввода с клавиатуры. Команды управления экраном, обрабатываемые драйвером ANSI, образуют целую систему для работы с полным экраном и могут выполнить почти все, что вообще позволяет экран дисплея. В нее входят команды перемещения курсора, очистки экрана, установки атрибутов изображения (цвет, подчеркивание, мерцание и т. д.), изменения режима изображения с текстового на графический и наоборот.
Когда к драйверу поступает какая-либо из команд преобразования ввода с клавиатуры, то он просматривает ее и заменяет символ, полученный в результате нажатия на одну из клавиш, на другой символ или даже целую цепочку символов.
Оба типа этих команд передаются драйверу ANSI одним и тем же путем - в потоке символов, выводимых на экран дисплея.
В коммуникационных программах наиболее часто применяются 13 ANSI-команд, обозначаемых символами: H A B C D R n f s u J K m. Обращайте свое внимание на регистр букв! "A" не эквивалентно "a" (см. врезку "Синтаксис и краткое описание некоторых ANSI-команд").
Доступ к ANSI.SYS из коммуникационной программы
Для доступа к ANSI.SYS вы должны открыть консоль как файл. (Исторически сложившийся термин "консоль" в этом случае обозначает то место, куда в данный момент происходит вывод информации. Открыть консоль как файл - назначить вывод данных в файл. - Прим. ред.) Это обеспечит доступ к драйверу ANSI.SYS, вызов которого должен быть помещен в вашем файле CONFIG.SYS. Открытие консоли легко осуществляется в QuickBASIC. Вам лишь необходимо ввести следующую команду:
OPEN "CON" FOR OUTPUT AS filenum
где filenum - номер файла. Например, если вы хотите открыть консоль как файл под номером 2, введите команду:
OPEN "CON" FOR OUTPUT AS 2
Следовательно, все, что вы будете писать в файл номер 2, будет обрабатываться не QuickBASIC, а ANSI.SYS.
Использование драйвера ANSI.SYS
Итак, мы собираемся управлять экраном только посредством ANSI.SYS. Трудность в том, что драйвер ANSI.SYS и интерпретатор языка QuickBASIC ничего "не знают" друг о друге. Если вы хотите использовать ANSI.SYS для работы с экранными функциями, не употребляйте конструкции типа LOCATE, PRINT, CLS, COLOR. Вместо них применяйте эквивалентные команды и посылайте их через ANSI.SYS, вводя:
PRINT #filenum, ANSIcommand;
где filenum - номер файла, который вы ранее открыли, а ANSIcommand - специальная команда ANSI, включающая любые необходимые параметры.
Другой важный момент - сохранение нескольких общих ANSI-символов и команд в строковых переменных типа SHARED. (SHARED обозначает, что объявленные таким образом переменные можно будет использовать во всех подпрограммах.)
Это облегчит программирование и увеличит скорость выполнения. Делается это следующим образом:
DIM SHARED ao$, cs$, es$, hc$
es$ = CHR$(27) 'это ESC-символ
ao$ = es$ + "[0m" 'отключаем все атрибуты экрана
cs$ = es$ + "[2J" 'стираем содержимое экрана и возвращаем курсор
hc$ = es$ + "[f" 'это возвращает курсор
Приведем некоторые примеры. Примем открытую консоль за файл номер 2. Предположим, что вы хотите изменить цвет шрифта на светло-синий на черном фоне перед печатью какого-либо текста. Вы могли бы воспользоваться оператором COLOR 11, 0. Но то же самое может сделать сам ANSI.SYS. Для этого вам нужно ввести следующую команду:
PRINT #2, es$ + "[0;1;36;40m";
где 0 - отключает все атрибуты; 1 - устанавливает жирный шрифт; 36 - устанавливает синий цвет шрифта; 40 - устанавливает черный фон; m - устанавливает графическое представление.
Допустим, вы хотите очистить экран и возвратить курсор. Для этого можно использовать оператор CLS, но воспользуемся конструкцией:
PRINT #2, cs$;
Предположим, вы редактируете поле и хотите имитировать принудительный возврат на один символ. Можно было бы воспользоваться последовательностью команд на QuickBASIC:
LOCATE , POS(0) - 1
PRINT " ";
LOCATE , POS(0) - 1
Заменим их аналогичными, но для драйвера ANSI:
PRINT #2, es$ + "[1D";
PRINT #2, " ";
PRINT #2, es$ + "[1D";
Необходимо заметить, что приведенная выше программа работает только с цветными мониторами.
Работа с портами COM3 и COM4 в QuickBASIC
В приведенном исходном тексте используются обращения к коммуникационным портам COM1 и COM2. Как известно, QuickBASIC может работать только с ними. А что же делать, если модем подключен к порту COM3 или COM4?
Такое устройство, как мышь, использующее COM1, конфликтует со всеми устройствами на COM3 (аналогичная проблема для COM2/ COM4). Что же делать, если модем установлен на COM4 и вы хотите использовать операторы OPEN COMx? Используйте адрес для COM4, по которому должен "сидеть" COM2.
Распечатки карт памяти для IBM-совместимых ПК показывают, что в области памяти, принадлежащей базовой системе ввода-вывода (BIOS), по адресам 0000:400 - 407 можно найти значения адресов для адаптеров последовательных портов COM1 - COM4. Таким образом, если у вас есть четыре коммуникационных порта, то при вводе команды D 0000:400 в командной строке отладчика Debug вы увидите примерно следующее:
0000:0400 F8 03 F8 02 E8 03 00 00-78 03 00 00 00 00 00 00 ........x.......
Числа F803 и F802 представляют собой адреса COM1 (3F8) и COM2 (2F8). Позиции для COM3 и COM4 будут содержать только нули.
В листинге 2 дан исходный текст программы, выполняющей последовательность действий:
1. Сохраняем текущие адреса в областях BIOS ($h400 - $h403) для дальнейшего сброса.
2. Определяем, какой порт необходим, и заполняем оператором POKE соответствующий адрес в COM1 ($h400 - $h401) или COM2 ($h402 - $h403).
3. Используем операторы OPEN COMx.
4. В конце программы восстанавливаем старые адреса, иначе могут возникнуть проблемы с ссылающимися на них устройствами.
Аналогичные функции выполняет простая программа, приведенная в листинге 3.
Таким образом, в зависимости от того, хотите ли вы больше возможностей и готовы пожертвовать для этого дополнительным местом, или привыкли довольствоваться малым, можете выбрать между программами, приведенными на листингах 2 или 3.
Михаил Евдокимов - программист, координатор сети The Basic Network. E-mail: michaely@mati.edu.ru
Как найти The Basic Network
Сеть The Basic Network (посвящена различным вопросам программирования не только на Бейсик) вышла за пределы Москвы: существуют узлы в таких городах, как Можайск, С.-Петербург, Иркутск, Междуреченск, Одесса, Киев. В ближайшее время откроются представительства в дальнем зарубежье (США, Англии, Канаде). За дополнительной информацией о сети The Basic Network вы можете обратиться по следующим телефонам в Москве: (095) 351-04-72 (Сергей Чабунин), 356-50-07 (Михаил Евдокимов), 356-52-82 (Андрей Юров), 412-38-76 (Михаил Ивановский), 232-11-66 (Игорь Кирисюк); в Иркутске: (395) 234-40-28 (Максим Пензин); в Одессе: 380 (482) 26-07-04 (Игорь Володин). По этим же телефонам вы можете договориться о подключении к сети. Можно послать запрос по затронутой в статье теме по электронной почте: michaely@mati.edu.ru, bcs@mati.edu.ru, maxp@max.irk.ru, vis@te.net.ua, а также через Internet: misha@ivanovsky.msk.ru, написав в поле Subject заголовка сетевые адреса координаторов The Basic Network: 777:5020/0 или 777:5020/1.
Синтаксис и краткое описание некоторых ANSI-команд
<ESC>[row;colH - команда перемещает курсор в позицию, определенную параметрами row (ряд), col (колонка). Изначально каждый параметр равен единице. Ни один из них не возвращает текущее положение курсора.
<ESC>[#A - команда передвигает курсор вверх на число строк, определенное параметром #. Изначально его значение равно единице. Команда игнорируется, если курсор находится в самом верхнем ряду.
<ESC>[#B - команда передвигает курсор вниз на число строк, определенное параметром #. Изначально его значение равно единице. Команда игнорируется, если курсор находится в самом нижнем ряду.
<ESC>[#C - команда перемещает курсор на число строк, определенное параметром #. Изначально его значение равно единице. Команда игнорируется, если курсор находится в крайней правой колонке.
<ESC>[#D - команда перемещает курсор на число строк, определенное параметром #. Изначально его значение равно единице. Команда игнорируется, если курсор находится в самой левой колонке.
<ESC>[row;colR - команда позиции курсора; генерируется командой состояния устройства. Параметр ряда содержит номер текущей строки и колонки, на которой находится курсор.
<ESC>[6n - команда, вызывающая команду состояния позиции курсора.
<ESC>[row;colf - команда горизонтальной и вертикальной позиций; работает так же, как и команда позиционирования курсора.
<ESC>[s - команда сохраняет текущие параметры позиции курсора, т.е. номера колонки и ряда; используется с командой восстановления позиции курсора.
<ESC>[u - команда восстанавливает заранее сохраненные параметры позиции.
<ESC>[2J - команда очищает экран и возвращает курсор в исходную позицию.
<ESC>[K - команда очищает содержимое строки от текущей позиции курсора до конца строки.
<ESC>[#;...;#m - команда устанавливает графическое представление и меняет цвет экрана согласно указанным параметрам #. Ниже приведены возможные значения параметров # и описание каждого из них:
Адреса коммуникационных портов:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Листинг 1
' C.BAS - это элементарная коммуникационная программа,
' написанная на языке Microsoft QuickBASIC 4.5. Она
' открывает компьютерную консоль как файл, и все выводы
' на экран осуществляет через CON.
' Если у пользователя установлен правильно драйвер
' ANSI.SYS, то тогда C.BAS может использовать
' ANSI-ESC-последовательности для вывода цветов и
' ANSI-анимации на пользовательские экраны.
' Требования:
' 1) IBM-совместимый компьютер со свободными 128 Kбайт оперативной памяти;
' 2) модем;
' 3) цветные монитор и видеоплата;
' 4) загруженный в память драйвер ANSI.SYS.
DECLARE SUB bottomline () ' Печатает 25 строку
DECLARE SUB delay () ' Задержка времени
DECLARE SUB getparms () ' You need these
DECLARE SUB hangup () ' Повесить трубку
DECLARE SUB initialize () ' Инициализация
DECLARE SUB makeacall () ' Позвонить
DECLARE SUB opencomport () ' Открыть порт
DECLARE SUB outtahere () ' Выход!
DIM SHARED ao$ ' Большинство подпрограмм
DIM SHARED cs$ ' требует переменные, объявленные
DIM SHARED bp$ ' с помощью SHARE
DIM SHARED comport$
DIM SHARED comspec$
DIM SHARED es$
DIM SHARED dialmode$
DIM SHARED firsttime$
DIM SHARED init$
DIM SHARED hc$
ON ERROR GOTO errorroutine
DEFINT A-Z
es$ = CHR$(27) ' Код клавиши <Esc> в es$
ao$ = es$ + "[0m" ' Выключить атрибуты
cs$ = es$ + "[2J" ' Очистить экран
f1$ = CHR$(0) + CHR$(59) ' Клавиша <F1>
f10$ = CHR$(0) + CHR$(68) ' Клавиша <F10>
ff$ = CHR$(12)
hc$ = es$ + "[f" ' Возвратить курсор
OPEN "CON" FOR OUTPUT AS 2 ' Открыть консоль как файл
CALL initialize ' Подпрограмма инициализации
PRINT #2, ao$; ' Выключить атрибуты
PRINT #2, cs$ + " " + hc$; ' Возвратить курсор
CALL getparms
CALL opencomport ' Открыть порт
CALL bottomline ' Печатать самую
' нижнюю строку (25)
DO ' Бесконечный цикл
a$ = INKEY$ ' Проверка клавиатуры
IF a$ <> "" THEN ' Нажата ли клавиша?
SELECT CASE a$ ' Что делать?
CASE es$ ' Клавиша <Esc>?
CALL hangup ' Повесить трубку
CASE f1$ ' Клавиша <F1>?
CALL makeacall
CASE f10$ ' Клавиша <F10>?
CALL outtahere ' Выходим!
CASE ELSE ' Какие-нибудь другие клавиши?
PRINT #1, a$; ' Послать ее в модем
END SELECT
END IF
WHILE NOT EOF(1) ' Прибыли ли символы?
b$ = INPUT$(LOC(1), #1) ' Принять символы
WHILE INSTR(b$, ff$) <> 0 ' Если ASCII-формат,
q = INSTR(b$, ff$) ' тогда символы получены
b$ = LEFT$(b$, q - 1) + cs$ + MID$(b$, q + 1)
' поменять ее на ANSI
WEND
PRINT #2, b$; ' Печатать символы
a$ = INKEY$ ' Проверка клавиатуры
IF a$ <> "" THEN ' Нажата ли клавиша?
SELECT CASE a$ ' Что делать?
CASE es$ ' Клавиша <Esc>?
CALL hangup ' Повесить трубку
CASE f1$ ' Клавиша <F1>?
CALL makeacall
CASE f10$ ' Клавиша <F10>?
CALL outtahere ' Выходим!
CASE ELSE ' Какие нибудь другие клавиши?
PRINT #1, a$; ' Послать a$ в модем
END SELECT
END IF
WEND
LOOP ' Конец цикла
errorroutine:
PRINT "Error type "; ERR; " occurred!"
RESUME NEXT
SUB bottomline ' Печатаем строку 25
PRINT #2, cs$; ' Очищаем экран
PRINT #2, es$ + "[25;1f"; ' LOCATE 25, 1
PRINT #2, es$ + "[1;37;44m"; 'Яркий белый на голубом фоне
PRINT #2, "Communication (Little BBS)
programe writtened using QB 4.5";
PRINT #2, es$ + "[1;33m"; ' Желтый на голубом фоне
PRINT #2, " <Esc>-Hang Up <F1>-Dial <F10>-End";
PRINT #2, ao$; ' Выключить атрибуты
PRINT #2, hc$ + " " + hc$; ' Курсор в начало
END SUB
SUB delay ' Подпрограмма задержки
now! = TIMER
WHILE TIMER - now! < 1.5
WEND
END SUB
' Подпрограмма получения параметров PRINT #2, cs$;
SUB getparms
'Очистим экран
IF firsttime$ = "on" THEN ' Пропустить это, если
firsttime$ = "off" ' это ваш первый звонок;
ELSE
PRINT #2, es$ + "[1;36m"; ' Светло-синий
PRINT #2, hc$; ' Курсор в начало
PRINT #2, "Modem speed "; ' Скорость модема
PRINT #2, es$ + "[1;33m"; ' Желтый
PRINT #2, "3";
PRINT #2, es$ + "[1;36m"; ' Светло-синий
PRINT #2, "00 ";
PRINT #2, es$ + "[1;33m"; ' Желтый
PRINT #2, "1";
PRINT #2, es$ + "[1;36m"; ' Светло-синий
PRINT #2, "200 ";
PRINT #2, es$ + "[1;33m"; ' Желтый
PRINT #2, "2";
PRINT #2, es$ + "[1;36m"; ' Светло-синий
PRINT #2, "400 ";
PRINT #2, es$ + "[1;33m"; ' Желтый
PRINT #2, "9";
PRINT #2, es$ + "[1;36m"; ' Светло-синий
PRINT #2, "600 [";
PRINT #2, es$ + "[1;33m"; ' Желтый
PRINT #2, "1";
PRINT #2, es$ + "[1;36m"; ' Светло-синий
PRINT #2, "/";
PRINT #2, es$ + "[1;33m"; ' Желтый
PRINT #2, "2";
PRINT #2, es$ + "[1;36m"; ' Светло-синий
PRINT #2, "/";
PRINT #2, es$ + "[1;33m"; ' Желтый
PRINT #2, "3";
PRINT #2, es$ + "[1;36m"; ' Светло-синий
PRINT #2, "/";
PRINT #2, es$ + "[1;33m"; ' Желтый
PRINT #2, "9";
PRINT #2, es$ + "[1;36m"; ' Светло-синий
PRINT #2, "]? ";
PRINT #2, es$ + "[1;33m"; ' Желтый
bp$ = "" 'Инициализация в нуль
WHILE bp$ <> "1" AND bp$ <> "2"
AND bp$ <> "3" AND bp$ <> "9"
bp$ = INKEY$ ' Ждем, пока не нажаты <1>, <2>, <3>
WEND ' или <9>
comspec$ = "COM" + comport$ + ":" ' Инициализировать
' comspec$
SELECT CASE bp$ ' Выбрать
CASE "1" ' Нажата 1?
PRINT #2, "1200 bps"; ' Скорость 1200 bps
comspec$ = comspec$ + "1200" 'Добавить 1200
'к comspec$
CASE "2" ' Нажата 2?
PRINT #2, "2400 bps"; ' Скорость 2400 bps
comspec$ = comspec$ + "2400" 'Добавить 2400
'к comspec$
CASE "3" ' Нажата 3?
PRINT #2, "300 bps"; ' Скорость 300 bps
comspec$ = comspec$ + "300" 'Добавить 300
'к comspec$
CASE "9" ' Нажата 9?
PRINT #2, "9600 bps"; ' Скорость 9600 bps
comspec$ = comspec$ + "9600" 'Добавить 9600
'к comspec$
END SELECT ' Конец выбора
comspec$ = comspec$ + ",N,8,1,DS" 'К полученной
'comspec$
'добавить N81DS
END IF
END SUB
SUB hangup ' Byebye, BBS
PRINT #2, cs$; ' Очистим экран
PRINT #2, es$ + "[1;5;37;41m"; ' Темно-белый на красном
PRINT #2, es$ + "[25;39H"; ' LOCATE 25, 39
PRINT #2, "Wait"; ' Ждите
CALL delay ' Вызвать подпрограмму задержки
PRINT #1, "+++"; ' "Разбудить" модем
CALL delay ' Вызвать подпрограмму задержки
PRINT #1, "ATH0" ' Повесить трубку
PRINT #2, ao$; ' Убрать атрибуты
IF NOT EOF(1) THEN
b$ = INPUT$(LOC(1), #1)
END IF
CALL bottomline
END SUB
SUB initialize ' Инициализация модема
PRINT #2, ao$; ' Убрать атрибуты
PRINT #2, cs$; ' Очистить экран
PRINT #2, es$ + "[1;36m"; ' Светло-синий
PRINT #2, "Modem initialization string? ";
PRINT #2, es$ + "[1;33m"; ' Желтый
a$ = ""
WHILE a$ <> CHR$(13) ' Пока не нажата <Enter>
a$ = INKEY$ ' Получить код клавиши
IF a$ = CHR$(8) AND LEN(init$) THEN ' <Backspace>?
PRINT #2, es$ + "[1D";
PRINT #2, " ";
PRINT #2, es$ + "[1D";
IF LEN(init$) > 1 THEN
init$ = LEFT$(init$, LEN(init$) - 1)
ELSE
init$ = ""
END IF
ELSE
a$ = UCASE$(a$)
IF a$ > " " THEN
init$ = init$ + a$ ' Добавить символ к init$
PRINT #2, a$; ' Печатать символ
END IF
END IF
WEND
PRINT #2, cs$; ' Очистить экран
PRINT #2, es$ + "[1;36m"; ' Светло-синий
PRINT #2, "Comm Port [";
PRINT #2, es$ + "[1;33m"; ' Желтый
PRINT #2, "1";
PRINT #2, es$ + "[1;36m"; ' Светло-синий
PRINT #2, "/";
PRINT #2, es$ + "[1;33m"; ' Желтый
PRINT #2, "2";
PRINT #2, es$ + "[1;36m"; ' Светло-синий
PRINT #2, "]? ";
PRINT #2, es$ + "[1;33m"; ' Желтый
WHILE comport$ <> "1" AND comport$ <> "2"
' Ждать нажатия <1> или <2>
comport$ = INKEY$
WEND
PRINT #2, comport$;
PRINT #2, cs$; ' Очистить экран
PRINT #2, es$ + "[1;36m"; ' Светло-синий
PRINT #2, "DIAL ";
PRINT #2, es$ + "[1;33m"; ' Желтый
PRINT #2, "P";
PRINT #2, es$ + "[1;36m"; ' Светло-синий
PRINT #2, "ulse or ";
PRINT #2, es$ + "[1;33m"; ' Желтый
PRINT #2, "T";
PRINT #2, es$ + "[1;36m"; ' Светло-синий
PRINT #2, "one [";
PRINT #2, es$ + "[1;33m"; ' Желтый
PRINT #2, "P";
PRINT #2, es$ + "[1;36m"; ' Светло-синий
PRINT #2, "/";
PRINT #2, es$ + "[1;33m"; ' Желтый
PRINT #2, "T";
PRINT #2, es$ + "[1;36m"; ' Светло-синий
PRINT #2, "]? ";
WHILE dialmode$ <> "P" AND dialmode$ <> "T"
' Ждать нажатия <P> или <T>
dialmode$ = INKEY$
dialmode$ = UCASE$(dialmode$) 'Объявить заглавные буквы
WEND
PRINT #2, es$ + "[1;33m"; ' Желтый
IF dialmode$ = "P" THEN ' Нажата клавиша <P>?
PRINT #2, "Pulse"; ' Тип линии - импульсная,
ELSE ' в противном случае -
PRINT #2, "Tone"; ' тоновая
END IF
END SUB
SUB makeacall ' Позвонить
PRINT #2, cs$; ' Очистить экран
PRINT #2, es$ + "[1;5;37;41m"; ' Мигание
PRINT #2, es$ + "[25;39H"; ' LOCATE 25, 39
PRINT #2, "Wait";
CALL delay
PRINT #1, "+++"; ' "Разбудить" модем
CALL delay ' Задержка
PRINT #1, "ATH0" ' Повесить трубку
PRINT #2, ao$; ' Отключить все атрибуты
IF NOT EOF(1) THEN
b$ = INPUT$(LOC(1), #1)
END IF
CALL getparms ' Получить параметры
CALL opencomport ' Открыть порт
PRINT #2, cs$; ' Очистить экран
PRINT #2, es$ + "[1;36m"; ' Светло-синий
PRINT #2, "Phone number? ";
PRINT #2, es$ + "[1;33m"; ' Желтый
dial$ = "" ' Обнуляем
WHILE a$ <> CHR$(13) ' Пока не нажата кл. <Enter>
a$ = INKEY$ ' Записываем код нажатой клавиши
IF a$ = CHR$(8) AND LEN(dial$) THEN ' <Backspace?>
PRINT #2, es$ + "[1D";
PRINT #2, " ";
PRINT #2, es$ + "[1D"; ' Переместить
' курсор влево
IF LEN(dial$) > 1 THEN
dial$ = LEFT$(dial$, LEN(dial$) - 1)
' один символ
ELSE ' или
dial$ = "" ' обнуляем
END IF
ELSE
a$ = UCASE$(a$) ' Объявить верхний регистр
IF a$ > " " THEN ' Убрать странные символы
dial$ = dial$ + a$ ' Добавить символ к dial$
PRINT #2, a$; ' Печатать символ
END IF
END IF
WEND
PRINT #1, "ATD" + dialmode$ + dial$ ' Звонить
PRINT #2, ao$; ' Отключить атрибуты
PRINT #2, cs$ + " " + hc$; ' Очистить экран
END SUB
SUB opencomport ' Открыть порт
CLOSE #1 ' Закрыть Сom-порт
OPEN comspec$ FOR RANDOM AS 1 'Открыть Сom-порт
IF firsttime$ = "" THEN
PRINT #1, init$ ' Послать строчку init$ в модем
firsttime$ = "on" ' Запомнить
END IF
END SUB
SUB outtahere ' Выход
PRINT #2, cs$; ' Очистить экран
PRINT #2, es$ + "[1;5;37;41m"; ' Мерцание
PRINT #2, es$ + "[25;39H"; ' LOCATE 25, 39
PRINT #2, "Wait";
CALL delay ' Задержка
PRINT #1, "+++"; ' "Разбудить" модем
CALL delay ' Задержка
PRINT #1, "ATH0" ' Повесить трубку
IF NOT EOF(1) THEN ' Очистить Com-буфер
b$ = INPUT$(LOC(1), #1) ' от неиспользованных
END IF ' байтов
CLOSE #1 ' Закрыть Com-порт
PRINT #2, ao$; ' Отключить атрибуты
PRINT #2, cs$ + " " + hc$; ' Очистить экран
CLOSE #2 ' Закрыть консоль
b$ = ""
END
END SUB
Листинг 2
' DIAL.BAS
' Поддерживаемые порты: COM1 - COM4
' Синтаксис: DIAL portnum% (portnum% - номер порта)
' Замечания: переместите курсор на телефонный номер;
' : нажмите клавишу ']', переместитесь в
' : конец номера и нажмите <Enter>;
' : используйте команды OPEN COMx
DECLARE SUB Hangup (Port%)
DECLARE SUB Getnum (row%, Col%, markit%, Port%)
DECLARE SUB Setup (Port%)
COLOR 0, 7
LOCATE 25, 1
PRINT " Переместите курсор в начало телефонного
номера и нажмите <Пробел> (Spacebar) ";
LOCATE 10, 1
IF VAL(COMMAND$) < 1 OR VAL(COMMAND$) > 4 THEN
' Получить номер порта
(portnum%)
PRINT "Номер порта должен быть указан в
командной строке "
END
ELSE Port% = VAL(COMMAND$)
END IF
' Устанавливаем некоторые специальные функции клавиатуры
CR$ = CHR$(13)
Nul$ = CHR$(0)
ArrowLt$ = Nul$ + CHR$(75)
ArrowRt$ = Nul$ + CHR$(77)
ArrowUp$ = Nul$ + CHR$(72)
ArrowDn$ = Nul$ + CHR$(80)
EndKey$ = Nul$ + CHR$(79)
Esc$ = CHR$(27)
Home$ = Nul$ + CHR$(71)
SpaceBar$ = CHR$(32)
'Сохраняем вектора в BIOS адреса для Com1-Com2
OldPort1H = PEEK(&H400)
OldPort1L = PEEK(&H401)
OldPort2H = PEEK(&H402)
OldPort2L = PEEK(&H403)
'Перемещаем курсор по экрану
DO ' Этот отрывок позволяет пользователю
In$ = INKEY$ ' перемещать курсор по экрану
SELECT CASE In$ ' и перейти в начало телефонного номера
CASE CR$
IF markit% THEN ' Нажатие <Enter> (CR$)
' означает конец выделения
row% = CSRLIN
Col% = POS(0) - count%
EXIT DO
END IF
CASE Esc$ ' Нажатие <Esc> (Esc$) - отмена операции
END
CASE Home$ ' Перейти в начало строки
LOCATE , 1
CASE EndKey$ ' Перейти в конец строки
LOCATE , 80
CASE ArrowUp$ ' Клавиша <Вверх>
x% = CSRLIN
IF x% > 1 THEN LOCATE x% - 1
CASE ArrowDn$ ' Клавиша <Вниз>
x% = CSRLIN
IF x% < 25 THEN LOCATE x% + 1
CASE ArrowLt$ ' Клавиша <Влево>
IF POS(0) > 1 THEN LOCATE , POS(0) - 1
IF markit% THEN count% = count% - 1
'Если markit%, тогда был нажата клавиша <Пробел>
CASE ArrowRt$ ' Клавиша <Вправо>
IF markit% THEN
'Если markit%, тогда была нажата клавиша <Пробел>
count% = count% + 1
row% = CSRLIN: Col% = POS(0)
a% = SCREEN(row%, Col%)
PRINT CHR$(a%);
ELSE
IF POS(0) < 80 THEN LOCATE , POS(0) + 1
END IF
CASE SpaceBar$
IF markit% THEN
'Если markit%, тогда была нажата клавиша <Пробел>
count% = count% + 1
row% = CSRLIN: Col% = POS(0)
a% = SCREEN(row%, Col%)
PRINT CHR$(a%);
ELSE
BEEP
markit% = -1 ' Установим флаг для пометки номера
END IF
END SELECT
LOCATE , , 1 ' Сохраним позицию курсора
LOOP
' Получим номер телефона с экрана
Getnum row%, Col%, count%, Port%
' Восстановим старые вектора
CLOSE 1
DEF SEG = 0
POKE &H400, OldPort1H
POKE &H401, OldPort1L
POKE &H402, OldPort2H
POKE &H403, OldPort2L
DEF SEG
END
SUB Getnum (row%, Col%, markit%, Port%)
IF row% < 1 THEN row% = 1: IF Col% < 1 THEN Col% = 1
LOCATE row%, Col%
FOR x% = 0 TO markit%
' Прочитаем номер телефона с экрана
a% = SCREEN(row%, Col% + x%)
Dialstr$ = Dialstr$ + CHR$(a%)
NEXT x%
LOCATE 23, 25
PRINT "Dialing : "; Dialstr$;
LOCATE 25, 1
PRINT "Поднимите трубку и нажмите
клавишу <Пробел> или нажмите <Esc> для отмены операции";
COLOR 7, 0
Setup Port%
PRINT #1, "ATDP" + Dialstr$ ' Набрать номер
DO
b$ = INKEY$
IF b$ = " " THEN
Hangup Port%
EXIT DO
END IF
IF b$ = CHR$(27) THEN
Hangup Port%
EXIT DO
END IF
LOOP
END SUB
SUB Hangup (Port%)
PRINT "...Disconnecting 1";
SELECT CASE Port% ' Снизим DTR
CASE 1
OUT &H3FC, (INP(&H3FC) AND 252) ' Com1
CASE 2
OUT &H2FC, (INP(&H2FC) AND 252) ' Com2
CASE 3
OUT &H3FC, (INP(&H3FC) AND 252) ' Com3
CASE 4
OUT &H2FC, (INP(&H2FC) AND 252) ' Com4
END SELECT
PRINT "...2...";
PRINT #1, "+++"; ' Переключить в командный режим
SLEEP 1
PRINT #1, "ATH" ' Пошлем команду,
' чтобы повесить трубку
PRINT "...CLICK";
END SUB
SUB Setup (Port%)
' Если нужно, установим порты с помощью обмена адресов
' между Com4 и Com2 или Com3 и Com1
DEF SEG = 0
POKE &H400, &HF8
POKE &H401, 3
POKE &H402, &HF8
POKE &H403, 2
SELECT CASE Port%
CASE 1
Start$ = "COM1:2400,N,8,1,DS0"
CASE 2
Start$ = "COM2:2400,N,8,1,DS0"
CASE 3
POKE &H400, &HE8 ' Для Com1 в Com3
POKE &H401, &H3
Start$ = "COM1:2400,N,8,1,DS0"
CASE 4
POKE &H402, &HE8 ' Для Com2 в Com4
POKE &H403, &H2
Start$ = "COM2:2400,N,8,1,DS0"
END SELECT
DEF SEG
OPEN Start$ FOR RANDOM AS 1
END SUB
Листинг 3
DEFINT C ' Считываем адреса портов Com2 и Com3 DEF SEG = 0 Com2 = PEEK(&H402) + 256 * PEEK(&H403) Com3 = PEEK(&H404) + 256 * PEEK(&H405) ' Меняем местами адреса портов Com2 и Com3 POKE &H402, Com3 AND 255 POKE &H403, Com3 256 POKE &H404, Com2 AND 255 POKE &H405, Com2 256 ' Следующая часть программы является простым ' примером работы предыдущих функций. ' Она протестирована на Hayes-совместимом ' модеме (ON COM3). Так как адреса портов ' поменялись местами, то вы можете открыть ' порт COM2 вместо COM3. CLS C = FREEFILE OPEN "Com2:2400,N,8,1,RS,DS" FOR RANDOM AS #C LEN = 40 ' Dial 999 9999 : введите нужный вам номер телефона PRINT #C, "ATDP 123 4567,,,,,,,,,,,,," PRINT "Нажмите любую клавишу, чтобы повесить трубку" k$ = INPUT$(1) ' Разъединить линию PRINT #C, "ATH+++" CLOSE #C ' Восстановить адреса портов Com2 и Com3 ' Это очень важно, так как если это не будет ' сделано, появятся проблемы с присоединенными ' к этим портам устройствами. Так, ' например, у вас исчезнет курсор мыши, и вы не ' сможете использовать ее до полной перезагрузки компьютера. POKE &H402, Com2 AND 255 POKE &H403, Com2 256 POKE &H404, Com3 AND 255 POKE &H405, Com3 256 END







