Файл: jourdain_spravochnik_programmista.docx

ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 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> должна использоваться для переключения между состоя-

ниями, когда нажатие клавиши перемещения курсора приводит к

сдвижке экрана, а не к передвижению курсора.

Конечно, Вы можете создать все требуемые Вашей программе кла-

виши-переключатели просто назначив клавиши для этой цели. Хотя