linux应用程序_1_文本浏览器_8_输入设备_2_轮询机制

本文介绍了一款Linux下的文本阅读器如何集成标准输入和触摸屏作为输入设备,包括初始化、事件处理和退出流程。文章详细展示了通过修改源代码实现输入设备功能的方法,以及如何在触摸屏上通过位置判断翻页方向。

linux应用程序_1_文本浏览器_8_输入设备_2_轮询机制

 

 

这里的两种输入设备分别是指标准输入(非阻塞方式)、触摸屏输入,测试代码可以修改前面的draw.c、main.c得到,文末给出相关的draw和main,Makefile也需要作出相应修改

1、增加input目录的Makefile

2、修改顶层Makefile:

编译选项:增加tslib头文件所在目录

链接选项:增加tslib库所在目录

 

总的来说,具体输入设备所在文件需要完成两项工作

1、设置结构体

2、完善具体操作,向上对接input_manager.c

 

对触摸屏(ts.c):

初始化:

打开设备

配置参数

获取显示设备参数

static int TsInputInit(void)
{
	char *pcTsdevice=NULL;

	if(! (pcTsdevice = getenv("TSLIB_TSDEVICE"))) 
	{			
		DBG_PRINT("Error at %s ,%d", __FILE__, __LINE__);
		return -1;
	}
	g_ptTs = ts_open(pcTsdevice,1);
	

	if(!g_ptTs)
	{
		DBG_PRINT("Error at %s ,%d", __FILE__, __LINE__);
		return -1;
	}
	
	if (ts_config(g_ptTs)) 
	{
		DBG_PRINT("Error at %s ,%d", __FILE__, __LINE__);
		return -1;
	}

	
	if(GetSeletedDispRes(&g_iXres, &g_iYres))
	{
		DBG_PRINT("Error at %s ,%d", __FILE__, __LINE__);
		return -1;
	}


	return 0;
}

获取事件:

采用轮询方式读取触摸屏

事件发生时,过500ms才处理(避免一次按下翻页多次)

static int TsInputGetEvent(PT_InputEventOpr ptInputEventOpr)
{
	struct ts_sample tSamp;
	int iRet;

	static struct timeval tPreTime;


	iRet = ts_read(g_ptTs, &tSamp, 1);
	
	if (iRet < 0) 
		return -1;


	iRet = IsOutOf500ms(&tPreTime, &tSamp.tv);
	if(!iRet)
		return -1;

	tPreTime.tv_sec  = tSamp.tv.tv_sec;
	tPreTime.tv_usec = tSamp.tv.tv_usec;	
	ptInputEventOpr->iType = INPUT_TYPE_TS;
	
	if(tSamp.x < (g_iXres / 3))
		ptInputEventOpr->iVal  = INPUT_VAL_PRE;
	else if(tSamp.x > (g_iXres * 2 / 3))
		ptInputEventOpr->iVal  = INPUT_VAL_NEXT;
	else 
		ptInputEventOpr->iVal  = INPUT_VAL_EXIT;

	return 0;
}

 

标准输入(stdin.c):

初始化:

1、获取终端参数

2、修改终端参数

static int StdinInputInit(void)
{
    struct termios tTtystate;
 
    //get the terminal state
    tcgetattr(STDIN_FILENO, &tTtystate);
 
 
    //turn off canonical mode
    tTtystate.c_lflag &= ~ICANON;
    //minimum of number input read.
    tTtystate.c_cc[VMIN] = 1;
   

    
    //set the terminal attributes.
    tcsetattr(STDIN_FILENO, TCSANOW, &tTtystate);

	return 0;
}

 

退出:

与初始化类似,标志不同

static int StdinInputExit(void)
{
    struct termios tTtystate;
 
    //get the terminal state
    tcgetattr(STDIN_FILENO, &tTtystate);

    //turn on canonical mode
    tTtystate.c_lflag |= ICANON;
	
    //set the terminal attributes.
    tcsetattr(STDIN_FILENO, TCSANOW, &tTtystate);

	return 0;
}

获取事件:

1、清空结构体

2、添加文件描述符

3、select(同poll)

4、有数据则处理,没有则返回

