bool are_hashed_keycodes_in_sound(HASH_TYPE keycodes_hash, HASH_TYPE sound) { return (keycodes_hash & sound) == keycodes_hash; } uint8_t keycode_to_index(uint16_t keycode) { return keycode - FIRST_INTERNAL_KEYCODE; } void sound_keycode_array(uint16_t keycode) { uint8_t index = keycode_to_index(keycode); keycode_index++; keycodes_buffer_array[index] = keycode_index; } void silence_keycode_hash_array(HASH_TYPE keycode_hash) { for (int i = 0; i < NUMBER_OF_KEYS; i++) { bool index_in_hash = ((HASH_TYPE) 1 << i) & keycode_hash; if (index_in_hash) { uint8_t current_val = keycodes_buffer_array[i]; keycodes_buffer_array[i] = 0; for (int j = 0; j < NUMBER_OF_KEYS; j++) { if (keycodes_buffer_array[j] > current_val) { keycodes_buffer_array[j]--; } } keycode_index--; } } } bool are_hashed_keycodes_in_array(HASH_TYPE keycode_hash) { for (int i = 0; i < NUMBER_OF_KEYS; i++) { bool index_in_hash = ((HASH_TYPE) 1 << i) & keycode_hash; bool index_in_array = (bool) keycodes_buffer_array[i]; if (index_in_hash && !index_in_array) { return false; } } return true; } void kill_one_shots(void) { struct Chord chord_storage; struct Chord* chord_ptr; struct Chord* chord; for (int i = 0; i < NUMBER_OF_CHORDS; i++) { chord_ptr = (struct Chord*) pgm_read_word (&list_of_chords[i]); memcpy_P(&chord_storage, chord_ptr, sizeof(struct Chord)); chord = &chord_storage; if (*chord->state == IN_ONE_SHOT) { *chord->state = RESTART; chord->function(chord); if (*chord->state == RESTART) { *chord->state = IDLE; } } } } void process_finished_dances(void) { struct Chord chord_storage; struct Chord* chord_ptr; struct Chord* chord; for (int i = 0; i < NUMBER_OF_CHORDS; i++) { chord_ptr = (struct Chord*) pgm_read_word (&list_of_chords[i]); memcpy_P(&chord_storage, chord_ptr, sizeof(struct Chord)); chord = &chord_storage; if (*chord->state == ACTIVATED) { *chord->state = PRESS_FROM_ACTIVE; chord->function(chord); if (a_key_went_through) { kill_one_shots(); } dance_timer = timer_read(); } else if (*chord->state == IDLE_IN_DANCE) { *chord->state = FINISHED; chord->function(chord); if (*chord->state == FINISHED) { *chord->state = RESTART; if (*chord->state == RESTART) { *chord->state = IDLE; } } } else if (*chord->state == PRESS_FROM_ACTIVE) { *chord->state = FINISHED_FROM_ACTIVE; chord->function(chord); if (a_key_went_through) { kill_one_shots(); } dance_timer = timer_read(); } } } uint8_t keycodes_buffer_array_min(uint8_t* first_keycode_index) { for (int i = 0; i < NUMBER_OF_KEYS; i++) { if (keycodes_buffer_array[i] == 1) { if (first_keycode_index != NULL) { *first_keycode_index = (uint8_t) i; } return 1; } } return 0; } void remove_subchords(void) { struct Chord chord_storage; struct Chord* chord_ptr; struct Chord* chord; for (int i = 0; i < NUMBER_OF_CHORDS; i++) { chord_ptr = (struct Chord*) pgm_read_word (&list_of_chords[i]); memcpy_P(&chord_storage, chord_ptr, sizeof(struct Chord)); chord = &chord_storage; if (!(*chord->state == READY || *chord->state == READY_IN_DANCE || *chord->state == READY_LOCKED)) { continue; } struct Chord chord_storage_2; struct Chord* chord_ptr_2; struct Chord* chord_2; for (int j = 0; j < NUMBER_OF_CHORDS; j++) { if (i == j) {continue;} chord_ptr_2 = (struct Chord*) pgm_read_word (&list_of_chords[j]); memcpy_P(&chord_storage_2, chord_ptr_2, sizeof(struct Chord)); chord_2 = &chord_storage_2; if (are_hashed_keycodes_in_sound(chord_2->keycodes_hash, chord->keycodes_hash)) { if (*chord_2->state == READY) { *chord_2->state = IDLE; } if (*chord_2->state == READY_IN_DANCE) { *chord_2->state = IDLE_IN_DANCE; } if (*chord_2->state == READY_LOCKED) { *chord_2->state = LOCKED; } } } } } void process_ready_chords(void) { uint8_t first_keycode_index = 0; while (keycodes_buffer_array_min(&first_keycode_index)) { // find ready chords struct Chord chord_storage; struct Chord* chord_ptr; struct Chord* chord; for (int i = 0; i < NUMBER_OF_CHORDS; i++) { chord_ptr = (struct Chord*) pgm_read_word (&list_of_chords[i]); memcpy_P(&chord_storage, chord_ptr, sizeof(struct Chord)); chord = &chord_storage; // if the chord does not contain the first keycode bool contains_first_keycode = ((uint32_t) 1 << first_keycode_index) & chord->keycodes_hash; if (!contains_first_keycode) { continue; } if (!are_hashed_keycodes_in_array(chord->keycodes_hash)){ continue; } if (*chord->state == LOCKED) { *chord->state = READY_LOCKED; continue; } if (!(chord->pseudolayer == current_pseudolayer || chord->pseudolayer == ALWAYS_ON)) { continue; } if (*chord->state == IDLE) { *chord->state = READY; continue; } if (*chord->state == IDLE_IN_DANCE) { *chord->state = READY_IN_DANCE; } } // remove subchords remove_subchords(); // execute logic // this should be only one chord for (int i = 0; i < NUMBER_OF_CHORDS; i++) { chord_ptr = (struct Chord*) pgm_read_word (&list_of_chords[i]); memcpy_P(&chord_storage, chord_ptr, sizeof(struct Chord)); chord = &chord_storage; if (*chord->state == READY_LOCKED) { *chord->state = RESTART; chord->function(chord); if (*chord->state == RESTART) { *chord->state = IDLE; } break; } if (*chord->state == READY || *chord->state == READY_IN_DANCE) { if (last_chord && last_chord != chord) { process_finished_dances(); } bool lock_next_prev_state = lock_next; *chord->state = ACTIVATED; chord->function(chord); dance_timer = timer_read(); if (lock_next && lock_next == lock_next_prev_state) { lock_next = false; *chord->state = PRESS_FROM_ACTIVE; chord->function(chord); if (*chord->state == PRESS_FROM_ACTIVE) { *chord->state = LOCKED; } if (a_key_went_through) { kill_one_shots(); } } break; } } // silence notes silence_keycode_hash_array(chord->keycodes_hash); } } void deactivate_active_chords(uint16_t keycode) { HASH_TYPE hash = (HASH_TYPE)1 << (keycode - SAFE_RANGE); bool broken; struct Chord chord_storage; struct Chord* chord_ptr; struct Chord* chord; for (int i = 0; i < NUMBER_OF_CHORDS; i++) { chord_ptr = (struct Chord*) pgm_read_word (&list_of_chords[i]); memcpy_P(&chord_storage, chord_ptr, sizeof(struct Chord)); chord = &chord_storage; broken = are_hashed_keycodes_in_sound(hash, chord->keycodes_hash); if (!broken) { continue; } switch (*chord->state) { case ACTIVATED: *chord->state = DEACTIVATED; chord->function(chord); if (*chord->state == DEACTIVATED) { dance_timer = timer_read(); *chord->state = IDLE_IN_DANCE; } if (*chord->state != IN_ONE_SHOT) { kill_one_shots(); } break; case PRESS_FROM_ACTIVE: case FINISHED_FROM_ACTIVE: *chord->state = RESTART; chord->function(chord); if (*chord->state == RESTART) { *chord->state = IDLE; } kill_one_shots(); break; default: break; } } } void process_command(void) { command_mode = 0; for (int i = 0; i < COMMAND_MAX_LENGTH; i++) { if (command_buffer[i]) { register_code(command_buffer[i]); } send_keyboard_report(); } wait_ms(TAP_TIMEOUT); for (int i = 0; i < COMMAND_MAX_LENGTH; i++) { if (command_buffer[i]) { unregister_code(command_buffer[i]); } send_keyboard_report(); } for (int i = 0; i < COMMAND_MAX_LENGTH; i++) { command_buffer[i] = 0; } command_ind = 0; } void process_leader(void) { in_leader_mode = false; for (int i = 0; i < NUMBER_OF_LEADER_COMBOS; i++) { uint16_t trigger[LEADER_MAX_LENGTH]; memcpy_P(trigger, leader_triggers[i], LEADER_MAX_LENGTH * sizeof(uint16_t)); if (identical(leader_buffer, trigger)) { (*leader_functions[i])(); break; } } for (int i = 0; i < LEADER_MAX_LENGTH; i++) { leader_buffer[i] = 0; } } bool process_record_user(uint16_t keycode, keyrecord_t *record) { if (keycode < FIRST_INTERNAL_KEYCODE || keycode > LAST_INTERNAL_KEYCODE) { return true; } if (record->event.pressed) { sound_keycode_array(keycode); } else { process_ready_chords(); deactivate_active_chords(keycode); } chord_timer = timer_read(); leader_timer = timer_read(); return false; } void matrix_scan_user(void) { bool chord_timer_expired = timer_elapsed(chord_timer) > CHORD_TIMEOUT; if (chord_timer_expired && keycodes_buffer_array_min(NULL)) { process_ready_chords(); } bool dance_timer_expired = timer_elapsed(dance_timer) > DANCE_TIMEOUT; if (dance_timer_expired) { // would love to have && in_dance but not sure how process_finished_dances(); } bool in_command_mode = command_mode == 2; if (in_command_mode) { process_command(); } bool leader_timer_expired = timer_elapsed(leader_timer) > LEADER_TIMEOUT; if (leader_timer_expired && in_leader_mode) { process_leader(); } } void clear(const struct Chord* self) { if (*self->state == ACTIVATED) { // kill all chords struct Chord chord_storage; struct Chord* chord_ptr; struct Chord* chord; for (int i = 0; i < NUMBER_OF_CHORDS; i++) { chord_ptr = (struct Chord*) pgm_read_word (&list_of_chords[i]); memcpy_P(&chord_storage, chord_ptr, sizeof(struct Chord)); chord = &chord_storage; *chord->state = IDLE; if (chord->counter) { *chord->counter = 0; } } // clear keyboard clear_keyboard(); send_keyboard_report(); // switch to default pseudolayer current_pseudolayer = DEFAULT_PSEUDOLAYER; // clear all keyboard states lock_next = false; autoshift_mode = true; command_mode = 0; in_leader_mode = false; leader_ind = 0; dynamic_macro_mode = false; a_key_went_through = false; for (int i = 0; i < DYNAMIC_MACRO_MAX_LENGTH; i++) { dynamic_macro_buffer[i] = 0; } } }