Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[New Feature] Custom Modified Values #2900

Closed
wants to merge 14 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions common_features.mk
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,10 @@ ifeq ($(strip $(LEADER_ENABLE)), yes)
OPT_DEFS += -DLEADER_ENABLE
endif

ifeq ($(strip $(CUSTOM_MODIFIED_VALUES_ENABLE)), yes)
OPT_DEFS += -DCUSTOM_MODIFIED_VALUES_ENABLE
endif

include $(DRIVER_PATH)/qwiic/qwiic.mk

QUANTUM_SRC:= \
Expand Down
444 changes: 444 additions & 0 deletions docs/feature_custom_modified_values.md

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions docs/features.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ QMK has a staggering number of features for building your keyboard. It can take
* [Bootmagic](feature_bootmagic.md) - Adjust the behavior of your keyboard using hotkeys.
* [Combos](feature_combo.md) - Custom actions for multiple key holds.
* [Command](feature_command.md) - Runtime version of bootmagic (Formerly known as "Magic").
* [Custom Modified Values](feature_custom_modified_values.md) - Customize the keycodes processed by the firmware depending on the modifiers state
* [Dynamic Macros](feature_dynamic_macros.md) - Record and playback macros from the keyboard itself.
* [Grave Escape](feature_grave_esc.md) - Lets you use a single key for Esc and Grave.
* [HD44780 LCD Display](feature_hd44780.md) - Support for LCD character displays using the HD44780 standard.
Expand Down
1 change: 1 addition & 0 deletions keyboards/ergodox_ez/keymaps/CMV_adya/config.h
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#define CUSTOM_MODIFIED_VALUES_ENABLE
303 changes: 303 additions & 0 deletions keyboards/ergodox_ez/keymaps/CMV_adya/keymap.c

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions keyboards/ergodox_ez/keymaps/CMV_adya/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
See the `docs/feature_custom_modified_values.md` file for more details on the feature this keymap is using (which allows you to **assign several keycodes for a single key**: the keycode returned to the firmware **depends on the state of the `Shifts` and `Right Alt` keys**).
28 changes: 28 additions & 0 deletions keyboards/ergodox_ez/keymaps/CMV_adya/rules.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
CUSTOM_MODIFIED_VALUES_ENABLE = yes


BOOTMAGIC_ENABLE = no
MOUSEKEY_ENABLE = yes
EXTRAKEY_ENABLE = yes
CONSOLE_ENABLE = no
COMMAND_ENABLE = no
SLEEP_LED_ENABLE = no
NKRO_ENABLE = no
BACKLIGHT_ENABLE = no
MIDI_ENABLE = no
UNICODE_ENABLE = yes
UNICODEMAP_ENABLE = no
BLUETOOTH_ENABLE = no
AUDIO_ENABLE = no
FAUXCLICKY_ENABLE = no
#VARIABLE_TRACE = no
API_SYSEX_ENABLE = no
KEY_LOCK_ENABLE = no

RGBLIGHT_ENABLE = no
TAP_DANCE_ENABLE = no
FORCE_NKRO = no
KEYLOGGER_ENABLE = no
UCIS_ENABLE = no
AUTOLOG_ENABLE = no
RGBLIGHT_ANIMATION= no
32 changes: 32 additions & 0 deletions keyboards/ergodox_ez/keymaps/CMV_adya/shortcut_utils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#ifndef _SHORTCUT_UTILS_H_
#define _SHORTCUT_UTILS_H_

#include <stdint.h>
#include <stdarg.h>
#include <quantum.h>

#define VA_ARRAY_UINT16_T(array, argc) va_list valist; \
int i; \
va_start(valist, argc); \
for(i = 0; i < argc; i++) { \
array[i] = va_arg(valist, uint16_t); \
} \
va_end(valist);

void shortcut_press(int argc_local, ...) {
uint16_t kcs[argc_local];
VA_ARRAY_UINT16_T(kcs, argc_local)
for(i = 0; i < argc_local; i++) {
register_code16(kcs[i]);
}
}

void shortcut_release(int argc_local, ...) {
uint16_t kcs[argc_local];
VA_ARRAY_UINT16_T(kcs, argc_local)
for(i = 0; i < argc_local; i++) {
unregister_code16(kcs[i]);
}
}