static int StdinInputGetEvent(PT_InputEventOpr ptInputEventOpr)
{
    char cOneChar;
    struct timeval tTv;
    fd_set plFds;
	
    tTv.tv_sec = 0;
    tTv.tv_usec = 0;

    FD_ZERO(&plFds);
	
    FD_SET(STDIN_FILENO, &plFds); //STDIN_FILENO is 0
    
    select(STDIN_FILENO+1, &plFds, NULL, NULL, &tTv);

	if(!FD_ISSET(STDIN_FILENO, &plFds))
	{
		return -1;
	}
	cOneChar = fgetc(stdin);

	
	switch(cOneChar)
	{
		case 'p':
		{
			ptInputEventOpr->iVal  = INPUT_VAL_PRE;
			break;
		}
		case 'n':
		{
			ptInputEventOpr->iVal  = INPUT_VAL_NEXT;
			break;
		}
		case 'q':
		{
			ptInputEventOpr->iVal  = INPUT_VAL_EXIT;
			break;
		}
		default:
			ptInputEventOpr->iVal  = INPUT_VAL_UNKNOWN;
	}
	
	return 0;
}

 

 

附代码:

stdin.c

#include <input_manager.h>
#include <config.h>
#include <stdio.h>
#include <termios.h>
#include <unistd.h>

static int StdinInputInit(void);
static int StdinInputExit(void);
static int StdinInputGetEvent(PT_InputEventOpr ptInputEventOpr);

static T_InputOpr g_tStdinInputOpr = {
	.pcName = "stdin",
	.InputInit = StdinInputInit,
	.InputExit = StdinInputExit,
	.InputGetEvent = StdinInputGetEvent,
};



static int StdinInputInit(void)
{
    struct termios tTtystate;
 
    //get the terminal state
    tcgetattr(STDIN_FILENO, &tTtystate);
 
 
    //turn off canonical mode
    tTtystate.c_lflag &= ~ICANON;
    //minimum of number input read.
    tTtystate.c_cc[VMIN] = 1;
   

    
    //set the terminal attributes.
    tcsetattr(STDIN_FILENO, TCSANOW, &tTtystate);

	return 0;
}

static int StdinInputExit(void)
{
    struct termios tTtystate;
 
    //get the terminal state
    tcgetattr(STDIN_FILENO, &tTtystate);

    //turn on canonical mode
    tTtystate.c_lflag |= ICANON;
	
    //set the terminal attributes.
    tcsetattr(STDIN_FILENO, TCSANOW, &tTtystate);

	return 0;
}

static int StdinInputGetEvent(PT_InputEventOpr ptInputEventOpr)
{
	char cOneChar;
    struct timeval tTv;
	fd_set plFds;
	
    tTv.tv_sec = 0;
    tTv.tv_usec = 0;

    FD_ZERO(&plFds);
	
    FD_SET(STDIN_FILENO, &plFds); //STDIN_FILENO is 0
    
    select(STDIN_FILENO+1, &plFds, NULL, NULL, &tTv);

	if(!FD_ISSET(STDIN_FILENO, &plFds))
	{
		return -1;
	}
	cOneChar = fgetc(stdin);

	
	switch(cOneChar)
	{
		case 'p':
		{
			ptInputEventOpr->iVal  = INPUT_VAL_PRE;
			break;
		}
		case 'n':
		{
			ptInputEventOpr->iVal  = INPUT_VAL_NEXT;
			break;
		}
		case 'q':
		{
			ptInputEventOpr->iVal  = INPUT_VAL_EXIT;
			break;
		}
		default:
			ptInputEventOpr->iVal  = INPUT_VAL_UNKNOWN;
	}
	
	return 0;
}



int StdinInit(void)
{
	return RegisterInputOpr(&g_tStdinInputOpr);
}

ts.c

#include <config.h>
#include <input_manager.h>


#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/time.h>

#include <tslib.h>

#include <draw.h>


static int TsInputInit(void);
static int TsInputExit(void);
static int TsInputGetEvent(PT_InputEventOpr ptInputEventOpr);


static T_InputOpr g_tTsInputOpr = {
	.pcName        = "ts",
	.InputInit     = TsInputInit,
	.InputExit     = TsInputExit,
	.InputGetEvent = TsInputGetEvent,
};

static struct tsdev *g_ptTs;
static int g_iXres, g_iYres;



static int TsInputInit(void)
{
	char *pcTsdevice=NULL;

	if(! (pcTsdevice = getenv("TSLIB_TSDEVICE"))) 
	{			
		DBG_PRINT("Error at %s ,%d", __FILE__, __LINE__);
		return -1;
	}
	g_ptTs = ts_open(pcTsdevice,1);
	

	if(!g_ptTs)
	{
		DBG_PRINT("Error at %s ,%d", __FILE__, __LINE__);
		return -1;
	}
	
	if (ts_config(g_ptTs)) 
	{
		DBG_PRINT("Error at %s ,%d", __FILE__, __LINE__);
		return -1;
	}

	
	if(GetSeletedDispRes(&g_iXres, &g_iYres))
	{
		DBG_PRINT("Error at %s ,%d", __FILE__, __LINE__);
		return -1;
	}


	return 0;
}

