Страница 9 из 26
3.1.8 Написание процедуры ввода с клавиатуры общего назначения. Система кодов, используемых клавиатурой, не поддается простой интрепретации. Коды могут иметь длину 1 или 2 байта и нет просто- го соответствия между длиной кода и тем, служит ли он для обозна- чения символа или для управления оборудованием. Не все комбинации клавиш даже выдают уникальный код, поэтому необходимы добавочные усилия, чтобы различить их. Ни коды ASCII, ни расширенные коды не упорядочены таким образом, который бы позволил их простую группи- ровку и проверку ошибок. Другими словами, процедура ввода с кла- виатуры общего назначения требует хлопотливого программирования. Здесь приведены примеры на Бейсике и с использованием прерыва- ния 16H. В них показано как свести вместе большинство информации, приведенной в данной главе. Общий алгоритм показан на рис. 3-3.
Высокий уровень. Процедура обработки ввода с клавиатуры, написанная на Бейсике, может делать все что делает ассемблерная процедура, за одним исключением. Функция INKEY$ не предоставляет доступа к скан-ко- дам. Это означает, что Вы не можете сказать получены ли коды ASCII 8, 9, 13 и 27 от нажатия клавиш <BackSpace>, <Tab>, <Enter> и <Escape> или через Ctrl-H, -I, -M и -[. Различие может быть установлено проверкой бита статуса клавиши Ctrl, по адресу 0040:0017, в момент нажатия клавиши. Но этот метод не будет рабо- тать, если введенный символ был запасен в буфере клавиатуры в течение некоторого времени.
100 C$=INKEY$:IF C$="" THEN 100 'получение символа 110 IF LEN(C$)=2 THEN 700 'если расширенный, то на 700 120 C=ASC(C$) 'иначе берем номер кода ASCII 130 IF C<32 THEN 300 'если управляющий, то на 300 140 IF C<65 OR C>123 THEN 100 'принимаем только символы 150 '''пишущей машинки и делаем с ними, что хотим, например: 160 S$=S$+C$ 'добавляем символ к строке 170 PRINT C$; 'выводим его на экран 180 '''... и т.д. 190 GOTO 100 'на ввод следующего символа . . 300 '''процедура обработки управляющих кодов ASCII 310 DEF SEG = 0 'указываем на начало памяти 320 REGISTER=PEEK(&H417) 'берем регистр статуса 330 X=REGISTER AND 4 'X=4, когда нажат Ctrl 340 IF X=0 THEN 500 'если не нажат, то на 500 350 '''если это комбинация Ctrl-буква, то делаем что хотим 360 IF C=8 THEN GOSUB 12000 'например, переходим на проце- 370 '''дуру вывода экрана помощи и т.д. 380 GOTO 100 'на ввод следующего символа . .
500 '''процедура обработки 4-х клавиш: декодирует коды ASCII 8, 510 '''9, 13 и 27, когда клавиша Ctrl не нажата 520 IF C=8 THEN GOSUB 5000 'обработка <BackSpace> 530 IF C=9 THEN GOSUB 6000 'обработка <Tab> 540 IF C=13 THEN GOSUB 7000 'обработка <CR> 550 IF C=27 THEN GOSUB 8000 'обработка <Esc> 560 GOTO 100 'на ввод следующего символа . . 700 '''процедура обработки расширенных кодов 710 C$=RIGHT$(C$,1) 'берем только 2-й байт C$ 720 C=ASC(C$) 'переводим в числовую форму 730 '''в C - расширенный код - делаем с ним, что хотим, например 740 IF C<71 OR C>81 THEN 100 'берем только управление курсором 750 IF C=72 THEN GOSUB 3500 'обработка "курсор-вверх" 760 '''... и т.д. 770 GOTO 100 'на ввод следующего символа
Средний уровень. Этот пример отличается от предыдущего методом распознавания четырех частных случаев Ctrl-H, -I, -M и -[. Здесь, когда встает вопрос о том, возник ли указанный код при нажатии одной клавиши, или в комбинации с клавишей Ctrl, проверяется скан-код. Этот метод более правилен, чем проверка бита статуса, так как скан-код запоминается в буфере клавиатуры, а установка бита статуса может быть изменена.
;---получение кода нажатой клавиши и определение его типа NEXT: MOV AH,0 ;функция ввода с клавиатуры BIOS INT 16H ;получаем введенный код CMP AL,0 ;проверка на расширенный код JE EXTENDED_CODE ;если да, то на спец. процедуру CMP AL,32 ;проверка на управляющий символ JL CONTROL_CODE ;если да, то на спец. процедуру CMP AL,65 ;если символ не входит в набор пишу- JL NEXT ;щей машинки, то берем следующий CMP AL,123 ; JL NEXT ; ;---теперь обрабатываем символ в AL STOSB ;запоминаем символ по адресу ES:DI MOV AH,2 ;функция вывода символа на экран MOV DL,AL ;помещаем символ в DL перед выводом INT 21H ;выводим его на экран . . JMP NEXT ;переходим к следующему символу
;---анализируем управляющие коды CONTROL_CODE: CMP AL,13 ;код ASCII 13? JNE TAB ;если нет, то след. проверка CMP AH,28 ;иначе проверяем скан-код <CR> JNE C_M ;если нет, то было Ctrl-M CALL CARRIAGE_RET;обработка возврата каретки JMP NEXT ;переход к следующему символу C_M: CALL CTRL_M ;обработка Ctrl-M JMP NEXT ;переход к следующему символу TAB: CMP AL,9 ;проверка на табуляцию... . . CMP AL,10 ;затем проверка других . . REJECT: JMP NEXT ;переход к следующему символу ;---анализ расширенных кодов (2-й байт кода в AH): EXTENDED_CODE: CMP AH,71 ;проверка нижней границы JL REJECT ;если меньше, то след. символ CMP AH,81 ;проверка верхней границы JL REJECT ;если больше, то след. символ ;---AH содержит символ управления курсором, анализируем его: CMP AH,72 ;"курсор-вверх"? JE C_U ;если да, то на процедуру CMP AH,80 ;"курсор-вниз"? JE C_D ;если да, то на процедуру . . C_U: CALL CURSOR_UP ;вызов соответствующей процедуры JMP NEXT ;переход к следующему символу C_D: CALL CURSOR_DOWN ;вызов соответствующей процедуры JMP NEXT ;переход к следующему символу
|