-
Notifications
You must be signed in to change notification settings - Fork 21
/
Copy pathfilterpaper.c
164 lines (131 loc) · 5.46 KB
/
filterpaper.c
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
// Copyright @filterpaper
// SPDX-License-Identifier: GPL-2.0+
#include QMK_KEYBOARD_H
#include "autocorrect.h"
#ifdef COMBO_ENABLE
# include "combos.h"
#endif
// Convert 5-bit to 8-bit packed modifiers
#define MOD_TAP_GET_MOD_BITS(k) (((k) & 0x0f00) >> (((k) & 0x1000) ? 4 : 8))
// Basic keycode filter for tap-hold keys
#define GET_TAP_KEYCODE(k) ((k) & 0xff)
// Tap-hold decision helper macros
#define IS_LAYER_TAP(k) (IS_QK_LAYER_TAP(k) && QK_LAYER_TAP_GET_LAYER(k))
#define IS_SHORTCUT(k) (IS_QK_LAYER_TAP(k) && !QK_LAYER_TAP_GET_LAYER(k))
#define IS_MOD_TAP_SHIFT(k) (IS_QK_MOD_TAP(k) && (k) & (QK_LSFT))
#define IS_MOD_TAP_CAG(k) (IS_QK_MOD_TAP(k) && (k) & (QK_LCTL|QK_LALT|QK_LGUI))
#define IS_HOMEROW(r) (r->event.key.row == 1 || r->event.key.row == 5)
#define IS_HOMEROW_SHIFT(k, r) (IS_HOMEROW(r) && IS_MOD_TAP_SHIFT(k))
#define IS_HOMEROW_CAG(k, r) (IS_HOMEROW(r) && IS_MOD_TAP_CAG(k))
#define IS_TYPING(k) ( \
((uint8_t)(k) <= KC_Z || IS_SHORTCUT(k)) && \
last_input_activity_elapsed() < INPUT_IDLE_MS)
#define IS_UNILATERAL(r, n) ( \
(r->event.key.row == 1 && 0 <= n.event.key.row && n.event.key.row <= 2) || \
(r->event.key.row == 5 && 4 <= n.event.key.row && n.event.key.row <= 6) )
static uint16_t inter_keycode;
static keyrecord_t inter_record;
bool pre_process_record_user(uint16_t keycode, keyrecord_t *record) {
static bool is_pressed[UINT8_MAX];
const uint16_t tap_keycode = GET_TAP_KEYCODE(keycode);
if (record->event.pressed) {
// Press the tap keycode if the tap-hold key follows a previous key swiftly
if ((IS_HOMEROW_CAG(keycode, record) || IS_SHORTCUT(keycode)) && IS_TYPING(inter_keycode)) {
is_pressed[tap_keycode] = true;
record->keycode = tap_keycode;
}
// Cache incoming input for in-progress and subsequent tap-hold decisions
inter_keycode = keycode;
inter_record = *record;
}
// Release the pressed tap keycode
else if (is_pressed[tap_keycode]) {
is_pressed[tap_keycode] = false;
record->keycode = tap_keycode;
}
return true;
}
#ifdef CHORDAL_HOLD
char chordal_hold_handedness(keypos_t key) {
// Exempt thumb key rows
if (key.row == 3 || key.row == 7) return '*';
return key.row < MATRIX_ROWS / 2 ? 'L' : 'R';
}
bool get_chordal_hold(uint16_t tap_hold_keycode, keyrecord_t* tap_hold_record,
uint16_t other_keycode, keyrecord_t* other_record) {
// Allow Shift modifier combination
if (IS_MOD_TAP_CAG(tap_hold_keycode) && IS_MOD_TAP_SHIFT(other_keycode)) return true;
// Prevent shortcut key chords
else if (IS_SHORTCUT(tap_hold_keycode)) return false;
// Otherwise defer to the opposite hands rule
return get_chordal_hold_default(tap_hold_record, other_record);
}
#endif
bool get_hold_on_other_key_press(uint16_t keycode, keyrecord_t *record) {
#ifndef CHORDAL_HOLD
// Press the tap keycode when a mod-tap key overlaps with a non-Shift key
// on the same hand or when a shortcut key overlaps with any key
if ((IS_UNILATERAL(record, inter_record) && !IS_MOD_TAP_SHIFT(inter_keycode)) || IS_SHORTCUT(keycode)) {
record->tap.interrupted = false;
record->tap.count++;
process_record(record);
return false;
}
#endif
// Activate layer hold with another key press
return IS_LAYER_TAP(keycode);
}
bool get_permissive_hold(uint16_t keycode, keyrecord_t *record) {
// Enable Shift with a nested key press
return IS_HOMEROW_SHIFT(keycode, record);
}
uint16_t get_tapping_term(uint16_t keycode, keyrecord_t *record) {
// Shorten interval for Shift
return IS_HOMEROW_SHIFT(keycode, record) ? SHIFT_TAP_TERM : TAPPING_TERM;
}
// Turn off caps lock at word boundry
static inline void process_caps_unlock(uint16_t keycode, keyrecord_t *record) {
// Get tap keycode from tap-hold keys
if (IS_QK_MOD_TAP(keycode) || IS_QK_LAYER_TAP(keycode)) {
if (record->tap.count == 0) return;
keycode = GET_TAP_KEYCODE(keycode);
}
switch (keycode) {
case KC_A ... KC_0:
case KC_BSPC:
case KC_MINS:
case KC_UNDS:
case KC_CAPS:
// Retain caps lock if there are no active non-Shift modifiers
if ((get_mods() & ~MOD_MASK_SHIFT) == false) return;
// Everything else is a word boundary
default: tap_code(KC_CAPS);
}
}
// Send custom hold keycode
static inline bool process_tap_hold(uint16_t keycode, keyrecord_t *record) {
if (record->tap.count) return true;
tap_code16(keycode);
return false;
}
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
if (record->event.pressed) {
if (!process_autocorrect(keycode, record)) return false;
if (host_keyboard_led_state().caps_lock) process_caps_unlock(keycode, record);
// Clipboard shortcuts
if (keycode == TH_M) return process_tap_hold(Z_PST, record);
else if (keycode == TH_COMM) return process_tap_hold(Z_CPY, record);
else if (keycode == TH_DOT) return process_tap_hold(Z_CUT, record);
else if (keycode == TH_SLSH) return process_tap_hold(Z_UND, record);
}
return true;
}
// Simplify unused magic config functions
#ifndef MAGIC_ENABLE
uint8_t mod_config(uint8_t mod) { return mod; }
uint16_t keycode_config(uint16_t keycode) { return keycode; }
#endif
// Reduce marix scanning delay
#ifndef DIRECT_PINS
void matrix_io_delay(void) { __asm__ volatile("nop\nnop\nnop\n"); }
#endif