-
Notifications
You must be signed in to change notification settings - Fork 1
/
layout_common.h
373 lines (335 loc) · 9.36 KB
/
layout_common.h
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
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
/* #line 1 "layout_common.rl" */
// -*- compile-command: "ragel -Vp -o layout_common.dot layout_common.rl && dot layout_common.dot -Tpng -o layout_common.png && ragel -pL -G2 -o layout_common.h layout_common.rl" -*-
/* The Atreus has "only" 42 keys. The idea is that the 'fn' key will have
3 different meanings:
- hold: when pressed, clicked another key, and then released
- click: when pressed and released quickly
- double click: when clicked, and then clicked again
Each 'meaning' will correspond to a different layer:
- layer0: the 'normal' layer where each key corresponds to the QWERTY layout
- layer1: the 'hold' layer, where you put all the keys that usually are
followed by another from the same layer1 (like numbers or cursor
movement keys)
- layer2: the 'click' layer, where I put all the symbols that aren't usually
followed by another from the same layer2 (like Spanish accented vowels)
- layer3: the 'double-click' layer, where I put keys that are usually
followed by another from the same layer (cursors again) and the ones that
are less used (like function keys)
With this four layers, you have 42 * 4 = 168 keys. You don't really have so
many because you want some keys like fn, shift, ctrl, alt or enter in every
layer. But I've found that I don't need more keys.
The problem is that the 'meaning' of the layers is not well defined:
- sometimes you hold fn, press another key, and then release fn before the
other key.
- or you try to click fn but press the other key before releasing it
The logic to solve those problems is full of "Ifs", "elses" and strange
status variables. Usually, you forget some "If" condition, or modify a status
variable when you shouldn't, and you keyboard start to act weird without you
knowing why.
Then I started to play with Ragel: a compiler for state machines, and I
tried to solve this problem using it. The resulting logic is working quite
good for me.
Another trick was to use a disabled layer (layer -1), for those undefined
moments when you can't decide which layer to use. The disabled layer will
not send any key.
The input of the state machine, is the variable "kb_value", an int with
only two significant bits:
- bit 0: is active when fn is pressed
- bit 1: is active when any other key is pressed
The state machine uses or modifies other variables, like a state_timer
to count cycles, the array of keyboard_keys pressed, or the
current_layer_number.
There are probably other (simpler?) ways of implementing this logic, but
this is being a rewarding journey: Ragel is a very interesting technology
to use, and the Atreus is the keyboard that I enjoy using daily in my job.
*/
// Minimum number of cycles pressing fn to be considered a hold
#define MIN_HOLD_CYCLES 40
// Maximum number of cycles after wich another click does not be
// interpreted as a double click
#define MAX_DOUBLE_CLICK_CYCLES 40
/* function key pressed */
int fn_pressed = 0;
/* microscript variables */
static uint8_t cs; // current parser state
static const char* eof = 0; // set eof = p = pe to mark input end
int state_timer; // a timer needed for some states
uint8_t first_click_key; // first key pressed while in click layer
unsigned char kb_value; // | Alphanum | Function | -> input to microscript
/* #line 149 "layout_common.rl" */
/* #line 82 "layout_common.h" */
static const int microscript_start = 1;
static const int microscript_first_final = 9;
static const int microscript_error = 0;
static const int microscript_en_main = 1;
/* #line 151 "layout_common.rl" */
void init_microscript( void ) {
/* #line 95 "layout_common.h" */
{
cs = microscript_start;
}
/* #line 154 "layout_common.rl" */
}
void parse_microscript(void) {
unsigned char* p = &kb_value;
const unsigned char* pe = p + 1; // end pointer
/* #line 109 "layout_common.h" */
{
short _widec;
if ( p == pe )
goto _test_eof;
switch ( cs )
{
tr10:
/* #line 90 "layout_common.rl" */
{ current_layer_number = 0; }
goto st1;
tr16:
/* #line 101 "layout_common.rl" */
{ first_click_key = 0; }
/* #line 90 "layout_common.rl" */
{ current_layer_number = 0; }
goto st1;
st1:
if ( ++p == pe )
goto _test_eof1;
case 1:
/* #line 130 "layout_common.h" */
switch( (*p) ) {
case 1u: goto tr1;
case 3u: goto tr1;
}
goto st1;
tr1:
/* #line 89 "layout_common.rl" */
{ current_layer_number = -1; }
/* #line 94 "layout_common.rl" */
{ state_timer = MIN_HOLD_CYCLES; }
goto st2;
st2:
if ( ++p == pe )
goto _test_eof2;
case 2:
/* #line 146 "layout_common.h" */
_widec = (*p);
if ( (*p) > 1u ) {
if ( 3u <= (*p) && (*p) <= 3u ) {
_widec = (short)(256u + ((*p) - 0u));
if (
/* #line 96 "layout_common.rl" */
--state_timer > 0 ) _widec += 256;
}
} else if ( (*p) >= 1u ) {
_widec = (short)(256u + ((*p) - 0u));
if (
/* #line 96 "layout_common.rl" */
--state_timer > 0 ) _widec += 256;
}
switch( _widec ) {
case 0: goto tr2;
case 2: goto tr2;
case 257: goto tr4;
case 259: goto tr4;
case 513: goto st2;
case 515: goto st2;
}
if ( 4 <= _widec )
goto tr2;
goto st0;
tr2:
/* #line 92 "layout_common.rl" */
{ current_layer_number = 2; }
/* #line 95 "layout_common.rl" */
{ state_timer = MAX_DOUBLE_CLICK_CYCLES; }
goto st3;
tr6:
/* #line 97 "layout_common.rl" */
{ if (state_timer > 1) state_timer--; }
goto st3;
st3:
if ( ++p == pe )
goto _test_eof3;
case 3:
/* #line 186 "layout_common.h" */
_widec = (*p);
if ( (*p) < 2u ) {
if ( 1u <= (*p) && (*p) <= 1u ) {
_widec = (short)(256u + ((*p) - 0u));
if (
/* #line 96 "layout_common.rl" */
--state_timer > 0 ) _widec += 256;
}
} else if ( (*p) > 2u ) {
if ( 3u <= (*p) && (*p) <= 3u ) {
_widec = (short)(256u + ((*p) - 0u));
if (
/* #line 96 "layout_common.rl" */
--state_timer > 0 ) _widec += 256;
}
} else {
_widec = (short)(768u + ((*p) - 0u));
if (
/* #line 98 "layout_common.rl" */
keyboard_keys[0] > 0 ) _widec += 256;
}
switch( _widec ) {
case 0: goto tr6;
case 257: goto tr7;
case 259: goto tr7;
case 513: goto tr8;
case 515: goto tr8;
case 770: goto tr6;
case 1026: goto tr9;
}
if ( 4 <= _widec )
goto tr6;
goto st0;
st0:
cs = 0;
goto _out;
tr7:
/* #line 89 "layout_common.rl" */
{ current_layer_number = -1; }
/* #line 94 "layout_common.rl" */
{ state_timer = MIN_HOLD_CYCLES; }
goto st4;
st4:
if ( ++p == pe )
goto _test_eof4;
case 4:
/* #line 233 "layout_common.h" */
_widec = (*p);
if ( (*p) > 1u ) {
if ( 3u <= (*p) && (*p) <= 3u ) {
_widec = (short)(256u + ((*p) - 0u));
if (
/* #line 96 "layout_common.rl" */
--state_timer > 0 ) _widec += 256;
}
} else if ( (*p) >= 1u ) {
_widec = (short)(256u + ((*p) - 0u));
if (
/* #line 96 "layout_common.rl" */
--state_timer > 0 ) _widec += 256;
}
switch( _widec ) {
case 0: goto tr10;
case 2: goto tr10;
case 257: goto tr4;
case 259: goto tr4;
case 513: goto st4;
case 515: goto st4;
}
if ( 4 <= _widec )
goto tr10;
goto st0;
tr4:
/* #line 91 "layout_common.rl" */
{ current_layer_number = 1; }
goto st5;
st5:
if ( ++p == pe )
goto _test_eof5;
case 5:
/* #line 267 "layout_common.h" */
if ( (*p) == 0u )
goto tr10;
goto st5;
tr8:
/* #line 89 "layout_common.rl" */
{ current_layer_number = -1; }
/* #line 94 "layout_common.rl" */
{ state_timer = MIN_HOLD_CYCLES; }
goto st6;
st6:
if ( ++p == pe )
goto _test_eof6;
case 6:
/* #line 281 "layout_common.h" */
_widec = (*p);
if ( (*p) > 1u ) {
if ( 3u <= (*p) && (*p) <= 3u ) {
_widec = (short)(256u + ((*p) - 0u));
if (
/* #line 96 "layout_common.rl" */
--state_timer > 0 ) _widec += 256;
}
} else if ( (*p) >= 1u ) {
_widec = (short)(256u + ((*p) - 0u));
if (
/* #line 96 "layout_common.rl" */
--state_timer > 0 ) _widec += 256;
}
switch( _widec ) {
case 0: goto tr13;
case 2: goto tr13;
case 257: goto tr4;
case 259: goto tr4;
case 513: goto st6;
case 515: goto st6;
}
if ( 4 <= _widec )
goto tr13;
goto st0;
tr13:
/* #line 93 "layout_common.rl" */
{ current_layer_number = 3; }
goto st7;
st7:
if ( ++p == pe )
goto _test_eof7;
case 7:
/* #line 315 "layout_common.h" */
switch( (*p) ) {
case 1u: goto tr7;
case 3u: goto tr7;
}
goto st7;
tr9:
/* #line 99 "layout_common.rl" */
{ first_click_key = keyboard_keys[0]; }
goto st8;
st8:
if ( ++p == pe )
goto _test_eof8;
case 8:
/* #line 329 "layout_common.h" */
_widec = (*p);
_widec = (short)(1280u + ((*p) - 0u));
if (
/* #line 100 "layout_common.rl" */
first_click_key == keyboard_keys[0] ) _widec += 256;
if ( _widec > 1535 ) {
if ( 1536 <= _widec && _widec <= 1791 )
goto st8;
} else if ( _widec >= 1280 )
goto tr16;
goto st0;
}
_test_eof1: cs = 1; goto _test_eof;
_test_eof2: cs = 2; goto _test_eof;
_test_eof3: cs = 3; goto _test_eof;
_test_eof4: cs = 4; goto _test_eof;
_test_eof5: cs = 5; goto _test_eof;
_test_eof6: cs = 6; goto _test_eof;
_test_eof7: cs = 7; goto _test_eof;
_test_eof8: cs = 8; goto _test_eof;
_test_eof: {}
_out: {}
}
/* #line 161 "layout_common.rl" */
}
void activate_fn() {
fn_pressed = 1;
};
void (*layer_functions[])(void) = {reset, activate_fn};
void per_cycle() {
/* kb_value: usb_presses fn_pressed */
/* 0 0 0 */
/* 1 0 1 */
/* 2 1 0 */
/* 3 1 1 */
kb_value = 2 * (usb_presses > 0) + fn_pressed;
fn_pressed = 0;
parse_microscript();
};