locals @@
.model tiny
HOTKEY = 8600h ; расширенный код F12
; вопрос/ответ для проверки, установлен ли обработчик
MY_QUESTION = 0AFE7h
MY_ANSWER = 64D9h
; изменение адресов после перемещения резидентной части
delta EQU (offset keyTable - 5Ch)
.code
.startup
jmp Install ; переходим на код инициализации
; ---- начало резидентной части ----
; таблица перекодировки клавиш
; заменяются и скан-коды, и соответствующие им символы
keyTable label word
; скан-код нажатой клавиши
; |
; | v----- на какой заменяется
db 'E',12h ; 16 -> 18
db 'R',13h ; 17 -> 19
db 'T',14h ; 18 -> 20
db 'Y',15h ; 19 -> 21
db 'U',16h ; 20 -> 22
db 'I',17h ; 21 -> 23
db 'O',18h ; 22 -> 24
db 'P',19h ; 23 -> 25
db 'A',1eh ; 24 -> 30
db 'S',1fh ; 25 -> 31
dw 0 ; 26
dw 0 ; 27
dw 0 ; 28
dw 0 ; 29
db 'D',20h ; 30 -> 32
db 'F',21h ; 31 -> 33
db 'G',22h ; 32 -> 34
db 'H',23h ; 33 -> 35
db 'J',24h ; 34 -> 36
db 'K',25h ; 35 -> 37
db 'L',26h ; 36 -> 38
db 'Z',2ch ; 37 -> 44
db 'X',2dh ; 38 -> 45
dw 0 ; 39
dw 0 ; 40
dw 0 ; 41
dw 0 ; 42
dw 0 ; 43
db 'C',2eh ; 44 -> 46
db 'V',2fh ; 45 -> 47
db 'B',30h ; 46 -> 48
db 'N',31h ; 47 -> 49
db 'M',32h ; 48 -> 50
db 'Q',10h ; 49 -> 16
db 'W',11h ; 50 -> 17
my_int16:
cmp ax,MY_QUESTION ; проверка наличия в памяти?
jne @@1
mov ax,MY_ANSWER ; ответ: обработчик уже установлен
iret
@@1:
; обрабатываем функции 0, 1, 10h, 11h прерывания 16h
cmp ah,1
jb @@f0
je @@f1
cmp ah,10h
jb @@old
je @@f0
cmp ah,11h
je @@f1
@@old: ; иная функция, передаем управление старому обработчику
db 0EAh ; код JMP FAR
int16_ptr dd 0 ; адрес перехода
@@f0: ; функции 0 и 10h
; сначала вызовем старый обработчик прерывания
pushf
call dword ptr CS:[int16_ptr-delta]
jmp short @@common
@@f1: ; функции 1 и 11h
; сначала вызовем старый обработчик прерывания
pushf
call dword ptr CS:[int16_ptr-delta]
jz @@ret2 ; не была нажата клавиша
@@common:
pushf ; сохраняем флаги - нужно для 1, 11h
cmp ax,HOTKEY ; была нажата клавиша вкл/выкл перекодировки?
jne @@no_hotkey ; нет
cmp byte ptr CS:[@@no_hotkey+1-delta],al ; дистанция перехода = 0?
jne @@on
; выключаем перекодировку
mov byte ptr CS:[@@no_hotkey+1-delta],offset @@ret - offset @@encode
jmp short @@ret
@@on:
; включаем перекодировку
mov byte ptr CS:[@@no_hotkey+1-delta],al ; 0 - переход на следующую команду
jmp short @@ret
@@no_hotkey: ; если перекодировка выкл (начальное состояние), то выходим
jmp short @@ret ; при включении - просто переходим к следующей команде
@@encode:
test al,al
jz @@ret ; AL = 0 - расширенный код
; проверяем попадание скан-кода в диапазон буквенных латинских клавиш
cmp ah,10h
jb @@ret ; не латинская буква
cmp ah,32h
ja @@ret ; не латинская буква
push bx ; сохраняем используемый регистр
mov bl,ah
xor bh,bh
shl bx,1 ; индексируем массив слов
add bx,offset keyTable - 10h*2 - delta ; смещение таблицы перекодировки со сдвигом
cmp byte ptr CS:[bx],0
je @@no_code ; не латинская буква
cmp al,'a' ; сравнение для определения "прописная - строчная"
mov ax,CS:[bx] ; скан- и ASCII-коды клавиши
jb @@no_code ; исходный код меньше 'a' - прописная буква
or al,20h ; преобразование в строчную
@@no_code:
pop bx ; восстанавливаем измененный регист
@@ret:
popf ; восстанавливаем флаги после оригинального прерывания
@@ret2:
retf 2 ; возвращаемся с отбрасыванием старых флагов
; ---- конец резидентной части ----
Install: ; код инициализации
mov ah,9 ; AH=9 - вывод сообщения
mov dx,offset msgInfo ; DS:DX - адрес строки
int 21h
mov ax,MY_QUESTION ; проверить наличие в памяти
int 16h
cmp ax,MY_ANSWER ; сравнить с ответом
jne @@set
; программа уже установлена
mov ah,9 ; AH=9 - вывод сообщения
mov dx,offset msgAlready ; DS:DX - адрес строки
int 21h
int 20h ; выход
@@set:
; перемещаем резидентный код для экономии памяти
mov si,offset keyTable
mov di,5Ch
mov cx,(offset Install - offset keyTable + 1)/2 ; кол-во слов
cld
rep movsw
mov ah,49h ; освобождаем блок окружения (environment)
mov ES,DS:[2Ch] ; сегмент блока окружения
int 21h
; перехватываем прерывание 16h
mov ax,3516h ; AH = 35h - получить вектор, AL - прерывание
int 21h
mov word ptr DS:[int16_ptr-delta],bx ; ES:BX - адрес
mov word ptr DS:[int16_ptr-delta+2],ES
mov ah,25h ; AH = 25h - установить вектор, AL - прерывание
mov dx,offset my_int16 -delta ; DS:DX - адрес обработчика
int 21h
mov dx,offset Install - delta ; адрес конца резидентной части
int 27h ; оставляем резидентный код в памяти и выходим
msgInfo db 'Keyboard encoder',13,10
db 'Press F12 to activate/deactivate encoding',13,10,'$'
msgAlready db 'The encoder has been installed already', 13,10,'$'
end
Если Вы уже зарегистрированы на Портале - войдите в систему, если Вы еще не регистрировались - пройдите простую процедуру регистрации.