前言
之前写过一篇关于软键盘输入设计的文章点击这里查看,用的是掌机自支持的zzdbase语言,文章结尾说了其实最初想用C来实现的,但是中途遇到了困难,便改为zzdbase语言了。最近项目中想到一个比较好的软件架构,刚好用来编写之前的软键盘输入程序。花了半天时间,将原来的代码改为了c预言实现。
本次主要更改的地方
- 软件架构更改(本文章不叙述)
- 软键盘实现
- 硬键盘与软键盘切换
- 一些小优化
软键盘实现(主要看代码)
首先定义ASCII码表,用10进制表示。最后一个为“0”,为空字符。码表之所以定义成这种,是考虑到了键盘布局和输入方便的因素。
U8 ASCData[27]={126,33,64,35,36,37,94,38,44,92,61,60,62,63,91,93,123,125,95,124,96,39,32,34,59,58,0};
下面是根据定义好的ASCII码表来显示软键盘。
void DoShowKeyboard(void)
{
U8 i;
U8 num_temp[1];
U8 row;
/* 设置屏幕背景 */
ClearLCDn(6,3);
ShowString(6,0," ",LCD_COLOR_NAG);
ShowString(7,0," ",LCD_COLOR_NAG);
ShowString(8,0," ",LCD_COLOR_NAG);
// 分3行显示
for(i=0;i<27;i++)
{
if (i<=8)
{
row = (i+1)*2;
sprintf(num_temp,"%c",ASCData[i]);
if (i == 0)
{
ShowString(6,row,num_temp,LCD_COLOR_POS); // 默认第一个高亮选中
}
else
{
ShowString(6,row,num_temp,LCD_COLOR_NAG);
}
}
else if ((i<=17)&&(i>=9))
{
row = (i-8)*2;
sprintf(num_temp,"%c",ASCData[i]);
ShowString(7,row,num_temp,LCD_COLOR_NAG);
}
else if ((i<=26)&&(i>=18))
{
row = (i-17)*2;
sprintf(num_temp,"%c",ASCData[i]);
ShowString(8,row,num_temp,LCD_COLOR_NAG);
}
else
{
break;
}
}
}
软硬键盘切换输入
软硬键盘切换输入的实现主要通过侦听键盘按键,如按下切换键(本例设置为KEY_HELP),则在两种模式之间进行切换,实现两种模式的字符输入。
/* 输入主函数 */
U8 DoInputValues(U8 * buf, U8 len)
{
S16 Key; //接收键盘输入的键值
U8 len_fact = 0; //已输入的字符串长度
U8 CursorPos = 0;// 定义一个目前输入模式,0-硬键盘输入 1-软键盘输入
U8 KeyL; //键值低8位字节 用来显示硬键盘输入的ASCii码
U8 res;
_setkeymode(2);
LOOP6:for(;;)
{
DoRefreshShow(buf,len_fact); // 刷新已输入字符串显示
if (CursorPos == 0) // 硬键盘输入模式
{
GotoCursor(2,0);
Key = _bioskey(0); //监听输入键值
if (Key == ESC) //退出键
{
return 1;
}
else if (Key == ENTER) //确认键
{
return len_fact;
}
else if (Key == DEL) // 删除键
{
if (len_fact == 0)
{
goto LOOP6;
}
else // 已输入字符串长度不为0,删除最后一个字符(置0值)
{
len_fact--;
memset(buf+len_fact,0x00,1);
goto LOOP6;
}
}
else if (Key == KEY_HELP)// 帮助键 切换到软键盘输入
{
CursorPos = 1;
goto LOOP6;
}
else // 硬键盘输入键值 如 A B C 1 2 3等
{
;
}
}
else if (CursorPos == 1) // 软键盘输入模式 执行软键盘输入函数
{
res = DoSoftwareInput(buf,&len_fact);
if (res == 1)
{
CursorPos = 0;
goto LOOP6;
}
}
KeyL = (U8)(Key&0x00FF); // 取硬键盘输入键值低8位 保存其ASCII码
*(buf + len_fact) = (U8)(KeyL);
len_fact++;
}
}
软键盘输入函数
U8 DoSoftwareInput(U8 * buf, U8 *len)
{
S16 keyvalue;
S8 index = 0;
S8 indexold=0;
U8 line,row;
U8 num_temp[1];
U8 *tempbuf = buf;
U8 lentemp;
lentemp = *len; // 传入已输入字符串长度指针
DoShowKeyboard(); // 显示软键盘
loop4:for(;;)
{
_setdispcolor(LCD_COLOR_POS);
DoRefreshShow(tempbuf,lentemp); // 刷新显示
GotoCursor(2,0);
keyvalue = _bioskey(0); // 监听键盘按键
if (keyvalue == ENTER) // 确认,将当前软键盘高亮的字符保存
{
if (lentemp == 32)
{
;
}
else if (lentemp<32)
{
*(tempbuf + lentemp) = ASCData[index];
lentemp++;
}
else
{
;
}
goto loop4;
}
else if ((keyvalue == ESC)||(keyvalue == KEY_HELP)) // 退出软键盘输入 切换到硬键盘
{
DoQuitKeyboard();
*len = lentemp;
return 1;
}
else if (keyvalue == DEL) // 删除 删除最后一个字符
{
if (lentemp == 0)
{
;
}
else
{
lentemp--;
*(tempbuf + lentemp) = 0x00;
}
goto loop4;
}
else if (keyvalue == UP) // 向上键 软键盘高亮数字移动
{
indexold = index;
index -= 9;
if (indexold == 8)
{
index = 17;
}
else if (index < 0)
{
index = index+27;
}
}
else if (keyvalue == DOWN)
{
indexold = index;
index += 9;
if (indexold == 17)
{
index = 8;
}
else if (index > 25)
{
index = index-27;
}
}
else if (keyvalue == LEFT)
{
indexold = index;
index--;
if (index < 0)
{
index = 25;
}
}
else if (keyvalue == RIGHT)
{
indexold = index;
index++;
if (index > 25)
{
index = 0;
}
}
else
{
goto loop4;
}
// 新选中的字符变为高亮状态 index索引ASCII表位置
if ((index>=0)&&(index<=8))
{
line = 6;
row = (index+1)*2;
}
if ((index>=9)&&(index<=17))
{
line = 7;
row = (index-8)*2;
}
if ((index>=18)&&(index<=26))
{
line = 8;
row = (index-17)*2;
}
sprintf(num_temp,"%c",ASCData[index]);
ShowString(line,row,num_temp,LCD_COLOR_POS);
// 原来高亮的字符变为非高亮 indexold索引其ASCII位置
if ((indexold>=0)&&(indexold<=8))
{
line = 6;
row = (indexold+1)*2;
}
if ((indexold>=9)&&(indexold<=17))
{
line = 7;
row = (indexold-8)*2;
}
if ((indexold>=18)&&(indexold<=26))
{
line = 8;
row = (indexold-17)*2;
}
sprintf(num_temp,"%c",ASCData[indexold]);
ShowString(line,row,num_temp,LCD_COLOR_NAG);
}
}
小的优化
C语言相比于zzdbase语言更具有灵活性,可自我发挥空间更大。例如在修改此例中,将原来zzdbase语言封装好的发送接收自己重新做了调整,加入了定时,可以用来判断接收超时。
// 发送接收函数
void DoSendAndReceive(U8 *Sendbuf, U8 *Sendlen, U8 *Recvbuf, U8 *Recvlen)
{
U8 i,res;
U8 tempsendlen,temprecvlen; // 定义发送接收长度
U8 tempsendbuf[256],temprecvbuf[256]; //定义发送接收缓冲区
U8 starttime[9]={0}; //定义计时开始时间
U8 endtime[9]={0}; //定义计时结束时间
U8 startsecond,endsecond; // 开始 结束 秒
U8 delay; //接收延时
tempsendlen = *Sendlen;
memcpy(tempsendbuf,Sendbuf,tempsendlen);
for(i=0;i<tempsendlen;i++)
{
_com_send(tempsendbuf[i]);
}
memset(temprecvbuf,0x00,sizeof(temprecvbuf)); //接收缓冲初始化
ClearMid();
ShowString(1,0,"数据接收中...",LCD_COLOR_POS);
//接收计时,超过设置值退出(接收超时)
_gettime(starttime);//获取当前时间,保存到计时开始
startsecond= (U8)(((starttime[6] - '0') * 10) + (starttime[7] - '0'));// 保存开始计时 秒
do{
res = _com_read_buf(temprecvbuf,&temprecvlen,256,500); // 接收侦听循环
_gettime(endtime);
endsecond= (U8)((endtime[6] - '0') * 10 + (endtime[7] - '0'));
if (endsecond < startsecond)
{
endsecond += 60;
}
delay = endsecond - startsecond;
ShowTime(2,0,delay); // 显示已过去的时间
if (delay > 3) //默认接收3秒 超过3s 退出侦听,判断为接收超时
{
break;
}
}while(res==1);
if (temprecvlen != 0) // 接收到数据 数据和长度传给指针
{
memcpy(Recvbuf,temprecvbuf,temprecvlen);
*Recvlen = temprecvlen;
}
else
{
;
}
}
通过此次的更改对比,发现C语言的优势便在于灵活性非常强,不受掌机库函数的限制,而且经过测试发现,更改后的C语言程序版本比之前的zzdbase语言版本更稳定,操作性更强,主要是因为在c版本上做了一些优化,并且更改了软件框架,使之更容易实现我所需要的功能。