1 | // +----------------------------------------------------------------------+
|
2 | // | |
|
3 | // | Comfort Keyhandling Code |
|
4 | // | |
|
5 | // | (C) 13/02/2008 - Daniel Porzig - www.base32.de |
|
6 | // +----------------------------------------------------------------------+
|
7 | //
|
8 | //
|
9 | //
|
10 | // How to use:
|
11 | //
|
12 | // 1.) If available, enable internal pull-up resistors, otherwise you
|
13 | // have to use external pull-up resistors for every key you use.
|
14 | // 2.) Call InitKeys();
|
15 | // 3.) Setup Keys by calling "setup_key" for every key.
|
16 | // 4.) Call "CheckKeys()" about every 50ms
|
17 | // 5.) Check the key states by calling KeyPress(..) or KeyLongPress(..)
|
18 | // for every key you want to use
|
19 | //
|
20 | //
|
21 | //
|
22 |
|
23 | // how many keys should be used
|
24 | #define NUM_KEYS 7
|
25 |
|
26 | // key states
|
27 | #define KS_RELEASED 0
|
28 | #define KS_PRESSED 1
|
29 | #define KS_LONGPRESSED 2
|
30 |
|
31 | // key modes
|
32 | #define KM_ACT_ON_PRESS 0x01
|
33 | #define KM_ACT_ON_RELEASE 0x02
|
34 | #define KM_ACT_ON_LONGPRESS 0x03
|
35 |
|
36 | // Key Data Structure (for each key)
|
37 | struct key_struct
|
38 | {
|
39 | int8 _mode; // key mode (const)
|
40 | int8 _repeat_delay; // delay for repeatedly pressed keys (const)
|
41 | int8 _longpress_delay; // how long the key has to be pressed before a longpress gets activated
|
42 | int8 state;
|
43 | int8 counter;
|
44 | int8 longpress_cnt;
|
45 | };
|
46 | struct key_struct keys[NUM_KEYS];
|
47 |
|
48 | // key state variables
|
49 | int8 last_keystate = 0xFF;
|
50 | int8 key_actions = 0x00;
|
51 | int8 key_longpress_actions = 0x00;
|
52 |
|
53 |
|
54 | // Configure a single button
|
55 | // num - which key to configure
|
56 | // mode - configure how the key reacts (KM_ACT_ON_PRESS, KM_ACT_ON_RELEASE or KM_ACT_ON_LONGPRESS)
|
57 | // repeat_delay - when a button is (long)pressed continuously, this value sets the delay between
|
58 | // repeatedly triggered actions
|
59 | // longpress_delay - configures how long a key (with key-mode == KM_ACT_ON_LONGPRESS) has to be hold down before
|
60 | // a longpress action is triggered
|
61 | void setup_key(int8 num, int8 mode, int8 repeat_delay, int8 longpress_delay)
|
62 | {
|
63 | keys[num]._mode = mode;
|
64 | keys[num]._repeat_delay = repeat_delay;
|
65 | keys[num]._longpress_delay = longpress_delay;
|
66 | }
|
67 |
|
68 | // initializes Key data for all keys
|
69 | // call this function before first call of "CheckKeys()"
|
70 | void InitKeys()
|
71 | {
|
72 | int8 a;
|
73 | for(a=0; a<NUM_KEYS; a++)
|
74 | {
|
75 | keys[a].state = KS_RELEASED;
|
76 | keys[a].counter = 0;
|
77 | keys[a].longpress_cnt = 0;
|
78 | }
|
79 | last_keystate = 0xFF;
|
80 | }
|
81 |
|
82 | // Returns true if the standard action for key(num) has to be executed
|
83 | int1 KeyPress(int8 num)
|
84 | {
|
85 | return bit_test(key_actions, num);
|
86 | }
|
87 |
|
88 | // Returns true if the key(num) is currently longpressed
|
89 | int1 KeyLongpress(int8 num)
|
90 | {
|
91 | return bit_test(key_longpress_actions, num);
|
92 | }
|
93 |
|
94 | // Returns true if one or more keys are currently pressed or have changed state since last CheckKeys()
|
95 | int1 KeyActivity()
|
96 | {
|
97 | return (key_longpress_actions || key_actions)||(last_keystate!=0xFF);
|
98 | }
|
99 |
|
100 | // This function does all the keyhandling. Call this function about every 50ms.
|
101 | void CheckKeys()
|
102 | {
|
103 | int8 i, diff;
|
104 | int8 keystate = 0xFF;
|
105 |
|
106 | // get current state of keys
|
107 | keystate = input_b();
|
108 |
|
109 | // reset action flags
|
110 | key_actions = 0x00;
|
111 | key_longpress_actions = 0x00;
|
112 |
|
113 | // determin the difference between current and last keystate
|
114 | diff = last_keystate ^ keystate;
|
115 |
|
116 | // loop through all keys
|
117 | for(i=0; i<NUM_KEYS; i++)
|
118 | {
|
119 | // key has changed?
|
120 | if(bit_test(diff,i))
|
121 | {
|
122 | switch(keys[i].state)
|
123 | {
|
124 | case KS_PRESSED: // key was in pressed state before
|
125 | keys[i].state = KS_RELEASED; // change keystate
|
126 | keys[i].counter = 0; // reset longpress counter
|
127 |
|
128 | if(keys[i]._mode == KM_ACT_ON_RELEASE)
|
129 | {
|
130 | // +---------------------+
|
131 | // | DO STANDARD ACTION! |
|
132 | // +---------------------+
|
133 | bit_set(key_actions,i);
|
134 | }
|
135 | else
|
136 | if(keys[i]._mode == KM_ACT_ON_LONGPRESS)
|
137 | {
|
138 | // key was released, but key was not in Longpress state yet.
|
139 | // +---------------------+
|
140 | // | DO STANDARD ACTION! |
|
141 | // +---------------------+
|
142 | bit_set(key_actions,i);
|
143 | }
|
144 | else
|
145 | {
|
146 | // KM_ACT_ON_PRESS: DO NOTHING
|
147 | }
|
148 | break;
|
149 | case KS_RELEASED: // key was in released state before
|
150 | keys[i].state = KS_PRESSED; // change keystate
|
151 | if(keys[i]._mode == KM_ACT_ON_PRESS)
|
152 | {
|
153 | keys[i].counter = 0; // reset keypress counter
|
154 | // +---------------------+
|
155 | // | DO STANDARD ACTION! |
|
156 | // +---------------------+
|
157 | bit_set(key_actions,i);
|
158 | }
|
159 | else if(keys[i]._mode == KM_ACT_ON_LONGPRESS)
|
160 | {
|
161 | // action is triggered later
|
162 | keys[i].longpress_cnt = 0; // reset longpress counter
|
163 | }
|
164 | else
|
165 | {
|
166 | // KM_ACT_ON_RELEASE: DO NOTHING
|
167 | }
|
168 | break;
|
169 | case KS_LONGPRESSED: // key was released after a Longpress. Special handling!
|
170 | keys[i].state = KS_RELEASED; // change keystate
|
171 |
|
172 | // does this key have lonpress mode enabled?
|
173 | if(keys[i]._mode == KM_ACT_ON_LONGPRESS)
|
174 | {
|
175 | // When a key was released after a longpress, nothing should happen!
|
176 | }
|
177 | else
|
178 | {
|
179 | // KM_ACT_ON_RELEASE: DO NOTHING
|
180 | // KM_ACT_ON_PRESS: DO NOTHING
|
181 | }
|
182 | break;
|
183 | }
|
184 | }
|
185 | else
|
186 | {
|
187 | // check keys whose states DID NOT change here!
|
188 | // (autofire, longpress repeat)
|
189 |
|
190 | if(keys[i].state == KS_PRESSED)
|
191 | {
|
192 | if(keys[i]._mode == KM_ACT_ON_RELEASE)
|
193 | {
|
194 | // key is either still pressed or still released so
|
195 | // no action needed here
|
196 | }
|
197 | else
|
198 | if(keys[i]._mode == KM_ACT_ON_PRESS) // check "autofire" function
|
199 | {
|
200 | // key is still pressed
|
201 | keys[i].counter++; // increase keypress counter
|
202 | if(keys[i].counter >= keys[i]._repeat_delay)
|
203 | {
|
204 | keys[i].counter = 0;
|
205 | // +---------------------+
|
206 | // | DO STANDARD ACTION! |
|
207 | // +---------------------+
|
208 | bit_set(key_actions,i);
|
209 | }
|
210 | }
|
211 | else
|
212 | if(keys[i]._mode == KM_ACT_ON_LONGPRESS)
|
213 | {
|
214 | // key is still pressed
|
215 | keys[i].longpress_cnt++; // increase keypress counter
|
216 |
|
217 | // do we have to trigger the longpress action?
|
218 | if(keys[i].longpress_cnt >= keys[i]._longpress_delay)
|
219 | {
|
220 | keys[i].counter = 0;
|
221 | // +----------------------+
|
222 | // | DO LONGPRESS ACTION! |
|
223 | // +----------------------+
|
224 | keys[i].state = KS_LONGPRESSED; // set key into longpressed state
|
225 | bit_set(key_longpress_actions,i);
|
226 | }
|
227 | }
|
228 | }
|
229 | else
|
230 | if(keys[i].state == KS_LONGPRESSED) // check longpressed button "autofire" function
|
231 | {
|
232 | // key is still (long)pressed
|
233 | // (we don't have to check the key's mode here since only a KM_ACT_ON_LONGPRESS-
|
234 | // button can get into the KS_LONGPRESSED state
|
235 | keys[i].counter++; // increase keypress counter
|
236 |
|
237 | // do we have to trigger the longpress action again?
|
238 | if(keys[i].counter >= keys[i]._repeat_delay)
|
239 | {
|
240 | keys[i].counter = 0;
|
241 | // +----------------------+
|
242 | // | DO LONGPRESS ACTION! |
|
243 | // +----------------------+
|
244 | bit_set(key_longpress_actions,i);
|
245 | }
|
246 | }
|
247 | }
|
248 | }
|
249 | // save current keystate
|
250 | last_keystate = keystate;
|
251 | }
|