diff options
Diffstat (limited to 'quantum/process_keycode')
| -rw-r--r-- | quantum/process_keycode/process_audio.c | 22 | ||||
| -rw-r--r-- | quantum/process_keycode/process_key_lock.c | 138 | ||||
| -rw-r--r-- | quantum/process_keycode/process_key_lock.h | 24 | ||||
| -rw-r--r-- | quantum/process_keycode/process_leader.c | 4 | ||||
| -rw-r--r-- | quantum/process_keycode/process_music.c | 153 | ||||
| -rw-r--r-- | quantum/process_keycode/process_music.h | 9 | ||||
| -rw-r--r-- | quantum/process_keycode/process_steno.c | 165 | ||||
| -rw-r--r-- | quantum/process_keycode/process_steno.h | 31 | ||||
| -rw-r--r-- | quantum/process_keycode/process_tap_dance.c | 18 | ||||
| -rw-r--r-- | quantum/process_keycode/process_tap_dance.h | 14 | ||||
| -rw-r--r-- | quantum/process_keycode/process_terminal.c | 252 | ||||
| -rw-r--r-- | quantum/process_keycode/process_terminal.h | 27 | ||||
| -rw-r--r-- | quantum/process_keycode/process_terminal_nop.h | 25 | ||||
| -rw-r--r-- | quantum/process_keycode/process_unicode_common.c | 6 | ||||
| -rw-r--r-- | quantum/process_keycode/process_unicode_common.h | 1 | ||||
| -rw-r--r-- | quantum/process_keycode/process_unicodemap.c | 4 |
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 | ||
| 7 | float voice_change_song[][2] = VOICE_CHANGE_SONG; | ||
| 8 | |||
| 9 | #ifndef PITCH_STANDARD_A | ||
| 10 | #define PITCH_STANDARD_A 440.0f | ||
| 11 | #endif | ||
| 12 | |||
| 4 | static float compute_freq_for_midi_note(uint8_t note) | 13 | static 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 | ||
| 10 | bool process_audio(uint16_t keycode, keyrecord_t *record) { | 19 | bool 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. | ||
| 50 | uint64_t key_state[4] = { 0x0, 0x0, 0x0, 0x0 }; | ||
| 51 | bool watching = false; | ||
| 52 | |||
| 53 | // Translate any OSM keycodes back to their unmasked versions. | ||
| 54 | uint16_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 | |||
| 62 | bool 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 | |||
| 22 | bool 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 @@ | |||
| 27 | bool music_activated = false; | 27 | bool music_activated = false; |
| 28 | uint8_t music_starting_note = 0x0C; | 28 | uint8_t music_starting_note = 0x0C; |
| 29 | int music_offset = 7; | 29 | int music_offset = 7; |
| 30 | uint8_t music_mode = MUSIC_MODE_CHROMATIC; | ||
| 30 | 31 | ||
| 31 | // music sequencer | 32 | // music sequencer |
| 32 | static bool music_sequence_recording = false; | 33 | static bool music_sequence_recording = false; |
| @@ -39,6 +40,39 @@ static uint8_t music_sequence_position = 0; | |||
| 39 | static uint16_t music_sequence_timer = 0; | 40 | static uint16_t music_sequence_timer = 0; |
| 40 | static uint16_t music_sequence_interval = 100; | 41 | static 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 | |||
| 42 | static void music_noteon(uint8_t note) { | 76 | static 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 | ||
| 176 | void music_on(void) { | 211 | void 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 | ||
| 181 | void music_off(void) { | 219 | void 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 | |||
| 227 | void 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 | ||
| 186 | void matrix_scan_music(void) { | 235 | void 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 | ||
| 24 | enum music_modes { | ||
| 25 | MUSIC_MODE_CHROMATIC, | ||
| 26 | MUSIC_MODE_GUITAR, | ||
| 27 | MUSIC_MODE_VIOLIN, | ||
| 28 | MUSIC_MODE_MAJOR, | ||
| 29 | NUMBER_OF_MODES | ||
| 30 | }; | ||
| 31 | |||
| 24 | bool process_music(uint16_t keycode, keyrecord_t *record); | 32 | bool process_music(uint16_t keycode, keyrecord_t *record); |
| 25 | 33 | ||
| 26 | bool is_music_on(void); | 34 | bool is_music_on(void); |
| @@ -31,6 +39,7 @@ void music_off(void); | |||
| 31 | void music_on_user(void); | 39 | void music_on_user(void); |
| 32 | void music_scale_user(void); | 40 | void music_scale_user(void); |
| 33 | void music_all_notes_off(void); | 41 | void music_all_notes_off(void); |
| 42 | void music_mode_cycle(void); | ||
| 34 | 43 | ||
| 35 | void matrix_scan_music(void); | 44 | void 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 | |||
| 60 | uint8_t state[MAX_STATE_SIZE] = {0}; | ||
| 61 | uint8_t pressed = 0; | ||
| 62 | steno_mode_t mode; | ||
| 63 | |||
| 64 | uint8_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 | |||
| 73 | void steno_clear_state(void) { | ||
| 74 | __builtin_memset(state, 0, sizeof(state)); | ||
| 75 | } | ||
| 76 | |||
| 77 | void steno_init() { | ||
| 78 | if (!eeconfig_is_enabled()) { | ||
| 79 | eeconfig_init(); | ||
| 80 | } | ||
| 81 | mode = eeprom_read_byte(EECONFIG_STENOMODE); | ||
| 82 | } | ||
| 83 | |||
| 84 | void 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 | |||
| 90 | void 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 | |||
| 99 | bool update_state_bolt(uint8_t key) { | ||
| 100 | uint8_t boltcode = boltmap[key]; | ||
| 101 | state[TXB_GET_GROUP(boltcode)] |= boltcode; | ||
| 102 | return false; | ||
| 103 | } | ||
| 104 | |||
| 105 | bool send_state_bolt(void) { | ||
| 106 | send_steno_state(BOLT_STATE_SIZE, false); | ||
| 107 | virtser_send(0); // terminating byte | ||
| 108 | return false; | ||
| 109 | } | ||
| 110 | |||
| 111 | bool update_state_gemini(uint8_t key) { | ||
| 112 | state[key / 7] |= 1 << (6 - (key % 7)); | ||
| 113 | return false; | ||
| 114 | } | ||
| 115 | |||
| 116 | bool 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 | |||
| 122 | bool 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 | |||
| 25 | typedef enum { STENO_MODE_BOLT, STENO_MODE_GEMINI } steno_mode_t; | ||
| 26 | |||
| 27 | bool process_steno(uint16_t keycode, keyrecord_t *record); | ||
| 28 | void steno_init(void); | ||
| 29 | void 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 | ||
| 44 | void 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 | |||
| 54 | void 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 | |||
| 44 | static inline void _process_tap_dance_action_fn (qk_tap_dance_state_t *state, | 62 | static 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 | ||
| 57 | typedef 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); | |||
| 86 | void qk_tap_dance_pair_finished (qk_tap_dance_state_t *state, void *user_data); | 97 | void qk_tap_dance_pair_finished (qk_tap_dance_state_t *state, void *user_data); |
| 87 | void qk_tap_dance_pair_reset (qk_tap_dance_state_t *state, void *user_data); | 98 | void qk_tap_dance_pair_reset (qk_tap_dance_state_t *state, void *user_data); |
| 88 | 99 | ||
| 100 | void qk_tap_dance_dual_role_finished (qk_tap_dance_state_t *state, void *user_data); | ||
| 101 | void 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 | |||
| 23 | bool terminal_enabled = false; | ||
| 24 | char buffer[80] = ""; | ||
| 25 | char newline[2] = "\n"; | ||
| 26 | char arguments[6][20]; | ||
| 27 | |||
| 28 | __attribute__ ((weak)) | ||
| 29 | const 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)) | ||
| 42 | const 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)) | ||
| 51 | const 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 | |||
| 59 | struct stringcase { | ||
| 60 | char* string; | ||
| 61 | void (*func)(void); | ||
| 62 | } typedef stringcase; | ||
| 63 | |||
| 64 | void 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 | |||
| 74 | void disable_terminal(void) { | ||
| 75 | terminal_enabled = false; | ||
| 76 | } | ||
| 77 | |||
| 78 | void 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 | |||
| 94 | void terminal_help(void); | ||
| 95 | |||
| 96 | extern const uint16_t keymaps[][MATRIX_ROWS][MATRIX_COLS]; | ||
| 97 | |||
| 98 | void 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 | |||
| 120 | void 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 | |||
| 139 | stringcase terminal_cases[] = { | ||
| 140 | { "about", terminal_about }, | ||
| 141 | { "help", terminal_help }, | ||
| 142 | { "keycode", terminal_keycode }, | ||
| 143 | { "keymap", terminal_keymap }, | ||
| 144 | { "exit", disable_terminal } | ||
| 145 | }; | ||
| 146 | |||
| 147 | void 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 | |||
| 156 | void command_not_found(void) { | ||
| 157 | SEND_STRING("command \""); | ||
| 158 | send_string(buffer); | ||
| 159 | SEND_STRING("\" not found\n"); | ||
| 160 | } | ||
| 161 | |||
| 162 | void 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 | |||
| 196 | bool 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 | |||
| 22 | extern const char keycode_to_ascii_lut[58]; | ||
| 23 | extern const char shifted_keycode_to_ascii_lut[58]; | ||
| 24 | extern const char terminal_prompt[8]; | ||
| 25 | bool 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 { |
