韦东山_数码相册程序_解析

显示之bmp数据提取

显示之文件操作

显示之界面切换(main_page)

1、显示之bmp数据提取

typedef struct PixelDatas { int iWidth; int iHeight; int iBpp; int iLineBytes; int iTotalBytes; unsigned char *aucPixelDatas;
}T_PixelDatas, *PT_PixelDatas;

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

typedef struct PicFileParser { char *name; int (*isSupport)(PT_FileMap ptFileMap); int (*GetPixelDatas)(PT_FileMap ptFileMap, PT_PixelDatas ptPixelDatas); int (*FreePixelDatas)(PT_PixelDatas ptPixelDatas);
struct PicFileParser *ptNext;
}T_PicFileParser, *PT_PicFileParser;

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

1、文件头信息

typedef struct tagBITMAPFILEHEADER { /* bmfh */ unsigned short bfType; unsigned long  bfSize; unsigned short bfReserved1; unsigned short bfReserved2; unsigned long  bfOffBits;
} BITMAPFILEHEADER;

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

2、位图信息

typedef struct tagBITMAPINFOHEADER { /* bmih */ unsigned long  biSize; unsigned long  biWidth; unsigned long  biHeight; unsigned short biPlanes; unsigned short biBitCount; unsigned long  biCompression; unsigned long  biSizeImage; unsigned long  biXPelsPerMeter; unsigned long  biYPelsPerMeter; unsigned long  biClrUsed; unsigned long  biClrImportant;
} BITMAPINFOHEADER;

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

3、RGB颜色阵列:

