首页 > 代码库 > 键值转换--复杂按键事件识别程序(链接层-优化版)

键值转换--复杂按键事件识别程序(链接层-优化版)

复杂按键事件识别程序(链接层-优化版)


本文相对于键值转换--复杂按键事件识别程序(链接层)文章中所述的按键事件转换程序进行优化(原来的代码太多,太杂,不易于维护)。

优点:代码简洁,易于修改和阅读。

缺点:无法区分某一特殊按键在不同的系统状态下的按键时间(比如同一个键在不同的情况下可以长按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;
   }
}






键值转换--复杂按键事件识别程序(链接层-优化版)