ncurses这个库,最早听说应该是当年刚接触Linux的时候,当时,我们宿舍就一个人在鼓捣Linux,他是我们后来的班长,如今在ZLG混,也不知混得怎么样了。我也不知道哪条神经线路出现故障了,竟然傻乎乎去学Linux,到后来,一发不可收拾,从此走上了一条不归路。到毕业前,我曾经说过了研究ncurses库的,还写了文章,文章说要在毕业时将ncurses掌握到什么程度。可惜,人算不如天算,计划跟不上变化,天有不测之风云,后来就不了了之了。
ncurses库已经离我们越来越远了,很多场合已经用不上了,特别是现在iphone、ipad、android横行的时代。
现在,趁着研究汉字显示的时候,用一下它吧。其实,最主要的原因是前面的代码只能竖着显示汉字,不能横着显示,因此看不到一连串汉字的显示效果。虽然没有兑现当时的诺言,不过还是没有忘记它(这话听起来怎么有点像那什么似的)。
以一个最简单的代码示例欢迎ncurses库:
/* hello.c */
#include <ncurses.h>
int main()
{
initscr(); /* 初始化,进入NCURSES模式 */
mvprintw(10,1,"ABCD");
refresh(); /* 将虚拟屏幕上的内容写到显示器上,并刷新*/
mvprintw(11,1,"ABCD");
refresh();
endwin(); /* 退出NCURSES模式 */
return 0;
}
编译命令如下:
$ gcc hello.c -lncurses
因为ncurses不是Linux标准库,因此需要使用-l指定这个库。
这个代码运行的效果是在屏幕的第10行和11行的第1列显示“ABCD”。
本文就是利用ncurses库,在指定的坐标打印字符。在原来基础上进行的修改不多,只需添加几个与ncurses有关的函数即可,比如初始化屏幕的,结束ncurses屏幕,刷新,等等。
下面是初步完成粗糙的新鲜出炉的代码,解决了前面文章中提到的中英文混合显示的bug。
/***************************************************
字符集编码统一为gb2312,即源代码文件保存格式为gb2312(notepad++下显示为“ANSI”),
编译环境的字符集编码为gb2312,如果不是,可能得不到预期效果
多个汉字 & 中英文混合显示
编译:$ gcc font-test-ncurses.c -lncurses
运行:$ ./a.out
源代码文件编码:ANSI
测试环境编码:zh_CN.UTF-8、zh_CN.gd2312
log:
中文使用字库HZK16,英文使用font_8x16.h头文件中的数组,寻址方式为a[i]*16,与ASCII字库一样
而font_8x16-me.h头文件的数组,寻址方式为(a[i] - 0x20) * 16。
*16与<<4暂时未作比较。
*************************************************/
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <ncurses.h>
/* ncurses库头文件 */
//#include "font_8x16.h"
#include
"font_8x16-me.h"
#define font_size
32
#define ascii_size
16
//#define ascii_code fontdata_8x16 /* font_8x16.h */
#define ascii_code fontdata_8x16_me
/* for debug */
//#define DEBUG
#ifdef DEBUG
#define debug(fmt, ...) printw(fmt, ##__VA_ARGS__)
#else
#define debug(fmt, ...)
#endif
void display_font(
int y,
int x,
unsigned
char *mat)
{
int i, j, k;
for(i=
0;i<
16;i++)
{
for(j=
0;j<
2;j++)
/* 汉字占2个字节 */
{
for(k=
0;k<
8;k++)
/* 输出一个字节*/
{
/* 逐位相与,为1者,输出“*” */
if(mat[i*
2+j] & (
0x80>>k))
mvprintw(y+i, x+j*
8+k,
"*");
else
mvprintw(y+i, x+j*
8+k,
" ");
}
}
}
refresh();
}
void display_font_ascii(
int y,
int x,
unsigned
char *ascii)
{
int i, j;
debug(
"=================/n");
for(i=
0;i<
16;i++)
{
for(j=
0;j<
8;j++)
{
if(ascii[i] & (
0x80>>j))
mvprintw(y+i, x+j,
"*");
else
mvprintw(y+i, x+j,
" ");
}
}
debug(
"=================/n");
refresh();
}
int main()
{
int i;
//unsigned char incode[] = "我Az你个pf"; /* 全部是中文字符,英文为全角状态下输入 */
//unsigned char incode[] = "人生如梦"; /* 全部中文 */
//unsigned char incode[] = "I'm Late Lee"; /* 全部英文 */
unsigned
char incode[] =
"我A你个BCD";
/* 中文、英文 */
unsigned
char *p;
unsigned
char *p_ascii;
int qh,wh;
unsigned
long offset;
FILE *HZK;
unsigned
char mat[
32]={
0};
int y =
5;
/* 行 */
int x =
0;
/* 列 */
initscr();
/* init screen */
if((HZK=fopen(
"HZK16",
"rb"))==NULL) {
perror(
"Can't Open hzk16");
exit(
0);
}
/* 中英混合显示 */
#if
0
/* 中英文混合显示时,这种方法似乎不好处理,暂时舍弃 */
for (i =
0; i <
sizeof(incode)-
1; i+=
2)
{
qh = incode[i] -
0xa0;
wh = incode[i+
1] -
0xa0;
if (qh >
0 && wh >
0) {
debug(
"code : %x %x/n", incode[i], incode[i+
1]);
offset = (
94*(qh-
1) + (wh-
1) ) *
32;
// 计算偏移
fseek(HZK,offset,SEEK_SET);
fread(mat,
32,
1,HZK);
display_font(y, x, mat);
x +=
16;
}
else {
int offset1, offset2;
offset1 = (incode[i]-
0x20) *
16;
/*16*/
offset2 = (incode[i+
1]-
0x20) *
16;
/*16*/
p_ascii = ascii_code + offset1;
display_font_ascii(y, x, p_ascii);
x +=
8;
p_ascii = ascii_code + offset2;
display_font_ascii(y, x, p_ascii);
x +=
8;
}
}
#endif
/* 另一种方法 */
#if
01
p = incode;
while (*p !=
0)
{
qh = *p -
0xa0;
wh = *(p+
1) -
0xa0;
if (qh >
0 && wh >
0){
debug(
"code : %x %x/n", *p, *(p+
1));
offset = (
94*(qh-
1) + (wh-
1) ) *
32;
debug(
"qh: %x wh: %x offset: %x/n", qh, wh, offset);
fseek(HZK,offset,SEEK_SET);
fread(mat,
32,
1,HZK);
display_font(y, x, mat);
x +=
16;
p+=
2;
/* 中文字符,移动2个字节 */
}
else {
int offset1;
offset1 = (*p -
0x20 ) *
16;
p_ascii = ascii_code + offset1;
display_font_ascii(y, x, p_ascii);
x +=
8;
p+=
1;
/* 英文字符,移动1个字节 */
}
}
#endif
fclose(HZK);
getch();
/*暂停*/
endwin();
/* close it */
return
0;
}
中文显示效果如下(“人生如梦”,为方便网页显示,非实际数据,下同):
* * * * *
* * * * * * *
* * * * ***************
* * * * * * * *
* ************ ******* ******* *** ***
* * * * * * * * * * * * ***
* * * * * * * * * * * *
* * * * * * * * * ** *
* * * * * * * * * ********
* * *********** * * * * ** *
* * * * * * * * * *
* * * * * * * * * *
* * * * * * **
* * * * * * ****** *
* *** *************** * * * * ***
* * * ***
中英文混合显示效果如下(“我A你个BCD”):
* * * * *
*** * * * * *
**** * * * * * * * ****** **** *****
* * * *** * ******** * * ** ** ** ** ** **
* * * ** ** * * * * * ** ** ** * ** **
*************** ** ** ** * * * * * ** ** ** ** **
* * ** ** * * * * * * *** ***** ** ** **
* * * ******* * * ** * * ** ** ** ** **
* * * * ** ** * * * * * ** ** ** ** **
** ** ** ** * * * * * ** ** ** * ** **
** * ** ** * * * ** * ** ** ** ** ** **
** * * * ** ** * * * * * ****** **** *****
* * * * * *
* * * * * * *
* * * * * * * *
* ** * * *
我一般不对代码进行详细注释和解释,对于看得懂的人,过多注释反而不好;对于看不懂的人,再多注释也是徒劳。不过,我还是凭良心在代码中写了一些注释。由于完整的工程代码还没有整理,未知bug还没找到,不敢放在网络上,见谅。由于各种网页行距、字与字之间间隔不太相同,如果文中效果显示不好,请移步这里查看:中文、英文字库显示效果。
后记:
到本文为止,在PC机上的测试就完成了,已经取得了“决定性的进展”,下面就可以模仿tslib的代码,在触摸屏上显示汉字了,再接着就可以将触摸屏、ADC采集结合起来了。——未来总是美好的。
本次测试过程约使用了一周时间,完成了ADC驱动后,不知哪根神经线出了问题,也不知道怎么想的,突然想去研究汉字显示。结果也慢慢学到了点东西。从在脑中的计划,到实施,似乎一切都按我想像中的步骤有序地进行着:先学习编码,显示单个汉字,显示多个汉字,中英文混合显示,纵向显示,横向显示,等等。在未来的日子,我所遇之事是否也会按我的计划进行呢?我不得而知。《终结者3》中有一句经典台词,大意是说未来还没有定数,命运靠自己创造云云。我对社会也算有了初步认识,再说当年的激情、豪气,就有点显得不现实了(对于我所感兴趣的写代码事情,我依然有激情)。生活是要有一些激励的故事、人物的,但不会是我。我只想做普通人,在遇到问题时我会烦恼,解决问题后我会十分高兴,有研究心得时,愿意与他人分享。
无论怎么,未来总是美好的,一切都未知,值得我们憧憬。