复杂按键事件识别程序(链接层-优化版)
本文相对于键值转换--复杂按键事件识别程序(链接层)文章中所述的按键事件转换程序进行优化(原来的代码太多,太杂,不易于维护)。
优点:代码简洁,易于修改和阅读。
缺点:无法区分某一特殊按键在不同的系统状态下的按键时间(比如同一个键在不同的情况下可以长按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