~ruther/qmk_firmware

1a8c0dd22d6a2255511d0db6a456315541b5815b — Erez Zukerman 9 years ago 79d26f3
Leader key implementation (#326)

* implements leader key for planck experimental

* allows override of leader timeout

* adds ability to use the leader key in seq

* fixes leader keycode

* adds chording prototype

* fixes keycode detection

* moves music mode to quantum.c

* disables chording by default

* updates process_action functions to return bool
M keyboard/atomic/atomic.c => keyboard/atomic/atomic.c +4 -3
@@ 11,8 11,9 @@ void matrix_scan_user(void) {
}

__attribute__ ((weak))
void process_action_user(keyrecord_t *record) {
bool process_action_user(keyrecord_t *record) {
    // leave this function blank - it can be defined in a keymap file
    return true;
}

__attribute__ ((weak))


@@ 45,11 46,11 @@ void matrix_scan_kb(void) {
    matrix_scan_user();
}

void process_action_kb(keyrecord_t *record) {
bool process_action_kb(keyrecord_t *record) {
    // put your per-action keyboard code here
    // runs for every action, just before processing by the firmware

    process_action_user(record);
    return process_action_user(record);
}

void led_set_kb(uint8_t usb_led) {

M keyboard/atomic/atomic.h => keyboard/atomic/atomic.h +1 -1
@@ 29,7 29,7 @@

void matrix_init_user(void);
void matrix_scan_user(void);
void process_action_user(keyrecord_t *record);
bool process_action_user(keyrecord_t *record);
void led_set_user(uint8_t usb_led);
void backlight_init_ports(void);


M keyboard/gh60_rev_c/gh60.c => keyboard/gh60_rev_c/gh60.c +4 -3
@@ 12,8 12,9 @@ void matrix_scan_user(void) {
}

__attribute__ ((weak))
void process_action_user(keyrecord_t *record) {
bool process_action_user(keyrecord_t *record) {
	// leave this function blank - it can be defined in a keymap file
	return true;
}

__attribute__ ((weak))


@@ 35,11 36,11 @@ void matrix_scan_kb(void) {
	matrix_scan_user();
}

void process_action_kb(keyrecord_t *record) {
bool process_action_kb(keyrecord_t *record) {
	// put your per-action keyboard code here
	// runs for every action, just before processing by the firmware

	process_action_user(record);
	return process_action_user(record);
}

void led_set_kb(uint8_t usb_led) {

M keyboard/gh60_rev_c/gh60.h => keyboard/gh60_rev_c/gh60.h +1 -1
@@ 75,7 75,7 @@ inline void gh60_wasd_leds_off(void)   	{ DDRF &= ~(1<<7); PORTF &= ~(1<<7); }

void matrix_init_user(void);
void matrix_scan_user(void);
void process_action_user(keyrecord_t *record);
bool process_action_user(keyrecord_t *record);
void led_set_user(uint8_t usb_led);

#endif

M keyboard/planck/keymaps/experimental/keymap.c => keyboard/planck/keymaps/experimental/keymap.c +30 -18
@@ 6,6 6,7 @@
#ifdef AUDIO_ENABLE
  #include "audio.h"
#endif

#include "eeconfig.h"

extern keymap_config_t keymap_config;


@@ 78,7 79,7 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
  {KC_TAB,  KC_Q,    KC_W,    KC_F,    KC_P,    KC_G,    KC_J,    KC_L,    KC_U,    KC_Y,    KC_SCLN, KC_BSPC},
  {KC_ESC,  KC_A,    KC_R,    KC_S,    KC_T,    KC_D,    KC_H,    KC_N,    KC_E,    KC_I,    KC_O,    KC_QUOT},
  {KC_LSFT, KC_Z,    KC_X,    KC_C,    KC_V,    KC_B,    KC_K,    KC_M,    KC_COMM, KC_DOT,  KC_SLSH, KC_ENT },
  {M(M_BL), KC_LCTL, KC_LALT, KC_LGUI, LOWER,   KC_SPC,  KC_SPC,  RAISE,   KC_LEFT, KC_DOWN, KC_UP,   KC_RGHT}
  {KC_LEAD, KC_LCTL, KC_LALT, KC_LGUI, LOWER,   KC_SPC,  KC_SPC,  RAISE,   KC_LEFT, KC_DOWN, KC_UP,   KC_RGHT}
},

/* Dvorak


@@ 291,7 292,7 @@ const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt)
        case 8:
          if (record->event.pressed) {
            #ifdef AUDIO_ENABLE
              layer_off(_MUSIC);
              music_activated = false;
              stop_all_notes();
            #endif
          }


@@ 300,7 301,7 @@ const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt)
          if (record->event.pressed) {
            #ifdef AUDIO_ENABLE
              PLAY_NOTE_ARRAY(music_scale, false, 0);
              layer_on(_MUSIC);
              music_activated = true;
            #endif
          }
        break;


@@ 360,24 361,35 @@ void matrix_init_user(void) {
}

#ifdef AUDIO_ENABLE
void play_goodbye_tone()
{
  PLAY_NOTE_ARRAY(goodbye, false, 0);
  _delay_ms(150);
}
  void play_goodbye_tone(void)
  {
    PLAY_NOTE_ARRAY(goodbye, false, 0);
    _delay_ms(150);
  }
#endif

uint8_t starting_note = 0x0C;
int offset = 0;
LEADER_EXTERNS();

void process_action_user(keyrecord_t *record) {
#define LEADER_TIMEOUT 300

  if (IS_LAYER_ON(_MUSIC)) {
    if (record->event.pressed) {
        play_note(((double)220.0)*pow(2.0, -4.0)*pow(2.0,(starting_note + SCALE[record->event.key.col + offset])/12.0+(MATRIX_ROWS - record->event.key.row)), 0xF);
    } else {
        stop_note(((double)220.0)*pow(2.0, -4.0)*pow(2.0,(starting_note + SCALE[record->event.key.col + offset])/12.0+(MATRIX_ROWS - record->event.key.row)));
void matrix_scan_user(void) {
  LEADER_DICTIONARY() { 
    leading = false;
    leader_end(); 

    SEQ_ONE_KEY(KC_F) {
      register_code(KC_S);
      unregister_code(KC_S);
    }
    SEQ_TWO_KEYS(KC_A, KC_S) {
      register_code(KC_H);
      unregister_code(KC_H);
    }
    SEQ_THREE_KEYS(KC_A, KC_S, KC_D) {
      register_code(KC_LGUI);
      register_code(KC_S);
      unregister_code(KC_S);
      unregister_code(KC_LGUI);
    }
  }

}
#endif

M keyboard/planck/planck.c => keyboard/planck/planck.c +5 -3
@@ 7,7 7,9 @@ __attribute__ ((weak))
void matrix_scan_user(void) {}

__attribute__ ((weak))
void process_action_user(keyrecord_t *record) {}
bool process_action_user(keyrecord_t *record) {
    return true;
}

__attribute__ ((weak))
void led_set_user(uint8_t usb_led) {}


@@ 32,8 34,8 @@ void matrix_scan_kb(void) {
	matrix_scan_user();
}

void process_action_kb(keyrecord_t *record) {
	process_action_user(record);
bool process_action_kb(keyrecord_t *record) {
	return process_action_user(record);
}

void led_set_kb(uint8_t usb_led) {

M keyboard/planck/planck.h => keyboard/planck/planck.h +2 -14
@@ 1,19 1,7 @@
#ifndef PLANCK_H
#define PLANCK_H

#include "matrix.h"
#include "keymap_common.h"
#ifdef BACKLIGHT_ENABLE
	#include "backlight.h"
#endif
#ifdef RGBLIGHT_ENABLE
  #include "rgblight.h"
#endif
#include <stddef.h>
#include <avr/io.h>
#ifdef MIDI_ENABLE
	#include <keymap_midi.h>
#endif
#include "quantum.h"

#define PLANCK_MIT( \
	k00, k01, k02, k03, k04, k05, k06, k07, k08, k09, k0a, k0b, \


@@ 43,7 31,7 @@

void matrix_init_user(void);
void matrix_scan_user(void);
void process_action_user(keyrecord_t *record);
bool process_action_user(keyrecord_t *record);

void led_set_user(uint8_t usb_led);
void backlight_init_ports(void);

M keyboard/preonic/preonic.c => keyboard/preonic/preonic.c +4 -4
@@ 11,8 11,8 @@ void matrix_scan_user(void) {
};

__attribute__ ((weak))
void process_action_user(keyrecord_t *record) {

bool process_action_user(keyrecord_t *record) {
    return true;
};

void matrix_init_kb(void) {


@@ 36,8 36,8 @@ void matrix_scan_kb(void) {
	matrix_scan_user();
};

void process_action_kb(keyrecord_t *record) {
	process_action_user(record);
bool process_action_kb(keyrecord_t *record) {
	return process_action_user(record);
}

#ifdef BACKLIGHT_ENABLE

M keyboard/preonic/preonic.h => keyboard/preonic/preonic.h +1 -1
@@ 47,6 47,6 @@

void matrix_init_user(void);
void matrix_scan_user(void);
void process_action_kb(keyrecord_t *record);
bool process_action_kb(keyrecord_t *record);

#endif

M quantum/keymap_common.c => quantum/keymap_common.c +1 -1
@@ 251,7 251,7 @@ static action_t keycode_to_action(uint16_t keycode)
            }
            eeconfig_update_keymap(keymap_config.raw);
            break;
        case 0x5100 ... 0x5FFF: ;
        case 0x5100 ... 0x56FF: ;
            // Layer movement shortcuts
            // See .h to see constraints/usage
            int type = (keycode >> 0x8) & 0xF;

M quantum/keymap_common.h => quantum/keymap_common.h +3 -1
@@ 159,7 159,7 @@ extern const uint16_t fn_actions[];
#define S(kc) LSFT(kc)
#define F(kc) FUNC(kc)

#define M(kc) kc | 0x3000
#define M(kc) (kc | 0x3000)

#define MACRODOWN(...) (record->event.pressed ? MACRO(__VA_ARGS__) : MACRO_NONE)



@@ 191,6 191,8 @@ extern const uint16_t fn_actions[];

#define RESET 0x5000
#define DEBUG 0x5001
#define KC_LEAD 0x5014


// MAGIC keycodes
#define MAGIC_SWAP_CONTROL_CAPSLOCK      0x5002

M quantum/matrix.c => quantum/matrix.c +4 -4
@@ 55,12 55,12 @@ static void unselect_rows(void);
static void select_row(uint8_t row);

__attribute__ ((weak))
void matrix_init_kb(void) {
void matrix_init_quantum(void) {

}

__attribute__ ((weak))
void matrix_scan_kb(void) {
void matrix_scan_quantum(void) {

}



@@ 93,7 93,7 @@ void matrix_init(void)
        matrix_debouncing[i] = 0;
    }

    matrix_init_kb();
    matrix_init_quantum();
}




@@ 157,7 157,7 @@ uint8_t matrix_scan(void)
    }
#endif

    matrix_scan_kb();
    matrix_scan_quantum();

    return 1;
}

A quantum/quantum.c => quantum/quantum.c +167 -0
@@ 0,0 1,167 @@
#include "quantum.h"

__attribute__ ((weak))
void matrix_init_kb(void) {}

__attribute__ ((weak))
void matrix_scan_kb(void) {}

__attribute__ ((weak))
bool process_action_kb(keyrecord_t *record) {
  return true;
}

__attribute__ ((weak))
void leader_start(void) {}

__attribute__ ((weak))
void leader_end(void) {}

#ifdef AUDIO_ENABLE
  uint8_t starting_note = 0x0C;
  int offset = 0;
  bool music_activated = false;
#endif

// Leader key stuff
bool leading = false;
uint16_t leader_time = 0;

uint16_t leader_sequence[3] = {0, 0, 0};
uint8_t leader_sequence_size = 0;

// Chording stuff
#define CHORDING_MAX 4
bool chording = false;

uint8_t chord_keys[CHORDING_MAX] = {0};
uint8_t chord_key_count = 0;
uint8_t chord_key_down = 0;

bool keys_chord(uint8_t keys[]) {
  uint8_t keys_size = sizeof(keys)/sizeof(keys[0]);
  bool pass = true;
  uint8_t in = 0;
  for (uint8_t i = 0; i < chord_key_count; i++) {
    bool found = false;
    for (uint8_t j = 0; j < keys_size; j++) {
      if (chord_keys[i] == (keys[j] & 0xFF)) {
        in++; // detects key in chord
        found = true;
        break;
      }
    }
    if (found)
      continue;
    if (chord_keys[i] != 0)  {
      pass = false; // makes sure rest are blank
    }
  }
  return (pass && (in == keys_size));
}

bool process_action_quantum(keyrecord_t *record) {

  /* This gets the keycode from the key pressed */
  keypos_t key = record->event.key;
  uint16_t keycode;

  #if !defined(NO_ACTION_LAYER) && defined(PREVENT_STUCK_MODIFIERS)
    uint8_t layer;

    if (record->event.pressed) {
      layer = layer_switch_get_layer(key);
      update_source_layers_cache(key, layer);
    } else {
      layer = read_source_layers_cache(key);
    }
    keycode = keymap_key_to_keycode(layer, key);
  #else
    keycode = keymap_key_to_keycode(layer_switch_get_layer(key), key);
  #endif

  #ifdef AUDIO_ENABLE
    if (music_activated) {
      if (record->event.pressed) {
          play_note(((double)220.0)*pow(2.0, -4.0)*pow(2.0,(starting_note + SCALE[record->event.key.col + offset])/12.0+(MATRIX_ROWS - record->event.key.row)), 0xF);
      } else {
          stop_note(((double)220.0)*pow(2.0, -4.0)*pow(2.0,(starting_note + SCALE[record->event.key.col + offset])/12.0+(MATRIX_ROWS - record->event.key.row)));
      }
      if (keycode < 0xFF) // ignores all normal keycodes, but lets RAISE, LOWER, etc through
        return false;
    }
  #endif



#ifndef DISABLE_LEADER
  // Leader key set-up
  if (record->event.pressed) {
    if (!leading && keycode == KC_LEAD) {
      leader_start();
      leading = true;
      leader_time = timer_read();
      leader_sequence_size = 0;
      leader_sequence[0] = 0;
      leader_sequence[1] = 0;
      leader_sequence[2] = 0;
      return false;
    }
    if (leading && timer_elapsed(leader_time) < LEADER_TIMEOUT) {
      leader_sequence[leader_sequence_size] = keycode;
      leader_sequence_size++;
      return false;
    }
  }
#endif

#define DISABLE_CHORDING
#ifndef DISABLE_CHORDING

  if (keycode >= 0x5700 && keycode <= 0x57FF) {
    if (record->event.pressed) {
      if (!chording) {
        chording = true;
        for (uint8_t i = 0; i < CHORDING_MAX; i++)
          chord_keys[i] = 0;
        chord_key_count = 0;
        chord_key_down = 0;
      }
      chord_keys[chord_key_count] = (keycode & 0xFF);
      chord_key_count++;
      chord_key_down++;
      return false;
    } else {
      if (chording) {
        chord_key_down--;
        if (chord_key_down == 0) {
          chording = false;
          // Chord Dictionary
          if (keys_chord((uint8_t[]){KC_ENTER, KC_SPACE})) {
            register_code(KC_A);
            unregister_code(KC_A);
            return false;
          }
          for (uint8_t i = 0; i < chord_key_count; i++) {
            register_code(chord_keys[i]);
            unregister_code(chord_keys[i]);
            return false;
          }
        }
      }
    }
  }

#endif


  return process_action_kb(record);
}

void matrix_init_quantum() {
  matrix_init_kb();
}

void matrix_scan_quantum() {
  matrix_scan_kb();
}
\ No newline at end of file

A quantum/quantum.h => quantum/quantum.h +48 -0
@@ 0,0 1,48 @@
#ifndef QUANTUM_H
#define QUANTUM_H

#include "matrix.h"
#include "keymap_common.h"
#ifdef BACKLIGHT_ENABLE
    #include "backlight.h"
#endif
#ifdef RGBLIGHT_ENABLE
  #include "rgblight.h"
#endif
#ifdef AUDIO_ENABLE
  #include "audio.h"
#endif
#ifdef MIDI_ENABLE
	#include <keymap_midi.h>
#endif
#include "action_layer.h"
#include "eeconfig.h"
#include <stddef.h>
#include <avr/io.h>

extern uint32_t default_layer_state;

#ifndef NO_ACTION_LAYER
	extern uint32_t layer_state;
#endif

bool music_activated;

void matrix_init_kb(void);
void matrix_scan_kb(void);
bool process_action_kb(keyrecord_t *record);

void leader_start(void);
void leader_end(void);

#ifndef LEADER_TIMEOUT
	#define LEADER_TIMEOUT 200
#endif
#define SEQ_ONE_KEY(key) if (leader_sequence[0] == (key) && leader_sequence[1] == 0 && leader_sequence[2] == 0)
#define SEQ_TWO_KEYS(key1, key2) if (leader_sequence[0] == (key1) && leader_sequence[1] == (key2) && leader_sequence[2] == 0)
#define SEQ_THREE_KEYS(key1, key2, key3) if (leader_sequence[0] == (key1) && leader_sequence[1] == (key2) && leader_sequence[2] == (key3))

#define LEADER_EXTERNS() extern bool leading; extern uint16_t leader_time; extern uint16_t leader_sequence[3]; extern uint8_t leader_sequence_size
#define LEADER_DICTIONARY() if (leading && timer_elapsed(leader_time) > LEADER_TIMEOUT)

#endif
\ No newline at end of file

M quantum/quantum.mk => quantum/quantum.mk +2 -1
@@ 1,7 1,8 @@
QUANTUM_DIR = quantum

# # project specific files
SRC += $(QUANTUM_DIR)/keymap_common.c \
SRC += $(QUANTUM_DIR)/quantum.c \
	$(QUANTUM_DIR)/keymap_common.c \
	$(QUANTUM_DIR)/led.c

# ifdef KEYMAP_FILE

M quantum/template/template.c => quantum/template/template.c +4 -3
@@ 11,8 11,9 @@ void matrix_scan_user(void) {
}

__attribute__ ((weak))
void process_action_user(keyrecord_t *record) {
bool process_action_user(keyrecord_t *record) {
	// leave this function blank - it can be defined in a keymap file
    return true;
}

__attribute__ ((weak))


@@ 34,11 35,11 @@ void matrix_scan_kb(void) {
	matrix_scan_user();
}

void process_action_kb(keyrecord_t *record) {
bool process_action_kb(keyrecord_t *record) {
	// put your per-action keyboard code here
	// runs for every action, just before processing by the firmware

	process_action_user(record);
	return process_action_user(record);
}

void led_set_kb(uint8_t usb_led) {

M quantum/template/template.h => quantum/template/template.h +1 -1
@@ 24,7 24,7 @@

void matrix_init_user(void);
void matrix_scan_user(void);
void process_action_user(keyrecord_t *record);
bool process_action_user(keyrecord_t *record);
void led_set_user(uint8_t usb_led);

#endif

M tmk_core/common/action.c => tmk_core/common/action.c +5 -2
@@ 70,7 70,9 @@ void process_action_nocache(keyrecord_t *record)
#endif

__attribute__ ((weak))
void process_action_kb(keyrecord_t *record) {}
bool process_action_quantum(keyrecord_t *record) {
    return true;
}

void process_action(keyrecord_t *record)
{


@@ 89,7 91,8 @@ void process_action(keyrecord_t *record)
    }
#endif

    process_action_kb(record);
    if (!process_action_quantum(record))
        return;

    action_t action = store_or_get_action(event.pressed, event.key);
    dprint("ACTION: "); debug_action(action);

M tmk_core/common/action.h => tmk_core/common/action.h +1 -1
@@ 59,7 59,7 @@ const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt);
void action_function(keyrecord_t *record, uint8_t id, uint8_t opt);

/* keyboard-specific key event (pre)processing */
void process_action_kb(keyrecord_t *record);
bool process_action_quantum(keyrecord_t *record);

/* Utilities for actions.  */
#if !defined(NO_ACTION_LAYER) && defined(PREVENT_STUCK_MODIFIERS)

M tmk_core/common/matrix.h => tmk_core/common/matrix.h +2 -2
@@ 64,8 64,8 @@ void matrix_power_up(void);
void matrix_power_down(void);

/* keyboard-specific setup/loop functionality */
void matrix_init_kb(void);
void matrix_scan_kb(void);
void matrix_init_quantum(void);
void matrix_scan_quantum(void);

#ifdef __cplusplus
}