static int TsInputExit(void)
{

	return 0;
}

static int IsOutOf500ms(struct timeval *ptPreTime, struct timeval *ptNowTime)
{
	int iPreTime, iNowTime;

	iPreTime = ptPreTime->tv_sec * 1000 + ptPreTime->tv_usec / 1000;
	iNowTime = ptNowTime->tv_sec * 1000 + ptNowTime->tv_usec / 1000;

	if((iNowTime - iPreTime) < 500)	
		return 0;		
	
	return 1;	
}

static int TsInputGetEvent(PT_InputEventOpr ptInputEventOpr)
{
	struct ts_sample tSamp;
	int iRet;

	static struct timeval tPreTime;


	iRet = ts_read(g_ptTs, &tSamp, 1);
	
	if (iRet < 0) 
		return -1;


	iRet = IsOutOf500ms(&tPreTime, &tSamp.tv);
	if(!iRet)
		return -1;

	tPreTime.tv_sec  = tSamp.tv.tv_sec;
	tPreTime.tv_usec = tSamp.tv.tv_usec;	
	ptInputEventOpr->iType = INPUT_TYPE_TS;
	
	if(tSamp.x < (g_iXres / 3))
		ptInputEventOpr->iVal  = INPUT_VAL_PRE;
	else if(tSamp.x > (g_iXres * 2 / 3))
		ptInputEventOpr->iVal  = INPUT_VAL_NEXT;
	else 
		ptInputEventOpr->iVal  = INPUT_VAL_EXIT;

	return 0;
}


int TsInit(void)
{
	return RegisterInputOpr(&g_tTsInputOpr);
}


 

draw.c

#include <config.h>
//#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/mman.h>
#include <encoding_manager.h>
#include <fonts_manager.h>
#include <disp_manager.h>
#include <fcntl.h>
#include <string.h>
#include <draw.h>
#include <input_manager.h>

typedef struct PageDesc{
	int iPage;
	
	unsigned char *pucCurPosAtFile;
	
	struct PageDesc *ptPrePage;	
	struct PageDesc *ptNextPage;		
}T_PageDesc, *PT_PageDesc;

static PT_PageDesc g_ptPageDesc;
static unsigned char *g_pucNextPosAtFile;


static int g_iFd;
static unsigned char *g_pucFileStart;
static unsigned char *g_pucFileEnd;
static PT_EncodingOpr g_ptEncodingOpr;
static PT_DispOpr g_ptDispOpr;
static int g_iFontSize;



int OpenTextFile(char *pcFileName)
{
	struct stat tStat;

	g_iFd = open(pcFileName, O_RDONLY);
	if(g_iFd < 0)
	{
		DBG_PRINT("Error at %s,%d\r\n", __FILE__, __LINE__);
		return -1;
	}

	fstat(g_iFd, &tStat);
	g_pucFileStart = mmap(NULL, tStat.st_size, PROT_READ, MAP_SHARED, g_iFd, 0);
	if(g_pucFileStart == (unsigned char *)-1)
	{
		DBG_PRINT("Error at %s,%d\r\n", __FILE__, __LINE__);
		return -2;
	}
	g_pucFileEnd = g_pucFileStart + tStat.st_size;

	g_ptEncodingOpr = SelectEncodingOpr(g_pucFileStart);
	if(!g_ptEncodingOpr)
	{
		DBG_PRINT("Error at %s,%d\r\n", __FILE__, __LINE__);
		return -3;
	}
	
	return 0;

}

int SetFontsDetail(char *pcHzkFile, char *pcFreetypeFile, int iFontSize)
{
	PT_FontOpr ptFontOprTmp;
	PT_FontOpr ptFontOpr = g_ptEncodingOpr->ptFontOprSupportHead;
	int iError = 0, iRet = 1;

	g_iFontSize = iFontSize;

	DBG_PRINT("%s support\r\n",g_ptEncodingOpr->pcName);
	while(ptFontOpr)
	{
		if(strcmp(ptFontOpr->pcName, "ascii") == 0)
		{
			iError = ptFontOpr->FontInit(NULL, iFontSize);
			if(iError)
				DBG_PRINT("%s can't support %s\r\n", g_ptEncodingOpr->pcName, "ascii");
		}
		else if(strcmp(ptFontOpr->pcName, "gbk") == 0)
		{
			iError = ptFontOpr->FontInit(pcHzkFile, iFontSize);
			if(iError)
				DBG_PRINT("%s can't support %s\r\n", g_ptEncodingOpr->pcName, "gbk");
		}
		else
		{
			iError = ptFontOpr->FontInit(pcFreetypeFile, iFontSize);
			if(iError)
				DBG_PRINT("%s can't support %s\r\n", g_ptEncodingOpr->pcName, "freetype");
		}				
		ptFontOprTmp = ptFontOpr->ptNext;

		if(!iError)
		{
			iRet = 0;
		}
		else
		{
			DBG_PRINT("Need to Del at SetFontsDetail : %s\r\n",ptFontOpr->pcName);		
			DelFontOprFrmEncoding(g_ptEncodingOpr, ptFontOpr);
		}		
		ptFontOpr = ptFontOprTmp;
	}	

	return iRet;
	
}

