~ruther/qmk_firmware

5fb95c5f94d6c939dfea2fc716ef818d6242b918 — Michael F. Lamb 5 years ago 05d6e6c
create users/datagrok (#7653)

* users/datagrok: add shared functions

* users/datagrok: improve base-layer selection feature

* users/datagrok: add README.md
A users/datagrok/README.md => users/datagrok/README.md +63 -0
@@ 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

A users/datagrok/feature_cdeq.c => users/datagrok/feature_cdeq.c +47 -0
@@ 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;
  }
}

A users/datagrok/feature_cdeq.h => users/datagrok/feature_cdeq.h +2 -0
@@ 0,0 1,2 @@
#include QMK_KEYBOARD_H
bool process_record_cdeq(uint16_t keycode, keyrecord_t *record);

A users/datagrok/feature_default_layers_selector.c => users/datagrok/feature_default_layers_selector.c +46 -0
@@ 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;
}

A users/datagrok/feature_default_layers_selector.h => users/datagrok/feature_default_layers_selector.h +69 -0
@@ 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);