功能:实现按键的单机,双击,长按
采用定时器检测按键电平,判断按键触发方式
//假设10ms判断一次按键电平
#define SINGLE_PRESS_TIME 3 //30ms
#define LONG_PRESS_TIME 300 //3s
#define REPEAT_PRESS_TIME 50
#define KEY_NUM 8
#define KEY_FIFO_SIZE 8
typedef enum
{
KEY_NULL,
KEY_PRESS,
KEY_RELEASE
}KEY_STATU;
typedef enum
{
DISABLE,
ENABLE
}KEY_ENABLE_STATUS;
typedef enum
{
NONE,
SINGLE_CLICK,
DOUBLE_CLICK,
LONG_PRESS
}KEY_EVT;
typedef struct
{
KEY_ENABLE_STATUS enflag; //按键使能标志
KEY_STATU statu; //按键状态标志
KEY_EVT key_evt; //按键产生的事件
int repeatflag; //双击标志位
int flag; //第一次单机标志位
int repeat_press_time; //双击间隔时间
int press_time; //按键出发时间
void (*is_key_down)(void); //判断是否按键按下
void (*long_press_evt)(void); //长按事件
void (*single_click_evt)(void); //单击事件
void (*double_click_evt)(void); //双击事件
}KEY;
typedef struct
{
int key_num;
KEY_EVT key_evt;
}KEY_FIFO_T;
typedef struct
{
int read;
int write;
KEY_FIFO_T evt_fifo[KEY_FIFO_SIZE];
}KEY_FIFO;
KEY key_buff[KEY_NUM];
KEY_FIFO key_fifo;
void API_PUTEVTS(int key_num, KEY_EVT key_evt)
{
key_fifo.evt_fifo[key_fifo.write].key_num = key_num;
key_fifo.evt_fifo[key_fifo.write].key_evt = key_evt;
key_fifo.write = (key_fifo.write + 1) % KEY_FIFO_SIZE;
}
bool API_GETEVTS(KEY_FIFO_T *evt)
{
bool ret = false;
if(key_fifo.read == key_fifo.write)
ret = false;
else
{
ret = true;
evt->key_num = key_fifo.evt_fifo[key_fifo.read].key_num;
evt->key_evt = key_fifo.evt_fifo[key_fifo.read].key_evt;
key_fifo.read = (key_fifo.read + 1) % KEY_FIFO_SIZE;
}
return ret;
}
void KEY_SCAN()
{
for(int key_num = 0; key_num < KEY_NUM; key_num++)
{
if(key_buff[key_num].enflag)
{
switch(key_buff[key_num].statu)
{
case KEY_NULL:
if(key_buff[key_num].is_key_down())
{
key_buff[key_num].statu = KEY_PRESS;
key_buff[key_num].press_time = 0;
}
if(key_buff[key_num].repeat_press_time > 0)
{
key_buff[key_num].repeat_press_time--;
}
break;
case KEY_PRESS:
if(key_buff[key_num].is_key_down())
key_buff[key_num].press_time++;
if(key_buff[key_num].press_time < SINGLE_PRESS_TIME)
key_buff[key_num].statu = KEY_NULL;
else
{
if(key_buff[key_num].repeat_press_time > 0)
{
key_buff[key_num].repeatflag = 1;
}
key_buff[key_num].statu = KEY_RELEASE;
}
break;
case KEY_RELEASE:
if(key_buff[key_num].is_key_down())
{
key_buff[key_num].press_time++;
}
else
{
if(key_buff[key_num].press_time < LONG_PRESS_TIME)
{
if(!key_buff[key_num].flag)
{
key_buff[key_num].repeat_press_time = REPEAT_PRESS_TIME;
key_buff[key_num].flag = 1;
}
else
{
if(key_buff[key_num].repeatflag)
{
key_buff[key_num].key_evt = DOUBLE_CLICK;
key_buff[key_num].repeatflag = 0;
}
else
{
key_buff[key_num].key_evt = SINGLE_CLICK;
}
key_buff[key_num].flag = 0;
API_PUTEVTS(key_num, key_buff[key_num].key_evt);
}
}
else
{
key_buff[key_num].key_evt = LONG_PRESS;
API_PUTEVTS(key_num, key_buff[key_num].key_evt);
}
key_buff[key_num].statu = KEY_NULL;
}
break;
default:
break;
}
}
}
}
void KEY_EVT()
{
KEY_FIFO_T evt;
if(API_GETEVTS(&evt))
{
switch(evt.key_evt)
{
case SINGLE_CLICK:
key_buff[evt.key_num].single_click_evt();
break;
case DOUBLE_CLICK:
key_buff[evt.key_num].double_click_evt();
break;
case LONG_PRESS:
key_buff[evt.key_num].long_press_evt();
break;
default:
break;
}
}
}