int SelectAndInitDisplay(char *pcName)
{
	int iError;

	g_ptDispOpr = GetDispOpr(pcName);

	if(!g_ptDispOpr)
	{
		DBG_PRINT("Error at %s,%d\r\n", __FILE__, __LINE__);
		return -1;
	}

	iError = g_ptDispOpr->DeviceInit();
	if(iError)
	{
		DBG_PRINT("Error at %s,%d\r\n", __FILE__, __LINE__);
		return -2;
	}	

	return 0;
}


int GetSeletedDispRes(int *piXres, int *piYres)
{
	if(!g_ptDispOpr)
		return -1;

	*piXres = g_ptDispOpr->iXres;
	*piYres = g_ptDispOpr->iYres;
	
	return 0;
}


static int IncY(int iY)
{
	if(iY + g_iFontSize >= g_ptDispOpr->iYres)
		return 0;
	
	return (iY + g_iFontSize);
}

static int RelocateFontPos(PT_BitMap ptBitMap)
{
	int iY;
	int iDltX, iDltY;

	
	if(ptBitMap->iYMax > g_ptDispOpr->iYres)	
		return -1;
	
	if(ptBitMap->iXMax > g_ptDispOpr->iXres)
	{
		iY = IncY(ptBitMap->iCurOriginY);
		if(!iY)
		{
			return -1;
		}

		iDltX = 0 - ptBitMap->iCurOriginX;
		iDltY = iY - ptBitMap->iCurOriginY;

		ptBitMap->iCurOriginX += iDltX;
		ptBitMap->iCurOriginY += iDltY;
		
		ptBitMap->iNextOriginX += iDltX;
		ptBitMap->iNextOriginY += iDltY;

		ptBitMap->iXLeft	   += iDltX;
		ptBitMap->iYTop 	   += iDltY;

		ptBitMap->iXMax	 	   += iDltX;
		ptBitMap->iYMax 	   += iDltY;

	}

	return 0;
}

static int ReallyShowOneCode(PT_BitMap  ptBitMap)
{
	int iX, iY;
	int iBit,iCnt;
	unsigned char cVal = 7;

	if(ptBitMap->iBpp == 1)
	{
		for(iY = ptBitMap->iYTop;iY < ptBitMap->iYMax;iY++)
		{
			iCnt = (iY - ptBitMap->iYTop) * ptBitMap->iPitch;
			for(iX = ptBitMap->iXLeft, iBit = 7;iX < ptBitMap->iXMax;iX++)
			{
				if(iBit == 7)
					cVal = ptBitMap->pucBuf[iCnt++];
				if(cVal & (1<<iBit))
					g_ptDispOpr->ShowPixel(iX, iY, COLOR_FOREGROUND);
				else					
				;//	g_ptDispOpr->ShowPixel(iX, iY, COLOR_BACKGROUND);
				
				if((--iBit) < 0)
				{
					iBit = 7;
				}
			}
		}
	}
	else if(ptBitMap->iBpp == 8)
	{
		for(iY = ptBitMap->iYTop;iY < ptBitMap->iYMax;iY++)
			for(iX = ptBitMap->iXLeft;iX < ptBitMap->iXMax;iX++)			
				g_ptDispOpr->ShowPixel(iX, iY, COLOR_FOREGROUND);
			
	}
	else
	{
		DBG_PRINT("Error at %s,%d\r\n", __FILE__, __LINE__);
		DBG_PRINT("don't suppot bpp %d \r\n", ptBitMap->iBpp);
		return -1;
	}

	return 0;
}

