aboutsummaryrefslogtreecommitdiff
path: root/quantum/process_keycode
diff options
context:
space:
mode:
Diffstat (limited to 'quantum/process_keycode')
-rw-r--r--quantum/process_keycode/process_auto_shift.c2
-rw-r--r--quantum/process_keycode/process_chording.c76
-rw-r--r--quantum/process_keycode/process_chording.h32
-rw-r--r--quantum/process_keycode/process_clicky.c72
-rw-r--r--quantum/process_keycode/process_clicky.h10
-rw-r--r--quantum/process_keycode/process_leader.c49
-rw-r--r--quantum/process_keycode/process_leader.h2
-rw-r--r--quantum/process_keycode/process_tap_dance.c6
-rw-r--r--quantum/process_keycode/process_tap_dance.h1
-rw-r--r--quantum/process_keycode/process_terminal.c6
-rw-r--r--quantum/process_keycode/process_ucis.c8
-rw-r--r--quantum/process_keycode/process_ucis.h6
-rw-r--r--quantum/process_keycode/process_unicode.c7
-rw-r--r--quantum/process_keycode/process_unicode.h5
-rw-r--r--quantum/process_keycode/process_unicode_common.c223
-rw-r--r--quantum/process_keycode/process_unicode_common.h68
-rw-r--r--quantum/process_keycode/process_unicodemap.c33
-rw-r--r--quantum/process_keycode/process_unicodemap.h8
18 files changed, 353 insertions, 261 deletions
diff --git a/quantum/process_keycode/process_auto_shift.c b/quantum/process_keycode/process_auto_shift.c
index 01d99445b..0d0930ee6 100644
--- a/quantum/process_keycode/process_auto_shift.c
+++ b/quantum/process_keycode/process_auto_shift.c
@@ -173,6 +173,8 @@ bool process_auto_shift(uint16_t keycode, keyrecord_t *record) {
173 case KC_DOT: 173 case KC_DOT:
174 case KC_SLSH: 174 case KC_SLSH:
175 case KC_GRAVE: 175 case KC_GRAVE:
176 case KC_NONUS_BSLASH:
177 case KC_NONUS_HASH:
176#endif 178#endif
177 179
178 autoshift_flush(); 180 autoshift_flush();
diff --git a/quantum/process_keycode/process_chording.c b/quantum/process_keycode/process_chording.c
deleted file mode 100644
index 6c6ebe300..000000000
--- a/quantum/process_keycode/process_chording.c
+++ /dev/null
@@ -1,76 +0,0 @@
1/* Copyright 2016 Jack Humbert
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
17#include "process_chording.h"
18
19bool keys_chord(uint8_t keys[]) {
20 uint8_t keys_size = sizeof(keys)/sizeof(keys[0]);
21 bool pass = true;
22 uint8_t in = 0;
23 for (uint8_t i = 0; i < chord_key_count; i++) {
24 bool found = false;
25 for (uint8_t j = 0; j < keys_size; j++) {
26 if (chord_keys[i] == (keys[j] & 0xFF)) {
27 in++; // detects key in chord
28 found = true;
29 break;
30 }
31 }
32 if (found)
33 continue;
34 if (chord_keys[i] != 0) {
35 pass = false; // makes sure rest are blank
36 }
37 }
38 return (pass && (in == keys_size));
39}
40
41bool process_chording(uint16_t keycode, keyrecord_t *record) {
42 if (keycode >= QK_CHORDING && keycode <= QK_CHORDING_MAX) {
43 if (record->event.pressed) {
44 if (!chording) {
45 chording = true;
46 for (uint8_t i = 0; i < CHORDING_MAX; i++)
47 chord_keys[i] = 0;
48 chord_key_count = 0;
49 chord_key_down = 0;
50 }
51 chord_keys[chord_key_count] = (keycode & 0xFF);
52 chord_key_count++;
53 chord_key_down++;
54 return false;
55 } else {
56 if (chording) {
57 chord_key_down--;
58 if (chord_key_down == 0) {
59 chording = false;
60 // Chord Dictionary
61 if (keys_chord((uint8_t[]){KC_ENTER, KC_SPACE})) {
62 register_code(KC_A);
63 unregister_code(KC_A);
64 return false;
65 }
66 for (uint8_t i = 0; i < chord_key_count; i++) {
67 register_code(chord_keys[i]);
68 unregister_code(chord_keys[i]);
69 return false;
70 }
71 }
72 }
73 }
74 }
75 return true;
76}
diff --git a/quantum/process_keycode/process_chording.h b/quantum/process_keycode/process_chording.h
deleted file mode 100644
index 8c0f4862a..000000000
--- a/quantum/process_keycode/process_chording.h
+++ /dev/null
@@ -1,32 +0,0 @@
1/* Copyright 2016 Jack Humbert
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
17#ifndef PROCESS_CHORDING_H
18#define PROCESS_CHORDING_H
19
20#include "quantum.h"
21
22// Chording stuff
23#define CHORDING_MAX 4
24bool chording = false;
25
26uint8_t chord_keys[CHORDING_MAX] = {0};
27uint8_t chord_key_count = 0;
28uint8_t chord_key_down = 0;
29
30bool process_chording(uint16_t keycode, keyrecord_t *record);
31
32#endif
diff --git a/quantum/process_keycode/process_clicky.c b/quantum/process_keycode/process_clicky.c
index 1e950d111..8238c263f 100644
--- a/quantum/process_keycode/process_clicky.c
+++ b/quantum/process_keycode/process_clicky.c
@@ -3,11 +3,6 @@
3 3
4#ifdef AUDIO_CLICKY 4#ifdef AUDIO_CLICKY
5 5
6#ifdef AUDIO_CLICKY_ON
7bool clicky_enable = true;
8#else // AUDIO_CLICKY_ON
9bool clicky_enable = false;
10#endif // AUDIO_CLICKY_ON
11#ifndef AUDIO_CLICKY_FREQ_DEFAULT 6#ifndef AUDIO_CLICKY_FREQ_DEFAULT
12#define AUDIO_CLICKY_FREQ_DEFAULT 440.0f 7#define AUDIO_CLICKY_FREQ_DEFAULT 440.0f
13#endif // !AUDIO_CLICKY_FREQ_DEFAULT 8#endif // !AUDIO_CLICKY_FREQ_DEFAULT
@@ -25,8 +20,11 @@ bool clicky_enable = false;
25#endif // !AUDIO_CLICKY_FREQ_RANDOMNESS 20#endif // !AUDIO_CLICKY_FREQ_RANDOMNESS
26 21
27float clicky_freq = AUDIO_CLICKY_FREQ_DEFAULT; 22float clicky_freq = AUDIO_CLICKY_FREQ_DEFAULT;
23float clicky_rand = AUDIO_CLICKY_FREQ_RANDOMNESS;
28float clicky_song[][2] = {{AUDIO_CLICKY_FREQ_DEFAULT, 3}, {AUDIO_CLICKY_FREQ_DEFAULT, 1}}; // 3 and 1 --> durations 24float clicky_song[][2] = {{AUDIO_CLICKY_FREQ_DEFAULT, 3}, {AUDIO_CLICKY_FREQ_DEFAULT, 1}}; // 3 and 1 --> durations
29 25
26extern audio_config_t audio_config;
27
30#ifndef NO_MUSIC_MODE 28#ifndef NO_MUSIC_MODE
31extern bool music_activated; 29extern bool music_activated;
32extern bool midi_activated; 30extern bool midi_activated;
@@ -36,31 +34,61 @@ void clicky_play(void) {
36#ifndef NO_MUSIC_MODE 34#ifndef NO_MUSIC_MODE
37 if (music_activated || midi_activated) return; 35 if (music_activated || midi_activated) return;
38#endif // !NO_MUSIC_MODE 36#endif // !NO_MUSIC_MODE
39 clicky_song[0][0] = 2.0f * clicky_freq * (1.0f + AUDIO_CLICKY_FREQ_RANDOMNESS * ( ((float)rand()) / ((float)(RAND_MAX)) ) ); 37 clicky_song[0][0] = 2.0f * clicky_freq * (1.0f + clicky_rand * ( ((float)rand()) / ((float)(RAND_MAX)) ) );
40 clicky_song[1][0] = clicky_freq * (1.0f + AUDIO_CLICKY_FREQ_RANDOMNESS * ( ((float)rand()) / ((float)(RAND_MAX)) ) ); 38 clicky_song[1][0] = clicky_freq * (1.0f + clicky_rand * ( ((float)rand()) / ((float)(RAND_MAX)) ) );
41 PLAY_SONG(clicky_song); 39 PLAY_SONG(clicky_song);
42} 40}
43 41
42void clicky_freq_up(void) {
43 float new_freq = clicky_freq * AUDIO_CLICKY_FREQ_FACTOR;
44 if (new_freq < AUDIO_CLICKY_FREQ_MAX) {
45 clicky_freq = new_freq;
46 }
47}
48
49void clicky_freq_down(void) {
50 float new_freq = clicky_freq / AUDIO_CLICKY_FREQ_FACTOR;
51 if (new_freq > AUDIO_CLICKY_FREQ_MIN) {
52 clicky_freq = new_freq;
53 }
54}
55
56void clicky_freq_reset(void) {
57 clicky_freq = AUDIO_CLICKY_FREQ_DEFAULT;
58}
59
60void clicky_toggle(void) {
61 audio_config.clicky_enable ^= 1;
62 eeconfig_update_audio(audio_config.raw);
63}
64
65void clicky_on(void) {
66 audio_config.clicky_enable = 1;
67 eeconfig_update_audio(audio_config.raw);
68}
69
70void clicky_off(void) {
71 audio_config.clicky_enable = 0;
72 eeconfig_update_audio(audio_config.raw);
73}
74
75bool is_clicky_on(void) {
76 return (audio_config.clicky_enable != 0);
77}
78
44bool process_clicky(uint16_t keycode, keyrecord_t *record) { 79bool process_clicky(uint16_t keycode, keyrecord_t *record) {
45 if (keycode == CLICKY_TOGGLE && record->event.pressed) { clicky_enable = !clicky_enable; } 80 if (keycode == CLICKY_TOGGLE && record->event.pressed) { clicky_toggle(); }
46 81
47 if (keycode == CLICKY_RESET && record->event.pressed) { clicky_freq = AUDIO_CLICKY_FREQ_DEFAULT; } 82 if (keycode == CLICKY_ENABLE && record->event.pressed) { clicky_on(); }
83 if (keycode == CLICKY_DISABLE && record->event.pressed) { clicky_off(); }
48 84
49 if (keycode == CLICKY_UP && record->event.pressed) { 85 if (keycode == CLICKY_RESET && record->event.pressed) { clicky_freq_reset(); }
50 float new_freq = clicky_freq * AUDIO_CLICKY_FREQ_FACTOR; 86
51 if (new_freq < AUDIO_CLICKY_FREQ_MAX) { 87 if (keycode == CLICKY_UP && record->event.pressed) { clicky_freq_up(); }
52 clicky_freq = new_freq; 88 if (keycode == CLICKY_DOWN && record->event.pressed) { clicky_freq_down(); }
53 }
54 }
55 if (keycode == CLICKY_DOWN && record->event.pressed) {
56 float new_freq = clicky_freq / AUDIO_CLICKY_FREQ_FACTOR;
57 if (new_freq > AUDIO_CLICKY_FREQ_MIN) {
58 clicky_freq = new_freq;
59 }
60 }
61 89
62 90
63 if ( clicky_enable ) { 91 if ( audio_config.clicky_enable ) {
64 if (record->event.pressed) { 92 if (record->event.pressed) {
65 clicky_play();; 93 clicky_play();;
66 } 94 }
diff --git a/quantum/process_keycode/process_clicky.h b/quantum/process_keycode/process_clicky.h
index e274af56f..f746edb95 100644
--- a/quantum/process_keycode/process_clicky.h
+++ b/quantum/process_keycode/process_clicky.h
@@ -4,4 +4,14 @@
4void clicky_play(void); 4void clicky_play(void);
5bool process_clicky(uint16_t keycode, keyrecord_t *record); 5bool process_clicky(uint16_t keycode, keyrecord_t *record);
6 6
7void clicky_freq_up(void);
8void clicky_freq_down(void);
9void clicky_freq_reset(void);
10
11void clicky_toggle(void);
12void clicky_on(void);
13void clicky_off(void);
14
15bool is_clicky_on(void);
16
7#endif 17#endif
diff --git a/quantum/process_keycode/process_leader.c b/quantum/process_keycode/process_leader.c
index c87ef115a..897e9eabf 100644
--- a/quantum/process_keycode/process_leader.c
+++ b/quantum/process_keycode/process_leader.c
@@ -14,7 +14,7 @@
14 * along with this program. If not, see <http://www.gnu.org/licenses/>. 14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */ 15 */
16 16
17#ifndef DISABLE_LEADER 17#ifdef LEADER_ENABLE
18 18
19#include "process_leader.h" 19#include "process_leader.h"
20 20
@@ -35,25 +35,40 @@ uint16_t leader_time = 0;
35uint16_t leader_sequence[5] = {0, 0, 0, 0, 0}; 35uint16_t leader_sequence[5] = {0, 0, 0, 0, 0};
36uint8_t leader_sequence_size = 0; 36uint8_t leader_sequence_size = 0;
37 37
38void qk_leader_start(void) {
39 if (leading) { return; }
40 leader_start();
41 leading = true;
42 leader_time = timer_read();
43 leader_sequence_size = 0;
44 leader_sequence[0] = 0;
45 leader_sequence[1] = 0;
46 leader_sequence[2] = 0;
47 leader_sequence[3] = 0;
48 leader_sequence[4] = 0;
49}
50
38bool process_leader(uint16_t keycode, keyrecord_t *record) { 51bool process_leader(uint16_t keycode, keyrecord_t *record) {
39 // Leader key set-up 52 // Leader key set-up
40 if (record->event.pressed) { 53 if (record->event.pressed) {
41 if (!leading && keycode == KC_LEAD) { 54 if (leading) {
42 leader_start(); 55 if (timer_elapsed(leader_time) < LEADER_TIMEOUT) {
43 leading = true; 56#ifndef LEADER_KEY_STRICT_KEY_PROCESSING
44 leader_time = timer_read(); 57 if ((keycode >= QK_MOD_TAP && keycode <= QK_MOD_TAP_MAX) || (keycode >= QK_LAYER_TAP && keycode <= QK_LAYER_TAP_MAX)) {
45 leader_sequence_size = 0; 58 keycode = keycode & 0xFF;
46 leader_sequence[0] = 0; 59 }
47 leader_sequence[1] = 0; 60#endif // LEADER_KEY_STRICT_KEY_PROCESSING
48 leader_sequence[2] = 0; 61 leader_sequence[leader_sequence_size] = keycode;
49 leader_sequence[3] = 0; 62 leader_sequence_size++;
50 leader_sequence[4] = 0; 63#ifdef LEADER_PER_KEY_TIMING
51 return false; 64 leader_time = timer_read();
52 } 65#endif
53 if (leading && timer_elapsed(leader_time) < LEADER_TIMEOUT) { 66 return false;
54 leader_sequence[leader_sequence_size] = keycode; 67 }
55 leader_sequence_size++; 68 } else {
56 return false; 69 if (keycode == KC_LEAD) {
70 qk_leader_start();
71 }
57 } 72 }
58 } 73 }
59 return true; 74 return true;
diff --git a/quantum/process_keycode/process_leader.h b/quantum/process_keycode/process_leader.h
index 59c3eed1b..15bccc3f6 100644
--- a/quantum/process_keycode/process_leader.h
+++ b/quantum/process_keycode/process_leader.h
@@ -24,7 +24,7 @@ bool process_leader(uint16_t keycode, keyrecord_t *record);
24 24
25void leader_start(void); 25void leader_start(void);
26void leader_end(void); 26void leader_end(void);
27 27void qk_leader_start(void);
28 28
29#define SEQ_ONE_KEY(key) if (leader_sequence[0] == (key) && leader_sequence[1] == 0 && leader_sequence[2] == 0 && leader_sequence[3] == 0 && leader_sequence[4] == 0) 29#define SEQ_ONE_KEY(key) if (leader_sequence[0] == (key) && leader_sequence[1] == 0 && leader_sequence[2] == 0 && leader_sequence[3] == 0 && leader_sequence[4] == 0)
30#define SEQ_TWO_KEYS(key1, key2) if (leader_sequence[0] == (key1) && leader_sequence[1] == (key2) && leader_sequence[2] == 0 && leader_sequence[3] == 0 && leader_sequence[4] == 0) 30#define SEQ_TWO_KEYS(key1, key2) if (leader_sequence[0] == (key1) && leader_sequence[1] == (key2) && leader_sequence[2] == 0 && leader_sequence[3] == 0 && leader_sequence[4] == 0)
diff --git a/quantum/process_keycode/process_tap_dance.c b/quantum/process_keycode/process_tap_dance.c
index 833780691..16d33ddde 100644
--- a/quantum/process_keycode/process_tap_dance.c
+++ b/quantum/process_keycode/process_tap_dance.c
@@ -16,6 +16,10 @@
16#include "quantum.h" 16#include "quantum.h"
17#include "action_tapping.h" 17#include "action_tapping.h"
18 18
19#ifndef TAPPING_TERM
20#define TAPPING_TERM 200
21#endif
22
19#ifndef NO_ACTION_ONESHOT 23#ifndef NO_ACTION_ONESHOT
20uint8_t get_oneshot_mods(void); 24uint8_t get_oneshot_mods(void);
21#endif 25#endif
@@ -127,6 +131,7 @@ void preprocess_tap_dance(uint16_t keycode, keyrecord_t *record) {
127 if (keycode == action->state.keycode && keycode == last_td) 131 if (keycode == action->state.keycode && keycode == last_td)
128 continue; 132 continue;
129 action->state.interrupted = true; 133 action->state.interrupted = true;
134 action->state.interrupting_keycode = keycode;
130 process_tap_dance_action_on_dance_finished (action); 135 process_tap_dance_action_on_dance_finished (action);
131 reset_tap_dance (&action->state); 136 reset_tap_dance (&action->state);
132 } 137 }
@@ -205,5 +210,6 @@ void reset_tap_dance (qk_tap_dance_state_t *state) {
205 state->count = 0; 210 state->count = 0;
206 state->interrupted = false; 211 state->interrupted = false;
207 state->finished = false; 212 state->finished = false;
213 state->interrupting_keycode = 0;
208 last_td = 0; 214 last_td = 0;
209} 215}
diff --git a/quantum/process_keycode/process_tap_dance.h b/quantum/process_keycode/process_tap_dance.h
index 8b0a47c49..ca12f4746 100644
--- a/quantum/process_keycode/process_tap_dance.h
+++ b/quantum/process_keycode/process_tap_dance.h
@@ -27,6 +27,7 @@ typedef struct
27 uint8_t oneshot_mods; 27 uint8_t oneshot_mods;
28 uint8_t weak_mods; 28 uint8_t weak_mods;
29 uint16_t keycode; 29 uint16_t keycode;
30 uint16_t interrupting_keycode;
30 uint16_t timer; 31 uint16_t timer;
31 bool interrupted; 32 bool interrupted;
32 bool pressed; 33 bool pressed;
diff --git a/quantum/process_keycode/process_terminal.c b/quantum/process_keycode/process_terminal.c
index 6998639f2..e791deffc 100644
--- a/quantum/process_keycode/process_terminal.c
+++ b/quantum/process_keycode/process_terminal.c
@@ -273,11 +273,17 @@ bool process_terminal(uint16_t keycode, keyrecord_t *record) {
273 disable_terminal(); 273 disable_terminal();
274 return false; 274 return false;
275 } 275 }
276
277 if ((keycode >= QK_MOD_TAP && keycode <= QK_MOD_TAP_MAX) || (keycode >= QK_LAYER_TAP && keycode <= QK_LAYER_TAP_MAX)) {
278 keycode = keycode & 0xFF;
279 }
280
276 if (keycode < 256) { 281 if (keycode < 256) {
277 uint8_t str_len; 282 uint8_t str_len;
278 char char_to_add; 283 char char_to_add;
279 switch (keycode) { 284 switch (keycode) {
280 case KC_ENTER: 285 case KC_ENTER:
286 case KC_KP_ENTER:
281 push_to_cmd_buffer(); 287 push_to_cmd_buffer();
282 current_cmd_buffer_pos = 0; 288 current_cmd_buffer_pos = 0;
283 process_terminal_command(); 289 process_terminal_command();
diff --git a/quantum/process_keycode/process_ucis.c b/quantum/process_keycode/process_ucis.c
index 86c0937f5..5de2e41fc 100644
--- a/quantum/process_keycode/process_ucis.c
+++ b/quantum/process_keycode/process_ucis.c
@@ -32,6 +32,10 @@ void qk_ucis_start_user(void) {
32 unicode_input_finish(); 32 unicode_input_finish();
33} 33}
34 34
35__attribute__((weak))
36void qk_ucis_success(uint8_t symbol_index) {
37}
38
35static bool is_uni_seq(char *seq) { 39static bool is_uni_seq(char *seq) {
36 uint8_t i; 40 uint8_t i;
37 41
@@ -142,6 +146,10 @@ bool process_ucis (uint16_t keycode, keyrecord_t *record) {
142 } 146 }
143 unicode_input_finish(); 147 unicode_input_finish();
144 148
149 if (symbol_found) {
150 qk_ucis_success(i);
151 }
152
145 qk_ucis_state.in_progress = false; 153 qk_ucis_state.in_progress = false;
146 return false; 154 return false;
147 } 155 }
diff --git a/quantum/process_keycode/process_ucis.h b/quantum/process_keycode/process_ucis.h
index 3f736a709..b114d839a 100644
--- a/quantum/process_keycode/process_ucis.h
+++ b/quantum/process_keycode/process_ucis.h
@@ -14,8 +14,7 @@
14 * along with this program. If not, see <http://www.gnu.org/licenses/>. 14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */ 15 */
16 16
17#ifndef PROCESS_UCIS_H 17#pragma once
18#define PROCESS_UCIS_H
19 18
20#include "quantum.h" 19#include "quantum.h"
21#include "process_unicode_common.h" 20#include "process_unicode_common.h"
@@ -45,7 +44,6 @@ extern const qk_ucis_symbol_t ucis_symbol_table[];
45void qk_ucis_start(void); 44void qk_ucis_start(void);
46void qk_ucis_start_user(void); 45void qk_ucis_start_user(void);
47void qk_ucis_symbol_fallback (void); 46void qk_ucis_symbol_fallback (void);
47void qk_ucis_success(uint8_t symbol_index);
48void register_ucis(const char *hex); 48void register_ucis(const char *hex);
49bool process_ucis (uint16_t keycode, keyrecord_t *record); 49bool process_ucis (uint16_t keycode, keyrecord_t *record);
50
51#endif
diff --git a/quantum/process_keycode/process_unicode.c b/quantum/process_keycode/process_unicode.c
index fd008eca1..19beb8452 100644
--- a/quantum/process_keycode/process_unicode.c
+++ b/quantum/process_keycode/process_unicode.c
@@ -17,14 +17,8 @@
17#include "action_util.h" 17#include "action_util.h"
18#include "eeprom.h" 18#include "eeprom.h"
19 19
20static uint8_t first_flag = 0;
21
22bool process_unicode(uint16_t keycode, keyrecord_t *record) { 20bool process_unicode(uint16_t keycode, keyrecord_t *record) {
23 if (keycode > QK_UNICODE && record->event.pressed) { 21 if (keycode > QK_UNICODE && record->event.pressed) {
24 if (first_flag == 0) {
25 set_unicode_input_mode(eeprom_read_byte(EECONFIG_UNICODEMODE));
26 first_flag = 1;
27 }
28 uint16_t unicode = keycode & 0x7FFF; 22 uint16_t unicode = keycode & 0x7FFF;
29 unicode_input_start(); 23 unicode_input_start();
30 register_hex(unicode); 24 register_hex(unicode);
@@ -32,4 +26,3 @@ bool process_unicode(uint16_t keycode, keyrecord_t *record) {
32 } 26 }
33 return true; 27 return true;
34} 28}
35
diff --git a/quantum/process_keycode/process_unicode.h b/quantum/process_keycode/process_unicode.h
index c525b74f0..0913e9910 100644
--- a/quantum/process_keycode/process_unicode.h
+++ b/quantum/process_keycode/process_unicode.h
@@ -13,12 +13,9 @@
13 * You should have received a copy of the GNU General Public License 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/>. 14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */ 15 */
16#ifndef PROCESS_UNICODE_H 16#pragma once
17#define PROCESS_UNICODE_H
18 17
19#include "quantum.h" 18#include "quantum.h"
20#include "process_unicode_common.h" 19#include "process_unicode_common.h"
21 20
22bool process_unicode(uint16_t keycode, keyrecord_t *record); 21bool process_unicode(uint16_t keycode, keyrecord_t *record);
23
24#endif
diff --git a/quantum/process_keycode/process_unicode_common.c b/quantum/process_keycode/process_unicode_common.c
index 7f34ad57c..b64feb700 100644
--- a/quantum/process_keycode/process_unicode_common.c
+++ b/quantum/process_keycode/process_unicode_common.c
@@ -16,94 +16,115 @@
16 16
17#include "process_unicode_common.h" 17#include "process_unicode_common.h"
18#include "eeprom.h" 18#include "eeprom.h"
19#include <ctype.h>
20#include <string.h>
19 21
20static uint8_t input_mode; 22unicode_config_t unicode_config;
21uint8_t mods; 23#if UNICODE_SELECTED_MODES != -1
24static uint8_t selected[] = { UNICODE_SELECTED_MODES };
25static uint8_t selected_count = sizeof selected / sizeof *selected;
26static uint8_t selected_index;
27#endif
22 28
23void set_unicode_input_mode(uint8_t os_target) 29void unicode_input_mode_init(void) {
24{ 30 unicode_config.raw = eeprom_read_byte(EECONFIG_UNICODEMODE);
25 input_mode = os_target; 31#if UNICODE_SELECTED_MODES != -1
26 eeprom_update_byte(EECONFIG_UNICODEMODE, os_target); 32 #if UNICODE_CYCLE_PERSIST
33 // Find input_mode in selected modes
34 uint8_t i;
35 for (i = 0; i < selected_count; i++) {
36 if (selected[i] == unicode_config.input_mode) {
37 selected_index = i;
38 break;
39 }
40 }
41 if (i == selected_count) {
42 // Not found: input_mode isn't selected, change to one that is
43 unicode_config.input_mode = selected[selected_index = 0];
44 }
45 #else
46 // Always change to the first selected input mode
47 unicode_config.input_mode = selected[selected_index = 0];
48 #endif
49#endif
50 dprintf("Unicode input mode init to: %u\n", unicode_config.input_mode);
27} 51}
28 52
29uint8_t get_unicode_input_mode(void) { 53uint8_t get_unicode_input_mode(void) {
30 return input_mode; 54 return unicode_config.input_mode;
31} 55}
32 56
57void set_unicode_input_mode(uint8_t mode) {
58 unicode_config.input_mode = mode;
59 persist_unicode_input_mode();
60 dprintf("Unicode input mode set to: %u\n", unicode_config.input_mode);
61}
62
63void cycle_unicode_input_mode(uint8_t offset) {
64#if UNICODE_SELECTED_MODES != -1
65 selected_index = (selected_index + offset) % selected_count;
66 unicode_config.input_mode = selected[selected_index];
67 #if UNICODE_CYCLE_PERSIST
68 persist_unicode_input_mode();
69 #endif
70 dprintf("Unicode input mode cycle to: %u\n", unicode_config.input_mode);
71#endif
72}
73
74void persist_unicode_input_mode(void) {
75 eeprom_update_byte(EECONFIG_UNICODEMODE, unicode_config.input_mode);
76}
77
78static uint8_t saved_mods;
79
33__attribute__((weak)) 80__attribute__((weak))
34void unicode_input_start (void) { 81void unicode_input_start(void) {
35 // save current mods 82 saved_mods = get_mods(); // Save current mods
36 mods = keyboard_report->mods; 83 clear_mods(); // Unregister mods to start from a clean state
37 84
38 // unregister all mods to start from clean state 85 switch (unicode_config.input_mode) {
39 if (mods & MOD_BIT(KC_LSFT)) unregister_code(KC_LSFT);
40 if (mods & MOD_BIT(KC_RSFT)) unregister_code(KC_RSFT);
41 if (mods & MOD_BIT(KC_LCTL)) unregister_code(KC_LCTL);
42 if (mods & MOD_BIT(KC_RCTL)) unregister_code(KC_RCTL);
43 if (mods & MOD_BIT(KC_LALT)) unregister_code(KC_LALT);
44 if (mods & MOD_BIT(KC_RALT)) unregister_code(KC_RALT);
45 if (mods & MOD_BIT(KC_LGUI)) unregister_code(KC_LGUI);
46 if (mods & MOD_BIT(KC_RGUI)) unregister_code(KC_RGUI);
47
48 switch(input_mode) {
49 case UC_OSX: 86 case UC_OSX:
50 register_code(KC_LALT); 87 register_code(UNICODE_OSX_KEY);
51 break;
52 case UC_OSX_RALT:
53 register_code(KC_RALT);
54 break; 88 break;
55 case UC_LNX: 89 case UC_LNX:
56 register_code(KC_LCTL); 90 register_code(KC_LCTL);
57 register_code(KC_LSFT); 91 register_code(KC_LSFT);
58 register_code(KC_U); 92 tap_code(KC_U); // TODO: Replace with tap_code16(LCTL(LSFT(KC_U))); and test
59 unregister_code(KC_U);
60 unregister_code(KC_LSFT); 93 unregister_code(KC_LSFT);
61 unregister_code(KC_LCTL); 94 unregister_code(KC_LCTL);
62 break; 95 break;
63 case UC_WIN: 96 case UC_WIN:
64 register_code(KC_LALT); 97 register_code(KC_LALT);
65 register_code(KC_PPLS); 98 tap_code(KC_PPLS);
66 unregister_code(KC_PPLS);
67 break; 99 break;
68 case UC_WINC: 100 case UC_WINC:
69 register_code(KC_RALT); 101 tap_code(UNICODE_WINC_KEY);
70 unregister_code(KC_RALT); 102 tap_code(KC_U);
71 register_code(KC_U); 103 break;
72 unregister_code(KC_U);
73 } 104 }
105
74 wait_ms(UNICODE_TYPE_DELAY); 106 wait_ms(UNICODE_TYPE_DELAY);
75} 107}
76 108
77__attribute__((weak)) 109__attribute__((weak))
78void unicode_input_finish (void) { 110void unicode_input_finish(void) {
79 switch(input_mode) { 111 switch (unicode_config.input_mode) {
80 case UC_OSX: 112 case UC_OSX:
81 case UC_WIN: 113 unregister_code(UNICODE_OSX_KEY);
82 unregister_code(KC_LALT); 114 break;
83 break; 115 case UC_LNX:
84 case UC_OSX_RALT: 116 tap_code(KC_SPC);
85 unregister_code(KC_RALT); 117 break;
86 break; 118 case UC_WIN:
87 case UC_LNX: 119 unregister_code(KC_LALT);
88 register_code(KC_SPC); 120 break;
89 unregister_code(KC_SPC);
90 break;
91 } 121 }
92 122
93 // reregister previously set mods 123 set_mods(saved_mods); // Reregister previously set mods
94 if (mods & MOD_BIT(KC_LSFT)) register_code(KC_LSFT);
95 if (mods & MOD_BIT(KC_RSFT)) register_code(KC_RSFT);
96 if (mods & MOD_BIT(KC_LCTL)) register_code(KC_LCTL);
97 if (mods & MOD_BIT(KC_RCTL)) register_code(KC_RCTL);
98 if (mods & MOD_BIT(KC_LALT)) register_code(KC_LALT);
99 if (mods & MOD_BIT(KC_RALT)) register_code(KC_RALT);
100 if (mods & MOD_BIT(KC_LGUI)) register_code(KC_LGUI);
101 if (mods & MOD_BIT(KC_RGUI)) register_code(KC_RGUI);
102} 124}
103 125
104__attribute__((weak)) 126__attribute__((weak))
105uint16_t hex_to_keycode(uint8_t hex) 127uint16_t hex_to_keycode(uint8_t hex) {
106{
107 if (hex == 0x0) { 128 if (hex == 0x0) {
108 return KC_0; 129 return KC_0;
109 } else if (hex < 0xA) { 130 } else if (hex < 0xA) {
@@ -116,7 +137,89 @@ uint16_t hex_to_keycode(uint8_t hex)
116void register_hex(uint16_t hex) { 137void register_hex(uint16_t hex) {
117 for(int i = 3; i >= 0; i--) { 138 for(int i = 3; i >= 0; i--) {
118 uint8_t digit = ((hex >> (i*4)) & 0xF); 139 uint8_t digit = ((hex >> (i*4)) & 0xF);
119 register_code(hex_to_keycode(digit)); 140 tap_code(hex_to_keycode(digit));
120 unregister_code(hex_to_keycode(digit)); 141 }
142}
143
144void send_unicode_hex_string(const char *str) {
145 if (!str) { return; }
146
147 while (*str) {
148 // Find the next code point (token) in the string
149 for (; *str == ' '; str++);
150 size_t n = strcspn(str, " "); // Length of the current token
151 char code_point[n+1];
152 strncpy(code_point, str, n);
153 code_point[n] = '\0'; // Make sure it's null-terminated
154
155 // Normalize the code point: make all hex digits lowercase
156 for (char *p = code_point; *p; p++) {
157 *p = tolower((unsigned char)*p);
158 }
159
160 // Send the code point as a Unicode input string
161 unicode_input_start();
162 send_string(code_point);
163 unicode_input_finish();
164
165 str += n; // Move to the first ' ' (or '\0') after the current token
166 }
167}
168
169bool process_unicode_common(uint16_t keycode, keyrecord_t *record) {
170 if (record->event.pressed) {
171 switch (keycode) {
172 case UNICODE_MODE_FORWARD:
173 cycle_unicode_input_mode(+1);
174 break;
175 case UNICODE_MODE_REVERSE:
176 cycle_unicode_input_mode(-1);
177 break;
178
179 case UNICODE_MODE_OSX:
180 set_unicode_input_mode(UC_OSX);
181#if defined(AUDIO_ENABLE) && defined(UNICODE_SONG_OSX)
182 static float song_osx[][2] = UNICODE_SONG_OSX;
183 PLAY_SONG(song_osx);
184#endif
185 break;
186 case UNICODE_MODE_LNX:
187 set_unicode_input_mode(UC_LNX);
188#if defined(AUDIO_ENABLE) && defined(UNICODE_SONG_LNX)
189 static float song_lnx[][2] = UNICODE_SONG_LNX;
190 PLAY_SONG(song_lnx);
191#endif
192 break;
193 case UNICODE_MODE_WIN:
194 set_unicode_input_mode(UC_WIN);
195#if defined(AUDIO_ENABLE) && defined(UNICODE_SONG_WIN)
196 static float song_win[][2] = UNICODE_SONG_WIN;
197 PLAY_SONG(song_win);
198#endif
199 break;
200 case UNICODE_MODE_BSD:
201 set_unicode_input_mode(UC_BSD);
202#if defined(AUDIO_ENABLE) && defined(UNICODE_SONG_BSD)
203 static float song_bsd[][2] = UNICODE_SONG_BSD;
204 PLAY_SONG(song_bsd);
205#endif
206 break;
207 case UNICODE_MODE_WINC:
208 set_unicode_input_mode(UC_WINC);
209#if defined(AUDIO_ENABLE) && defined(UNICODE_SONG_WINC)
210 static float song_winc[][2] = UNICODE_SONG_WINC;
211 PLAY_SONG(song_winc);
212#endif
213 break;
214 }
121 } 215 }
216#if defined(UNICODE_ENABLE)
217 return process_unicode(keycode, record);
218#elif defined(UNICODEMAP_ENABLE)
219 return process_unicodemap(keycode, record);
220#elif defined(UCIS_ENABLE)
221 return process_ucis(keycode, record);
222#else
223 return true;
224#endif
122} 225}
diff --git a/quantum/process_keycode/process_unicode_common.h b/quantum/process_keycode/process_unicode_common.h
index 4d2b04fb3..e608ab76b 100644
--- a/quantum/process_keycode/process_unicode_common.h
+++ b/quantum/process_keycode/process_unicode_common.h
@@ -14,33 +14,71 @@
14 * along with this program. If not, see <http://www.gnu.org/licenses/>. 14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */ 15 */
16 16
17#ifndef PROCESS_UNICODE_COMMON_H 17#pragma once
18#define PROCESS_UNICODE_COMMON_H
19 18
20#include "quantum.h" 19#include "quantum.h"
21 20
22#ifndef UNICODE_TYPE_DELAY 21#if defined(UNICODE_ENABLE) + defined(UNICODEMAP_ENABLE) + defined(UCIS_ENABLE) > 1
23#define UNICODE_TYPE_DELAY 10 22 #error "Cannot enable more than one Unicode method (UNICODE, UNICODEMAP, UCIS) at the same time"
23#endif
24
25// Keycodes used for starting Unicode input on different platforms
26#ifndef UNICODE_OSX_KEY
27 #define UNICODE_OSX_KEY KC_LALT
28#endif
29#ifndef UNICODE_WINC_KEY
30 #define UNICODE_WINC_KEY KC_RALT
24#endif 31#endif
25 32
26__attribute__ ((unused)) 33// Comma-delimited, ordered list of input modes selected for use (e.g. in cycle)
27static uint8_t input_mode; 34// Example: #define UNICODE_SELECTED_MODES UC_WINC, UC_LNX
35#ifndef UNICODE_SELECTED_MODES
36 #define UNICODE_SELECTED_MODES -1
37#endif
38
39// Whether input mode changes in cycle should be written to EEPROM
40#ifndef UNICODE_CYCLE_PERSIST
41 #define UNICODE_CYCLE_PERSIST true
42#endif
28 43
29void set_unicode_input_mode(uint8_t os_target); 44// Delay between starting Unicode input and sending a sequence, in ms
45#ifndef UNICODE_TYPE_DELAY
46 #define UNICODE_TYPE_DELAY 10
47#endif
48
49enum unicode_input_modes {
50 UC_OSX, // Mac OS X using Unicode Hex Input
51 UC_LNX, // Linux using IBus
52 UC_WIN, // Windows using EnableHexNumpad
53 UC_BSD, // BSD (not implemented)
54 UC_WINC, // Windows using WinCompose (https://github.com/samhocevar/wincompose)
55 UC__COUNT // Number of available input modes (always leave at the end)
56};
57
58typedef union {
59 uint32_t raw;
60 struct {
61 uint8_t input_mode : 8;
62 };
63} unicode_config_t;
64
65extern unicode_config_t unicode_config;
66
67void unicode_input_mode_init(void);
30uint8_t get_unicode_input_mode(void); 68uint8_t get_unicode_input_mode(void);
69void set_unicode_input_mode(uint8_t mode);
70void cycle_unicode_input_mode(uint8_t offset);
71void persist_unicode_input_mode(void);
72
31void unicode_input_start(void); 73void unicode_input_start(void);
32void unicode_input_finish(void); 74void unicode_input_finish(void);
75
33void register_hex(uint16_t hex); 76void register_hex(uint16_t hex);
77void send_unicode_hex_string(const char *str);
34 78
35#define UC_OSX 0 // Mac OS X 79bool process_unicode_common(uint16_t keycode, keyrecord_t *record);
36#define UC_LNX 1 // Linux
37#define UC_WIN 2 // Windows 'HexNumpad'
38#define UC_BSD 3 // BSD (not implemented)
39#define UC_WINC 4 // WinCompose https://github.com/samhocevar/wincompose
40#define UC_OSX_RALT 5 // Mac OS X using Right Alt key for Unicode Compose
41 80
42#define UC_BSPC UC(0x0008) 81#define UC_BSPC UC(0x0008)
43
44#define UC_SPC UC(0x0020) 82#define UC_SPC UC(0x0020)
45 83
46#define UC_EXLM UC(0x0021) 84#define UC_EXLM UC(0x0021)
@@ -145,5 +183,3 @@ void register_hex(uint16_t hex);
145#define UC_RCBR UC(0x007D) 183#define UC_RCBR UC(0x007D)
146#define UC_TILD UC(0x007E) 184#define UC_TILD UC(0x007E)
147#define UC_DEL UC(0x007F) 185#define UC_DEL UC(0x007F)
148
149#endif
diff --git a/quantum/process_keycode/process_unicodemap.c b/quantum/process_keycode/process_unicodemap.c
index 47c27b911..cee9acb5f 100644
--- a/quantum/process_keycode/process_unicodemap.c
+++ b/quantum/process_keycode/process_unicodemap.c
@@ -18,8 +18,7 @@
18#include "process_unicode_common.h" 18#include "process_unicode_common.h"
19 19
20__attribute__((weak)) 20__attribute__((weak))
21const uint32_t PROGMEM unicode_map[] = { 21const uint32_t PROGMEM unicode_map[] = {};
22};
23 22
24void register_hex32(uint32_t hex) { 23void register_hex32(uint32_t hex) {
25 bool onzerostart = true; 24 bool onzerostart = true;
@@ -42,26 +41,26 @@ void register_hex32(uint32_t hex) {
42} 41}
43 42
44__attribute__((weak)) 43__attribute__((weak))
45void unicode_map_input_error() {} 44void unicodemap_input_error() {}
46 45
47bool process_unicode_map(uint16_t keycode, keyrecord_t *record) { 46bool process_unicodemap(uint16_t keycode, keyrecord_t *record) {
48 uint8_t input_mode = get_unicode_input_mode(); 47 if ((keycode & QK_UNICODEMAP) == QK_UNICODEMAP && record->event.pressed) {
49 if ((keycode & QK_UNICODE_MAP) == QK_UNICODE_MAP && record->event.pressed) { 48 uint16_t index = keycode - QK_UNICODEMAP;
50 const uint32_t* map = unicode_map; 49 uint32_t code = pgm_read_dword(unicode_map + index);
51 uint16_t index = keycode - QK_UNICODE_MAP; 50 uint8_t input_mode = get_unicode_input_mode();
52 uint32_t code = pgm_read_dword(&map[index]); 51
53 if (code > 0xFFFF && code <= 0x10ffff && (input_mode == UC_OSX || input_mode == UC_OSX_RALT)) { 52 if (code > 0xFFFF && code <= 0x10FFFF && input_mode == UC_OSX) {
54 // Convert to UTF-16 surrogate pair 53 // Convert to UTF-16 surrogate pair
55 code -= 0x10000; 54 code -= 0x10000;
56 uint32_t lo = code & 0x3ff; 55 uint32_t lo = code & 0x3FF, hi = (code & 0xFFC00) >> 10;
57 uint32_t hi = (code & 0xffc00) >> 10; 56
58 unicode_input_start(); 57 unicode_input_start();
59 register_hex32(hi + 0xd800); 58 register_hex32(hi + 0xD800);
60 register_hex32(lo + 0xdc00); 59 register_hex32(lo + 0xDC00);
61 unicode_input_finish(); 60 unicode_input_finish();
62 } else if ((code > 0x10ffff && (input_mode == UC_OSX || input_mode == UC_OSX_RALT)) || (code > 0xFFFFF && input_mode == UC_LNX)) { 61 } else if ((code > 0x10FFFF && input_mode == UC_OSX) || (code > 0xFFFFF && input_mode == UC_LNX)) {
63 // when character is out of range supported by the OS 62 // Character is out of range supported by the OS
64 unicode_map_input_error(); 63 unicodemap_input_error();
65 } else { 64 } else {
66 unicode_input_start(); 65 unicode_input_start();
67 register_hex32(code); 66 register_hex32(code);
diff --git a/quantum/process_keycode/process_unicodemap.h b/quantum/process_keycode/process_unicodemap.h
index 929c88c0b..5764697f8 100644
--- a/quantum/process_keycode/process_unicodemap.h
+++ b/quantum/process_keycode/process_unicodemap.h
@@ -14,12 +14,10 @@
14 * along with this program. If not, see <http://www.gnu.org/licenses/>. 14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */ 15 */
16 16
17#ifndef PROCESS_UNICODEMAP_H 17#pragma once
18#define PROCESS_UNICODEMAP_H
19 18
20#include "quantum.h" 19#include "quantum.h"
21#include "process_unicode_common.h" 20#include "process_unicode_common.h"
22 21
23void unicode_map_input_error(void); 22void unicodemap_input_error(void);
24bool process_unicode_map(uint16_t keycode, keyrecord_t *record); 23bool process_unicodemap(uint16_t keycode, keyrecord_t *record);
25#endif