diff options
author | Zay950 <Zay950@users.noreply.github.com> | 2017-03-29 12:00:38 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-03-29 12:00:38 -0700 |
commit | 2366ebfbbdeb6ec29cc9a0facda44d666305dd6e (patch) | |
tree | 883efed0b7260f3143f5a2a879bc3844a8255e0b /quantum/process_keycode | |
parent | 80c5ada3394c5ad8087df00ef878eb2cbcd87d70 (diff) | |
parent | 942f2ccee44bdb2e251553e9730cd8d59307d8b2 (diff) | |
download | qmk_firmware-2366ebfbbdeb6ec29cc9a0facda44d666305dd6e.tar.gz qmk_firmware-2366ebfbbdeb6ec29cc9a0facda44d666305dd6e.zip |
Merge branch 'master' into to_push
Diffstat (limited to 'quantum/process_keycode')
25 files changed, 1935 insertions, 658 deletions
diff --git a/quantum/process_keycode/process_audio.c b/quantum/process_keycode/process_audio.c new file mode 100644 index 0000000000..0b6380ed39 --- /dev/null +++ b/quantum/process_keycode/process_audio.c @@ -0,0 +1,62 @@ +#include "audio.h" +#include "process_audio.h" + +static float compute_freq_for_midi_note(uint8_t note) +{ + // https://en.wikipedia.org/wiki/MIDI_tuning_standard + return pow(2.0, (note - 69) / 12.0) * 440.0f; +} + +bool process_audio(uint16_t keycode, keyrecord_t *record) { + + if (keycode == AU_ON && record->event.pressed) { + audio_on(); + return false; + } + + if (keycode == AU_OFF && record->event.pressed) { + audio_off(); + return false; + } + + if (keycode == AU_TOG && record->event.pressed) { + if (is_audio_on()) + { + audio_off(); + } + else + { + audio_on(); + } + return false; + } + + if (keycode == MUV_IN && record->event.pressed) { + voice_iterate(); + music_scale_user(); + return false; + } + + if (keycode == MUV_DE && record->event.pressed) { + voice_deiterate(); + music_scale_user(); + return false; + } + + return true; +} + +void process_audio_noteon(uint8_t note) { + play_note(compute_freq_for_midi_note(note), 0xF); +} + +void process_audio_noteoff(uint8_t note) { + stop_note(compute_freq_for_midi_note(note)); +} + +void process_audio_all_notes_off(void) { + stop_all_notes(); +} + +__attribute__ ((weak)) +void audio_on_user() {}
\ No newline at end of file diff --git a/quantum/process_keycode/process_audio.h b/quantum/process_keycode/process_audio.h new file mode 100644 index 0000000000..7ac15b7330 --- /dev/null +++ b/quantum/process_keycode/process_audio.h @@ -0,0 +1,11 @@ +#ifndef PROCESS_AUDIO_H +#define PROCESS_AUDIO_H + +bool process_audio(uint16_t keycode, keyrecord_t *record); +void process_audio_noteon(uint8_t note); +void process_audio_noteoff(uint8_t note); +void process_audio_all_notes_off(void); + +void audio_on_user(void); + +#endif
\ No newline at end of file diff --git a/quantum/process_keycode/process_chording.c b/quantum/process_keycode/process_chording.c index d7814629f3..6c6ebe300a 100644 --- a/quantum/process_keycode/process_chording.c +++ b/quantum/process_keycode/process_chording.c @@ -1,3 +1,19 @@ +/* Copyright 2016 Jack Humbert + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + #include "process_chording.h" bool keys_chord(uint8_t keys[]) { @@ -57,4 +73,4 @@ bool process_chording(uint16_t keycode, keyrecord_t *record) { } } return true; -}
\ No newline at end of file +} diff --git a/quantum/process_keycode/process_chording.h b/quantum/process_keycode/process_chording.h index 49c97db3bc..8c0f4862a8 100644 --- a/quantum/process_keycode/process_chording.h +++ b/quantum/process_keycode/process_chording.h @@ -1,3 +1,19 @@ +/* Copyright 2016 Jack Humbert + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + #ifndef PROCESS_CHORDING_H #define PROCESS_CHORDING_H @@ -13,4 +29,4 @@ uint8_t chord_key_down = 0; bool process_chording(uint16_t keycode, keyrecord_t *record); -#endif
\ No newline at end of file +#endif diff --git a/quantum/process_keycode/process_combo.c b/quantum/process_keycode/process_combo.c new file mode 100644 index 0000000000..58d45add22 --- /dev/null +++ b/quantum/process_keycode/process_combo.c @@ -0,0 +1,150 @@ +/* Copyright 2016 Jack Humbert + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "process_combo.h" +#include "print.h" + + +#define COMBO_TIMER_ELAPSED -1 + + +__attribute__ ((weak)) +combo_t key_combos[] = { + +}; + +__attribute__ ((weak)) +void process_combo_event(uint8_t combo_index, bool pressed) { + +} + +static uint8_t current_combo_index = 0; + +static inline void send_combo(uint16_t action, bool pressed) +{ + if (action) { + if (pressed) { + register_code16(action); + } else { + unregister_code16(action); + } + } else { + process_combo_event(current_combo_index, pressed); + } +} + +#define ALL_COMBO_KEYS_ARE_DOWN (((1<<count)-1) == combo->state) +#define NO_COMBO_KEYS_ARE_DOWN (0 == combo->state) +#define KEY_STATE_DOWN(key) do{ combo->state |= (1<<key); } while(0) +#define KEY_STATE_UP(key) do{ combo->state &= ~(1<<key); } while(0) +static bool process_single_combo(combo_t *combo, uint16_t keycode, keyrecord_t *record) +{ + uint8_t count = 0; + uint8_t index = -1; + /* Find index of keycode and number of combo keys */ + for (const uint16_t *keys = combo->keys; ;++count) { + uint16_t key = pgm_read_word(&keys[count]); + if (keycode == key) index = count; + if (COMBO_END == key) break; + } + + /* Return if not a combo key */ + if (-1 == (int8_t)index) return false; + + /* The combos timer is used to signal whether the combo is active */ + bool is_combo_active = COMBO_TIMER_ELAPSED == combo->timer ? false : true; + + if (record->event.pressed) { + KEY_STATE_DOWN(index); + + if (is_combo_active) { + if (ALL_COMBO_KEYS_ARE_DOWN) { /* Combo was pressed */ + send_combo(combo->keycode, true); + combo->timer = COMBO_TIMER_ELAPSED; + } else { /* Combo key was pressed */ + combo->timer = timer_read(); +#ifdef COMBO_ALLOW_ACTION_KEYS + combo->prev_record = *record; +#else + combo->prev_key = keycode; +#endif + } + } + } else { + if (ALL_COMBO_KEYS_ARE_DOWN) { /* Combo was released */ + send_combo(combo->keycode, false); + } + + if (is_combo_active) { /* Combo key was tapped */ +#ifdef COMBO_ALLOW_ACTION_KEYS + record->event.pressed = true; + process_action(record, store_or_get_action(record->event.pressed, record->event.key)); + record->event.pressed = false; + process_action(record, store_or_get_action(record->event.pressed, record->event.key)); +#else + register_code16(keycode); + send_keyboard_report(); + unregister_code16(keycode); +#endif + combo->timer = 0; + } + + KEY_STATE_UP(index); + } + + if (NO_COMBO_KEYS_ARE_DOWN) { + combo->timer = 0; + } + + return is_combo_active; +} + +bool process_combo(uint16_t keycode, keyrecord_t *record) +{ + bool is_combo_key = false; + + for (current_combo_index = 0; current_combo_index < COMBO_COUNT; ++current_combo_index) { + combo_t *combo = &key_combos[current_combo_index]; + is_combo_key |= process_single_combo(combo, keycode, record); + } + + return !is_combo_key; +} + +void matrix_scan_combo(void) +{ + for (int i = 0; i < COMBO_COUNT; ++i) { + combo_t *combo = &key_combos[i]; + if (combo->timer && + combo->timer != COMBO_TIMER_ELAPSED && + timer_elapsed(combo->timer) > COMBO_TERM) { + + /* This disables the combo, meaning key events for this + * combo will be handled by the next processors in the chain + */ + combo->timer = COMBO_TIMER_ELAPSED; + +#ifdef COMBO_ALLOW_ACTION_KEYS + process_action(&combo->prev_record, + store_or_get_action(combo->prev_record.event.pressed, + combo->prev_record.event.key)); +#else + unregister_code16(combo->prev_key); + register_code16(combo->prev_key); +#endif + } + } +} diff --git a/quantum/process_keycode/process_combo.h b/quantum/process_keycode/process_combo.h new file mode 100644 index 0000000000..a5dbd788a4 --- /dev/null +++ b/quantum/process_keycode/process_combo.h @@ -0,0 +1,59 @@ +/* Copyright 2016 Jack Humbert + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef PROCESS_COMBO_H +#define PROCESS_COMBO_H + +#include <stdint.h> +#include "progmem.h" +#include "quantum.h" + +typedef struct +{ + const uint16_t *keys; + uint16_t keycode; +#ifdef EXTRA_EXTRA_LONG_COMBOS + uint32_t state; +#elif EXTRA_LONG_COMBOS + uint16_t state; +#else + uint8_t state; +#endif + uint16_t timer; +#ifdef COMBO_ALLOW_ACTION_KEYS + keyrecord_t prev_record; +#else + uint16_t prev_key; +#endif +} combo_t; + + +#define COMBO(ck, ca) {.keys = &(ck)[0], .keycode = (ca)} +#define COMBO_ACTION(ck) {.keys = &(ck)[0]} + +#define COMBO_END 0 +#ifndef COMBO_COUNT +#define COMBO_COUNT 0 +#endif +#ifndef COMBO_TERM +#define COMBO_TERM TAPPING_TERM +#endif + +bool process_combo(uint16_t keycode, keyrecord_t *record); +void matrix_scan_combo(void); +void process_combo_event(uint8_t combo_index, bool pressed); + +#endif diff --git a/quantum/process_keycode/process_leader.c b/quantum/process_keycode/process_leader.c index e53d221e75..473906d657 100644 --- a/quantum/process_keycode/process_leader.c +++ b/quantum/process_keycode/process_leader.c @@ -1,3 +1,19 @@ +/* Copyright 2016 Jack Humbert + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + #include "process_leader.h" __attribute__ ((weak)) @@ -35,4 +51,4 @@ bool process_leader(uint16_t keycode, keyrecord_t *record) { } } return true; -}
\ No newline at end of file +} diff --git a/quantum/process_keycode/process_leader.h b/quantum/process_keycode/process_leader.h index c83db8abbd..da7a3d2ef7 100644 --- a/quantum/process_keycode/process_leader.h +++ b/quantum/process_keycode/process_leader.h @@ -1,3 +1,19 @@ +/* Copyright 2016 Jack Humbert + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + #ifndef PROCESS_LEADER_H #define PROCESS_LEADER_H @@ -20,4 +36,4 @@ void leader_end(void); #define LEADER_EXTERNS() extern bool leading; extern uint16_t leader_time; extern uint16_t leader_sequence[5]; extern uint8_t leader_sequence_size #define LEADER_DICTIONARY() if (leading && timer_elapsed(leader_time) > LEADER_TIMEOUT) -#endif
\ No newline at end of file +#endif diff --git a/quantum/process_keycode/process_midi.c b/quantum/process_keycode/process_midi.c index 577dad43ac..9184feaae8 100644 --- a/quantum/process_keycode/process_midi.c +++ b/quantum/process_keycode/process_midi.c @@ -1,68 +1,253 @@ +/* Copyright 2016 Jack Humbert + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ #include "process_midi.h" -bool midi_activated = false; -uint8_t midi_starting_note = 0x0C; -int midi_offset = 7; - -bool process_midi(uint16_t keycode, keyrecord_t *record) { - if (keycode == MI_ON && record->event.pressed) { - midi_activated = true; -#ifdef AUDIO_ENABLE - music_scale_user(); -#endif - return false; - } +#ifdef MIDI_ENABLE +#include "midi.h" + +#ifdef MIDI_BASIC + +void process_midi_basic_noteon(uint8_t note) +{ + midi_send_noteon(&midi_device, 0, note, 128); +} + +void process_midi_basic_noteoff(uint8_t note) +{ + midi_send_noteoff(&midi_device, 0, note, 0); +} + +void process_midi_all_notes_off(void) +{ + midi_send_cc(&midi_device, 0, 0x7B, 0); +} + +#endif // MIDI_BASIC + +#ifdef MIDI_ADVANCED + +#include "timer.h" + +static uint8_t tone_status[MIDI_TONE_COUNT]; + +static uint8_t midi_modulation; +static int8_t midi_modulation_step; +static uint16_t midi_modulation_timer; + +inline uint8_t compute_velocity(uint8_t setting) +{ + return (setting + 1) * (128 / (MIDI_VELOCITY_MAX - MIDI_VELOCITY_MIN + 1)); +} - if (keycode == MI_OFF && record->event.pressed) { - midi_activated = false; - midi_send_cc(&midi_device, 0, 0x7B, 0); - return false; +void midi_init(void) +{ + midi_config.octave = MI_OCT_2 - MIDI_OCTAVE_MIN; + midi_config.transpose = 0; + midi_config.velocity = (MIDI_VELOCITY_MAX - MIDI_VELOCITY_MIN); + midi_config.channel = 0; + midi_config.modulation_interval = 8; + + for (uint8_t i = 0; i < MIDI_TONE_COUNT; i++) + { + tone_status[i] = MIDI_INVALID_NOTE; } - if (midi_activated) { - if (record->event.key.col == (MATRIX_COLS - 1) && record->event.key.row == (MATRIX_ROWS - 1)) { - if (record->event.pressed) { - midi_starting_note++; // Change key - midi_send_cc(&midi_device, 0, 0x7B, 0); - } - return false; - } - if (record->event.key.col == (MATRIX_COLS - 2) && record->event.key.row == (MATRIX_ROWS - 1)) { - if (record->event.pressed) { - midi_starting_note--; // Change key - midi_send_cc(&midi_device, 0, 0x7B, 0); - } - return false; - } - if (record->event.key.col == (MATRIX_COLS - 3) && record->event.key.row == (MATRIX_ROWS - 1) && record->event.pressed) { - midi_offset++; // Change scale - midi_send_cc(&midi_device, 0, 0x7B, 0); - return false; - } - if (record->event.key.col == (MATRIX_COLS - 4) && record->event.key.row == (MATRIX_ROWS - 1) && record->event.pressed) { - midi_offset--; // Change scale - midi_send_cc(&midi_device, 0, 0x7B, 0); - return false; - } - // basic - // uint8_t note = (midi_starting_note + SCALE[record->event.key.col + midi_offset])+12*(MATRIX_ROWS - record->event.key.row); - // advanced - // uint8_t note = (midi_starting_note + record->event.key.col + midi_offset)+12*(MATRIX_ROWS - record->event.key.row); - // guitar - uint8_t note = (midi_starting_note + record->event.key.col + midi_offset)+5*(MATRIX_ROWS - record->event.key.row); - // violin - // uint8_t note = (midi_starting_note + record->event.key.col + midi_offset)+7*(MATRIX_ROWS - record->event.key.row); - - if (record->event.pressed) { - // midi_send_noteon(&midi_device, record->event.key.row, midi_starting_note + SCALE[record->event.key.col], 127); - midi_send_noteon(&midi_device, 0, note, 127); - } else { - // midi_send_noteoff(&midi_device, record->event.key.row, midi_starting_note + SCALE[record->event.key.col], 127); - midi_send_noteoff(&midi_device, 0, note, 127); - } - - if (keycode < 0xFF) // ignores all normal keycodes, but lets RAISE, LOWER, etc through - return false; + midi_modulation = 0; + midi_modulation_step = 0; + midi_modulation_timer = 0; +} + +void midi_task(void) +{ + if (timer_elapsed(midi_modulation_timer) < midi_config.modulation_interval) + return; + midi_modulation_timer = timer_read(); + + if (midi_modulation_step != 0) + { + dprintf("midi modulation %d\n", midi_modulation); + midi_send_cc(&midi_device, midi_config.channel, 0x1, midi_modulation); + + if (midi_modulation_step < 0 && midi_modulation < -midi_modulation_step) { + midi_modulation = 0; + midi_modulation_step = 0; + return; + } + + midi_modulation += midi_modulation_step; + + if (midi_modulation > 127) + midi_modulation = 127; } - return true; } + +uint8_t midi_compute_note(uint16_t keycode) +{ + return 12 * midi_config.octave + (keycode - MIDI_TONE_MIN) + midi_config.transpose; +} + +bool process_midi(uint16_t keycode, keyrecord_t *record) +{ + switch (keycode) { + case MIDI_TONE_MIN ... MIDI_TONE_MAX: + { + uint8_t channel = midi_config.channel; + uint8_t tone = keycode - MIDI_TONE_MIN; + uint8_t velocity = compute_velocity(midi_config.velocity); + if (record->event.pressed) { + uint8_t note = midi_compute_note(keycode); + midi_send_noteon(&midi_device, channel, note, velocity); + dprintf("midi noteon channel:%d note:%d velocity:%d\n", channel, note, velocity); + tone_status[tone] = note; + } + else { + uint8_t note = tone_status[tone]; + if (note != MIDI_INVALID_NOTE) + { + midi_send_noteoff(&midi_device, channel, note, velocity); + dprintf("midi noteoff channel:%d note:%d velocity:%d\n", channel, note, velocity); + } + tone_status[tone] = MIDI_INVALID_NOTE; + } + return false; + } + case MIDI_OCTAVE_MIN ... MIDI_OCTAVE_MAX: + if (record->event.pressed) { + midi_config.octave = keycode - MIDI_OCTAVE_MIN; + dprintf("midi octave %d\n", midi_config.octave); + } + return false; + case MI_OCTD: + if (record->event.pressed && midi_config.octave > 0) { + midi_config.octave--; + dprintf("midi octave %d\n", midi_config.octave); + } + return false; + case MI_OCTU: + if (record->event.pressed && midi_config.octave < (MIDI_OCTAVE_MAX - MIDI_OCTAVE_MIN)) { + midi_config.octave++; + dprintf("midi octave %d\n", midi_config.octave); + } + return false; + case MIDI_TRANSPOSE_MIN ... MIDI_TRANSPOSE_MAX: + if (record->event.pressed) { + midi_config.transpose = keycode - MI_TRNS_0; + dprintf("midi transpose %d\n", midi_config.transpose); + } + return false; + case MI_TRNSD: + if (record->event.pressed && midi_config.transpose > (MIDI_TRANSPOSE_MIN - MI_TRNS_0)) { + midi_config.transpose--; + dprintf("midi transpose %d\n", midi_config.transpose); + } + return false; + case MI_TRNSU: + if (record->event.pressed && midi_config.transpose < (MIDI_TRANSPOSE_MAX - MI_TRNS_0)) { + const bool positive = midi_config.transpose > 0; + midi_config.transpose++; + if (positive && midi_config.transpose < 0) + midi_config.transpose--; + dprintf("midi transpose %d\n", midi_config.transpose); + } + return false; + case MIDI_VELOCITY_MIN ... MIDI_VELOCITY_MAX: + if (record->event.pressed) { + midi_config.velocity = keycode - MIDI_VELOCITY_MIN; + dprintf("midi velocity %d\n", midi_config.velocity); + } + return false; + case MI_VELD: + if (record->event.pressed && midi_config.velocity > 0) { + midi_config.velocity--; + dprintf("midi velocity %d\n", midi_config.velocity); + } + return false; + case MI_VELU: + if (record->event.pressed) { + midi_config.velocity++; + dprintf("midi velocity %d\n", midi_config.velocity); + } + return false; + case MIDI_CHANNEL_MIN ... MIDI_CHANNEL_MAX: + if (record->event.pressed) { + midi_config.channel = keycode - MIDI_CHANNEL_MIN; + dprintf("midi channel %d\n", midi_config.channel); + } + return false; + case MI_CHD: + if (record->event.pressed) { + midi_config.channel--; + dprintf("midi channel %d\n", midi_config.channel); + } + return false; + case MI_CHU: + if (record->event.pressed) { + midi_config.channel++; + dprintf("midi channel %d\n", midi_config.channel); + } + return false; + case MI_ALLOFF: + if (record->event.pressed) { + midi_send_cc(&midi_device, midi_config.channel, 0x7B, 0); + dprintf("midi all notes off\n"); + } + return false; + case MI_SUS: + midi_send_cc(&midi_device, midi_config.channel, 0x40, record->event.pressed ? 127 : 0); + dprintf("midi sustain %d\n", record->event.pressed); + return false; + case MI_PORT: + midi_send_cc(&midi_device, midi_config.channel, 0x41, record->event.pressed ? 127 : 0); + dprintf("midi portamento %d\n", record->event.pressed); + return false; + case MI_SOST: + midi_send_cc(&midi_device, midi_config.channel, 0x42, record->event.pressed ? 127 : 0); + dprintf("midi sostenuto %d\n", record->event.pressed); + return false; + case MI_SOFT: + midi_send_cc(&midi_device, midi_config.channel, 0x43, record->event.pressed ? 127 : 0); + dprintf("midi soft %d\n", record->event.pressed); + return false; + case MI_LEG: + midi_send_cc(&midi_device, midi_config.channel, 0x43, record->event.pressed ? 127 : 0); + dprintf("midi legato %d\n", record->event.pressed); + return false; + case MI_MOD: + midi_modulation_step = record->event.pressed ? 1 : -1; + return false; + case MI_MODSD: + if (record->event.pressed) { + midi_config.modulation_interval++; + // prevent overflow + if (midi_config.modulation_interval == 0) + midi_config.modulation_interval--; + dprintf("midi modulation interval %d\n", midi_config.modulation_interval); + } + return false; + case MI_MODSU: + if (record->event.pressed && midi_config.modulation_interval > 0) { + midi_config.modulation_interval--; + dprintf("midi modulation interval %d\n", midi_config.modulation_interval); + } + return false; + }; + + return true; +} + +#endif // MIDI_ADVANCED + +#endif // MIDI_ENABLE diff --git a/quantum/process_keycode/process_midi.h b/quantum/process_keycode/process_midi.h index acd4fc1b16..ccac8981a6 100644 --- a/quantum/process_keycode/process_midi.h +++ b/quantum/process_keycode/process_midi.h @@ -1,207 +1,56 @@ +/* Copyright 2016 Jack Humbert + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + #ifndef PROCESS_MIDI_H #define PROCESS_MIDI_H #include "quantum.h" -bool process_midi(uint16_t keycode, keyrecord_t *record); +#ifdef MIDI_ENABLE + +#ifdef MIDI_BASIC +void process_midi_basic_noteon(uint8_t note); +void process_midi_basic_noteoff(uint8_t note); +void process_midi_all_notes_off(void); +#endif -#define MIDI(n) ((n) | 0x6000) -#define MIDI12 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000, 0x6000 +#ifdef MIDI_ADVANCED +typedef union { + uint32_t raw; + struct { + uint8_t octave :4; + int8_t transpose :4; + uint8_t velocity :4; + uint8_t channel :4; + uint8_t modulation_interval :4; + }; +} midi_config_t; + +midi_config_t midi_config; + +void midi_init(void); +void midi_task(void); +bool process_midi(uint16_t keycode, keyrecord_t *record); -#define CHNL(note, channel) (note + (channel << 8)) +#define MIDI_INVALID_NOTE 0xFF +#define MIDI_TONE_COUNT (MIDI_TONE_MAX - MIDI_TONE_MIN + 1) -#define SCALE (int8_t []){ 0 + (12*0), 2 + (12*0), 4 + (12*0), 5 + (12*0), 7 + (12*0), 9 + (12*0), 11 + (12*0), \ - 0 + (12*1), 2 + (12*1), 4 + (12*1), 5 + (12*1), 7 + (12*1), 9 + (12*1), 11 + (12*1), \ - 0 + (12*2), 2 + (12*2), 4 + (12*2), 5 + (12*2), 7 + (12*2), 9 + (12*2), 11 + (12*2), \ - 0 + (12*3), 2 + (12*3), 4 + (12*3), 5 + (12*3), 7 + (12*3), 9 + (12*3), 11 + (12*3), \ - 0 + (12*4), 2 + (12*4), 4 + (12*4), 5 + (12*4), 7 + (12*4), 9 + (12*4), 11 + (12*4), } +uint8_t midi_compute_note(uint16_t keycode); +#endif // MIDI_ADVANCED -#define N_CN1 (0x600C + (12 * -1) + 0 ) -#define N_CN1S (0x600C + (12 * -1) + 1 ) -#define N_DN1F (0x600C + (12 * -1) + 1 ) -#define N_DN1 (0x600C + (12 * -1) + 2 ) -#define N_DN1S (0x600C + (12 * -1) + 3 ) -#define N_EN1F (0x600C + (12 * -1) + 3 ) -#define N_EN1 (0x600C + (12 * -1) + 4 ) -#define N_FN1 (0x600C + (12 * -1) + 5 ) -#define N_FN1S (0x600C + (12 * -1) + 6 ) -#define N_GN1F (0x600C + (12 * -1) + 6 ) -#define N_GN1 (0x600C + (12 * -1) + 7 ) -#define N_GN1S (0x600C + (12 * -1) + 8 ) -#define N_AN1F (0x600C + (12 * -1) + 8 ) -#define N_AN1 (0x600C + (12 * -1) + 9 ) -#define N_AN1S (0x600C + (12 * -1) + 10) -#define N_BN1F (0x600C + (12 * -1) + 10) -#define N_BN1 (0x600C + (12 * -1) + 11) -#define N_C0 (0x600C + (12 * 0) + 0 ) -#define N_C0S (0x600C + (12 * 0) + 1 ) -#define N_D0F (0x600C + (12 * 0) + 1 ) -#define N_D0 (0x600C + (12 * 0) + 2 ) -#define N_D0S (0x600C + (12 * 0) + 3 ) -#define N_E0F (0x600C + (12 * 0) + 3 ) -#define N_E0 (0x600C + (12 * 0) + 4 ) -#define N_F0 (0x600C + (12 * 0) + 5 ) -#define N_F0S (0x600C + (12 * 0) + 6 ) -#define N_G0F (0x600C + (12 * 0) + 6 ) -#define N_G0 (0x600C + (12 * 0) + 7 ) -#define N_G0S (0x600C + (12 * 0) + 8 ) -#define N_A0F (0x600C + (12 * 0) + 8 ) -#define N_A0 (0x600C + (12 * 0) + 9 ) -#define N_A0S (0x600C + (12 * 0) + 10) -#define N_B0F (0x600C + (12 * 0) + 10) -#define N_B0 (0x600C + (12 * 0) + 11) -#define N_C1 (0x600C + (12 * 1) + 0 ) -#define N_C1S (0x600C + (12 * 1) + 1 ) -#define N_D1F (0x600C + (12 * 1) + 1 ) -#define N_D1 (0x600C + (12 * 1) + 2 ) -#define N_D1S (0x600C + (12 * 1) + 3 ) -#define N_E1F (0x600C + (12 * 1) + 3 ) -#define N_E1 (0x600C + (12 * 1) + 4 ) -#define N_F1 (0x600C + (12 * 1) + 5 ) -#define N_F1S (0x600C + (12 * 1) + 6 ) -#define N_G1F (0x600C + (12 * 1) + 6 ) -#define N_G1 (0x600C + (12 * 1) + 7 ) -#define N_G1S (0x600C + (12 * 1) + 8 ) -#define N_A1F (0x600C + (12 * 1) + 8 ) -#define N_A1 (0x600C + (12 * 1) + 9 ) -#define N_A1S (0x600C + (12 * 1) + 10) -#define N_B1F (0x600C + (12 * 1) + 10) -#define N_B1 (0x600C + (12 * 1) + 11) -#define N_C2 (0x600C + (12 * 2) + 0 ) -#define N_C2S (0x600C + (12 * 2) + 1 ) -#define N_D2F (0x600C + (12 * 2) + 1 ) -#define N_D2 (0x600C + (12 * 2) + 2 ) -#define N_D2S (0x600C + (12 * 2) + 3 ) -#define N_E2F (0x600C + (12 * 2) + 3 ) -#define N_E2 (0x600C + (12 * 2) + 4 ) -#define N_F2 (0x600C + (12 * 2) + 5 ) -#define N_F2S (0x600C + (12 * 2) + 6 ) -#define N_G2F (0x600C + (12 * 2) + 6 ) -#define N_G2 (0x600C + (12 * 2) + 7 ) -#define N_G2S (0x600C + (12 * 2) + 8 ) -#define N_A2F (0x600C + (12 * 2) + 8 ) -#define N_A2 (0x600C + (12 * 2) + 9 ) -#define N_A2S (0x600C + (12 * 2) + 10) -#define N_B2F (0x600C + (12 * 2) + 10) -#define N_B2 (0x600C + (12 * 2) + 11) -#define N_C3 (0x600C + (12 * 3) + 0 ) -#define N_C3S (0x600C + (12 * 3) + 1 ) -#define N_D3F (0x600C + (12 * 3) + 1 ) -#define N_D3 (0x600C + (12 * 3) + 2 ) -#define N_D3S (0x600C + (12 * 3) + 3 ) -#define N_E3F (0x600C + (12 * 3) + 3 ) -#define N_E3 (0x600C + (12 * 3) + 4 ) -#define N_F3 (0x600C + (12 * 3) + 5 ) -#define N_F3S (0x600C + (12 * 3) + 6 ) -#define N_G3F (0x600C + (12 * 3) + 6 ) -#define N_G3 (0x600C + (12 * 3) + 7 ) -#define N_G3S (0x600C + (12 * 3) + 8 ) -#define N_A3F (0x600C + (12 * 3) + 8 ) -#define N_A3 (0x600C + (12 * 3) + 9 ) -#define N_A3S (0x600C + (12 * 3) + 10) -#define N_B3F (0x600C + (12 * 3) + 10) -#define N_B3 (0x600C + (12 * 3) + 11) -#define N_C4 (0x600C + (12 * 4) + 0 ) -#define N_C4S (0x600C + (12 * 4) + 1 ) -#define N_D4F (0x600C + (12 * 4) + 1 ) -#define N_D4 (0x600C + (12 * 4) + 2 ) -#define N_D4S (0x600C + (12 * 4) + 3 ) -#define N_E4F (0x600C + (12 * 4) + 3 ) -#define N_E4 (0x600C + (12 * 4) + 4 ) -#define N_F4 (0x600C + (12 * 4) + 5 ) -#define N_F4S (0x600C + (12 * 4) + 6 ) -#define N_G4F (0x600C + (12 * 4) + 6 ) -#define N_G4 (0x600C + (12 * 4) + 7 ) -#define N_G4S (0x600C + (12 * 4) + 8 ) -#define N_A4F (0x600C + (12 * 4) + 8 ) -#define N_A4 (0x600C + (12 * 4) + 9 ) -#define N_A4S (0x600C + (12 * 4) + 10) -#define N_B4F (0x600C + (12 * 4) + 10) -#define N_B4 (0x600C + (12 * 4) + 11) -#define N_C5 (0x600C + (12 * 5) + 0 ) -#define N_C5S (0x600C + (12 * 5) + 1 ) -#define N_D5F (0x600C + (12 * 5) + 1 ) -#define N_D5 (0x600C + (12 * 5) + 2 ) -#define N_D5S (0x600C + (12 * 5) + 3 ) -#define N_E5F (0x600C + (12 * 5) + 3 ) -#define N_E5 (0x600C + (12 * 5) + 4 ) -#define N_F5 (0x600C + (12 * 5) + 5 ) -#define N_F5S (0x600C + (12 * 5) + 6 ) -#define N_G5F (0x600C + (12 * 5) + 6 ) -#define N_G5 (0x600C + (12 * 5) + 7 ) -#define N_G5S (0x600C + (12 * 5) + 8 ) -#define N_A5F (0x600C + (12 * 5) + 8 ) -#define N_A5 (0x600C + (12 * 5) + 9 ) -#define N_A5S (0x600C + (12 * 5) + 10) -#define N_B5F (0x600C + (12 * 5) + 10) -#define N_B5 (0x600C + (12 * 5) + 11) -#define N_C6 (0x600C + (12 * 6) + 0 ) -#define N_C6S (0x600C + (12 * 6) + 1 ) -#define N_D6F (0x600C + (12 * 6) + 1 ) -#define N_D6 (0x600C + (12 * 6) + 2 ) -#define N_D6S (0x600C + (12 * 6) + 3 ) -#define N_E6F (0x600C + (12 * 6) + 3 ) -#define N_E6 (0x600C + (12 * 6) + 4 ) -#define N_F6 (0x600C + (12 * 6) + 5 ) -#define N_F6S (0x600C + (12 * 6) + 6 ) -#define N_G6F (0x600C + (12 * 6) + 6 ) -#define N_G6 (0x600C + (12 * 6) + 7 ) -#define N_G6S (0x600C + (12 * 6) + 8 ) -#define N_A6F (0x600C + (12 * 6) + 8 ) -#define N_A6 (0x600C + (12 * 6) + 9 ) -#define N_A6S (0x600C + (12 * 6) + 10) -#define N_B6F (0x600C + (12 * 6) + 10) -#define N_B6 (0x600C + (12 * 6) + 11) -#define N_C7 (0x600C + (12 * 7) + 0 ) -#define N_C7S (0x600C + (12 * 7) + 1 ) -#define N_D7F (0x600C + (12 * 7) + 1 ) -#define N_D7 (0x600C + (12 * 7) + 2 ) -#define N_D7S (0x600C + (12 * 7) + 3 ) -#define N_E7F (0x600C + (12 * 7) + 3 ) -#define N_E7 (0x600C + (12 * 7) + 4 ) -#define N_F7 (0x600C + (12 * 7) + 5 ) -#define N_F7S (0x600C + (12 * 7) + 6 ) -#define N_G7F (0x600C + (12 * 7) + 6 ) -#define N_G7 (0x600C + (12 * 7) + 7 ) -#define N_G7S (0x600C + (12 * 7) + 8 ) -#define N_A7F (0x600C + (12 * 7) + 8 ) -#define N_A7 (0x600C + (12 * 7) + 9 ) -#define N_A7S (0x600C + (12 * 7) + 10) -#define N_B7F (0x600C + (12 * 7) + 10) -#define N_B7 (0x600C + (12 * 7) + 11) -#define N_C8 (0x600C + (12 * 8) + 0 ) -#define N_C8S (0x600C + (12 * 8) + 1 ) -#define N_D8F (0x600C + (12 * 8) + 1 ) -#define N_D8 (0x600C + (12 * 8) + 2 ) -#define N_D8S (0x600C + (12 * 8) + 3 ) -#define N_E8F (0x600C + (12 * 8) + 3 ) -#define N_E8 (0x600C + (12 * 8) + 4 ) -#define N_F8 (0x600C + (12 * 8) + 5 ) -#define N_F8S (0x600C + (12 * 8) + 6 ) -#define N_G8F (0x600C + (12 * 8) + 6 ) -#define N_G8 (0x600C + (12 * 8) + 7 ) -#define N_G8S (0x600C + (12 * 8) + 8 ) -#define N_A8F (0x600C + (12 * 8) + 8 ) -#define N_A8 (0x600C + (12 * 8) + 9 ) -#define N_A8S (0x600C + (12 * 8) + 10) -#define N_B8F (0x600C + (12 * 8) + 10) -#define N_B8 (0x600C + (12 * 8) + 11) -#define N_C8 (0x600C + (12 * 8) + 0 ) -#define N_C8S (0x600C + (12 * 8) + 1 ) -#define N_D8F (0x600C + (12 * 8) + 1 ) -#define N_D8 (0x600C + (12 * 8) + 2 ) -#define N_D8S (0x600C + (12 * 8) + 3 ) -#define N_E8F (0x600C + (12 * 8) + 3 ) -#define N_E8 (0x600C + (12 * 8) + 4 ) -#define N_F8 (0x600C + (12 * 8) + 5 ) -#define N_F8S (0x600C + (12 * 8) + 6 ) -#define N_G8F (0x600C + (12 * 8) + 6 ) -#define N_G8 (0x600C + (12 * 8) + 7 ) -#define N_G8S (0x600C + (12 * 8) + 8 ) -#define N_A8F (0x600C + (12 * 8) + 8 ) -#define N_A8 (0x600C + (12 * 8) + 9 ) -#define N_A8S (0x600C + (12 * 8) + 10) -#define N_B8F (0x600C + (12 * 8) + 10) -#define N_B8 (0x600C + (12 * 8) + 11) +#endif // MIDI_ENABLE -#endif
\ No newline at end of file +#endif diff --git a/quantum/process_keycode/process_music.c b/quantum/process_keycode/process_music.c index 2d52e47a72..217dca2807 100644 --- a/quantum/process_keycode/process_music.c +++ b/quantum/process_keycode/process_music.c @@ -1,43 +1,72 @@ +/* Copyright 2016 Jack Humbert + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ #include "process_music.h" +#ifdef AUDIO_ENABLE +#include "process_audio.h" +#endif +#if defined(MIDI_ENABLE) && defined(MIDI_BASIC) +#include "process_midi.h" +#endif + +#if defined(AUDIO_ENABLE) || (defined(MIDI_ENABLE) && defined(MIDI_BASIC)) + bool music_activated = false; -uint8_t starting_note = 0x0C; -int offset = 7; +uint8_t music_starting_note = 0x0C; +int music_offset = 7; // music sequencer static bool music_sequence_recording = false; static bool music_sequence_recorded = false; static bool music_sequence_playing = false; -static float music_sequence[16] = {0}; +static uint8_t music_sequence[16] = {0}; static uint8_t music_sequence_count = 0; static uint8_t music_sequence_position = 0; static uint16_t music_sequence_timer = 0; static uint16_t music_sequence_interval = 100; -bool process_music(uint16_t keycode, keyrecord_t *record) { +static void music_noteon(uint8_t note) { + #ifdef AUDIO_ENABLE + process_audio_noteon(note); + #endif + #if defined(MIDI_ENABLE) && defined(MIDI_BASIC) + process_midi_basic_noteon(note); + #endif +} - if (keycode == AU_ON && record->event.pressed) { - audio_on(); - return false; - } +static void music_noteoff(uint8_t note) { + #ifdef AUDIO_ENABLE + process_audio_noteoff(note); + #endif + #if defined(MIDI_ENABLE) && defined(MIDI_BASIC) + process_midi_basic_noteoff(note); + #endif +} - if (keycode == AU_OFF && record->event.pressed) { - audio_off(); - return false; - } +void music_all_notes_off(void) { + #ifdef AUDIO_ENABLE + process_audio_all_notes_off(); + #endif + #if defined(MIDI_ENABLE) && defined(MIDI_BASIC) + process_midi_all_notes_off(); + #endif +} - if (keycode == AU_TOG && record->event.pressed) { - if (is_audio_on()) - { - audio_off(); - } - else - { - audio_on(); - } - return false; - } +bool process_music(uint16_t keycode, keyrecord_t *record) { if (keycode == MU_ON && record->event.pressed) { music_on(); @@ -61,22 +90,10 @@ bool process_music(uint16_t keycode, keyrecord_t *record) { return false; } - if (keycode == MUV_IN && record->event.pressed) { - voice_iterate(); - music_scale_user(); - return false; - } - - if (keycode == MUV_DE && record->event.pressed) { - voice_deiterate(); - music_scale_user(); - return false; - } - if (music_activated) { if (keycode == KC_LCTL && record->event.pressed) { // Start recording - stop_all_notes(); + music_all_notes_off(); music_sequence_recording = true; music_sequence_recorded = false; music_sequence_playing = false; @@ -85,7 +102,7 @@ bool process_music(uint16_t keycode, keyrecord_t *record) { } if (keycode == KC_LALT && record->event.pressed) { // Stop recording/playing - stop_all_notes(); + music_all_notes_off(); if (music_sequence_recording) { // was recording music_sequence_recorded = true; } @@ -95,7 +112,7 @@ bool process_music(uint16_t keycode, keyrecord_t *record) { } if (keycode == KC_LGUI && record->event.pressed && music_sequence_recorded) { // Start playing - stop_all_notes(); + music_all_notes_off(); music_sequence_recording = false; music_sequence_playing = true; music_sequence_position = 0; @@ -115,21 +132,33 @@ bool process_music(uint16_t keycode, keyrecord_t *record) { return false; } - float freq = ((float)220.0)*pow(2.0, -5.0)*pow(2.0,(starting_note + SCALE[record->event.key.col + offset])/12.0+(MATRIX_ROWS - record->event.key.row)); + #define MUSIC_MODE_GUITAR + + #ifdef MUSIC_MODE_CHROMATIC + uint8_t note = (music_starting_note + record->event.key.col + music_offset - 3)+12*(MATRIX_ROWS - record->event.key.row); + #elif defined(MUSIC_MODE_GUITAR) + uint8_t note = (music_starting_note + record->event.key.col + music_offset + 32)+5*(MATRIX_ROWS - record->event.key.row); + #elif defined(MUSIC_MODE_VIOLIN) + uint8_t note = (music_starting_note + record->event.key.col + music_offset + 32)+7*(MATRIX_ROWS - record->event.key.row); + #else + uint8_t note = (music_starting_note + SCALE[record->event.key.col + music_offset] - 3)+12*(MATRIX_ROWS - record->event.key.row); + #endif + if (record->event.pressed) { - play_note(freq, 0xF); + music_noteon(note); if (music_sequence_recording) { - music_sequence[music_sequence_count] = freq; + music_sequence[music_sequence_count] = note; music_sequence_count++; } } else { - stop_note(freq); + music_noteoff(note); } if (keycode < 0xFF) // ignores all normal keycodes, but lets RAISE, LOWER, etc through return false; } - return true; + + return true; } bool is_music_on(void) { @@ -151,26 +180,26 @@ void music_on(void) { void music_off(void) { music_activated = 0; - stop_all_notes(); + music_all_notes_off(); } - -__attribute__ ((weak)) -void music_on_user() {} - -__attribute__ ((weak)) -void audio_on_user() {} - -__attribute__ ((weak)) -void music_scale_user() {} - void matrix_scan_music(void) { if (music_sequence_playing) { if ((music_sequence_timer == 0) || (timer_elapsed(music_sequence_timer) > music_sequence_interval)) { music_sequence_timer = timer_read(); - stop_note(music_sequence[(music_sequence_position - 1 < 0)?(music_sequence_position - 1 + music_sequence_count):(music_sequence_position - 1)]); - play_note(music_sequence[music_sequence_position], 0xF); + uint8_t prev_note = music_sequence[(music_sequence_position - 1 < 0)?(music_sequence_position - 1 + music_sequence_count):(music_sequence_position - 1)]; + uint8_t next_note = music_sequence[music_sequence_position]; + music_noteoff(prev_note); + music_noteon(next_note); music_sequence_position = (music_sequence_position + 1) % music_sequence_count; } } } + +__attribute__ ((weak)) +void music_on_user() {} + +__attribute__ ((weak)) +void music_scale_user() {} + +#endif // defined(AUDIO_ENABLE) || (defined(MIDI_ENABLE) && defined(MIDI_BASIC))
\ No newline at end of file diff --git a/quantum/process_keycode/process_music.h b/quantum/process_keycode/process_music.h index 318b3e3875..8dfbf041f4 100644 --- a/quantum/process_keycode/process_music.h +++ b/quantum/process_keycode/process_music.h @@ -1,8 +1,26 @@ +/* Copyright 2016 Jack Humbert + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + #ifndef PROCESS_MUSIC_H #define PROCESS_MUSIC_H #include "quantum.h" +#if defined(AUDIO_ENABLE) || (defined(MIDI_ENABLE) && defined(MIDI_BASIC)) + bool process_music(uint16_t keycode, keyrecord_t *record); bool is_music_on(void); @@ -10,9 +28,9 @@ void music_toggle(void); void music_on(void); void music_off(void); -void audio_on_user(void); void music_on_user(void); void music_scale_user(void); +void music_all_notes_off(void); void matrix_scan_music(void); @@ -24,4 +42,6 @@ void matrix_scan_music(void); 0 + (12*4), 2 + (12*4), 4 + (12*4), 5 + (12*4), 7 + (12*4), 9 + (12*4), 11 + (12*4), } #endif -#endif
\ No newline at end of file +#endif // defined(AUDIO_ENABLE) || (defined(MIDI_ENABLE) && defined(MIDI_BASIC)) + +#endif diff --git a/quantum/process_keycode/process_printer.c b/quantum/process_keycode/process_printer.c new file mode 100644 index 0000000000..807f7a0b91 --- /dev/null +++ b/quantum/process_keycode/process_printer.c @@ -0,0 +1,270 @@ +/* Copyright 2016 Jack Humbert + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "process_printer.h" +#include "action_util.h" + +bool printing_enabled = false; +uint8_t character_shift = 0; + +void enabled_printing() { + printing_enabled = true; + serial_init(); +} + +void disable_printing() { + printing_enabled = false; +} + +uint8_t shifted_numbers[10] = {0x21, 0x40, 0x23, 0x24, 0x25, 0x5E, 0x26, 0x2A, 0x28, 0x29}; + +// uint8_t keycode_to_ascii[0xFF][2]; + +// keycode_to_ascii[KC_MINS] = {0x2D, 0x5F}; + +void print_char(char c) { + USB_Disable(); + serial_send(c); + USB_Init(); +} + +void print_box_string(uint8_t text[]) { + uint8_t len = strlen(text); + uint8_t out[len * 3 + 8]; + out[0] = 0xDA; + for (uint8_t i = 0; i < len; i++) { + out[i+1] = 0xC4; + } + out[len + 1] = 0xBF; + out[len + 2] = '\n'; + + out[len + 3] = 0xB3; + for (uint8_t i = 0; i < len; i++) { + out[len + 4 + i] = text[i]; + } + out[len * 2 + 4] = 0xB3; + out[len * 2 + 5] = '\n'; + + + out[len * 2 + 6] = 0xC0; + for (uint8_t i = 0; i < len; i++) { + out[len * 2 + 7 + i] = 0xC4; + } + out[len * 3 + 7] = 0xD9; + out[len * 3 + 8] = '\n'; + + print_string(out); +} + +void print_string(char c[]) { + for(uint8_t i = 0; i < strlen(c); i++) + print_char(c[i]); +} + +bool process_printer(uint16_t keycode, keyrecord_t *record) { + if (keycode == PRINT_ON) { + enabled_printing(); + return false; + } + if (keycode == PRINT_OFF) { + disable_printing(); + return false; + } + + if (printing_enabled) { + switch(keycode) { + case KC_EXLM ... KC_RPRN: + case KC_UNDS: + case KC_PLUS: + case KC_LCBR: + case KC_RCBR: + case KC_PIPE: + case KC_TILD: + keycode &= 0xFF; + case KC_LSFT: + case KC_RSFT: + if (record->event.pressed) { + character_shift++; + } else { + character_shift--; + } + return false; + break; + } + + switch(keycode) { + case KC_F1: + if (record->event.pressed) { + print_box_string("This is a line of text!"); + } + return false; + case KC_ESC: + if (record->event.pressed) { + print_char(0x1B); + } + return false; + break; + case KC_SPC: + if (record->event.pressed) { + print_char(0x20); + } + return false; + break; + case KC_A ... KC_Z: + if (record->event.pressed) { + if (character_shift) { + print_char(0x41 + (keycode - KC_A)); + } else { + print_char(0x61 + (keycode - KC_A)); + } + } + return false; + break; + case KC_1 ... KC_0: + if (record->event.pressed) { + if (character_shift) { + print_char(shifted_numbers[keycode - KC_1]); + } else { + print_char(0x30 + ((keycode - KC_1 + 1) % 10)); + } + } + return false; + break; + case KC_ENT: + if (record->event.pressed) { + if (character_shift) { + print_char(0x0C); + } else { + print_char(0x0A); + } + } + return false; + break; + case KC_BSPC: + if (record->event.pressed) { + if (character_shift) { + print_char(0x18); + } else { + print_char(0x1A); + } + } + return false; + break; + case KC_DOT: + if (record->event.pressed) { + if (character_shift) { + print_char(0x3E); + } else { + print_char(0x2E); + } + } + return false; + break; + case KC_COMM: + if (record->event.pressed) { + if (character_shift) { + print_char(0x3C); + } else { + print_char(0x2C); + } + } + return false; + break; + case KC_SLSH: + if (record->event.pressed) { + if (character_shift) { + print_char(0x3F); + } else { + print_char(0x2F); + } + } + return false; + break; + case KC_QUOT: + if (record->event.pressed) { + if (character_shift) { + print_char(0x22); + } else { + print_char(0x27); + } + } + return false; + break; + case KC_GRV: + if (record->event.pressed) { + if (character_shift) { + print_char(0x7E); + } else { + print_char(0x60); + } + } + return false; + break; + case KC_MINS: + if (record->event.pressed) { + if (character_shift) { + print_char(0x5F); + } else { + print_char(0x2D); + } + } + return false; + break; + case KC_EQL: + if (record->event.pressed) { + if (character_shift) { + print_char(0x2B); + } else { + print_char(0x3D); + } + } + return false; + break; + case KC_LBRC: + if (record->event.pressed) { + if (character_shift) { + print_char(0x7B); + } else { + print_char(0x5B); + } + } + return false; + break; + case KC_RBRC: + if (record->event.pressed) { + if (character_shift) { + print_char(0x7D); + } else { + print_char(0x5D); + } + } + return false; + break; + case KC_BSLS: + if (record->event.pressed) { + if (character_shift) { + print_char(0x7C); + } else { + print_char(0x5C); + } + } + return false; + break; + } + } + return true; + +} diff --git a/quantum/process_keycode/process_printer.h b/quantum/process_keycode/process_printer.h new file mode 100644 index 0000000000..aa494ac8a7 --- /dev/null +++ b/quantum/process_keycode/process_printer.h @@ -0,0 +1,24 @@ +/* Copyright 2016 Jack Humbert + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef PROCESS_PRINTER_H +#define PROCESS_PRINTER_H + +#include "quantum.h" + +#include "protocol/serial.h" + +#endif diff --git a/quantum/process_keycode/process_printer_bb.c b/quantum/process_keycode/process_printer_bb.c new file mode 100644 index 0000000000..55d3b552b2 --- /dev/null +++ b/quantum/process_keycode/process_printer_bb.c @@ -0,0 +1,276 @@ +/* Copyright 2016 Jack Humbert + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "process_printer.h" +#include "action_util.h" + +bool printing_enabled = false; +uint8_t character_shift = 0; + +#define SERIAL_PIN_DDR DDRD +#define SERIAL_PIN_PORT PORTD +#define SERIAL_PIN_MASK _BV(PD3) +#define SERIAL_DELAY 52 + +inline static +void serial_delay(void) { + _delay_us(SERIAL_DELAY); +} + +inline static +void serial_high(void) { + SERIAL_PIN_PORT |= SERIAL_PIN_MASK; +} + +inline static +void serial_low(void) { + SERIAL_PIN_PORT &= ~SERIAL_PIN_MASK; +} + +inline static +void serial_output(void) { + SERIAL_PIN_DDR |= SERIAL_PIN_MASK; +} + + +void enabled_printing() { + printing_enabled = true; + serial_output(); + serial_high(); +} + +void disable_printing() { + printing_enabled = false; +} + +uint8_t shifted_numbers[10] = {0x21, 0x40, 0x23, 0x24, 0x25, 0x5E, 0x26, 0x2A, 0x28, 0x29}; + +// uint8_t keycode_to_ascii[0xFF][2]; + +// keycode_to_ascii[KC_MINS] = {0x2D, 0x5F}; + +void print_char(char c) { + uint8_t b = 8; + serial_output(); + while( b-- ) { + if(c & (1 << b)) { + serial_high(); + } else { + serial_low(); + } + serial_delay(); + } +} + +void print_string(char c[]) { + for(uint8_t i = 0; i < strlen(c); i++) + print_char(c[i]); +} + +bool process_printer(uint16_t keycode, keyrecord_t *record) { + if (keycode == PRINT_ON) { + enabled_printing(); + return false; + } + if (keycode == PRINT_OFF) { + disable_printing(); + return false; + } + + if (printing_enabled) { + switch(keycode) { + case KC_EXLM ... KC_RPRN: + case KC_UNDS: + case KC_PLUS: + case KC_LCBR: + case KC_RCBR: + case KC_PIPE: + case KC_TILD: + keycode &= 0xFF; + case KC_LSFT: + case KC_RSFT: + if (record->event.pressed) { + character_shift++; + } else { + character_shift--; + } + return false; + break; + } + + switch(keycode) { + case KC_F1: + if (record->event.pressed) { + print_string("This is a line of text!\n\n\n"); + } + return false; + case KC_ESC: + if (record->event.pressed) { + print_char(0x1B); + } + return false; + break; + case KC_SPC: + if (record->event.pressed) { + print_char(0x20); + } + return false; + break; + case KC_A ... KC_Z: + if (record->event.pressed) { + if (character_shift) { + print_char(0x41 + (keycode - KC_A)); + } else { + print_char(0x61 + (keycode - KC_A)); + } + } + return false; + break; + case KC_1 ... KC_0: + if (record->event.pressed) { + if (character_shift) { + print_char(shifted_numbers[keycode - KC_1]); + } else { + print_char(0x30 + ((keycode - KC_1 + 1) % 10)); + } + } + return false; + break; + case KC_ENT: + if (record->event.pressed) { + if (character_shift) { + print_char(0x0C); + } else { + print_char(0x0A); + } + } + return false; + break; + case KC_BSPC: + if (record->event.pressed) { + if (character_shift) { + print_char(0x18); + } else { + print_char(0x1A); + } + } + return false; + break; + case KC_DOT: + if (record->event.pressed) { + if (character_shift) { + print_char(0x3E); + } else { + print_char(0x2E); + } + } + return false; + break; + case KC_COMM: + if (record->event.pressed) { + if (character_shift) { + print_char(0x3C); + } else { + print_char(0x2C); + } + } + return false; + break; + case KC_SLSH: + if (record->event.pressed) { + if (character_shift) { + print_char(0x3F); + } else { + print_char(0x2F); + } + } + return false; + break; + case KC_QUOT: + if (record->event.pressed) { + if (character_shift) { + print_char(0x22); + } else { + print_char(0x27); + } + } + return false; + break; + case KC_GRV: + if (record->event.pressed) { + if (character_shift) { + print_char(0x7E); + } else { + print_char(0x60); + } + } + return false; + break; + case KC_MINS: + if (record->event.pressed) { + if (character_shift) { + print_char(0x5F); + } else { + print_char(0x2D); + } + } + return false; + break; + case KC_EQL: + if (record->event.pressed) { + if (character_shift) { + print_char(0x2B); + } else { + print_char(0x3D); + } + } + return false; + break; + case KC_LBRC: + if (record->event.pressed) { + if (character_shift) { + print_char(0x7B); + } else { + print_char(0x5B); + } + } + return false; + break; + case KC_RBRC: + if (record->event.pressed) { + if (character_shift) { + print_char(0x7D); + } else { + print_char(0x5D); + } + } + return false; + break; + case KC_BSLS: + if (record->event.pressed) { + if (character_shift) { + print_char(0x7C); + } else { + print_char(0x5C); + } + } + return false; + break; + } + } + return true; + +} diff --git a/quantum/process_keycode/process_tap_dance.c b/quantum/process_keycode/process_tap_dance.c index 6ae362c4c2..68c8425bb4 100644 --- a/quantum/process_keycode/process_tap_dance.c +++ b/quantum/process_keycode/process_tap_dance.c @@ -1,3 +1,18 @@ +/* Copyright 2016 Jack Humbert + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ #include "quantum.h" #include "action_tapping.h" @@ -43,12 +58,16 @@ static inline void process_tap_dance_action_on_dance_finished (qk_tap_dance_acti if (action->state.finished) return; action->state.finished = true; + add_mods(action->state.oneshot_mods); + send_keyboard_report(); _process_tap_dance_action_fn (&action->state, action->user_data, action->fn.on_dance_finished); } static inline void process_tap_dance_action_on_reset (qk_tap_dance_action_t *action) { _process_tap_dance_action_fn (&action->state, action->user_data, action->fn.on_reset); + del_mods(action->state.oneshot_mods); + send_keyboard_report(); } bool process_tap_dance(uint16_t keycode, keyrecord_t *record) { @@ -70,6 +89,7 @@ bool process_tap_dance(uint16_t keycode, keyrecord_t *record) { action->state.keycode = keycode; action->state.count++; action->state.timer = timer_read(); + action->state.oneshot_mods = get_oneshot_mods(); process_tap_dance_action_on_each_tap (action); if (last_td && last_td != keycode) { @@ -109,7 +129,7 @@ void matrix_scan_tap_dance () { if (highest_td == -1) return; - for (int i = 0; i <= highest_td; i++) { +for (int i = 0; i <= highest_td; i++) { qk_tap_dance_action_t *action = &tap_dance_actions[i]; if (action->state.count && timer_elapsed (action->state.timer) > TAPPING_TERM) { diff --git a/quantum/process_keycode/process_tap_dance.h b/quantum/process_keycode/process_tap_dance.h index f753cbba66..330809f83a 100644 --- a/quantum/process_keycode/process_tap_dance.h +++ b/quantum/process_keycode/process_tap_dance.h @@ -1,3 +1,18 @@ +/* Copyright 2016 Jack Humbert + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ #ifndef PROCESS_TAP_DANCE_H #define PROCESS_TAP_DANCE_H @@ -9,6 +24,7 @@ typedef struct { uint8_t count; + uint8_t oneshot_mods; uint16_t keycode; uint16_t timer; bool interrupted; diff --git a/quantum/process_keycode/process_ucis.c b/quantum/process_keycode/process_ucis.c new file mode 100644 index 0000000000..86c0937f5e --- /dev/null +++ b/quantum/process_keycode/process_ucis.c @@ -0,0 +1,149 @@ +/* Copyright 2017 Jack Humbert + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "process_ucis.h" + +qk_ucis_state_t qk_ucis_state; + +void qk_ucis_start(void) { + qk_ucis_state.count = 0; + qk_ucis_state.in_progress = true; + + qk_ucis_start_user(); +} + +__attribute__((weak)) +void qk_ucis_start_user(void) { + unicode_input_start(); + register_hex(0x2328); + unicode_input_finish(); +} + +static bool is_uni_seq(char *seq) { + uint8_t i; + + for (i = 0; seq[i]; i++) { + uint16_t code; + if (('1' <= seq[i]) && (seq[i] <= '0')) + code = seq[i] - '1' + KC_1; + else + code = seq[i] - 'a' + KC_A; + + if (i > qk_ucis_state.count || qk_ucis_state.codes[i] != code) + return false; + } + + return (qk_ucis_state.codes[i] == KC_ENT || + qk_ucis_state.codes[i] == KC_SPC); +} + +__attribute__((weak)) +void qk_ucis_symbol_fallback (void) { + for (uint8_t i = 0; i < qk_ucis_state.count - 1; i++) { + uint8_t code = qk_ucis_state.codes[i]; + register_code(code); + unregister_code(code); + wait_ms(UNICODE_TYPE_DELAY); + } +} + +void register_ucis(const char *hex) { + for(int i = 0; hex[i]; i++) { + uint8_t kc = 0; + char c = hex[i]; + + switch (c) { + case '0': + kc = KC_0; + break; + case '1' ... '9': + kc = c - '1' + KC_1; + break; + case 'a' ... 'f': + kc = c - 'a' + KC_A; + break; + case 'A' ... 'F': + kc = c - 'A' + KC_A; + break; + } + + if (kc) { + register_code (kc); + unregister_code (kc); + wait_ms (UNICODE_TYPE_DELAY); + } + } +} + +bool process_ucis (uint16_t keycode, keyrecord_t *record) { + uint8_t i; + + if (!qk_ucis_state.in_progress) + return true; + + if (qk_ucis_state.count >= UCIS_MAX_SYMBOL_LENGTH && + !(keycode == KC_BSPC || keycode == KC_ESC || keycode == KC_SPC || keycode == KC_ENT)) { + return false; + } + + if (!record->event.pressed) + return true; + + qk_ucis_state.codes[qk_ucis_state.count] = keycode; + qk_ucis_state.count++; + + if (keycode == KC_BSPC) { + if (qk_ucis_state.count >= 2) { + qk_ucis_state.count -= 2; + return true; + } else { + qk_ucis_state.count--; + return false; + } + } + + if (keycode == KC_ENT || keycode == KC_SPC || keycode == KC_ESC) { + bool symbol_found = false; + + for (i = qk_ucis_state.count; i > 0; i--) { + register_code (KC_BSPC); + unregister_code (KC_BSPC); + wait_ms(UNICODE_TYPE_DELAY); + } + + if (keycode == KC_ESC) { + qk_ucis_state.in_progress = false; + return false; + } + + unicode_input_start(); + for (i = 0; ucis_symbol_table[i].symbol; i++) { + if (is_uni_seq (ucis_symbol_table[i].symbol)) { + symbol_found = true; + register_ucis(ucis_symbol_table[i].code + 2); + break; + } + } + if (!symbol_found) { + qk_ucis_symbol_fallback(); + } + unicode_input_finish(); + + qk_ucis_state.in_progress = false; + return false; + } + return true; +} diff --git a/quantum/process_keycode/process_ucis.h b/quantum/process_keycode/process_ucis.h new file mode 100644 index 0000000000..3f736a709f --- /dev/null +++ b/quantum/process_keycode/process_ucis.h @@ -0,0 +1,51 @@ +/* Copyright 2017 Jack Humbert + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef PROCESS_UCIS_H +#define PROCESS_UCIS_H + +#include "quantum.h" +#include "process_unicode_common.h" + +#ifndef UCIS_MAX_SYMBOL_LENGTH +#define UCIS_MAX_SYMBOL_LENGTH 32 +#endif + +typedef struct { + char *symbol; + char *code; +} qk_ucis_symbol_t; + +typedef struct { + uint8_t count; + uint16_t codes[UCIS_MAX_SYMBOL_LENGTH]; + bool in_progress:1; +} qk_ucis_state_t; + +extern qk_ucis_state_t qk_ucis_state; + +#define UCIS_TABLE(...) {__VA_ARGS__, {NULL, NULL}} +#define UCIS_SYM(name, code) {name, #code} + +extern const qk_ucis_symbol_t ucis_symbol_table[]; + +void qk_ucis_start(void); +void qk_ucis_start_user(void); +void qk_ucis_symbol_fallback (void); +void register_ucis(const char *hex); +bool process_ucis (uint16_t keycode, keyrecord_t *record); + +#endif diff --git a/quantum/process_keycode/process_unicode.c b/quantum/process_keycode/process_unicode.c index f42f255389..cecfaeee9b 100644 --- a/quantum/process_keycode/process_unicode.c +++ b/quantum/process_keycode/process_unicode.c @@ -1,4 +1,20 @@ +/* Copyright 2016 Jack Humbert + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ #include "process_unicode.h" +#include "action_util.h" static uint8_t input_mode; static uint8_t first_flag = 0; @@ -75,6 +91,7 @@ void register_hex(uint16_t hex) { } } + bool process_unicode(uint16_t keycode, keyrecord_t *record) { if (keycode > QK_UNICODE && record->event.pressed) { if (first_flag == 0) { @@ -89,182 +106,3 @@ bool process_unicode(uint16_t keycode, keyrecord_t *record) { return true; } -#ifdef UNICODEMAP_ENABLE -__attribute__((weak)) -const uint32_t PROGMEM unicode_map[] = { -}; - -void register_hex32(uint32_t hex) { - uint8_t onzerostart = 1; - for(int i = 7; i >= 0; i--) { - if (i <= 3) { - onzerostart = 0; - } - uint8_t digit = ((hex >> (i*4)) & 0xF); - if (digit == 0) { - if (onzerostart == 0) { - register_code(hex_to_keycode(digit)); - unregister_code(hex_to_keycode(digit)); - } - } else { - register_code(hex_to_keycode(digit)); - unregister_code(hex_to_keycode(digit)); - onzerostart = 0; - } - } -} - -__attribute__((weak)) -void unicode_map_input_error() {} - -bool process_unicode_map(uint16_t keycode, keyrecord_t *record) { - if ((keycode & QK_UNICODE_MAP) == QK_UNICODE_MAP && record->event.pressed) { - const uint32_t* map = unicode_map; - uint16_t index = keycode & 0x7FF; - uint32_t code = pgm_read_dword_far(&map[index]); - if ((code > 0xFFFF && input_mode == UC_OSX) || (code > 0xFFFFF && input_mode == UC_LNX)) { - // when character is out of range supported by the OS - unicode_map_input_error(); - } else { - unicode_input_start(); - register_hex32(code); - unicode_input_finish(); - } - } - return true; -} -#endif - -#ifdef UCIS_ENABLE -qk_ucis_state_t qk_ucis_state; - -void qk_ucis_start(void) { - qk_ucis_state.count = 0; - qk_ucis_state.in_progress = true; - - qk_ucis_start_user(); -} - -__attribute__((weak)) -void qk_ucis_start_user(void) { - unicode_input_start(); - register_hex(0x2328); - unicode_input_finish(); -} - -static bool is_uni_seq(char *seq) { - uint8_t i; - - for (i = 0; seq[i]; i++) { - uint16_t code; - if (('1' <= seq[i]) && (seq[i] <= '0')) - code = seq[i] - '1' + KC_1; - else - code = seq[i] - 'a' + KC_A; - - if (i > qk_ucis_state.count || qk_ucis_state.codes[i] != code) - return false; - } - - return (qk_ucis_state.codes[i] == KC_ENT || - qk_ucis_state.codes[i] == KC_SPC); -} - -__attribute__((weak)) -void qk_ucis_symbol_fallback (void) { - for (uint8_t i = 0; i < qk_ucis_state.count - 1; i++) { - uint8_t code = qk_ucis_state.codes[i]; - register_code(code); - unregister_code(code); - wait_ms(UNICODE_TYPE_DELAY); - } -} - -void register_ucis(const char *hex) { - for(int i = 0; hex[i]; i++) { - uint8_t kc = 0; - char c = hex[i]; - - switch (c) { - case '0': - kc = KC_0; - break; - case '1' ... '9': - kc = c - '1' + KC_1; - break; - case 'a' ... 'f': - kc = c - 'a' + KC_A; - break; - case 'A' ... 'F': - kc = c - 'A' + KC_A; - break; - } - - if (kc) { - register_code (kc); - unregister_code (kc); - wait_ms (UNICODE_TYPE_DELAY); - } - } -} - -bool process_ucis (uint16_t keycode, keyrecord_t *record) { - uint8_t i; - - if (!qk_ucis_state.in_progress) - return true; - - if (qk_ucis_state.count >= UCIS_MAX_SYMBOL_LENGTH && - !(keycode == KC_BSPC || keycode == KC_ESC || keycode == KC_SPC || keycode == KC_ENT)) { - return false; - } - - if (!record->event.pressed) - return true; - - qk_ucis_state.codes[qk_ucis_state.count] = keycode; - qk_ucis_state.count++; - - if (keycode == KC_BSPC) { - if (qk_ucis_state.count >= 2) { - qk_ucis_state.count -= 2; - return true; - } else { - qk_ucis_state.count--; - return false; - } - } - - if (keycode == KC_ENT || keycode == KC_SPC || keycode == KC_ESC) { - bool symbol_found = false; - - for (i = qk_ucis_state.count; i > 0; i--) { - register_code (KC_BSPC); - unregister_code (KC_BSPC); - wait_ms(UNICODE_TYPE_DELAY); - } - - if (keycode == KC_ESC) { - qk_ucis_state.in_progress = false; - return false; - } - - unicode_input_start(); - for (i = 0; ucis_symbol_table[i].symbol; i++) { - if (is_uni_seq (ucis_symbol_table[i].symbol)) { - symbol_found = true; - register_ucis(ucis_symbol_table[i].code + 2); - break; - } - } - if (!symbol_found) { - qk_ucis_symbol_fallback(); - } - unicode_input_finish(); - - qk_ucis_state.in_progress = false; - return false; - } - return true; -} -#endif diff --git a/quantum/process_keycode/process_unicode.h b/quantum/process_keycode/process_unicode.h index 065eeb5f6a..c525b74f03 100644 --- a/quantum/process_keycode/process_unicode.h +++ b/quantum/process_keycode/process_unicode.h @@ -1,166 +1,24 @@ +/* Copyright 2016 Jack Humbert + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ #ifndef PROCESS_UNICODE_H #define PROCESS_UNICODE_H #include "quantum.h" - -#define UC_OSX 0 // Mac OS X -#define UC_LNX 1 // Linux -#define UC_WIN 2 // Windows 'HexNumpad' -#define UC_BSD 3 // BSD (not implemented) -#define UC_WINC 4 // WinCompose https://github.com/samhocevar/wincompose - -#ifndef UNICODE_TYPE_DELAY -#define UNICODE_TYPE_DELAY 10 -#endif - -void set_unicode_input_mode(uint8_t os_target); -uint8_t get_unicode_input_mode(void); -void unicode_input_start(void); -void unicode_input_finish(void); -void register_hex(uint16_t hex); +#include "process_unicode_common.h" bool process_unicode(uint16_t keycode, keyrecord_t *record); -#ifdef UNICODEMAP_ENABLE -bool process_unicode_map(uint16_t keycode, keyrecord_t *record); -#endif - -#ifdef UCIS_ENABLE -#ifndef UCIS_MAX_SYMBOL_LENGTH -#define UCIS_MAX_SYMBOL_LENGTH 32 -#endif - -typedef struct { - char *symbol; - char *code; -} qk_ucis_symbol_t; - -typedef struct { - uint8_t count; - uint16_t codes[UCIS_MAX_SYMBOL_LENGTH]; - bool in_progress:1; -} qk_ucis_state_t; - -extern qk_ucis_state_t qk_ucis_state; - -#define UCIS_TABLE(...) {__VA_ARGS__, {NULL, NULL}} -#define UCIS_SYM(name, code) {name, #code} - -extern const qk_ucis_symbol_t ucis_symbol_table[]; - -void qk_ucis_start(void); -void qk_ucis_start_user(void); -void qk_ucis_symbol_fallback (void); -void register_ucis(const char *hex); -bool process_ucis (uint16_t keycode, keyrecord_t *record); - -#endif - -#define UC_BSPC UC(0x0008) - -#define UC_SPC UC(0x0020) - -#define UC_EXLM UC(0x0021) -#define UC_DQUT UC(0x0022) -#define UC_HASH UC(0x0023) -#define UC_DLR UC(0x0024) -#define UC_PERC UC(0x0025) -#define UC_AMPR UC(0x0026) -#define UC_QUOT UC(0x0027) -#define UC_LPRN UC(0x0028) -#define UC_RPRN UC(0x0029) -#define UC_ASTR UC(0x002A) -#define UC_PLUS UC(0x002B) -#define UC_COMM UC(0x002C) -#define UC_DASH UC(0x002D) -#define UC_DOT UC(0x002E) -#define UC_SLSH UC(0x002F) - -#define UC_0 UC(0x0030) -#define UC_1 UC(0x0031) -#define UC_2 UC(0x0032) -#define UC_3 UC(0x0033) -#define UC_4 UC(0x0034) -#define UC_5 UC(0x0035) -#define UC_6 UC(0x0036) -#define UC_7 UC(0x0037) -#define UC_8 UC(0x0038) -#define UC_9 UC(0x0039) - -#define UC_COLN UC(0x003A) -#define UC_SCLN UC(0x003B) -#define UC_LT UC(0x003C) -#define UC_EQL UC(0x003D) -#define UC_GT UC(0x003E) -#define UC_QUES UC(0x003F) -#define UC_AT UC(0x0040) - -#define UC_A UC(0x0041) -#define UC_B UC(0x0042) -#define UC_C UC(0x0043) -#define UC_D UC(0x0044) -#define UC_E UC(0x0045) -#define UC_F UC(0x0046) -#define UC_G UC(0x0047) -#define UC_H UC(0x0048) -#define UC_I UC(0x0049) -#define UC_J UC(0x004A) -#define UC_K UC(0x004B) -#define UC_L UC(0x004C) -#define UC_M UC(0x004D) -#define UC_N UC(0x004E) -#define UC_O UC(0x004F) -#define UC_P UC(0x0050) -#define UC_Q UC(0x0051) -#define UC_R UC(0x0052) -#define UC_S UC(0x0053) -#define UC_T UC(0x0054) -#define UC_U UC(0x0055) -#define UC_V UC(0x0056) -#define UC_W UC(0x0057) -#define UC_X UC(0x0058) -#define UC_Y UC(0x0059) -#define UC_Z UC(0x005A) - -#define UC_LBRC UC(0x005B) -#define UC_BSLS UC(0x005C) -#define UC_RBRC UC(0x005D) -#define UC_CIRM UC(0x005E) -#define UC_UNDR UC(0x005F) - -#define UC_GRV UC(0x0060) - -#define UC_a UC(0x0061) -#define UC_b UC(0x0062) -#define UC_c UC(0x0063) -#define UC_d UC(0x0064) -#define UC_e UC(0x0065) -#define UC_f UC(0x0066) -#define UC_g UC(0x0067) -#define UC_h UC(0x0068) -#define UC_i UC(0x0069) -#define UC_j UC(0x006A) -#define UC_k UC(0x006B) -#define UC_l UC(0x006C) -#define UC_m UC(0x006D) -#define UC_n UC(0x006E) -#define UC_o UC(0x006F) -#define UC_p UC(0x0070) -#define UC_q UC(0x0071) -#define UC_r UC(0x0072) -#define UC_s UC(0x0073) -#define UC_t UC(0x0074) -#define UC_u UC(0x0075) -#define UC_v UC(0x0076) -#define UC_w UC(0x0077) -#define UC_x UC(0x0078) -#define UC_y UC(0x0079) -#define UC_z UC(0x007A) - -#define UC_LCBR UC(0x007B) -#define UC_PIPE UC(0x007C) -#define UC_RCBR UC(0x007D) -#define UC_TILD UC(0x007E) -#define UC_DEL UC(0x007F) - #endif diff --git a/quantum/process_keycode/process_unicode_common.c b/quantum/process_keycode/process_unicode_common.c new file mode 100644 index 0000000000..6012b4f07e --- /dev/null +++ b/quantum/process_keycode/process_unicode_common.c @@ -0,0 +1,101 @@ +/* Copyright 2017 Jack Humbert + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "process_unicode_common.h" + +uint8_t mods; + +void set_unicode_input_mode(uint8_t os_target) +{ + input_mode = os_target; +} + +uint8_t get_unicode_input_mode(void) { + return input_mode; +} + +__attribute__((weak)) +void unicode_input_start (void) { + // save current mods + mods = keyboard_report->mods; + + // unregister all mods to start from clean state + if (mods & MOD_BIT(KC_LSFT)) unregister_code(KC_LSFT); + if (mods & MOD_BIT(KC_RSFT)) unregister_code(KC_RSFT); + if (mods & MOD_BIT(KC_LCTL)) unregister_code(KC_LCTL); + if (mods & MOD_BIT(KC_RCTL)) unregister_code(KC_RCTL); + if (mods & MOD_BIT(KC_LALT)) unregister_code(KC_LALT); + if (mods & MOD_BIT(KC_RALT)) unregister_code(KC_RALT); + if (mods & MOD_BIT(KC_LGUI)) unregister_code(KC_LGUI); + if (mods & MOD_BIT(KC_RGUI)) unregister_code(KC_RGUI); + + switch(input_mode) { + case UC_OSX: + register_code(KC_LALT); + break; + case UC_LNX: + register_code(KC_LCTL); + register_code(KC_LSFT); + register_code(KC_U); + unregister_code(KC_U); + unregister_code(KC_LSFT); + unregister_code(KC_LCTL); + break; + case UC_WIN: + register_code(KC_LALT); + register_code(KC_PPLS); + unregister_code(KC_PPLS); + break; + case UC_WINC: + register_code(KC_RALT); + unregister_code(KC_RALT); + register_code(KC_U); + unregister_code(KC_U); + } + wait_ms(UNICODE_TYPE_DELAY); +} + +__attribute__((weak)) +void unicode_input_finish (void) { + switch(input_mode) { + case UC_OSX: + case UC_WIN: + unregister_code(KC_LALT); + break; + case UC_LNX: + register_code(KC_SPC); + unregister_code(KC_SPC); + break; + } + + // reregister previously set mods + if (mods & MOD_BIT(KC_LSFT)) register_code(KC_LSFT); + if (mods & MOD_BIT(KC_RSFT)) register_code(KC_RSFT); + if (mods & MOD_BIT(KC_LCTL)) register_code(KC_LCTL); + if (mods & MOD_BIT(KC_RCTL)) register_code(KC_RCTL); + if (mods & MOD_BIT(KC_LALT)) register_code(KC_LALT); + if (mods & MOD_BIT(KC_RALT)) register_code(KC_RALT); + if (mods & MOD_BIT(KC_LGUI)) register_code(KC_LGUI); + if (mods & MOD_BIT(KC_RGUI)) register_code(KC_RGUI); +} + +void register_hex(uint16_t hex) { + for(int i = 3; i >= 0; i--) { + uint8_t digit = ((hex >> (i*4)) & 0xF); + register_code(hex_to_keycode(digit)); + unregister_code(hex_to_keycode(digit)); + } +} diff --git a/quantum/process_keycode/process_unicode_common.h b/quantum/process_keycode/process_unicode_common.h new file mode 100644 index 0000000000..f5be1da5cb --- /dev/null +++ b/quantum/process_keycode/process_unicode_common.h @@ -0,0 +1,148 @@ +/* Copyright 2017 Jack Humbert + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef PROCESS_UNICODE_COMMON_H +#define PROCESS_UNICODE_COMMON_H + +#include "quantum.h" + +#ifndef UNICODE_TYPE_DELAY +#define UNICODE_TYPE_DELAY 10 +#endif + +__attribute__ ((unused)) +static uint8_t input_mode; + +void set_unicode_input_mode(uint8_t os_target); +uint8_t get_unicode_input_mode(void); +void unicode_input_start(void); +void unicode_input_finish(void); +void register_hex(uint16_t hex); + +#define UC_OSX 0 // Mac OS X +#define UC_LNX 1 // Linux +#define UC_WIN 2 // Windows 'HexNumpad' +#define UC_BSD 3 // BSD (not implemented) +#define UC_WINC 4 // WinCompose https://github.com/samhocevar/wincompose + +#define UC_BSPC UC(0x0008) + +#define UC_SPC UC(0x0020) + +#define UC_EXLM UC(0x0021) +#define UC_DQUT UC(0x0022) +#define UC_HASH UC(0x0023) +#define UC_DLR UC(0x0024) +#define UC_PERC UC(0x0025) +#define UC_AMPR UC(0x0026) +#define UC_QUOT UC(0x0027) +#define UC_LPRN UC(0x0028) +#define UC_RPRN UC(0x0029) +#define UC_ASTR UC(0x002A) +#define UC_PLUS UC(0x002B) +#define UC_COMM UC(0x002C) +#define UC_DASH UC(0x002D) +#define UC_DOT UC(0x002E) +#define UC_SLSH UC(0x002F) + +#define UC_0 UC(0x0030) +#define UC_1 UC(0x0031) +#define UC_2 UC(0x0032) +#define UC_3 UC(0x0033) +#define UC_4 UC(0x0034) +#define UC_5 UC(0x0035) +#define UC_6 UC(0x0036) +#define UC_7 UC(0x0037) +#define UC_8 UC(0x0038) +#define UC_9 UC(0x0039) + +#define UC_COLN UC(0x003A) +#define UC_SCLN UC(0x003B) +#define UC_LT UC(0x003C) +#define UC_EQL UC(0x003D) +#define UC_GT UC(0x003E) +#define UC_QUES UC(0x003F) +#define UC_AT UC(0x0040) + +#define UC_A UC(0x0041) +#define UC_B UC(0x0042) +#define UC_C UC(0x0043) +#define UC_D UC(0x0044) +#define UC_E UC(0x0045) +#define UC_F UC(0x0046) +#define UC_G UC(0x0047) +#define UC_H UC(0x0048) +#define UC_I UC(0x0049) +#define UC_J UC(0x004A) +#define UC_K UC(0x004B) +#define UC_L UC(0x004C) +#define UC_M UC(0x004D) +#define UC_N UC(0x004E) +#define UC_O UC(0x004F) +#define UC_P UC(0x0050) +#define UC_Q UC(0x0051) +#define UC_R UC(0x0052) +#define UC_S UC(0x0053) +#define UC_T UC(0x0054) +#define UC_U UC(0x0055) +#define UC_V UC(0x0056) +#define UC_W UC(0x0057) +#define UC_X UC(0x0058) +#define UC_Y UC(0x0059) +#define UC_Z UC(0x005A) + +#define UC_LBRC UC(0x005B) +#define UC_BSLS UC(0x005C) +#define UC_RBRC UC(0x005D) +#define UC_CIRM UC(0x005E) +#define UC_UNDR UC(0x005F) + +#define UC_GRV UC(0x0060) + +#define UC_a UC(0x0061) +#define UC_b UC(0x0062) +#define UC_c UC(0x0063) +#define UC_d UC(0x0064) +#define UC_e UC(0x0065) +#define UC_f UC(0x0066) +#define UC_g UC(0x0067) +#define UC_h UC(0x0068) +#define UC_i UC(0x0069) +#define UC_j UC(0x006A) +#define UC_k UC(0x006B) +#define UC_l UC(0x006C) +#define UC_m UC(0x006D) +#define UC_n UC(0x006E) +#define UC_o UC(0x006F) +#define UC_p UC(0x0070) +#define UC_q UC(0x0071) +#define UC_r UC(0x0072) +#define UC_s UC(0x0073) +#define UC_t UC(0x0074) +#define UC_u UC(0x0075) +#define UC_v UC(0x0076) +#define UC_w UC(0x0077) +#define UC_x UC(0x0078) +#define UC_y UC(0x0079) +#define UC_z UC(0x007A) + +#define UC_LCBR UC(0x007B) +#define UC_PIPE UC(0x007C) +#define UC_RCBR UC(0x007D) +#define UC_TILD UC(0x007E) +#define UC_DEL UC(0x007F) + +#endif diff --git a/quantum/process_keycode/process_unicodemap.c b/quantum/process_keycode/process_unicodemap.c new file mode 100644 index 0000000000..0227fbdd7b --- /dev/null +++ b/quantum/process_keycode/process_unicodemap.c @@ -0,0 +1,72 @@ +/* Copyright 2017 Jack Humbert + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "process_unicodemap.h" +#include "process_unicode_common.h" + +__attribute__((weak)) +const uint32_t PROGMEM unicode_map[] = { +}; + +void register_hex32(uint32_t hex) { + bool onzerostart = true; + for(int i = 7; i >= 0; i--) { + if (i <= 3) { + onzerostart = false; + } + uint8_t digit = ((hex >> (i*4)) & 0xF); + if (digit == 0) { + if (!onzerostart) { + register_code(hex_to_keycode(digit)); + unregister_code(hex_to_keycode(digit)); + } + } else { + register_code(hex_to_keycode(digit)); + unregister_code(hex_to_keycode(digit)); + onzerostart = false; + } + } +} + +__attribute__((weak)) +void unicode_map_input_error() {} + +bool process_unicode_map(uint16_t keycode, keyrecord_t *record) { + uint8_t input_mode = get_unicode_input_mode(); + if ((keycode & QK_UNICODE_MAP) == QK_UNICODE_MAP && record->event.pressed) { + const uint32_t* map = unicode_map; + uint16_t index = keycode - QK_UNICODE_MAP; + uint32_t code = pgm_read_dword_far(&map[index]); + if (code > 0xFFFF && code <= 0x10ffff && input_mode == UC_OSX) { + // Convert to UTF-16 surrogate pair + code -= 0x10000; + uint32_t lo = code & 0x3ff; + uint32_t hi = (code & 0xffc00) >> 10; + unicode_input_start(); + register_hex32(hi + 0xd800); + register_hex32(lo + 0xdc00); + unicode_input_finish(); + } else if ((code > 0x10ffff && input_mode == UC_OSX) || (code > 0xFFFFF && input_mode == UC_LNX)) { + // when character is out of range supported by the OS + unicode_map_input_error(); + } else { + unicode_input_start(); + register_hex32(code); + unicode_input_finish(); + } + } + return true; +} diff --git a/quantum/process_keycode/process_unicodemap.h b/quantum/process_keycode/process_unicodemap.h new file mode 100644 index 0000000000..929c88c0b6 --- /dev/null +++ b/quantum/process_keycode/process_unicodemap.h @@ -0,0 +1,25 @@ +/* Copyright 2017 Jack Humbert + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef PROCESS_UNICODEMAP_H +#define PROCESS_UNICODEMAP_H + +#include "quantum.h" +#include "process_unicode_common.h" + +void unicode_map_input_error(void); +bool process_unicode_map(uint16_t keycode, keyrecord_t *record); +#endif |