static int ShowOnePage(unsigned char *pucNowPos)
{
	unsigned int dwCodeLen;
	unsigned int dwCode;
	int iHasGetCode = 0, iHasCleanSrceen = 1;
	PT_FontOpr ptFontOprTmp;
	int iError;
	unsigned char *pucBufStart = pucNowPos;
	T_BitMap tBitMap;

	tBitMap.iCurOriginX = 0;
	tBitMap.iCurOriginY = g_iFontSize;

	while(1)
	{
		dwCode = 0;
		dwCodeLen = g_ptEncodingOpr->GetCode(pucBufStart, g_pucFileEnd, &dwCode);
		if(!dwCodeLen)
		{
			if(iHasGetCode)
			{
				printf("Page :%03d\r\n",g_ptPageDesc->iPage);
				return 0;
			}
			else
			{
				DBG_PRINT("Error at %s,%d\r\n", __FILE__, __LINE__);
				return -1;			
			}
		}		

		pucBufStart += dwCodeLen;
		iHasGetCode = 1;

		if(dwCode == '\r')
		{
			continue;			
		}
		else if(dwCode == '\t')
		{
			dwCode = ' ';
		}
		else if(dwCode == '\n')
		{
			g_pucNextPosAtFile = pucBufStart;

			tBitMap.iCurOriginX = 0;
			tBitMap.iCurOriginY = IncY(tBitMap.iCurOriginY);		

			if(tBitMap.iCurOriginY == 0)
			{				
				printf("Page :%03d\r\n",g_ptPageDesc->iPage);
				return 0;
			}
			continue;
		}


		ptFontOprTmp = g_ptEncodingOpr->ptFontOprSupportHead; 
		while(ptFontOprTmp)
		{
			iError = ptFontOprTmp->GetBitMap(dwCode, &tBitMap);			
			if(iError)
			{								
				ptFontOprTmp = ptFontOprTmp->ptNext;
				continue;
			}

			iError = RelocateFontPos(&tBitMap);
			if(iError)
			{
				DBG_PRINT("Error at %s,%d\r\n", __FILE__, __LINE__);
				return 0;
			}
			

			if(iHasCleanSrceen)
			{
				g_ptDispOpr->CleanScreen(COLOR_BACKGROUND);
				iHasCleanSrceen = 0;				
			}

			iError = ReallyShowOneCode(&tBitMap);
			if(iError)
			{
				DBG_PRINT("Error at %s,%d\r\n", __FILE__, __LINE__);
				return -1;
			}

			tBitMap.iCurOriginX = tBitMap.iNextOriginX;
			tBitMap.iCurOriginY = tBitMap.iNextOriginY;
			g_pucNextPosAtFile = pucBufStart;
			
			break;
		}
	}
		
	return 0;
}



int ShowNextPage(void)
{
	int iError;
	PT_PageDesc ptOnePage;

	if(!g_ptPageDesc)
	{
		g_ptPageDesc = malloc(sizeof(T_PageDesc));
		if(!g_ptPageDesc)
			return -1;

		g_ptPageDesc->iPage  		 = 1;
		g_ptPageDesc->ptNextPage     = NULL;
		g_ptPageDesc->ptPrePage 	 = NULL;
		g_ptPageDesc->pucCurPosAtFile = g_pucFileStart + g_ptEncodingOpr->iHeadLen;				
	}
	else
	{
		if(g_pucNextPosAtFile == g_pucFileEnd)
		{
			return 0;
		}
		if(!(g_ptPageDesc->ptNextPage))
		{
			ptOnePage = malloc(sizeof(T_PageDesc));
			if(!ptOnePage)
				return -1;
			ptOnePage->ptNextPage 	  = NULL;
			ptOnePage->pucCurPosAtFile = g_pucNextPosAtFile;
			ptOnePage->iPage		  = g_ptPageDesc->iPage + 1;
			g_ptPageDesc->ptNextPage  = ptOnePage;
			ptOnePage->ptPrePage      = g_ptPageDesc;
			g_ptPageDesc = ptOnePage;			
		}
		else
		{
			g_ptPageDesc = g_ptPageDesc->ptNextPage;
		}
	}

	iError = ShowOnePage(g_ptPageDesc->pucCurPosAtFile);	
	if(iError)
	{
		DBG_PRINT("Error at %s,%d\r\n", __FILE__, __LINE__);
		return -1;
	}

	return 0;
}

int ShowPrePage(void)
{
	int iError;
	
	if(!g_ptPageDesc || !g_ptPageDesc->ptPrePage)
	{
		return -1;		
	}
		
	g_ptPageDesc = g_ptPageDesc->ptPrePage;	

	iError = ShowOnePage(g_ptPageDesc->pucCurPosAtFile);
	if(iError)	
	{
		DBG_PRINT("Error at %s,%d\r\n", __FILE__, __LINE__);
		return -1;
	}
	
		
	return 0;
}

