summaryrefslogtreecommitdiffstats
path: root/layer.c
blob: 0854eede0d394708a8caa23b337e7a85e534cc83 (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
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
/*
Copyright 2011 Jun Wako <wakojun@gmail.com>

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "keymap.h"
#include "host.h"
#include "debug.h"
#include "timer.h"
#include "usb_keycodes.h"
#include "layer.h"


/*
 * Parameters:
 *     SWITCH_DELAY        |=======|
 *     SEND_FN_TERM        |================|
 *
 * Fn key processing cases:
 * 1. release Fn after SEND_FN_TERM.
 *     Layer sw         ___________|~~~~~~~~~~~|___
 *     Fn press         ___|~~~~~~~~~~~~~~~~~~~|___
 *     Fn send          ___________________________
 *
 * 2. release Fn during SEND_FN_TERM.(not layer used)
 *     Layer sw         ___________|~~~~~~|________
 *     Fn press         ___|~~~~~~~~~~~~~~|________
 *     Fn key send      __________________|~|______
 *     other key press  ___________________________
 *     other key send   ___________________________
 *
 * 3. release Fn during SEND_FN_TERM.(layer used)
 *     Layer sw         ___________|~~~~~~|________
 *     Fn press         ___|~~~~~~~~~~~~~~|________
 *     Fn key send      ___________________________
 *     Fn send          ___________________________
 *     other key press  _____________|~~|__________
 *     other key send   _____________|~~|__________
 *
 * 4. press other key during SWITCH_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_SWITCH_DELAY: prevent from moving to new layer
#ifndef LAYER_SWITCH_DELAY
#   define LAYER_SWITCH_DELAY 150
#endif

// LAYER_SEND_FN_TERM: send keycode if release key in this term
#ifndef LAYER_SEND_FN_TERM
#   define LAYER_SEND_FN_TERM 500
#endif


uint8_t default_layer = 0;
uint8_t current_layer = 0;

static bool layer_used = false;
static uint8_t new_layer(uint8_t fn_bits);


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_MOUSEKEY(code))) {
        layer_used = true;
    }
    return code;
}

// bit substract b from a
#define BIT_SUBST(a, b) (a&(a^b))
void layer_switching(uint8_t fn_bits)
{
    // layer switching
    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 state is not changed
        if (fn_bits == 0) {
            // do nothing
        } else {
            if (!keymap_fn_keycode(BIT_SUBST(fn_bits, sent_fn)) ||
                    timer_elapsed(last_timer) > LAYER_SWITCH_DELAY) {
                uint8_t _layer_to_switch = new_layer(BIT_SUBST(fn_bits, sent_fn));
                if (current_layer != _layer_to_switch) { // not switch layer yet
                    debug("Fn case: 1,2,3(LAYER_SWITCH_DELAY passed)\n");
                    debug("Switch Layer: "); debug_hex(current_layer);
                    current_layer = _layer_to_switch;
                    layer_used = false;
                    debug(" -> "); debug_hex(current_layer); debug("\n");
                }
            } else {
                if (host_has_anykey()) { // other keys is pressed
                    uint8_t _fn_to_send = BIT_SUBST(fn_bits, sent_fn);
                    if (_fn_to_send) {
                        debug("Fn case: 4(press other key during SWITCH_DELAY.)\n");
                        // send only Fn key first
                        uint8_t tmp_mods = keyboard_report->mods;
                        host_add_code(keymap_fn_keycode(_fn_to_send));
                        host_set_mods(last_mods);
                        host_send_keyboard_report();
                        host_set_mods(tmp_mods);
                        host_del_code(keymap_fn_keycode(_fn_to_send));
                        sent_fn |= _fn_to_send;
                    }
                }
            }
            // add Fn keys to send
            //host_add_code(keymap_fn_keycode(fn_bits&sent_fn));  // TODO: do all Fn keys
        }
    } else { // Fn state is changed(edge)
        uint8_t fn_changed = 0;

        debug("fn_bits: "); debug_bin(fn_bits); debug("\n");
        debug("sent_fn: "); debug_bin(sent_fn); 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");
        debug("timer_count: "); debug_hex16(timer_count); debug("\n");

        // pressed Fn
        if ((fn_changed = BIT_SUBST(fn_bits, last_fn))) {
            debug("fn_changed: "); debug_bin(fn_changed); debug("\n");
            if (host_has_anykey()) {
                debug("Fn case: 5(pressed Fn with other key)\n");
                sent_fn |= fn_changed;
            } else if (fn_changed & sent_fn) { // pressed same Fn in a row
                if (timer_elapsed(last_timer) > LAYER_SEND_FN_TERM) {
                    debug("Fn case: 6(not repeat)\n");
                    // time passed: not repeate
                    sent_fn &= ~fn_changed;
                } else {
                    debug("Fn case: 6(repeat)\n");
                }
            }
        }
        // released Fn
        if ((fn_changed = BIT_SUBST(last_fn, fn_bits))) {
            debug("fn_changed: "); debug_bin(fn_changed); debug("\n");
            if (timer_elapsed(last_timer) < LAYER_SEND_FN_TERM) {
                if (!layer_used && BIT_SUBST(fn_changed, sent_fn)) {
                    debug("Fn case: 2(send Fn one shot: released Fn during LAYER_SEND_FN_TERM)\n");
                    // send only Fn key first
                    uint8_t tmp_mods = keyboard_report->mods;
                    host_add_code(keymap_fn_keycode(fn_changed));
                    host_set_mods(last_mods);
                    host_send_keyboard_report();
                    host_set_mods(tmp_mods);
                    host_del_code(keymap_fn_keycode(fn_changed));
                    sent_fn |= fn_changed;
                }
            }
            debug("Switch Layer(released Fn): "); debug_hex(current_layer);
            current_layer = new_layer(BIT_SUBST(fn_bits, sent_fn));
            debug(" -> "); debug_hex(current_layer); debug("\n");
        }

        layer_used = false;
        last_fn = fn_bits;
        last_mods = keyboard_report->mods;
        last_timer = timer_read();
    }
    // send Fn keys
    for (uint8_t i = 0; i < 8; i++) {
        if ((sent_fn & fn_bits) & (1<<i)) {
            host_add_code(keymap_fn_keycode(1<<i));
        }
    }
}

inline
static uint8_t new_layer(uint8_t fn_bits)
{
    return (fn_bits ? keymap_fn_layer(fn_bits) : default_layer);
}