#endif
4 changes: 1 addition & 3 deletions keyboards/qwertyydox/rules.mk
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,7 @@ MIDI_ENABLE = no # MIDI controls
AUDIO_ENABLE = no # Audio output on port C6
UNICODE_ENABLE = no # Unicode
BLUETOOTH_ENABLE = no # Enable Bluetooth with the Adafruit EZ-Key HID
RGBLIGHT_ENABLE = no # Enable WS2812 RGB underlight.
SUBPROJECT_rev1 = yes
USE_I2C = yes # I2C is used between the sides
RGBLIGHT_ENABLE = no # Enable WS2812 RGB underlight.
# Do not enable SLEEP_LED_ENABLE. it uses the same timer as BACKLIGHT_ENABLE
SLEEP_LED_ENABLE = no # Breathing sleep LED during USB suspend

Expand Down
12 changes: 12 additions & 0 deletions quantum/custom_modified_values.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#ifndef _CUSTOM_MODIFIED_VALUES_H_
#define _CUSTOM_MODIFIED_VALUES_H_

#include <stdint.h>
#include <stdbool.h>
#include "action.h"
#include "action_util.h"

#define CMV(kc_default, kc_shifted, kc_altgred, kc_sftralt) set_cmv_buffer(kc_default, kc_shifted, kc_altgred, kc_sftralt)
bool set_cmv_buffer(uint16_t kc_default, uint16_t kc_shifted, uint16_t kc_altgred, uint16_t kc_sftralt);

#endif
50 changes: 50 additions & 0 deletions quantum/keymap_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "process_midi.h"
#endif

#ifdef CUSTOM_MODIFIED_VALUES_ENABLE
#include "custom_modified_values.h"
#endif

extern keymap_config_t keymap_config;

#include <inttypes.h>
Expand Down Expand Up @@ -204,12 +208,58 @@ void action_function(keyrecord_t *record, uint8_t id, uint8_t opt)
{
}

#ifdef CUSTOM_MODIFIED_VALUES_ENABLE
static uint16_t cmv_buffer[4] = {0,0,0,0};

bool set_cmv_buffer(uint16_t kc_default, uint16_t kc_shifted, uint16_t kc_altgred, uint16_t kc_sftralt) {
cmv_buffer[0] = kc_default;
cmv_buffer[1] = kc_shifted;
cmv_buffer[2] = kc_altgred;
cmv_buffer[3] = kc_sftralt;
return false;
}

__attribute__ ((weak))
bool keycodes_for_key(uint16_t default_kc, uint8_t layer, keypos_t key) {
return true;
}

static uint16_t* get_custom_modified_values_for_key(uint16_t default_kc, uint8_t layer, keypos_t key) {
if(keycodes_for_key(default_kc, layer, key)) {
set_cmv_buffer(default_kc, 0, 0, 0);
}
return cmv_buffer;
}

static uint8_t get_kcid(uint16_t* kcs) {
if(are_there_non_charmods()) return 0;
else if(are_there_shifts() && are_there_ralts() && kcs[3]) return 3;
else if(are_there_shifts() && kcs[1]) return 1;
else if(are_there_ralts() && kcs[2]) return 2;
return 0;
}

static uint16_t keymap_key_to_keycode_cmv(uint8_t layer, keypos_t key) {
uint8_t kcid = get_kcid(get_custom_modified_values_for_key(pgm_read_word(&keymaps[layer][key.row][key.col]), layer, key));
if (kcid) {
set_mods_blocker(true);
} else {
set_mods_blocker(false);
}
return cmv_buffer[kcid];
}
#endif

// translates key to keycode
__attribute__ ((weak))
uint16_t keymap_key_to_keycode(uint8_t layer, keypos_t key)
{
#if defined(CUSTOM_MODIFIED_VALUES_ENABLE)
return keymap_key_to_keycode_cmv(layer, key);
#else
// Read entire word (16bits)
return pgm_read_word(&keymaps[(layer)][(key.row)][(key.col)]);
#endif
}

