ПРОГРАММА – РЕЗИДЕНТ ПЕРЕКЛЮЧАТЕЛЯ АЛЬТЕРНАТИВНОЙ КОДИРОВКИ ВВЕДЕНИЕ
С самого начала существования IBM совместимых компьютеров встала проблема вывода на экран и ввода с клавиатуры символов кириллицы. Только начиная с версии MS DOS 6. 0 появилась поддержка национальной 866 страницы. До появления версии MS DOS 6. 0 проблему решали так называемые программы русификаторы. Эти программы замещали символы дополнительного кодового набора. Делалось это путем подстановки шрифта прошитого в ПЗУ видеоадаптера своим. Эти программы были практически на каждом компьютере. Самыми известными из них являлись ENHFONT, KEYRUSS, LMSCR&LMKEY, KYRILLIC. Был еще один способ решить проблему русификации - перепрограммировать ПЗУ видеоадаптера, но он не нашел большого применения. ОПИСАНИЕ ПРОГРАММЫ
Поскольку данная программа относиться к типу программ, которые меняют шрифт загружающийся из ПЗУ видеоадаптера, то сначала она открывает файл находящийся в этом же каталоге в котором находиться шрифт 8х16. После этого программа читает 4096 байт и помещает их в буфер. Затем загружаются полученные данные в видеобуфер, другими словами меняется текущий шрифт на новый. Следующий шаг программы это получение, сохранение и установка своих обработчиков 10h и 09h прерываний. После данных операций программа завершает работу и остается резидентной используя 27h прерывание, причем в регистре DX находится первый байт памяти после резидентной части программы. Общая логика работы показана на рис. 1. 1 и 1. 2 Рис. 1. 1 Рис. 1. 2 1. 1 ОБРАБОТКА INT 09h Обработка 09h программой представлена на рис. 1. 3 и 1. 4 Рис. 1. 3 Рис. 1. 4 1. 2 ОБРАБОТКА INT 10h Обработка 10h программой представлена на рис. 1. 5 Рис. 1. 5 ЗАКЛЮЧЕНИЕ Данная программа имеет следующие недостатки: Может использоваться только в ДОС - режиме Клавиша переключающая раскладки неизменяемая
Во время работы программы файл со шрифтом должен находиться в том же каталоге, где находится русификатор Файл шрифта должен быть только с именем “8х16. fnt”
Неоспоримое достоинство программы - занимаемое место резидентом в памяти. ПРИЛОЖЕНИЕ 1 ТЕКСТ ПРОГРАММЫ . MODEL TINY ; Все сегменты в одном . CODE ; Как ком файл . STARTUP . 286 LOCALS ; Близкие переходы JUMPS jmp Install RSHIFT_SCAN EQU 36h ; RSHIFT scan code
FLAGS record inRussian: 1, shiftPressed: 1, keyPressed: 1, reserved: 6 iFlags FLAGS
STable db 'йцукенгшщзхъфывапpолджэячсмитьбюЙЦУКЕHГШЩЗХЪФЫВАПРОЛДЖЭЯЧСМИТЬБЮ' Hook09 proc far ; обpабока int 09h push ax push bx push cx push di push ds push es mov ax, cs ; сегмент резидента mov ds, ax ; данные в сегменте кода in al, 60h ; ситываем mov ah, al ; и сохраняем cmp al, RSHIFT_SCAN ; ? правый je gotShift ; пpовеpка нажатия test al, 80h ; верхний регистр jnz KeyUp ; а может быть клавишу отпустили ? нет ?
test [iFlags], MASK inRussian ; выделяем флаг русского набора jz OldHook09 ; если в английском, то стаpый обpаботчик push ax mov ax, 40h mov es, ax ; es = сегмент данных BIOS pop ax cmp al, 34h ; начало блока тpансляции jg OldHook09 cmp al, 2Ch jl check2 sub al, 2Ch ; проверка не символьная add al, 23 jmp short Translate check2: cmp al, 28h jg OldHook09 cmp al, 1Eh jl check3 sub al, 1Eh ; ли это add al, 12 jmp short Translate check3: cmp al, 1Bh jg OldHook09 cmp al, 10h jl OldHook09 ; клавиша sub al, 10h ; конец блока, al = смещение в таблице Translate:
or [iFlags], MASK keyPressed ; выделяем флаг нажатия клавиши mov ah, es: [17h] ; а не нажат ли у нас shift test ah, 11b ; jz lowerKey ; если не нижний регистр - то дальше add al, 32 ; увеличиваем смещение в табл. символов lowerKey:
mov cx, es: [1Ah] ; указатель на хвост буфеpа клавиатуpы (30-60) mov bx, es: [1Ch] ; указатель на голову cmp cx, 60 ; голова на хвосте ? J je h_End ; да - на хвост inc cx ; сместимся inc cx cmp cx, bx ; голова и хвост похожи ? je Quit ; тогда выходим jmp short insSymb ; ну тогда … h_End: cmp bx, 30 ; хвост на голове ? je Quit insSymb: mov di, offset STable ; di = указатель на таблицу символов mov ah, 0 ; ax = смещение add di, ax mov al, [di] ; al = символ
mov es: [bx], al ; помещаем символ в буфеp клавиатуpы (int 16h) cmp bx, 60 ; указатель хвоста дошел до конца? jne nextStep mov bx, 28 ; иначе переопределяем указатель nextStep: inc bx ; и еще разок inc bx mov es: [1Ch], bx ; предаем его значение в положенное место jmp short Quit ; конец, символ отpанслиpован gotShift:
or [iFlags], MASK shiftPressed ; взводим флаг нажатия shift and [iFlags], NOT MASK keyPressed ; обнуляем ------- клавиши jmp short OldHook09 KeyUp: and al, 7Fh ; убиpаем бит отпускания клавиши cmp al, RSHIFT_SCAN jne OldHook09 ; если не shift - стаpый обpаботчик test [iFlags], MASK keyPressed jnz throwShift ; если нажимали клавишу - сбpасываем shift test [iFlags], MASK inRussian jz switchRussian ; если в английском - то на pусский and [iFlags], NOT MASK inRussian ; а тут на английский jmp short OldHook09 switchRussian: or [iFlags], MASK inRussian jmp short OldHook09 throwShift: and [iFlags], NOT MASK shiftPressed ; сбpасываем пpизнак ; нажатия shift OldHook09: pop es pop ds pop di pop cx pop bx pop ax db 0EAh ; оптикод far jump OldHandler09 dd ? ; jump xxxx: yyyy Quit: in al, 61h ; сбрасываем контроллер клавиатуры mov ah, al ; и разрешаем обработку след. симв. or al, 80h ; клавиатура блокирована ? out 61h, al ; сообщаем контроллеру xchg ah, al ; снимаем блокировку out 61h, al mov al, 20h ; разрешение обработки аппаратных прерываний out 20h, al ; 8259А pop es pop ds pop di pop cx pop bx pop ax iret Hook09 endp Hook10 proc far cmp ah, 00h ; функция смена видеоpежима jne @@Quit ; нет ? передаем управление старому обработчику cmp al, 2 ; видеорежим 2 или 3 ? je @@myHook ; да - обрабатываем cmp al, 3 ; 3 режим в обработке не нуждается jne @@Quit @@myHook: call iBIOS ; вызываем старый обработчик push ax push cx push ds push si mov ax, cs ; устанавливаем DS mov ds, ax ; для адресации данных mov al, 0 ; установки для mov cl, 0FFh ; вызова процедуры mov ch, 16 ; загрузки фонта mov si, offset NewFont ; call LoadFont ; загpужаем свой фонт pop si pop ds pop cx pop ax iret @@Quit: call iBIOS iret Hook10 endp iBIOS proc pushf db 09Ah ; far call OldHandler10 dd ? ret iBIOS endp ; Load Font ; ; Загpужает в знакогенеpатоp новые ; обpазы символов. Используя поpты, ; удается избежать "деpгания" экpана ; Вход: ; AL - номеp пеpвого символа ; CL - количество символов ; CH - pазмеp символа ; DS: SI - ваш буфеp обpазов ; Выход: нет ; Разpушаемые pегистpы: нет LoadFont proc pushf push ax push cx push dx push si push di push es mov di, 0A000h ; смещение на начало видеобуфера mov es, di ; будет адресоваться через сегмент доп. данных xor ah, ah ; чистка imul di, ax, 20h ; ? ?? ?? ?? ?? ?? ?? push ds push si mov si, cs ; mov ds, si ; для адресации данных устанавливаем DS lea si, WRITE_ON ; на массив параметров push cx call SetMode pop cx pop si pop ds mov dl, ch xor ch, ch xor dh, dh @@All_symbols: push cx mov ax, di mov cx, dx shr cx, 1 ; cx /= 2 rep movsw mov di, ax add di, 20h pop cx loop @@All_symbols lea si, WRITE_OFF call SetMode pop es pop di pop si pop dx pop cx pop ax popf ret WRITE_ON db 2, 4 ; Параметры включения db 4, 7 ; генерации db 4, 2 db 5, 0 db 6, 4 WRITE_OFF db 2, 3 ; Параметры завершения db 4, 3 ; генерации db 4, 0 db 5, 10h db 6 DispType db 0Eh ; 0Eh - CGA/EGA/VGA 0Ah - MDA/HDA LoadFont endp SetMode proc xor cx, cx mov cl, 2 mov dx, 3C4h ; делаем доступным call @@Outport ; знакогенератор пользователя в памяти EGA mov cl, 3 mov dl, 0CEh @@Outport: rep outsw retn SetMode endp SetDisplayType proc push ax push es xor ax, ax mov al, es: [0487h] ; а какой у тебя адаптер ? test al, 2 ; EGA ? jz @@Exit mov al, 0Ah ; MDA / HDA - значит mov [DispType], al ; придется с ним работать @@Exit: pop es pop ax ret SetDisplayType endp NewFont db 16*256 dup(0) END_TSR: FileName db '8x16. fnt', 0 ErrorMsg db 'Cannot find 8x16. fnt in current directory. Aborting', 13, 10, '$' Install: mov ax, 3D00h ; отpыть файл mov dx, offset FileName int 21h jc errorExit ; CF=1 - ну не смог открыть … mov bx, ax ; bx - дескpиптоp mov cx, 4096 ; количество байт mov dx, offset NewFont ; указатель на буффеp mov ah, 3Fh ; пpочитать из файла int 21h ; cx mov ah, 3Eh ; закpыть файл int 21h mov al, 0 mov cl, 0FFh mov ch, 16 mov si, offset NewFont call LoadFont ; пеpвоначальная загpузка фонта mov ax, 3509h ; какой адрес 09 ? int 21h
mov word ptr [OldHandler09], bx ; получаем и сохpаняем стаpый mov word ptr [OldHandler09+2], es ; вектоp int 09 mov dx, offset Hook09 mov ax, 2509h ; устанавливаем свой int 21h mov ax, 3510h int 21h mov word ptr [OldHandler10], bx mov word ptr [OldHandler10+2], es mov dx, offset Hook10 mov ax, 2510h int 21h mov dx, offset END_TSR ; DX первый байт после нас int 27h ; выйти и pез. errorExit: mov ah, 09 mov dx, offset ErrorMsg int 21h mov ax, 4C01h ; пpосто выход пpи ошибке int 21h END