diff options
| -rw-r--r-- | keyboards/ergodox/keymaps/algernon/Makefile | 9 | ||||
| -rw-r--r-- | keyboards/ergodox/keymaps/algernon/images/adore-layer.png | bin | 93748 -> 93893 bytes | |||
| -rw-r--r-- | keyboards/ergodox/keymaps/algernon/images/base-layer.png | bin | 95222 -> 95204 bytes | |||
| -rw-r--r-- | keyboards/ergodox/keymaps/algernon/keymap.c | 494 | ||||
| -rw-r--r-- | keyboards/ergodox/keymaps/algernon/readme.md | 67 | ||||
| -rw-r--r-- | keyboards/ergodox/keymaps/algernon/tools/heatmap-layout.ADORE.json (renamed from keyboards/ergodox/keymaps/algernon/tools/heatmap-adore-layout.json) | 108 | ||||
| -rw-r--r-- | keyboards/ergodox/keymaps/algernon/tools/heatmap-layout.Dvorak.json (renamed from keyboards/ergodox/keymaps/algernon/tools/heatmap-base-layout.json) | 29 | ||||
| -rwxr-xr-x | keyboards/ergodox/keymaps/algernon/tools/log-to-heatmap.py | 368 | 
8 files changed, 552 insertions, 523 deletions
| diff --git a/keyboards/ergodox/keymaps/algernon/Makefile b/keyboards/ergodox/keymaps/algernon/Makefile index 00194857ac..7c2b3ad97c 100644 --- a/keyboards/ergodox/keymaps/algernon/Makefile +++ b/keyboards/ergodox/keymaps/algernon/Makefile @@ -1,22 +1,23 @@  BOOTMAGIC_ENABLE=no  COMMAND_ENABLE=no  SLEEP_LED_ENABLE=no -UNICODE_ENABLE=no  FORCE_NKRO ?= yes  DEBUG_ENABLE = no  CONSOLE_ENABLE = no  TAP_DANCE_ENABLE = yes  KEYLOGGER_ENABLE ?= yes +UCIS_ENABLE = yes +MOUSEKEY_ENABLE ?= yes -ADORE_AUTOLOG ?= no +AUTOLOG_ENABLE ?= no  ifeq (${FORCE_NKRO},yes)  OPT_DEFS += -DFORCE_NKRO  endif -ifeq (${ADORE_AUTOLOG},yes) +ifeq (${AUTOLOG_ENABLE},yes)  KEYLOGGER_ENABLE = yes -OPT_DEFS += -DADORE_AUTOLOG +OPT_DEFS += -DAUTOLOG_ENABLE  endif  ifeq (${KEYLOGGER_ENABLE},yes) diff --git a/keyboards/ergodox/keymaps/algernon/images/adore-layer.png b/keyboards/ergodox/keymaps/algernon/images/adore-layer.pngBinary files differ index 44ad8a1eb7..3d0a5fb20c 100644 --- a/keyboards/ergodox/keymaps/algernon/images/adore-layer.png +++ b/keyboards/ergodox/keymaps/algernon/images/adore-layer.png diff --git a/keyboards/ergodox/keymaps/algernon/images/base-layer.png b/keyboards/ergodox/keymaps/algernon/images/base-layer.pngBinary files differ index da159fbe2e..7ea57aae38 100644 --- a/keyboards/ergodox/keymaps/algernon/images/base-layer.png +++ b/keyboards/ergodox/keymaps/algernon/images/base-layer.png diff --git a/keyboards/ergodox/keymaps/algernon/keymap.c b/keyboards/ergodox/keymaps/algernon/keymap.c index 144030e2e9..9f476d8a6b 100644 --- a/keyboards/ergodox/keymaps/algernon/keymap.c +++ b/keyboards/ergodox/keymaps/algernon/keymap.c @@ -2,6 +2,7 @@   * algernon's ErgoDox EZ layout, please see the readme.md file!   */ +#include <stdarg.h>  #include "ergodox.h"  #include "led.h"  #include "debug.h" @@ -33,7 +34,6 @@ enum {    // Buttons that do extra stuff    A_GUI,    A_PLVR, -  A_ESC,    A_MPN,    // Function / number keys @@ -47,7 +47,6 @@ enum {    KF_8,    KF_9,    KF_10, -  KF_11, // =, F11    // Application select keys    APP_SLK, // Slack @@ -62,6 +61,11 @@ enum {    A_MDL,    A_MDR, +  // Mouse acceleration +  A_ACL0, +  A_ACL1, +  A_ACL2, +    // Hungarian layer keys    HU_AA, // Á    HU_OO, // Ó @@ -89,7 +93,6 @@ enum {  enum {    CT_CLN = 0, -  CT_MNS,    CT_TA,    CT_LBP,    CT_RBP @@ -102,7 +105,11 @@ uint16_t gui_timer = 0;  uint16_t kf_timers[12];  #if KEYLOGGER_ENABLE +# ifdef AUTOLOG_ENABLE +bool log_enable = true; +# else  bool log_enable = false; +# endif  #endif  bool time_travel = false; @@ -114,12 +121,12 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {  /* Keymap 0: Base Layer   *   * ,-----------------------------------------------------.           ,-----------------------------------------------------. - * | Next/Prev | 1 F1 | 2 F2 | 3 F3 | 4 F4 | 5 F5 | Plvr |           | Apps | 6 F6 | 7 F7 | 8 F8 | 9 F9 | 0 F10|       F11 | + * | Next/Prev | 1 F1 | 2 F2 | 3 F3 | 4 F4 | 5 F5 | Plvr |           |  F12 | 6 F6 | 7 F7 | 8 F8 | 9 F9 | 0 F10|       F11 |   * |-----------+------+------+------+------+-------------|           |------+------+------+------+------+------+-----------| - * |         ~ |   '  |   ,  |   .  |   P  |   Y  |   [  |           |  ]   |   F  |   G  |   C  |   R  |  L   | \         | - * |-----------+------+------+------+------+------|      |           |      |------+------+------+------+------+-----------| + * |         ~ |   '  |   ,  |   .  |   P  |   Y  |   (  |           |  )   |   F  |   G  |   C  |   R  |  L   | \         | + * |-----------+------+------+------+------+------|   [  |           |  ]   |------+------+------+------+------+-----------|   * | Tab/ARROW |   A  |   O  |   E  |   U  |   I  |------|           |------|   D  |   H  |   T  |   N  |  S   | = / Arrow | - * |-----------+------+------+------+------+------|   (  |           |  )   |------+------+------+------+------+-----------| + * |-----------+------+------+------+------+------|   :  |           |  -   |------+------+------+------+------+-----------|   * | Play/Pause|   /  |   Q  |   J  |   K  |   X  |      |           |      |   B  |   M  |   W  |   V  |  Z   |      Stop |   * `-----------+------+------+------+------+-------------'           `-------------+------+------+------+------+-----------'   *     |       |      |      |      |   :  |                                       |   -  |      |      |      |       | @@ -135,21 +142,21 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {  [BASE] = KEYMAP(  // left hand   M(A_MPN)           ,M(KF_1)     ,M(KF_2)     ,M(KF_3),M(KF_4),M(KF_5),M(A_PLVR) -,KC_GRV             ,KC_QUOT     ,KC_COMM     ,KC_DOT ,KC_P   ,KC_Y   ,KC_LBRC +,KC_GRV             ,KC_QUOT     ,KC_COMM     ,KC_DOT ,KC_P   ,KC_Y   ,TD(CT_LBP)  ,TD(CT_TA)          ,KC_A        ,KC_O        ,KC_E   ,KC_U   ,KC_I -,KC_MPLY            ,KC_SLSH     ,KC_Q        ,KC_J   ,KC_K   ,KC_X   ,KC_LPRN +,KC_MPLY            ,KC_SLSH     ,KC_Q        ,KC_J   ,KC_K   ,KC_X   ,TD(CT_CLN)  ,KC_NO              ,KC_NO       ,KC_NO       ,KC_NO  ,TD(CT_CLN)                                                              ,F(F_ALT),F(F_GUI)                                                                       ,F(F_CTRL) -                                                    ,KC_BSPC,F(F_SFT),M(A_ESC) +                                                    ,KC_BSPC,F(F_SFT),KC_ESC                                                                  // right hand -                                                               ,KC_APP    ,M(KF_6),M(KF_7)   ,M(KF_8),M(KF_9) ,M(KF_10) ,KC_F11 -                                                               ,KC_RBRC   ,KC_F   ,KC_G      ,KC_C   ,KC_R    ,KC_L     ,KC_BSLS +                                                               ,KC_F12    ,M(KF_6),M(KF_7)   ,M(KF_8),M(KF_9) ,M(KF_10) ,KC_F11 +                                                               ,TD(CT_RBP),KC_F   ,KC_G      ,KC_C   ,KC_R    ,KC_L     ,KC_BSLS                                                                            ,KC_D   ,KC_H      ,KC_T   ,KC_N    ,KC_S     ,KC_EQL -                                                               ,KC_RPRN   ,KC_B   ,KC_M      ,KC_W   ,KC_V    ,KC_Z     ,KC_MSTP -                                                                                  ,TD(CT_MNS),KC_NO  ,KC_NO   ,KC_NO    ,KC_NO +                                                               ,KC_MINS   ,KC_B   ,KC_M      ,KC_W   ,KC_V    ,KC_Z     ,KC_MSTP +                                                                                  ,KC_MINS   ,KC_NO  ,KC_NO   ,KC_NO    ,KC_NO                                                                 ,OSL(NMDIA),KC_DEL                                                                 ,KC_LEAD @@ -159,13 +166,13 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {  /* Keymap 1: Adore layer   *   * ,-----------------------------------------------------.           ,-----------------------------------------------------. - * | Play/Pause| 1 F1 | 2 F2 | 3 F3 | 4 F4 | 5 F5 | Plvr |           | Apps | 6 F6 | 7 F7 | 8 F8 | 9 F9 | 0 F10|       F11 | + * | Play/Pause| 1 F1 | 2 F2 | 3 F3 | 4 F4 | 5 F5 | Plvr |           |  F12 | 6 F6 | 7 F7 | 8 F8 | 9 F9 | 0 F10|       F11 |   * |-----------+------+------+------+------+-------------|           |------+------+------+------+------+------+-----------| - * |        `~ |   X  |   W  |   K  |   L  |   M  |   (  |           |  )   |   F  |   H  |   C  |   P  |  Y   | \         | + * |        `~ |   Y  |   W  |   G  |   L  |   M  |   (  |           |  )   |   F  |   H  |   C  |   P  |  X   | \         |   * |-----------+------+------+------+------+------|   [  |           |  ]   |------+------+------+------+------+-----------|   * | Tab/Arrow |   A  |   O  |   E  |   I  |   U  |------|           |------|   D  |   R  |   T  |   N  |  S   | =         |   * |-----------+------+------+------+------+------|      |           |      |------+------+------+------+------+-----------| - * |           |   Z  |   Q  |   '  |   ,  |   .  |   :  |           |  -   |   B  |   G  |   V  |   J  |  /   |           | + * |           |   Z  |   Q  |   '  |   ,  |   .  |   :  |           |  -   |   B  |   K  |   V  |   J  |  /   |           |   * `-----------+------+------+------+------+-------------'           `-------------+------+------+------+------+-----------'   *     |       |      |      |      |      |                                       |      |      |      |      |       |   *     `-----------------------------------'                                       `-----------------------------------' @@ -180,20 +187,20 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {  [ADORE] = KEYMAP(  // left hand   KC_MPLY            ,M(KF_1)     ,M(KF_2)     ,M(KF_3),M(KF_4),M(KF_5),M(A_PLVR) -,KC_GRV             ,KC_X        ,KC_W        ,KC_K   ,KC_L   ,KC_M   ,TD(CT_LBP) +,KC_GRV             ,KC_Y        ,KC_W        ,KC_G   ,KC_L   ,KC_M   ,TD(CT_LBP)  ,TD(CT_TA)          ,KC_A        ,KC_O        ,KC_E   ,KC_I   ,KC_U  ,KC_NO              ,KC_Z        ,KC_Q        ,KC_QUOT,KC_COMM,KC_DOT ,TD(CT_CLN)  ,KC_NO              ,KC_NO       ,KC_NO       ,KC_NO  ,KC_NO                                                              ,F(F_ALT),F(F_GUI)                                                                       ,F(F_CTRL) -                                                    ,KC_BSPC,F(F_SFT),M(A_ESC) +                                                    ,KC_BSPC,F(F_SFT),KC_ESC                                                                  // right hand -                                                               ,KC_APP    ,M(KF_6),M(KF_7),M(KF_8),M(KF_9) ,M(KF_10) ,KC_F11 -                                                               ,TD(CT_RBP),KC_F   ,KC_H   ,KC_C   ,KC_P    ,KC_Y     ,KC_BSLS +                                                               ,KC_F12    ,M(KF_6),M(KF_7),M(KF_8),M(KF_9) ,M(KF_10) ,KC_F11 +                                                               ,TD(CT_RBP),KC_F   ,KC_H   ,KC_C   ,KC_P    ,KC_X     ,KC_BSLS                                                                            ,KC_D   ,KC_R   ,KC_T   ,KC_N    ,KC_S     ,KC_EQL -                                                               ,TD(CT_MNS),KC_B   ,KC_G   ,KC_V   ,KC_J    ,KC_SLSH  ,KC_NO +                                                               ,KC_MINS   ,KC_B   ,KC_K   ,KC_V   ,KC_J    ,KC_SLSH  ,KC_NO                                                                                    ,KC_NO  ,KC_NO  ,KC_NO   ,KC_NO    ,KC_NO                                                                 ,OSL(NMDIA),KC_DEL @@ -363,14 +370,14 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {   */  [NMDIA] = KEYMAP(  // left hand - KC_ACL0    ,KC_NO       ,KC_NO      ,KC_NO   ,KC_NO   ,KC_NO   ,LGUI(KC_L) -,KC_ACL1    ,KC_NO       ,KC_HOME    ,KC_UP   ,KC_PGUP ,KC_NO   ,KC_NO -,KC_ACL2    ,KC_NO       ,KC_LEFT    ,KC_DOWN ,KC_RIGHT,KC_NO + M(A_ACL0)  ,KC_NO       ,KC_NO      ,KC_NO   ,KC_NO   ,KC_NO   ,LGUI(KC_L) +,M(A_ACL1)  ,KC_NO       ,KC_HOME    ,KC_UP   ,KC_PGUP ,KC_NO   ,KC_NO +,M(A_ACL2)  ,KC_NO       ,KC_LEFT    ,KC_DOWN ,KC_RIGHT,KC_NO  ,KC_MPLY    ,KC_NO       ,KC_END     ,KC_DOWN ,KC_PGDN ,KC_NO   ,KC_NO  ,KC_NO      ,KC_NO       ,KC_NO      ,KC_NO   ,KC_NO                                                          ,KC_MUTE ,KC_VOLU                                                                   ,KC_VOLD -                                                 ,KC_SPC,KC_ENTER,M(A_ESC) +                                                 ,KC_SPC,KC_ENTER,KC_ESC                                                                       // right hand                                                                       ,LGUI(KC_L),KC_NO   ,KC_NO   ,KC_NO   ,KC_NO   ,KC_NO    ,KC_NO @@ -439,7 +446,7 @@ const uint16_t PROGMEM fn_actions[] = {    ,[F_CTRL] = ACTION_MODS_ONESHOT (MOD_LCTL)  }; -void toggle_steno(int pressed) +static void toggle_steno(int pressed)  {    uint8_t layer = biton32(layer_state); @@ -462,7 +469,7 @@ void toggle_steno(int pressed)    }  } -macro_t *ang_do_hun (keyrecord_t *record, uint16_t accent, uint16_t hun_char) +static macro_t *ang_do_hun (keyrecord_t *record, uint16_t accent, uint16_t hun_char)  {    uint8_t need_shift = 0;    uint8_t hold_shift = 0; @@ -507,46 +514,43 @@ macro_t *ang_do_hun (keyrecord_t *record, uint16_t accent, uint16_t hun_char)    return MACRO_NONE;  } -void ang_handle_kf (keyrecord_t *record, uint8_t id) +static bool from_appsel; + +static void ang_handle_kf (keyrecord_t *record, uint8_t id)  {    uint8_t code = id - KF_1;    if (record->event.pressed) {      kf_timers[code] = timer_read ();    } else { -    uint8_t kc; +    uint8_t kc_base; -    if (timer_elapsed (kf_timers[code]) > TAPPING_TERM) { +    if (from_appsel) { +      from_appsel = false; +      return; +    } + +    if (kf_timers[code] && timer_elapsed (kf_timers[code]) > TAPPING_TERM) {        // Long press -      kc = KC_F1 + code; +      kc_base = KC_F1;      } else { -      if (id == KF_11) -        kc = KC_EQL; -      else -        kc = KC_1 + code; +      kc_base = KC_1;      } +    kf_timers[code] = 0; +    code += kc_base; -    register_code (kc); -    unregister_code (kc); +    register_code (code); +    unregister_code (code);    }  } +static struct { +  uint8_t idx; +} m_accel_state; +  const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt)  {        switch(id) { -      case A_ESC: -        if (record->event.pressed) { -          if ((get_oneshot_mods ()) && !has_oneshot_mods_timed_out ()) { -            clear_oneshot_mods (); -          } else { -            register_code (KC_ESC); -          } -          layer_off (HUN); -        } else { -          unregister_code (KC_ESC); -        } -        break; -        case A_MPN:          if (record->event.pressed) {            if (keyboard_report->mods & MOD_BIT(KC_LSFT) || @@ -588,6 +592,7 @@ const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt)        case HU_UEE:          return ang_do_hun (record, KC_EQL, KC_U); +#if MOUSEKEY_ENABLE          /* Mouse movement */        case A_MUL:          if (record->event.pressed) { @@ -633,6 +638,24 @@ const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt)          mousekey_send();          break; +      case A_ACL0 ... A_ACL2: +        if (record->event.pressed) { +          uint8_t idx = id - A_ACL0; +          if (m_accel_state.idx == id) { +            mousekey_off(m_accel_state.idx - A_ACL0 + KC_ACL0); +            m_accel_state.idx = 0; +          } else { +            if (m_accel_state.idx) { +              mousekey_off(m_accel_state.idx - A_ACL0 + KC_ACL0); +              m_accel_state.idx = 0; +            } +            mousekey_on(KC_ACL0 + idx); +            m_accel_state.idx = id; +          } +        } +        break; +#endif +          /* Plover base */        case A_PLVR:          toggle_steno(record->event.pressed); @@ -663,22 +686,34 @@ const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt)          break;        case APP_SLK: +        from_appsel = true;          return MACRODOWN(T(S), T(L), T(A), T(C), T(K), T(ENT), END);        case APP_EMCS: +        from_appsel = true;          return MACRODOWN(T(G), T(N), T(U), T(SPC), T(E), T(M), T(A), T(C), T(S), T(SPC), T(2), T(4), T(ENT), END);        case APP_TERM: -        return MACRODOWN(T(T), T(E), T(R), T(M), T(ENT), END); +        from_appsel = true; +        if (!record->event.pressed) { +          register_code(KC_ESC); +          unregister_code(KC_ESC); +          wait_ms(TAPPING_TERM + 25); +          register_code(KC_DEL); +          unregister_code(KC_DEL); +        } +        break;        case APP_CHRM: +        from_appsel = true;          return MACRODOWN(T(C), T(H), T(R), T(O), T(M), T(ENT), END);        case APP_MSIC: +        from_appsel = true;          return MACRODOWN(T(R), T(H), T(Y), T(T), T(H), T(M), T(B), T(O), T(X), T(ENT), END);          /* Function keys */ -      case KF_1 ... KF_11: +      case KF_1 ... KF_10:          ang_handle_kf (record, id);          break;        } @@ -686,12 +721,14 @@ const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt)        return MACRO_NONE;  }; -uint8_t is_adore = 0; +static uint8_t is_adore = 0;  // Runs just one time when the keyboard initializes.  void matrix_init_user(void) {    uint8_t dl; +  set_unicode_input_mode(UC_LNX); +    ergodox_led_all_on();    for (int i = LED_BRIGHTNESS_HI; i > LED_BRIGHTNESS_LO; i--) {      ergodox_led_all_set (i); @@ -709,120 +746,38 @@ void matrix_init_user(void) {    dl = eeconfig_read_default_layer ();    if (dl == (1UL << ADORE)) {      is_adore = 1; -#if ADORE_AUTOLOG -    log_enable = true; -#endif    }  };  LEADER_EXTERNS(); -void ang_do_unicode (void) { -  register_code (KC_RCTL); -  register_code (KC_RSFT); -  register_code (KC_U); -  unregister_code (KC_U); -  unregister_code (KC_RSFT); -  unregister_code (KC_RCTL); -  wait_ms (100); -} +static void ang_tap (uint8_t code, ...) { +  uint8_t kc = code; +  va_list ap; -void ang_tap (uint16_t codes[]) { -  for (int i = 0; codes[i] != 0; i++) { -    register_code (codes[i]); -    unregister_code (codes[i]); -    wait_ms (50); -  } +  va_start(ap, code); + +  do { +    register_code(kc); +    unregister_code(kc); +    wait_ms(50); +    kc = va_arg(ap, int); +  } while (kc != 0); +  va_end(ap);  }  #define TAP_ONCE(code)  \    register_code (code); \    unregister_code (code) -void ang_tap_dance_bp_finished (qk_tap_dance_state_t *state, void *user_data) { -  bool left, parens; - -  if (state->count > 2) { -    state->count = 0; -    return; -  } - -  if (state->keycode == TD(CT_LBP)) -    left = true; -  else -    left = false; - -  if (state->count == 1) -    parens = false; -  else -    parens = true; - -  if (parens) { -    register_code (KC_RSFT); -    if (left) { -      TAP_ONCE(KC_9); -    } else { -      TAP_ONCE(KC_0); -    } -    unregister_code (KC_RSFT); -  } else { -    if (left) { -      TAP_ONCE (KC_LBRC); -    } else { -      TAP_ONCE (KC_RBRC); -    } -  } -} - -void ang_tap_dance_cln_finished (qk_tap_dance_state_t *state, void *user_data) { -  if (state->count == 1) { -    register_code (KC_RSFT); -    register_code (KC_SCLN); -  } else if (state->count == 2) { -    register_code (KC_SCLN); -  } -} - -void ang_tap_dance_cln_reset (qk_tap_dance_state_t *state, void *user_data) { -  if (state->count == 1) { -    unregister_code (KC_SCLN); -    unregister_code (KC_RSFT); -  } else if (state->count == 2) { -    unregister_code (KC_SCLN); -  } -} - -void ang_tap_dance_mns_finished (qk_tap_dance_state_t *state, void *user_data) { -  if (state->count == 1) { -    register_code (KC_MINS); -  } else if (state->count == 2) { -    register_code (KC_RSFT); -    register_code (KC_MINS); -  } -} - -void ang_tap_dance_mns_reset (qk_tap_dance_state_t *state, void *user_data) { -  if (state->count == 1) { -    unregister_code (KC_MINS); -  } else if (state->count == 2) { -    unregister_code (KC_RSFT); -    unregister_code (KC_MINS); -  } -} -  typedef struct {    bool layer_toggle;    bool sticky; -  bool finished_once;  } td_ta_state_t; -void ang_tap_dance_ta_finished (qk_tap_dance_state_t *state, void *user_data) { +static void ang_tap_dance_ta_finished (qk_tap_dance_state_t *state, void *user_data) {    td_ta_state_t *td_ta = (td_ta_state_t *) user_data; -  if (td_ta->finished_once) { -    return; -  } -    if (td_ta->sticky) {      td_ta->sticky = false;      td_ta->layer_toggle = false; @@ -830,7 +785,6 @@ void ang_tap_dance_ta_finished (qk_tap_dance_state_t *state, void *user_data) {      return;    } -  td_ta->finished_once = true;    if (state->count == 1 && !state->pressed) {      register_code (KC_TAB);      td_ta->sticky = false; @@ -842,35 +796,29 @@ void ang_tap_dance_ta_finished (qk_tap_dance_state_t *state, void *user_data) {    }  } -void ang_tap_dance_ta_reset (qk_tap_dance_state_t *state, void *user_data) { +static void ang_tap_dance_ta_reset (qk_tap_dance_state_t *state, void *user_data) {    td_ta_state_t *td_ta = (td_ta_state_t *) user_data;    if (!td_ta->layer_toggle)      unregister_code (KC_TAB);    if (!td_ta->sticky)      layer_off (ARRW); - -  td_ta->finished_once = false;  }  qk_tap_dance_action_t tap_dance_actions[] = { -   [CT_CLN] = ACTION_TAP_DANCE_FN_ADVANCED (NULL, ang_tap_dance_cln_finished, ang_tap_dance_cln_reset) -  ,[CT_MNS] = ACTION_TAP_DANCE_FN_ADVANCED (NULL, ang_tap_dance_mns_finished, ang_tap_dance_mns_reset) +   [CT_CLN] = ACTION_TAP_DANCE_DOUBLE (KC_COLN, KC_SCLN)    ,[CT_TA]  = {       .fn = { NULL, ang_tap_dance_ta_finished, ang_tap_dance_ta_reset }, -     .user_data = (void *)&((td_ta_state_t) { false, false, false }) +     .user_data = (void *)&((td_ta_state_t) { false, false })     } -  ,[CT_LBP] = ACTION_TAP_DANCE_FN (ang_tap_dance_bp_finished) -  ,[CT_RBP] = ACTION_TAP_DANCE_FN (ang_tap_dance_bp_finished) +  ,[CT_LBP] = ACTION_TAP_DANCE_DOUBLE (KC_LBRC, KC_LPRN) +  ,[CT_RBP] = ACTION_TAP_DANCE_DOUBLE (KC_RBRC, KC_RPRN)  }; -static uint16_t uni[32]; -static uint8_t unicnt; -static bool unimagic = false; -  // Runs constantly in the background, in a loop.  void matrix_scan_user(void) {    uint8_t layer = biton32(layer_state); +  bool is_arrow = false;    if (gui_timer && timer_elapsed (gui_timer) > TAPPING_TERM)      unregister_code (KC_LGUI); @@ -893,13 +841,19 @@ void matrix_scan_user(void) {      ergodox_right_led_2_set (LED_BRIGHTNESS_HI);    } +  if (layer_state & (1UL << ARRW)) { +    ergodox_right_led_1_on (); +    ergodox_right_led_3_on (); +    is_arrow = true; +  } +    if (keyboard_report->mods & MOD_BIT(KC_LSFT) ||        ((get_oneshot_mods() & MOD_BIT(KC_LSFT)) && !has_oneshot_mods_timed_out())) {      ergodox_right_led_1_set (LED_BRIGHTNESS_HI);      ergodox_right_led_1_on ();    } else {      ergodox_right_led_1_set (LED_BRIGHTNESS_LO); -    if (layer != NMDIA && layer != PLVR && layer != ADORE) +    if (layer != NMDIA && layer != PLVR && layer != ADORE && !is_arrow)        ergodox_right_led_1_off ();    } @@ -919,7 +873,7 @@ void matrix_scan_user(void) {      ergodox_right_led_3_on ();    } else {      ergodox_right_led_3_set (LED_BRIGHTNESS_LO); -    if (layer != HUN && layer != PLVR && layer != ADORE) +    if (layer != HUN && layer != PLVR && layer != ADORE && !is_arrow)        ergodox_right_led_3_off ();    } @@ -936,20 +890,17 @@ void matrix_scan_user(void) {      }  #endif +    SEQ_ONE_KEY (KC_Q) { +      register_code16 (LCTL(KC_1)); +      unregister_code16 (LCTL(KC_1)); +    } +      SEQ_ONE_KEY (KC_T) {        time_travel = !time_travel;      }      SEQ_ONE_KEY (KC_U) { -      ang_do_unicode (); -    } - -    SEQ_TWO_KEYS (KC_LEAD, KC_U) { -      unicnt = 0; -      unimagic = true; -      register_code(KC_RSFT); -      TAP_ONCE(KC_U); -      unregister_code(KC_RSFT); +      qk_ucis_start();      }      SEQ_ONE_KEY (KC_V) { @@ -958,25 +909,23 @@ void matrix_scan_user(void) {      SEQ_ONE_KEY (KC_L) {        /* λ */ -      ang_do_unicode (); - -      uint16_t codes[] = {KC_0, KC_3, KC_B, KC_B, KC_ENT, 0}; -      ang_tap (codes); +      unicode_input_start(); +      register_hex(0x03bb); +      unicode_input_finish();      }      SEQ_ONE_KEY (KC_Y) { -      uint16_t codes[] = {KC_BSLS, KC_O, KC_SLSH, 0}; -      ang_tap (codes); +      ang_tap (KC_BSLS, KC_O, KC_SLSH, 0);      }      SEQ_ONE_KEY (KC_S) { -      ang_do_unicode (); TAP_ONCE (KC_A); TAP_ONCE (KC_F); TAP_ONCE (KC_SPC); +      unicode_input_start(); register_hex(0xaf); unicode_input_finish();        TAP_ONCE (KC_BSLS);        register_code (KC_RSFT); TAP_ONCE (KC_MINS); TAP_ONCE (KC_9); unregister_code (KC_RSFT); -      ang_do_unicode (); TAP_ONCE (KC_3); TAP_ONCE (KC_0); TAP_ONCE (KC_C); TAP_ONCE (KC_4); TAP_ONCE (KC_SPC); +      unicode_input_start (); register_hex(0x30c4); unicode_input_finish();        register_code (KC_RSFT); TAP_ONCE (KC_0); TAP_ONCE (KC_MINS); unregister_code (KC_RSFT);        TAP_ONCE (KC_SLSH); -      ang_do_unicode (); TAP_ONCE (KC_A); TAP_ONCE (KC_F); TAP_ONCE (KC_SPC); +      unicode_input_start (); register_hex(0xaf); unicode_input_finish();      }      SEQ_TWO_KEYS (KC_W, KC_M) { @@ -987,8 +936,7 @@ void matrix_scan_user(void) {        wait_ms (1000); -      uint16_t codes[] = {KC_M, KC_A, KC_X, KC_MINS, KC_F, KC_O, KC_C, KC_U, KC_S, KC_E, KC_D, KC_ENT, 0}; -      ang_tap (codes); +      ang_tap (KC_M, KC_A, KC_X, KC_MINS, KC_F, KC_O, KC_C, KC_U, KC_S, KC_E, KC_D, KC_ENT, 0);        register_code (KC_LGUI);        register_code (KC_UP);        unregister_code (KC_UP); @@ -1013,13 +961,7 @@ void matrix_scan_user(void) {          ergodox_right_led_2_off ();          wait_ms (100);          ergodox_right_led_1_off (); -#if ADORE_AUTOLOG -        log_enable = true; -#endif        } else { -#if ADORE_AUTOLOG -        log_enable = false; -#endif          is_adore = 0;          default_layer_and (0);          default_layer_or (1UL << BASE); @@ -1043,140 +985,38 @@ void matrix_scan_user(void) {  static uint16_t last4[4]; -bool is_uni_seq(char *seq) { -  uint8_t i; - -  for (i = 0; seq[i]; i++) { -    uint16_t code; -    if (('1' <= seq[i]) && (seq[i] <= '9')) -      code = seq[i] - '1' + KC_1; -    else if (seq[i] == '0') -      code = KC_0; -    else -      code = seq[i] - 'a' + KC_A; - -    if (i > unicnt) -      return false; -    if (uni[i] != code) -      return false; -  } - -  if (uni[i] == KC_ENT || uni[i] == KC_SPC) -    return true; - -  return false; -} - -uint16_t hex_to_keycode(uint8_t hex) -{ -  if (hex == 0x0) { -    return KC_0; -  } else if (hex < 0xA) { -    return KC_1 + (hex - 0x1); -  } else { -    return KC_A + (hex - 0xA); -  } -} - -void register_hex(uint16_t hex) { -  bool leading_zeros = true; - -  for(int i = 3; i >= 0; i--) { -    uint8_t digit = ((hex >> (i*4)) & 0xF); -    if (digit != 0) -      leading_zeros = false; -    else if (leading_zeros) -      continue; -    register_code(hex_to_keycode(digit)); -    unregister_code(hex_to_keycode(digit)); -    wait_ms(10); -  } -} - -typedef struct { -  char *symbol; -  uint16_t codes[4]; -} qk_ucis_symbol_t; - -static qk_ucis_symbol_t ucis_symbol_table[] = { -  {"poop", {0x1, 0xf4a9, 0}}, -  {"rofl", {0x1, 0xf923, 0}}, -  {"kiss", {0x1, 0xf619, 0}}, -  {"snowman", {0x2603, 0}}, -  {NULL, {}} -}; - -bool process_record_ucis (uint16_t keycode, keyrecord_t *record) { -  uint8_t i; - -  if (!unimagic) -    return true; - -  if (!record->event.pressed) -    return true; - -  uni[unicnt] = keycode; -  unicnt++; - -  if (keycode == KC_BSPC) { -    if (unicnt >= 2) { -      unicnt-= 2; -      return true; -    } else { -      unicnt--; -      return false; -    } -  } - -  if (keycode == KC_ENT || keycode == KC_SPC) { -    bool symbol_found = false; - -    for (i = unicnt; i > 0; i--) { -      register_code (KC_BSPC); -      unregister_code (KC_BSPC); -      wait_ms(10); -    } - -    ang_do_unicode(); -    wait_ms(10); -    for (i = 0; ucis_symbol_table[i].symbol; i++) { -      if (is_uni_seq (ucis_symbol_table[i].symbol)) { -        symbol_found = true; -        for (uint8_t j = 0; ucis_symbol_table[i].codes[j]; j++) { -          register_hex(ucis_symbol_table[i].codes[j]); -        } -        break; -      } -    } -    if (!symbol_found) { -      for (i = 0; i < unicnt - 1; i++) { -        uint8_t code; - -        if (uni[i] > KF_1) -          code = uni[i] - KF_1 + KC_1; -        else -          code = uni[i]; -        TAP_ONCE(code); -        wait_ms (10); -      } -    } - -    unimagic = false; -    return true; -  } -  return true; -} +const qk_ucis_symbol_t ucis_symbol_table[] = UCIS_TABLE +( + UCIS_SYM("poop", 0x1f4a9), + UCIS_SYM("rofl", 0x1f923), + UCIS_SYM("kiss", 0x1f619), + UCIS_SYM("snowman", 0x2603), + UCIS_SYM("coffee", 0x2615), + UCIS_SYM("heart", 0x2764), + UCIS_SYM("bolt", 0x26a1) +);  bool process_record_user (uint16_t keycode, keyrecord_t *record) {  #if KEYLOGGER_ENABLE    if (log_enable) { -    xprintf ("KL: col=%d, row=%d\n", record->event.key.col, -             record->event.key.row); +    xprintf ("KL: col=%02d, row=%02d, pressed=%d, layer=%s\n", record->event.key.col, +             record->event.key.row, record->event.pressed, (is_adore) ? "ADORE" : "Dvorak");    }  #endif -  if (!process_record_ucis (keycode, record)) -    return false; +  if (keycode == KC_ESC && record->event.pressed) { +    bool queue = true; + +    if ((get_oneshot_mods ()) && !has_oneshot_mods_timed_out ()) { +      clear_oneshot_mods (); +      queue = false; +    } +    if (layer_state & (1UL<<HUN)) { +      layer_off (HUN); +      queue = false; +    } +    return queue; +  }    if (time_travel && !record->event.pressed) {      uint8_t p; @@ -1188,15 +1028,13 @@ bool process_record_user (uint16_t keycode, keyrecord_t *record) {      last4[3] = keycode;      if (last4[0] == KC_D && last4[1] == KC_A && last4[2] == KC_T && last4[3] == KC_E) { -      uint16_t codes[] = {KC_E, KC_SPC, KC_MINS, KC_D, KC_SPC, KC_QUOT, 0}; -      ang_tap (codes); +      ang_tap (KC_E, KC_SPC, KC_MINS, KC_D, KC_SPC, KC_QUOT, 0);        register_code (KC_RSFT);        register_code (KC_EQL);        unregister_code (KC_EQL);        unregister_code (KC_RSFT); -      uint16_t codes2[] = {KC_4, KC_SPC, KC_D, KC_A, KC_Y, KC_S, KC_QUOT, 0}; -      ang_tap (codes2); +      ang_tap (KC_4, KC_SPC, KC_D, KC_A, KC_Y, KC_S, KC_QUOT, 0);        return false;      } @@ -1204,3 +1042,17 @@ bool process_record_user (uint16_t keycode, keyrecord_t *record) {    return true;  } + +void qk_ucis_symbol_fallback (void) { +  for (uint8_t i = 0; i < qk_ucis_state.count - 1; i++) { +    uint8_t code; + +    if (qk_ucis_state.codes[i] > KF_1) +      code = qk_ucis_state.codes[i] - KF_1 + KC_1; +    else +      code = qk_ucis_state.codes[i]; +    register_code(code); +    unregister_code(code); +    wait_ms (10); +  } +} diff --git a/keyboards/ergodox/keymaps/algernon/readme.md b/keyboards/ergodox/keymaps/algernon/readme.md index 26dfddbe6a..5e7adb3320 100644 --- a/keyboards/ergodox/keymaps/algernon/readme.md +++ b/keyboards/ergodox/keymaps/algernon/readme.md @@ -3,11 +3,15 @@  algernon's layout  ======================= -This is an unconventional layout for the ErgoDox EZ. For more details about the history of the layout, see my [blog posts about my ErgoDox journey][blog-ergodox]. +This is an unconventional layout for the [ErgoDox EZ][ez]. For more details about the history of the layout, see my [blog posts about my ErgoDox journey][blog-ergodox]. + [ez]: https://ergodox-ez.com/   [blog-ergodox]: https://asylum.madhouse-project.org/blog/tags/ergodox/ -Some of the things in the layout only work when one uses Spacemacs and GNOME under Linux. Your mileage may vary. +Some of the things in the layout only work when one uses [Spacemacs][spacemacs] and [GNOME][gnome] under Linux. Your mileage may vary. + + [spacemacs]: http://spacemacs.org/ + [gnome]: https://www.gnome.org/  ## Table of Contents @@ -40,10 +44,10 @@ At its core, this is a Dvorak layout, with some minor changes. The more interest  * The `GUI` key is special, because when I double-tap it, it sends `GUI + w`, which pops up an application selector. It also switches to a one-shot layer, where the number row on the left half turns into app selector macros, for the most common things I usually want to switch to. Otherwise it behaves as on a normal layout.  * The `ESC` key also doubles as a one-shot cancel key: if tapped while any of the one-shot modifiers are in-flight (as in, single-tapped, and not expired yet), it cancels all one-shot modifiers. It also cancels the **Hun** layer, if active. Otherwise it sends the usual keycode.  * The **Media** and **Hun** layer keys are one-shot, the **STENO** key is a toggle. -* When holding any of the **Arrow** layer keys, the arrow layer activates while the layer key is held. Tapping the key produces the normal key. +* When holding the `Tab`/**Arrow** key, the arrow layer activates while the key is held. Tapping the key produces the normal, `Tab` key. Double-tapping it toggles the **Arrow** layer on until a third tap.  * Tapping the `:` key once yields `:`, tapping it twice yields `;`. +* Tapping the `[{(`/`)}]` keys once yields `[` (or `{` when shifted), tapping them twice yields `(`.  * The **Lead** key allows me to type in a sequence of keys, and trigger some actions: -    - `LEAD u` enters unicode input mode, by sending the GTK+ key sequence that does this.      - `LEAD l` uses the unicode input method to enter a `λ`.      - `LEAD s` does a lot of magic to type in a shruggie: `¯\_(ツ)_/¯`      - `LEAD y` types `\o/`. @@ -52,7 +56,7 @@ At its core, this is a Dvorak layout, with some minor changes. The more interest      - `LEAD v` prints the firmware version, the keyboard and the keymap.      - `LEAD d` toggles logging keypress positions to the HID console.      - `LEAD t` toggles time travel. Figuring out the current `date` is left as an exercise to the reader. -    - `LEAD LEAD u` enters the [Unicode symbol input][#unicode-symbol-input] mode. +    - `LEAD u` enters the [Unicode symbol input](#unicode-symbol-input) mode.  ## ADORE layer @@ -91,6 +95,7 @@ For the layers, the following rules apply:  * When the [ADORE layer](#adore-layer) is toggled on, LEDs will light up from left to right in a sequence, then turn off. When the layer is toggled off, the LEDs light up and turn off in the other direction. No LEDs are on while the layer is active.  * When the [Hungarian layer](#hungarian-layer) is active, the *green* and *blue* LEDs are on.  * When the [Navigation and media layer](#navigation-and-media-layer) is active, the *red* and *green* ones are on. +* When the **ARROW** layer is active, the *red* and *blue* ones are on.  * For the [Steno layer](#steno-layer), all LEDs will be turned on.  Unless noted otherwise, the layers use a dim light for the LEDs, while modifiers use a stronger one, and modifiers override any layer preferences. For example, when on the one-handed layer, with the left side active (*red* light blinking), if `Shift` is on, the *red* light will be constantly on. @@ -116,7 +121,7 @@ This is an experimental feature, and may or may not work reliably.  When the keypress logging functionality is enabled (by `LEAD d`), the keyboard will output a line every time a key is pressed, containing the position of the key in the matrix. This allows one to collect this information, and build analytics over it, such as a heat map, including dead keys too. -Included with the firmware is a small tool that can parse these logs, and create a heatmap that one can import into [KLE][kle]. To use it, simply point `tools/log-to-heatmap.py` to a base layout file (one is included in the `tools/` directory), and the key position log. The latter one can create by running `hid-listen`, and redirecting its output to a file. +Included with the firmware is a small tool that can parse these logs, and create a heatmap that one can import into [KLE][kle]. To use it, either pipe the output of `hid_listen` into it, or pipe it an already saved log, and it will save the results into files in an output directory (given on the command-line). See the output of `tools/log-to-heatmap.py --help` for more information.   [kle]: http://www.keyboard-layout-editor.com/ @@ -151,7 +156,35 @@ The keymap default to forcing NKRO, which seems to upset Windows, and except the  # Changelog -## v1.5 - 2016-08-12 +## v1.6 + +*2016-08-24* + +### Base layer changes + +* The parentheses & bracket keys have been merged: tapping them results in `[` or `{` (if it was shifted), double tapping leads to `(`. +* The `:;` and `-_` keys are now available on the base layer, on their [ADORE](#adore-layer) location, too, just below `[{(`/`]})`. +* The `Apps` key has been replaced by `F12`. +* The `-`/`_` is no longer a tap-dance key. + +### ADORE layer changes + +* Adjustments were made to the [ADORE](#adore-layer) layer, to separate some inconvenient combinations. + +### Miscellaneous changes + +* `LEAD u` now starts the symbolic unicode input system, instead of the OS-one. +* The mouse acceleration keys on the [Navigation and Media](#navigation-and-media-layer) layer have been turned into toggles: tap them once to turn them on, until tapped again. Tapping an accelerator button will turn all the others off. +* When the **ARROW** layer is on, the *red* and *blue* LEDs light up now. + +### Heatmap + +* The built-in keylogger has been greatly enhanced, it now outputs the pressed state, and the layer (Dvorak or ADORE). As such, the `ADORE_AUTOLOG` option has been removed, instead there is `AUTOLOG_ENABLE` now, which when enabled, makes the keylogger start when the keyboard boots. It defaults to off. +* The heatmap generator received a lot of updates. + +## v1.5 + +*2016-08-12*  * The **1HAND** layer has been removed.  * A `Delete` key is now available on the right thumb cluster. @@ -161,7 +194,9 @@ The keymap default to forcing NKRO, which seems to upset Windows, and except the  * On the **ARROW** layer, `Backspace` has been replaced by `Enter`.  * There is some experimental support for entering Unicode symbols. -## v1.4 - 2016-07-29 +## v1.4 + +*2016-07-29*  * When toggling the key logging on or off, the LEDs will do a little dance.  * The keylogger is now optional, but enabled by default. Use `KEYLOGGER_ENABLE=no` on the `make` command line to disable it. @@ -169,14 +204,18 @@ The keymap default to forcing NKRO, which seems to upset Windows, and except the  * The `-`/`_` key was turned into a tap-dance key too.  * There is now a way to travel time with the keyboard, toggle the feature on by hitting `LEAD t`. -## v1.3 - 2016-07-06 +## v1.3 + +*2016-07-06*  * Added support for logging keys, by pressing `LEAD d`. Also included is a tool to generate a [heatmap](#heatmap) out of the logs.  * The arrow and navigation keys were rearranged again, and now require an additional key being held to activate. See the [base layer](#base-layer) for an image that shows where arrows are.  * The **experimental** layer has been redone, and is now called [ADORE](#adore-layer), and as such, can be enabled by `LEAD a` now.  * Switching between Dvorak and ADORE is now persisted into EEPROM, and survives a reboot. -## v1.2 - 2016-06-22 +## v1.2 + +*2016-06-22*  * The forced NKRO mode can be easily toggled off at compile-time, to make the firmware compatible with [certain operating systems](#using-on-windows).  * The `:;` key has changed behaviour: to access the `;` symbol, the key needs to be double-tapped, instead of shifted. @@ -187,7 +226,9 @@ The keymap default to forcing NKRO, which seems to upset Windows, and except the  * On the **experimental** layer, the `L` and `Q`, and the `K` and `G` keys were swapped.  * The [Steno](#steno-layer) layer gained a few more `#` and `*` keys, to make it easier on my fingers. -## v1.1 - 2016-06-14 +## v1.1 + +*2016-06-14*  * The keyboard starts in NKRO mode, bootmagic and other things are disabled.  * A [Steno](#steno-layer) layer was added, to be used with Plover. @@ -201,7 +242,9 @@ The keymap default to forcing NKRO, which seems to upset Windows, and except the      - `:` now inputs `;` when shifted.  * `ESC` cancels the [Hungarian](#hungarian-layer) layer too, not just modifiers. -## v1.0 - 2016-05-26 +## v1.0 + +*2016-05-26*  Initial version. diff --git a/keyboards/ergodox/keymaps/algernon/tools/heatmap-adore-layout.json b/keyboards/ergodox/keymaps/algernon/tools/heatmap-layout.ADORE.json index 544f61ce87..4dfa877a78 100644 --- a/keyboards/ergodox/keymaps/algernon/tools/heatmap-adore-layout.json +++ b/keyboards/ergodox/keymaps/algernon/tools/heatmap-layout.ADORE.json @@ -75,9 +75,9 @@      "STENO",      {        "x": 4.5, -      "f": 6 +      "f": 3      }, -    "<i class='mss mss-Unicode-Option-3'></i>", +    "F12",      {        "c": "#7adabd",        "a": 4, @@ -94,12 +94,20 @@      {        "y": -0.875,        "c": "#ffb2d2", -      "f": 3, +      "f": 9, +      "a": 6,        "w": 1.5      }, -    "\n\n~\n`", +    "\n\n<i class='kb kb-Multimedia-Play-Pause'></i>",      { -      "t": "#0d0d0b" +      "t": "#0d0d0b", +      "f": 3, +      "a": 4, +      "fa": [ +          0, +          0, +          2 +      ]      },      "!\n1\nF1",      { @@ -120,7 +128,7 @@        "t": "#000000",        "a": 6      }, -    "L", +    "G",      {        "x": 10.5      }, @@ -132,16 +140,16 @@        "x": 2.5,        "c": "#bfbad1",        "t": "#0d0d0b", -      "a": 4 +      "a": 6      }, -    ">\n.", +    "W",      {        "x": 1,        "c": "#7adabd",        "t": "#000000",        "a": 6      }, -    "W", +    "L",      {        "x": 8.5      }, @@ -164,14 +172,15 @@      {        "c": "#93c9b7",        "a": 4, +      "fa": [0, 0, 0],        "h": 1.5      }, -    "{\n[", +    "{\n(\n[",      {        "x": 4.5,        "h": 1.5      }, -    "}\n]", +    "}\n)\n]",      {        "c": "#7adabd",        "a": 6 @@ -183,21 +192,22 @@        "y": -0.875,        "c": "#ffb07b",        "t": "#0d0d0b", -      "f": 6, +      "f": 3, +      "a": 4,        "w": 1.5      }, -    "<i class='fa fa-fast-backward'></i>\n\n<i class='fa fa-fast-forward'></i>", +    "\n\n~\n`",      {        "c": "#ffb2d2", -      "a": 4, +      "a": 6,        "f": 3      }, -    "<\n,", +    "Y",      {        "x": 14.5,        "a": 6      }, -    "Y", +    "X",      {        "a": 4,        "w": 1.5 @@ -300,15 +310,14 @@        "x": 6.5,        "c": "#93c9b7",        "t": "#000000", -      "a": 7,        "h": 1.5      }, -    "(", +    ";\n:",      {        "x": 4.5,        "h": 1.5      }, -    ")" +    "_\n-"    ],    [      { @@ -320,7 +329,9 @@      },      "\"\n'",      { -      "x": 10.5 +      "x": 10.5, +      "a": 6, +      "f": 3      },      "V"    ], @@ -329,19 +340,22 @@        "y": -0.875,        "x": 2.5,        "c": "#bfbad1", -      "t": "#0d0d0b" +      "t": "#0d0d0b", +      "a": 6      }, -    "Z", +    "Q",      {        "x": 1,        "c": "#7adabd", -      "t": "#000000" +      "t": "#000000", +      "a": 4      }, -    "K", +    "<\n,",      { -      "x": 8.5 +      "x": 8.5, +      "a": 6      }, -    "G", +    "K",      {        "x": 1,        "c": "#bfbad1", @@ -354,11 +368,13 @@        "y": -0.875,        "x": 5.5,        "c": "#7adabd", -      "t": "#000000" +      "t": "#000000", +      "a": 4      }, -    "X", +    ">\n.",      { -      "x": 6.5 +      "x": 6.5, +      "a": 6      },      "B"    ], @@ -367,28 +383,32 @@        "y": -0.875,        "c": "#ffb07b",        "f": 9, -      "w": 1.5 +      "w": 1.5, +      "g": true      }, -    "\n\n<i class='kb kb-Multimedia-Play-Pause'></i>", +    "",      {        "c": "#ffb2d2",        "t": "#0d0d0b", -      "a": 4, -      "f": 3 +      "a": 6, +      "f": 3, +      "g": false      }, -    "?\n/", +    "Z",      {        "x": 14.5, -      "a": 6 +      "a": 4      }, -    "Q", +    "?\n/",      {        "c": "#ffb07b",        "t": "#000000",        "f": 9, -      "w": 1.5 +      "g": true, +      "w": 1.5, +      "a": 4      }, -    "<i class='kb kb-Multimedia-Stop'></i>" +    ""    ],    [      { @@ -414,14 +434,14 @@      {        "x": 1,        "c": "#d4872a", -      "g": false, +      "g": true,        "a": 5      }, -    ";\n:", +    "",      {        "x": 8.5      }, -    "_\n-", +    "",      {        "x": 1,        "c": "#d9dae0", @@ -503,13 +523,13 @@      },      "MEDIA",      {}, -    "1HAND" +    "DEL"    ],    [      {        "x": -3      }, -    "LEAD", +    "HUN",      {        "c": "#d4872a",        "f": 9, @@ -528,6 +548,6 @@        "c": "#f9cd31",        "f": 2      }, -    "HUN" +    "LEAD"    ]  ] diff --git a/keyboards/ergodox/keymaps/algernon/tools/heatmap-base-layout.json b/keyboards/ergodox/keymaps/algernon/tools/heatmap-layout.Dvorak.json index 148bb1f23b..1248d36af7 100644 --- a/keyboards/ergodox/keymaps/algernon/tools/heatmap-base-layout.json +++ b/keyboards/ergodox/keymaps/algernon/tools/heatmap-layout.Dvorak.json @@ -75,9 +75,9 @@      "STENO",      {        "x": 4.5, -      "f": 6 +      "f": 3      }, -    "<i class='mss mss-Unicode-Option-3'></i>", +    "F12",      {        "c": "#7adabd",        "a": 4, @@ -94,12 +94,21 @@      {        "y": -0.875,        "c": "#ffb2d2", -      "f": 3, +      "f": 6, +      "a": 6,        "w": 1.5      }, -    "\n\n~\n`", +    "<i class='fa fa-fast-backward'></i>\n\n<i class='fa fa-fast-forward'></i>",      { -      "t": "#0d0d0b" +      "f": 3, +      "t": "#0d0d0b", +      "a": 4, +      "fa": [ +          0, +          0, +          2 +      ] +      },      "!\n1\nF1",      { @@ -167,12 +176,12 @@        "a": 4,        "h": 1.5      }, -    "{\n[", +    "{\n(\n[",      {        "x": 4.5,        "h": 1.5      }, -    "}\n]", +    "}\n)\n]",      {        "c": "#7adabd",        "a": 6 @@ -184,10 +193,10 @@        "y": -0.875,        "c": "#ffb07b",        "t": "#0d0d0b", -      "f": 6, +      "f": 3,        "w": 1.5      }, -    "<i class='fa fa-fast-backward'></i>\n\n<i class='fa fa-fast-forward'></i>", +    "\n\n~\n`",      {        "c": "#ffb2d2",        "a": 4, @@ -503,7 +512,7 @@      },      "MEDIA",      {}, -    "1HAND" +    "DEL"    ],    [      { diff --git a/keyboards/ergodox/keymaps/algernon/tools/log-to-heatmap.py b/keyboards/ergodox/keymaps/algernon/tools/log-to-heatmap.py index a13d12e81a..68585843be 100755 --- a/keyboards/ergodox/keymaps/algernon/tools/log-to-heatmap.py +++ b/keyboards/ergodox/keymaps/algernon/tools/log-to-heatmap.py @@ -3,143 +3,247 @@ import json  import os  import sys  import re +import argparse  from math import floor +from os.path import dirname + +class Heatmap(object): +    coords = [ +        [ +            # Row 0 +            [ 4,  0], [ 4,  2], [ 2,  0], [ 1,  0], [ 2,  2], [ 3,  0], [ 3,  2], +            [ 3,  4], [ 3,  6], [ 2,  4], [ 1,  2], [ 2,  6], [ 4,  4], [ 4,  6], +        ], +        [ +            # Row 1 +            [ 8,  0], [ 8,  2], [ 6,  0], [ 5,  0], [ 6,  2], [ 7,  0], [ 7,  2], +            [ 7,  4], [ 7,  6], [ 6,  4], [ 5,  2], [ 6,  6], [ 8,  4], [ 8,  6], +        ], +        [ +            # Row 2 +            [12,  0], [12,  2], [10,  0], [ 9,  0], [10,  2], [11, 0], [     ], +            [      ], [11,  2], [10,  4], [ 9,  2], [10,  6], [12, 4], [12, 6], +        ], +        [ +            # Row 3 +            [17,  0], [17,  2], [15,  0], [14,  0], [15,  2], [16,  0], [13,  0], +            [13,  2], [16,  2], [15,  4], [14,  2], [15,  6], [17,  4], [17,  6], +        ], +        [ +            # Row 4 +            [20,  0], [20,  2], [19,  0], [18,  0], [19,  2], [], [], [], [], +            [19,  4], [18,  2], [19,  6], [20,  4], [20,  6], +        ], +        [ +            # Row 5 +            [     ], [23,  0], [22,  2], [22,  0], [22,  4], [21,  0], [21,  2], +            [24, 0], [24,  2], [25,  0], [25,  4], [25,  2], [26,  0], [      ], +        ], +    ] + +    def set_attr_at(self, block, n, attr, fn, val): +        blk = self.heatmap[block][n] +        if attr in blk: +            blk[attr] = fn(blk[attr], val) +        else: +            blk[attr] = fn(None, val) + +    def coord(self, col, row): +        return self.coords[row][col] + +    @staticmethod +    def set_attr(orig, new): +        return new + +    def set_bg(self, (block, n), color): +        self.set_attr_at(block, n, "c", self.set_attr, color) +        #self.set_attr_at(block, n, "g", self.set_attr, False) + +    def set_tap_info(self, (block, n), count, cap): +        def _set_tap_info(o, _count, _cap): +            ns = 4 - o.count ("\n") +            return o + "\n" * ns + "%.02f%%" % (float(_count) / float(_cap) * 100) + +        if not cap: +            cap = 1 +        self.heatmap[block][n + 1] = _set_tap_info (self.heatmap[block][n + 1], count, cap) + +    @staticmethod +    def heatmap_color (v): +        colors = [ [0.3, 0.3, 1], [0.3, 1, 0.3], [1, 1, 0.3], [1, 0.3, 0.3]] +        fb = 0 +        if v <= 0: +            idx1, idx2 = 0, 0 +        elif v >= 1: +            idx1, idx2 = len(colors) - 1, len(colors) - 1 +        else: +            val = v * (len(colors) - 1) +            idx1 = int(floor(val)) +            idx2 = idx1 + 1 +            fb = val - float(idx1) + +        r = (colors[idx2][0] - colors[idx1][0]) * fb + colors[idx1][0] +        g = (colors[idx2][1] - colors[idx1][1]) * fb + colors[idx1][1] +        b = (colors[idx2][2] - colors[idx1][2]) * fb + colors[idx1][2] + +        r, g, b = [x * 255 for x in r, g, b] +        return "#%02x%02x%02x" % (r, g, b) + +    def __init__(self, layout): +        self.log = {} +        self.total = 0 +        self.max_cnt = 0 +        self.layout = layout + +    def update_log(self, (c, r)): +        if not (c, r) in self.log: +            self.log[(c, r)] = 0 +        self.log[(c, r)] = self.log[(c, r)] + 1 +        self.total = self.total + 1 +        if self.max_cnt < self.log[(c, r)]: +            self.max_cnt = self.log[(c, r)] + +    def get_heatmap(self): +        with open("%s/heatmap-layout.%s.json" % (dirname(sys.argv[0]), self.layout), "r") as f: +            self.heatmap = json.load (f) + +        ## Reset colors +        for row in self.coords: +            for coord in row: +                if coord != []: +                    self.set_bg (coord, "#d9dae0") + +        for (c, r) in self.log: +            coords = self.coord(c, r) +            b, n = coords +            cap = self.max_cnt +            if cap == 0: +                cap = 1 +            v = float(self.log[(c, r)]) / cap +            self.set_bg (coords, self.heatmap_color (v)) +            self.set_tap_info (coords, self.log[(c, r)], self.total) +        return self.heatmap + +    def get_stats(self): +        usage = [ +            # left hand +            [0, 0, 0, 0, 0], +            # right hand +            [0, 0, 0, 0, 0] +        ] +        finger_map = [0, 0, 1, 2, 3, 4, 4] +        for (c, r) in self.log: +            if r == 5: # thumb cluster +                if c <= 6: # left side +                    usage[0][4] = usage[0][4] + self.log[(c, r)] +                else: +                    usage[1][4] = usage[1][4] + self.log[(c, r)] +            else: +                fc = c +                hand = 0 +                if fc >= 7: +                    fc = fc - 7 +                    hand = 1 +                fm = finger_map[fc] +                usage[hand][fm] = usage[hand][fm] + self.log[(c, r)] +        hand_usage = [0, 0] +        for f in usage[0]: +            hand_usage[0] = hand_usage[0] + f +        for f in usage[1]: +            hand_usage[1] = hand_usage[1] + f + +        total = self.total +        if total == 0: +            total = 1 +        stats = { +            "hands": { +                "left": { +                    "usage": float(hand_usage[0]) / total * 100, +                    "fingers": { +                        "0 - pinky": 0, +                        "1 - ring": 0, +                        "2 - middle": 0, +                        "3 - index": 0, +                        "4 - thumb": 0, +                    } +                }, +                "right": { +                    "usage": float(hand_usage[1]) / total * 100, +                    "fingers": { +                        "0 - thumb": 0, +                        "1 - index": 0, +                        "2 - middle": 0, +                        "3 - ring": 0, +                        "4 - pinky": 0, +                    } +                }, +            } +        } + +        hmap = ['left', 'right'] +        fmap = ['0 - pinky', '1 - ring', '2 - middle', '3 - index', '4 - thumb', +                '0 - thumb', '1 - index', '2 - middle', '3 - ring', '4 - pinky'] +        for hand_idx in range(len(usage)): +            hand = usage[hand_idx] +            for finger_idx in range(len(hand)): +                stats['hands'][hmap[hand_idx]]['fingers'][fmap[finger_idx + hand_idx * 5]] = float(hand[finger_idx]) / total * 100 +        return stats + +def dump_all(out_dir, heatmaps): +    for layer in heatmaps.keys(): +        if len(heatmaps[layer].log) == 0: +            continue -cr_coord_map = [ -    [ -        # Row 0 -        [ 4,  0], [ 4,  2], [ 2,  0], [ 1,  0], [ 2,  2], [ 3,  0], [ 3,  2], -        [ 3,  4], [ 3,  6], [ 2,  4], [ 1,  2], [ 2,  6], [ 4,  4], [ 4,  6], -    ], -    [ -        # Row 1 -        [ 8,  0], [ 8,  2], [ 6,  0], [ 5,  0], [ 6,  2], [ 7,  0], [ 7,  2], -        [ 7,  4], [ 7,  6], [ 6,  4], [ 5,  2], [ 6,  6], [ 8,  4], [ 8,  6], -    ], -    [ -        # Row 2 -        [12,  0], [12,  2], [10,  0], [ 9,  0], [10,  2], [11, 0], [     ], -        [      ], [11,  2], [10,  4], [ 9,  2], [10,  6], [12, 4], [12, 6], -    ], -    [ -        # Row 3 -        [17,  0], [17,  2], [15,  0], [14,  0], [15,  2], [16,  0], [13,  0], -        [13,  2], [16,  2], [15,  4], [14,  2], [15,  6], [17,  4], [17,  6], -    ], -    [ -        # Row 4 -        [20,  0], [20,  2], [19,  0], [18,  0], [19,  2], [], [], [], [], -        [19,  4], [18,  2], [19,  6], [20,  4], [20,  6], -    ], -    [ -        # Row 5 -        [     ], [23,  0], [22,  2], [22,  0], [22,  4], [21,  0], [21,  2], -        [24, 0], [24,  2], [25,  0], [25,  4], [25,  2], [26,  0], [      ], -    ], -] - -def set_attr_at(j, b, n, attr, fn, val): -    blk = j[b][n] -    if attr in blk: -        blk[attr] = fn(blk[attr], val) -    else: -        blk[attr] = fn(None, val) - -def coord(col, row): -    return cr_coord_map[row][col] - -def set_attr(orig, new): -    return new - -def set_bg(j, (b, n), color): -    set_attr_at(j, b, n, "c", set_attr, color) -    #set_attr_at(j, b, n, "g", set_attr, False) - -def _set_tap_info(o, count, cap): -    ns = 4 - o.count ("\n") -    return o + "\n" * ns + "%.02f%%" % (float(count) / float(cap) * 100) - -def set_tap_info(j, (b, n), count, cap): -    j[b][n + 1] = _set_tap_info (j[b][n + 1], count, cap) - -def heatmap_color (v): -    colors = [ [0.3, 0.3, 1], [0.3, 1, 0.3], [1, 1, 0.3], [1, 0.3, 0.3]] -    fb = 0 -    if v <= 0: -        idx1, idx2 = 0, 0 -    elif v >= 1: -        idx1, idx2 = len(colors) - 1, len(colors) - 1 -    else: -        val = v * (len(colors) - 1) -        idx1 = int(floor(val)) -        idx2 = idx1 + 1 -        fb = val - float(idx1) - -    r = (colors[idx2][0] - colors[idx1][0]) * fb + colors[idx1][0] -    g = (colors[idx2][1] - colors[idx1][1]) * fb + colors[idx1][1] -    b = (colors[idx2][2] - colors[idx1][2]) * fb + colors[idx1][2] - -    r, g, b = [x * 255 for x in r, g, b] -    return "#%02x%02x%02x" % (r, g, b) - -# Load the keylog -def load_keylog(fname, restrict_row): -    keylog = {} -    total = 0 -    with open(fname, "r") as f: -        lines = f.readlines() -    for line in lines: -        m = re.search ('KL: col=(\d+), row=(\d+)', line) +        with open ("%s/%s.json" % (out_dir, layer), "w") as f: +            json.dump(heatmaps[layer].get_heatmap(), f) +        print >>sys.stderr, "%s stats:" % (layer) +        json.dump (heatmaps[layer].get_stats(), sys.stderr, +                   indent = 4, sort_keys = True) +        print >>sys.stderr, "" +        print >>sys.stderr, "" + +def main(opts): + +    heatmaps = {"Dvorak": Heatmap("Dvorak"), +                "ADORE": Heatmap("ADORE") +    } +    cnt = 0 +    restrict_row = opts.restrict_row +    out_dir = opts.outdir + +    while True: +        line = sys.stdin.readline() +        if not line: +            break +        m = re.search ('KL: col=(\d+), row=(\d+), pressed=(\d+), layer=(.*)', line)          if not m:              continue -        (c, r) = (int(m.group (2)), int(m.group (1))) -        if restrict_row != None and r != int(restrict_row): + +        cnt = cnt + 1 +        (c, r, l) = (int(m.group (2)), int(m.group (1)), m.group (4)) +        if restrict_row != -1 and r != restrict_row: +            continue +        if c in opts.ignore_columns:              continue -        if (c, r) in keylog: -            keylog[(c, r)] = keylog[(c, r)] + 1 -        else: -            keylog[(c, r)] = 1 -        total = total + 1 -    return total / 2, keylog - -def l_flat(s): -    f = s.split("\n") -    return ", ".join (f) - -def main(base_fn, log_fn, restrict_row = None): - -    with open(base_fn, "r") as f: -        layout = json.load (f) - -    ## Reset colors -    for row in cr_coord_map: -        for col in row: -            if col != []: -                set_bg (layout, col, "#d9dae0") -                #set_attr_at (layout, col[0], col[1], "g", set_attr, True) - -    total, log = load_keylog (log_fn, restrict_row) -    max_cnt = 0 -    for (c, r) in log: -        max_cnt = max(max_cnt, log[(c, r)]) - -    # Create the heatmap -    for (c, r) in log: -        coords = coord(c, r) -        b, n = coords -        cap = max_cnt -        v = float(log[(c, r)]) / cap -        print >> sys.stderr, "%s => %d/%d => %f = %s" % (l_flat(layout[b][n+1]), log[(c,r)], cap, v, heatmap_color(v)) -        set_bg (layout, coord(c, r), heatmap_color (v)) -        set_tap_info (layout, coord (c, r), log[(c, r)], total) - -    print json.dumps(layout) -if __name__ == "__main__": -    if len(sys.argv) < 3: -        print """Log to Heatmap -- creates a heatmap out of keyboard logs +        heatmaps[l].update_log ((c, r)) + +        if opts.dump_interval != -1 and cnt >= opts.dump_interval: +            cnt = 0 +            dump_all(out_dir, heatmaps) -Usage: log-to-heatmap.py base-layout.json logfile [row] >layout.json""" -        sys.exit (1) -    main(*sys.argv[1:]) +    dump_all (out_dir, heatmaps) + +if __name__ == "__main__": +    parser = argparse.ArgumentParser (description = "keylog to heatmap processor") +    parser.add_argument ('outdir', action = 'store', +                         help = 'Output directory') +    parser.add_argument ('--row', dest = 'restrict_row', action = 'store', type = int, +                         default = -1, help = 'Restrict processing to this row only') +    parser.add_argument ('--dump-interval', dest = 'dump_interval', action = 'store', type = int, +                         default = 100, help = 'Dump stats and heatmap at every Nth event, -1 for dumping at EOF only') +    parser.add_argument ('--ignore-column', dest = 'ignore_columns', action = 'append', type = int, +                         default = [], help = 'Ignore the specified columns') +    args = parser.parse_args() +    main(args) | 