// translates function id to action
Expand Down
2 changes: 1 addition & 1 deletion quantum/quantum.c
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ bool process_record_quantum(keyrecord_t *record) {
keypos_t key = record->event.key;
uint16_t keycode;

#if !defined(NO_ACTION_LAYER) && !defined(STRICT_LAYER_RELEASE)
#if !defined(NO_ACTION_LAYER) && defined(PREVENT_STUCK_MODIFIERS)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs to be reverted. There is no more PSM, as it is now the default behavior.

Suggested change
#if !defined(NO_ACTION_LAYER) && defined(PREVENT_STUCK_MODIFIERS)
#if !defined(NO_ACTION_LAYER) && !defined(STRICT_LAYER_RELEASE)

/* TODO: Use store_or_get_action() or a similar function. */
if (!disable_action_cache) {
uint8_t layer;
Expand Down
4 changes: 4 additions & 0 deletions quantum/quantum.h
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,10 @@ extern uint32_t default_layer_state;
#define readPin(pin) palReadLine(pin)
#endif

#ifdef CUSTOM_MODIFIED_VALUES_ENABLE
#include "custom_modified_values.h"
#endif

#define STRINGIZE(z) #z
#define ADD_SLASH_X(y) STRINGIZE(\x ## y)
#define SYMBOL_STR(x) ADD_SLASH_X(x)
Expand Down
2 changes: 1 addition & 1 deletion tmk_core/common/action.c
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ void process_hand_swap(keyevent_t *event) {
}
#endif

#if !defined(NO_ACTION_LAYER) && !defined(STRICT_LAYER_RELEASE)
#if !defined(NO_ACTION_LAYER) && defined(PREVENT_STUCK_MODIFIERS)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#if !defined(NO_ACTION_LAYER) && defined(PREVENT_STUCK_MODIFIERS)
#if !defined(NO_ACTION_LAYER) && !defined(STRICT_LAYER_RELEASE)

bool disable_action_cache = false;

void process_record_nocache(keyrecord_t *record)
Expand Down
2 changes: 1 addition & 1 deletion tmk_core/common/action.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ void action_function(keyrecord_t *record, uint8_t id, uint8_t opt);
bool process_record_quantum(keyrecord_t *record);

/* Utilities for actions. */
#if !defined(NO_ACTION_LAYER) && !defined(STRICT_LAYER_RELEASE)
#if !defined(NO_ACTION_LAYER) && defined(PREVENT_STUCK_MODIFIERS)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#if !defined(NO_ACTION_LAYER) && defined(PREVENT_STUCK_MODIFIERS)
#if !defined(NO_ACTION_LAYER) && !defined(STRICT_LAYER_RELEASE)

extern bool disable_action_cache;
#endif

Expand Down
4 changes: 2 additions & 2 deletions tmk_core/common/action_layer.c
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ void layer_debug(void)
}
#endif

#if !defined(NO_ACTION_LAYER) && !defined(STRICT_LAYER_RELEASE)
#if !defined(NO_ACTION_LAYER) && defined(PREVENT_STUCK_MODIFIERS)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#if !defined(NO_ACTION_LAYER) && defined(PREVENT_STUCK_MODIFIERS)
#if !defined(NO_ACTION_LAYER) && !defined(STRICT_LAYER_RELEASE)

uint8_t source_layers_cache[(MATRIX_ROWS * MATRIX_COLS + 7) / 8][MAX_LAYER_BITS] = {{0}};

void update_source_layers_cache(keypos_t key, uint8_t layer)
Expand Down Expand Up @@ -272,7 +272,7 @@ uint8_t read_source_layers_cache(keypos_t key)
*/
action_t store_or_get_action(bool pressed, keypos_t key)
{
#if !defined(NO_ACTION_LAYER) && !defined(STRICT_LAYER_RELEASE)
#if !defined(NO_ACTION_LAYER) && defined(PREVENT_STUCK_MODIFIERS)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#if !defined(NO_ACTION_LAYER) && defined(PREVENT_STUCK_MODIFIERS)
#if !defined(NO_ACTION_LAYER) && !defined(STRICT_LAYER_RELEASE)

if (disable_action_cache) {
return layer_switch_get_action(key);
}
Expand Down
2 changes: 1 addition & 1 deletion tmk_core/common/action_layer.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ uint32_t layer_state_set_user(uint32_t state);
uint32_t layer_state_set_kb(uint32_t state);

/* pressed actions cache */
#if !defined(NO_ACTION_LAYER) && !defined(STRICT_LAYER_RELEASE)
#if !defined(NO_ACTION_LAYER) && defined(PREVENT_STUCK_MODIFIERS)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#if !defined(NO_ACTION_LAYER) && defined(PREVENT_STUCK_MODIFIERS)
#if !defined(NO_ACTION_LAYER) && !defined(STRICT_LAYER_RELEASE)

/* The number of bits needed to represent the layer number: log2(32). */
#define MAX_LAYER_BITS 5
void update_source_layers_cache(keypos_t key, uint8_t layer);
Expand Down
72 changes: 66 additions & 6 deletions tmk_core/common/action_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,33 @@ bool has_oneshot_mods_timed_out(void) {
#endif
#endif

#ifdef CUSTOM_MODIFIED_VALUES_ENABLE
// # define CMV_NON_CHARMODS_MASK (0b00000000 | MOD_BIT(KC_RGUI) | MOD_BIT(KC_RCTRL) | MOD_BIT(KC_LGUI) | MOD_BIT(KC_LALT) | MOD_BIT(KC_LCTRL))
# define CMV_NON_CHARMODS_MASK 0b10011101
// # define CMV_SHIFTS_MASK (0b00000000 | MOD_BIT(KC_RSHIFT) | MOD_BIT(KC_LSHIFT))
# define CMV_SHIFTS_MASK 0b00100010
// # define CMV_RALT_MASK (0b00000000 | MOD_BIT(KC_RALT))
# define CMV_RALT_MASK 0b01000000

# ifndef NO_ACTION_ONESHOT
# define ARE_THERE_THESE_MODS(mods_mask) ( \
(mods_mask & real_mods) || \
(mods_mask & macro_mods) || \
(mods_mask & oneshot_mods) || \
(mods_mask & oneshot_locked_mods))
# else
# define ARE_THERE_THESE_MODS(mods_mask) ((mods_mask & real_mods) || (mods_mask & macro_mods))
# endif

static bool dont_send_mods = false;

bool are_there_non_charmods(void) { return ARE_THERE_THESE_MODS(CMV_NON_CHARMODS_MASK); }
bool are_there_shifts(void) { return ARE_THERE_THESE_MODS(CMV_SHIFTS_MASK); }
bool are_there_ralts(void) { return ARE_THERE_THESE_MODS(CMV_RALT_MASK); }
bool get_mods_blocker(void) { return dont_send_mods; }
void set_mods_blocker(bool new_value) { dont_send_mods = new_value; }
#endif

/* oneshot layer */
#ifndef NO_ACTION_ONESHOT
/** \brief oneshot_layer_data bits
Expand All @@ -86,7 +113,7 @@ inline bool has_oneshot_layer_timed_out() {
}
#endif

/** \brief Set oneshot layer
/** \brief Set oneshot layer
*
* FIXME: needs doc
*/
Expand All @@ -98,7 +125,7 @@ void set_oneshot_layer(uint8_t layer, uint8_t state)
oneshot_layer_time = timer_read();
#endif
}
/** \brief Reset oneshot layer
/** \brief Reset oneshot layer
*
* FIXME: needs doc
*/
Expand All @@ -108,7 +135,7 @@ void reset_oneshot_layer(void) {
oneshot_layer_time = 0;
#endif
}
/** \brief Clear oneshot layer
/** \brief Clear oneshot layer
*
* FIXME: needs doc
*/
Expand Down Expand Up @@ -138,6 +165,26 @@ bool is_oneshot_layer_active(void)
* FIXME: needs doc
*/
void send_keyboard_report(void) {
#ifdef CUSTOM_MODIFIED_VALUES_ENABLE
if (dont_send_mods) {
keyboard_report->mods = weak_mods;
# ifndef NO_ACTION_ONESHOT
if (oneshot_mods) {
# if (defined(ONESHOT_TIMEOUT) && (ONESHOT_TIMEOUT > 0))
if (has_oneshot_mods_timed_out()) {
dprintf("Oneshot: timeout\n");
clear_oneshot_mods();
}
# endif
if (has_anykey(keyboard_report)) {
clear_oneshot_mods();
host_keyboard_send(keyboard_report);
clear_keys();
}
}
# endif
} else {
#endif
keyboard_report->mods = real_mods;
keyboard_report->mods |= weak_mods;
keyboard_report->mods |= macro_mods;
Expand All @@ -154,8 +201,11 @@ void send_keyboard_report(void) {
clear_oneshot_mods();
}
}

#endif
#ifdef CUSTOM_MODIFIED_VALUES_ENABLE
}
#endif

host_keyboard_send(keyboard_report);
}