static int CovertOneLine(int iWidth, int iSrcBpp, int iDstBpp, unsigned char *pudSrcDatas, unsigned char *pudDstDatas)
{
unsigned int dwRed;
unsigned int dwGreen;
unsigned int dwBlue;
unsigned int dwColor;

unsigned short *pwDstDatas16bpp = (unsigned short *)pudDstDatas;
unsigned int   *pwDstDatas32bpp = (unsigned int *)pudDstDatas;

int i;
int pos = 0;

if (iSrcBpp != 24)
{ return -1;
}

if (iDstBpp == 24)
{ memcpy(pudDstDatas, pudSrcDatas, iWidth*3);
}
else
{ for (i = 0; i < iWidth; i++) { dwBlue  = pudSrcDatas[pos++]; dwGreen = pudSrcDatas[pos++]; dwRed   = pudSrcDatas[pos++]; if (iDstBpp == 32) { dwColor = (dwRed << 16) | (dwGreen << 8) | dwBlue; *pwDstDatas32bpp = dwColor; pwDstDatas32bpp++; } else if (iDstBpp == 16) { /* 565 */ dwRed   = dwRed >> 3; dwGreen = dwGreen >> 2; dwBlue  = dwBlue >> 3; dwColor = (dwRed << 11) | (dwGreen << 5) | (dwBlue); *pwDstDatas16bpp = dwColor; pwDstDatas16bpp++; } }
}
return 0;
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49

加载文件

得到图片属性,以及RGB数据。

  1. 加载头文件
  2. 加载位图信息头
  3. 行对齐
  4. 加载图片数据
  5. 绘制

static int GetPixelDatasFrmBMP(PT_FileMap ptFileMap, PT_PixelDatas ptPixelDatas)
{ BITMAPFILEHEADER *ptBITMAPFILEHEADER; BITMAPINFOHEADER *ptBITMAPINFOHEADER; unsigned char *aFileHead; int iWidth; int iHeight; int iBMPBpp; int y; unsigned char *pucSrc; unsigned char *pucDest; int iLineWidthAlign; int iLineWidthReal; aFileHead = ptFileMap->pucFileMapMem; ptBITMAPFILEHEADER = (BITMAPFILEHEADER *)aFileHead; ptBITMAPINFOHEADER = (BITMAPINFOHEADER *)(aFileHead + sizeof(BITMAPFILEHEADER)); iWidth = ptBITMAPINFOHEADER->biWidth; iHeight = ptBITMAPINFOHEADER->biHeight; iBMPBpp = ptBITMAPINFOHEADER->biBitCount; if (iBMPBpp != 24) { DBG_PRINTF("iBMPBpp = %d\n", iBMPBpp); DBG_PRINTF("sizeof(BITMAPFILEHEADER) = %d\n", sizeof(BITMAPFILEHEADER)); return -1; } ptPixelDatas->iWidth  = iWidth; ptPixelDatas->iHeight = iHeight; //ptPixelDatas->iBpp= iBpp; ptPixelDatas->iLineBytes= iWidth * ptPixelDatas->iBpp / 8;
ptPixelDatas->iTotalBytes   = ptPixelDatas->iHeight * ptPixelDatas->iLineBytes; ptPixelDatas->aucPixelDatas = malloc(ptPixelDatas->iTotalBytes); if (NULL == ptPixelDatas->aucPixelDatas) { return -1; } iLineWidthReal = iWidth * iBMPBpp / 8; iLineWidthAlign = (iLineWidthReal + 3) & ~0x3;   /* 向4取整 */ pucSrc = aFileHead + ptBITMAPFILEHEADER->bfOffBits; pucSrc = pucSrc + (iHeight - 1) * iLineWidthAlign; pucDest = ptPixelDatas->aucPixelDatas; for (y = 0; y < iHeight; y++) { //memcpy(pucDest, pucSrc, iLineWidthReal); CovertOneLine(iWidth, iBMPBpp, ptPixelDatas->iBpp, pucSrc, pucDest); pucSrc  -= iLineWidthAlign; pucDest += ptPixelDatas->iLineBytes; } return 0; }

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60

2、显示之文件操作

定义文件结构体:

typedef struct FileMap { char strFileName[256]; // int iFd; FILE * tFp; int iFileSize; unsigned char *pucFileMapMem;
}T_FileMap, *PT_FileMap;

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

typedef enum { FILETYPE_DIR = 0, FILETYPE_FILE,
}E_FileType;

  
 
  • 1
  • 2
  • 3
  • 4

typedef struct DirContent { char strName[256]; E_FileType eFileType; }T_DirContent, *PT_DirContent;

  
 
  • 1
  • 2
  • 3
  • 4

文件信息获取:

int MapFile(PT_FileMap ptFileMap)
{ int iFd;
FILE *tFp; struct stat tStat; /* 打开文件 */ tFp = fopen(ptFileMap->strFileName, "r+"); if (tFp == NULL) { DBG_PRINTF("can't open %s\n", ptFileMap->strFileName); return -1; } ptFileMap->tFp = tFp;
iFd = fileno(tFp); fstat(iFd, &tStat); ptFileMap->iFileSize = tStat.st_size; ptFileMap->pucFileMapMem = (unsigned char *)mmap(NULL , tStat.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, iFd, 0); if (ptFileMap->pucFileMapMem == (unsigned char *)-1) { DBG_PRINTF("mmap error!\n"); return -1; } return 0;
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

void UnMapFile(PT_FileMap ptFileMap)
{ munmap(ptFileMap->pucFileMapMem, ptFileMap->iFileSize); fclose(ptFileMap->tFp);
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5

文件类型判断

static int isDir(char *strFilePath, char *strFileName)
{
char strTmp[256];
struct stat tStat;

snprintf(strTmp, 256, "%s/%s", strFilePath, strFileName);
strTmp[255] = '\0';

if ((stat(strTmp, &tStat) == 0) && S_ISDIR(tStat.st_mode))
{
return 1;
}
else
{
return 0;
}
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

static int isRegFile(char *strFilePath, char *strFileName)
{
char strTmp[256];
struct stat tStat;

snprintf(strTmp, 256, "%s/%s", strFilePath, strFileName);
strTmp[255] = '\0';

if ((stat(strTmp, &tStat) == 0) && S_ISREG(tStat.st_mode))
{
return 1;
}
else
{
return 0;
}
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

把某目录下所含的顶层子目录、顶层目录下的文件都记录下来

int GetDirContents(char *strDirName, PT_DirContent **pptDirContents, int *piNumber) 
{
PT_DirContent *aptDirContents; struct dirent **aptNameList; int iNumber; int i; int j; /* 扫描目录,结果按名字排序,存在aptNameList[0],aptNameList[1],... */ iNumber = scandir(strDirName, &aptNameList, 0, alphasort); if (iNumber < 0) { DBG_PRINTF("scandir error : %s!\n", strDirName); return -1; } /* 忽略".", ".."这两个目录 */ aptDirContents = malloc(sizeof(PT_DirContent) * (iNumber - 2)); if (NULL == aptDirContents) { DBG_PRINTF("malloc error!\n"); return -1; }
*pptDirContents = aptDirContents; for (i = 0; i < iNumber - 2; i++) { aptDirContents[i] = malloc(sizeof(T_DirContent)); if (NULL == aptDirContents) { DBG_PRINTF("malloc error!\n"); return -1; } } /* 先把目录挑出来存入aptDirContents */ for (i = 0, j = 0; i < iNumber; i++) { /* 忽略".",".."这两个目录 */ if ((0 == strcmp(aptNameList[i]->d_name, ".")) || (0 == strcmp(aptNameList[i]->d_name, ".."))) continue;
/* 并不是所有的文件系统都支持d_type, 所以不能直接判断d_type */ /* if (aptNameList[i]->d_type == DT_DIR) */
if (isDir(strDirName, aptNameList[i]->d_name)) { strncpy(aptDirContents[j]->strName, aptNameList[i]->d_name, 256); aptDirContents[j]->strName[255] = '\0'; aptDirContents[j]->eFileType= FILETYPE_DIR;
free(aptNameList[i]);
aptNameList[i] = NULL; j++; } } /* 再把常规文件挑出来存入aptDirContents */ for (i = 0; i < iNumber; i++) {
if (aptNameList[i] == NULL)
continue; /* 忽略".",".."这两个目录 */ if ((0 == strcmp(aptNameList[i]->d_name, ".")) || (0 == strcmp(aptNameList[i]->d_name, ".."))) continue;
/* 并不是所有的文件系统都支持d_type, 所以不能直接判断d_type */ /* if (aptNameList[i]->d_type == DT_REG) */
if (isRegFile(strDirName, aptNameList[i]->d_name)) { strncpy(aptDirContents[j]->strName, aptNameList[i]->d_name, 256); aptDirContents[j]->strName[255] = '\0'; aptDirContents[j]->eFileType= FILETYPE_FILE;
free(aptNameList[i]);
aptNameList[i] = NULL; j++; } } /* 释放aptDirContents中未使用的项 */ for (i = j; i < iNumber - 2; i++) { free(aptDirContents[i]); } /* 释放scandir函数分配的内存 */ for (i = 0; i < iNumber; i++) {
if (aptNameList[i])
{ free(aptNameList[i]);
} } free(aptNameList); *piNumber = j; return 0;
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96

以深度优先的方式获得目录下的文件

 * 即: 先获得顶层目录下的文件, 再进入一级子目录A
 * 先获得一级子目录A下的文件, 再进入二级子目录AA, ...
 * 处理完一级子目录A后, 再进入一级子目录B
 *
 * "连播模式"下调用该函数获得要显示的文件
 * 有两种方法获得这些文件:
 * 1. 事先只需要调用一次函数,把所有文件的名字保存到某个缓冲区中
 * 2. 要使用文件时再调用函数,只保存当前要使用的文件的名字
 * 第1种方法比较简单,但是当文件很多时有可能导致内存不足.
 * 我们使用第2种方法:
 * 假设某目录(包括所有子目录)下所有的文件都给它编一个号
 * piStartNumberToRecord : 从第几个文件开始取出它们的名字
 * piCurFileNumber   : 本次函数执行时读到的第1个文件的编号
 * piFileCountHaveGet: 已经得到了多少个文件的名字
 * iFileCountTotal   : 总共要取出多少个文件的名字
 *
 */
int GetFilesIndir(char *strDirName, int *piStartNumberToRecord, int *piCurFileNumber, int *piFileCountHaveGet, int iFileCountTotal, char apstrFileNames[][256])
{
int iError;
PT_DirContent *aptDirContents;  /* 数组:存有目录下"顶层子目录","文件"的名字 */
int iDirContentsNumber; /* aptDirContents数组有多少项 */
int i;
char strSubDirName[256];

/* 为避免访问的目录互相嵌套, 设置能访问的目录深度为10 */
#define MAX_DIR_DEEPNESS 10
static int iDirDeepness = 0;

if (iDirDeepness > MAX_DIR_DEEPNESS)
{
return -1;
}

iDirDeepness++;

iError = GetDirContents(strDirName, &aptDirContents, &iDirContentsNumber);
if (iError)
{
DBG_PRINTF("GetDirContents error!\n");
iDirDeepness--;
return -1;
}

/* 先记录文件 */
for (i = 0; i < iDirContentsNumber; i++)
{
if (aptDirContents[i]->eFileType == FILETYPE_FILE)
{
if (*piCurFileNumber >= *piStartNumberToRecord)
{
snprintf(apstrFileNames[*piFileCountHaveGet], 256, "%s/%s", strDirName, aptDirContents[i]->strName);
(*piFileCountHaveGet)++;
(*piCurFileNumber)++;
(*piStartNumberToRecord)++;
if (*piFileCountHaveGet >= iFileCountTotal)
{
FreeDirContents(aptDirContents, iDirContentsNumber);
iDirDeepness--;
return 0;
}
}
else
{
(*piCurFileNumber)++;
}
}
}

/* 递归处理目录 */
for (i = 0; i < iDirContentsNumber; i++)
{
if ((aptDirContents[i]->eFileType == FILETYPE_DIR) && isRegDir(strDirName, aptDirContents[i]->strName))
{
snprintf(strSubDirName, 256, "%s/%s", strDirName, aptDirContents[i]->strName);
GetFilesIndir(strSubDirName, piStartNumberToRecord, piCurFileNumber, piFileCountHaveGet, iFileCountTotal, apstrFileNames);
if (*piFileCountHaveGet >= iFileCountTotal)
{
FreeDirContents(aptDirContents, iDirContentsNumber);
iDirDeepness--;
return 0;
}
}
}

FreeDirContents(aptDirContents, iDirContentsNumber);
iDirDeepness--;
return 0;
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89

3、显示之页面切换(main_page)

main中调用PagesInit();

int PagesInit(void)
{ int iError; iError  = MainPageInit(); iError |= SettingPageInit(); iError |= IntervalPageInit(); iError |= BrowsePageInit(); iError |= AutoPageInit(); iError |= ManualPageInit(); return iError;
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

注册

int MainPageInit(void)
{ return RegisterPageAction(&g_tMainPageAction);
}

int SettingPageInit(void)
{ return RegisterPageAction(&g_tSettingPageAction);
}

int IntervalPageInit(void)
{ return RegisterPageAction(&g_tIntervalPageAction);
}

int BrowsePageInit(void)
{ return RegisterPageAction(&g_tBrowsePageAction);
}

int AutoPageInit(void)
{ return RegisterPageAction(&g_tAutoPageAction);
}

int ManualPageInit(void)
{ return RegisterPageAction(&g_tManualPageAction);
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

链表操作

int RegisterPageAction(PT_PageAction ptPageAction)
{ PT_PageAction ptTmp; if (!g_ptPageActionHead) { g_ptPageActionHead   = ptPageAction; ptPageAction->ptNext = NULL; } else { ptTmp = g_ptPageActionHead; while (ptTmp->ptNext) { ptTmp = ptTmp->ptNext; } ptTmp->ptNext = ptPageAction; ptPageAction->ptNext = NULL; } return 0;
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

链表结构

typedef struct PageAction { char *name; void (*Run)(PT_PageParams ptParentPageParams); int (*GetInputEvent)(PT_PageLayout ptPageLayout, PT_InputEvent ptInputEvent); int (*Prepare)(void); struct PageAction *ptNext;
}T_PageAction, *PT_PageAction;

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

现在逐一分析

主界面运行

int MainPageInit(void)
{ return RegisterPageAction(&g_tMainPageAction);
}

  
 
  • 1
  • 2
  • 3
  • 4

static T_PageAction g_tMainPageAction = { .name  = "main", .Run   = MainPageRun, .GetInputEvent = MainPageGetInputEvent, //.Prepare   = MainPagePrepare;
};

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

分析Run = MainPageRun 函数指针:

  1. 显示页面
  2. 创建Prepare线程
  3. 调用GetInputEvent获得输入事件,进而处理

注释:

  1. 将屏幕显示在主界面后
  2. 按下按钮 (tInputEvent.iPressure == 0)->g_tInputEvent.iPressure
  3. iIndex != -1;
  4. iIndexPressed = iIndex
  5. PressButton(&g_atMainPageIconsLayout[iIndexPressed]);//位图取反

  6. 松开按钮 (tInputEvent.iPressure != 0)->g_tInputEvent.iPressure

  7. PressButton(&g_atMainPageIconsLayout[iIndexPressed]);//位图取反
  8. 按下和松开按键一样 则进入选择:switch

static void MainPageRun(PT_PageParams ptParentPageParams)
{
int iIndex;
T_InputEvent tInputEvent;
int bPressed = 0;
int iIndexPressed = -1;
T_PageParams tPageParams;

tPageParams.iPageID = ID("main");

/* 1. 显示页面 */
ShowMainPage(&g_tMainPageLayout);

/* 2. 创建Prepare线程 */

/* 3. 调用GetInputEvent获得输入事件,进而处理 */
while (1)
{ iIndex = MainPageGetInputEvent(&g_tMainPageLayout, &tInputEvent); if (tInputEvent.iPressure == 0) { /* 如果是松开 */ if (bPressed) { /* 曾经有按钮被按下 */ ReleaseButton(&g_atMainPageIconsLayout[iIndexPressed]); bPressed = 0; if (iIndexPressed == iIndex) /* 按下和松开都是同一个按钮 */ { switch (iIndexPressed) { case 0: /* 浏览按钮 */ { /* tPageParams.strCurPictureFile[0]为'\0'时, 使用设置页面里选定的目录来显示 */ tPageParams.strCurPictureFile[0] = '\0'; Page("manual")->Run(&tPageParams); /* 从设置页面返回后显示当首的主页面 */ ShowMainPage(&g_tMainPageLayout); break; } case 1: /* 连播按钮 */ { Page("auto")->Run(&tPageParams); /* 从设置页面返回后显示当首的主页面 */ ShowMainPage(&g_tMainPageLayout); break; } case 2: /* 设置按钮 */ { Page("setting")->Run(&tPageParams); /* 从设置页面返回后显示当首的主页面 */ ShowMainPage(&g_tMainPageLayout); break; } default: { break; } } } iIndexPressed = -1; } } else { /* 按下状态 */ if (iIndex != -1) { if (!bPressed) { /* 未曾按下按钮 */ bPressed = 1; iIndexPressed = iIndex; PressButton(&g_atMainPageIconsLayout[iIndexPressed]); } } } }
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87

主菜单:

  1. manual 浏览
  2. auto 连播
  3. setting 设置

1、浏览模式

注册

int ManualPageInit(void)
{ return RegisterPageAction(&g_tManualPageAction);
}

  
 
  • 1
  • 2
  • 3
  • 4

static T_PageAction g_tManualPageAction = { .name  = "manual", .Run   = ManualPageRun,
};

  
 
  • 1
  • 2
  • 3
  • 4

/* manual页面的Run参数含义: 
 * 如果它的父页面是主页面   - 显示browse页面, 
 * 否则 - 显示图片
 */
static void ManualPageRun(PT_PageParams ptParentPageParams)
{ T_InputEvent tInputEvent; T_InputEvent tPreInputEvent; int bButtonPressed = 0; int bPicSlipping = 0; int iIndexPressed = -1;
int iIndex;
T_PageParams tPageParams;
int iError;
char strDirName[256];
char strFileName[256];
char strFullPathName[256];
PT_DirContent *aptDirContents;
int iDirContentsNumber;
int iPicFileIndex;
char *pcTmp;
PT_VideoMem ptDevVideoMem;
int iZoomedWidth;
int iZoomedHeight;
PT_PixelDatas ptZoomedPicPixelDatas = &g_tZoomedPicPixelDatas;

/* 这两句只是避免编译警告 */
tPreInputEvent.iX = 0;
tPreInputEvent.iY = 0;

tPageParams.iPageID = ID("manual");

if (ptParentPageParams->iPageID == ID("main"))
{
/* 如果它的父页面是主页面 - 显示browse页面*/
Page("browse")->Run(ptParentPageParams);
}
else
{
ptDevVideoMem = GetDevVideoMem();
strcpy(strFullPathName, ptParentPageParams->strCurPictureFile);

/* 显示菜单和图片文件 */
ShowManualPage(&g_tManualPageMenuIconsLayout, strFullPathName);

/* 取出目录名 */
strcpy(strDirName, ptParentPageParams->strCurPictureFile);
pcTmp = strrchr(strDirName, '/');
*pcTmp = '\0';

/* 取出文件名 */
strcpy(strFileName, pcTmp+1);

/* 获得当前目录下所有目录和文件的名字 */
iError = GetDirContents(strDirName, &aptDirContents, &iDirContentsNumber);

/* 确定当前显示的是哪一个文件 */
for (iPicFileIndex = 0; iPicFileIndex < iDirContentsNumber; iPicFileIndex++)
{
if (0 == strcmp(strFileName, aptDirContents[iPicFileIndex]->strName))
{
break;
}
}

while (1)
{
/* 先确定是否触摸了菜单图标 */
iIndex = ManualPageGetInputEvent(&g_tManualPageMenuIconsLayout, &tInputEvent); /* 如果是松开 */
if (tInputEvent.iPressure == 0)
{ bPicSlipping = 0;

if (bButtonPressed)
{
/* 曾经有按钮被按下 */
ReleaseButton(&g_atManualMenuIconsLayout[iIndexPressed]);
bButtonPressed = 0;

if (iIndexPressed == iIndex) /* 按下和松开都是同一个按钮 */
{
switch (iIndexPressed)
{
case 0: /* 返回按钮 */
{
return;
break;
}
case 1: /* 缩小按钮 */
{
/* 获得缩小后的数据 */
iZoomedWidth  = (float)g_tZoomedPicPixelDatas.iWidth * ZOOM_RATIO;
iZoomedHeight = (float)g_tZoomedPicPixelDatas.iHeight * ZOOM_RATIO;
ptZoomedPicPixelDatas = GetZoomedPicPixelDatas(&g_tOriginPicPixelDatas, iZoomedWidth, iZoomedHeight);

/* 重新计算中心点 */
g_iXofZoomedPicShowInCenter = (float)g_iXofZoomedPicShowInCenter * ZOOM_RATIO;
g_iYofZoomedPicShowInCenter = (float)g_iYofZoomedPicShowInCenter * ZOOM_RATIO;

/* 显示新数据 */
ShowZoomedPictureInLayout(ptZoomedPicPixelDatas, ptDevVideoMem);

break;
}
case 2: /* 放大按钮 */
{
/* 获得放大后的数据 */
iZoomedWidth  = (float)g_tZoomedPicPixelDatas.iWidth / ZOOM_RATIO;
iZoomedHeight = (float)g_tZoomedPicPixelDatas.iHeight / ZOOM_RATIO;
ptZoomedPicPixelDatas = GetZoomedPicPixelDatas(&g_tOriginPicPixelDatas, iZoomedWidth, iZoomedHeight);

/* 重新计算中心点 */
g_iXofZoomedPicShowInCenter = (float)g_iXofZoomedPicShowInCenter / ZOOM_RATIO;
g_iYofZoomedPicShowInCenter = (float)g_iYofZoomedPicShowInCenter / ZOOM_RATIO;

/* 显示新数据 */
ShowZoomedPictureInLayout(ptZoomedPicPixelDatas, ptDevVideoMem);

break;
}
case 3: /* "上一张"按钮 */
{
while (iPicFileIndex > 0)
{
iPicFileIndex--;
snprintf(strFullPathName, 256, "%s/%s", strDirName, aptDirContents[iPicFileIndex]->strName);
strFullPathName[255] = '\0';

if (isPictureFileSupported(strFullPathName))
{
ShowPictureInManualPage(ptDevVideoMem, strFullPathName);
break;
}
}

break;
}
case 4: /* "下一张"按钮 */
{
while (iPicFileIndex < iDirContentsNumber - 1)
{
iPicFileIndex++;
snprintf(strFullPathName, 256, "%s/%s", strDirName, aptDirContents[iPicFileIndex]->strName);
strFullPathName[255] = '\0';

if (isPictureFileSupported(strFullPathName))
{
ShowPictureInManualPage(ptDevVideoMem, strFullPathName);
break;
}
}
break;
}
case 5: /* "连播"按钮 */
{
/* Manual页面的触发有两个方法: 在主页面按"浏览模式"进入"浏览页面"->"选中某个文件", 在"连播页面"里点击正在显示的图片 
 * 如果是后者, 直接return就可以了:因为return后是返回到"连播页面"的, 它会继续"连播"
 */
if (ptParentPageParams->iPageID == ID("browse"))  /* 触发自"浏览页面" */
{
strcpy(tPageParams.strCurPictureFile, strFullPathName);
Page("auto")->Run(&tPageParams);  /* auto页面返回前,会把它正在显示的文件存在tPageParams.strCurPictureFile */
ShowManualPage(&g_tManualPageMenuIconsLayout, tPageParams.strCurPictureFile);
}
else /* 当前manual页面的父页面是auto页面, 直接返回即可 */
{
return;
}
break;
}
default:
{
break;
}
}
}

iIndexPressed = -1;
}
}
else /* 按下状态 */
{
/* 点击的是菜单按钮 */
if (iIndex != -1)
{
if (!bButtonPressed)
{
/* 未曾按下按钮 */
bButtonPressed = 1;
iIndexPressed = iIndex;
PressButton(&g_atManualMenuIconsLayout[iIndexPressed]);
}
} else  /* 点击的是图片显示区域, 滑动图片 */ { /* 如果没有按钮被按下 */ if (!bButtonPressed && !bPicSlipping) { bPicSlipping = 1;
tPreInputEvent = tInputEvent; } if (bPicSlipping) {
/* 如果触点滑动距离大于规定值, 则挪动图片 */
if (DistanceBetweenTwoPoint(&tInputEvent, &tPreInputEvent) > SLIP_MIN_DISTANCE)
{
/* 重新计算中心点 */
g_iXofZoomedPicShowInCenter -= (tInputEvent.iX - tPreInputEvent.iX);
g_iYofZoomedPicShowInCenter -= (tInputEvent.iY - tPreInputEvent.iY);

/* 显示新数据 */
ShowZoomedPictureInLayout(ptZoomedPicPixelDatas, ptDevVideoMem);

/* 记录滑动点 */
tPreInputEvent = tInputEvent;
} } }
} }
}
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225

连播

  • /* 以深度优先的方式获得目录下的文件
    • 即: 先获得顶层目录下的文件, 再进入一级子目录A
    • 先获得一级子目录A下的文件, 再进入二级子目录AA, …
    • 处理完一级子目录A后, 再进入一级子目录B
  • *
    • ”连播模式”下调用该函数获得要显示的文件
    • 有两种方法获得这些文件:
      1. 事先只需要调用一次函数,把所有文件的名字保存到某个缓冲区中
      1. 要使用文件时再调用函数,只保存当前要使用的文件的名字
    • 第1种方法比较简单,但是当文件很多时有可能导致内存不足.
    • 我们使用第2种方法:
    • 假设某目录(包括所有子目录)下所有的文件都给它编一个号
    • g_iStartNumberToRecord : 从第几个文件开始取出它们的名字
    • g_iCurFileNumber : 本次函数执行时读到的第1个文件的编号
    • g_iFileCountHaveGet : 已经得到了多少个文件的名字
    • g_iFileCountTotal : 每一次总共要取出多少个文件的名字
    • g_iNextProcessFileIndex: 在g_apstrFileNames数组中即将要显示在LCD上的文件
  • *
  • */

static T_PageAction g_tAutoPageAction = { .name  = "auto", .Run   = AutoPageRun,
};

  
 
  • 1
  • 2
  • 3
  • 4

static void AutoPageRun(PT_PageParams ptParentPageParams)
{ T_InputEvent tInputEvent; int iRet;
char *pcTmp;

g_bAutoPlayThreadShouldExit = 0;

/* 获得配置值: 显示哪一个目录, 显示图片的间隔 */
GetPageCfg(&g_tPageCfg);

/* 如果ptParentPageParams.strCurPictureFile[0] != '\0'
 * 自动播放这个目录下的图片: ptParentPageParams.strCurPictureFile
 */
if (ptParentPageParams->strCurPictureFile[0] != '\0')
{
strcpy(g_tPageCfg.strSeletedDir, ptParentPageParams->strCurPictureFile);
pcTmp = strrchr(g_tPageCfg.strSeletedDir, '/');
*pcTmp = '\0';
}

/* 1. 启动一个线程来连续显示图片 */
pthread_create(&g_tAutoPlayThreadID, NULL, AutoPlayThreadFunction, NULL);

/* 2. 当前线程等待触摸屏输入, 先做简单点: 如果点击了触摸屏, 让线程退出 */
while (1)
{
iRet = GetInputEvent(&tInputEvent);
if (0 == iRet)
{
pthread_mutex_lock(&g_tAutoPlayThreadMutex);
g_bAutoPlayThreadShouldExit = 1;   /* AutoPlayThreadFunction线程检测到这个变量为1后会退出 */
pthread_mutex_unlock(&g_tAutoPlayThreadMutex);
pthread_join(g_tAutoPlayThreadID, NULL);  /* 等待子线程退出 */
return;
}
}

}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39


设置


步骤1:显示界面 :

首先看出入参数结构

ShowMainPage(&g_tMainPageLayout);

static T_PageLayout g_tMainPageLayout = {
.iMaxTotalBytes = 0,
.atLayout = g_atMainPageIconsLayout,
};

  
 
  • 1
  • 2
  • 3
  • 4

g_atMainPageIconsLayout结构定义如下:

static T_Layout g_atMainPageIconsLayout[] = { {0, 0, 0, 0, "browse_mode.bmp"}, {0, 0, 0, 0, "continue_mod.bmp"}, {0, 0, 0, 0, "setting.bmp"}, {0, 0, 0, 0, NULL},
};

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

定义结构体如下:

typedef struct PageLayout { int iTopLeftX;/* 这个区域的左上角、右下角坐标 */ int iTopLeftY; int iBotRightX; int iBotRightY; int iBpp; int iMaxTotalBytes; PT_Layout atLayout;  /* 这个区域分成好几个小区域 */
}T_PageLayout, *PT_PageLayout;

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

PT_Layout 结构:

typedef struct Layout { int iTopLeftX; int iTopLeftY; int iBotRightX; int iBotRightY; char *strIconName;
}T_Layout, *PT_Layout;

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7



看一下showMainpage函数:

  1. 获得显存
  2. 描画数据
  3. 刷到设备上去
  4. 解放显存

static void ShowMainPage(PT_PageLayout ptPageLayout)
{
PT_VideoMem ptVideoMem;
int iError;

PT_Layout atLayout = ptPageLayout->atLayout;

/* 1. 获得显存 */
ptVideoMem = GetVideoMem(ID("main"), 1);
if (ptVideoMem == NULL)
{ DBG_PRINTF("can't get video mem for main page!\n"); return;
}

/* 2. 描画数据 */

/* 如果还没有计算过各图标的坐标 */
if (atLayout[0].iTopLeftX == 0)
{ CalcMainPageLayout(ptPageLayout);
}

iError = GeneratePage(ptPageLayout, ptVideoMem); /* 3. 刷到设备上去 */
FlushVideoMemToDev(ptVideoMem);

/* 4. 解放显存 */
PutVideoMem(ptVideoMem);
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

  1. 获得显存

  1. 描画数据

  1. 刷到设备上去

  1. 解放显存

待添加:

步骤三:调用GetInputEvent获得输入事件,进而处理

iIndex = MainPageGetInputEvent(&g_tMainPageLayout, &tInputEvent);

static int MainPageGetInputEvent(PT_PageLayout ptPageLayout, PT_InputEvent ptInputEvent)
{ return GenericGetInputEvent(ptPageLayout, ptInputEvent);
}

  
 
  • 1
  • 2
  • 3
  • 4

传入参数分析:

typedef struct PageLayout { int iTopLeftX;/* 这个区域的左上角、右下角坐标 */ int iTopLeftY; int iBotRightX; int iBotRightY; int iBpp; int iMaxTotalBytes; PT_Layout atLayout;  /* 这个区域分成好几个小区域 */
}T_PageLayout, *PT_PageLayout;


typedef struct InputEvent { struct timeval tTime; int iType;  /* stdin, touchsceen */ int iX; int iY; int iKey; int iPressure;
}T_InputEvent, *PT_InputEvent;

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

函数:

int GenericGetInputEvent(PT_PageLayout ptPageLayout, PT_InputEvent ptInputEvent)
{ T_InputEvent tInputEvent; int iRet; int i = 0; PT_Layout atLayout = ptPageLayout->atLayout; /* 获得原始的触摸屏数据 * 它是调用input_manager.c的函数,此函数会让当前线否休眠 * 当触摸屏线程获得数据后,会把它唤醒 */ iRet = GetInputEvent(&tInputEvent); if (iRet) { return -1; } if (tInputEvent.iType != INPUT_TYPE_TOUCHSCREEN) { return -1; } *ptInputEvent = tInputEvent; /* 处理数据 */ /* 确定触点位于哪一个按钮上 */ while (atLayout[i].strIconName) { if ((tInputEvent.iX >= atLayout[i].iTopLeftX) && (tInputEvent.iX <= atLayout[i].iBotRightX) && \ (tInputEvent.iY >= atLayout[i].iTopLeftY) && (tInputEvent.iY <= atLayout[i].iBotRightY)) { /* 找到了被点中的按钮 */ return i; } else { i++; } } /* 触点没有落在按钮上 */ return -1;
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

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; }

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

问题:g_tinputevent这个全局变量在哪里改变的。

触摸初始化:

InputInit();
AllInputDevicesInit();

  
 
  • 1
  • 2

InputInit();

int InputInit(void)
{ int iError = 0; // iError = StdinInit(); iError |= TouchScreenInit(); return iError;
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

int TouchScreenInit(void)
{ return RegisterInputOpr(&g_tTouchScreenOpr);
}

  
 
  • 1
  • 2
  • 3
  • 4

static T_InputOpr g_tTouchScreenOpr = { .name  = "touchscreen", .DeviceInit= TouchScreenDevInit, .DeviceExit= TouchScreenDevExit, .GetInputEvent = TouchScreenGetInputEvent,
};

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

TouchScreenDevInit

/* 注意: 由于要用到LCD的分辨率, 此函数要在SelectAndInitDisplay之后调用 */
static int TouchScreenDevInit(void)
{ char *pcTSName = NULL; int iBpp; if ((pcTSName = getenv("TSLIB_TSDEVICE")) != NULL ) { g_tTSDev = ts_open(pcTSName, 0);  /* 以阻塞方式打开 */ } else { g_tTSDev = ts_open("/dev/event0", 1); } if (!g_tTSDev) { DBG_PRINTF(APP_ERR"ts_open error!\n"); return -1; } if (ts_config(g_tTSDev)) { DBG_PRINTF("ts_config error!\n"); return -1; } if (GetDispResolution(&giXres, &giYres, &iBpp)) { return -1; } return 0;
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

TouchScreenGetInputEvent

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->iType = INPUT_TYPE_TOUCHSCREEN; ptInputEvent->iX= tSamp.x; ptInputEvent->iY= tSamp.y; ptInputEvent->iPressure = tSamp.pressure; return 0; } else { return -1; } } return 0;
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

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;
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

InputEventThreadFunction线程

下面这个函数就是获得g_tInputEvent的数值

static void *InputEventThreadFunction(void *pVoid)
{ T_InputEvent tInputEvent; /* 定义函数指针 */ int (*GetInputEvent)(PT_InputEvent ptInputEvent); GetInputEvent = (int (*)(PT_InputEvent))pVoid; while (1) { if(0 == GetInputEvent(&tInputEvent)) { /* 唤醒主线程, 把tInputEvent的值赋给一个全局变量 */ /* 访问临界资源前,先获得互斥量 */ pthread_mutex_lock(&g_tMutex); g_tInputEvent = tInputEvent; /*  唤醒主线程 */ pthread_cond_signal(&g_tConVar); /* 释放互斥量 */ pthread_mutex_unlock(&g_tMutex); } } return NULL;
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

待完善

文章来源: xuesong.blog.csdn.net,作者:内核笔记,版权归原作者所有,如需转载,请联系作者。

原文链接:xuesong.blog.csdn.net/article/details/78242707

(完)