* 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); |