aboutsummaryrefslogtreecommitdiff
path: root/quantum
diff options
context:
space:
mode:
Diffstat (limited to 'quantum')
-rw-r--r--quantum/keymap_extras/keymap_br_abnt2.h16
-rw-r--r--quantum/process_keycode/process_combo.c134
-rw-r--r--quantum/process_keycode/process_combo.h43
-rw-r--r--quantum/process_keycode/process_tap_dance.c7
-rw-r--r--quantum/process_keycode/process_tap_dance.h1
-rw-r--r--quantum/process_keycode/process_unicode.c11
-rw-r--r--quantum/quantum.c73
-rw-r--r--quantum/quantum.h5
-rw-r--r--quantum/quantum_keycodes.h11
9 files changed, 296 insertions, 5 deletions
diff --git a/quantum/keymap_extras/keymap_br_abnt2.h b/quantum/keymap_extras/keymap_br_abnt2.h
index 0df177721..b001139dd 100644
--- a/quantum/keymap_extras/keymap_br_abnt2.h
+++ b/quantum/keymap_extras/keymap_br_abnt2.h
@@ -1,3 +1,19 @@
1/* Copyright 2017 Potiguar Faga
2 *
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
1#ifndef KEYMAP_BR_ABNT2_H 17#ifndef KEYMAP_BR_ABNT2_H
2#define KEYMAP_BR_ABNT2_H 18#define KEYMAP_BR_ABNT2_H
3 19
diff --git a/quantum/process_keycode/process_combo.c b/quantum/process_keycode/process_combo.c
new file mode 100644
index 000000000..e2189ad98
--- /dev/null
+++ b/quantum/process_keycode/process_combo.c
@@ -0,0 +1,134 @@
1#include "process_combo.h"
2#include "print.h"
3
4
5#define COMBO_TIMER_ELAPSED -1
6
7
8__attribute__ ((weak))
9combo_t key_combos[] = {
10
11};
12
13__attribute__ ((weak))
14void process_combo_event(uint8_t combo_index, bool pressed) {
15
16}
17
18static uint8_t current_combo_index = 0;
19
20static inline void send_combo(uint16_t action, bool pressed)
21{
22 if (action) {
23 if (pressed) {
24 register_code16(action);
25 } else {
26 unregister_code16(action);
27 }
28 } else {
29 process_combo_event(current_combo_index, pressed);
30 }
31}
32
33#define ALL_COMBO_KEYS_ARE_DOWN (((1<<count)-1) == combo->state)
34#define NO_COMBO_KEYS_ARE_DOWN (0 == combo->state)
35#define KEY_STATE_DOWN(key) do{ combo->state |= (1<<key); } while(0)
36#define KEY_STATE_UP(key) do{ combo->state &= ~(1<<key); } while(0)
37static bool process_single_combo(combo_t *combo, uint16_t keycode, keyrecord_t *record)
38{
39 uint8_t count = 0;
40 uint8_t index = -1;
41 /* Find index of keycode and number of combo keys */
42 for (const uint16_t *keys = combo->keys; ;++count) {
43 uint16_t key = pgm_read_word(&keys[count]);
44 if (keycode == key) index = count;
45 if (COMBO_END == key) break;
46 }
47
48 /* Return if not a combo key */
49 if (-1 == (int8_t)index) return false;
50
51 /* The combos timer is used to signal whether the combo is active */
52 bool is_combo_active = COMBO_TIMER_ELAPSED == combo->timer ? false : true;
53
54 if (record->event.pressed) {
55 KEY_STATE_DOWN(index);
56
57 if (is_combo_active) {
58 if (ALL_COMBO_KEYS_ARE_DOWN) { /* Combo was pressed */
59 send_combo(combo->keycode, true);
60 combo->timer = COMBO_TIMER_ELAPSED;
61 } else { /* Combo key was pressed */
62 combo->timer = timer_read();
63#ifdef COMBO_ALLOW_ACTION_KEYS
64 combo->prev_record = *record;
65#else
66 combo->prev_key = keycode;
67#endif
68 }
69 }
70 } else {
71 if (ALL_COMBO_KEYS_ARE_DOWN) { /* Combo was released */
72 send_combo(combo->keycode, false);
73 }
74
75 if (is_combo_active) { /* Combo key was tapped */
76#ifdef COMBO_ALLOW_ACTION_KEYS
77 record->event.pressed = true;
78 process_action(record, store_or_get_action(record->event.pressed, record->event.key));
79 record->event.pressed = false;
80 process_action(record, store_or_get_action(record->event.pressed, record->event.key));
81#else
82 register_code16(keycode);
83 send_keyboard_report();
84 unregister_code16(keycode);
85#endif
86 combo->timer = 0;
87 }
88
89 KEY_STATE_UP(index);
90 }
91
92 if (NO_COMBO_KEYS_ARE_DOWN) {
93 combo->timer = 0;
94 }
95
96 return is_combo_active;
97}
98
99bool process_combo(uint16_t keycode, keyrecord_t *record)
100{
101 bool is_combo_key = false;
102
103 for (current_combo_index = 0; current_combo_index < COMBO_COUNT; ++current_combo_index) {
104 combo_t *combo = &key_combos[current_combo_index];
105 is_combo_key |= process_single_combo(combo, keycode, record);
106 }
107
108 return !is_combo_key;
109}
110
111void matrix_scan_combo(void)
112{
113 for (int i = 0; i < COMBO_COUNT; ++i) {
114 combo_t *combo = &key_combos[i];
115 if (combo->timer &&
116 combo->timer != COMBO_TIMER_ELAPSED &&
117 timer_elapsed(combo->timer) > COMBO_TERM) {
118
119 /* This disables the combo, meaning key events for this
120 * combo will be handled by the next processors in the chain
121 */
122 combo->timer = COMBO_TIMER_ELAPSED;
123
124#ifdef COMBO_ALLOW_ACTION_KEYS
125 process_action(&combo->prev_record,
126 store_or_get_action(combo->prev_record.event.pressed,
127 combo->prev_record.event.key));
128#else
129 unregister_code16(combo->prev_key);
130 register_code16(combo->prev_key);
131#endif
132 }
133 }
134}
diff --git a/quantum/process_keycode/process_combo.h b/quantum/process_keycode/process_combo.h
new file mode 100644
index 000000000..847f2b737
--- /dev/null
+++ b/quantum/process_keycode/process_combo.h
@@ -0,0 +1,43 @@
1#ifndef PROCESS_COMBO_H
2#define PROCESS_COMBO_H
3
4#include <stdint.h>
5#include "progmem.h"
6#include "quantum.h"
7
8typedef struct
9{
10 const uint16_t *keys;
11 uint16_t keycode;
12#ifdef EXTRA_EXTRA_LONG_COMBOS
13 uint32_t state;
14#elif EXTRA_LONG_COMBOS
15 uint16_t state;
16#else
17 uint8_t state;
18#endif
19 uint16_t timer;
20#ifdef COMBO_ALLOW_ACTION_KEYS
21 keyrecord_t prev_record;
22#else
23 uint16_t prev_key;
24#endif
25} combo_t;
26
27
28#define COMBO(ck, ca) {.keys = &(ck)[0], .keycode = (ca)}
29#define COMBO_ACTION(ck) {.keys = &(ck)[0]}
30
31#define COMBO_END 0
32#ifndef COMBO_COUNT
33#define COMBO_COUNT 0
34#endif
35#ifndef COMBO_TERM
36#define COMBO_TERM TAPPING_TERM
37#endif
38
39bool process_combo(uint16_t keycode, keyrecord_t *record);
40void matrix_scan_combo(void);
41void process_combo_event(uint8_t combo_index, bool pressed);
42
43#endif
diff --git a/quantum/process_keycode/process_tap_dance.c b/quantum/process_keycode/process_tap_dance.c
index 6ae362c4c..403dca538 100644
--- a/quantum/process_keycode/process_tap_dance.c
+++ b/quantum/process_keycode/process_tap_dance.c
@@ -43,12 +43,16 @@ static inline void process_tap_dance_action_on_dance_finished (qk_tap_dance_acti
43 if (action->state.finished) 43 if (action->state.finished)
44 return; 44 return;
45 action->state.finished = true; 45 action->state.finished = true;
46 add_mods(action->state.oneshot_mods);
47 send_keyboard_report();
46 _process_tap_dance_action_fn (&action->state, action->user_data, action->fn.on_dance_finished); 48 _process_tap_dance_action_fn (&action->state, action->user_data, action->fn.on_dance_finished);
47} 49}
48 50
49static inline void process_tap_dance_action_on_reset (qk_tap_dance_action_t *action) 51static inline void process_tap_dance_action_on_reset (qk_tap_dance_action_t *action)
50{ 52{
51 _process_tap_dance_action_fn (&action->state, action->user_data, action->fn.on_reset); 53 _process_tap_dance_action_fn (&action->state, action->user_data, action->fn.on_reset);
54 del_mods(action->state.oneshot_mods);
55 send_keyboard_report();
52} 56}
53 57
54bool process_tap_dance(uint16_t keycode, keyrecord_t *record) { 58bool process_tap_dance(uint16_t keycode, keyrecord_t *record) {
@@ -70,6 +74,7 @@ bool process_tap_dance(uint16_t keycode, keyrecord_t *record) {
70 action->state.keycode = keycode; 74 action->state.keycode = keycode;
71 action->state.count++; 75 action->state.count++;
72 action->state.timer = timer_read(); 76 action->state.timer = timer_read();
77 action->state.oneshot_mods = get_oneshot_mods();
73 process_tap_dance_action_on_each_tap (action); 78 process_tap_dance_action_on_each_tap (action);
74 79
75 if (last_td && last_td != keycode) { 80 if (last_td && last_td != keycode) {
@@ -109,7 +114,7 @@ void matrix_scan_tap_dance () {
109 if (highest_td == -1) 114 if (highest_td == -1)
110 return; 115 return;
111 116
112 for (int i = 0; i <= highest_td; i++) { 117for (int i = 0; i <= highest_td; i++) {
113 qk_tap_dance_action_t *action = &tap_dance_actions[i]; 118 qk_tap_dance_action_t *action = &tap_dance_actions[i];
114 119
115 if (action->state.count && timer_elapsed (action->state.timer) > TAPPING_TERM) { 120 if (action->state.count && timer_elapsed (action->state.timer) > TAPPING_TERM) {
diff --git a/quantum/process_keycode/process_tap_dance.h b/quantum/process_keycode/process_tap_dance.h
index f753cbba6..726752ecc 100644
--- a/quantum/process_keycode/process_tap_dance.h
+++ b/quantum/process_keycode/process_tap_dance.h
@@ -9,6 +9,7 @@
9typedef struct 9typedef struct
10{ 10{
11 uint8_t count; 11 uint8_t count;
12 uint8_t oneshot_mods;
12 uint16_t keycode; 13 uint16_t keycode;
13 uint16_t timer; 14 uint16_t timer;
14 bool interrupted; 15 bool interrupted;
diff --git a/quantum/process_keycode/process_unicode.c b/quantum/process_keycode/process_unicode.c
index a30e93ae3..9995ba9bd 100644
--- a/quantum/process_keycode/process_unicode.c
+++ b/quantum/process_keycode/process_unicode.c
@@ -141,7 +141,16 @@ bool process_unicode_map(uint16_t keycode, keyrecord_t *record) {
141 const uint32_t* map = unicode_map; 141 const uint32_t* map = unicode_map;
142 uint16_t index = keycode & 0x7FF; 142 uint16_t index = keycode & 0x7FF;
143 uint32_t code = pgm_read_dword_far(&map[index]); 143 uint32_t code = pgm_read_dword_far(&map[index]);
144 if ((code > 0xFFFF && input_mode == UC_OSX) || (code > 0xFFFFF && input_mode == UC_LNX)) { 144 if (code > 0xFFFF && code <= 0x10ffff && input_mode == UC_OSX) {
145 // Convert to UTF-16 surrogate pair
146 code -= 0x10000;
147 uint32_t lo = code & 0x3ff;
148 uint32_t hi = (code & 0xffc00) >> 10;
149 unicode_input_start();
150 register_hex32(hi + 0xd800);
151 register_hex32(lo + 0xdc00);
152 unicode_input_finish();
153 } else if ((code > 0x10ffff && input_mode == UC_OSX) || (code > 0xFFFFF && input_mode == UC_LNX)) {
145 // when character is out of range supported by the OS 154 // when character is out of range supported by the OS
146 unicode_map_input_error(); 155 unicode_map_input_error();
147 } else { 156 } else {
diff --git a/quantum/quantum.c b/quantum/quantum.c
index 63ffe2074..d3905decf 100644
--- a/quantum/quantum.c
+++ b/quantum/quantum.c
@@ -1,4 +1,7 @@
1#include "quantum.h" 1#include "quantum.h"
2#ifdef PROTOCOL_LUFA
3#include "outputselect.h"
4#endif
2 5
3#ifndef TAPPING_TERM 6#ifndef TAPPING_TERM
4#define TAPPING_TERM 200 7#define TAPPING_TERM 200
@@ -33,14 +36,42 @@ static void do_code16 (uint16_t code, void (*f) (uint8_t)) {
33 f(KC_RGUI); 36 f(KC_RGUI);
34} 37}
35 38
39static inline void qk_register_weak_mods(uint8_t kc) {
40 add_weak_mods(MOD_BIT(kc));
41 send_keyboard_report();
42}
43
44static inline void qk_unregister_weak_mods(uint8_t kc) {
45 del_weak_mods(MOD_BIT(kc));
46 send_keyboard_report();
47}
48
49static inline void qk_register_mods(uint8_t kc) {
50 add_weak_mods(MOD_BIT(kc));
51 send_keyboard_report();
52}
53
54static inline void qk_unregister_mods(uint8_t kc) {
55 del_weak_mods(MOD_BIT(kc));
56 send_keyboard_report();
57}
58
36void register_code16 (uint16_t code) { 59void register_code16 (uint16_t code) {
37 do_code16 (code, register_code); 60 if (IS_MOD(code) || code == KC_NO) {
61 do_code16 (code, qk_register_mods);
62 } else {
63 do_code16 (code, qk_register_weak_mods);
64 }
38 register_code (code); 65 register_code (code);
39} 66}
40 67
41void unregister_code16 (uint16_t code) { 68void unregister_code16 (uint16_t code) {
42 unregister_code (code); 69 unregister_code (code);
43 do_code16 (code, unregister_code); 70 if (IS_MOD(code) || code == KC_NO) {
71 do_code16 (code, qk_unregister_mods);
72 } else {
73 do_code16 (code, qk_unregister_weak_mods);
74 }
44} 75}
45 76
46__attribute__ ((weak)) 77__attribute__ ((weak))
@@ -130,6 +161,9 @@ bool process_record_quantum(keyrecord_t *record) {
130 #ifndef DISABLE_CHORDING 161 #ifndef DISABLE_CHORDING
131 process_chording(keycode, record) && 162 process_chording(keycode, record) &&
132 #endif 163 #endif
164 #ifdef COMBO_ENABLE
165 process_combo(keycode, record) &&
166 #endif
133 #ifdef UNICODE_ENABLE 167 #ifdef UNICODE_ENABLE
134 process_unicode(keycode, record) && 168 process_unicode(keycode, record) &&
135 #endif 169 #endif
@@ -212,6 +246,36 @@ bool process_record_quantum(keyrecord_t *record) {
212 return false; 246 return false;
213 break; 247 break;
214 #endif 248 #endif
249 #ifdef PROTOCOL_LUFA
250 case OUT_AUTO:
251 if (record->event.pressed) {
252 set_output(OUTPUT_AUTO);
253 }
254 return false;
255 break;
256 case OUT_USB:
257 if (record->event.pressed) {
258 set_output(OUTPUT_USB);
259 }
260 return false;
261 break;
262 #ifdef BLUETOOTH_ENABLE
263 case OUT_BT:
264 if (record->event.pressed) {
265 set_output(OUTPUT_BLUETOOTH);
266 }
267 return false;
268 break;
269 #endif
270 #ifdef ADAFRUIT_BLE_ENABLE
271 case OUT_BLE:
272 if (record->event.pressed) {
273 set_output(OUTPUT_ADAFRUIT_BLE);
274 }
275 return false;
276 break;
277 #endif
278 #endif
215 case MAGIC_SWAP_CONTROL_CAPSLOCK ... MAGIC_TOGGLE_NKRO: 279 case MAGIC_SWAP_CONTROL_CAPSLOCK ... MAGIC_TOGGLE_NKRO:
216 if (record->event.pressed) { 280 if (record->event.pressed) {
217 // MAGIC actions (BOOTMAGIC without the boot) 281 // MAGIC actions (BOOTMAGIC without the boot)
@@ -508,6 +572,11 @@ void matrix_scan_quantum() {
508 #ifdef TAP_DANCE_ENABLE 572 #ifdef TAP_DANCE_ENABLE
509 matrix_scan_tap_dance(); 573 matrix_scan_tap_dance();
510 #endif 574 #endif
575
576 #ifdef COMBO_ENABLE
577 matrix_scan_combo();
578 #endif
579
511 matrix_scan_kb(); 580 matrix_scan_kb();
512} 581}
513 582
diff --git a/quantum/quantum.h b/quantum/quantum.h
index e6adf974a..18f072189 100644
--- a/quantum/quantum.h
+++ b/quantum/quantum.h
@@ -15,7 +15,6 @@
15#ifdef RGBLIGHT_ENABLE 15#ifdef RGBLIGHT_ENABLE
16 #include "rgblight.h" 16 #include "rgblight.h"
17#endif 17#endif
18
19#include "action_layer.h" 18#include "action_layer.h"
20#include "eeconfig.h" 19#include "eeconfig.h"
21#include <stddef.h> 20#include <stddef.h>
@@ -63,6 +62,10 @@ extern uint32_t default_layer_state;
63 #include "process_printer.h" 62 #include "process_printer.h"
64#endif 63#endif
65 64
65#ifdef COMBO_ENABLE
66 #include "process_combo.h"
67#endif
68
66#define SEND_STRING(str) send_string(PSTR(str)) 69#define SEND_STRING(str) send_string(PSTR(str))
67void send_string(const char *str); 70void send_string(const char *str);
68 71
diff --git a/quantum/quantum_keycodes.h b/quantum/quantum_keycodes.h
index e0d469561..8a78a58c9 100644
--- a/quantum/quantum_keycodes.h
+++ b/quantum/quantum_keycodes.h
@@ -141,6 +141,16 @@ enum quantum_keycodes {
141 PRINT_ON, 141 PRINT_ON,
142 PRINT_OFF, 142 PRINT_OFF,
143 143
144 // output selection
145 OUT_AUTO,
146 OUT_USB,
147#ifdef BLUETOOTH_ENABLE
148 OUT_BT,
149#endif
150#ifdef ADAFRUIT_BLE_ENABLE
151 OUT_BLE,
152#endif
153
144 // always leave at the end 154 // always leave at the end
145 SAFE_RANGE 155 SAFE_RANGE
146}; 156};
@@ -292,6 +302,7 @@ enum quantum_keycodes {
292#define CTL_T(kc) MT(MOD_LCTL, kc) 302#define CTL_T(kc) MT(MOD_LCTL, kc)
293#define SFT_T(kc) MT(MOD_LSFT, kc) 303#define SFT_T(kc) MT(MOD_LSFT, kc)
294#define ALT_T(kc) MT(MOD_LALT, kc) 304#define ALT_T(kc) MT(MOD_LALT, kc)
305#define ALGR_T(kc) MT(MOD_RALT, kc) // dual-function AltGR
295#define GUI_T(kc) MT(MOD_LGUI, kc) 306#define GUI_T(kc) MT(MOD_LGUI, kc)
296#define C_S_T(kc) MT((MOD_LCTL | MOD_LSFT), kc) // Control + Shift e.g. for gnome-terminal 307#define C_S_T(kc) MT((MOD_LCTL | MOD_LSFT), kc) // Control + Shift e.g. for gnome-terminal
297#define MEH_T(kc) MT((MOD_LCTL | MOD_LSFT | MOD_LALT), kc) // Meh is a less hyper version of the Hyper key -- doesn't include Win or Cmd, so just alt+shift+ctrl 308#define MEH_T(kc) MT((MOD_LCTL | MOD_LSFT | MOD_LALT), kc) // Meh is a less hyper version of the Hyper key -- doesn't include Win or Cmd, so just alt+shift+ctrl