Expand All @@ -168,12 +218,22 @@ uint8_t get_mods(void) { return real_mods; }
*
* FIXME: needs doc
*/
void add_mods(uint8_t mods) { real_mods |= mods; }
void add_mods(uint8_t mods) {
#ifdef CUSTOM_MODIFIED_VALUES_ENABLE
clear_keys();
#endif
real_mods |= mods;
}
/** \brief del mods
*
* FIXME: needs doc
*/
void del_mods(uint8_t mods) { real_mods &= ~mods; }
void del_mods(uint8_t mods) {
#ifdef CUSTOM_MODIFIED_VALUES_ENABLE
clear_keys();
#endif
real_mods &= ~mods;
}
/** \brief set mods
*
* FIXME: needs doc
Expand Down
9 changes: 9 additions & 0 deletions tmk_core/common/action_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,15 @@ bool has_oneshot_layer_timed_out(void);
/* inspect */
uint8_t has_anymod(void);

/* custom modified values */
# ifdef CUSTOM_MODIFIED_VALUES_ENABLE
bool are_there_non_charmods(void);
bool are_there_shifts(void);
bool are_there_ralts(void);
bool get_mods_blocker(void);
void set_mods_blocker(bool new_value);
# endif

#ifdef __cplusplus
}
#endif
Expand Down