aboutsummaryrefslogtreecommitdiff
path: root/quantum/process_keycode
diff options
context:
space:
mode:
Diffstat (limited to 'quantum/process_keycode')
-rw-r--r--quantum/process_keycode/process_audio.c22
-rw-r--r--quantum/process_keycode/process_key_lock.c138
-rw-r--r--quantum/process_keycode/process_key_lock.h24
-rw-r--r--quantum/process_keycode/process_leader.c4
-rw-r--r--quantum/process_keycode/process_music.c153
-rw-r--r--quantum/process_keycode/process_music.h9
-rw-r--r--quantum/process_keycode/process_steno.c165
-rw-r--r--quantum/process_keycode/process_steno.h31
-rw-r--r--quantum/process_keycode/process_tap_dance.c18
-rw-r--r--quantum/process_keycode/process_tap_dance.h14
-rw-r--r--quantum/process_keycode/process_terminal.c252
-rw-r--r--quantum/process_keycode/process_terminal.h27
-rw-r--r--quantum/process_keycode/process_terminal_nop.h25
-rw-r--r--quantum/process_keycode/process_unicode_common.c6
-rw-r--r--quantum/process_keycode/process_unicode_common.h1
-rw-r--r--quantum/process_keycode/process_unicodemap.c4
16 files changed, 831 insertions, 62 deletions
diff --git a/quantum/process_keycode/process_audio.c b/quantum/process_keycode/process_audio.c
index 0b6380ed3..32057ae8d 100644
--- a/quantum/process_keycode/process_audio.c
+++ b/quantum/process_keycode/process_audio.c
@@ -1,10 +1,19 @@
1#include "audio.h" 1#include "audio.h"
2#include "process_audio.h" 2#include "process_audio.h"
3 3
4#ifndef VOICE_CHANGE_SONG
5 #define VOICE_CHANGE_SONG SONG(VOICE_CHANGE_SOUND)
6#endif
7float voice_change_song[][2] = VOICE_CHANGE_SONG;
8
9#ifndef PITCH_STANDARD_A
10 #define PITCH_STANDARD_A 440.0f
11#endif
12
4static float compute_freq_for_midi_note(uint8_t note) 13static float compute_freq_for_midi_note(uint8_t note)
5{ 14{
6 // https://en.wikipedia.org/wiki/MIDI_tuning_standard 15 // https://en.wikipedia.org/wiki/MIDI_tuning_standard
7 return pow(2.0, (note - 69) / 12.0) * 440.0f; 16 return pow(2.0, (note - 69) / 12.0) * PITCH_STANDARD_A;
8} 17}
9 18
10bool process_audio(uint16_t keycode, keyrecord_t *record) { 19bool process_audio(uint16_t keycode, keyrecord_t *record) {
@@ -20,12 +29,9 @@ bool process_audio(uint16_t keycode, keyrecord_t *record) {
20 } 29 }
21 30
22 if (keycode == AU_TOG && record->event.pressed) { 31 if (keycode == AU_TOG && record->event.pressed) {
23 if (is_audio_on()) 32 if (is_audio_on()) {
24 {
25 audio_off(); 33 audio_off();
26 } 34 } else {
27 else
28 {
29 audio_on(); 35 audio_on();
30 } 36 }
31 return false; 37 return false;
@@ -33,13 +39,13 @@ bool process_audio(uint16_t keycode, keyrecord_t *record) {
33 39
34 if (keycode == MUV_IN && record->event.pressed) { 40 if (keycode == MUV_IN && record->event.pressed) {
35 voice_iterate(); 41 voice_iterate();
36 music_scale_user(); 42 PLAY_SONG(voice_change_song);
37 return false; 43 return false;
38 } 44 }
39 45
40 if (keycode == MUV_DE && record->event.pressed) { 46 if (keycode == MUV_DE && record->event.pressed) {
41 voice_deiterate(); 47 voice_deiterate();
42 music_scale_user(); 48 PLAY_SONG(voice_change_song);
43 return false; 49 return false;
44 } 50 }
45 51
diff --git a/quantum/process_keycode/process_key_lock.c b/quantum/process_keycode/process_key_lock.c
new file mode 100644
index 000000000..d7978f91c
--- /dev/null
+++ b/quantum/process_keycode/process_key_lock.c
@@ -0,0 +1,138 @@
1/* Copyright 2017 Fredric Silberberg
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 "inttypes.h"
18#include "stdint.h"
19#include "process_key_lock.h"
20
21#define BV_64(shift) (((uint64_t)1) << (shift))
22#define GET_KEY_ARRAY(code) (((code) < 0x40) ? key_state[0] : \
23 ((code) < 0x80) ? key_state[1] : \
24 ((code) < 0xC0) ? key_state[2] : key_state[3])
25#define GET_CODE_INDEX(code) (((code) < 0x40) ? (code) : \
26 ((code) < 0x80) ? (code) - 0x40 : \
27 ((code) < 0xC0) ? (code) - 0x80 : (code) - 0xC0)
28#define KEY_STATE(code) (GET_KEY_ARRAY(code) & BV_64(GET_CODE_INDEX(code))) == BV_64(GET_CODE_INDEX(code))
29#define SET_KEY_ARRAY_STATE(code, val) do { \
30 switch (code) { \
31 case 0x00 ... 0x3F: \
32 key_state[0] = (val); \
33 break; \
34 case 0x40 ... 0x7F: \
35 key_state[1] = (val); \
36 break; \
37 case 0x80 ... 0xBF: \
38 key_state[2] = (val); \
39 break; \
40 case 0xC0 ... 0xFF: \
41 key_state[3] = (val); \
42 break; \
43 } \
44} while(0)
45#define SET_KEY_STATE(code) SET_KEY_ARRAY_STATE(code, (GET_KEY_ARRAY(code) | BV_64(GET_CODE_INDEX(code))))
46#define UNSET_KEY_STATE(code) SET_KEY_ARRAY_STATE(code, (GET_KEY_ARRAY(code)) & ~(BV_64(GET_CODE_INDEX(code))))
47#define IS_STANDARD_KEYCODE(code) ((code) <= 0xFF)
48
49// Locked key state. This is an array of 256 bits, one for each of the standard keys supported qmk.
50uint64_t key_state[4] = { 0x0, 0x0, 0x0, 0x0 };
51bool watching = false;
52
53// Translate any OSM keycodes back to their unmasked versions.
54uint16_t inline translate_keycode(uint16_t keycode) {
55 if (keycode > QK_ONE_SHOT_MOD && keycode <= QK_ONE_SHOT_MOD_MAX) {
56 return keycode ^ QK_ONE_SHOT_MOD;
57 } else {
58 return keycode;
59 }
60}
61
62bool process_key_lock(uint16_t *keycode, keyrecord_t *record) {
63 // We start by categorizing the keypress event. In the event of a down
64 // event, there are several possibilities:
65 // 1. The key is not being locked, and we are not watching for new keys.
66 // In this case, we bail immediately. This is the common case for down events.
67 // 2. The key was locked, and we need to unlock it. In this case, we will
68 // reset the state in our map and return false. When the user releases the
69 // key, the up event will no longer be masked and the OS will observe the
70 // released key.
71 // 3. KC_LOCK was just pressed. In this case, we set up the state machine
72 // to watch for the next key down event, and finish processing
73 // 4. The keycode is below 0xFF, and we are watching for new keys. In this case,
74 // we will send the key down event to the os, and set the key_state for that
75 // key to mask the up event.
76 // 5. The keycode is above 0xFF, and we're wathing for new keys. In this case,
77 // the user pressed a key that we cannot "lock", as it's a series of keys,
78 // or a macro invocation, or a layer transition, or a custom-defined key, or
79 // or some other arbitrary code. In this case, we bail immediately, reset
80 // our watch state, and return true.
81 //
82 // In the event of an up event, there are these possibilities:
83 // 1. The key is not being locked. In this case, we return true and bail
84 // immediately. This is the common case.
85 // 2. The key is being locked. In this case, we will mask the up event
86 // by returning false, so the OS never sees that the key was released
87 // until the user pressed the key again.
88
89 // We translate any OSM keycodes back to their original keycodes, so that if the key being
90 // one-shot modded is a standard keycode, we can handle it. This is the only set of special
91 // keys that we handle
92 uint16_t translated_keycode = translate_keycode(*keycode);
93
94 if (record->event.pressed) {
95 // Non-standard keycode, reset and return
96 if (!(IS_STANDARD_KEYCODE(translated_keycode) || translated_keycode == KC_LOCK)) {
97 watching = false;
98 return true;
99 }
100
101 // If we're already watching, turn off the watch.
102 if (translated_keycode == KC_LOCK) {
103 watching = !watching;
104 return false;
105 }
106
107 if (IS_STANDARD_KEYCODE(translated_keycode)) {
108 // We check watching first. This is so that in the following scenario, we continue to
109 // hold the key: KC_LOCK, KC_F, KC_LOCK, KC_F
110 // If we checked in reverse order, we'd end up holding the key pressed after the second
111 // KC_F press is registered, when the user likely meant to hold F
112 if (watching) {
113 watching = false;
114 SET_KEY_STATE(translated_keycode);
115 // We need to set the keycode passed in to be the translated keycode, in case we
116 // translated a OSM back to the original keycode.
117 *keycode = translated_keycode;
118 // Let the standard keymap send the keycode down event. The up event will be masked.
119 return true;
120 }
121
122 if (KEY_STATE(translated_keycode)) {
123 UNSET_KEY_STATE(translated_keycode);
124 // The key is already held, stop this process. The up event will be sent when the user
125 // releases the key.
126 return false;
127 }
128 }
129
130 // Either the key isn't a standard key, or we need to send the down event. Continue standard
131 // processing
132 return true;
133 } else {
134 // Stop processing if it's a standard key and we're masking up.
135 return !(IS_STANDARD_KEYCODE(translated_keycode) && KEY_STATE(translated_keycode));
136 }
137}
138
diff --git a/quantum/process_keycode/process_key_lock.h b/quantum/process_keycode/process_key_lock.h
new file mode 100644
index 000000000..876db4a32
--- /dev/null
+++ b/quantum/process_keycode/process_key_lock.h
@@ -0,0 +1,24 @@
1/* Copyright 2017 Fredric Silberberg
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_KEY_LOCK_H
18#define PROCESS_KEY_LOCK_H
19
20#include "quantum.h"
21
22bool process_key_lock(uint16_t *keycode, keyrecord_t *record);
23
24#endif // PROCESS_KEY_LOCK_H
diff --git a/quantum/process_keycode/process_leader.c b/quantum/process_keycode/process_leader.c
index 473906d65..e0fe47654 100644
--- a/quantum/process_keycode/process_leader.c
+++ b/quantum/process_keycode/process_leader.c
@@ -14,6 +14,8 @@
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
18
17#include "process_leader.h" 19#include "process_leader.h"
18 20
19__attribute__ ((weak)) 21__attribute__ ((weak))
@@ -52,3 +54,5 @@ bool process_leader(uint16_t keycode, keyrecord_t *record) {
52 } 54 }
53 return true; 55 return true;
54} 56}
57
58#endif
diff --git a/quantum/process_keycode/process_music.c b/quantum/process_keycode/process_music.c
index 217dca280..63841d1e8 100644
--- a/quantum/process_keycode/process_music.c
+++ b/quantum/process_keycode/process_music.c
@@ -27,6 +27,7 @@
27bool music_activated = false; 27bool music_activated = false;
28uint8_t music_starting_note = 0x0C; 28uint8_t music_starting_note = 0x0C;
29int music_offset = 7; 29int music_offset = 7;
30uint8_t music_mode = MUSIC_MODE_CHROMATIC;
30 31
31// music sequencer 32// music sequencer
32static bool music_sequence_recording = false; 33static bool music_sequence_recording = false;
@@ -39,6 +40,39 @@ static uint8_t music_sequence_position = 0;
39static uint16_t music_sequence_timer = 0; 40static uint16_t music_sequence_timer = 0;
40static uint16_t music_sequence_interval = 100; 41static uint16_t music_sequence_interval = 100;
41 42
43#ifdef AUDIO_ENABLE
44 #ifndef MUSIC_ON_SONG
45 #define MUSIC_ON_SONG SONG(MUSIC_ON_SOUND)
46 #endif
47 #ifndef MUSIC_OFF_SONG
48 #define MUSIC_OFF_SONG SONG(MUSIC_OFF_SOUND)
49 #endif
50 #ifndef CHROMATIC_SONG
51 #define CHROMATIC_SONG SONG(CHROMATIC_SOUND)
52 #endif
53 #ifndef GUITAR_SONG
54 #define GUITAR_SONG SONG(GUITAR_SOUND)
55 #endif
56 #ifndef VIOLIN_SONG
57 #define VIOLIN_SONG SONG(VIOLIN_SOUND)
58 #endif
59 #ifndef MAJOR_SONG
60 #define MAJOR_SONG SONG(MAJOR_SOUND)
61 #endif
62 float music_mode_songs[NUMBER_OF_MODES][5][2] = {
63 CHROMATIC_SONG,
64 GUITAR_SONG,
65 VIOLIN_SONG,
66 MAJOR_SONG
67 };
68 float music_on_song[][2] = MUSIC_ON_SONG;
69 float music_off_song[][2] = MUSIC_OFF_SONG;
70#endif
71
72#ifndef MUSIC_MASK
73 #define MUSIC_MASK keycode < 0xFF
74#endif
75
42static void music_noteon(uint8_t note) { 76static void music_noteon(uint8_t note) {
43 #ifdef AUDIO_ENABLE 77 #ifdef AUDIO_ENABLE
44 process_audio_noteon(note); 78 process_audio_noteon(note);
@@ -79,70 +113,71 @@ bool process_music(uint16_t keycode, keyrecord_t *record) {
79 } 113 }
80 114
81 if (keycode == MU_TOG && record->event.pressed) { 115 if (keycode == MU_TOG && record->event.pressed) {
82 if (music_activated) 116 if (music_activated) {
83 {
84 music_off(); 117 music_off();
85 } 118 } else {
86 else
87 {
88 music_on(); 119 music_on();
89 } 120 }
90 return false; 121 return false;
91 } 122 }
92 123
93 if (music_activated) { 124 if (keycode == MU_MOD && record->event.pressed) {
125 music_mode_cycle();
126 return false;
127 }
94 128
95 if (keycode == KC_LCTL && record->event.pressed) { // Start recording 129 if (music_activated) {
96 music_all_notes_off(); 130 if (record->event.pressed) {
97 music_sequence_recording = true; 131 if (keycode == KC_LCTL) { // Start recording
98 music_sequence_recorded = false; 132 music_all_notes_off();
99 music_sequence_playing = false; 133 music_sequence_recording = true;
100 music_sequence_count = 0; 134 music_sequence_recorded = false;
101 return false; 135 music_sequence_playing = false;
102 } 136 music_sequence_count = 0;
137 return false;
138 }
103 139
104 if (keycode == KC_LALT && record->event.pressed) { // Stop recording/playing 140 if (keycode == KC_LALT) { // Stop recording/playing
105 music_all_notes_off(); 141 music_all_notes_off();
106 if (music_sequence_recording) { // was recording 142 if (music_sequence_recording) { // was recording
107 music_sequence_recorded = true; 143 music_sequence_recorded = true;
144 }
145 music_sequence_recording = false;
146 music_sequence_playing = false;
147 return false;
108 } 148 }
109 music_sequence_recording = false;
110 music_sequence_playing = false;
111 return false;
112 }
113 149
114 if (keycode == KC_LGUI && record->event.pressed && music_sequence_recorded) { // Start playing 150 if (keycode == KC_LGUI && music_sequence_recorded) { // Start playing
115 music_all_notes_off(); 151 music_all_notes_off();
116 music_sequence_recording = false; 152 music_sequence_recording = false;
117 music_sequence_playing = true; 153 music_sequence_playing = true;
118 music_sequence_position = 0; 154 music_sequence_position = 0;
119 music_sequence_timer = 0; 155 music_sequence_timer = 0;
120 return false; 156 return false;
121 } 157 }
122 158
123 if (keycode == KC_UP) { 159 if (keycode == KC_UP) {
124 if (record->event.pressed) 160 music_sequence_interval-=10;
125 music_sequence_interval-=10; 161 return false;
126 return false; 162 }
127 }
128 163
129 if (keycode == KC_DOWN) { 164 if (keycode == KC_DOWN) {
130 if (record->event.pressed) 165 music_sequence_interval+=10;
131 music_sequence_interval+=10; 166 return false;
132 return false; 167 }
133 } 168 }
134 169
135 #define MUSIC_MODE_GUITAR 170 uint8_t note;
136 171 if (music_mode == MUSIC_MODE_CHROMATIC)
137 #ifdef MUSIC_MODE_CHROMATIC 172 note = (music_starting_note + record->event.key.col + music_offset - 3)+12*(MATRIX_ROWS - record->event.key.row);
138 uint8_t note = (music_starting_note + record->event.key.col + music_offset - 3)+12*(MATRIX_ROWS - record->event.key.row); 173 else if (music_mode == MUSIC_MODE_GUITAR)
139 #elif defined(MUSIC_MODE_GUITAR) 174 note = (music_starting_note + record->event.key.col + music_offset + 32)+5*(MATRIX_ROWS - record->event.key.row);
140 uint8_t note = (music_starting_note + record->event.key.col + music_offset + 32)+5*(MATRIX_ROWS - record->event.key.row); 175 else if (music_mode == MUSIC_MODE_VIOLIN)
141 #elif defined(MUSIC_MODE_VIOLIN) 176 note = (music_starting_note + record->event.key.col + music_offset + 32)+7*(MATRIX_ROWS - record->event.key.row);
142 uint8_t note = (music_starting_note + record->event.key.col + music_offset + 32)+7*(MATRIX_ROWS - record->event.key.row); 177 else if (music_mode == MUSIC_MODE_MAJOR)
143 #else 178 note = (music_starting_note + SCALE[record->event.key.col + music_offset] - 3)+12*(MATRIX_ROWS - record->event.key.row);
144 uint8_t note = (music_starting_note + SCALE[record->event.key.col + music_offset] - 3)+12*(MATRIX_ROWS - record->event.key.row); 179 else
145 #endif 180 note = music_starting_note;
146 181
147 if (record->event.pressed) { 182 if (record->event.pressed) {
148 music_noteon(note); 183 music_noteon(note);
@@ -154,7 +189,7 @@ bool process_music(uint16_t keycode, keyrecord_t *record) {
154 music_noteoff(note); 189 music_noteoff(note);
155 } 190 }
156 191
157 if (keycode < 0xFF) // ignores all normal keycodes, but lets RAISE, LOWER, etc through 192 if (MUSIC_MASK)
158 return false; 193 return false;
159 } 194 }
160 195
@@ -175,12 +210,26 @@ void music_toggle(void) {
175 210
176void music_on(void) { 211void music_on(void) {
177 music_activated = 1; 212 music_activated = 1;
213 #ifdef AUDIO_ENABLE
214 PLAY_SONG(music_on_song);
215 #endif
178 music_on_user(); 216 music_on_user();
179} 217}
180 218
181void music_off(void) { 219void music_off(void) {
182 music_activated = 0;
183 music_all_notes_off(); 220 music_all_notes_off();
221 music_activated = 0;
222 #ifdef AUDIO_ENABLE
223 PLAY_SONG(music_off_song);
224 #endif
225}
226
227void music_mode_cycle(void) {
228 music_all_notes_off();
229 music_mode = (music_mode + 1) % NUMBER_OF_MODES;
230 #ifdef AUDIO_ENABLE
231 PLAY_SONG(music_mode_songs[music_mode]);
232 #endif
184} 233}
185 234
186void matrix_scan_music(void) { 235void matrix_scan_music(void) {
diff --git a/quantum/process_keycode/process_music.h b/quantum/process_keycode/process_music.h
index 8dfbf041f..ee027197c 100644
--- a/quantum/process_keycode/process_music.h
+++ b/quantum/process_keycode/process_music.h
@@ -21,6 +21,14 @@
21 21
22#if defined(AUDIO_ENABLE) || (defined(MIDI_ENABLE) && defined(MIDI_BASIC)) 22#if defined(AUDIO_ENABLE) || (defined(MIDI_ENABLE) && defined(MIDI_BASIC))
23 23
24enum music_modes {
25 MUSIC_MODE_CHROMATIC,
26 MUSIC_MODE_GUITAR,
27 MUSIC_MODE_VIOLIN,
28 MUSIC_MODE_MAJOR,
29 NUMBER_OF_MODES
30};
31
24bool process_music(uint16_t keycode, keyrecord_t *record); 32bool process_music(uint16_t keycode, keyrecord_t *record);
25 33
26bool is_music_on(void); 34bool is_music_on(void);
@@ -31,6 +39,7 @@ void music_off(void);
31void music_on_user(void); 39void music_on_user(void);
32void music_scale_user(void); 40void music_scale_user(void);
33void music_all_notes_off(void); 41void music_all_notes_off(void);
42void music_mode_cycle(void);
34 43
35void matrix_scan_music(void); 44void matrix_scan_music(void);
36 45
diff --git a/quantum/process_keycode/process_steno.c b/quantum/process_keycode/process_steno.c
new file mode 100644
index 000000000..16bbf154f
--- /dev/null
+++ b/quantum/process_keycode/process_steno.c
@@ -0,0 +1,165 @@
1/* Copyright 2017 Joseph Wasson
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#include "process_steno.h"
17#include "quantum_keycodes.h"
18#include "eeprom.h"
19#include "keymap_steno.h"
20#include "virtser.h"
21
22// TxBolt Codes
23#define TXB_NUL 0
24#define TXB_S_L 0b00000001
25#define TXB_T_L 0b00000010
26#define TXB_K_L 0b00000100
27#define TXB_P_L 0b00001000
28#define TXB_W_L 0b00010000
29#define TXB_H_L 0b00100000
30#define TXB_R_L 0b01000001
31#define TXB_A_L 0b01000010
32#define TXB_O_L 0b01000100
33#define TXB_STR 0b01001000
34#define TXB_E_R 0b01010000
35#define TXB_U_R 0b01100000
36#define TXB_F_R 0b10000001
37#define TXB_R_R 0b10000010
38#define TXB_P_R 0b10000100
39#define TXB_B_R 0b10001000
40#define TXB_L_R 0b10010000
41#define TXB_G_R 0b10100000
42#define TXB_T_R 0b11000001
43#define TXB_S_R 0b11000010
44#define TXB_D_R 0b11000100
45#define TXB_Z_R 0b11001000
46#define TXB_NUM 0b11010000
47
48#define TXB_GRP0 0b00000000
49#define TXB_GRP1 0b01000000
50#define TXB_GRP2 0b10000000
51#define TXB_GRP3 0b11000000
52#define TXB_GRPMASK 0b11000000
53
54#define TXB_GET_GROUP(code) ((code & TXB_GRPMASK) >> 6)
55
56#define BOLT_STATE_SIZE 4
57#define GEMINI_STATE_SIZE 6
58#define MAX_STATE_SIZE GEMINI_STATE_SIZE
59
60uint8_t state[MAX_STATE_SIZE] = {0};
61uint8_t pressed = 0;
62steno_mode_t mode;
63
64uint8_t boltmap[64] = {
65 TXB_NUL, TXB_NUM, TXB_NUM, TXB_NUM, TXB_NUM, TXB_NUM, TXB_NUM,
66 TXB_S_L, TXB_S_L, TXB_T_L, TXB_K_L, TXB_P_L, TXB_W_L, TXB_H_L,
67 TXB_R_L, TXB_A_L, TXB_O_L, TXB_STR, TXB_STR, TXB_NUL, TXB_NUL,
68 TXB_NUL, TXB_STR, TXB_STR, TXB_E_R, TXB_U_R, TXB_F_R, TXB_R_R,
69 TXB_P_R, TXB_B_R, TXB_L_R, TXB_G_R, TXB_T_R, TXB_S_R, TXB_D_R,
70 TXB_NUM, TXB_NUM, TXB_NUM, TXB_NUM, TXB_NUM, TXB_NUM, TXB_Z_R
71};
72
73void steno_clear_state(void) {
74 __builtin_memset(state, 0, sizeof(state));
75}
76
77void steno_init() {
78 if (!eeconfig_is_enabled()) {
79 eeconfig_init();
80 }
81 mode = eeprom_read_byte(EECONFIG_STENOMODE);
82}
83
84void steno_set_mode(steno_mode_t new_mode) {
85 steno_clear_state();
86 mode = new_mode;
87 eeprom_update_byte(EECONFIG_STENOMODE, mode);
88}
89
90void send_steno_state(uint8_t size, bool send_empty) {
91 for (uint8_t i = 0; i < size; ++i) {
92 if (state[i] || send_empty) {
93 virtser_send(state[i]);
94 }
95 }
96 steno_clear_state();
97}
98
99bool update_state_bolt(uint8_t key) {
100 uint8_t boltcode = boltmap[key];
101 state[TXB_GET_GROUP(boltcode)] |= boltcode;
102 return false;
103}
104
105bool send_state_bolt(void) {
106 send_steno_state(BOLT_STATE_SIZE, false);
107 virtser_send(0); // terminating byte
108 return false;
109}
110
111bool update_state_gemini(uint8_t key) {
112 state[key / 7] |= 1 << (6 - (key % 7));
113 return false;
114}
115
116bool send_state_gemini(void) {
117 state[0] |= 0x80; // Indicate start of packet
118 send_steno_state(GEMINI_STATE_SIZE, true);
119 return false;
120}
121
122bool process_steno(uint16_t keycode, keyrecord_t *record) {
123 switch (keycode) {
124 case QK_STENO_BOLT:
125 if (IS_PRESSED(record->event)) {
126 steno_set_mode(STENO_MODE_BOLT);
127 }
128 return false;
129
130 case QK_STENO_GEMINI:
131 if (IS_PRESSED(record->event)) {
132 steno_set_mode(STENO_MODE_GEMINI);
133 }
134 return false;
135
136 case STN__MIN...STN__MAX:
137 if (IS_PRESSED(record->event)) {
138 uint8_t key = keycode - QK_STENO;
139 ++pressed;
140 switch(mode) {
141 case STENO_MODE_BOLT:
142 return update_state_bolt(key);
143 case STENO_MODE_GEMINI:
144 return update_state_gemini(key);
145 default:
146 return false;
147 }
148 } else {
149 --pressed;
150 if (pressed <= 0) {
151 pressed = 0;
152 switch(mode) {
153 case STENO_MODE_BOLT:
154 return send_state_bolt();
155 case STENO_MODE_GEMINI:
156 return send_state_gemini();
157 default:
158 return false;
159 }
160 }
161 }
162
163 }
164 return true;
165}
diff --git a/quantum/process_keycode/process_steno.h b/quantum/process_keycode/process_steno.h
new file mode 100644
index 000000000..3bbcbeaaf
--- /dev/null
+++ b/quantum/process_keycode/process_steno.h
@@ -0,0 +1,31 @@
1/* Copyright 2017 Joseph Wasson
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#ifndef PROCESS_STENO_H
17#define PROCESS_STENO_H
18
19#include "quantum.h"
20
21#if defined(STENO_ENABLE) && !defined(VIRTSER_ENABLE)
22 #error "must have virtser enabled to use steno"
23#endif
24
25typedef enum { STENO_MODE_BOLT, STENO_MODE_GEMINI } steno_mode_t;
26
27bool process_steno(uint16_t keycode, keyrecord_t *record);
28void steno_init(void);
29void steno_set_mode(steno_mode_t mode);
30
31#endif \ No newline at end of file
diff --git a/quantum/process_keycode/process_tap_dance.c b/quantum/process_keycode/process_tap_dance.c
index 4fd45810b..f1f28e016 100644
--- a/quantum/process_keycode/process_tap_dance.c
+++ b/quantum/process_keycode/process_tap_dance.c
@@ -41,6 +41,24 @@ void qk_tap_dance_pair_reset (qk_tap_dance_state_t *state, void *user_data) {
41 } 41 }
42} 42}
43 43
44void qk_tap_dance_dual_role_finished (qk_tap_dance_state_t *state, void *user_data) {
45 qk_tap_dance_dual_role_t *pair = (qk_tap_dance_dual_role_t *)user_data;
46
47 if (state->count == 1) {
48 register_code16 (pair->kc);
49 } else if (state->count == 2) {
50 layer_move (pair->layer);
51 }
52}
53
54void qk_tap_dance_dual_role_reset (qk_tap_dance_state_t *state, void *user_data) {
55 qk_tap_dance_dual_role_t *pair = (qk_tap_dance_dual_role_t *)user_data;
56
57 if (state->count == 1) {
58 unregister_code16 (pair->kc);
59 }
60}
61
44static inline void _process_tap_dance_action_fn (qk_tap_dance_state_t *state, 62static inline void _process_tap_dance_action_fn (qk_tap_dance_state_t *state,
45 void *user_data, 63 void *user_data,
46 qk_tap_dance_user_fn_t fn) 64 qk_tap_dance_user_fn_t fn)
diff --git a/quantum/process_keycode/process_tap_dance.h b/quantum/process_keycode/process_tap_dance.h
index f42c154a0..37a27c536 100644
--- a/quantum/process_keycode/process_tap_dance.h
+++ b/quantum/process_keycode/process_tap_dance.h
@@ -54,11 +54,22 @@ typedef struct
54 uint16_t kc2; 54 uint16_t kc2;
55} qk_tap_dance_pair_t; 55} qk_tap_dance_pair_t;
56 56
57typedef struct
58{
59 uint16_t kc;
60 uint8_t layer;
61} qk_tap_dance_dual_role_t;
62
57#define ACTION_TAP_DANCE_DOUBLE(kc1, kc2) { \ 63#define ACTION_TAP_DANCE_DOUBLE(kc1, kc2) { \
58 .fn = { NULL, qk_tap_dance_pair_finished, qk_tap_dance_pair_reset }, \ 64 .fn = { NULL, qk_tap_dance_pair_finished, qk_tap_dance_pair_reset }, \
59 .user_data = (void *)&((qk_tap_dance_pair_t) { kc1, kc2 }), \ 65 .user_data = (void *)&((qk_tap_dance_pair_t) { kc1, kc2 }), \
60 } 66 }
61 67
68#define ACTION_TAP_DANCE_DUAL_ROLE(kc, layer) { \
69 .fn = { NULL, qk_tap_dance_dual_role_finished, qk_tap_dance_dual_role_reset }, \
70 .user_data = (void *)&((qk_tap_dance_dual_role_t) { kc, layer }), \
71 }
72
62#define ACTION_TAP_DANCE_FN(user_fn) { \ 73#define ACTION_TAP_DANCE_FN(user_fn) { \
63 .fn = { NULL, user_fn, NULL }, \ 74 .fn = { NULL, user_fn, NULL }, \
64 .user_data = NULL, \ 75 .user_data = NULL, \
@@ -86,6 +97,9 @@ void reset_tap_dance (qk_tap_dance_state_t *state);
86void qk_tap_dance_pair_finished (qk_tap_dance_state_t *state, void *user_data); 97void qk_tap_dance_pair_finished (qk_tap_dance_state_t *state, void *user_data);
87void qk_tap_dance_pair_reset (qk_tap_dance_state_t *state, void *user_data); 98void qk_tap_dance_pair_reset (qk_tap_dance_state_t *state, void *user_data);
88 99
100void qk_tap_dance_dual_role_finished (qk_tap_dance_state_t *state, void *user_data);
101void qk_tap_dance_dual_role_reset (qk_tap_dance_state_t *state, void *user_data);
102
89#else 103#else
90 104
91#define TD(n) KC_NO 105#define TD(n) KC_NO
diff --git a/quantum/process_keycode/process_terminal.c b/quantum/process_keycode/process_terminal.c
new file mode 100644
index 000000000..deb1543e3
--- /dev/null
+++ b/quantum/process_keycode/process_terminal.c
@@ -0,0 +1,252 @@
1/* Copyright 2017 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_terminal.h"
18#include <string.h>
19#include "version.h"
20#include <stdio.h>
21#include <math.h>
22
23bool terminal_enabled = false;
24char buffer[80] = "";
25char newline[2] = "\n";
26char arguments[6][20];
27
28__attribute__ ((weak))
29const char terminal_prompt[8] = "> ";
30
31#ifdef AUDIO_ENABLE
32 #ifndef TERMINAL_SONG
33 #define TERMINAL_SONG SONG(TERMINAL_SOUND)
34 #endif
35 float terminal_song[][2] = TERMINAL_SONG;
36 #define TERMINAL_BELL() PLAY_SONG(terminal_song)
37#else
38 #define TERMINAL_BELL()
39#endif
40
41__attribute__ ((weak))
42const char keycode_to_ascii_lut[58] = {
43 0, 0, 0, 0,
44 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
45 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
46 '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 0, 0, 0, '\t',
47 ' ', '-', '=', '[', ']', '\\', 0, ';', '\'', '`', ',', '.', '/'
48};
49
50__attribute__ ((weak))
51const char shifted_keycode_to_ascii_lut[58] = {
52 0, 0, 0, 0,
53 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
54 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
55 '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', 0, 0, 0, '\t',
56 ' ', '_', '+', '{', '}', '|', 0, ':', '\'', '~', '<', '>', '?'
57};
58
59struct stringcase {
60 char* string;
61 void (*func)(void);
62} typedef stringcase;
63
64void enable_terminal(void) {
65 terminal_enabled = true;
66 strcpy(buffer, "");
67 for (int i = 0; i < 6; i++)
68 strcpy(arguments[i], "");
69 // select all text to start over
70 // SEND_STRING(SS_LCTRL("a"));
71 send_string(terminal_prompt);
72}
73
74void disable_terminal(void) {
75 terminal_enabled = false;
76}
77
78void terminal_about(void) {
79 SEND_STRING("QMK Firmware\n");
80 SEND_STRING(" v");
81 SEND_STRING(QMK_VERSION);
82 SEND_STRING("\n"SS_TAP(X_HOME)" Built: ");
83 SEND_STRING(QMK_BUILDDATE);
84 send_string(newline);
85 #ifdef TERMINAL_HELP
86 if (strlen(arguments[1]) != 0) {
87 SEND_STRING("You entered: ");
88 send_string(arguments[1]);
89 send_string(newline);
90 }
91 #endif
92}
93
94void terminal_help(void);
95
96extern const uint16_t keymaps[][MATRIX_ROWS][MATRIX_COLS];
97
98void terminal_keycode(void) {
99 if (strlen(arguments[1]) != 0 && strlen(arguments[2]) != 0 && strlen(arguments[3]) != 0) {
100 char keycode_dec[5];
101 char keycode_hex[5];
102 uint16_t layer = strtol(arguments[1], (char **)NULL, 10);
103 uint16_t row = strtol(arguments[2], (char **)NULL, 10);
104 uint16_t col = strtol(arguments[3], (char **)NULL, 10);
105 uint16_t keycode = pgm_read_word(&keymaps[layer][row][col]);
106 itoa(keycode, keycode_dec, 10);
107 itoa(keycode, keycode_hex, 16);
108 SEND_STRING("0x");
109 send_string(keycode_hex);
110 SEND_STRING(" (");
111 send_string(keycode_dec);
112 SEND_STRING(")\n");
113 } else {
114 #ifdef TERMINAL_HELP
115 SEND_STRING("usage: keycode <layer> <row> <col>\n");
116 #endif
117 }
118}
119
120void terminal_keymap(void) {
121 if (strlen(arguments[1]) != 0) {
122 uint16_t layer = strtol(arguments[1], (char **)NULL, 10);
123 for (int r = 0; r < MATRIX_ROWS; r++) {
124 for (int c = 0; c < MATRIX_COLS; c++) {
125 uint16_t keycode = pgm_read_word(&keymaps[layer][r][c]);
126 char keycode_s[8];
127 sprintf(keycode_s, "0x%04x, ", keycode);
128 send_string(keycode_s);
129 }
130 send_string(newline);
131 }
132 } else {
133 #ifdef TERMINAL_HELP
134 SEND_STRING("usage: keymap <layer>\n");
135 #endif
136 }
137}
138
139stringcase terminal_cases[] = {
140 { "about", terminal_about },
141 { "help", terminal_help },
142 { "keycode", terminal_keycode },
143 { "keymap", terminal_keymap },
144 { "exit", disable_terminal }
145};
146
147void terminal_help(void) {
148 SEND_STRING("commands available:\n ");
149 for( stringcase* case_p = terminal_cases; case_p != terminal_cases + sizeof( terminal_cases ) / sizeof( terminal_cases[0] ); case_p++ ) {
150 send_string(case_p->string);
151 SEND_STRING(" ");
152 }
153 send_string(newline);
154}
155
156void command_not_found(void) {
157 SEND_STRING("command \"");
158 send_string(buffer);
159 SEND_STRING("\" not found\n");
160}
161
162void process_terminal_command(void) {
163 // we capture return bc of the order of events, so we need to manually send a newline
164 send_string(newline);
165
166 char * pch;
167 uint8_t i = 0;
168 pch = strtok(buffer, " ");
169 while (pch != NULL) {
170 strcpy(arguments[i], pch);
171 pch = strtok(NULL, " ");
172 i++;
173 }
174
175 bool command_found = false;
176 for( stringcase* case_p = terminal_cases; case_p != terminal_cases + sizeof( terminal_cases ) / sizeof( terminal_cases[0] ); case_p++ ) {
177 if( 0 == strcmp( case_p->string, buffer ) ) {
178 command_found = true;
179 (*case_p->func)();
180 break;
181 }
182 }
183
184 if (!command_found)
185 command_not_found();
186
187 if (terminal_enabled) {
188 strcpy(buffer, "");
189 for (int i = 0; i < 6; i++)
190 strcpy(arguments[i], "");
191 SEND_STRING(SS_TAP(X_HOME));
192 send_string(terminal_prompt);
193 }
194}
195
196bool process_terminal(uint16_t keycode, keyrecord_t *record) {
197
198 if (keycode == TERM_ON && record->event.pressed) {
199 enable_terminal();
200 return false;
201 }
202
203 if (terminal_enabled && record->event.pressed) {
204 if (keycode == TERM_OFF && record->event.pressed) {
205 disable_terminal();
206 return false;
207 }
208 if (keycode < 256) {
209 uint8_t str_len;
210 char char_to_add;
211 switch (keycode) {
212 case KC_ENTER:
213 process_terminal_command();
214 return false; break;
215 case KC_ESC:
216 SEND_STRING("\n");
217 enable_terminal();
218 return false; break;
219 case KC_BSPC:
220 str_len = strlen(buffer);
221 if (str_len > 0) {
222 buffer[str_len-1] = 0;
223 return true;
224 } else {
225 TERMINAL_BELL();
226 return false;
227 } break;
228 case KC_LEFT:
229 case KC_RIGHT:
230 case KC_UP:
231 case KC_DOWN:
232 return false; break;
233 default:
234 if (keycode <= 58) {
235 char_to_add = 0;
236 if (get_mods() & (MOD_BIT(KC_LSHIFT) | MOD_BIT(KC_RSHIFT))) {
237 char_to_add = shifted_keycode_to_ascii_lut[keycode];
238 } else if (get_mods() == 0) {
239 char_to_add = keycode_to_ascii_lut[keycode];
240 }
241 if (char_to_add != 0) {
242 strncat(buffer, &char_to_add, 1);
243 }
244 } break;
245 }
246
247
248
249 }
250 }
251 return true;
252} \ No newline at end of file
diff --git a/quantum/process_keycode/process_terminal.h b/quantum/process_keycode/process_terminal.h
new file mode 100644
index 000000000..d945949a4
--- /dev/null
+++ b/quantum/process_keycode/process_terminal.h
@@ -0,0 +1,27 @@
1/* Copyright 2017 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_TERMINAL_H
18#define PROCESS_TERMINAL_H
19
20#include "quantum.h"
21
22extern const char keycode_to_ascii_lut[58];
23extern const char shifted_keycode_to_ascii_lut[58];
24extern const char terminal_prompt[8];
25bool process_terminal(uint16_t keycode, keyrecord_t *record);
26
27#endif \ No newline at end of file
diff --git a/quantum/process_keycode/process_terminal_nop.h b/quantum/process_keycode/process_terminal_nop.h
new file mode 100644
index 000000000..56895b33c
--- /dev/null
+++ b/quantum/process_keycode/process_terminal_nop.h
@@ -0,0 +1,25 @@
1/* Copyright 2017 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_TERMINAL_H
18#define PROCESS_TERMINAL_H
19
20#include "quantum.h"
21
22#define TERM_ON KC_NO
23#define TERM_OFF KC_NO
24
25#endif \ No newline at end of file
diff --git a/quantum/process_keycode/process_unicode_common.c b/quantum/process_keycode/process_unicode_common.c
index 84b5d673d..7f34ad57c 100644
--- a/quantum/process_keycode/process_unicode_common.c
+++ b/quantum/process_keycode/process_unicode_common.c
@@ -49,6 +49,9 @@ void unicode_input_start (void) {
49 case UC_OSX: 49 case UC_OSX:
50 register_code(KC_LALT); 50 register_code(KC_LALT);
51 break; 51 break;
52 case UC_OSX_RALT:
53 register_code(KC_RALT);
54 break;
52 case UC_LNX: 55 case UC_LNX:
53 register_code(KC_LCTL); 56 register_code(KC_LCTL);
54 register_code(KC_LSFT); 57 register_code(KC_LSFT);
@@ -78,6 +81,9 @@ void unicode_input_finish (void) {
78 case UC_WIN: 81 case UC_WIN:
79 unregister_code(KC_LALT); 82 unregister_code(KC_LALT);
80 break; 83 break;
84 case UC_OSX_RALT:
85 unregister_code(KC_RALT);
86 break;
81 case UC_LNX: 87 case UC_LNX:
82 register_code(KC_SPC); 88 register_code(KC_SPC);
83 unregister_code(KC_SPC); 89 unregister_code(KC_SPC);
diff --git a/quantum/process_keycode/process_unicode_common.h b/quantum/process_keycode/process_unicode_common.h
index f5be1da5c..4d2b04fb3 100644
--- a/quantum/process_keycode/process_unicode_common.h
+++ b/quantum/process_keycode/process_unicode_common.h
@@ -37,6 +37,7 @@ void register_hex(uint16_t hex);
37#define UC_WIN 2 // Windows 'HexNumpad' 37#define UC_WIN 2 // Windows 'HexNumpad'
38#define UC_BSD 3 // BSD (not implemented) 38#define UC_BSD 3 // BSD (not implemented)
39#define UC_WINC 4 // WinCompose https://github.com/samhocevar/wincompose 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
40 41
41#define UC_BSPC UC(0x0008) 42#define UC_BSPC UC(0x0008)
42 43
diff --git a/quantum/process_keycode/process_unicodemap.c b/quantum/process_keycode/process_unicodemap.c
index 75f35112b..47c27b911 100644
--- a/quantum/process_keycode/process_unicodemap.c
+++ b/quantum/process_keycode/process_unicodemap.c
@@ -50,7 +50,7 @@ bool process_unicode_map(uint16_t keycode, keyrecord_t *record) {
50 const uint32_t* map = unicode_map; 50 const uint32_t* map = unicode_map;
51 uint16_t index = keycode - QK_UNICODE_MAP; 51 uint16_t index = keycode - QK_UNICODE_MAP;
52 uint32_t code = pgm_read_dword(&map[index]); 52 uint32_t code = pgm_read_dword(&map[index]);
53 if (code > 0xFFFF && code <= 0x10ffff && input_mode == UC_OSX) { 53 if (code > 0xFFFF && code <= 0x10ffff && (input_mode == UC_OSX || input_mode == UC_OSX_RALT)) {
54 // Convert to UTF-16 surrogate pair 54 // Convert to UTF-16 surrogate pair
55 code -= 0x10000; 55 code -= 0x10000;
56 uint32_t lo = code & 0x3ff; 56 uint32_t lo = code & 0x3ff;
@@ -59,7 +59,7 @@ bool process_unicode_map(uint16_t keycode, keyrecord_t *record) {
59 register_hex32(hi + 0xd800); 59 register_hex32(hi + 0xd800);
60 register_hex32(lo + 0xdc00); 60 register_hex32(lo + 0xdc00);
61 unicode_input_finish(); 61 unicode_input_finish();
62 } else if ((code > 0x10ffff && input_mode == UC_OSX) || (code > 0xFFFFF && input_mode == UC_LNX)) { 62 } else if ((code > 0x10ffff && (input_mode == UC_OSX || input_mode == UC_OSX_RALT)) || (code > 0xFFFFF && input_mode == UC_LNX)) {
63 // when character is out of range supported by the OS 63 // when character is out of range supported by the OS
64 unicode_map_input_error(); 64 unicode_map_input_error();
65 } else { 65 } else {