ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 04.07.2020
Просмотров: 3186
Скачиваний: 1
виш-переключателей, для которых делаются соответствующие измене-
ния в байтах их статуса. С другой стороны, все коды нажатия обра-
батываются. При этом опять могут изменяться байты статуса кла-
виш-переключателей. В случае же символьных кодов, надо проверять
байты статуса, чтобы определить, например, что скан-код 30 соот-
ветствует нижнему или верхнему регистру буквы A.
После того как введенный символ идентифицирован, процедура
ввода с клавиатуры должна найти соответствующий ему код ASCII или
расширенный код. Приведенный пример слишком короток, чтобы рас-
смотреть все случаи. В общем случае скан-коды сопоставляются
элементам таблицы данных, которая анализируется инструкцией XLAT.
XLAT принимает в AL число от 0 до 255, а возвращает в AL 1-байт-
ное значение из 256-байтной таблицы, на которую указывает DS:BX.
Таблица может находиться в сегменте данных. Если в AL находился
скан-код 30, то туда будет помещен из таблицы байт номер 30 (31-й
байт, так как отсчет начинается с нуля). Этот байт в таблице
должен быть установлен равным 97, давая код ASCII для "a". Конеч-
но для получения заглавной A нужна другая таблица, к которой
обращение будет происходить, если статус сдвига установлен. Или
заглавные буквы могут храниться в другой части той же таблицы, но
в этом случае к скан-коду надо будет добавлять смещение, опреде-
ляемое статусом клавиш-переключателей.
Наконец, номера кодов должны быть помещены в буфер клавиатуры.
Процедура должна сначала проверить, имеется ли в буфере место для
следующего символа. В [3.1.1] показано, что этот буфер устроен
как циклическая очередь. Ячейка памяти 0040:001A содержит указа-
тель на голову буфера, а 0040:001C - указатель на хвост. Эти
словные указатели дают смещение в области данных BIOS (которая
начинается в сегменте 40H) и находятся в диапазоне от 30 до 60.
Новые символы вставляются в ячейки буфера с более старшими адре-
сами, а когда достигнута верхняя граница, то следующий символ
переносится в нижний конец буфера. Когда буфер полон, то указа-
тель хвоста на 2 меньше указателя на голову - кроме случая, когда
указатель на голову равен 30 (начало области буфера), а в этом
случае буфер полон, когда указатель хвоста равен 60.
Для вставки символа в буфер, надо поместить его в позицию, на
которую указывает хвост буфера и затем увеличить указатель хвоста
на 2; если указатель хвоста был равен 60, то надо изменить его
значение на 30. Вот и все. Схема прерывания клавиатуры показана
на рис. 3-4.
Низкий уровень.
Эффективная процедура требует глубокого продумывания. В этом
примере даны только самые зачатки. Он принимает только буквы на
нижнем и верхнем регистрах, причем все они загружены в одну таб-
лицу, в которой буквы верхнего регистра находятся на 100 байт
выше, чем их младшие братья. Анализируется только левая клавиша
сдвига и текущее состояние клавиши CapsLock игнорируется.
;---в сегменте данных
TABLE DB 16 DUP(0) ;пропускаем 1-е 16 байт
DB 'qwertyuiop',0,0,0,0 ;верхний ряд клавиатуры
DB 'asdfghjkl',0,0,0,0,0 ;средний ряд клавиатуры
DB 'zxcvbnm' ;нижний ряд клавиатуры
DB 16 DUP(0) ;пропуск до верхнего регистра
DB 'QWERTYUIOP',0,0,0,0 ;те же символы на верхнем
DB 'ASDFGHJKL',0,0,0,0,0 ;регистре
DB 'ZXCVBNM' ;
;---в начале программы устанавливаем прерывание
CLI ;запрет прерываний
PUSH DS ;сохраняем регистр
MOV AX,SEG NEW_KEYBOARD ;DS:DX должны указывать на
MOV DS,AX ;процедуру обработки
MOV DX,OFFSET NEW_KEYBOARD ;прерывания
MOV AL,9 ;номер вектора прерывания
MOV AH,25H ;номер функции DOS
INT 21H ;меняем вектор прерывания
POP DS ;восстанавливаем регистр
STI ;разрешаем прерывания
Программа продолжается, затем оставаясь резидентной [1.3.4].
;---это само прерывание клавиатуры
NEW_KEYBOARD PROC FAR ;сохраняем все изменяемые
PUSH AX ;регистры
PUSH BX ;
PUSH CX ;
PUSH DI ;
PUSH ES ;
;---получаем скан-код и посылаем сигнал подтверждения
IN AL,60H ;получаем скан-код из порта A
MOV AH,AL ;помещаем копию в AH
PUSH AX ;сохраняем скан-код
IN AL,61H ;читаем состояние порта B
OR AL,10000000B ;устанавливаем бит 7
OUT 61H,AL ;посылаем измененный байт в порт
AND AL,01111111B ;сбрасываем бит 7
OUT 61H,AL ;возвращаем состояние порта B
;---ES должен указывать на область данных BIOS
MOV AX,40H ;устанавливаем сегмент
MOV ES,AX ;
POP AX ;возвращаем скан-код из стека
;---проверка клавиши сдвига
CMP AL,42 ;нажат левый сдвиг?
JNE KEY_UP ;нет - смотрим следующее
MOV BL,1 ;да - изменяем бит статуса
OR ES:[17H],BL ;меняем прямо регистр статуса
JMP QUIT ;выход из процедуры
KEY_UP: CMP AL,170 ;левый сдвиг отпущен?
JNE NEXTKEY ;нет - смотрим следующее
MOV BL,11111110B ;да - меняем бит статуса
AND ES:[17H],BL ;меняем прямо регистр статуса
JMP QUIT ;выход из процедуры
NEXTKEY: ;просмотр других переключателей
;---это символьная клавиша - интерпретируем скан-код
TEST AL,10000000B ;код освобождения клавиши?
JNZ QUIT ;да - выходим из процедуры
MOV BL,ES:[17H] ;иначе берем байт статуса
TEST BL,00000011B ;клавиша сдвига нажата?
JZ CONVERT_CODE ;нет - уходим дальше
ADD AL,100 ;да - значит заглавная буква
CONVERT_CODE: MOV BX,OFFSET TABLE ;готовим таблицу
XLAT TABLE ;преобразуем скан-код в ASCII
CMP AL,0 ;возвращен 0?
JE QUIT ;если да, то на выход
;---код клавиши готов, проверяем не полон ли буфер клавиатуры
MOV BX,1AH ;смещение указателя на голову
MOV CX,ES:[BX] ;получаем его значение
MOV DI,ES:[BX]+2 ;получаем указатель хвоста
CMP CX,60 ;голова на вершине буфера?
JE HIGH_END ;да - переходим к спец. случаю
INC CX ;увеличиваем указатель головы
INC CX ;на 2
CMP CX,DI ;сравниваем с указателем хвоста
JE QUIT ;если равны, то буфер полон
JMP GO_AHEAD ;иначе вставляем символ
HIGH_END: CMP DI,30 ;проверка спец. случая
JE QUIT ;если буфер полон, то выход
;---буфер не полон - вставляем в него символ
GO_AHEAD: MOV ES:[DI],AL ;помещаем символ в позицию хвоста
CMP DI,60 ;хвост в конце буфера?
JNE NO_WRAP ;если нет, то добавляем 2
MOV DI,28 ;иначе указатель хвоста = 28+2
NO_WRAP: ADD DI,2 ;получаем новое значение хвоста
MOV ES:[BX]+2,DI ;посылаем его в область данных
;---завершение прерывания
QUIT: POP ES ;восстанавливаем изменяемые
POP DI ;регистры
POP CX ;
POP BX ;
POP AX ;
MOV AL,20H ;выдаем сигнал об окончании
OUT 20H,AL ;аппаратного прерывания
IRET ;возврат из прерывания
NEW_KEYBOARD ENDP
Раздел 2. Доступ к отдельным клавишам.
Процедура обработки нажатия клавиши должна проверять массу
различных типов клавиш и условий, поскольку как одно-, так и
двухбайтные коды могут появляться в комбинации с клавишами-перек-
лючателями. Не все клавиши логически сгруппированы, по типу кода,
который им соответствует. Например, клавиша <Backspace> генери-
рует однобайтный код ASCII, а клавиша <Delete> - двухбайтный
расширенный код. Клавиша Ctlr генерирует однобайтный код, когда
она используется в сочетании с алфавитными клавишами и двухбайт-
ный код в остальных случаях. Эти нерегулярности вознмкают из-за
ограниченности набора ASCII: прерывание клавиатуры следует согла-
шениям ASCII, когда возможно, но когда это невозможно выдает свои
(расширенные) коды.
В данном разделе перечислены различные группы клавиш, даны их
коды и указаны встречающиеся аномалии. В большинстве случаев эта
информация доступна в менее удобном виде из таблиц кодов ASCII и
расширенных кодов, приведенных в разделе 3 этой главы. Здесь
обсуждаются также специальные свойства, приписываемые отдельным
клавишам Бейсиком, а также специальная обработка, для интерпрета-
ции отдельных клавиш (таких как забой), применяемая в прерываниях
DOS.
3.2.1 Использование клавиш <BackSpace>, <Enter>, <Escape> и <Tab>.
Клавиши <BackSpace>, <Enter>, <Escape> и <Tab> - единственные
четыре несимвольные клавиши, которые генерируют однобайтные ко-
ды ASCII. Эти коды содержатся в наборе управляющих кодов [7.1.9],
которые занимают первые 32 кода в наборе ASCII. Эти четыре кода
могут быть получены также комбинацией буквенных клавиш с клавишей
Ctrl:
ASCII 8 BackSpace Ctrl + H
ASCII 9 Tab Ctrl + I
ASCII 13 Enter Ctrl + M
ASCII 27 Escape Ctrl + [
В [3.2.2] показано как различать нажатие одной клавиши и комбина-
цию с клавишей Ctrl. Отметим, что обратная табуляция, производи-
мая нажатием комбинации <Shift> + <Tab>, выдает расширенный код
0;15.
Некоторые из прерываний обработки ввода с клавиатуры автомати-
чески интерпретируют эти четыре специальных кода. В Бейсике функ-
ция INPUT реагирует на <Backspace>, <Tab> и <Enter>. Функция
INKEY$ не интерпретирует ни один из управляющих кодов, поскольку
у нее нет автоматического эха на экран. Всю работу должна выпол-
нять Ваша программа. Напомним, что для управления движением кур-
сора Бейсик предоставляет функцию TAB. Из прерываний BIOS и DOS,
те которые выдают эхо на терминал интерпретируют также клавиши
<BackSpace> и <Tab>. После того как эти коды интерпретируются
соответствующим образом, коды ASCII все равно появляются в AL,
после чего они могут быть включены в строку символов или игнори-
рованы, в зависимости от того, что требуется.
3.2.2 Использование клавиш-переключателей: <Shift>, <Ctrl> и
<Alt>.
Три типа клавиш-переключателей заставляют только другие клави-
ши клавиатуры генерировать различные коды. Как правило, такие
комбинации генерируют расширенные коды. Но в двух случаях они
дают коды ASCII: (1) когда используется клавиша <Shift> с
клавишами
алфавитно-цифровых символов и (2) нажатие комбинации клавиш от
Ctrl-A до Ctrl-Z дает ASCII коды от 1 до 26. Все остальные комби-
нации дают расширенные коды, перечисленные в [3.3.5]. PCjr имеет
несколько исключений, которые обсуждаются ниже.
Недопустимые комбинации клавиш не производят кода, вообще. За
исключением случая специальных комбинаций с Ctrl-Alt, одновремен-
ное нажатие нескольких переключателей приводит к тому, что только
один из них становится эффективным, причем приоритет у Alt, затем
Ctrl, и затем Shift. В [3.1.7] показано как проверить нажата ли в
данный момент клавиша-переключатель. В [3.2.3] показано, как
использовать клавишу ScrollLock, в качестве переключателя с любой
другой клавишей клавиатуры. Другие комбинации с клавишами-перек-
лючателями можно сделать допустимыми только полностью переписав
прерывание клавиатуры, которое заменило бы прерывание BIOS
[3.1.9].
Имеется проблема, связанная с некоторыми комбинациями с клави-
шей Ctrl, такими как Ctrl + H, I, M и [, поскольку они генерируют
коды ASCII, идентичные тем, которые генерируют клавиши <BackSpa-
ce>, <Tab>, <Enter> и <Escape>. В [3.1.8] показано как программа
на ассемблере может может, проверив скан-коды, определить была ли
нажата управляющая клавиша или комбинация буквы с Ctrl (скан-код
находится в AH, когда мы получаем код нажатой клавиши через пре-
рывание 16H). К сожалению, программы на Бейсике лишены такой
возможности. В таком случае программа может попытаться различить
эти две возможности, анализируя состояние регистра статуса. Если
бит 2 байта статуса по адресу 0040:0017 установлен, то клавиша
Ctrl - нажата. Этот метод работает только в тот момент, когда
происходит нажатие клавиши, но не тогда, когда Вы берете символ
из буфера клавиатуры через некоторое время.
Клавиатура PCjr имеет только 63 клавиши, по сравнению с 83 для
IBM PC или XT и 84 для AT. Некоторые комбинации клавиш-переключа-
телей служат для имитации некоторых недостающих клавиш (комбина-
ции с использованием функциональных клавиш приведены в [3.2.5]):
Комбинация клавиш PCjr PC/XT/AT эквиваленты
Alt + Fn + 0-9 0-9 (скан-коды дополнительной циф-
ровой клавиатуры
Alt + / \
Alt + ' `
Alt + [ |
Alt + ] ~
Alt + . * (скан-код, как от клавиши PrtSc
Shift + Del . (скан-код, как от доп. кл-ры)
Клавиатура PCjr допускает также следующие уникальные комбина-
ции с участием клавиш-переключателей:
Fn + Shift + Esc переключает цифровые клавиши в
функциональные
Ctrl + Alt + CapsLock переключает звуковое подтверждение
нажатия клавиши
Ctrl + Alt + Ins запускает диагностику
Ctrl + Alt + CursorLeft сдвигает экран влево
Ctrl + Alt + CursorRight сдвигает экран вправо
3.2.3 Использование клавиш-переключателей: NumLock, CapsLock,
Ins и ScrollLock.
За исключением клавиши Ins, все остальные клавиши-переключате-
ли не производят кода, который помещался бы в буфер клавиатуры.
Вместо этого, они изменяют состояние двух байтов статуса, которые
расположены в области данных BIOS по адресам 0040:0017 и
0040:0018. Прерывание клавиатуры проверяет установку этих байтов
перед тем как присвоить код введенному символу. Ваши программы
имеют доступ к регистрам статуса и могут изменить установку любой
из клавиш-переключателей как объяснено в [3.1.7].
Другие биты регистра статуса показывают нажата ли данная кла-
виша-переключатель в текущий момент. Это свойство позволяет прог-
рамме использовать клавиши-переключатели в качестве клавиш сдви-
га. Возможны потенциальные применения этого, пока не создано
новых кодов клавиш. Например, <ScrollLock> может быть итспользо-
ван для того, чтобы добавить добавочный набор комбинаций сдвиг +
функциональная клавиатура. Программа, которая будет получать код
обычной функциональной клавиши, проверять нажата ли клавиша
<ScrollLock> и соответственно интерпретировать нажатие клавиши.
Отметим, что любая из клавиш <Shift> обращает текущую установку
клавиши <NumLock>.
Клавиша <Ins> помещает в буфер клавиатуры код 0;82, который
Ваша программа может прочитать в любой момент. Однако установка
для <Ins> в байтах регистра статуса меняется немедленно. Даже
если в буфере нет места для кода <Ins>, то в регистре статуса при
нажатии клавиши вносятся изменения. Как <Ins>, так и <Scroll-
Lock>, не влияют на другие клавиши клавиатуры (в отличие от <Num-
Lock> и <CapsLock>). Вы можете приписать им любую роль, какую
захотите. Техническое руководство IBM утверждает, что клавиша
<ScrollLock> должна использоваться для переключения между состоя-
ниями, когда нажатие клавиши перемещения курсора приводит к
сдвижке экрана, а не к передвижению курсора.
Конечно, Вы можете создать все требуемые Вашей программе кла-
виши-переключатели просто назначив клавиши для этой цели. Хотя