int DrawInit(void)
{
	int iError;


	iError = InputInit();
	if(iError)
	{
		DBG_PRINT("Error at %s,%d\r\n", __FILE__, __LINE__);
		return -1;
	}
		
	iError = DisplaysInit();
	if(iError)
	{
		DBG_PRINT("Error at %s,%d\r\n", __FILE__, __LINE__);
		return -1;
	}
	iError = FontsInit();
	if(iError)
	{
		DBG_PRINT("Error at %s,%d\r\n", __FILE__, __LINE__);
		return -1;
	}
	iError = EncodingsInit();
	if(iError)
	{
		DBG_PRINT("Error at %s,%d\r\n", __FILE__, __LINE__);
		return -1;
	}
	
	return 0;
}


main.c

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <config.h>
#include <draw.h>
#include <encoding_manager.h>
#include <fonts_manager.h>
#include <disp_manager.h>
#include <input_manager.h>


int main(int argc, char *argv[])
{
	char pcHzkName[20];
	char pcFreetypeName[20];
	char pcTextName[20];
	char pcDispName[20];

	int iError;
	int iList = 0;
	int iFontSize = 16;

	T_InputEventOpr tInputEventOpr;


	pcHzkName[0] = 0;
	pcFreetypeName[0] = 0;
	pcTextName[0] = 0;
	pcDispName[0] = 0;

#ifdef ONPC
	strcpy(pcDispName,"onpc");
#else
	strcpy(pcDispName,"fb");
#endif
	while ((iError = getopt(argc, argv, "ls:f:h:d:")) != -1)
	{
		switch(iError)
		{
			case 'l' : 
			{
				iList = 1;				
				break;
			}
			case 's' : 
			{
				iFontSize = strtoul(optarg, NULL, 0);
				break;
			}
			case 'f' :
			{
				strncpy(pcFreetypeName, optarg, 20);
				pcFreetypeName[19] = '0';
				break;
			}
			case 'h' :
			{
				strncpy(pcHzkName, optarg, 20);
				pcHzkName[19] = '0';
				break;
			}
			case 'd' :
			{
				strncpy(pcDispName, optarg, 20);
				pcDispName[19] = '\0';			
				break;
			}
			default:
			{
				printf("Usage: %s [-s Size] [-d display] [-f font_file] [-h HZK] <text_file>\n", argv[0]);
				printf("Usage: %s -l\n", argv[0]);
				return -1;
			}
		}
	}

	if (!iList && (optind >= argc))
	{
		printf("Usage: %s [-s Size] [-d display] [-f font_file] [-h HZK] <text_file>\n", argv[0]);
		printf("Usage: %s -l\n", argv[0]);
		return -1;
	}

	iError = DrawInit();
	if(iError)
	{
		printf("DrawInit error!\n");
		return -1;
	}

	if(iList)
	{
		ShowDispOpr();

		ShowSupportFont();

		ShowSupportEncoding();

		ShowInputOpr();
		
		return 0;
	}

	strncpy(pcTextName, argv[optind], 20);
	pcTextName[19] = '\0';
	
	iError = OpenTextFile(pcTextName);
	if (iError)
	{
		printf("OpenTextFile error!\n");
		return -1;
	}

	iError = SetFontsDetail(pcHzkName, pcFreetypeName, iFontSize);
	if (iError)
	{
		printf("SetFontsDetail error!\n");
		return -1;
	}

	iError = SelectAndInitDisplay(pcDispName);
	if (iError)
	{
		printf("SelectAndInitDisplay error!\n");
		return -1;
	}

	iError = ReallyInputInit();
	if (iError)
	{
		printf("SelectAndInitDisplay error!\n");
		return -1;
	}

	printf("Enter 'n' to show next page, 'u' to show previous page, 'q' to exit: \r\n");
	ShowNextPage();

	while(1)
	{	
		while(GetInputEvent(&tInputEventOpr));
		
		switch(tInputEventOpr.iVal)
		{
			case INPUT_VAL_PRE :
			{
				ShowPrePage();
				break;
			}
			case INPUT_VAL_NEXT :
			{
				ShowNextPage();
				break;
			}
			case INPUT_VAL_EXIT :
			{
				printf("\r\n\r\nexit!\r\n");
				DisplayExit();
				return 0;
			}
		}
		tInputEventOpr.iVal = INPUT_VAL_UNKNOWN;
	}

	return 0;
}


 

