📄 关于frambuffer--狼牙月.htm
字号:
<P>1不进行conv_uni_to_pc( )的转换。</P>
<P>2加载符合双字节处理的映射关系,即对非控制字符进行1对1的不变映射。我们自己定制的符合这种映射关系的UNICODE码表是direct.uni。要想查看/装载当前系统的unicode映射表,可使外部命令loadunimap。</P>
<P>经过conv_uni_to_pc( )转换之后,"hello,
world.\n"中的字符被一个一个地填写到tty1的缓冲区中。然后do_con_write(
)调用下层的驱动,把缓冲区中的内容输出到显示器上(也就相当于把缓冲区的内容拷贝到VGA显存中去)。</P>
<P>sw->con_putcs(vc_cons〔currcons〕.d, (u16
*)draw_from, (u16*)draw_to-(u16 *)draw_from, y,
draw_x);</P>
<P>之所以要调用底层驱动,是因为存在不同的显示设备,其对应VGA显存的存取方式也不一样。</P>
<P>上面的Sw->con_putcs(
)就会调用到fbcon.c中的fbcon_putcs()函数(con_putcs是一个函数的指针,在Framebuffer模式下指向
fbcon_putcs()函数)。也就是说在do_con_write(
)函数中是直接调用了fbcon_putcs()函数来进行字符的绘制。比如说在256色模式下,真正负责输出的函数是void
fbcon_cfb8_putcs(struct vc_data *conp, struct display
*p,const unsigned short *s, int count, int yy, int
xx)</P>
<P>显示中文</P>
<P>比如说我们试图输出一句中文∶putcs(你好\n
);(你好的内码为0xc4,0xe3,0xba,0xc3)。这时候会怎么样呢,有一点可以肯定,"你好"肯定不会出现在屏幕上,国为核心中没有汉字字库,中文显示就是无米之炊了.</P>
<P>1 在负责字符显示的void fbcon_cfb8_putcs(
)函数中,原有操作如下∶对于每个要显示的字符,依次从虚拟终端缓冲区中以WORD为单位读取(低位字节是ASCII码,高8位是字符的属性),由于汉字是双字节编码方式,所以这种操作是不可能显示出汉字的,只能显示出xxxx_putcs()是一个一个VGA字符.</P>
<P>要解决的问题∶</P>
<P>确保在do_con_write(
)时uni□pc转换不会改变原有编码。一个很直接的实现方式就是加载一个我们自己定制的UNICODE映射表,loadunimapdirect.uni,或者直接把direct.uni置为核心的缺省映射表。</P>
<P>针对如上问题,我们要做的第一个尝试方案是如下。</P>
<P>首先需要在核心中加载汉字字库,然后修改fbcon_cfb8_putcs()函数,在fbcon_cfb8_putcs(
)中一次读两个WORD,检查这两个WORD的低位字节是否能拼成一个汉字,如果发现能拼成一个汉字,就算出这个汉字在汉字字库中的偏移,然后把它当成一个16
x 16的VGA字符来显示。</P>
<P>试验的结果表明∶</P>
<P>1能够输出汉字,但仍有许多不理想的地方,比如说,输出以半个汉字开始的一串汉字,则这半个汉字后面的汉字都会是乱码。这是半个汉字的问题。</P>
<P>2光标移动会破坏汉字的显示。表现为,光标移动过的汉字会变成乱码。这是因为光标的更新是通过xxxx_putc(
)函数来完成的。</P>
<P>xxxx_putc( )函数与xxxx_putcs(
)函数实现的功能类似,但是xxxx_putc()函数只刷新一个字符而不是一个字符串,因而xxxx_putc()的输入参数是一个整数,而不是一个字符串的地址。Xxxx_putc(
)函数的声明如下∶void fbcon_cfb8_putc(struct vc_data *conp,
struct display *p, int c, int yy, int xx)</P>
<P>下一个尝试方案就是同时修改xxxx_putcs(
)函数和xxxx_putc()函数。为了解决半个汉字的问题,每一次输出之前,都从屏幕当前行的起始位置开始扫描,以确定要输出的字符是否落在半个汉字的位置上。如果是半个汉字的位置,则进行相应的调整,即从向前移动一个字节的位置开始输出。</P>
<P>这个方案有一个困难,即xxxx_putc(
)函数不用缓冲区的地址,而是用一个整数作为参数。所以xxxx_putc(
)无法直接利用相邻的字符来判别该定符是否是汉字。</P>
<P>解决方案是,利用xxxx_putc( )的光标位置参数(yy,
xx),可以逆推出该字符在缓冲区中的位置。但仍有一些小麻烦,在Linux的虚拟终端下,用户可能会上卷该屏幕(shift
+
pageup),导致光标的y座标和相应字符在缓冲区的行数不一致。相应的解决方案是,在逆推的过程中,考虑卷屏的参量。</P>
<P>这样一来,我们就又进了一步,得到了一个相对更好的版本。但仍有问题没有解决。敲入turbonetcfg,会发现菜单的边框字符也被当成汉字显示。这是因为,这种边框字符是扩展字符,也使用了字符的第8位,因而被当作汉字来显示。例如,单线一的制表符内码为0xC4,当连成一条长线就是由一连串0xC4组成,而0xC4C4正是汉字哪。于是水平的制表符被一连串的哪字替代了。要解决这个问题就非常不容易了,因为制表符的种类比较多,而且垂直制表符与其后面字符的组合型式又多种多样,因而很难判断出相应位置的字符是不是制表符,从理论上说,无论采取什么样的排除算法,都必然存在误判的情况,因为总存在二义性,没有充足的条件来推断出当前字符究竟是制表符还是汉字。</P>
<P>我们一方面寻找更好的排除组合算法,一方面试图寻找其它的解决方案。要想从根本上解决定个问题,必须利用其它的辅助信息,仅仅从缓冲区的字符来判断是不够的。</P>
<P>经过一番努力,我们发现,在UNIX中使用扩展字符时,都要先输出字符转义序列(Escape
sequence)来切换当前字符集。字符转义序列是以控制字符Esc为首的控制命令,在UNIX的虚拟终端中完成终端控制命令,这种命令包括,移动光标座标、卷屏、删除、切换字符集等等。也就是说在输出代表制表符的字符串之前,通常是要先输出特定的字符转义序列。在console.c里,有根据字符转义序列命令来记录字符状态的变量。结合该变量提供的信息,就可以非常干净地把制表符与汉字区别开来。</P>
<P>在如上思路的指引下,我们又产生了新的解决方案。经过改动得到了另一各版本.</P>
<P>在这个新版本上,turbonetcfg在初次绘制的时候,制表符与汉字被清晰地区分开来,结果是非常正确的。但还有新的问题存在∶turbonetcfg
在重绘的时候(如切换虚拟终端或是移动鼠标光标的时候),制表符还是变成了汉字,因为重绘完全依赖于缓冲区,而这时用来记录字符集状态的变量并不反映当前字符集状态。问题还是没有最终解决。我们又回到了起点。∶(
看来问题的最终解决手段必须是把字符集的状态伴随每一个字符存在缓冲区中。让我们来研究一下缓冲区的结构。每一个字符占用16bit的缓冲区,低8位是ASCII值,完全被利用,高8位包含前景颜色和背景颜色的属性,也没有多余的空间可以利用。因而只能另外开辟新的缓冲区。为了保持一致性,我们决定在原来的缓冲区后面添加相同大小的缓冲区,用来存放是否是汉字的信息。</P>
<P>也许有读者会问,我们只需要为每个字符添加一bit<BR></P>
<DIV></DIV></DIV></SPAN></TD></TR></TBODY></TABLE>
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR>
<TD height=3> </TD></TR></TBODY></TABLE>
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR>
<TD>
<DIV align=right><SPAN class=textbox-urls><A
href="http://www.mcublog.com/blog/user1/9450/archives/2006/19773.html#">阅读全文<SPAN
id=ob_logreaded></SPAN></A> | <A
href="http://www.mcublog.com/blog/user1/9450/archives/2006/19773.html#cmt">回复(1)</A>
| <A
href="http://www.mcublog.com/blog/showtb.asp?id=19773"
target=_blank>引用通告<SPAN id=ob_tbnum></SPAN></A> | <A
href="http://www.mcublog.com/blog/user_post.asp?logid=19773"
target=_blank>编辑</A></SPAN></DIV></TD></TR></TBODY></TABLE>
<TABLE height=14 cellSpacing=0 cellPadding=0 width="100%"
align=center border=0>
<TBODY>
<TR>
<TD><IMG height=25
src="关于frambuffer--狼牙月.files/index_13.jpg"
width=264></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE>
<DIV id=morelog>
<UL>
<LI>上一篇:<A
href="http://www.mcublog.com/blog/user1/9450/archives/2006/19756.html">jollen的blog</A>
<LI>下一篇:<A
href="http://www.mcublog.com/blog/user1/9450/archives/2006/19871.html">tftlcd backlight</A></LI></UL></DIV>
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR>
<TD>
<TABLE class=seyle4 cellSpacing=0 cellPadding=0 width="100%"
border=0>
<TBODY>
<TR>
<TD> </TD></TR>
<TR>
<TD id=content9><STRONG>Re:关于frambuffer<A
name=7999></A></STRONG></TD></TR>
<TR>
<TD>
<DIV align=right><SPAN class=textbox-label>[ <SPAN
id=t_7999>2007-1-30 11:53:18</SPAN> | By: <SPAN
class=style3><SPAN id=n_7999>kinghua_q</SPAN></SPAN>
]</SPAN></DIV></TD></TR></TBODY></TABLE>
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR>
<TD height=3> </TD></TR></TBODY></TABLE>
<TABLE style="TABLE-LAYOUT: fixed" cellSpacing=0 cellPadding=0
width="100%" align=center border=0>
<TBODY>
<TR>
<TD><SPAN class=oblog_text><A
href="http://kinghua_q.mcublog.com/" target=_blank><IMG
class=ob_face height=48
src="关于frambuffer--狼牙月.files/ico_default.gif" width=48
align=absMiddle></A><SPAN id=c_7999>好 我帮你顶下</SPAN>
</SPAN></TD></TR></TBODY></TABLE>
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR>
<TD height=3> </TD></TR></TBODY></TABLE>
<TABLE cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY>
<TR>
<TD>
<DIV align=right><SPAN class=textbox-urls><A
href="http://kinghua_q.mcublog.com/"
target=_blank>个人主页</A> | <A
href="javascript:reply_quote('7999')">引用</A> | <A
href="http://www.mcublog.com/blog/user1/9450/archives/2006/19773.html#top">返回</A>
| <A
href="http://www.mcublog.com/blog/user_comments.asp?action=del&id=7999"
target=_blank>删除</A> | <A
href="http://www.mcublog.com/blog/user_comments.asp?action=modify&re=true&id=7999"
target=_blank>回复</A></SPAN></DIV></TD></TR></TBODY></TABLE>
<TABLE height=14 cellSpacing=0 cellPadding=0 width="100%"
align=center border=0>
<TBODY>
<TR>
<TD><IMG height=25
src="关于frambuffer--狼牙月.files/index_13.jpg"
width=264></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE>
<SCRIPT src=""></SCRIPT>
<A name=cmt></A>
<H2>发表评论:</H2>
<DIV id=form_comment>
<FORM id=commentform name=commentform
onsubmit="return Verifycomment()"
action=/blog/savecomment.asp?logid=19773 method=post>
<UL>大名:<INPUT id=UserName maxLength=20 size=15 name=UserName></UL>
<UL>密码:<INPUT id=Password type=password maxLength=20 size=15
name=Password> (游客无须输入密码)</UL>
<UL>主页:<INPUT id=homepage maxLength=50 size=42 value=http://
name=homepage></UL>
<UL>标题:<INPUT id=commenttopic maxLength=50 size=42
value=Re:关于frambuffer name=commenttopic></UL>
<UL><INPUT id=edit type=hidden name=edit>
<DIV id=oblog_edit>MCU博客数据载入中, 请稍候...</DIV></UL>
<UL><SPAN
id=ob_code></SPAN><INPUT type=submit value=" 提交 "></UL></FORM></DIV></TD></TR></TBODY></TABLE></DIV></TD></TR></TBODY></TABLE>
<TABLE cellSpacing=0 cellPadding=0 width=788 align=center border=0>
<TBODY>
<TR>
<TD><IMG height=36 alt="" src="关于frambuffer--狼牙月.files/index_20.jpg"
width=788 border=0></TD></TR></TBODY></TABLE>
<SCRIPT src=""></SCRIPT>
<DIV id=powered><A href="http://www.oblog.cn/" target=_blank><IMG
alt="Powered by Oblog." src="关于frambuffer--狼牙月.files/oblog_powered.gif"
border=0></A></DIV>
<SCRIPT src="关于frambuffer--狼牙月.files/show_subject.htm"></SCRIPT>
<SCRIPT src="关于frambuffer--狼牙月.files/show_placard.htm"></SCRIPT>
<SCRIPT src="关于frambuffer--狼牙月.files/200612.htm"></SCRIPT>
<SCRIPT src="关于frambuffer--狼牙月.files/show_search.htm"></SCRIPT>
<SCRIPT src="关于frambuffer--狼牙月.files/show_newblog.htm"></SCRIPT>
<SCRIPT src="关于frambuffer--狼牙月.files/show_comment.htm"></SCRIPT>
<SCRIPT src=""></SCRIPT>
<SCRIPT src=""></SCRIP
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -