14.encoding(附编码解释)/fonts/debug/input文件夹分析

1.encoding

用到的结构体

typedef struct EncodingOpr {
	char *name;    				/* 编码模块的名字 */
	int iHeadLen;  				/* 文件头的长度: 一般在文件的开始用几个字节来表示它的编码方式 */
	PT_FontOpr ptFontOprSupportedHead;  			/* 把能支持这种编码的"字体模块", 放在这个链表里 */
	int (*isSupport)(unsigned char *pucBufHead);  	/* 用这个函数来判断是否支持某个文件 */
	int (*GetCodeFrmBuf)(unsigned char *pucBufStart, unsigned char *pucBufEnd, unsigned int *pdwCode);  /* 取出一个字符的编码值 */
	struct EncodingOpr *ptNext; 					 /* 链表 */
}T_EncodingOpr, *PT_EncodingOpr;

encoding_manager.c

static PT_EncodingOpr g_ptEncodingOprHead; //编码的头
int RegisterEncodingOpr(PT_EncodingOpr ptEncodingOpr);
void ShowEncodingOpr(void);
PT_EncodingOpr SelectEncodingOprForFile(unsigned char *pucFileBufHead);	//给文件选一种编码方式,就是一一调用编码链表成员里的isSupport函数判断
/* 这个函数本质就是ascii.c中的AsciiGetCodeFrmBuf
 * 这个函数获取编码,只适用于ascii和gbk
 * 传入一个起始一个结束地址,如果这个起始地址的值小于128,那么就说明这是一个单字节的ascii码
 * 而如果这个值大于128,那么就说明这是一个双字节的GBK码
 */
int GetCodeFrmBuf(unsigned char *pucBufStart, unsigned char *pucBufEnd, unsigned int *pdwCode)	
/* 传入一个编码结构体,一个字体结构体 
 * malloc一个字体结构体T_FontOpr内存,把传进来的结构体赋值给malloc的这块内存
 * 编码结构体的ptFontOprSupportedHead,以头插法把刚malloc的内存插入链表
 * 为什么这里要malloc一块内存,而不用传入的字体结构体直接插入?:
 * 因为在字体结构体链表中,这个结构体已经插入那里了,next指针指向是那个链表的下一个
 */
int AddFontOprForEncoding(PT_EncodingOpr ptEncodingOpr, PT_FontOpr ptFontOpr)

/* 从编码结构体的支持字体链表中删除和这个同名的字体结构体,并释放掉当初malloc的内存 */
int DelFontOprFrmEncoding(PT_EncodingOpr ptEncodingOpr, PT_FontOpr ptFontOpr)

/* 调用各编码的Init,注册到encoding_manager.c文件中 */
int EncodingInit(void)

关于各编码方式

  • ASCII和GBK(GB2312)
  1. ASCII是单字节的编码方式,GBK是双字节的编码方式,GBK兼容ASCII,是在ASCII的基础上扩展。
  2. ASCII编码方式只用到0-127,也就是一个字节的前7位,第八位未用到为0.
  3. GB2312首先对ASCII进行扩展,使用两个字节,第一个字节和第二个字节都是从0xA1,即其两个字节的最高位都是1,这样就可以很好的和ASCII区分开。
  4. GBK是在GB2312的基础上继续扩展,是对GB2312的扩展,其不要求第二个字节必须大于127,只要求第一个字节大于127,也就是说,只要第一个字节大于127,那么就代表这是一个汉字的开始,且占用两个字节
  5. https://blog.youkuaiyun.com/ldanduo/article/details/8203532/ 这篇文章写的还可以
  • unicode和UTF8/UTF16LE/UTF16BE
  1. unicode是国际的一种同一编码标准,统一占用两个字节,和中国自己的GBK编码完全不一样,没有一个公式可以转换,只能查表
  2. UTF8等只是对unicode的不同的表现形式,UTF16LE/BE只是对UNICODE的一个字节序的改变,UTF8是可以将英文用一个字节表示,具体的编码方式,从代码里看

2.fonts

结构体

/* 用来存放一个“字”的位置信息 */
typedef struct FontBitMap {
	int iXLeft;  		/* 位图左上角X座标 */
	int iYTop;   		/* 位图左上角Y座标 */
	int iXMax;   		/* 位图的最大X座标值 */
	int iYMax;   		/* 位图的最大Y座标值 */
	int iBpp;    		/* 位图中一个象素用多少位来表示 */
	int iPitch;  		/* 对于单色位图, 两行象素之间的跨度, 即第N行、第N+1行象素数据之间的偏移值,注意这里是单色*/
	int iCurOriginX; 	/* 位图的原点X座标(一般是左下角), 使用原点来确定相邻字符的位置 */
	int iCurOriginY;  	/* 位图的原点Y座标 */
	int iNextOriginX; 	/* 下一个字符即右边字符的原点X座标 */
	int iNextOriginY; 	/* 下一个字符即右边字符的原点Y座标 */
	unsigned char *pucBuffer;  	/* 存有字符的位图数据 */
}T_FontBitMap, *PT_FontBitMap;

/* 支持哪些字体的结构体 */
typedef struct FontOpr {
	char *name;            										 /* 字体模块的名字 */
	int (*FontInit)(char *pcFontFile, unsigned int dwFontSize);  /* 字体模块的初始化函数 */
	int (*GetFontBitmap)(unsigned int dwCode, PT_FontBitMap ptFontBitMap);  /* 根据编码值获得字符的位图 */
	void (*SetFontSize)(unsigned int dwFontSize);   			/* 设置字体尺寸(单位:象素) */
	struct FontOpr *ptNext;  									/* 链表 */
}T_FontOpr, *PT_FontOpr;

fonts_manager.c

int RegisterFontOpr(PT_FontOpr ptFontOpr);
void ShowFontOpr(void);
PT_FontOpr GetFontOpr(char *pcName);
void SetFontSize(unsigned int dwFontSize);		// 调用每个字体结构体的SetFontSize来设置字体大小
unsigned int GetFontSize(void);					// 获得字体的大小

/* 通过编码dwCode,调用每一个注册过的字体的GetFontBitmap函数,直到成功获取 */
int GetFontBitmap(unsigned int dwCode, PT_FontBitMap ptFontBitMap);

/* 设置字体的一些细节
 * 根据字体的名字pcFontsName,调用这个名字对应结构体的Init函数
 * 把这个字体可能用到的文件(gbk用到HZK16,ascii不用,freetype用.ttc文件)*/
int SetFontsDetail(char *pcFontsName, char *pcFontsFile, unsigned int dwFontSize);

关于字体的初始化和获取bitmap,直接阅读源码

3.debug文件夹

关于debug的网络打印部分,参看之前的
https://blog.youkuaiyun.com/qq_22655017/article/details/95459887
debug本地显示(串口stdout),直接阅读源码

4.input文件夹

宏和结构体

/* 输入事件类别 */
#define INPUT_TYPE_STDIN        0
#define INPUT_TYPE_TOUCHSCREEN  1

/* 标志一个事件,包括了xy的坐标,是按键还是触摸屏,按键的话键值是多少,触摸屏的话是按下还是松开 */
typedef struct InputEvent {
	struct timeval tTime;   /* 发生这个输入事件时的时间 */
	int iType;  			/* 类别: stdin, touchsceen */
	int iX;     			/* X/Y座标 */
	int iY;
	int iKey;   			/* 按键值 */
	int iPressure;			/* 压力值 */
}T_InputEvent, *PT_InputEvent;

/* 设备结构体,不同的设备需要开不同的子线程去阻塞(或者select)等待事件输入 */
typedef struct InputOpr {
	char *name;         		/* 输入模块的名字 */
	pthread_t tTreadID;  		/* 子线程ID */
	int (*DeviceInit)(void);  	/* 设备初始化函数 */
	int (*DeviceExit)(void); 	/* 设备退出函数 */
	int (*GetInputEvent)(PT_InputEvent ptInputEvent);  /* 获得输入数据 */
	struct InputOpr *ptNext;
}T_InputOpr, *PT_InputOpr;

input_manager.c

int RegisterInputOpr(PT_InputOpr ptInputOpr)
void ShowInputOpr(void)

/* 下面三个函数 看下面的函数详解 */
static void *InputEventThreadFunction(void *pVoid)
int AllInputDevicesInit(void)
int GetInputEvent(PT_InputEvent ptInputEvent)

