Repository navigation
Expand file tree
/
Copy pathkey.h
More file actions
254 lines (217 loc) · 10.6 KB
/
Copy pathkey.h
File metadata and controls
254 lines (217 loc) · 10.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
#ifndef __KEY_H__
#define __KEY_H__
#ifdef __cplusplus
extern "C" {
#endif
#include "modules.h"
/******************************************************************************
User Interface [START]
*******************************************************************************/
// 用户定义的按键读取层
// 1.定义读取函数: KEY_ID -in-> Read_Func -out-> KEY_READ_UP/DOWN
// 2.初始化按键: key_init(dev, Read_Func, ...)
typedef enum {
KEY_READ_UP = 0,
KEY_READ_DOWN = 1,
} key_read_e;
// 读取方式1: 注册回调函数, 自动返回按键ID和事件类型
// 1.定义回调函数: KEY_ID, KEY_EVENT_XXX -in-> Callback_Func
// 2.初始化时注册回调: key_init(..., Callback_Func)
// 读取方式2: 手动调用读取函数, 返回单值事件数据 (按键ID<<8 | 事件类型)
// 1.手动读取事件FIFO: key_value_t value = key_read_fifo(dev);
// 2.使用事件数据: value.id, value.event
#define KEY_EVENT_NULL 0x0000 // 无事件
#define KEY_EVENT_DOWN 0x0001 // 按下事件
#define KEY_EVENT_UP 0x0002 // 松开事件
#define KEY_EVENT_SHORT 0x0009 // 短按事件
#define KEY_EVENT_LONG 0x0003 // 长按事件
#define KEY_EVENT_HOLD 0x0004 // 按住事件
#define KEY_EVENT_HOLD_REPEAT 0x0005 // 按住重复事件
#define KEY_EVENT_HOLD_REPEAT_STOP 0x0006 // 按住重复停止事件
#define KEY_EVENT_DOUBLE 0x000A // 双击事件
#define KEY_EVENT_DOUBLE_REPEAT 0x0007 // 双击按住重复事件
#define KEY_EVENT_DOUBLE_REPEAT_STOP 0x0008 // 双击按住重复停止事件
#define KEY_EVENT_MULTI(N) (0x000B + (N) - 3) // 多击N次事件(最多63次)
typedef struct {
uint8_t id; // 按键ID
uint8_t event; // 事件类型
} key_value_t;
typedef struct { // 按键设备设置(key_dev->setting)
uint16_t check_period_ms; // 按键检测周期 (Key_Tick调用周期)
uint16_t shake_filter_ms; // 按键抖动滤波周期 (N*check_period_ms)
uint8_t simple_event : 1; // 产生简单事件(按下/松开)
uint8_t complex_event : 1; // 产生复杂事件(短按/长按/双击...)
uint8_t multi_max : 6; // 多击最大次数 (<3:禁用多击事件, 最大63)
uint16_t long_ms; // 长按时间 (0:无长按事件)
uint16_t hold_ms; // 按住时间 (0:无按住事件)
uint16_t multi_ms; // 多击最大间隔时间 (0:无多击事件)
uint16_t repeat_wait_ms; // 按住/双击按住重复等待时间 (0:无等待)
uint16_t repeat_send_ms; // 按住/双击按住重复执行间隔 (0:无重复事件)
uint16_t repeat_send_speedup; // 按住/双击按住重复执行加速 (0:无加速)
uint16_t repeat_send_min_ms; // 按住/双击按住重复最小间隔 (加速后)
} key_setting_t;
#define KEY_BUF_SIZE 16 // 按键事件FIFO大小
typedef struct __key_dev { // 按键设备结构体
struct { // 事件FIFO
key_value_t value[KEY_BUF_SIZE];
uint8_t rd;
uint8_t wr;
} event_fifo;
uint8_t key_num; // 按键数量
key_setting_t setting; // 设备设置
key_read_e (*read_func)(uint8_t id); // 读取函数
void (*callback)(uint8_t key, uint8_t event); // 事件回调函数
struct __key { // 按键状态机数组
void (*state)(struct __key_dev*, uint8_t, key_read_e); // 状态机函数
uint16_t count_ms; // 按键计时
uint16_t count_temp; // 消抖计时
uint8_t multi_count; // 多击计数
} key_arr[];
} key_dev_t;
// 默认按键设置
#define default_key_setting \
{ \
.check_period_ms = 10, \
.shake_filter_ms = 20, \
.simple_event = 1, \
.complex_event = 1, \
.multi_max = 6, \
.long_ms = 300, \
.hold_ms = 800, \
.multi_ms = 200, \
.repeat_wait_ms = 600, \
.repeat_send_ms = 100, \
.repeat_send_speedup = 4, \
.repeat_send_min_ms = 10, \
}
/******************************* 事件说明 *******************************
0.按键消抖(图表表示按键驱动读取结果KEY_READ_xxx):
0.1 有效的按下状态:
UP | #####
| #<-shake_filter_ms->
DOWN| ####################......
0.2 有效的松开状态:
UP | ####################......
| #<-shake_filter_ms->
DOWN| #####
1.简单事件:
任意有效的按下/松开状态变化都会产生KEY_EVENT_DOWN/UP事件
在保留消抖效果的同时, 可用于游戏控制等不需要多状态的应用
2.复杂事件(图表表示按键状态, 省略消抖过程, 符号^标识事件KEY_EVENT_xxx触发点):
2.1 SHORT:短按, 按下后立即松开
##### #####
#<- <long_ms ->#
################
^SHORT
2.2 LONG:长按, 按下并保持一段时间后松开
##### #####
#<- >long_ms && <hold_ms ->#
############################
^LONG
2.3 DOUBLE:双击, 短按后一定间隔内再次按下
##### ################# ################
#<- <long_ms ->#<- <multi_ms ->#<- <repeat_wait_ms ->#<- >multi_ms ->
################ #######################
^DOUBLE *DOUBLE^
(*:当multi_max>=3时需要等待抬起后判断多击才能触发双击事件, 这不影响重复事件)
2.4 DREPEAT:双击按住重复, 双击并保持一定时间后开始重复触发, 松开触发停止事件
...#### ####
#<-repeat_wait_ms-><-repeat_send_ms0-><-repeat_send_ms1-> #
#############################################################
^DOUBLE ^DOUBLE_REPEAT ^DOUBLE_REPEAT ^...^...STOP
(加速效果:repeat_send_msN = repeat_send_ms - N * repeat_send_speedup)
2.5 HOLD:按住, 按下不松开直到一定时间
#####
#<- hold_ms ->
###############......
^KEY_EVENT_HOLD
2.6 HREPEAT:按住重复, 按住后一定时间后开始重复触发, 松开触发停止事件
####
<-repeat_wait_ms-><-repeat_send_ms0-><-repeat_send_ms1-> #
...##############################################################
^HOLD ^HOLD_REPEAT ^HOLD_REPEAT ^...^...STOP
(加速效果:repeat_send_msN = repeat_send_ms - N * repeat_send_speedup)
2.7 MULTI:多击事件(>=三击), 与双击逻辑类似, 但不支持重复
##### ############# ############# ############
# <long_ms # <multi_ms # <repeat_wait_ms # <multi_ms # any # >multi_ms
############ ################### #######
*MULTI(3)^ MULTI(3)^
(*:当按键次数N==multi_max时, 会在下降沿直接触发多击事件, 不等待抬起)
******************************************************************************/
/******************************************************************************
User Interface [END]
*******************************************************************************/
// 静态声明一个按键设备(指针)(由于结构体包含柔性数组, 因此必须使用该宏声明)
#define KEY_DEV_DEF(name, num) \
static uint8_t __key_buf_##name[sizeof(key_dev_t) + \
(num) * sizeof(struct __key)] = {0}; \
key_dev_t* name = (key_dev_t*)__key_buf_##name
/**
* @brief 按键系统初始化 (设置初始化为默认值)
* @param key_dev 按键设备指针(NULL:尝试动态分配内存)
* @param read_func 读取函数(传入按键ID,返回按键状态(`KEY_READ_UP/DOWN`))
* @param num 总按键数量
* @param callback 事件回调函数(可选)
* @retval key_dev_t* 按键设备指针(NULL:初始化失败/内存分配失败)
* @note 清理时可直接free(key_dev)
*/
extern key_dev_t* key_init(key_dev_t* key_dev,
key_read_e (*read_func)(uint8_t id), uint8_t num,
void (*callback)(uint8_t key, uint8_t event));
/**
* @brief 按键系统初始化 (使用自定义设置)
* @param key_dev 按键设备指针(NULL:尝试动态分配内存)
* @param read_func 读取函数(传入按键ID,返回按键状态(`KEY_READ_UP/DOWN`))
* @param num 总按键数量
* @param callback 事件回调函数(可选)
* @param setting 按键设备设置
* @retval key_dev_t* 按键设备指针(NULL:初始化失败/内存分配失败)
* @note 清理时可直接free(key_dev)
*/
extern key_dev_t* key_init_with_setting(
key_dev_t* key_dev, key_read_e (*read_func)(uint8_t id), uint8_t num,
void (*callback)(uint8_t key, uint8_t event), key_setting_t setting);
/**
* @brief 按键系统处理函数
* @param key_dev 按键设备指针
* @note 调用周期必须匹配setting.check_period_ms
*/
extern void key_tick(key_dev_t* key_dev);
/**
* @brief 读取按键事件FIFO
* @param key_dev 按键设备指针
* @retval key_value_t 按键值(按键ID<<8 | 事件类型)
* @note 使用宏KEYx_IS_xxx判断事件
*/
extern key_value_t key_read_fifo(key_dev_t* key_dev);
/**
* @brief 获取按键按下状态(包含消抖)
* @param key_dev 按键设备指针
* @param key 按键序号
* @retval key_read_e 按键状态(KEY_READ_UP/DOWN)
*/
extern key_read_e key_read_raw(key_dev_t* key_dev, uint8_t key);
/**
* @brief 获取按键事件名称字符串
* @param event 按键事件
* @retval char* 事件名称字符串
*/
extern const char* key_get_event_name(uint8_t event);
/**
* @brief 判断是否为多击事件
* @param event 按键事件
*/
#define key_is_multi_event(event) ((event & 0xFF) >= KEY_EVENT_MULTI(3))
/**
* @brief 获取多击事件的次数
* @param event 按键事件
* @retval uint8_t 多击次数(<3:非多击事件)
*/
#define key_get_multi_event_num(event) \
((event & 0xFF) >= KEY_EVENT_MULTI(1) \
? (event & 0xFF) - KEY_EVENT_MULTI(0) \
: 0)
#ifdef __cplusplus
}
#endif
#endif /* __KEY_H__ */