Merge remote-tracking branch 'qmk 0.17.0' into firmware21

This commit is contained in:
Drashna Jael're
2022-05-29 15:38:33 -07:00
337 changed files with 14741 additions and 2516 deletions

View File

@@ -182,12 +182,7 @@ static bool autoshift_press(uint16_t keycode, uint16_t now, keyrecord_t *record)
# endif
) &&
# endif
TIMER_DIFF_16(now, autoshift_time) <
# ifdef TAPPING_TERM_PER_KEY
get_tapping_term(autoshift_lastkey, record)
# else
TAPPING_TERM
# endif
TIMER_DIFF_16(now, autoshift_time) < GET_TAPPING_TERM(autoshift_lastkey, record)
) {
// clang-format on
// Allow a tap-then-hold for keyrepeat.

View File

@@ -0,0 +1,163 @@
// Copyright 2021-2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "process_caps_word.h"
bool process_caps_word(uint16_t keycode, keyrecord_t* record) {
if (keycode == CAPSWRD) { // Pressing CAPSWRD toggles Caps Word.
if (record->event.pressed) {
caps_word_toggle();
}
return false;
}
#ifndef NO_ACTION_ONESHOT
const uint8_t mods = get_mods() | get_oneshot_mods();
#else
const uint8_t mods = get_mods();
#endif // NO_ACTION_ONESHOT
if (!is_caps_word_on()) {
// The following optionally turns on Caps Word by holding left and
// right shifts or by double tapping left shift. This way Caps Word
// may be used without needing a dedicated key and also without
// needing combos or tap dance.
#ifdef BOTH_SHIFTS_TURNS_ON_CAPS_WORD
// Many keyboards enable the Command feature by default, which also
// uses left+right shift. It can be configured to use a different
// key combination by defining IS_COMMAND(). We make a non-fatal
// warning if Command is enabled but IS_COMMAND() is *not* defined.
# if defined(COMMAND_ENABLE) && !defined(IS_COMMAND)
# pragma message "BOTH_SHIFTS_TURNS_ON_CAPS_WORD and Command should not be enabled at the same time, since both use the Left Shift + Right Shift key combination. Please disable Command, or ensure that `IS_COMMAND` is not set to (get_mods() == MOD_MASK_SHIFT)."
# else
if (mods == MOD_MASK_SHIFT
# ifdef COMMAND_ENABLE
// Don't activate Caps Word at the same time as Command.
&& !(IS_COMMAND())
# endif // COMMAND_ENABLE
) {
caps_word_on();
}
# endif // defined(COMMAND_ENABLE) && !defined(IS_COMMAND)
#endif // BOTH_SHIFTS_TURNS_ON_CAPS_WORD
#ifdef DOUBLE_TAP_SHIFT_TURNS_ON_CAPS_WORD
// Double tapping left shift turns on Caps Word.
//
// NOTE: This works with KC_LSFT and one-shot left shift. It
// wouldn't make sense with mod-tap or Space Cadet shift since
// double tapping would of course trigger the tapping action.
if (record->event.pressed) {
static bool tapped = false;
static uint16_t timer = 0;
if (keycode == KC_LSFT || keycode == OSM(MOD_LSFT)) {
if (tapped && !timer_expired(record->event.time, timer)) {
// Left shift was double tapped, activate Caps Word.
caps_word_on();
}
tapped = true;
timer = record->event.time + GET_TAPPING_TERM(keycode, record);
} else {
tapped = false; // Reset when any other key is pressed.
}
}
#endif // DOUBLE_TAP_SHIFT_TURNS_ON_CAPS_WORD
return true;
}
#if CAPS_WORD_IDLE_TIMEOUT > 0
caps_word_reset_idle_timer();
#endif // CAPS_WORD_IDLE_TIMEOUT > 0
// From here on, we only take action on press events.
if (!record->event.pressed) {
return true;
}
if (!(mods & ~(MOD_MASK_SHIFT | MOD_BIT(KC_RALT)))) {
switch (keycode) {
// Ignore MO, TO, TG, TT, and OSL layer switch keys.
case QK_MOMENTARY ... QK_MOMENTARY_MAX:
case QK_TO ... QK_TO_MAX:
case QK_TOGGLE_LAYER ... QK_TOGGLE_LAYER_MAX:
case QK_LAYER_TAP_TOGGLE ... QK_LAYER_TAP_TOGGLE_MAX:
case QK_ONE_SHOT_LAYER ... QK_ONE_SHOT_LAYER_MAX:
// Ignore AltGr.
case KC_RALT:
case OSM(MOD_RALT):
return true;
#ifndef NO_ACTION_TAPPING
case QK_MOD_TAP ... QK_MOD_TAP_MAX:
if (record->tap.count == 0) {
// Deactivate if a mod becomes active through holding
// a mod-tap key.
caps_word_off();
return true;
}
keycode &= 0xff;
break;
# ifndef NO_ACTION_LAYER
case QK_LAYER_TAP ... QK_LAYER_TAP_MAX:
# endif // NO_ACTION_LAYER
if (record->tap.count == 0) {
return true;
}
keycode &= 0xff;
break;
#endif // NO_ACTION_TAPPING
#ifdef SWAP_HANDS_ENABLE
case QK_SWAP_HANDS ... QK_SWAP_HANDS_MAX:
if (keycode > 0x56F0 || record->tap.count == 0) {
return true;
}
keycode &= 0xff;
break;
#endif // SWAP_HANDS_ENABLE
}
clear_weak_mods();
if (caps_word_press_user(keycode)) {
send_keyboard_report();
return true;
}
}
caps_word_off();
return true;
}
__attribute__((weak)) bool caps_word_press_user(uint16_t keycode) {
switch (keycode) {
// Keycodes that continue Caps Word, with shift applied.
case KC_A ... KC_Z:
case KC_MINS:
add_weak_mods(MOD_BIT(KC_LSFT)); // Apply shift to next key.
return true;
// Keycodes that continue Caps Word, without shifting.
case KC_1 ... KC_0:
case KC_BSPC:
case KC_DEL:
case KC_UNDS:
return true;
default:
return false; // Deactivate Caps Word.
}
}

View File

@@ -0,0 +1,37 @@
// Copyright 2021-2022 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#pragma once
#include "quantum.h"
#include "caps_word.h"
/**
* @brief Process handler for Caps Word feature.
*
* @param keycode Keycode registered by matrix press, per keymap
* @param record keyrecord_t structure
* @return true Continue processing keycodes, and send to host
* @return false Stop processing keycodes, and don't send to host
*/
bool process_caps_word(uint16_t keycode, keyrecord_t* record);
/**
* @brief Weak function for user-level Caps Word press modification.
*
* @param keycode Keycode registered by matrix press, per keymap
* @return true Continue Caps Word
* @return false Stop Caps Word
*/
bool caps_word_press_user(uint16_t keycode);

View File

@@ -88,8 +88,6 @@ static queued_combo_t combo_buffer[COMBO_BUFFER_LENGTH];
#define INCREMENT_MOD(i) i = (i + 1) % COMBO_BUFFER_LENGTH
#define COMBO_KEY_POS ((keypos_t){.col = 254, .row = 254})
#ifndef EXTRA_SHORT_COMBOS
/* flags are their own elements in combo_t struct. */
# define COMBO_ACTIVE(combo) (combo->active)
@@ -140,12 +138,7 @@ static queued_combo_t combo_buffer[COMBO_BUFFER_LENGTH];
static inline void release_combo(uint16_t combo_index, combo_t *combo) {
if (combo->keycode) {
keyrecord_t record = {
.event =
{
.key = COMBO_KEY_POS,
.time = timer_read() | 1,
.pressed = false,
},
.event = MAKE_KEYEVENT(KEYLOC_COMBO, KEYLOC_COMBO, false),
.keycode = combo->keycode,
};
#ifndef NO_ACTION_TAPPING
@@ -325,7 +318,7 @@ void apply_combo(uint16_t combo_index, combo_t *combo) {
if (ALL_COMBO_KEYS_ARE_DOWN(state, key_count)) {
// this in the end executes the combo when the key_buffer is dumped.
record->keycode = combo->keycode;
record->event.key = COMBO_KEY_POS;
record->event.key = MAKE_KEYPOS(KEYLOC_COMBO, KEYLOC_COMBO);
qrecord->combo_index = combo_index;
ACTIVATE_COMBO(combo);

View File

@@ -6,41 +6,25 @@
#include <string.h>
#include <math.h>
bool process_joystick_buttons(uint16_t keycode, keyrecord_t *record);
bool process_joystick(uint16_t keycode, keyrecord_t *record) {
if (process_joystick_buttons(keycode, record) && (joystick_status.status & JS_UPDATED) > 0) {
send_joystick_packet(&joystick_status);
joystick_status.status &= ~JS_UPDATED;
switch (keycode) {
case JS_BUTTON0 ... JS_BUTTON_MAX:
if (record->event.pressed) {
register_joystick_button(keycode - JS_BUTTON0);
} else {
unregister_joystick_button(keycode - JS_BUTTON0);
}
return false;
}
return true;
}
__attribute__((weak)) void joystick_task(void) {
if (process_joystick_analogread() && (joystick_status.status & JS_UPDATED)) {
send_joystick_packet(&joystick_status);
joystick_status.status &= ~JS_UPDATED;
if (process_joystick_analogread()) {
joystick_flush();
}
}
bool process_joystick_buttons(uint16_t keycode, keyrecord_t *record) {
if (keycode < JS_BUTTON0 || keycode > JS_BUTTON_MAX) {
return true;
} else {
uint8_t button_idx = (keycode - JS_BUTTON0);
if (record->event.pressed) {
joystick_status.buttons[button_idx / 8] |= 1 << (button_idx % 8);
} else {
joystick_status.buttons[button_idx / 8] &= ~(1 << (button_idx % 8));
}
joystick_status.status |= JS_UPDATED;
}
return true;
}
uint16_t savePinState(pin_t pin) {
#ifdef __AVR__
uint8_t pinNumber = pin & 0xF;

View File

@@ -0,0 +1,45 @@
// Copyright 2022 QMK
// SPDX-License-Identifier: GPL-2.0-or-later
#include "secure.h"
#include "process_secure.h"
#include "quantum_keycodes.h"
bool preprocess_secure(uint16_t keycode, keyrecord_t *record) {
if (secure_is_unlocking()) {
// !pressed will trigger on any already held keys (such as layer keys),
// and cause the request secure check to prematurely fail.
if (record->event.pressed) {
secure_keypress_event(record->event.key.row, record->event.key.col);
}
// Normal keypresses should be disabled until the sequence is completed
return false;
}
return true;
}
bool process_secure(uint16_t keycode, keyrecord_t *record) {
#ifndef SECURE_DISABLE_KEYCODES
if (!record->event.pressed) {
if (keycode == SECURE_LOCK) {
secure_lock();
return false;
}
if (keycode == SECURE_UNLOCK) {
secure_unlock();
return false;
}
if (keycode == SECURE_TOGGLE) {
secure_is_locked() ? secure_unlock() : secure_lock();
return false;
}
if (keycode == SECURE_REQUEST) {
secure_request_unlock();
return false;
}
}
#endif
return true;
}

View File

@@ -0,0 +1,15 @@
// Copyright 2022 QMK
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <stdbool.h>
#include "action.h"
/** \brief Intercept keycodes and detect unlock sequences
*/
bool preprocess_secure(uint16_t keycode, keyrecord_t *record);
/** \brief Handle any secure specific keycodes
*/
bool process_secure(uint16_t keycode, keyrecord_t *record);

View File

@@ -93,12 +93,7 @@ void perform_space_cadet(keyrecord_t *record, uint16_t sc_keycode, uint8_t holdM
register_mods(MOD_BIT(holdMod));
}
} else {
#ifdef TAPPING_TERM_PER_KEY
if (sc_last == holdMod && timer_elapsed(sc_timer) < get_tapping_term(sc_keycode, record))
#else
if (sc_last == holdMod && timer_elapsed(sc_timer) < TAPPING_TERM)
#endif
{
if (sc_last == holdMod && timer_elapsed(sc_timer) < GET_TAPPING_TERM(sc_keycode, record)) {
if (holdMod != tapMod) {
if (IS_MOD(holdMod)) {
unregister_mods(MOD_BIT(holdMod));

View File

@@ -174,11 +174,7 @@ void tap_dance_task() {
if (action->custom_tapping_term > 0) {
tap_user_defined = action->custom_tapping_term;
} else {
#ifdef TAPPING_TERM_PER_KEY
tap_user_defined = get_tapping_term(action->state.keycode, &(keyrecord_t){});
#else
tap_user_defined = TAPPING_TERM;
#endif
tap_user_defined = GET_TAPPING_TERM(action->state.keycode, &(keyrecord_t){});
}
if (action->state.count && timer_elapsed(action->state.timer) > tap_user_defined) {
process_tap_dance_action_on_dance_finished(action);

View File

@@ -16,8 +16,7 @@
#include "process_unicode_common.h"
#include "eeprom.h"
#include <ctype.h>
#include <string.h>
#include "utf8.h"
unicode_config_t unicode_config;
uint8_t unicode_saved_mods;
@@ -231,66 +230,6 @@ void register_unicode(uint32_t code_point) {
unicode_input_finish();
}
// clang-format off
void send_unicode_hex_string(const char *str) {
if (!str) {
return;
}
while (*str) {
// Find the next code point (token) in the string
for (; *str == ' '; str++); // Skip leading spaces
size_t n = strcspn(str, " "); // Length of the current token
char code_point[n+1];
strncpy(code_point, str, n); // Copy token into buffer
code_point[n] = '\0'; // Make sure it's null-terminated
// Normalize the code point: make all hex digits lowercase
for (char *p = code_point; *p; p++) {
*p = tolower((unsigned char)*p);
}
// Send the code point as a Unicode input string
unicode_input_start();
send_string(code_point);
unicode_input_finish();
str += n; // Move to the first ' ' (or '\0') after the current token
}
}
// clang-format on
// Borrowed from https://nullprogram.com/blog/2017/10/06/
static const char *decode_utf8(const char *str, int32_t *code_point) {
const char *next;
if (str[0] < 0x80) { // U+0000-007F
*code_point = str[0];
next = str + 1;
} else if ((str[0] & 0xE0) == 0xC0) { // U+0080-07FF
*code_point = ((int32_t)(str[0] & 0x1F) << 6) | ((int32_t)(str[1] & 0x3F) << 0);
next = str + 2;
} else if ((str[0] & 0xF0) == 0xE0) { // U+0800-FFFF
*code_point = ((int32_t)(str[0] & 0x0F) << 12) | ((int32_t)(str[1] & 0x3F) << 6) | ((int32_t)(str[2] & 0x3F) << 0);
next = str + 3;
} else if ((str[0] & 0xF8) == 0xF0 && (str[0] <= 0xF4)) { // U+10000-10FFFF
*code_point = ((int32_t)(str[0] & 0x07) << 18) | ((int32_t)(str[1] & 0x3F) << 12) | ((int32_t)(str[2] & 0x3F) << 6) | ((int32_t)(str[3] & 0x3F) << 0);
next = str + 4;
} else {
*code_point = -1;
next = str + 1;
}
// part of a UTF-16 surrogate pair - invalid
if (*code_point >= 0xD800 && *code_point <= 0xDFFF) {
*code_point = -1;
}
return next;
}
void send_unicode_string(const char *str) {
if (!str) {
return;

View File

@@ -90,7 +90,6 @@ void register_hex(uint16_t hex);
void register_hex32(uint32_t hex);
void register_unicode(uint32_t code_point);
void send_unicode_hex_string(const char *str);
void send_unicode_string(const char *str);
bool process_unicode_common(uint16_t keycode, keyrecord_t *record);