复杂按键事件识别程序(链接层-优化版)
本文相对于键值转换--复杂按键事件识别程序(链接层)文章中所述的按键事件转换程序进行优化(原来的代码太多,太杂,不易于维护)。
优点:代码简洁,易于修改和阅读。
缺点:无法区分某一特殊按键在不同的系统状态下的按键时间(比如同一个键在不同的情况下可以长按3s或则5s),连按和长按不能同时存在(也可以加条件进行区分)。
复杂按键包括多个按键的单按事件、长按事件、连按事件、组合按键事件等。。。
单按事件在按下键松开时判定,其它按键情况在达到规定的时间后触发相应按键事件。
本程序为链接层程序,处理和识别按键驱动层扫描到的按键信息g_u8KeyValue。为了区分不同的按键与组合按键,g_u8KeyValue的每一位表示一个按键的按下情况。定义如下:
//宏定义各按键按下时的bit值 #define KEY_EVENT_NULL_CLICK 0x00 #define KEY_EVENT_CLOCK_CLICK 0x01 #define KEY_EVENT_DOWN_CLICK 0x02 #define KEY_EVENT_MODE_CLICK 0x04 #define KEY_EVENT_LOCK_CLICK 0x08 #define KEY_EVENT_ONOFF_CLICK 0x10 #define KEY_EVENT_SETTING_CLICK 0x20 #define KEY_EVENT_UP_CLICK 0x40 #define KEY_EVENT_TIMING_CLICK 0x80 #define KEY_EVENT_LONG_KEY_CLICK 0xff //长按标志 //组合键 #define KEY_EVENT_SETTING_UP_CLICK 0x60 #define KEY_EVENT_SETTING_ONOFF_CLICK 0x30 #define Key_EVENT_MODE_UP_DOWN_CLICK 0x46
转换后的具体按键信息保存于g_KeyEvent结构体中。其定义如下:
typedef enum
{
KeyValueNull = 0,
KeyValueOnOff = 1,
KeyValueMode = 2,
KeyValueClock = 3,
KeyValueSetting = 4,
KeyValueTiming = 5,
KeyValueLock = 6,
KeyValueUp = 7,
KeyValueDown = 8,
KeyValueOnOff1s = 9,
KeyValueLock1s = 10,
KeyValueMode3s = 11,
KeyValueClock3s = 12,
KeyValueSetting3s = 13,
KeyValueUp3s = 14,
KeyValueUp10s =15,
KeyValueSettingUp3s = 16,
KeyValueSettingOnOff5s = 17,
KeyValueModeUpDown3s = 18,
KeyValueUpLong = 19,
KeyValueDownLong = 20,
}KEY_EVENT_E;
extern KEY_EVENT_E g_KeyEvent; //枚举按键事件
/* Private define ------------------------------------------------------------*/
#define KEY_PRESS_TIME 80 //单按最小时间
#define KEY_SINGLE_TIME 1000 //单按最大时间
typedef struct
{
u16 short_time; //是否有短按标志(组合键没短按 短按时间另定义)
KEY_EVENT_E short_event;//短按事件
u16 long_t; //长按时间
KEY_EVENT_E long_event; //长按事件
u16 continue_t; //连按时间间隔,连按默认触发的是短按事件
}KEY_BUTTON_T;
//定义了系统中需要的按键组合
KEY_BUTTON_T key_long = {0, KeyValueNull, 0, KeyValueNull, 0}, //long中没有任何事件
key_up = {1, KeyValueUp, 0, KeyValueUp3s, 500},
key_set = {1, KeyValueSetting, 3000, KeyValueSetting3s, 0},
key_clock = {1, KeyValueClock, 3000, KeyValueClock3s, 0},
key_down = {1, KeyValueDown, 0, KeyValueNull, 500},
key_mode = {1, KeyValueMode, 3000, KeyValueMode3s, 0},
key_lock = {1, KeyValueLock, 1000, KeyValueLock1s, 0},
key_onoff = {1, KeyValueOnOff, 1000, KeyValueOnOff1s, 0},
key_timing = {1, KeyValueTiming, 0, KeyValueNull, 0},
key_set_up = {0, KeyValueNull, 3000, KeyValueSettingUp3s, 0},
key_set_onoff = {0, KeyValueNull, 5000, KeyValueSettingOnOff5s, 0},
key_mode_up_down = {0, KeyValueNull, 3000, KeyValueModeUpDown3s, 0};
/* Private functions ---------------------------------------------------------*/
static KEY_BUTTON_T rFindKeyObject(u8 key_event);
/* Public functions ----------------------------------------------------------*/
void Link_KeyValueGet(void);
void Link_KeyEventTrans(void);
/*******************************************************************************
#Function : Link_KeyValueGet
#Description : 获取键值(按键事件)
#Parameter : NULL
#Return : NULL
#AuthorAndData : huangzhigang 20141027
*******************************************************************************/
void Link_KeyValueGet(void)
{
vDrv_KeyScanning(); //驱动层按键扫描
Link_KeyEventTrans(); //链接层转换成按键事件(应用层处理)
}
/*******************************************************************************
#Function : Link_KeyEventTrans
#Description : 按键事件转换(短按、长按、连按、组合键) 长按事件只能有一个有效
#Parameter : NULL
#Return : NULL
#AuthorAndData : huangzhigang 20141027
*******************************************************************************/
void Link_KeyEventTrans(void)
{
static u8 s_u8ContinuePressFlag = 0; //连按标志 用于区分连按与短按事件
static KEY_BUTTON_T key_tmp; //临时的按键对象
static TIMER_T KeyDelayTime; //按键时间
static uint8_t KeyBackUp = KEY_EVENT_NULL_CLICK; //按键状态备份
TimeMs(&KeyDelayTime);
if(g_u8KeyValue) //有按键按下 则做相应的处理
{
if(KeyBackUp != g_u8KeyValue)
{
KeyDelayTime.DelayTime = 0;
KeyBackUp = g_u8KeyValue;
key_tmp = rFindKeyObject(g_u8KeyValue);
}
if(key_tmp.continue_t && (KeyDelayTime.DelayTime >= key_tmp.continue_t))
{
g_KeyEvent = key_tmp.short_event; //连按时间成立
KeyBackUp = KEY_EVENT_NULL_CLICK; //清楚备份 下次可以继续进入这里
s_u8ContinuePressFlag = 1;
}
else if(key_tmp.long_t &&(KeyDelayTime.DelayTime >= key_tmp.long_t))
{
g_KeyEvent = key_tmp.long_event; //长按事件成立
key_tmp = key_long;
}
}
else //无按键按下 如果是松开按键的时刻 则进行单按检测
{
if(s_u8ContinuePressFlag) //连按时不检测短按事件
{
s_u8ContinuePressFlag = 0;
KeyBackUp = KEY_EVENT_NULL_CLICK;
}
if(KeyBackUp && key_tmp.short_time) //有值则表示是松开的时刻
{
if(key_tmp.short_time &&(KeyDelayTime.DelayTime >= KEY_PRESS_TIME)
&& (KeyDelayTime.DelayTime <= KEY_SINGLE_TIME))
{
g_KeyEvent = key_tmp.short_event; //短按事件成立
}
KeyBackUp = KEY_EVENT_NULL_CLICK;
}
else //没有值 表示空闲状态 无键按下
{
KeyBackUp = KEY_EVENT_NULL_CLICK;
g_KeyEvent = KeyValueNull; //清除键值
}
KeyDelayTime.DelayTime = 0;
}
}
/*******************************************************************************
#Function : rFindKeyObject
#Description : 找到按键对象并返回 key_long 定义了一种空对象 系统不做处理
#Parameter : NULL
#Return : 当前按键所对应的按键对象
#AuthorAndData : huangzhigang 20141027
*******************************************************************************/
static KEY_BUTTON_T rFindKeyObject(u8 key_event) //找到按键对象
{
switch(key_event)
{
case KEY_EVENT_NULL_CLICK:
return key_long;
case KEY_EVENT_CLOCK_CLICK:
return key_clock;
case KEY_EVENT_DOWN_CLICK:
return key_down;
case KEY_EVENT_MODE_CLICK:
return key_mode;
case KEY_EVENT_LOCK_CLICK:
return key_lock;
case KEY_EVENT_ONOFF_CLICK:
return key_onoff;
case KEY_EVENT_SETTING_CLICK:
return key_set;
case KEY_EVENT_UP_CLICK:
return key_up;
case KEY_EVENT_TIMING_CLICK:
return key_timing;
case KEY_EVENT_SETTING_UP_CLICK:
return key_set_up;
case KEY_EVENT_SETTING_ONOFF_CLICK:
return key_set_onoff;
case Key_EVENT_MODE_UP_DOWN_CLICK:
return key_mode_up_down;
case KEY_EVENT_LONG_KEY_CLICK: //长按标志
return key_long;
default:
return key_long;
}
}
原文地址:http://blog.csdn.net/a656343072/article/details/40508947