summaryrefslogtreecommitdiff
path: root/layer.c
blob: 9251e042e11c48ee647ee769ad347bcc5f90f17b (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
#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   ~~~~~~~|___________________
 */

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

// 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_bits = 0;
    static uint8_t last_mods = 0;
    static uint16_t last_timer = 0; 

    if (fn_bits == last_bits) { // 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
                // switch layer after LAYER_ENTER_DELAY elapse
                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_bits));
                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_bits));
                // cancel layer switching 
                new_layer = 0;
           }
        } else {
            if (fn_bits && new_layer == 0) {
                // case: 4,5
                // send Fn key
                usb_keyboard_add_code(keymap_fn_keycode(last_bits));
            }
        }
    } 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");
                // send Fn key (case: 2[no layer used],3)
                usb_keyboard_swap_report();
                usb_keyboard_clear_report();
                usb_keyboard_add_code(keymap_fn_keycode(last_bits));
                usb_keyboard_set_mods(last_mods);
                usb_keyboard_send();
                usb_keyboard_swap_report();
            }
            debug("Fn case: 1,2,3,4,5(return to default layer)\n");
            // return to default layer(case: 1,2,3,4,5)
            new_layer = 0;
            current_layer = 0;
        } else { // Fn Key is pressed(rising edge)
            if (!usb_keyboard_has_key()) {
                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);
            } else {
                debug("Fn case: 5(add Fn to report)\n");
                // add Fn key to send with other keys(case: 5)
                usb_keyboard_add_code(keymap_fn_keycode(fn_bits));
            }
        }
        layer_used = false;
        last_bits = fn_bits;
        last_mods = usb_keyboard_mods;
        last_timer = timer_read();
        debug("new_layer: "); debug_hex(new_layer); debug("\n");
        debug("last_bits: "); debug_bin(last_bits); debug("\n");
        debug("last_mods: "); debug_hex(last_mods); debug("\n");
        debug("last_timer: "); debug_hex16(last_timer); debug("\n");
    }
}