<think>我们根据是否存在文件`/tmp/5g_disable`来决定是否禁用控件。 由于浏览器环境下JavaScript无法直接访问文件系统,因此我们需要通过其他方式获取该状态。 假设我们通过后端API来检查文件是否存在,然后前端根据API返回的结果来设置禁用状态。 步骤: 1. 前端发送请求到后端,检查文件是否存在。 2. 根据返回的结果,设置控件的禁用状态和ARIA属性。 这里我们使用fetch API来模拟这个请求。 注意:在真实环境中,后端需要提供一个接口(例如:`/api/check-file`)来检查文件是否存在。 代码示例: ```javascript // 检查文件是否存在的函数 async function checkFileExists() { try { const response = await fetch('/api/check-file?filename=/tmp/5g_disable'); const data = await response.json(); return data.exists; // 假设返回{ exists: true/false } } catch (error) { console.error('检查文件出错:', error); return false; // 出错时默认不禁用 } } // 更新控件状态 async function updateControlState() { const exists = await checkFileExists(); const channelSelect = document.getElementById('channel'); const combobox = channelSelect.querySelector('[role="combobox"]'); const toggleBtn = document.getElementById('selection_automatique_canaux_5'); // 更新下拉框 channelSelect.classList.toggle('disabled', exists); combobox.setAttribute('aria-disabled', exists); combobox.setAttribute('tabindex', exists ? '-1' : '0'); combobox.setAttribute('aria-label', exists ? '已禁用(存在禁用文件)' : 'Sélection du canal'); // 更新开关按钮(如果文件存在,开关也禁用) toggleBtn.setAttribute('aria-disabled', exists); toggleBtn.setAttribute('tabindex', exists ? '-1' : '0'); toggleBtn.classList.toggle('disabled', exists); } // 初始化 document.addEventListener('DOMContentLoaded', updateControlState); ``` 注意:上面的代码假设后端API返回一个JSON对象,包含一个布尔类型的`exists`字段。 后端示例(Node.js Express): ```javascript app.get('/api/check-file', (req, res) => { const filename = req.query.filename; fs.access(filename, fs.constants.F_OK, (err) => { res.json({ exists: !err }); }); }); ``` 考虑到安全性,后端应该对文件名进行合法性检查,避免路径遍历攻击。 如果是在非浏览器环境(如Electron或Node.js桌面应用)中,可以直接访问文件系统: ```javascript const fs = require('fs'); function checkFileExistsSync(filePath) { try { fs.accessSync(filePath, fs.constants.F_OK); return true; } catch (e) { return false; } } ``` 根据环境选择合适的方法。 另外,我们还可以通过轮询或WebSocket等方式实时更新状态(如果需要实时性)。 下面是一个使用轮询的示例: ```javascript setInterval(updateControlState, 5000); // 每5秒检查一次 ``` 无障碍注意事项: 1. 当控件被禁用时,确保`aria-disabled`设置为true,并且`tabindex`为-1(避免键盘焦点)。 2. 提供禁用原因的文本说明,可以通过`aria-describedby`关联到一个隐藏的提示元素。 改进:在禁用状态下,为屏幕阅读器用户提供更详细的提示: ```html <div id="disable-reason" class="sr-only">存在禁用文件/tmp/5g_disable</div> ``` 在JavaScript中: ```javascript if (exists) { combobox.setAttribute('aria-describedby', 'disable-reason'); } else { combobox.removeAttribute('aria-describedby'); } ``` 完整示例代码(前端部分): ```javascript document.addEventListener('DOMContentLoaded', function() { const disableReasonElement = document.createElement('div'); disableReasonElement.id = 'disable-reason'; disableReasonElement.className = 'sr-only'; disableReasonElement.textContent = '存在禁用文件/tmp/5g_disable'; document.body.appendChild(disableReasonElement); async function updateControlState() { const exists = await checkFileExists(); const channelSelect = document.getElementById('channel'); const combobox = channelSelect.querySelector('[role="combobox"]'); const toggleBtn = document.getElementById('selection_automatique_canaux_5'); // 更新下拉框 channelSelect.classList.toggle('disabled', exists); combobox.setAttribute('aria-disabled', exists); combobox.setAttribute('tabindex', exists ? '-1' : '0'); if (exists) { combobox.setAttribute('aria-describedby', 'disable-reason'); combobox.setAttribute('aria-label', '已禁用(存在禁用文件)'); } else { combobox.removeAttribute('aria-describedby'); combobox.setAttribute('aria-label', 'Sélection du canal'); } // 更新开关按钮 toggleBtn.setAttribute('aria-disabled', exists); toggleBtn.setAttribute('tabindex', exists ? '-1' : '0'); toggleBtn.classList.toggle('disabled', exists); // 开关按钮的标签也需要更新 toggleBtn.setAttribute('aria-label', exists ? '已禁用' : 'Activer'); } // 初始化和轮询 updateControlState(); setInterval(updateControlState, 5000); }); ``` 注意:我们每5秒轮询一次,以确保文件状态变化时界面能够更新。 如果是在Electron等桌面环境中,可以使用`fs.watch`来监听文件变化,然后主动通知渲染进程更新。 最后,确保样式表中包含`.disabled`和`.sr-only`的样式。 这样,我们就实现了根据文件存在与否来禁用控件,并且保证了无障碍访问。 </think>### 根据文件存在状态禁用控件实现方案 要实现根据 `/tmp/5g_disable` 文件存在状态禁用控件,需构建文件检测逻辑与界面状态联动的完整系统: --- ### 🔍 文件检测机制设计 1. **后端文件检查接口** 创建API端点检测文件存在性: ```javascript // Node.js示例 (Express) app.get('/api/check-disable-file', (req, res) => { const fs = require('fs'); res.json({ disabled: fs.existsSync('/tmp/5g_disable') }); }); ``` 2. **前端状态检测函数** ```javascript async function is5GDisabled() { try { const response = await fetch('/api/check-disable-file'); const { disabled } = await response.json(); return disabled; } catch (error) { console.error('文件检测失败', error); return false; // 默认不禁用 } } ``` --- ### ️ 控件禁用实现 1. **统一状态管理** ```javascript // 创建全局状态对象 const radioControlState = { disabled: false, update: async function() { this.disabled = await is5GDisabled(); this.applyState(); }, applyState: function() { // 更新下拉框 const combobox = document.querySelector('[role="combobox"]'); combobox.setAttribute('aria-disabled', this.disabled); combobox.setAttribute('tabindex', this.disabled ? '-1' : '0'); // 更新开关按钮 const toggleBtn = document.getElementById('selection_automatique_canaux_5'); toggleBtn.classList.toggle('disabled', this.disabled); toggleBtn.setAttribute('aria-disabled', this.disabled); } }; ``` 2. **实时状态轮询** ```javascript // 每30秒检查文件状态 setInterval(() => radioControlState.update(), 30000); // 初始加载时检测 document.addEventListener('DOMContentLoaded', () => { radioControlState.update(); }); ``` 3. **服务器推送方案(高级)** 使用WebSocket实现实时状态更新: ```javascript const socket = new WebSocket('wss://yourserver.com/ws'); socket.onmessage = (event) => { if (event.data === 'FILE_CHANGED') { radioControlState.update(); } }; ``` --- ### 📁 文件监控服务(后端) 使用`inotify`实现Linux文件系统监控: ```bash #!/bin/bash # 文件监控脚本 while inotifywait -e create,delete /tmp; do if [[ "$file" == "5g_disable" ]]; then # 通知所有连接的客户端 echo "FILE_CHANGED" | websocat -s 3000 fi done ``` --- ### ️ 安全性增强 1. **文件路径验证** ```javascript // 防止路径遍历攻击 app.get('/api/check-disable-file', (req, res) => { const path = require('path'); const validPath = path.resolve('/tmp/5g_disable'); if (!validPath.startsWith('/tmp/')) { return res.status(403).send('非法路径'); } // ...检测逻辑 }); ``` 2. **访问控制** ```nginx # Nginx配置限制访问 location /api/check-disable-file { allow 192.168.1.0/24; deny all; proxy_pass http://localhost:3000; } ``` --- ### 📱 完整React组件示例 ```jsx function RadioSettings() { const [disabled, setDisabled] = useState(false); useEffect(() => { const checkStatus = async () => { const res = await fetch('/api/check-disable-file'); setDisabled((await res.json()).disabled); }; checkStatus(); const timer = setInterval(checkStatus, 30000); return () => clearInterval(timer); }, []); return ( <div className={`form_field ${disabled && 'disabled'}`}> <div role="combobox" aria-disabled={disabled} aria-label={disabled ? "已禁用(存在配置文件)" : "Sélection du canal"} tabIndex={disabled ? -1 : 0} > {/* 下拉框内容 */} </div> <button id="selection_automatique_canaux_5" aria-disabled={disabled} aria-label={disabled ? "配置锁定" : "Activer"} > {/* 开关内容 */} </button> </div> ); } ``` --- ### ✅ 部署检查清单 | 环节 | 关键事项 | |------|----------| | **文件检测** | 实现安全路径验证的API端点 | | **状态同步** | 前端轮询机制+WebSocket实时通知 | | **无障碍** | 动态更新aria-disabled/tabindex | | **错误处理** | 网络中断时的降级处理 | | **权限控制** | 限制文件检测API的访问范围 |
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值