* users/datagrok: add shared functions * users/datagrok: improve base-layer selection feature * users/datagrok: add README.mdpull/8021/head
@ -0,0 +1,63 @@ | |||||
# datagrok's QMK user-space code | |||||
## cdeq "comma dot exclamation question" | |||||
This is a hack to place `question mark` on `shift-comma` and `exclamation mark` on `shift-period`. | |||||
When using an operating system configured for a US/qwerty layout this replaces the angle brackets `<` `>` with `?` `!`. This helps on small keyboards to keep symbols for prose co-located in one layer, and symbols for programming in another. | |||||
It's a "hack" because the "proper" way to accomplish this would be to edit the operating system's keymap. | |||||
### setup | |||||
in your `keymap.c`: | |||||
#include "feature_cdeq.h" | |||||
bool process_record_user(uint16_t keycode, keyrecord_t *record) { | |||||
return process_record_cdeq(keycode, record); | |||||
} | |||||
in your `rules.mk`, | |||||
SRC += feature_cdeq.c | |||||
### examples | |||||
- atreus:datagrok | |||||
- bm43a:datagrok | |||||
- mitosis:datagrok | |||||
## base layer selector | |||||
Defines a keycode `KF_LAYO` to rotate between available default layers. | |||||
`Shift`+`KF_LAYO` makes the currently selected one persistent across reboots. | |||||
This is useful if you'd like your keyboard to support and toggle between QWERTY, Dvorak, Colemak, Workman, and other layouts while keeping a common arrangement of modifier and function keys. | |||||
Since toggling layouts seems like something one does infrequently, I wanted to be able to operate this feature with a single key, instead of one for each layer like planck:default or bootmagic. | |||||
### setup | |||||
in your `keymap.c`: | |||||
#define KF_LAYO SAFE_RANGE | |||||
#include "feature_default_layers_selector.h" | |||||
const uint8_t highest_base_layer = 4; | |||||
bool process_record_user(uint16_t keycode, keyrecord_t *record) { | |||||
return \ | |||||
process_record_save_default_layer(keycode, record) && \ | |||||
process_record_select_default_layer(keycode, record); | |||||
} | |||||
in your `rules.mk`, | |||||
SRC += feature_default_layers_selector.c | |||||
### examples | |||||
- atreus:datagrok | |||||
- bm43a:datagrok | |||||
- mitosis:datagrok |
@ -0,0 +1,47 @@ | |||||
// This is a hack to place <question mark> on <shift-comma> and <exclamation | |||||
// mark> on <shift-period>, when using an operating system configured for a | |||||
// US/qwerty layout. | |||||
// | |||||
// cdeq = "comma dot exclamation question" | |||||
#include QMK_KEYBOARD_H | |||||
bool comm_shifted = false; | |||||
bool ques_shifted = false; | |||||
bool process_record_cdeq(uint16_t keycode, keyrecord_t *record) { | |||||
uint8_t shifted; | |||||
uint16_t s_keycode; | |||||
bool *k_shifted; | |||||
switch (keycode) { | |||||
case KC_COMM: | |||||
s_keycode = KC_SLSH; | |||||
k_shifted = &comm_shifted; | |||||
break; | |||||
case KC_DOT: | |||||
s_keycode = KC_1; | |||||
k_shifted = &ques_shifted; | |||||
break; | |||||
default: | |||||
return true; | |||||
} | |||||
shifted = get_mods() & (MOD_BIT(KC_LSHIFT)|MOD_BIT(KC_RSHIFT)); | |||||
// Keydown. If shift is currently pressed, register its alternate keycode. | |||||
if (record->event.pressed && shifted) { | |||||
*k_shifted = true; | |||||
register_code(s_keycode); | |||||
return false; | |||||
// Keyup. If shift was pressed back when the key was pressed, unregister | |||||
// its alternate keycode. | |||||
} else if (!(record->event.pressed) && *k_shifted) { | |||||
*k_shifted = false; | |||||
unregister_code(s_keycode); | |||||
return false; | |||||
// Otherwise, behave as normal. | |||||
} else { | |||||
return true; | |||||
} | |||||
} |
@ -0,0 +1,2 @@ | |||||
#include QMK_KEYBOARD_H | |||||
bool process_record_cdeq(uint16_t keycode, keyrecord_t *record); |
@ -0,0 +1,46 @@ | |||||
#include "feature_default_layers_selector.h" | |||||
#ifdef AUDIO_ENABLE | |||||
#include "audio.h" | |||||
#ifdef DEFAULT_LAYER_SONGS | |||||
extern float default_layer_songs[][16][2]; | |||||
#endif | |||||
#endif | |||||
bool process_record_save_default_layer(uint16_t keycode, keyrecord_t *record) { | |||||
#if defined(AUDIO_ENABLE) | |||||
float saved_song[][2] = SONG(COIN_SOUND); | |||||
#endif | |||||
if (!(keycode == KF_LAYO | |||||
&& record->event.pressed | |||||
&& get_mods() & (MOD_BIT(KC_LSHIFT)|MOD_BIT(KC_RSHIFT)))) { | |||||
return true; | |||||
} | |||||
eeconfig_update_default_layer(default_layer_state); | |||||
#if defined(AUDIO_ENABLE) | |||||
PLAY_SONG(saved_song); | |||||
#endif | |||||
return false; | |||||
} | |||||
bool process_record_select_default_layer(uint16_t keycode, keyrecord_t *record) { | |||||
if (!(keycode == KF_LAYO | |||||
&& record->event.pressed)) { | |||||
return true; | |||||
} | |||||
if (!default_layer_state) { | |||||
default_layer_set(2); | |||||
} else { | |||||
default_layer_set( | |||||
(((1U<<(highest_base_layer+1))-1) & (default_layer_state<<1)) | |||||
| (default_layer_state>>highest_base_layer)); | |||||
} | |||||
led_set(host_keyboard_leds()); | |||||
#if defined(AUDIO_ENABLE) && defined(DEFAULT_LAYER_SONGS) | |||||
PLAY_SONG(default_layer_songs[get_highest_layer(default_layer_state)]); | |||||
#endif | |||||
return false; | |||||
} |
@ -0,0 +1,69 @@ | |||||
#include QMK_KEYBOARD_H | |||||
/* | |||||
Define a keycode KF_LAYO to rotate between available default layers. | |||||
Shift+KF_LAYO makes the current one persistent. | |||||
To use: | |||||
in your keymap.c, define KF_LAYO so it does not conflict with anything else. | |||||
then include this header and set highest_base_layer. | |||||
#define KF_LAYO SAFE_RANGE | |||||
#include "feature_default_layers_selector.h" | |||||
const uint8_t highest_base_layer = 4; // the index | |||||
and in your rules.mk, | |||||
SRC += feature_default_layers_selector.c | |||||
*/ | |||||
/* | |||||
See https://docs.qmk.fm/#/keymap for docs about layers including the concept | |||||
of "base" or "default" layers. | |||||
This is broken into two functions so that: | |||||
- If you don't want to store the default layer state in eeprom, don't call | |||||
process_record_save_default_layer. | |||||
- If you have your own mechanism for setting the default layer state (to one | |||||
or multiple layers), do that instead of process_record_select_default_layer. | |||||
If you call both functions, call process_record_save_default_layer first. | |||||
The QMK docs seem to assume that you will have only one layer as your | |||||
default layer at any time, but the source code actually supports an arbitrary | |||||
default_layer_state (composition of layers) | |||||
quantum has "set_single_persistent_default_layer" but that writes to eeprom | |||||
every time you change your default layer preference. i wanted a behavior | |||||
instead which lets you switch default layers all you want, then store the | |||||
current configuration once you're happy with it. that way if you get into an | |||||
unusable state you can just unplug and replug your keyboard to escape from it. | |||||
this code assumes: | |||||
1. each default layer state that you would select among consists of a single | |||||
layer, which we will call a "base" layer. | |||||
2. all your "base" layers are stored contiguously at the bottom of your | |||||
keymaps[] stack, and there are no non-"base" layers mixed in. | |||||
3. you have a maximum of 8 "base" layers. that is, the highest base layer is | |||||
index 7. | |||||
while 16 and 32 bit platforms might allow default_layer_state to include more | |||||
and higher-numbered layers, eeconfig_update_default_layer saves only the first | |||||
8 bits of default_layer_state to eeprom. | |||||
*/ | |||||
#ifndef KF_LAYO | |||||
#define KF_LAYO SAFE_RANGE | |||||
#endif | |||||
const uint8_t highest_base_layer; | |||||
bool process_record_save_default_layer(uint16_t keycode, keyrecord_t *record); | |||||
bool process_record_select_default_layer(uint16_t keycode, keyrecord_t *record); |