Merge remote-tracking branch 'qmk 0.17.0' into firmware21
This commit is contained in:
@@ -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.
|
||||
|
||||
163
quantum/process_keycode/process_caps_word.c
Normal file
163
quantum/process_keycode/process_caps_word.c
Normal 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.
|
||||
}
|
||||
}
|
||||
37
quantum/process_keycode/process_caps_word.h
Normal file
37
quantum/process_keycode/process_caps_word.h
Normal 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);
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
45
quantum/process_keycode/process_secure.c
Normal file
45
quantum/process_keycode/process_secure.c
Normal 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;
|
||||
}
|
||||
15
quantum/process_keycode/process_secure.h
Normal file
15
quantum/process_keycode/process_secure.h
Normal 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);
|
||||
@@ -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));
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user