Files
TAIXIN/sdk/lib/key/keyScan.c

217 lines
7.4 KiB
C
Raw Normal View History

#include "keyScan.h"
/*************************************************************************************
* timer事件
* key_scan_init来注册事件
*
*
**************************************************************************************/
static void g_key_scan(key_channel_t *ch)
{
const keys_t *arg = ch->key_arg;
uint8 key = ch->scan(ch);
uint8 key_code = KEY_EVENT_MAX;
uint8 key_event = KEY_EVENT_MAX;
//分析按键情况
//按键可能被释放或者说原本就是没有被按下
if(key == 0)
{
//按键没有被按下,无需去管理
if(ch->last_key == 0)
{
goto g_key_scan_end;
}
//按键从被按下到释放,反馈事件,有两种可能:短按释放,长按释放,异常情况则是(消抖没有完成就被释放)
else
{
//异常事件,正常不可能存在,检查程序,可能存在按键抖动情况,不作任何判断
if(ch->last_event == KEY_EVENT_MAX)
{
//printf("%s:%d err,last key:%d,now key:%d\tlast_event:%d\n",__FUNCTION__,__LINE__,ch->last_key,key,ch->last_event );
//printf("last time:%d\tnow time:%d\n",ch->last_time,os_jiffies());
}
else if(ch->last_event == KEY_EVENT_LDOWN || ch->last_event == KEY_EVENT_REPEAT)
{
ch->last_event = KEY_EVENT_MAX;
key_event = KEY_EVENT_LUP;
key_code = ch->last_key;
}
else if(ch->last_event == KEY_EVENT_DOWN)
{
ch->last_event = KEY_EVENT_MAX;
key_event = KEY_EVENT_SUP;
key_code = ch->last_key;
}
ch->last_key = key;
}
}
//有多种情况,key与last key不一样,分两种情况,按键抖动(相隔的时间太短),则以后面的key为准,并且时间清0,另一种则是按键检测的时候,错过了up的事件(因为用软定时,有可能错过,这个时候应该发出一个up事件,但也有可能按键接触不良,可以先发出up事件,key当作没有,等待下次的key再去判断)
else
{
//同样按键,判断时间超出按键抖动范围,如果是,则发出被按下事件
if(key == ch->last_key)
{
//上一次没有事件,则是消抖时间完成,发出按键按下事件
if(ch->last_event == KEY_EVENT_MAX)
{
if(os_jiffies() - ch->last_time > arg->period_dither)
{
ch->last_event = KEY_EVENT_DOWN;
key_event = KEY_EVENT_DOWN;
key_code = ch->last_key;
//无需更新时间,下一次则进入去判断是否长按
ch->last_time = os_jiffies();
}
//消抖时间没有完成
else
{
}
}
//上一次已经有down的事件,则需要继续判断后续的事件(是否为长按或者重复按键)
else
{
//短按,超过长按的时间,发出长按被按下的事件
if(ch->last_event == KEY_EVENT_DOWN )
{
if(os_jiffies() - ch->last_time > arg->period_long)
{
//长按事件被按下
ch->last_event = KEY_EVENT_LDOWN;
key_event = KEY_EVENT_LDOWN;
key_code = ch->last_key;
//用于判断是否是重复按键
ch->last_time = os_jiffies();
}
//不是长按,还在等待时间
else
{
}
}
else
{
if(ch->last_event == KEY_EVENT_LDOWN || ch->last_event == KEY_EVENT_REPEAT)
{
if(os_jiffies() - ch->last_time > arg->period_repeat)
{
ch->last_event = KEY_EVENT_REPEAT;
key_event = KEY_EVENT_REPEAT;
key_code = ch->last_key;
//用于判断下一次判断
ch->last_time = os_jiffies();
}
}
else
{
os_printf("%s:%d err,last key:%d,now key:%d\tlast_event:%d\n",__FUNCTION__,__LINE__,ch->last_key,key,ch->last_event );
}
}
}
}
//刚被按下,则记录时间,等待抖动结束
if(!ch->last_key)
{
ch->last_time = os_jiffies();
ch->last_key = key;
}
//两次按键不一致,那么就要去识别事件,如果last_event没有事件,代表消抖没有完成,则重新计算时间,如果消抖完成,则需要发出up事件,last_key = 0
else if(ch->last_key != key)
{
//消抖没有完成,更新按键的值
if(ch->last_event == KEY_EVENT_MAX)
{
ch->last_time = os_jiffies();
ch->last_key = key;
}
//消抖完成,发出up事件,然后last_key设置为0,等待下次按键判断
else
{
if(ch->last_event == KEY_EVENT_LDOWN || ch->last_event == KEY_EVENT_REPEAT)
{
ch->last_event = KEY_EVENT_MAX;
key_event = KEY_EVENT_LUP;
key_code = ch->last_key;
}
else if(ch->last_event == KEY_EVENT_DOWN)
{
ch->last_event = KEY_EVENT_MAX;
key_event = KEY_EVENT_SUP;
key_code = ch->last_key;
ch->last_time = os_jiffies();
}
ch->last_key = 0;
}
}
}
g_key_scan_end:
if(key_event != KEY_EVENT_MAX)
{
// key_map_t *map = ch->key_table_map;
//uint32 map_msg = map[key_code][key_event];
uint32 map_msg = (key_code<<8 | key_event);
if(map_msg && ch->key_send)
{
ch->key_send(map_msg,ch->extern_value);
}
}
}
//timer事件
static void key_auto_timer_cb(void *arg)
{
key_channel_t **channel = (key_channel_t **)arg;
key_channel_t **ch;
for (ch = &channel[0]; *ch; ++ch)
{
if(!(*ch)->enable)
{
continue;
}
if((*ch)->prepare)
{
(*ch)->prepare(*ch);
}
if((*ch)->scan)
{
g_key_scan(*ch);
}
}
}
static os_timer_t key_timer;
//先初始化,然后注册timer,注册按键的映射表,最后启动timer
void key_button_scan_init(key_channel_t **channel,key_send_msg send)
{
key_channel_t **ch = channel;
for (; *ch; ++ch)
{
(*ch)->last_event = KEY_EVENT_MAX;
(*ch)->last_key = KEY_EVENT_MAX;
(*ch)->last_time = os_jiffies();
(*ch)->key_send = send;
if((*ch)->init)
{
(*ch)->init(*ch);
}
}
os_timer_init(&key_timer, key_auto_timer_cb, OS_TIMER_MODE_PERIODIC, (void*)channel);
os_timer_start(&key_timer, 5);
}