summaryrefslogtreecommitdiffstats
path: root/layer.c
blob: 2d644c1a606187affeef891f30b55ed7b158da06 (plain)
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
#include "keymap_skel.h"
#include "usb_keyboard.h"
#include "debug.h"
#include "timer.h"
#include "layer.h"

/*
 * Parameters:
 *     enter_delay         |=======|
 *     send_fn_term        |================|
 *
 * Fn key processing cases:
 * 1. release Fn after send_fn_term.
 *     Layer sw         ___________|~~~~~~~~~~~|___
 *     Fn press         ___|~~~~~~~~~~~~~~~~~~~|___
 *     Fn send          ___________________________
 *
 * 2. release Fn in send_fn_term.(not layer used)
 *     Layer sw         ___________|~~~~~~|________
 *     Fn press         ___|~~~~~~~~~~~~~~|________
 *     Fn key send      __________________|~|______
 *     other key press  ___________________________
 *     other key send   ___________________________
 *
 * 3. release Fn in send_fn_term.(layer used)
 *     Layer sw         ___________|~~~~~~|________
 *     Fn press         ___|~~~~~~~~~~~~~~|________
 *     Fn key send      ___________________________
 *     Fn send          ___________________________
 *     other key press  _____________|~~|__________
 *     other key send   _____________|~~|__________
 *
 * 4. press other key in ENTER_DELAY.
 *     Layer sw         ___________________________
 *     Fn key press     ___|~~~~~~~~~|_____________
 *     Fn key send      ______|~~~~~~|_____________
 *     other key press  ______|~~~|________________
 *     other key send   _______|~~|________________
 *
 * 5. press Fn while press other key.
 *     Layer sw         ___________________________
 *     Fn key press     ___|~~~~~~~~~|_____________
 *     Fn key send      ___|~~~~~~~~~|_____________
 *     other key press  ~~~~~~~|___________________
 *     other key send   ~~~~~~~|___________________
 *
 * 6. press Fn twice quickly and keep holding down.(repeat)
 *     Layer sw         ___________________________
 *     Fn key press     ___|~|____|~~~~~~~~~~~~~~~~
 *     Fn key send      _____|~|__|~~~~~~~~~~~~~~~~
 */

// LAYER_ENTER_DELAY: prevent from moving new layer
#define LAYER_ENTER_DELAY 8

// LAYER_SEND_FN_TERM: send keycode if release key in this term
#define LAYER_SEND_FN_TERM 40


static uint8_t current_layer = 0;
static bool layer_used = false;


uint8_t layer_get_keycode(uint8_t row, uint8_t col)
{
    uint8_t code = keymap_get_keycode(current_layer, row, col);
    // normal key or mouse key
    if ((IS_KEY(code) || IS_MOUSE(code))) {
        layer_used = true;
    }
    return code;
}

void layer_switching(uint8_t fn_bits)
{
    // layer switching
    static uint8_t new_layer = 0;
    static uint8_t last_fn = 0;
    static uint8_t last_mods = 0;
    static uint16_t last_timer = 0; 
    static uint8_t sent_fn = 0;

    if (fn_bits == last_fn) { // Fn key is not changed
        if (current_layer != new_layer) {
            // not switch layer yet
            if (timer_elapsed(last_timer) > LAYER_ENTER_DELAY) {
                debug("Fn case: 1,2,3(switch layer)\n");
                // case: 1,2,3
                current_layer = new_layer;
                debug("timer_elapsed: "); debug_hex16(timer_elapsed(last_timer)); debug("\n"); 
                debug("switch layer: "); debug_hex(current_layer); debug("\n");
            } else if (usb_keyboard_has_key()) {
                debug("Fn case: 4(send Fn first, then add Fn to report)\n");
                // case: 4
                // send only Fn key first
                usb_keyboard_swap_report();
                usb_keyboard_clear_report();
                usb_keyboard_add_code(keymap_fn_keycode(last_fn));
                usb_keyboard_set_mods(last_mods);
                usb_keyboard_send();
                usb_keyboard_swap_report();
                // add Fn key to send with other keys
                usb_keyboard_add_code(keymap_fn_keycode(last_fn));

                new_layer = 0;
                sent_fn = last_fn;
           }
        } else {
            if (fn_bits && new_layer == 0) {
                // case: 4,5,6
                usb_keyboard_add_code(keymap_fn_keycode(last_fn));
                sent_fn = last_fn;
            }
        }
    } else { // Fn key is changed
        if (fn_bits == 0) { // Fn key is released(falling edge)
            if (!layer_used && timer_elapsed(last_timer) < LAYER_SEND_FN_TERM) {
                debug("Fn case: 2(send Fn)\n");
                // case: 2
                usb_keyboard_swap_report();
                usb_keyboard_clear_report();
                usb_keyboard_add_code(keymap_fn_keycode(last_fn));
                usb_keyboard_set_mods(last_mods);
                usb_keyboard_send();
                usb_keyboard_swap_report();
                sent_fn = last_fn;
            }
            debug("Fn case: 1,2,3,4,5,6(return to default layer)\n");
            new_layer = 0;
            current_layer = 0;
        } else { // Fn Key is pressed(rising edge)
            if (usb_keyboard_has_key() ||
                    (fn_bits == sent_fn &&timer_elapsed(last_timer) < LAYER_ENTER_DELAY)) {
                debug("Fn case: 5,6(add Fn to repeat)\n");
                usb_keyboard_add_code(keymap_fn_keycode(fn_bits));
                sent_fn = fn_bits;
            } else {
                debug("Fn case: 1,2,3,4(ready for switching layer)\n");
                // ready for switching layer(case: 1,2,3,4)
                new_layer = keymap_fn_layer(fn_bits);
                sent_fn = 0;
            }
        }
        layer_used = false;
        last_fn = fn_bits;
        last_mods = usb_keyboard_mods;
        last_timer = timer_read();
        debug("new_layer: "); debug_hex(new_layer); debug("\n");
        debug("last_fn: "); debug_bin(last_fn); debug("\n");
        debug("last_mods: "); debug_hex(last_mods); debug("\n");
        debug("last_timer: "); debug_hex16(last_timer); debug("\n");
    }
}