Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ASM_lectures.doc
Скачиваний:
37
Добавлен:
28.04.2019
Размер:
992.77 Кб
Скачать

Резидентный обработчик прерывания от клавиатуры с подключением после системного обработчика

Рассмотрим подключение обработчика после системного.

Во многих случаях прикладная обработка выполняется в качестве дополнения к системной. Системная программа BIOS отработки прерывания от клавиатуры преобразует скен-коды в коды ASCII, кроме этого выполняет массу дополнительных операций:

- сходит за указателями КБВ и модифицирует их;

- отслеживает нажатие (Ctrl)/(Break) и выполняет при его вводе специфические действия;

- позволяет вводить в КБВ коды непосредственно в цифровом виде с помощью нажатия (Alt) и цифр на цифровой клавиатуре и т.д.

Т.к. такое большое число функций не целесообразно переносить в прикладной обработчик, то во многих случаях удобнее только изменять коды в КБВ. Например, русификатор, работающий после системного обработчика, и только изменять коды ASCII в КБВ, если включен режим кириллицы.

Рассмотрим простой пример. Предположим, что пользователь, работающий с простым редактором часто пользуется символами псевдографики. В этом случае целесообразно закрепить коды ASCII этих символов за какими-то клавишами или сочетаниями клавиш, заменив коды ASCII этих клавиш.

Например: (Alt)/(U) -  - уголок (левый верхний уголок) и т.д.

CODE_SEG SEGMENT

ASSUME CS:CODE_SEG,DS:code_seg

ORG 100H

START:

JMP BEGIN

int_2Fh_vector DD ?

old_09h DD ?

;=============================================================================

;

;=============================================================================

new_09h proc far

pushf ; В системный обработчик

call CS:old_09h ; с возвратом

push AX

push BX

push ES

mov AX,40h ; Настроим ES на сегментный

mov ES,AX ; адрес области данных BIOS

mov BX,ES:[lCh] ; Адрес нового хвоста

dec BX ; Сместимся назад к последнему

dec BX ; введенному символу

cmp BX,lEh ; Хвост не вышел за пределы буфера?

jae go ; Нет, значит он был где-то внутри буфера

mov BX,3Ch ; Хвост после вычитания 2 вышел за пределы буфера,

; сл-но он был в самом начале, а последний введенный

; символ находится в самом конце буфера

go:

mov AX,ES:[BX] ; Получим последний символ из буфера

cmp AX,1600h ; Был введен расширенный код ASCII сочетания Alt/U?

jne go__out ; Нет

mov word PTR ES:[BX],OODAh ; Да, заменим код в буфере на код уголка

go_out:

pop ES

pop BX

pop AX

iret

new_09h endp

;=============================================================================

;

;=============================================================================

int_2Fh proc far

cmp AX,OC700h

jne pass_2Fh

mov AL,OFFh

iret

pass_2Fh:

jmp dword PTR CS:[int_2Fh_vector]

int_2Fh endp

;=============================================================================

;

;=============================================================================

begin:

mov AX,OC700h ; AH=OC7h номер процесса C7h

; AL=OOh -дать статус установки процесса

int 2Fh ; мультиплексное прерывание

cmp AL, 0

jz not_installed ; возвращает AL=0 если не установлена

lea DX,msg

call print

int 20h

msg DB 'Уже установлена',13,10,'$'

not_instailed:

mov AX,352Fh ; получить вектор

int 21h ; прерывания 2Fh

mov word ptr int_2Fh_vector,BX ; ES:BX - вектор

mov word ptr int_2Fh_vector+2,ES

mov DX,offset int_2Fh ; получить смещение точки входа в новый

; обработчик на DX

mov AX,252Fh ; функция установки прерывания

; изменить вектор 2Fh

int 21h ; AL - номер прерыв. DS:DX - указатель программы обработки прер.

mov AX,3509h ; получить вектор

int 21h ; прерывания 09h

mov word ptr old_09h,BX ; ES:BX - вектор

mov word ptr old_09h+2,ES ;

mov DX,offset new_09h ; получить смещение точки входа в новый

; обработчик на DX

mov AX,2509h ; функция установки прерывания

; изменить вектор 09h

int 21h ; AL - номер прерыв. DS:DX - указатель программы обработки прер.

;------------------------------------------------------------------------------

mov DX,offset begin ; оставить программу ...

int 27h ; ... резидентной и выйти

;=============================================================================

;

;=============================================================================

PRINT PROC NEAR

MOV АН,09H

INT 21H

RET

PRINT ENDP

;=============================================================================

CODE_SEG ENDS

END START

После системного управления передается в наш обработчик, а сегментный регистр EC настраивается на начало области данных BIOS (физический адрес 400h, сегментный адрес 40h).

Пусть перед вводом данного символа буфер был пуст.

40h:1Еh

Голова 1Аh

Мусор

Мусор

Хвост 1Сh

40h:ЗСh

Фактически в слове, на которое указывают оба указателя, находится код символа, введенного ранее и уже изъятого программой из буфера

Это адрес указателя

а не его

содержимое

Очередное нажатие клавиши вызывает нашу программу, а из нее - системный обработчик, который заносит двухбайтовый код нажатой клавиши в хвостовой элемент, перемещая хвостовой указатель на следующее слово буфера:

40h:1Eh

Голова 1Аh

Скан

ASCII

Хвост 16h

40h:ЗСh

На первый взгляд, получить код нажатой клавиши можно либо по адресу в головном указателе, либо вычтя 2 из адреса хвостового указателя.

Однако ни то, ни другое неверно.


Головной указатель действительно указывает на последний сохраненный в буфере код, лишь, если при запуске программы буфер был пуст. Если же в процессе загрузки программы пользователь нажимал какие-либо клавиши, их коды были помещены в буфер клавиатуры, и к моменту активизации нашей программы головной указатель будет указывать не на пустую ячейку буфера, а на самый старый из введенных символов.

При этом по мере занесения в буфер новых символов, обработке будет подвергаться все тот же самый старый символ. Следовательно, более надежно определять местонахождение последнего символа в буфере по адресу в хвостовом указателе. Однако не всегда этот адрес будет на 2 больше адреса последнего символа, так как буфер - кольцо. В том случае, когда очередная свободная ячейка буфера находилась в самом его конце, по адресу 40h:3Ch, после занесения туда очередного кода хвостовой указатель переместится в начало буфера, указывая на адрес 1Еh. В программе после вычитания 2 из адреса хвостового элемента, проверяется находится ли полученное значение в пределах буфера. Если оно равно или больше 1Еh, команда jae - выполняет переход на продолжение программы. Если полученное значение меньше 1Еh, то это значит, что хвостовой указатель указывает на самое начало буфера, а занесенный только что в буфер код находится в самом его конце:

40h:1Eh

Хвост 16h

В этом случае в BХ

заносится адрес последнего

символа в явном виде

Голова

Скан

ASCII

40h:ЗСh

Затем код нажатой клавиши извлекается из буфера и сравнивается с двухбайтовыми кодами (Alt)/(U) и др. - которые являются расширенными кодами ASCII. Если нажато одно из сочетаний, расш. Код ASCII в буфере заменяется на код ASCII символа псевдографики, без смещения указателя и осуществляется переход на go_out для завершения программы.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]