|
QB45
高级用户
积分 677
发帖 194
注册 2003-9-13
状态 离线
|
『楼 主』:
文本方式下,翻译字典制作原理与源程序(转帖)
一、西文文本方式下汉字显示
VGA/EGA通常带有256K VRAM,共分四个平面,每平面64K。文本方式下,偶内存地址的数据被放置于平面0中,它用于存放ASCII或汉字,奇内存地址的数据放置于平面1中(存放显示字符的属性,前四位表示背景色,后四位表示前景色)。而VGA/EGA显示的字符集(字模数据库),均放置于平面2中。我们不仅可使用其固化的ROM字库,还可以使用用户自己定义的字库。
对于VGA,平面2被分成8个8K的区域(用0-7表示其区号),可同时加装8种不同的字库;EGA则分为4个区(0-3表示其区号),可同时加装4种字库。实际上VGA/EGA文本模式下,字符的点阵信息均放置于平面2中。若我们将汉字的字模作为VGA/EGA一个字库,然后将其加装到平面2中,那么我们便可在西方文本方式下显示汉字。如,要显示汉字“我”,可先将“我”字的点阵信息取代字符C1、C2的点阵信息(汉字一般为16*16点阵,而西文字符为8*16点阵,所以一个汉字需要占两个字符位置),然后将“我”的内码更改为c1、c2,再将其输入屏幕即可。
此技术说起来非常简单,但在实际编程中有许多矛盾需要解决,标准ASCII,32-127之间的字符是可显示字符,若我们将汉字字模放置它们对应的字模处,则屏幕上发生混乱;而西文字符192-223是制表符,程序中经常用到,因此我们只能用128-191,224-255这些字符作为汉字字符的代替字,这样在屏幕上同时只能显示48个汉字。另一方面,我们在编程中还发现,若将以上的字符字模作为汉字字模区域,则汉字中总有一条空行,非常不美观,经验告诉我们,将192-223的字符作为汉字左边部分的代替字(右边随便,只要不与左同),汉字将正常显示,但此时英文制表符也会变成汉字。
解决这问题,似乎只有一个办法:将当前模式设置为图形方式,然后再取出各自的点阵信息显示在屏幕上,即可圆满解决。若这样作的话,此处“在西文文本方式下显示汉字”,也就不可谈了。
在VGA显卡中,平面2中同时加装8种不同的字库,但同一时刻,最多可使用2种字库,一个被称为字符集A,另一个被称为字符集B,因此屏幕上可同时显示512个不同的字符,这主要是由通过设置字符影射选择寄存器进行。我们可通过如下BIOS调用进行设置。
入口参数: BL=装入字符映射寄存器值
b4,b1,b0 =字库A在位平面2 中的区号
b5,b3,b2 =字库B在位平面2 中的区号*/
EGA b4,b5没用
AX=1103h
如:BL的b4,b1,b0=1,1,1 则表示字库A将选择7号区的字库。
此时,属性字节的B3位用于选择使用到的字符集(A或B,为1是使用字符集A)。若只激活一种字符集(A、B的值相同),属性字节的b3位可用作选择字符的高亮度。
现在,若我们将西文字符字库放置于平面2的n区号,中文字符字库放置于平面2的m区号(mn),便可以圆满在西文文本方式下显示中西混合字串,而且互不干涉。
这一技术处理过程如下:
1、将VGA/EGA标准西文字符集读入平面2的n区;
2、将用户含有中文字模信息的字符集读入平面2的m区(nm);
3、设置选择的AB字符集(如A选择区号为n的,B选择区号为m的)。
4、若为汉字,修改其内码,使之与其对应的字模保存处相同,如:字库偏移地址n*16(每个8*16点阵的字符字模占用16个字节),m*16处分别保存的是汉字X的左右点阵信息,则显示汉字X时,就将内码改为n,m,同时将其对应的属性b3位设置为1或0(视3步中AB选用的字库)。
二、屏幕翻译英汉字典的制作方法
UCDOS 6.0中为我们提供了一个EC.imd英中输入法文件,我们完全可以用此为英汉数据库。此文件是一个输入法驱动程序(IMD)。格式分析,笔者在《在西文方式下挂接UCDOS 5.0中的万能汉字输入》一文全面介绍过,限于篇幅,不再此复述,若读者对此感兴趣,可与笔者联系。
有了英汉字典,现在便是怎样读取屏幕上的英文单词。这是一个非常简单的问题,因为在文本模式3 中,显存地址从b800:0000处开始,字符的值存入偶地址,属性则存放在奇地址中,故坐标(x,y)处的字符便为peek(0xb800,y*160+2*x)。坐标(x,y)处屏幕上对应的英文单词,用户可参阅GetScreenWord()函数。
为了使我们的《屏幕英汉翻译字典》更具有通常性,我们有必要让用户在屏幕选择单词与自己输入单词中进行切换,另外若用户当前模式已经在中文环境下,我们没有必要用以上讲的西文文本方式下显示中文技术进行显示字串,因此我们最好要知道当前处于什么的文本模式下。
这一问题,较好的解决方法是读取0x3c5寄存器的值,若为奇数,表示当前处于中文文本方式下;为偶则表示处于西文文本方式下。因为中文文本模式下通常扫描行为8点,而西文方式下为9点。
三、程序实现
本程序利用UCDOS 6.0中的EC.IMD文件制作了一个屏幕英汉翻译字典(文件名为EC.c),用户在DOS下键入EC,便可对屏幕英语单词进行动态翻译(光标移动即选择单词)。另外,用户可通过TAB键切换到输入单词方式(再按一次,切换到屏幕翻译方式)进行动态翻译,按ESC键,则返回DOS。
若将此程序设计成TSR,便可动态在线翻译屏幕,这样便与朗道EC没有什么两样。读者不访动手试试。
|
我(QB45)的照片与简历
http://www.programfan.com/club/showbbs.asp?id=197280
|
|
2003-10-9 00:00 |
|
|
QB45
高级用户
积分 677
发帖 194
注册 2003-9-13
状态 离线
|
『第
2 楼』:
此程序在Turbo C 2.0中,配的VGA显示卡的X86微机上编译通过,在中、西文本两种方式下运行良好。
#include
#include
#include
#include
#include
#include
#include
#define EnglistWordNum 20 /*英语单词最大字符数*/
#define WORD unsigned int
#define BYTE unsigned char
#define ENGLISH 1 /*英文文本模式*/
#define CHINESE 2 /*中文文本模式*/
#define SHOW_DICT_UP 1 /*"屏幕字典"显示屏幕上方的位置*/
#define DICT_LINE 7 /*"屏幕字典"占用的行数*/
#define SHOW_DICT_DOWN (25-DICT_LINE) /*下方显示的行位置*/
#define SHOW_DICT_ENGLISHWORD_X 30 /*英语单词显示的列坐标*/
#define COLOR WHITE /*"屏幕字典"前景色*/
#define BKCOLOR BLUE /*"屏幕字典背景色*/
#define QU 192 /*左边汉字开始位置*/
#define WEI 128 /*右边汉字开始位置*/
#define HZK16 "C:\\ucdos\\hzk16" /*汉字库文件*/
#define EC "c:\\ucdos\\drv\\EC.imd" /*英中输入法字典文件*/
#define BEEP() printf("\7" /*响铃*/
enum
{ ESC = 0x011b,
END = 0x4f00,
TAB = 0x0f09,
HOME = 0x4700,
PageUp = 0x4900,
PageDown = 0x5100,
Ctrl_Home = 0x7700,
Ctrl_End = 0x7500,
BreakSpace =0xe08,
LEFT = 0x4b00,
RIGHT = 0x4d00,
ENTER = 0x1c0d,
UP = 0x4800,
DOWN = 0x5000,
} ;
enum InputMethodErrorCode /*错误代码*/
{ OK, /*无错误*/
HzkFileNotOpen, /*汉字库不能打开 */
FileNotOpen, /*编码文件不能打开 */
MallocError, /*内存分配错误 */
NotImdFile, /*不是IMD文件*/
};
typedef struct IMD
{ BYTE ImdId[0x10]; /*IMD文件标志*/
BYTE space1[0x10]; /*保留*/
BYTE CodingName[9]; /*编码名称*/
BYTE HotKey; /*功能键号*/
BYTE CodeTable[0x41]; /*码元表*/
BYTE CodeTableSize; /*实际编码大小*/
BYTE OmniptentKey; /*万能码长*/
BYTE MaxCodeLenght; /*最大码长*/
BYTE AutoChoiceInput; /*是否自动输入*/
BYTE RunSearch; /*是否执行模糊搜索*/
BYTE UseDefineWord; /*是否使用自定义词组*/
BYTE DefineWordsMode; /*自定义词组方案*/
BYTE space2; /*保留*/
BYTE PreWordCodeLength; /*单字查询编码最大长度*/
BYTE RecodeId; /*重码标志*/
WORD SearchWordNumber; /*单字查询编码个数*/
WORD InderCodeSize; /*单字查询编码长度*/
WORD CwordNumber; /*汉字个数*/
WORD InderTableOffset; /*查询索引表首地址*/
WORD InderTableNumber; /*索引表数目*/
BYTE space3; /*保留*/
} ;
char UserFont[256][16]; /*用户自定义扩展ASCII字模数据*/
int DictStatus=DOWN; /*当前字典显示的位置情况*/
char ShowMode; /*当前处于文本模式*/
int first=1; /*是否显示"屏幕字典"边框*/
FILE *LibFp; /*汉字库文件*/
FILE *ImdFp; /*编码文件指针*/
struct IMD *ImdHeadMsg; /*IMD文件头部信息*/
BYTE *InderTable; /*IMD查询索引表指针*/
int line=SHOW_DICT_DOWN; /*当前字字典显示的行坐标*/
int LoadIMD(BYTE *file);/*装入汉字输入法IMD文件*/
void RestoreScreen(); /*恢复屏幕内容*/
void SaveScreen(); /*保存屏幕内容*/
void PutChar(char c,int x,int y,int color,int bkcolor);
/*在西方文本方式下显示一字符C*/
void LoadDefaultFontToBuf(); /*装入VGA默认的字库到内存*/
void SetWordFont(unsigned char a,unsigned char b);
/*设置当前选用的工作字库*/
void LoadUserFontToVGA(); /*装入用户字库到VGA*/
void LoadDefaultFont(int n); /*装入默认的字库到VGA平面2*/
void LoadCwordModeToUserFont(char *buf,int n);
void RemoveIMD(); /*卸由LoadIMD函数装入的输入方法*/
void ShowMsg();
void GetWord(BYTE *,BYTE *,BYTE *);
int GetEnglishCword(BYTE *buf,BYTE *CodeBuf);
void ShowDictMsg();
char EnglishWord[30]="Screen EC Dictionary"; /*英语单词*/
char CwordMsg[80]="《屏幕英汉字典》 设计:湖北省 水师"; /*汉语信息*/
void GetCwordMode(unsigned char *s, unsigned char *mode)
/* 取汉字字模信息*/
{ long offset;
offset=((*s-0xa1)*94L+(*(s+1)-0xa1))*32L;
fseek(LibFp,offset,SEEK_SET);
fread(mode,1,32,LibFp);
}
void LoadCwordModeToUserFont(char *buf,int n)
/* 将一汉字字模写入用户定义的字库中 */
{ int i;
for(i=0;i0xa0)
{ GetCwordMode(s,buf);
LoadCwordModeToUserFont(buf,i);
i++; s+=2;
}
else s++;
}
LoadUserFontToVGA(FP_SEG(UserFont[0]),FP_OFF(UserFont[0]),1);
SetWordFont(0,1);
for(i=0,s=olds;*s
if (*s>0x80)
{PutChar(QU+i,x++,y,color,bkcolor);
PutChar(WEI+i,x++,y,color,bkcolor);
i++;s+=2;
}
else {gotoxy(1+x++,y+1);putch(*s++);}
}
void PutChar(char c,int x,int y,int color,int bkcolor)
{ /*显示的字符*/
pokeb(0xb800,2*x+y*160,c); /*写字符*/
color=((bkcolor&0xf)<<4)|(color&0x7);
/*前四位为背景色,后三位为前景色,B3=1时,用字符集A,否则用字符集B*/
color|=0x8;
pokeb(0xb800,2*x+y*160+1,color);
}
void LoadDefaultFont()
{ int i,j;
_AX=0x1104; /*装入VGA标准字库*/
_BL=0;
geninterrupt(0x10);
}
void LoadDefaultFontToBuf()
{ int bp;
bp=_BP; /*保存原BP值*/
_AX=0x1130; /*AX=1130H 返回字库信息*/
_BH=6; /*BH=6 请求返回ROM 8*16VGA标准字库的地址*/
geninterrupt(0x10);
/*返回 ES:BP=字符集的段地址:偏移地址 */
/*将VGA标准8*16点阵字库信息COPY到内存中*/
movedata(_ES, _BP,FP_SEG(&UserFont[0][0]),FP_OFF(&UserFont[0][0]),256*16);
_BP=bp; /*恢复原BP值*/
}
/********************************************
函数作用:装入用户字符集到位平面2中
入口参数:seg 用户字符集的段址
off 用户字符集的偏移地址
n 位平面2中的区号
*********************************************/
void LoadUserFontToVGA(int seg,int off,int n)
{ int bp;
bp=_BP;
_AX=seg; /*用户字符段地址*/
_ES=_AX;
_AX=0x1110; /*AX=1110 装入用户定义的字符集*/
_BH=16; /*每个字符字模数据字节数*/
_BL=n; /*位平面2中的区号(VGA 0-7;EGA:0-3) */
_DX=0; /*位平面2中区内偏移量*/
_CX=256; /*需装入的字符个数*/
_BP=off; /*用户字符的偏移地址*/
geninterrupt(0x10);
_BP=bp;
}
void SetWordFont(unsigned char a,unsigned char b)
/*函数作用:设置工作字符集
入口参数:a 字符集A的区号
b 字符集B的区号*/
{ b=(b&7)<< 2; /*VGA最多8个区*/
a=(a&3)|((a<<3)&0x10);
b=(b&12)|((b<<2)&0x20);
a|=b;
_BL=a;
/*b4,b1,b0 =字库A在位平面2 中的区号
b5,b3,b2 =字库B在位平面2 中的区号*/
_AX=0x1103; /*选择工作字符*/
geninterrupt(0x10);
}
void SaveScreen()
{movedata(0xb800,0,0xb800,160*25,160*25);}
void RestoreScreen()
{movedata(0xb800,160*25,0xb800,0,160*25);}
/*函数作用:获取屏幕坐标(x,y)处的英语单词
入口参数:x,y 屏幕坐标
buf 屏幕单词保存处*/
void GetScreenWord(int x,int y,char *buf)
{ int i; char c;
c=tolower(peekb(0xb800,y*160+2*x));
if (c='z') { *buf=0;return;}
if (x>0)
{ do{ c=tolower(peekb(0xb800,y*160+2*x));
if( c'z') { x++;break;}
x--;
}while(x>0);
}
for(c=tolower(peekb(0xb800,y*160+2*x));c='a'
{*buf++=c;x++;
c=tolower(peekb(0xb800,y*160+2*x));
}
*buf=0;
}
int EditString(char *buf,int x,int y,int max)
/*函数作用: 编辑字符串
入口参数: x,y 显示的坐标
buf 欲修改的字符串
max 最大个数
出口参数:用户按键 */
{ char s[256];
char format[10];
int key;
int len;
len=strlen(buf);
gotoxy(x,y); /*在坐标处显示字符串*/
strcpy(s,buf);
printf(s);
while(1)
{ key=bioskey(0);
switch(key)
{ case ESC:
case TAB: return(key);
case ENTER: strcpy(buf,s);
return(ENTER);
case BreakSpace:
if (len>0)
{ gotoxy(wherex()-1,wherey());
putchar(' ');
gotoxy(wherex()-1,wherey());
len--; s[len]=0;
}
else BEEP();
break;
default:
if (len=' ' && keyImdId,"UCDOS IMD FILE\x1a")
{/*比较是否为UCDOS IMD FIlE*/
free(ImdHeadMsg);/*释放为存放IMD文件头部信息而分配的内存*/
fclose(ImdFp);
return(NotImdFile);
}
size=ImdHeadMsg->InderTableNumber*3; /*计算索引表大小*/
InderTable=(BYTE *)malloc(size+1);/*为索引内容分配内存*/
if (InderTable==NULL)
{ free(ImdHeadMsg);
fclose(ImdFp);
return(MallocError);
}
fseek(ImdFp,0x80+ImdHeadMsg->InderTableOffset,SEEK_SET);
fread(&InderTable[3],size,1,ImdFp);
/*将索引内容读入索引列表中*/
size=ImdHeadMsg->InderTableOffset+
ImdHeadMsg->InderTableNumber*3+0x80;
memmove(InderTable,&size,3);
return(OK); /*挂接成功*/
}
|
我(QB45)的照片与简历
http://www.programfan.com/club/showbbs.asp?id=197280
|
|
2003-10-9 00:00 |
|
|
QB45
高级用户
积分 677
发帖 194
注册 2003-9-13
状态 离线
|
『第
3 楼』:
void GetWord(BYTE *buf,BYTE *s,BYTE *WordBuf)
{ /*************************************
作用:取编码s对应的汉字
入口参数:buf 汉字索引表内容
s 编码
WordBuf 编码对应的汉字信息
出 口: WordBuf 编码s对应的汉字或词组
为空时 表示无
*************************************/
{
BYTE *ss,*PreS,ch;
PreS=buf;
while(1)
{ ss=strstr(PreS,s);
if (ss==NULL){*WordBuf=0;return;} /*编码对应无汉字*/
if ( *(ss+strlen(s) )>= 0xa0 && *(ss-2)>=0xa0) break;
PreS=ss+strlen(s);
}
while(*ss0xa0)
*(WordBuf++)=*(ss++); /*查询该汉字*/
*ss|=0x80 ; /*高位置0*/
ch=*(ss+1);
/*其汉字后对应的是ASCII表示没有汉字或词组*/
if (ch>0x80)
{ *(WordBuf++)=*(ss++);
*(WordBuf++)=';';
}
else {*WordBuf++=*ss;
*WordBuf++='.';
*WordBuf=0;
return;
}
} }}
void ShowMsg() /*显示屏幕字典中的信息*/
{ textcolor(COLOR);
textbackground(BKCOLOR);
gotoxy(SHOW_DICT_ENGLISHWORD_X,line+2);
cprintf("%-20s",EnglishWord);
gotoxy(3,line+4);
if (*EnglishWord==0) /*若当前无英文单词,显示作者信息*/
{ strcpy(EnglishWord,"Screen EC Dictionary" /*英语单词*/
strcpy(CwordMsg,"《屏幕英汉字典 V1.0》 设计:湖北省浠水师范学校 江 龙 孙国喜" /*汉语信息*/
}
if (*CwordMsg==0) /*若单词对应的无汉字信息,表示此字典中无对应的单词*/
strcpy(CwordMsg,"本字典中无此单词."
if(ShowMode==CHINESE) /*当前处于中文文本模式下,直接输出*/
cprintf("%-74s",CwordMsg);
else /*否则,利用西文文本方式下显示字符串函数*/
{cprintf("%-74s"," " /*清汉字信息区域*/
PutString(CwordMsg,2,line+3,COLOR,BKCOLOR);
}
}
int IsInTable(BYTE key) /*key是否在码元表中*/
{ BYTE *s;
int l;
s=strchr(ImdHeadMsg->CodeTable,key);
if (*s==0 || s==NULL) return(0);
else return(s-ImdHeadMsg->CodeTable+1);
}
int GetEnglishCword(BYTE *buf,BYTE *CodeBuf)
/*作 用:取英语单词对应的汉语意义
入口参数:CodeBuf 英语单词 buf 汉字信息保存处
说 明:若无汉字信息,buf内容为0.*/
{ long ll=0,length=0,offset;
BYTE *WordBuf;
offset=IsInTable(CodeBuf[1]);
if(offset==0) offset=1;/*若第2个字符为空格,表示单个字母*/
offset=(IsInTable(*CodeBuf)-1)*ImdHeadMsg->CodeTableSize
+offset-1;
memmove(&ll,&InderTable[3*offset],3);
memmove(&length,&InderTable[3*(offset+1)],3);
length-=ll;
WordBuf=(BYTE *) malloc(length+3);
if (WordBuf==NULL) return(MallocError);
WordBuf[0]=0xa0;
WordBuf[1]=32;
fseek(ImdFp,ll,SEEK_SET); /*将文件指针移到索引内容处*/
fread(&WordBuf[2],length,1,ImdFp); /*读取内容*/
WordBuf[length+2]=0;
GetWord(&WordBuf[2],CodeBuf,buf);
free(WordBuf);
return(OK);
}
main()
{ char buf[80];
int oldx,oldy;
int x,y,key,IsChang;
int IsWhile=1;
oldx=wherex(); /*保存原坐标位置*/
oldy=wherey();
x=0;y=0;
if (inportb(0x3c5) % 2 ) /*当前处于的文本模式*/
ShowMode=CHINESE; /*当前处于中文文本方式下*/
else { ShowMode=ENGLISH; /*否则,当前处于西文文本方式下*/
LibFp=fopen(HZK16,"rb" /*打开汉字库*/
if (LibFp==NULL)
{printf("\7Error:%s not opend.\n",HZK16);
exit(0);
}
}
if(LoadIMD(EC)!=OK) exit(0);
SaveScreen();
ShowDictMsg();
while(IsWhile)
{ gotoxy(x+1,y+1);
key=bioskey(0);
IsChang=1;
switch(key)
{ case UP: /*上移一行*/
if (y>0) y--;
break;
case DOWN:/*下移一行*/
if (y80){ x=0;y++;}
break;
case ESC:/*ESC,退出*/
IsWhile=0; break;
case TAB:/*TAB键,切换到用户输入英文单词*/
while(1)
{key=EditString(EnglishWord,SHOW_DICT_ENGLISHWORD_X,
line+2,EnglistWordNum);
if (key==ENTER)
{if(*EnglishWord!=0) /*用户输入了英文单词*/
GetEnglishCword(CwordMsg,EnglishWord);
/*查找当前单词对应的汉语意义*/
ShowDictMsg(); /*在屏幕上显示此意义*/
}
else{ if(key==ESC) IsWhile=0;
break; }
}
break;
default: IsChang=0;break;
}
if (DictStatus==UP && y=SHOW_DICT_DOWN-1)
/*若当前光标到达了英汉字典显示区域,则改变字典的显示区域*/
{ first=1;
ChangeShowXY();
}
if (IsChang)
{ GetScreenWord(x,y,buf); /*取当前光标处的屏幕英语单词*/
if (*buf!=0 && strcmp(EnglishWord,buf) )
/*若当前屏幕单词与上一个不同,则查找当前单词对应的汉语意义*/
{ strcpy(EnglishWord,buf); /*将此单词保存*/
GetEnglishCword(CwordMsg,EnglishWord); /*查找当前单词对应的汉语意义*/
ShowDictMsg(); /*在屏幕上显示此意义*/
}
}
}
RemoveIMD(); /*卸去为IMD文件分配的内存*/
if (ShowMode==ENGLISH)
/*当前处于西文文本模式,将两工作字库设置一样*/
SetWordFont(0,0);
gotoxy(oldx,oldy); /*恢复原光标位置*/
RestoreScreen(); /*恢复原屏幕内容*/
|
我(QB45)的照片与简历
http://www.programfan.com/club/showbbs.asp?id=197280
|
|
2003-10-9 00:00 |
|
|
spirit
初级用户
积分 111
发帖 5
注册 2003-12-1
状态 离线
|
|
2004-1-8 00:00 |
|
|
陈沫
中级用户
积分 250
发帖 54
注册 2003-6-8
状态 离线
|
『第
5 楼』:
顶
|
http://lingding.vicp.net
或许能帮你忙 |
|
2004-1-10 00:00 |
|
|
tdj
银牌会员
论坛候鸟
积分 1131
发帖 332
注册 2003-11-27
状态 离线
|
|
2004-1-17 00:00 |
|
|