ПРОГРАМА - РЕЗИДЕНТ ПЕРЕМИКАЧІ АЛЬТЕРНАТИВНИЙ Кодування
ВСТУП
З самого початку існування 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аботчік
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аботчік
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ана
; Вхід:
; AL - номеp пеpвого символу
; CL - кількість символів
; CH - діаметра символу
; 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,10 h
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 '8 x16.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аняем стару
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