int InputInit(void)
  • InputEventThreadFunction函数
/* 每个设备都需要去创建一个子线程,在子线程中运行自己特殊的等待事件输入函数
 - 获得事件后需要反馈给上一层
 - 那么就可以直接把这一层封装成一个函数,各子线程函数都来调用
 - 并且在最后数据返回时,可以直接返回给这个文件,不需要考虑其他的数据走向问题*/
static void *InputEventThreadFunction(void *pVoid)
{
	T_InputEvent tInputEvent;		//这里不能是指针,只能是结构体,不然还得分配一块空间
	
	/* 定义函数指针 
	 * 这个指针指向传进来的参数
	 * 这个函数就是各设备自己用来阻塞(或select)检测输入事件的
	 */
	int (*GetInputEvent)(PT_InputEvent ptInputEvent);
	GetInputEvent = (int (*)(PT_InputEvent))pVoid;

	while (1)
	{
		if(0 == GetInputEvent(&tInputEvent))	//阻塞或者睡眠等待输入事件
		{
			/* 获得事件后,首先上锁 */
			pthread_mutex_lock(&g_tMutex);
			/* 把事件交给这个文件的全局变量 */
			g_tInputEvent = tInputEvent;

			/*  唤醒主线程 */
			pthread_cond_signal(&g_tConVar);

			/* 释放互斥量 */
			pthread_mutex_unlock(&g_tMutex);
		}
	}
	return NULL;
}
  • AllInputDevicesInit函数
/* 所有输入设备的初始化,挨个调用每个设备的初始化函数,并为每个设备开一个子线程*/
int AllInputDevicesInit(void)
{
	PT_InputOpr ptTmp = g_ptInputOprHead;
	int iError = -1;

	while (ptTmp)
	{
		if (0 == ptTmp->DeviceInit())
		{
			/* 创建子线程,最后一项传入参数就是函数指针,每个设备自己输入事件的函数 */
			pthread_create(&ptTmp->tTreadID, NULL, InputEventThreadFunction, ptTmp->GetInputEvent);			
			iError = 0;
		}
		ptTmp = ptTmp->ptNext;
	}
	return iError;
}

  • GetInputEvent函数
/* 和上层交接的一个函数,上层调用这个函数获得输入事件
 * 调用这个函数后就进入睡眠 
 * 有子线程唤醒后把数据返回
 */
int GetInputEvent(PT_InputEvent ptInputEvent)
{
	/* 休眠 */
	pthread_mutex_lock(&g_tMutex);
	pthread_cond_wait(&g_tConVar, &g_tMutex);	

	/* 被唤醒后,返回数据 */
	*ptInputEvent = g_tInputEvent;
	pthread_mutex_unlock(&g_tMutex);
	return 0;	
}

stdin.c(本工程中虽然写入了stdin的输入方式,但是并没有使用,在获取数据时,只获取了,并没有向上反馈)
以下几个函数是对输入设备(stdin)的初始化,主要是让输入终端接收到一个字符就返回,而不是遇到回车时返回,具体讲解见
https://blog.youkuaiyun.com/qq_22655017/article/details/95331554

static int StdinDevInit(void)
static int StdinDevExit(void)
int StdinInit(void)
  • touchscreen.c

关于tslib库的使用(打开触摸屏,对触摸屏设置,取触摸屏的数据等),详见之前的博客
https://blog.youkuaiyun.com/qq_22655017/article/details/95331554

下面详解子线程调用的函数

static int TouchScreenGetInputEvent(PT_InputEvent ptInputEvent)
{
	struct ts_sample tSamp;
	int iRet;	

	while (1)
	{
		iRet = ts_read(g_tTSDev, &tSamp, 1); 		/* 打开触摸屏设备时是阻塞方式,所以这里如果无数据则休眠 */
		if (iRet == 1)
		{
			ptInputEvent->tTime     = tSamp.tv;		/* 获得数据后,把数据放到传出参数ptInputEvent中,就可以返回了 */
			ptInputEvent->iType     = INPUT_TYPE_TOUCHSCREEN;
			ptInputEvent->iX        = tSamp.x;
			ptInputEvent->iY        = tSamp.y;
			ptInputEvent->iPressure = tSamp.pressure;
			return 0;
		}
		else
		{
			return -1;
		}
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值