summary refs log tree commit diff
path: root/quantum/process_keycode
diff options
context:
space:
mode:
authorJames Young <18669334+noroadsleft@users.noreply.github.com>2020-11-28 12:02:18 -0800
committerGitHub <noreply@github.com>2020-11-28 12:02:18 -0800
commitc66df1664497546f32662409778731143e45a552 (patch)
treeda73a2d532a27685a31d932b3a44a707d4a3af81 /quantum/process_keycode
parent15385d4113414d42bd062c60c9de5df797d3157f (diff)
2020 November 28 Breaking Changes Update (#11053)
* Branch point for 2020 November 28 Breaking Change                                                

* Remove matrix_col_t to allow MATRIX_ROWS > 32 (#10183)                                           

* Add support for soft serial to ATmega32U2 (#10204)                                               

* Change MIDI velocity implementation to allow direct control of velocity value (#9940)            

* Add ability to build a subset of all keyboards based on platform.                                

* Actually use eeprom_driver_init().                                                               

* Make bootloader_jump weak for ChibiOS. (#10417)                                                  

* Joystick 16-bit support (#10439)                                                                 

* Per-encoder resolutions (#10259)                                                                 

* Share button state from mousekey to pointing_device (#10179)                                     

* Add hotfix for chibios keyboards not wake (#10088)                                               

* Add advanced/efficient RGB Matrix Indicators (#8564)                                             

* Naming change.                                                                                   

* Support for STM32 GPIOF,G,H,I,J,K (#10206)                                                       

* Add milc as a dependency and remove the installed milc (#10563)                                  

* ChibiOS upgrade: early init conversions (#10214)                                                 

* ChibiOS upgrade: configuration file migrator (#9952)                                             

* Haptic and solenoid cleanup (#9700)                                                              

* XD75 cleanup (#10524)                                                                            

* OLED display update interval support (#10388)                                                    

* Add definition based on currently-selected serial driver. (#10716)                               

* New feature: Retro Tapping per key (#10622)                                                      

* Allow for modification of output RGB values when using rgblight/rgb_matrix. (#10638)             

* Add housekeeping task callbacks so that keyboards/keymaps are capable of executing code for each main loop iteration. (#10530)

* Rescale both ChibiOS and AVR backlighting.                                                       

* Reduce Helix keyboard build variation (#8669)                                                    

* Minor change to behavior allowing display updates to continue between task ticks (#10750)        

* Some GPIO manipulations in matrix.c change to atomic. (#10491)                                   

* qmk cformat (#10767)                                                                             

* [Keyboard] Update the Speedo firmware for v3.0 (#10657)                                          

* Maartenwut/Maarten namechange to evyd13/Evy (#10274)                                             

* [quantum] combine repeated lines of code (#10837)                                                

* Add step sequencer feature (#9703)                                                               

* aeboards/ext65 refactor (#10820)                                                                 

* Refactor xelus/dawn60 for Rev2 later (#10584)                                                    

* add DEBUG_MATRIX_SCAN_RATE_ENABLE to common_features.mk (#10824)                                 

* [Core] Added `add_oneshot_mods` & `del_oneshot_mods` (#10549)                                    

* update chibios os usb for the otg driver (#8893)                                                 

* Remove HD44780 References, Part 4 (#10735)                                                       

* [Keyboard] Add Valor FRL TKL (+refactor) (#10512)                                                

* Fix cursor position bug in oled_write_raw functions (#10800)                                     

* Fixup version.h writing when using SKIP_VERSION=yes (#10972)                                     

* Allow for certain code in the codebase assuming length of string. (#10974)                       

* Add AT90USB support for serial.c (#10706)                                                        

* Auto shift: support repeats and early registration (#9826)                                       

* Rename ledmatrix.h to match .c file (#7949)                                                      

* Split RGB_MATRIX_ENABLE into _ENABLE and _DRIVER (#10231)                                        

* Split LED_MATRIX_ENABLE into _ENABLE and _DRIVER (#10840)                                        

* Merge point for 2020 Nov 28 Breaking Change                                                      
Diffstat (limited to 'quantum/process_keycode')
-rw-r--r--quantum/process_keycode/process_auto_shift.c199
-rw-r--r--quantum/process_keycode/process_auto_shift.h1
-rw-r--r--quantum/process_keycode/process_joystick.c8
-rw-r--r--quantum/process_keycode/process_midi.c25
-rw-r--r--quantum/process_keycode/process_midi.h2
-rw-r--r--quantum/process_keycode/process_sequencer.c62
-rw-r--r--quantum/process_keycode/process_sequencer.h21
7 files changed, 256 insertions, 62 deletions
diff --git a/quantum/process_keycode/process_auto_shift.c b/quantum/process_keycode/process_auto_shift.c
index b1267922ce..a2d315408b 100644
--- a/quantum/process_keycode/process_auto_shift.c
+++ b/quantum/process_keycode/process_auto_shift.c
@@ -16,48 +16,149 @@
 
 #ifdef AUTO_SHIFT_ENABLE
 
+#    include <stdbool.h>
 #    include <stdio.h>
 
 #    include "process_auto_shift.h"
 
-static bool     autoshift_enabled = true;
 static uint16_t autoshift_time    = 0;
 static uint16_t autoshift_timeout = AUTO_SHIFT_TIMEOUT;
 static uint16_t autoshift_lastkey = KC_NO;
+static struct {
+    // Whether autoshift is enabled.
+    bool enabled : 1;
+    // Whether the last auto-shifted key was released after the timeout.  This
+    // is used to replicate the last key for a tap-then-hold.
+    bool lastshifted : 1;
+    // Whether an auto-shiftable key has been pressed but not processed.
+    bool in_progress : 1;
+    // Whether the auto-shifted keypress has been registered.
+    bool holding_shift : 1;
+} autoshift_flags = {true, false, false, false};
+
+/** \brief Record the press of an autoshiftable key
+ *
+ *  \return Whether the record should be further processed.
+ */
+static bool autoshift_press(uint16_t keycode, uint16_t now, keyrecord_t *record) {
+    if (!autoshift_flags.enabled) {
+        return true;
+    }
+
+#    ifndef AUTO_SHIFT_MODIFIERS
+    if (get_mods() & (~MOD_BIT(KC_LSFT))) {
+        return true;
+    }
+#    endif
+#    ifdef AUTO_SHIFT_REPEAT
+    const uint16_t elapsed = TIMER_DIFF_16(now, autoshift_time);
+#        ifndef AUTO_SHIFT_NO_AUTO_REPEAT
+    if (!autoshift_flags.lastshifted) {
+#        endif
+        if (elapsed < TAPPING_TERM && keycode == autoshift_lastkey) {
+            // Allow a tap-then-hold for keyrepeat.
+            if (!autoshift_flags.lastshifted) {
+                register_code(autoshift_lastkey);
+            } else {
+                // Simulate pressing the shift key.
+                add_weak_mods(MOD_BIT(KC_LSFT));
+                register_code(autoshift_lastkey);
+            }
+            return false;
+        }
+#        ifndef AUTO_SHIFT_NO_AUTO_REPEAT
+    }
+#        endif
+#    endif
 
-void autoshift_flush(void) {
-    if (autoshift_lastkey != KC_NO) {
-        uint16_t elapsed = timer_elapsed(autoshift_time);
+    // Record the keycode so we can simulate it later.
+    autoshift_lastkey           = keycode;
+    autoshift_time              = now;
+    autoshift_flags.in_progress = true;
 
-        if (elapsed > autoshift_timeout) {
-            tap_code16(LSFT(autoshift_lastkey));
+#    if !defined(NO_ACTION_ONESHOT) && !defined(NO_ACTION_TAPPING)
+    clear_oneshot_layer_state(ONESHOT_OTHER_KEY_PRESSED);
+#    endif
+    return false;
+}
+
+/** \brief Registers an autoshiftable key under the right conditions
+ *
+ * If the autoshift delay has elapsed, register a shift and the key.
+ *
+ * If the autoshift key is released before the delay has elapsed, register the
+ * key without a shift.
+ */
+static void autoshift_end(uint16_t keycode, uint16_t now, bool matrix_trigger) {
+    // Called on key down with KC_NO, auto-shifted key up, and timeout.
+    if (autoshift_flags.in_progress) {
+        // Process the auto-shiftable key.
+        autoshift_flags.in_progress = false;
+
+        // Time since the initial press was recorded.
+        const uint16_t elapsed = TIMER_DIFF_16(now, autoshift_time);
+        if (elapsed < autoshift_timeout) {
+            register_code(autoshift_lastkey);
+            autoshift_flags.lastshifted = false;
         } else {
-            tap_code(autoshift_lastkey);
+            // Simulate pressing the shift key.
+            add_weak_mods(MOD_BIT(KC_LSFT));
+            register_code(autoshift_lastkey);
+            autoshift_flags.lastshifted = true;
+#    if defined(AUTO_SHIFT_REPEAT) && !defined(AUTO_SHIFT_NO_AUTO_REPEAT)
+            if (matrix_trigger) {
+                // Prevents release.
+                return;
+            }
+#    endif
         }
 
-        autoshift_time    = 0;
-        autoshift_lastkey = KC_NO;
+#    if TAP_CODE_DELAY > 0
+        wait_ms(TAP_CODE_DELAY);
+#    endif
+        unregister_code(autoshift_lastkey);
+        del_weak_mods(MOD_BIT(KC_LSFT));
+    } else {
+        // Release after keyrepeat.
+        unregister_code(keycode);
+        if (keycode == autoshift_lastkey) {
+            // This will only fire when the key was the last auto-shiftable
+            // pressed. That prevents aaaaBBBB then releasing a from unshifting
+            // later Bs (if B wasn't auto-shiftable).
+            del_weak_mods(MOD_BIT(KC_LSFT));
+        }
     }
+    send_keyboard_report();  // del_weak_mods doesn't send one.
+    // Roll the autoshift_time forward for detecting tap-and-hold.
+    autoshift_time = now;
 }
 
-void autoshift_on(uint16_t keycode) {
-    autoshift_time    = timer_read();
-    autoshift_lastkey = keycode;
+/** \brief Simulates auto-shifted key releases when timeout is hit
+ *
+ *  Can be called from \c matrix_scan_user so that auto-shifted keys are sent
+ *  immediately after the timeout has expired, rather than waiting for the key
+ *  to be released.
+ */
+void autoshift_matrix_scan(void) {
+    if (autoshift_flags.in_progress) {
+        const uint16_t now     = timer_read();
+        const uint16_t elapsed = TIMER_DIFF_16(now, autoshift_time);
+        if (elapsed >= autoshift_timeout) {
+            autoshift_end(autoshift_lastkey, now, true);
+        }
+    }
 }
 
 void autoshift_toggle(void) {
-    if (autoshift_enabled) {
-        autoshift_enabled = false;
-        autoshift_flush();
-    } else {
-        autoshift_enabled = true;
-    }
+    autoshift_flags.enabled = !autoshift_flags.enabled;
+    del_weak_mods(MOD_BIT(KC_LSFT));
 }
 
-void autoshift_enable(void) { autoshift_enabled = true; }
+void autoshift_enable(void) { autoshift_flags.enabled = true; }
+
 void autoshift_disable(void) {
-    autoshift_enabled = false;
-    autoshift_flush();
+    autoshift_flags.enabled = false;
+    del_weak_mods(MOD_BIT(KC_LSFT));
 }
 
 #    ifndef AUTO_SHIFT_NO_SETUP
@@ -70,19 +171,30 @@ void autoshift_timer_report(void) {
 }
 #    endif
 
-bool get_autoshift_state(void) { return autoshift_enabled; }
+bool get_autoshift_state(void) { return autoshift_flags.enabled; }
 
 uint16_t get_autoshift_timeout(void) { return autoshift_timeout; }
 
 void set_autoshift_timeout(uint16_t timeout) { autoshift_timeout = timeout; }
 
 bool process_auto_shift(uint16_t keycode, keyrecord_t *record) {
+    // Note that record->event.time isn't reliable, see:
+    // https://github.com/qmk/qmk_firmware/pull/9826#issuecomment-733559550
+    const uint16_t now = timer_read();
+
     if (record->event.pressed) {
+        if (autoshift_flags.in_progress) {
+            // Evaluate previous key if there is one. Doing this elsewhere is
+            // more complicated and easier to break.
+            autoshift_end(KC_NO, now, false);
+        }
+        // For pressing another key while keyrepeating shifted autoshift.
+        del_weak_mods(MOD_BIT(KC_LSFT));
+
         switch (keycode) {
             case KC_ASTG:
                 autoshift_toggle();
                 return true;
-
             case KC_ASON:
                 autoshift_enable();
                 return true;
@@ -102,41 +214,28 @@ bool process_auto_shift(uint16_t keycode, keyrecord_t *record) {
                 autoshift_timer_report();
                 return true;
 #    endif
+        }
+    }
+
+    switch (keycode) {
 #    ifndef NO_AUTO_SHIFT_ALPHA
-            case KC_A ... KC_Z:
+        case KC_A ... KC_Z:
 #    endif
 #    ifndef NO_AUTO_SHIFT_NUMERIC
-            case KC_1 ... KC_0:
+        case KC_1 ... KC_0:
 #    endif
 #    ifndef NO_AUTO_SHIFT_SPECIAL
-            case KC_TAB:
-            case KC_MINUS ... KC_SLASH:
-            case KC_NONUS_BSLASH:
-#    endif
-                autoshift_flush();
-                if (!autoshift_enabled) return true;
-
-#    ifndef AUTO_SHIFT_MODIFIERS
-                if (get_mods()) {
-                    return true;
-                }
-#    endif
-                autoshift_on(keycode);
-
-                // We need some extra handling here for OSL edge cases
-#    if !defined(NO_ACTION_ONESHOT) && !defined(NO_ACTION_TAPPING)
-                clear_oneshot_layer_state(ONESHOT_OTHER_KEY_PRESSED);
+        case KC_TAB:
+        case KC_MINUS ... KC_SLASH:
+        case KC_NONUS_BSLASH:
 #    endif
+            if (record->event.pressed) {
+                return autoshift_press(keycode, now, record);
+            } else {
+                autoshift_end(keycode, now, false);
                 return false;
-
-            default:
-                autoshift_flush();
-                return true;
-        }
-    } else {
-        autoshift_flush();
+            }
     }
-
     return true;
 }
 
diff --git a/quantum/process_keycode/process_auto_shift.h b/quantum/process_keycode/process_auto_shift.h
index e86c4658e9..5b2718f11c 100644
--- a/quantum/process_keycode/process_auto_shift.h
+++ b/quantum/process_keycode/process_auto_shift.h
@@ -30,3 +30,4 @@ void     autoshift_toggle(void);
 bool     get_autoshift_state(void);
 uint16_t get_autoshift_timeout(void);
 void     set_autoshift_timeout(uint16_t timeout);
+void     autoshift_matrix_scan(void);
diff --git a/quantum/process_keycode/process_joystick.c b/quantum/process_keycode/process_joystick.c
index 5778a7434c..3ffaf42bf8 100644
--- a/quantum/process_keycode/process_joystick.c
+++ b/quantum/process_keycode/process_joystick.c
@@ -129,17 +129,17 @@ bool process_joystick_analogread_quantum() {
         // test the converted value against the lower range
         int32_t ref        = joystick_axes[axis_index].mid_digit;
         int32_t range      = joystick_axes[axis_index].min_digit;
-        int32_t ranged_val = ((axis_val - ref) * -127) / (range - ref);
+        int32_t ranged_val = ((axis_val - ref) * -JOYSTICK_RESOLUTION) / (range - ref);
 
         if (ranged_val > 0) {
             // the value is in the higher range
             range      = joystick_axes[axis_index].max_digit;
-            ranged_val = ((axis_val - ref) * 127) / (range - ref);
+            ranged_val = ((axis_val - ref) * JOYSTICK_RESOLUTION) / (range - ref);
         }
 
         // clamp the result in the valid range
-        ranged_val = ranged_val < -127 ? -127 : ranged_val;
-        ranged_val = ranged_val > 127 ? 127 : ranged_val;
+        ranged_val = ranged_val < -JOYSTICK_RESOLUTION ? -JOYSTICK_RESOLUTION : ranged_val;
+        ranged_val = ranged_val > JOYSTICK_RESOLUTION ? JOYSTICK_RESOLUTION : ranged_val;
 
         if (ranged_val != joystick_status.axes[axis_index]) {
             joystick_status.axes[axis_index] = ranged_val;
diff --git a/quantum/process_keycode/process_midi.c b/quantum/process_keycode/process_midi.c
index e525770144..8e2fb955e7 100644
--- a/quantum/process_keycode/process_midi.c
+++ b/quantum/process_keycode/process_midi.c
@@ -41,12 +41,12 @@ static int8_t   midi_modulation_step;
 static uint16_t midi_modulation_timer;
 midi_config_t   midi_config;
 
-inline uint8_t compute_velocity(uint8_t setting) { return (setting + 1) * (128 / (MIDI_VELOCITY_MAX - MIDI_VELOCITY_MIN + 1)); }
+inline uint8_t compute_velocity(uint8_t setting) { return setting * (128 / (MIDI_VELOCITY_MAX - MIDI_VELOCITY_MIN)); }
 
 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.velocity            = 127;
     midi_config.channel             = 0;
     midi_config.modulation_interval = 8;
 
@@ -66,7 +66,7 @@ bool process_midi(uint16_t keycode, keyrecord_t *record) {
         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);
+            uint8_t velocity = midi_config.velocity;
             if (record->event.pressed) {
                 if (tone_status[tone] == MIDI_INVALID_NOTE) {
                     uint8_t note = midi_compute_note(keycode);
@@ -124,19 +124,30 @@ bool process_midi(uint16_t keycode, keyrecord_t *record) {
             return false;
         case MIDI_VELOCITY_MIN ... MIDI_VELOCITY_MAX:
             if (record->event.pressed) {
-                midi_config.velocity = keycode - MIDI_VELOCITY_MIN;
+                midi_config.velocity = compute_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--;
+                if (midi_config.velocity == 127) {
+                    midi_config.velocity -= 10;
+                } else if (midi_config.velocity > 12) {
+                    midi_config.velocity -= 13;
+                } else {
+                    midi_config.velocity = 0;
+                }
+
                 dprintf("midi velocity %d\n", midi_config.velocity);
             }
             return false;
         case MI_VELU:
-            if (record->event.pressed) {
-                midi_config.velocity++;
+            if (record->event.pressed && midi_config.velocity < 127) {
+                if (midi_config.velocity < 115) {
+                    midi_config.velocity += 13;
+                } else {
+                    midi_config.velocity = 127;
+                }
                 dprintf("midi velocity %d\n", midi_config.velocity);
             }
             return false;
diff --git a/quantum/process_keycode/process_midi.h b/quantum/process_keycode/process_midi.h
index 0007b3ed25..ef5661dd4d 100644
--- a/quantum/process_keycode/process_midi.h
+++ b/quantum/process_keycode/process_midi.h
@@ -35,7 +35,7 @@ typedef union {
     struct {
         uint8_t octave : 4;
         int8_t  transpose : 4;
-        uint8_t velocity : 4;
+        uint8_t velocity : 7;
         uint8_t channel : 4;
         uint8_t modulation_interval : 4;
     };
diff --git a/quantum/process_keycode/process_sequencer.c b/quantum/process_keycode/process_sequencer.c
new file mode 100644
index 0000000000..334b4c0092
--- /dev/null
+++ b/quantum/process_keycode/process_sequencer.c
@@ -0,0 +1,62 @@
+/* Copyright 2020 Rodolphe Belouin
+ *
+ * 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_sequencer.h"
+
+bool process_sequencer(uint16_t keycode, keyrecord_t *record) {
+    if (record->event.pressed) {
+        switch (keycode) {
+            case SQ_ON:
+                sequencer_on();
+                return false;
+            case SQ_OFF:
+                sequencer_off();
+                return false;
+            case SQ_TOG:
+                sequencer_toggle();
+                return false;
+            case SQ_TMPD:
+                sequencer_decrease_tempo();
+                return false;
+            case SQ_TMPU:
+                sequencer_increase_tempo();
+                return false;
+            case SEQUENCER_RESOLUTION_MIN ... SEQUENCER_RESOLUTION_MAX:
+                sequencer_set_resolution(keycode - SEQUENCER_RESOLUTION_MIN);
+                return false;
+            case SQ_RESD:
+                sequencer_decrease_resolution();
+                return false;
+            case SQ_RESU:
+                sequencer_increase_resolution();
+                return false;
+            case SQ_SALL:
+                sequencer_set_all_steps_on();
+                return false;
+            case SQ_SCLR:
+                sequencer_set_all_steps_off();
+                return false;
+            case SEQUENCER_STEP_MIN ... SEQUENCER_STEP_MAX:
+                sequencer_toggle_step(keycode - SEQUENCER_STEP_MIN);
+                return false;
+            case SEQUENCER_TRACK_MIN ... SEQUENCER_TRACK_MAX:
+                sequencer_toggle_single_active_track(keycode - SEQUENCER_TRACK_MIN);
+                return false;
+        }
+    }
+
+    return true;
+}
diff --git a/quantum/process_keycode/process_sequencer.h b/quantum/process_keycode/process_sequencer.h
new file mode 100644
index 0000000000..2b85f24299
--- /dev/null
+++ b/quantum/process_keycode/process_sequencer.h
@@ -0,0 +1,21 @@
+/* Copyright 2020 Rodolphe Belouin
+ *
+ * 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/>.
+ */
+
+#pragma once
+
+#include "quantum.h"
+
+bool process_sequencer(uint16_t keycode, keyrecord_t *record);