├── README.md ├── MyKeyDrive.h ├── MyQueue.h ├── demo.c ├── MyQueue.c └── MyKeyDrive.c /README.md: -------------------------------------------------------------------------------- 1 | # MyKeyDrive 2 | 按键驱动,支持按键的单击、连击、长按和连续触发的检测方式 3 | 4 | # 使用方法 5 | 见demo.c 6 | -------------------------------------------------------------------------------- /MyKeyDrive.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file MyKeyDrive.h 3 | * @author MGDG 4 | * @brief 注册一个按键,注册时选择按键支持的检测方式,如单击、双击、长按、连续触发、长按时间、连续触发间隔。 5 | * 按键消息用到了队列驱动。 6 | * 注意:以下所有接口都是线程不安全的,在实时操作系统中使用这些接口时必须自己加锁保护。 7 | * @version 0.1 8 | * @date 2017-09-04 9 | * 10 | * @copyright 11 | * 12 | */ 13 | 14 | #ifndef _MY_KEY_DRIVER_H_ 15 | #define _MY_KEY_DRIVER_H_ 16 | 17 | #include 18 | 19 | #ifdef __cplusplus 20 | extern "C" { 21 | #endif 22 | 23 | #define MYKEY_EVENT_CLICK ((unsigned char)0x01U) /** 单击 */ 24 | #define MYKEY_EVENT_DBLCLICK ((unsigned char)0x02U) /** 双击 */ 25 | #define MYKEY_EVENT_LONG_PRESS ((unsigned char)0x04U) /** 长按 */ 26 | #define MYKEY_EVENT_REPEAT ((unsigned char)0x08U) /** 连续触发、重复触发 */ 27 | #define MYKEY_EVENT_RELASE ((unsigned char)0x10U) /** 松开 */ 28 | 29 | /** 30 | * @brief 按键句柄 31 | * 32 | */ 33 | typedef void *MyKeyHandle; 34 | 35 | /** 36 | * @brief 按键状态读取函数,按下返回1,弹起返回0 37 | * 38 | */ 39 | typedef int (*KeyStatusFunc)(void); 40 | 41 | /** 42 | * @brief 初始化按键扫描器 43 | * 44 | * @return int 0:success, other:failed 45 | */ 46 | int MyKey_Init(void); 47 | 48 | /** 49 | * @brief 注销按键扫描器 50 | * 51 | * @return int 0:success, other:failed 52 | */ 53 | int MyKey_Deinit(void); 54 | 55 | /** 56 | * @brief 注册一个按键 57 | * 58 | * @param Key 按键句柄 59 | * @param func 按键状态读取函数,按下返回true,弹起返回false 60 | * @param Mode 按键功能,按键事件集合 61 | * @param RepeatSpeed 长按时连续触发周期,单位ms 62 | * @param LongPressTime 长按时间 63 | * @return int 0:success, other:failed 64 | */ 65 | int MyKey_Register(MyKeyHandle *Key, KeyStatusFunc func, unsigned char Mode, size_t RepeatSpeed, size_t LongPressTime); 66 | 67 | /** 68 | * @brief 卸载一个按键 69 | * 70 | * @param Key 按键句柄 71 | * @return int 0:success, other:failed 72 | */ 73 | int MyKey_Unregister(MyKeyHandle *Key); 74 | 75 | /** 76 | * @brief 按键扫描,需要周期调用 77 | * 78 | * @param InterVal 调用间隔,单位ms 79 | */ 80 | void MyKey_Scan(size_t InterVal); 81 | 82 | /** 83 | * @brief 打印出已注册的按键ID 84 | * 85 | */ 86 | void MyKey_PrintKeyInfo(void); 87 | 88 | /** 89 | * @brief 从按键消息队列中获取一个按键消息 90 | * 91 | * @param KeyID 按键句柄 92 | * @param KeyEvent 按键事件,单击、双击还是长按等等 93 | * @param KeyClickCount 按键点击次数 94 | * @return int 0:success, other:failed 95 | */ 96 | int MyKey_Read(MyKeyHandle *KeyID, unsigned char *KeyEvent, unsigned char *KeyClickCount); 97 | 98 | #ifdef __cplusplus 99 | } 100 | #endif 101 | 102 | #endif 103 | -------------------------------------------------------------------------------- /MyQueue.h: -------------------------------------------------------------------------------- 1 | /** 2 | * @file MyQueue.h 3 | * @author mgdg 4 | * @brief 队列驱动文件 5 | * @version v1.1 6 | * @date 2019-09-12 7 | * @remark 创建可以存放任意元素的环形队列,包含了入队出队等基本操作 8 | */ 9 | 10 | #ifndef __MYQUEUE_H 11 | #define __MYQUEUE_H 12 | 13 | #include 14 | #include 15 | 16 | /*队列句柄*/ 17 | typedef struct myQueue *myQueueHandle_t; 18 | 19 | /** 20 | * @brief 创建队列 21 | * @param queue_len:队列长度,存储的元素个数 22 | * @param item_size:队列单个元素的大小,以字节为单位 23 | 24 | * @return myQueueHandle_t:队列句柄 25 | * @remark 26 | */ 27 | myQueueHandle_t myQueueCreate(size_t queue_len, size_t item_size); 28 | 29 | /** 30 | * @brief 删除队列 31 | * @param queue:队列句柄 32 | 33 | * @return void 34 | * @remark 35 | */ 36 | void myQueueDelete(myQueueHandle_t queue); 37 | 38 | /** 39 | * @brief 获取队列已存放数据个数 40 | * @param queue:队列句柄 41 | * 42 | * @return size_t:队列数据个数 43 | * @remark 44 | */ 45 | size_t myQueueNum(const myQueueHandle_t queue); 46 | 47 | /** 48 | * @brief 获取队列剩余可存放数据个数 49 | * @param queue:队列句柄 50 | * 51 | * @return size_t:队列剩余可存放数据个数 52 | * @remark 53 | */ 54 | size_t myQueueLeftNum(const myQueueHandle_t queue); 55 | 56 | /** 57 | * @brief 获取队列总容量 58 | * @param queue:队列句柄 59 | * 60 | * @return size_t:队列容量 61 | * @remark 62 | */ 63 | size_t myQueueCapacity(const myQueueHandle_t queue); 64 | 65 | /** 66 | * @brief 队列是否已满 67 | * @param queue:队列句柄 68 | * 69 | * @return bool:队列满状态 70 | * @remark 71 | */ 72 | bool myQueueIsFull(const myQueueHandle_t queue); 73 | 74 | /** 75 | * @brief 队列是否已空 76 | * @param *queue:队列句柄 77 | * 78 | * @return bool:队列空状态 79 | * @remark 80 | */ 81 | bool myQueueIsEmpty(const myQueueHandle_t queue); 82 | 83 | /** 84 | * @brief 将指定个数的数据放入队列 85 | * @param queue:队列句柄 86 | * @param *buf:数据指针 87 | * @param num:数据个数 88 | * 89 | * @return bool:是否放入成功 90 | * @remark 91 | */ 92 | bool myQueuePut(myQueueHandle_t queue, const void *buf, size_t num); 93 | 94 | /** 95 | * @brief 从队列中取出指定个数的数据 96 | * @param queue:队列句柄 97 | * @param *buf:数据指针 98 | * @param num:取出的队列个数 99 | * 100 | * @return bool:是否取出成功 101 | * @remark 102 | */ 103 | bool myQueueGet(myQueueHandle_t queue, void *buf, size_t num); 104 | 105 | /** 106 | * @brief 从指定偏移位置开始,从队列中获取指定个数的数据,但是不弹出数据 107 | * @param queue:队列句柄 108 | * @param *buf 109 | * @param num:数据长度 110 | * @param offset:偏移位置 111 | * 112 | * @return bool:是否获取成功 113 | * @remark 114 | */ 115 | bool myQueuePeek(const myQueueHandle_t queue, void *buf, size_t num, size_t offset); 116 | 117 | /** 118 | * @brief 弹掉指定个数的数据 119 | * @param queue:队列句柄 120 | * @param num:长度 121 | * 122 | * @return bool:是否弹出成功 123 | * @remark 124 | */ 125 | bool myQueuePop(myQueueHandle_t queue, size_t num); 126 | 127 | /** 128 | * @brief POP所有数据 129 | * @param queue:队列句柄 130 | * 131 | * @return bool:是否弹出成功 132 | * @remark 133 | */ 134 | bool myQueuePopAll(myQueueHandle_t queue); 135 | 136 | #endif 137 | -------------------------------------------------------------------------------- /demo.c: -------------------------------------------------------------------------------- 1 | /** 2 | ****************************************************************************** 3 | * @file demo.c 4 | * @author mgdg 5 | * @version V1.0.0 6 | * @date 2017-09-04 7 | * @brief demo 8 | ****************************************************************************** 9 | **/ 10 | #include "stdio.h" 11 | #include "MyKeyDrive.h" 12 | 13 | //声明两个按键 14 | static MyKeyHandle key1, key2; 15 | 16 | 17 | // void __定时器中断或者周期性任务__(void) 18 | // { 19 | // size_t CycleTime = 中断时间或者任务周期,单位ms; 20 | // MyKey_Scan(CycleTime); 21 | // } 22 | 23 | 24 | int GetKeyStatus_key1(void) 25 | { 26 | //返回按键按下状态 27 | return 0; 28 | } 29 | 30 | 31 | int GetKeyStatus_key2(void) 32 | { 33 | //返回按键按下状态 34 | return 0; 35 | } 36 | 37 | 38 | //注册按键 39 | static void KeyRegister(void) 40 | { 41 | //注册按键1,支持单击和长按,长按时间为1000ms 42 | if (MyKey_Register(&key1, GetKeyStatus_key1, MYKEY_EVENT_CLICK | MYKEY_EVENT_LONG_PRESS, 100, 1000) == 0) { 43 | printf("key1 register successed\r\n"); 44 | } else { 45 | printf("key1 register failed\r\n"); 46 | } 47 | 48 | //注册按键2,支持单击、长按和连续触发,长按时间为1000ms,连续触发间隔为100ms 49 | if (MyKey_Register(&key2, GetKeyStatus_key2, MYKEY_EVENT_CLICK | MYKEY_EVENT_DBLCLICK | MYKEY_EVENT_LONG_PRESS | MYKEY_EVENT_REPEAT, 100, 1000) == 0) { 50 | printf("key2 register successed\r\n"); 51 | } else { 52 | printf("key2 register failed\r\n"); 53 | } 54 | } 55 | 56 | 57 | //按键1事件处理函数 58 | static void Key1Process(size_t KeyEvent, size_t KeyClickCount) 59 | { 60 | switch (KeyEvent) { 61 | case MYKEY_EVENT_CLICK: { 62 | //按键单击处理 63 | printf("key1 click, count %ld\r\n", KeyClickCount); 64 | } 65 | break; 66 | 67 | case MYKEY_EVENT_DBLCLICK: { 68 | //按键双击处理 69 | printf("key1 double click, count %ld\r\n", KeyClickCount); 70 | 71 | //连续点击三次,卸载按键2 72 | if (KeyClickCount == 3) { 73 | if (MyKey_Unregister(&key2) == 0) { 74 | printf("key2 unregister success\r\n"); 75 | } else { 76 | printf("key2 unregister failed\r\n"); 77 | } 78 | } 79 | //连续点击四次,注册按键2 80 | else if (KeyClickCount == 4) { 81 | if (MyKey_Register(&key2, GetKeyStatus_key2, MYKEY_EVENT_CLICK | MYKEY_EVENT_DBLCLICK | MYKEY_EVENT_LONG_PRESS | MYKEY_EVENT_REPEAT, 100, 1000) == 0) { 82 | printf("key2 register successed\r\n"); 83 | } else { 84 | printf("key2 register failed\r\n"); 85 | } 86 | } 87 | //连续点击5次,卸载按键1,注意,此处将自己卸载了,卸载之后这个按键就没反应了 88 | else if (KeyClickCount == 5) { 89 | if (MyKey_Unregister(&key1) == 0) { 90 | printf("key1 unregister success\r\n"); 91 | } else { 92 | printf("key1 unregister failed\r\n"); 93 | } 94 | } 95 | 96 | } 97 | break; 98 | 99 | case MYKEY_EVENT_LONG_PRESS: { 100 | //按键长按处理 101 | printf("key1 long press, count %ld\r\n", KeyClickCount); 102 | 103 | //长按打印出已经注册的按键ID 104 | MyKey_PrintKeyInfo(); 105 | } 106 | break; 107 | 108 | case MYKEY_EVENT_REPEAT: { 109 | //按键连续触发处理 110 | printf("key1 repeat, count %ld\r\n", KeyClickCount); 111 | } 112 | break; 113 | 114 | case MYKEY_EVENT_RELASE: { 115 | printf("key1 relase\r\n"); 116 | } 117 | break; 118 | 119 | default: 120 | printf("undefine key message\r\n"); 121 | break; 122 | } 123 | } 124 | 125 | //按键2事件处理函数 126 | static void Key2Process(size_t KeyEvent, size_t KeyClickCount) 127 | { 128 | switch (KeyEvent) { 129 | case MYKEY_EVENT_CLICK: { 130 | //按键单击处理 131 | printf("key2 click, count %ld\r\n", KeyClickCount); 132 | } 133 | break; 134 | 135 | case MYKEY_EVENT_DBLCLICK: { 136 | //按键双击处理 137 | printf("key2 double click, count %ld\r\n", KeyClickCount); 138 | } 139 | break; 140 | 141 | case MYKEY_EVENT_LONG_PRESS: { 142 | //按键长按处理 143 | printf("key2 long press, count %ld\r\n", KeyClickCount); 144 | } 145 | break; 146 | 147 | case MYKEY_EVENT_REPEAT: { 148 | //按键连续触发处理 149 | printf("key2 repeat, count %ld\r\n", KeyClickCount); 150 | } 151 | break; 152 | 153 | case MYKEY_EVENT_RELASE: { 154 | printf("key2 relase\r\n"); 155 | } 156 | break; 157 | 158 | default: 159 | printf("undefine key message\r\n"); 160 | break; 161 | } 162 | } 163 | 164 | //主循环调用,从按键消息队列中取出消息并进行处理 165 | void KeyProcess(void) 166 | { 167 | MyKeyHandle KeyID; 168 | unsigned char KeyEvent; 169 | unsigned char KeyCliclCount; 170 | while (MyKey_Read(&KeyID, &KeyEvent, &KeyCliclCount) == 0) { 171 | if (KeyID == key1) { 172 | Key1Process(KeyEvent, KeyCliclCount); 173 | } else if (KeyID == key2) { 174 | Key2Process(KeyEvent, KeyCliclCount); 175 | } 176 | } 177 | } 178 | 179 | 180 | 181 | int main(void) 182 | { 183 | MyKey_Init(); 184 | KeyRegister(); 185 | 186 | while (1) { 187 | KeyProcess(); 188 | } 189 | } -------------------------------------------------------------------------------- /MyQueue.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file MyQueue.c 3 | * @author mgdg 4 | * @brief 队列驱动文件 5 | * @version v1.1 6 | * @date 2019-09-12 7 | * @remark 创建可以存放任意元素的环形队列,包含了入队出队等基本操作 8 | */ 9 | 10 | /*只有一个生产者和消费者的情况下不需要锁保护*/ 11 | //#define MYQUEUE_USE_LOCK 12 | 13 | #include "MyQueue.h" 14 | #include 15 | #include 16 | #include 17 | 18 | #ifdef MYQUEUE_USE_LOCK 19 | #include "freertos/FreeRTOS.h" 20 | #include "freertos/semphr.h" 21 | 22 | #define MYQUEUE_API_CREATELOCK(v) do{(v)->lock = xSemaphoreCreateMutex();assert((v)->lock);}while(0); 23 | #define MYQUEUE_API_DELETELOCK(v) do{vSemaphoreDelete((v)->lock);}while(0); 24 | #define MYQUEUE_API_LOCK(v) do{xSemaphoreTake((v)->lock, portMAX_DELAY);}while(0); 25 | #define MYQUEUE_API_UNLOCK(v) do{xSemaphoreGive((v)->lock);}while(0); 26 | #else 27 | #define MYQUEUE_API_CREATELOCK(v) 28 | #define MYQUEUE_API_DELETELOCK(v) 29 | #define MYQUEUE_API_LOCK(v) 30 | #define MYQUEUE_API_UNLOCK(v) 31 | #endif 32 | 33 | #define debug_i(format,...) /*printf(format"\n",##__VA_ARGS__)*/ 34 | #define NUM_IN_QUEUE(v) ((((v)->front) <= ((v)->rear))?(((v)->rear)-((v)->front)):(((v)->len)-((v)->front)+((v)->rear))) 35 | #define LFET_NUM_IN_QUEUE(v) ((((v)->front) <= ((v)->rear))?((((v)->len)-1)-(((v)->rear)-((v)->front))):(((v)->front)-((v)->rear)-1)) 36 | 37 | struct myQueue { 38 | void *buffer; /*数据缓冲区*/ 39 | size_t len; /*队列长度*/ 40 | size_t size; /*单个数据大小(单位 字节)*/ 41 | size_t front; /*数据头,指向下一个空闲存放地址*/ 42 | size_t rear; /*数据尾,指向第一个数据*/ 43 | #ifdef MYQUEUE_USE_LOCK 44 | SemaphoreHandle_t lock; /*保护锁*/ 45 | #endif 46 | }; 47 | 48 | myQueueHandle_t myQueueCreate(size_t queue_len, size_t item_size) 49 | { 50 | if ((0 == queue_len) || (0 == item_size)) { 51 | debug_i("create queue,len=%d,ItemSize=%d", queue_len, item_size); 52 | return NULL; 53 | } 54 | myQueueHandle_t queue = calloc(1, sizeof(struct myQueue)); 55 | assert(queue); 56 | queue->size = item_size; 57 | queue->len = queue_len; 58 | queue->buffer = malloc((queue->size) * (queue->len)); 59 | assert(queue->buffer); 60 | queue->front = queue->rear = 0; 61 | MYQUEUE_API_CREATELOCK(queue); 62 | MYQUEUE_API_UNLOCK(queue); 63 | return queue; 64 | } 65 | 66 | void myQueueDelete(myQueueHandle_t queue) 67 | { 68 | if (NULL == queue) { 69 | return; 70 | } 71 | MYQUEUE_API_LOCK(queue); 72 | free(queue->buffer); 73 | MYQUEUE_API_UNLOCK(queue); 74 | MYQUEUE_API_DELETELOCK(queue); 75 | free(queue); 76 | } 77 | 78 | size_t myQueueNum(const myQueueHandle_t queue) 79 | { 80 | if (NULL == queue) { 81 | return 0; 82 | } 83 | MYQUEUE_API_LOCK(queue); 84 | size_t num_in_queue = NUM_IN_QUEUE(queue); 85 | MYQUEUE_API_UNLOCK(queue); 86 | return num_in_queue; 87 | } 88 | 89 | size_t myQueueLeftNum(const myQueueHandle_t queue) 90 | { 91 | if (NULL == queue) { 92 | return 0; 93 | } 94 | MYQUEUE_API_LOCK(queue); 95 | size_t left_num_in_queue = LFET_NUM_IN_QUEUE(queue); 96 | MYQUEUE_API_UNLOCK(queue); 97 | return left_num_in_queue; 98 | } 99 | 100 | size_t myQueueCapacity(const myQueueHandle_t queue) 101 | { 102 | return (NULL == queue) ? 0 : (queue->len - 1); 103 | } 104 | 105 | bool myQueueIsFull(const myQueueHandle_t queue) 106 | { 107 | if (NULL == queue) { 108 | return false; 109 | } 110 | return (myQueueNum(queue) == ((queue->len) - 1)); 111 | } 112 | 113 | bool myQueueIsEmpty(const myQueueHandle_t queue) 114 | { 115 | return (NULL == queue) ? false : (0 == myQueueNum(queue)); 116 | } 117 | 118 | static __attribute__((always_inline)) inline size_t minn(size_t a, size_t b) 119 | { 120 | return a < b ? a : b; 121 | } 122 | 123 | static void *myQueue_memcpy(void *dst, const void *src, size_t n) 124 | { 125 | return memcpy(dst, src, n); 126 | } 127 | 128 | bool myQueuePut(myQueueHandle_t queue, const void *buf, size_t num) 129 | { 130 | if ((NULL == queue) || (NULL == queue->buffer) || (NULL == buf) || (0 == num)) { 131 | debug_i("put queue=%p,buf=%p,num=%d", queue, buf, num); 132 | return false; 133 | } 134 | bool rt = false; 135 | MYQUEUE_API_LOCK(queue); 136 | size_t left_num_in_queue = LFET_NUM_IN_QUEUE(queue); 137 | if (num <= left_num_in_queue) { 138 | size_t templen = minn((queue->len) - (queue->rear), num); 139 | if (templen > 0) { 140 | myQueue_memcpy((char *)(queue->buffer) + (queue->rear) * (queue->size), buf, templen * (queue->size)); 141 | } 142 | if (num > templen) { 143 | myQueue_memcpy((char *)(queue->buffer), (char *)buf + templen * (queue->size), (num - templen) * (queue->size)); 144 | } 145 | queue->rear = (queue->rear + num) % (queue->len); 146 | // p->rear += num; 147 | // if (p->rear >= p->len) { 148 | // p->rear -= p->len; 149 | // } 150 | rt = true; 151 | } else { 152 | debug_i("put failed, num=%d,left=%d,front=%d,rear=%d,len=%d", num, left_num_in_queue, queue->front, queue->rear, queue->len); 153 | } 154 | MYQUEUE_API_UNLOCK(queue); 155 | return rt; 156 | } 157 | 158 | bool myQueueGet(myQueueHandle_t queue, void *buf, size_t num) 159 | { 160 | if ((NULL == queue) || (NULL == queue->buffer) || (NULL == buf) || (0 == num)) { 161 | debug_i("get queue=%p,buf=%p,num=%d", queue, buf, num); 162 | return false; 163 | } 164 | bool rt = false; 165 | MYQUEUE_API_LOCK(queue); 166 | size_t num_in_queue = NUM_IN_QUEUE(queue); 167 | if (num <= num_in_queue) { 168 | size_t templen = minn((queue->len) - (queue->front), num); 169 | if (templen > 0) { 170 | myQueue_memcpy((char *)buf, (char *)(queue->buffer) + (queue->front) * (queue->size), templen * (queue->size)); 171 | } 172 | if (num > templen) { 173 | myQueue_memcpy((char *)buf + templen * (queue->size), queue->buffer, (num - templen) * (queue->size)); 174 | } 175 | queue->front = (queue->front + num) % (queue->len); 176 | // p->front += num; 177 | // if (p->front >= p->len) { 178 | // p->front -= p->len; 179 | // } 180 | rt = true; 181 | } else { 182 | debug_i("get failed, num=%d,inQueue=%d,front=%d,rear=%d,len=%d", num, num_in_queue, queue->front, queue->rear, queue->len); 183 | } 184 | MYQUEUE_API_UNLOCK(queue); 185 | return rt; 186 | } 187 | 188 | bool myQueuePeek(const myQueueHandle_t queue, void *buf, size_t num, size_t offset) 189 | { 190 | if ((NULL == queue) || (NULL == queue->buffer) || (NULL == buf) || (0 == num)) { 191 | debug_i("peek queue=%p,buf=%p,num=%d", queue, buf, num); 192 | return false; 193 | } 194 | bool rt = false; 195 | MYQUEUE_API_LOCK(queue); 196 | size_t num_in_queue = NUM_IN_QUEUE(queue); 197 | if ((offset + num) <= num_in_queue) { 198 | size_t temp_front = (queue->front) + offset; 199 | size_t templen = minn((queue->len) - temp_front, num); 200 | if (templen > 0) { 201 | myQueue_memcpy((char *)buf, (char *)(queue->buffer) + temp_front * (queue->size), templen * (queue->size)); 202 | } 203 | if (num > templen) { 204 | myQueue_memcpy((char *)buf + templen * (queue->size), queue->buffer, (num - templen) * (queue->size)); 205 | } 206 | rt = true; 207 | } else { 208 | debug_i("get failed, num=%d,inQueue=%d,front=%d,rear=%d,len=%d", num, num_in_queue, queue->front, queue->rear, queue->len); 209 | } 210 | MYQUEUE_API_UNLOCK(queue); 211 | return rt; 212 | } 213 | 214 | bool myQueuePop(myQueueHandle_t queue, size_t num) 215 | { 216 | if ((NULL == queue) || (0 == num)) { 217 | debug_i("pop queue=%p,num=%d", queue, num); 218 | return false; 219 | } 220 | bool rt = true; 221 | MYQUEUE_API_LOCK(queue); 222 | size_t num_in_queue = NUM_IN_QUEUE(queue); 223 | if (num <= num_in_queue) { 224 | queue->front = (queue->front + num) % (queue->len); 225 | } else { 226 | rt = false; 227 | debug_i("pop failed, num=%d,inQueue=%d,front=%d,rear=%d,len=%d", num, num_in_queue, queue->front, queue->rear, queue->len); 228 | } 229 | MYQUEUE_API_UNLOCK(queue); 230 | return rt; 231 | } 232 | 233 | bool myQueuePopAll(myQueueHandle_t queue) 234 | { 235 | if (NULL == queue) { 236 | return false; 237 | } 238 | MYQUEUE_API_LOCK(queue); 239 | queue->front = queue->rear; 240 | MYQUEUE_API_UNLOCK(queue); 241 | return true; 242 | } 243 | 244 | -------------------------------------------------------------------------------- /MyKeyDrive.c: -------------------------------------------------------------------------------- 1 | /** 2 | * @file MyKeyDrive.c 3 | * @author MGDG 4 | * @brief 注册一个按键,注册时选择按键支持的检测方式,如单击、双击、长按、连续触发、长按时间、连续触发间隔。 5 | * 按键消息用到了队列驱动 6 | * @version 0.1 7 | * @date 2017-09-04 8 | * 9 | * @copyright 10 | * 11 | */ 12 | 13 | #include "stdio.h" 14 | #include "MyKeyDrive.h" 15 | #include "MyQueue.h" 16 | 17 | #define KEY_EVENT_MSG_QUEUE_SIZE (10) /** 按键事件消息队列长度 */ 18 | #define KEY_FILTER_TIME (30) /** 消抖滤波时间,单位ms */ 19 | #define KEY_DBL_INTERVAL (250) /** 双击最大间隔时间,单位ms */ 20 | 21 | //按键状态 22 | typedef enum { 23 | KEYSTATE_RELASE = 0, /** 按键松开 */ 24 | KEYSTATE_PRESS_SD, /** 按键按下,支持单击和双击模式 */ 25 | KEYSTATE_PRESS_D, /** 按键按下,支持双击模式 */ 26 | KEYSTATE_PRESS_S, /** 按键按下,支持单击模式 */ 27 | KEYSTATE_PRESS_LR, /** 按键按下,支持长按和连续触发模式 */ 28 | KEYSTATE_PRESS_L, /** 按键按下,支持长按模式 */ 29 | KEYSTATE_PRESS_R, /** 按键按下,支持连续触发模式 */ 30 | } myKeyState_t; 31 | 32 | //按键消息结构体定义 33 | typedef struct { 34 | MyKeyHandle KeyID; /** 按键ID */ 35 | unsigned char KeyEvent; /** 按键事件 */ 36 | unsigned char KeyClickCount; /** 按键次数计数 */ 37 | } myKeyMsg_t; 38 | 39 | //按键属性 40 | typedef struct myKey { 41 | MyKeyHandle KeyID; /** 按键对应的ID,每个按键对应唯一的ID */ 42 | KeyStatusFunc KeyStatus; /** 按键按下的判断函数,1表示按下,初始化时指定 */ 43 | struct myKey *Next_Key; /** 下一个按键 */ 44 | size_t PressTime; /** 按键按下持续时间(ms) */ 45 | size_t FilterCount; /** 消抖滤波计时(ms) */ 46 | size_t RepeatSpeed; /** 连续触发周期(ms),初始化时指定 */ 47 | size_t RepeatCount; /** 连续触发周期计时(ms) */ 48 | size_t LongPressTime; /** 长按时间,超过该时间认为是长按(ms),初始化时指定 */ 49 | size_t DblClkCount; /** 双击间隔时间计时(ms) */ 50 | 51 | int keyState; /** 消抖后的按键状态,1表示按下,0表示弹起 */ 52 | unsigned char ClickCount; /** 连按次数计数 */ 53 | unsigned char Mode; /** 按键支持的检测模式,初始化时指定 */ 54 | myKeyState_t State; /** 按键当前状态 */ 55 | } myKey_t; 56 | 57 | static myKey_t *MyKeyList = NULL; /** 已注册的按键链表 */ 58 | static myQueueHandle_t KeyBufQueue = NULL; /** 按键事件队列 */ 59 | static volatile int MyKeyLock = 0; /** TODO: 保护锁,无操作系统环境下需要实现 */ 60 | 61 | static bool KeyList_Put(myKey_t **ListHead, MyKeyHandle KeyID) 62 | { 63 | myKey_t *p = NULL; 64 | myKey_t *q = NULL; 65 | 66 | if (KeyID == NULL) { 67 | return false; 68 | } 69 | 70 | if (*ListHead == NULL) { //链表为空 71 | p = (myKey_t *)KeyID; 72 | p->KeyID = KeyID; 73 | p->Next_Key = NULL; 74 | *ListHead = p; 75 | return true; 76 | } 77 | 78 | q = *ListHead; 79 | p = (*ListHead)->Next_Key; 80 | while (p != NULL) { 81 | if (q->KeyID == KeyID) { //链表中已经存在 82 | return true; 83 | } 84 | q = p; 85 | p = p->Next_Key; 86 | } 87 | 88 | //链表中不存在,链接进去 89 | p = (myKey_t *)KeyID; 90 | //初始化节点数据 91 | p->KeyID = KeyID; 92 | p->Next_Key = NULL; 93 | //加入链表 94 | q->Next_Key = p; 95 | return true; 96 | } 97 | 98 | 99 | int MyKey_Init(void) 100 | { 101 | KeyBufQueue = myQueueCreate(KEY_EVENT_MSG_QUEUE_SIZE, sizeof(myKeyMsg_t)); 102 | if (KeyBufQueue) { 103 | printf("Key message queue create success, queue len %d\r\n", KEY_EVENT_MSG_QUEUE_SIZE); 104 | return 0; 105 | } 106 | printf("Key message queue create failed\r\n"); 107 | return -1; 108 | } 109 | 110 | int MyKey_Deinit(void) 111 | { 112 | myQueueDelete(KeyBufQueue); 113 | myKey_t *p; 114 | while (MyKeyList) { 115 | p = MyKeyList; 116 | MyKeyList = MyKeyList->Next_Key; 117 | free(p); 118 | } 119 | } 120 | 121 | static bool KeyMessage_Put(MyKeyHandle KeyID, unsigned char KeyEvent, unsigned char ClickCount) 122 | { 123 | myKeyMsg_t temp; 124 | temp.KeyID = KeyID; 125 | temp.KeyEvent = KeyEvent; 126 | temp.KeyClickCount = ClickCount; 127 | return myQueuePut(KeyBufQueue, &temp, 1); 128 | } 129 | 130 | int MyKey_Read(MyKeyHandle *KeyID, unsigned char *KeyEvent, unsigned char *KeyClickCount) 131 | { 132 | myKeyMsg_t temp; 133 | if ( myQueueGet(KeyBufQueue, &temp, 1)) { 134 | *KeyID = temp.KeyID; 135 | *KeyEvent = temp.KeyEvent; 136 | *KeyClickCount = temp.KeyClickCount; 137 | return 0; 138 | } 139 | return -1; 140 | } 141 | 142 | int MyKey_Register(MyKeyHandle *Key, KeyStatusFunc func, unsigned char Mode, size_t RepeatSpeed, size_t LongPressTime) 143 | { 144 | //先检查按键是否已经被注册过了 145 | myKey_t *p = MyKeyList; 146 | while (p != NULL) { 147 | if (p->KeyStatus == func) { 148 | return -1; 149 | } 150 | p = p->Next_Key; 151 | } 152 | 153 | myKey_t *NewKey = (myKey_t *)malloc(sizeof(myKey_t)); 154 | if (NewKey == NULL) { 155 | return -1; 156 | } 157 | NewKey->KeyStatus = func; 158 | NewKey->KeyID = (MyKeyHandle)NewKey; 159 | NewKey->Mode = Mode; 160 | NewKey->State = KEYSTATE_RELASE; 161 | NewKey->PressTime = 0; 162 | NewKey->FilterCount = 0; 163 | NewKey->RepeatSpeed = RepeatSpeed; 164 | NewKey->RepeatCount = 0; 165 | NewKey->LongPressTime = LongPressTime; 166 | NewKey->ClickCount = 0; 167 | NewKey->keyState = 0; 168 | NewKey->DblClkCount = 0; 169 | NewKey->Next_Key = NULL; 170 | 171 | if (KeyList_Put(&MyKeyList, NewKey)) { 172 | *Key = (MyKeyHandle)NewKey; 173 | return 0; 174 | } else { 175 | free(NewKey); 176 | return -1; 177 | } 178 | } 179 | 180 | int MyKey_Unregister(MyKeyHandle *Key) 181 | { 182 | myKey_t *TempNode = (myKey_t *)(*Key); 183 | myKey_t *p = NULL; 184 | myKey_t *q = MyKeyList; 185 | 186 | if (TempNode == NULL) { //无效指定节点 187 | return -1; 188 | } 189 | 190 | //查找是否存在 191 | while (q != NULL) { 192 | if (q->KeyID == *Key) { 193 | break; 194 | } 195 | q = q->Next_Key; 196 | } 197 | if (q == NULL) { 198 | return -1; 199 | } 200 | q = MyKeyList; 201 | 202 | //存在 203 | if (MyKeyList == NULL) { //无效链表头节点 204 | if (TempNode->KeyID == *Key) { 205 | free(TempNode); //释放掉被删除的节点 206 | *Key = NULL; 207 | return 0; 208 | } 209 | return -1; 210 | } 211 | 212 | while (q != TempNode && q != NULL) { 213 | p = q; 214 | q = q->Next_Key; 215 | } 216 | 217 | if (q != TempNode) { //链表中不存在该节点 218 | if (TempNode->KeyID == *Key) { 219 | free(TempNode); //释放掉被删除的节点 220 | *Key = NULL; 221 | return 0; 222 | } 223 | return -1; 224 | } 225 | 226 | if (q->KeyID == *Key) { 227 | if (q == MyKeyList) { //删除的是第一个节点 228 | MyKeyList = MyKeyList->Next_Key; 229 | } else { 230 | p->Next_Key = q->Next_Key; 231 | } 232 | free(q); //释放掉被删除的节点 233 | *Key = NULL; 234 | return 0; 235 | } 236 | return -1; 237 | } 238 | 239 | void MyKey_PrintKeyInfo(void) 240 | { 241 | myKey_t *q = MyKeyList; 242 | if (q == NULL) { 243 | printf("NO KEY\r\n"); 244 | } 245 | while (q != NULL) { 246 | printf("KEY ID : %p\r\n", q->KeyID); 247 | q = q->Next_Key; 248 | } 249 | } 250 | 251 | void MyKey_Scan(size_t InterVal) 252 | { 253 | myKey_t *p = MyKeyList; 254 | while (p != NULL) { 255 | if (p->KeyStatus() == 1) { 256 | //按下消抖 257 | if (p->FilterCount < KEY_FILTER_TIME) { 258 | p->FilterCount = KEY_FILTER_TIME; 259 | } else if (p->FilterCount < (KEY_FILTER_TIME + KEY_FILTER_TIME)) { 260 | p->FilterCount += InterVal; 261 | } else { 262 | //消抖时间已到,上一次状态为弹起 263 | if (p->keyState == 0) { 264 | p->keyState = 1; 265 | //第一次按下 266 | if (p->State == KEYSTATE_RELASE) { 267 | p->ClickCount = 1; 268 | p->DblClkCount = 0; //双击等待时间清除 269 | p->PressTime = 0; //长按计时复位 270 | p->RepeatCount = 0; //连续触发计时复位 271 | //支持单击和双击 272 | if ( ((p->Mode)&MYKEY_EVENT_CLICK) && ((p->Mode)&MYKEY_EVENT_DBLCLICK) ) { 273 | p->State = KEYSTATE_PRESS_SD; 274 | } else if ((p->Mode)&MYKEY_EVENT_CLICK) { 275 | //仅支持单击 276 | p->State = KEYSTATE_PRESS_S; 277 | //即不支持长按,也不支持连续触发 278 | if (!( ((p->Mode)&MYKEY_EVENT_LONG_PRESS) || ((p->Mode)&MYKEY_EVENT_REPEAT) )) { 279 | //发送单击按键消息 280 | KeyMessage_Put(p->KeyID, MYKEY_EVENT_CLICK, p->ClickCount); 281 | } 282 | } else if ((p->Mode)&MYKEY_EVENT_DBLCLICK) { 283 | //仅支持双击 284 | p->State = KEYSTATE_PRESS_D; 285 | } 286 | } else if (p->State == KEYSTATE_PRESS_SD || p->State == KEYSTATE_PRESS_D) { 287 | //上一次为支持双击按下(支持单击和双击、仅支持双击) 288 | p->DblClkCount = 0; //连击间隔时间清0 289 | //连续按次数加1 290 | if (p->ClickCount < 255) { 291 | p->ClickCount++; 292 | } 293 | } 294 | } else { 295 | //持续按住 296 | //同时使能长按和连续触发,长按时间到达之后开始连续触发,不发送长按消息 297 | if ( ((p->Mode)&MYKEY_EVENT_LONG_PRESS) && ((p->Mode)&MYKEY_EVENT_REPEAT) ) { 298 | if (p->PressTime < p->LongPressTime) { 299 | p->PressTime += InterVal; 300 | if (p->PressTime >= p->LongPressTime) { 301 | p->RepeatCount = 0; //重复触发计时清0 302 | p->State = KEYSTATE_PRESS_LR; 303 | //发送按键长按消息 304 | //KeyMessage_Put(p->KeyID,MYKEY_EVENT_LONG_PRESS); 305 | } 306 | } else { 307 | p->RepeatCount += InterVal; 308 | if (p->RepeatCount >= p->RepeatSpeed) { 309 | p->RepeatCount = 0; 310 | p->State = KEYSTATE_PRESS_LR; 311 | //发送连续按键消息 312 | KeyMessage_Put(p->KeyID, MYKEY_EVENT_REPEAT, p->ClickCount); 313 | if (p->ClickCount < 255) { 314 | p->ClickCount++; 315 | } 316 | } 317 | } 318 | } else if ((p->Mode)&MYKEY_EVENT_LONG_PRESS) { 319 | //只使能长按功能 320 | if (p->PressTime < p->LongPressTime) { 321 | p->PressTime += InterVal; 322 | if (p->PressTime >= p->LongPressTime) { 323 | p->State = KEYSTATE_PRESS_L; 324 | //发送按键长按消息 325 | KeyMessage_Put(p->KeyID, MYKEY_EVENT_LONG_PRESS, p->ClickCount); 326 | } 327 | } 328 | } else if ((p->Mode)&MYKEY_EVENT_REPEAT) { 329 | //只使能连发功能 330 | p->RepeatCount += InterVal; 331 | if (p->RepeatCount >= p->RepeatSpeed) { 332 | p->RepeatCount = 0; 333 | p->State = KEYSTATE_PRESS_R; 334 | //发送连续按键消息 335 | KeyMessage_Put(p->KeyID, MYKEY_EVENT_REPEAT, p->ClickCount); 336 | if (p->ClickCount < 255) { 337 | p->ClickCount++; 338 | } 339 | } 340 | } 341 | } 342 | } 343 | } else { 344 | //弹起消抖 345 | if (p->FilterCount > KEY_FILTER_TIME) { 346 | p->FilterCount = KEY_FILTER_TIME; 347 | } else if (p->FilterCount != 0) { 348 | if (p->FilterCount >= InterVal) { 349 | p->FilterCount -= InterVal; 350 | } else { 351 | p->FilterCount = 0; 352 | } 353 | } else { 354 | //消抖时间到 355 | p->keyState = 0; 356 | switch (p->State) { 357 | //支持单击和双击 358 | case KEYSTATE_PRESS_SD: { 359 | p->DblClkCount += InterVal; 360 | //超过时间没有双击 361 | if (p->DblClkCount >= KEY_DBL_INTERVAL) { 362 | p->State = KEYSTATE_RELASE; 363 | p->DblClkCount = 0; 364 | if (p->ClickCount <= 1) { 365 | //发送单击按键消息 366 | KeyMessage_Put(p->KeyID, MYKEY_EVENT_CLICK, p->ClickCount); 367 | } else { 368 | //发送连击按键消息 369 | KeyMessage_Put(p->KeyID, MYKEY_EVENT_DBLCLICK, p->ClickCount); 370 | } 371 | p->ClickCount = 0; 372 | } 373 | } 374 | break; 375 | 376 | //仅支持双击 377 | case KEYSTATE_PRESS_D: { 378 | p->DblClkCount += InterVal; 379 | //超过时间没有双击 380 | if (p->DblClkCount >= KEY_DBL_INTERVAL) { 381 | p->State = KEYSTATE_RELASE; 382 | p->DblClkCount = 0; 383 | //发送连击消息 384 | KeyMessage_Put(p->KeyID, MYKEY_EVENT_DBLCLICK, p->ClickCount); 385 | p->ClickCount = 0; 386 | } 387 | } 388 | break; 389 | 390 | //仅支持单击 391 | case KEYSTATE_PRESS_S: { 392 | p->State = KEYSTATE_RELASE; 393 | //即不支持长按,也不支持连续触发 394 | if (!( ((p->Mode)&MYKEY_EVENT_LONG_PRESS) || ((p->Mode)&MYKEY_EVENT_REPEAT) )) { 395 | //发送按键松开消息 396 | KeyMessage_Put(p->KeyID, MYKEY_EVENT_RELASE, p->ClickCount); 397 | } else { 398 | //发送单击按键消息 399 | KeyMessage_Put(p->KeyID, MYKEY_EVENT_CLICK, p->ClickCount); 400 | } 401 | } 402 | break; 403 | 404 | //支持长按和连续触发 405 | case KEYSTATE_PRESS_LR: 406 | //仅支持长按 407 | case KEYSTATE_PRESS_L: 408 | //仅支持连续触发 409 | case KEYSTATE_PRESS_R: { 410 | p->State = KEYSTATE_RELASE; 411 | //发送按键松开消息 412 | KeyMessage_Put(p->KeyID, MYKEY_EVENT_RELASE, p->ClickCount); 413 | } 414 | break; 415 | 416 | default: { 417 | p->State = KEYSTATE_RELASE; 418 | } 419 | break; 420 | } 421 | } 422 | } 423 | p = p->Next_Key; 424 | } 425 | } 426 | --------------------------------------------------------------------------------