1060 lines
		
	
	
	
		
			27 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1060 lines
		
	
	
	
		
			27 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| #include "quantum.h"
 | |
| 
 | |
| __attribute__ ((weak))
 | |
| bool process_action_kb(keyrecord_t *record) {
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| __attribute__ ((weak))
 | |
| bool process_record_kb(uint16_t keycode, keyrecord_t *record) {
 | |
|   return process_record_user(keycode, record);
 | |
| }
 | |
| 
 | |
| __attribute__ ((weak))
 | |
| bool process_record_user(uint16_t keycode, keyrecord_t *record) {
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| __attribute__ ((weak))
 | |
| void leader_start(void) {}
 | |
| 
 | |
| __attribute__ ((weak))
 | |
| void leader_end(void) {}
 | |
| 
 | |
| uint8_t starting_note = 0x0C;
 | |
| int offset = 7;
 | |
| 
 | |
| 
 | |
| #ifdef AUDIO_ENABLE
 | |
|   bool music_activated = false;
 | |
| 
 | |
|   // music sequencer
 | |
|   static bool music_sequence_recording = false;
 | |
|   static bool music_sequence_playing = false;
 | |
|   static float music_sequence[16] = {0};
 | |
|   static uint8_t music_sequence_count = 0;
 | |
|   static uint8_t music_sequence_position = 0;
 | |
| 
 | |
|   static uint16_t music_sequence_timer = 0;
 | |
|   static uint16_t music_sequence_interval = 100;
 | |
| 
 | |
| #endif
 | |
| 
 | |
| #ifdef MIDI_ENABLE
 | |
|   bool midi_activated = false;
 | |
| #endif
 | |
| 
 | |
| // Leader key stuff
 | |
| bool leading = false;
 | |
| uint16_t leader_time = 0;
 | |
| 
 | |
| uint16_t leader_sequence[5] = {0, 0, 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;
 | |
| 
 | |
| #ifdef UNICODE_ENABLE
 | |
|   static uint8_t input_mode;
 | |
| #endif
 | |
| 
 | |
| // Shift / paren setup
 | |
| 
 | |
| #ifndef LSPO_KEY
 | |
|   #define LSPO_KEY KC_9
 | |
| #endif
 | |
| #ifndef RSPC_KEY
 | |
|   #define RSPC_KEY KC_0
 | |
| #endif
 | |
| 
 | |
| static bool shift_interrupted[2] = {0, 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));
 | |
| }
 | |
| 
 | |
| #ifdef UNICODE_ENABLE
 | |
| 
 | |
| 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 set_unicode_mode(uint8_t os_target)
 | |
| {
 | |
|   input_mode = os_target;
 | |
| }
 | |
| 
 | |
| #endif
 | |
| 
 | |
| bool process_record_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
 | |
| 
 | |
|   if (!process_record_kb(keycode, record))
 | |
|     return false;
 | |
| 
 | |
|     // This is how you use actions here
 | |
|     // if (keycode == KC_LEAD) {
 | |
|     //   action_t action;
 | |
|     //   action.code = ACTION_DEFAULT_LAYER_SET(0);
 | |
|     //   process_action(record, action);
 | |
|     //   return false;
 | |
|     // }
 | |
| 
 | |
|   #ifdef MIDI_ENABLE
 | |
|     if (keycode == MI_ON && record->event.pressed) {
 | |
|       midi_activated = true;
 | |
|       music_scale_user();
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     if (keycode == MI_OFF && record->event.pressed) {
 | |
|       midi_activated = false;
 | |
|       midi_send_cc(&midi_device, 0, 0x7B, 0);
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     if (midi_activated) {
 | |
|       if (record->event.key.col == (MATRIX_COLS - 1) && record->event.key.row == (MATRIX_ROWS - 1)) {
 | |
|           if (record->event.pressed) {
 | |
|               starting_note++; // Change key
 | |
|               midi_send_cc(&midi_device, 0, 0x7B, 0);
 | |
|           }
 | |
|           return false;
 | |
|       }
 | |
|       if (record->event.key.col == (MATRIX_COLS - 2) && record->event.key.row == (MATRIX_ROWS - 1)) {
 | |
|           if (record->event.pressed) {
 | |
|               starting_note--; // Change key
 | |
|               midi_send_cc(&midi_device, 0, 0x7B, 0);
 | |
|           }
 | |
|           return false;
 | |
|       }
 | |
|       if (record->event.key.col == (MATRIX_COLS - 3) && record->event.key.row == (MATRIX_ROWS - 1) && record->event.pressed) {
 | |
|           offset++; // Change scale
 | |
|           midi_send_cc(&midi_device, 0, 0x7B, 0);
 | |
|           return false;
 | |
|       }
 | |
|       if (record->event.key.col == (MATRIX_COLS - 4) && record->event.key.row == (MATRIX_ROWS - 1) && record->event.pressed) {
 | |
|           offset--; // Change scale
 | |
|           midi_send_cc(&midi_device, 0, 0x7B, 0);
 | |
|           return false;
 | |
|       }
 | |
|       // basic
 | |
|       // uint8_t note = (starting_note + SCALE[record->event.key.col + offset])+12*(MATRIX_ROWS - record->event.key.row);
 | |
|       // advanced
 | |
|       // uint8_t note = (starting_note + record->event.key.col + offset)+12*(MATRIX_ROWS - record->event.key.row);
 | |
|       // guitar
 | |
|       uint8_t note = (starting_note + record->event.key.col + offset)+5*(MATRIX_ROWS - record->event.key.row);
 | |
|       // violin
 | |
|       // uint8_t note = (starting_note + record->event.key.col + offset)+7*(MATRIX_ROWS - record->event.key.row);
 | |
| 
 | |
|       if (record->event.pressed) {
 | |
|         // midi_send_noteon(&midi_device, record->event.key.row, starting_note + SCALE[record->event.key.col], 127);
 | |
|         midi_send_noteon(&midi_device, 0, note, 127);
 | |
|       } else {
 | |
|         // midi_send_noteoff(&midi_device, record->event.key.row, starting_note + SCALE[record->event.key.col], 127);
 | |
|         midi_send_noteoff(&midi_device, 0, note, 127);
 | |
|       }
 | |
| 
 | |
|       if (keycode < 0xFF) // ignores all normal keycodes, but lets RAISE, LOWER, etc through
 | |
|         return false;
 | |
|     }
 | |
|   #endif
 | |
| 
 | |
|   #ifdef AUDIO_ENABLE
 | |
|     if (keycode == AU_ON && record->event.pressed) {
 | |
|       audio_on();
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     if (keycode == AU_OFF && record->event.pressed) {
 | |
|       audio_off();
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     if (keycode == AU_TOG && record->event.pressed) {
 | |
|         if (is_audio_on())
 | |
|         {
 | |
|             audio_off();
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             audio_on();
 | |
|         }
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     if (keycode == MU_ON && record->event.pressed) {
 | |
|         music_on();
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     if (keycode == MU_OFF && record->event.pressed) {
 | |
|         music_off();
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     if (keycode == MU_TOG && record->event.pressed) {
 | |
|         if (music_activated)
 | |
|         {
 | |
|             music_off();
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             music_on();
 | |
|         }
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     if (keycode == MUV_IN && record->event.pressed) {
 | |
|         voice_iterate();
 | |
|         music_scale_user();
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     if (keycode == MUV_DE && record->event.pressed) {
 | |
|         voice_deiterate();
 | |
|         music_scale_user();
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     if (music_activated) {
 | |
| 
 | |
|       if (keycode == KC_LCTL && record->event.pressed) { // Start recording
 | |
|         stop_all_notes();
 | |
|         music_sequence_recording = true;
 | |
|         music_sequence_playing = false;
 | |
|         music_sequence_count = 0;
 | |
|         return false;
 | |
|       }
 | |
| 
 | |
|       if (keycode == KC_LALT && record->event.pressed) { // Stop recording/playing
 | |
|         stop_all_notes();
 | |
|         music_sequence_recording = false;
 | |
|         music_sequence_playing = false;
 | |
|         return false;
 | |
|       }
 | |
| 
 | |
|       if (keycode == KC_LGUI && record->event.pressed) { // Start playing
 | |
|         stop_all_notes();
 | |
|         music_sequence_recording = false;
 | |
|         music_sequence_playing = true;
 | |
|         music_sequence_position = 0;
 | |
|         music_sequence_timer = 0;
 | |
|         return false;
 | |
|       }
 | |
| 
 | |
|       if (keycode == KC_UP) {
 | |
|         if (record->event.pressed)
 | |
|             music_sequence_interval-=10;
 | |
|         return false;
 | |
|       }
 | |
| 
 | |
|       if (keycode == KC_DOWN) {
 | |
|         if (record->event.pressed)
 | |
|             music_sequence_interval+=10;
 | |
|         return false;
 | |
|       }
 | |
| 
 | |
|       float freq = ((float)220.0)*pow(2.0, -5.0)*pow(2.0,(starting_note + SCALE[record->event.key.col + offset])/12.0+(MATRIX_ROWS - record->event.key.row));
 | |
|       if (record->event.pressed) {
 | |
|         play_note(freq, 0xF);
 | |
|         if (music_sequence_recording) {
 | |
|           music_sequence[music_sequence_count] = freq;
 | |
|           music_sequence_count++;
 | |
|         }
 | |
|       } else {
 | |
|         stop_note(freq);
 | |
|       }
 | |
| 
 | |
|       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;
 | |
|       leader_sequence[3] = 0;
 | |
|       leader_sequence[4] = 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 >= QK_CHORDING && keycode <= QK_CHORDING_MAX) {
 | |
|     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
 | |
| 
 | |
| #ifdef UNICODE_ENABLE
 | |
| 
 | |
|   if (keycode > QK_UNICODE && record->event.pressed) {
 | |
|     uint16_t unicode = keycode & 0x7FFF;
 | |
|     switch(input_mode) {
 | |
|       case UC_OSX:
 | |
|         register_code(KC_LALT);
 | |
|         break;
 | |
|       case UC_LNX:
 | |
|         register_code(KC_LCTL);
 | |
|         register_code(KC_LSFT);
 | |
|         register_code(KC_U);
 | |
|         unregister_code(KC_U);
 | |
|         break;
 | |
|       case UC_WIN:
 | |
|         register_code(KC_LALT);
 | |
|         register_code(KC_PPLS);
 | |
|         unregister_code(KC_PPLS);
 | |
|         break;
 | |
|     }
 | |
|     for(int i = 3; i >= 0; i--) {
 | |
|         uint8_t digit = ((unicode >> (i*4)) & 0xF);
 | |
|         register_code(hex_to_keycode(digit));
 | |
|         unregister_code(hex_to_keycode(digit));
 | |
|     }
 | |
|     switch(input_mode) {
 | |
|       case UC_OSX:
 | |
|       case UC_WIN:
 | |
|         unregister_code(KC_LALT);
 | |
|         break;
 | |
|       case UC_LNX:
 | |
|         unregister_code(KC_LCTL);
 | |
|         unregister_code(KC_LSFT);
 | |
|         break;
 | |
|     }
 | |
|   }
 | |
| 
 | |
| #endif
 | |
| 
 | |
|   // Shift / paren setup
 | |
| 
 | |
|   switch(keycode) {
 | |
|     case RESET:
 | |
|       if (record->event.pressed) {
 | |
|         clear_keyboard();
 | |
|         #ifdef AUDIO_ENABLE
 | |
|           stop_all_notes();
 | |
|           shutdown_user();
 | |
|         #endif
 | |
|         _delay_ms(250);
 | |
|         #ifdef ATREUS_ASTAR
 | |
|             *(uint16_t *)0x0800 = 0x7777; // these two are a-star-specific
 | |
|         #endif
 | |
|         bootloader_jump();
 | |
|         return false;
 | |
|       }
 | |
|       break;
 | |
|     case DEBUG:
 | |
|       if (record->event.pressed) {
 | |
|           print("\nDEBUG: enabled.\n");
 | |
|           debug_enable = true;
 | |
|           return false;
 | |
|       }
 | |
|       break;
 | |
|     case MAGIC_SWAP_CONTROL_CAPSLOCK ... MAGIC_UNSWAP_ALT_GUI:
 | |
|       if (record->event.pressed) {
 | |
|         // MAGIC actions (BOOTMAGIC without the boot)
 | |
|         if (!eeconfig_is_enabled()) {
 | |
|             eeconfig_init();
 | |
|         }
 | |
|         /* keymap config */
 | |
|         keymap_config.raw = eeconfig_read_keymap();
 | |
|         if (keycode == MAGIC_SWAP_CONTROL_CAPSLOCK) {
 | |
|             keymap_config.swap_control_capslock = 1;
 | |
|         } else if (keycode == MAGIC_CAPSLOCK_TO_CONTROL) {
 | |
|             keymap_config.capslock_to_control = 1;
 | |
|         } else if (keycode == MAGIC_SWAP_LALT_LGUI) {
 | |
|             keymap_config.swap_lalt_lgui = 1;
 | |
|         } else if (keycode == MAGIC_SWAP_RALT_RGUI) {
 | |
|             keymap_config.swap_ralt_rgui = 1;
 | |
|         } else if (keycode == MAGIC_NO_GUI) {
 | |
|             keymap_config.no_gui = 1;
 | |
|         } else if (keycode == MAGIC_SWAP_GRAVE_ESC) {
 | |
|             keymap_config.swap_grave_esc = 1;
 | |
|         } else if (keycode == MAGIC_SWAP_BACKSLASH_BACKSPACE) {
 | |
|             keymap_config.swap_backslash_backspace = 1;
 | |
|         } else if (keycode == MAGIC_HOST_NKRO) {
 | |
|             keymap_config.nkro = 1;
 | |
|         } else if (keycode == MAGIC_SWAP_ALT_GUI) {
 | |
|             keymap_config.swap_lalt_lgui = 1;
 | |
|             keymap_config.swap_ralt_rgui = 1;
 | |
|         }
 | |
|         /* UNs */
 | |
|         else if (keycode == MAGIC_UNSWAP_CONTROL_CAPSLOCK) {
 | |
|             keymap_config.swap_control_capslock = 0;
 | |
|         } else if (keycode == MAGIC_UNCAPSLOCK_TO_CONTROL) {
 | |
|             keymap_config.capslock_to_control = 0;
 | |
|         } else if (keycode == MAGIC_UNSWAP_LALT_LGUI) {
 | |
|             keymap_config.swap_lalt_lgui = 0;
 | |
|         } else if (keycode == MAGIC_UNSWAP_RALT_RGUI) {
 | |
|             keymap_config.swap_ralt_rgui = 0;
 | |
|         } else if (keycode == MAGIC_UNNO_GUI) {
 | |
|             keymap_config.no_gui = 0;
 | |
|         } else if (keycode == MAGIC_UNSWAP_GRAVE_ESC) {
 | |
|             keymap_config.swap_grave_esc = 0;
 | |
|         } else if (keycode == MAGIC_UNSWAP_BACKSLASH_BACKSPACE) {
 | |
|             keymap_config.swap_backslash_backspace = 0;
 | |
|         } else if (keycode == MAGIC_UNHOST_NKRO) {
 | |
|             keymap_config.nkro = 0;
 | |
|         } else if (keycode == MAGIC_UNSWAP_ALT_GUI) {
 | |
|             keymap_config.swap_lalt_lgui = 0;
 | |
|             keymap_config.swap_ralt_rgui = 0;
 | |
|         }
 | |
|         eeconfig_update_keymap(keymap_config.raw);
 | |
|         return false;
 | |
|       }
 | |
|       break;
 | |
|     case KC_LSPO: {
 | |
|       if (record->event.pressed) {
 | |
|         shift_interrupted[0] = false;
 | |
|         register_mods(MOD_BIT(KC_LSFT));
 | |
|       }
 | |
|       else {
 | |
|         if (!shift_interrupted[0]) {
 | |
|           register_code(LSPO_KEY);
 | |
|           unregister_code(LSPO_KEY);
 | |
|         }
 | |
|         unregister_mods(MOD_BIT(KC_LSFT));
 | |
|       }
 | |
|       return false;
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     case KC_RSPC: {
 | |
|       if (record->event.pressed) {
 | |
|         shift_interrupted[1] = false;
 | |
|         register_mods(MOD_BIT(KC_RSFT));
 | |
|       }
 | |
|       else {
 | |
|         if (!shift_interrupted[1]) {
 | |
|           register_code(RSPC_KEY);
 | |
|           unregister_code(RSPC_KEY);
 | |
|         }
 | |
|         unregister_mods(MOD_BIT(KC_RSFT));
 | |
|       }
 | |
|       return false;
 | |
|       break;
 | |
|     }
 | |
|     default: {
 | |
|       shift_interrupted[0] = true;
 | |
|       shift_interrupted[1] = true;
 | |
|       break;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return process_action_kb(record);
 | |
| }
 | |
| 
 | |
| const bool ascii_to_qwerty_shift_lut[0x80] PROGMEM = {
 | |
|     0, 0, 0, 0, 0, 0, 0, 0,
 | |
|     0, 0, 0, 0, 0, 0, 0, 0,
 | |
|     0, 0, 0, 0, 0, 0, 0, 0,
 | |
|     0, 0, 0, 0, 0, 0, 0, 0,
 | |
|     0, 1, 1, 1, 1, 1, 1, 0,
 | |
|     1, 1, 1, 1, 0, 0, 0, 0,
 | |
|     0, 0, 0, 0, 0, 0, 0, 0,
 | |
|     0, 0, 1, 0, 1, 0, 1, 1,
 | |
|     1, 1, 1, 1, 1, 1, 1, 1,
 | |
|     1, 1, 1, 1, 1, 1, 1, 1,
 | |
|     1, 1, 1, 1, 1, 1, 1, 1,
 | |
|     1, 1, 1, 0, 0, 0, 1, 1,
 | |
|     0, 0, 0, 0, 0, 0, 0, 0,
 | |
|     0, 0, 0, 0, 0, 0, 0, 0,
 | |
|     0, 0, 0, 0, 0, 0, 0, 0,
 | |
|     0, 0, 0, 1, 1, 1, 1, 0
 | |
| };
 | |
| 
 | |
| const uint8_t ascii_to_qwerty_keycode_lut[0x80] PROGMEM = {
 | |
|     0, 0, 0, 0, 0, 0, 0, 0,
 | |
|     KC_BSPC, KC_TAB, KC_ENT, 0, 0, 0, 0, 0,
 | |
|     0, 0, 0, 0, 0, 0, 0, 0,
 | |
|     0, 0, 0, KC_ESC, 0, 0, 0, 0,
 | |
|     KC_SPC, KC_1, KC_QUOT, KC_3, KC_4, KC_5, KC_7, KC_QUOT,
 | |
|     KC_9, KC_0, KC_8, KC_EQL, KC_COMM, KC_MINS, KC_DOT, KC_SLSH,
 | |
|     KC_0, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7,
 | |
|     KC_8, KC_9, KC_SCLN, KC_SCLN, KC_COMM, KC_EQL, KC_DOT, KC_SLSH,
 | |
|     KC_2, KC_A, KC_B, KC_C, KC_D, KC_E, KC_F, KC_G,
 | |
|     KC_H, KC_I, KC_J, KC_K, KC_L, KC_M, KC_N, KC_O,
 | |
|     KC_P, KC_Q, KC_R, KC_S, KC_T, KC_U, KC_V, KC_W,
 | |
|     KC_X, KC_Y, KC_Z, KC_LBRC, KC_BSLS, KC_RBRC, KC_6, KC_MINS,
 | |
|     KC_GRV, KC_A, KC_B, KC_C, KC_D, KC_E, KC_F, KC_G,
 | |
|     KC_H, KC_I, KC_J, KC_K, KC_L, KC_M, KC_N, KC_O,
 | |
|     KC_P, KC_Q, KC_R, KC_S, KC_T, KC_U, KC_V, KC_W,
 | |
|     KC_X, KC_Y, KC_Z, KC_LBRC, KC_BSLS, KC_RBRC, KC_GRV, KC_DEL
 | |
| };
 | |
| 
 | |
| /* for users whose OSes are set to Colemak */
 | |
| #if 0
 | |
| #include "keymap_colemak.h"
 | |
| 
 | |
| const bool ascii_to_colemak_shift_lut[0x80] PROGMEM = {
 | |
|     0, 0, 0, 0, 0, 0, 0, 0,
 | |
|     0, 0, 0, 0, 0, 0, 0, 0,
 | |
|     0, 0, 0, 0, 0, 0, 0, 0,
 | |
|     0, 0, 0, 0, 0, 0, 0, 0,
 | |
|     0, 1, 1, 1, 1, 1, 1, 0,
 | |
|     1, 1, 1, 1, 0, 0, 0, 0,
 | |
|     0, 0, 0, 0, 0, 0, 0, 0,
 | |
|     0, 0, 1, 0, 1, 0, 1, 1,
 | |
|     1, 1, 1, 1, 1, 1, 1, 1,
 | |
|     1, 1, 1, 1, 1, 1, 1, 1,
 | |
|     1, 1, 1, 1, 1, 1, 1, 1,
 | |
|     1, 1, 1, 0, 0, 0, 1, 1,
 | |
|     0, 0, 0, 0, 0, 0, 0, 0,
 | |
|     0, 0, 0, 0, 0, 0, 0, 0,
 | |
|     0, 0, 0, 0, 0, 0, 0, 0,
 | |
|     0, 0, 0, 1, 1, 1, 1, 0
 | |
| };
 | |
| 
 | |
| const uint8_t ascii_to_colemak_keycode_lut[0x80] PROGMEM = {
 | |
|     0, 0, 0, 0, 0, 0, 0, 0,
 | |
|     KC_BSPC, KC_TAB, KC_ENT, 0, 0, 0, 0, 0,
 | |
|     0, 0, 0, 0, 0, 0, 0, 0,
 | |
|     0, 0, 0, KC_ESC, 0, 0, 0, 0,
 | |
|     KC_SPC, KC_1, KC_QUOT, KC_3, KC_4, KC_5, KC_7, KC_QUOT,
 | |
|     KC_9, KC_0, KC_8, KC_EQL, KC_COMM, KC_MINS, KC_DOT, KC_SLSH,
 | |
|     KC_0, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7,
 | |
|     KC_8, KC_9, CM_SCLN, CM_SCLN, KC_COMM, KC_EQL, KC_DOT, KC_SLSH,
 | |
|     KC_2, CM_A, CM_B, CM_C, CM_D, CM_E, CM_F, CM_G,
 | |
|     CM_H, CM_I, CM_J, CM_K, CM_L, CM_M, CM_N, CM_O,
 | |
|     CM_P, CM_Q, CM_R, CM_S, CM_T, CM_U, CM_V, CM_W,
 | |
|     CM_X, CM_Y, CM_Z, KC_LBRC, KC_BSLS, KC_RBRC, KC_6, KC_MINS,
 | |
|     KC_GRV, CM_A, CM_B, CM_C, CM_D, CM_E, CM_F, CM_G,
 | |
|     CM_H, CM_I, CM_J, CM_K, CM_L, CM_M, CM_N, CM_O,
 | |
|     CM_P, CM_Q, CM_R, CM_S, CM_T, CM_U, CM_V, CM_W,
 | |
|     CM_X, CM_Y, CM_Z, KC_LBRC, KC_BSLS, KC_RBRC, KC_GRV, KC_DEL
 | |
| };
 | |
| 
 | |
| #endif
 | |
| 
 | |
| void send_string(const char *str) {
 | |
|     while (1) {
 | |
|         uint8_t keycode;
 | |
|         uint8_t ascii_code = pgm_read_byte(str);
 | |
|         if (!ascii_code) break;
 | |
|         keycode = pgm_read_byte(&ascii_to_qwerty_keycode_lut[ascii_code]);
 | |
|         if (pgm_read_byte(&ascii_to_qwerty_shift_lut[ascii_code])) {
 | |
|             register_code(KC_LSFT);
 | |
|             register_code(keycode);
 | |
|             unregister_code(keycode);
 | |
|             unregister_code(KC_LSFT);
 | |
|         }
 | |
|         else {
 | |
|             register_code(keycode);
 | |
|             unregister_code(keycode);
 | |
|         }
 | |
|         ++str;
 | |
|     }
 | |
| }
 | |
| 
 | |
| void update_tri_layer(uint8_t layer1, uint8_t layer2, uint8_t layer3) {
 | |
|   if (IS_LAYER_ON(layer1) && IS_LAYER_ON(layer2)) {
 | |
|     layer_on(layer3);
 | |
|   } else {
 | |
|     layer_off(layer3);
 | |
|   }
 | |
| }
 | |
| 
 | |
| void matrix_init_quantum() {
 | |
|   #ifdef BACKLIGHT_ENABLE
 | |
|     backlight_init_ports();
 | |
|   #endif
 | |
|   matrix_init_kb();
 | |
| }
 | |
| 
 | |
| void matrix_scan_quantum() {
 | |
|   #ifdef AUDIO_ENABLE
 | |
|   if (music_sequence_playing) {
 | |
|     if ((music_sequence_timer == 0) || (timer_elapsed(music_sequence_timer) > music_sequence_interval)) {
 | |
|       music_sequence_timer = timer_read();
 | |
|       stop_note(music_sequence[(music_sequence_position - 1 < 0)?(music_sequence_position - 1 + music_sequence_count):(music_sequence_position - 1)]);
 | |
|       play_note(music_sequence[music_sequence_position], 0xF);
 | |
|       music_sequence_position = (music_sequence_position + 1) % music_sequence_count;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   #endif
 | |
| 
 | |
|   matrix_scan_kb();
 | |
| }
 | |
| 
 | |
| #ifdef AUDIO_ENABLE
 | |
|   bool is_music_on(void) {
 | |
|       return (music_activated != 0);
 | |
|   }
 | |
| 
 | |
|   void music_toggle(void) {
 | |
|       if (!music_activated) {
 | |
|           music_on();
 | |
|       } else {
 | |
|           music_off();
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   void music_on(void) {
 | |
|       music_activated = 1;
 | |
|       music_on_user();
 | |
|   }
 | |
| 
 | |
|   void music_off(void) {
 | |
|       music_activated = 0;
 | |
|       stop_all_notes();
 | |
|   }
 | |
| 
 | |
| #endif
 | |
| 
 | |
| 
 | |
| #if defined(BACKLIGHT_ENABLE) && defined(BACKLIGHT_PIN)
 | |
| 
 | |
| static const uint8_t backlight_pin = BACKLIGHT_PIN;
 | |
| 
 | |
| #if BACKLIGHT_PIN == B7
 | |
| #  define COM1x1 COM1C1
 | |
| #  define OCR1x  OCR1C
 | |
| #elif BACKLIGHT_PIN == B6
 | |
| #  define COM1x1 COM1B1
 | |
| #  define OCR1x  OCR1B
 | |
| #elif BACKLIGHT_PIN == B5
 | |
| #  define COM1x1 COM1A1
 | |
| #  define OCR1x  OCR1A
 | |
| #else
 | |
| #  error "Backlight pin not supported - use B5, B6, or B7"
 | |
| #endif
 | |
| 
 | |
| __attribute__ ((weak))
 | |
| void backlight_init_ports(void)
 | |
| {
 | |
| 
 | |
|   // Setup backlight pin as output and output low.
 | |
|   // DDRx |= n
 | |
|   _SFR_IO8((backlight_pin >> 4) + 1) |= _BV(backlight_pin & 0xF);
 | |
|   // PORTx &= ~n
 | |
|   _SFR_IO8((backlight_pin >> 4) + 2) &= ~_BV(backlight_pin & 0xF);
 | |
| 
 | |
|   // Use full 16-bit resolution.
 | |
|   ICR1 = 0xFFFF;
 | |
| 
 | |
|   // I could write a wall of text here to explain... but TL;DW
 | |
|   // Go read the ATmega32u4 datasheet.
 | |
|   // And this: http://blog.saikoled.com/post/43165849837/secret-konami-cheat-code-to-high-resolution-pwm-on
 | |
| 
 | |
|   // Pin PB7 = OCR1C (Timer 1, Channel C)
 | |
|   // Compare Output Mode = Clear on compare match, Channel C = COM1C1=1 COM1C0=0
 | |
|   // (i.e. start high, go low when counter matches.)
 | |
|   // WGM Mode 14 (Fast PWM) = WGM13=1 WGM12=1 WGM11=1 WGM10=0
 | |
|   // Clock Select = clk/1 (no prescaling) = CS12=0 CS11=0 CS10=1
 | |
| 
 | |
|   TCCR1A = _BV(COM1x1) | _BV(WGM11); // = 0b00001010;
 | |
|   TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS10); // = 0b00011001;
 | |
| 
 | |
|   backlight_init();
 | |
|   #ifdef BACKLIGHT_BREATHING
 | |
|     breathing_defaults();
 | |
|   #endif
 | |
| }
 | |
| 
 | |
| __attribute__ ((weak))
 | |
| void backlight_set(uint8_t level)
 | |
| {
 | |
|   // Prevent backlight blink on lowest level
 | |
|   // PORTx &= ~n
 | |
|   _SFR_IO8((backlight_pin >> 4) + 2) &= ~_BV(backlight_pin & 0xF);
 | |
| 
 | |
|   if ( level == 0 ) {
 | |
|     // Turn off PWM control on backlight pin, revert to output low.
 | |
|     TCCR1A &= ~(_BV(COM1x1));
 | |
|     OCR1x = 0x0;
 | |
|   } else if ( level == BACKLIGHT_LEVELS ) {
 | |
|     // Turn on PWM control of backlight pin
 | |
|     TCCR1A |= _BV(COM1x1);
 | |
|     // Set the brightness
 | |
|     OCR1x = 0xFFFF;
 | |
|   } else {
 | |
|     // Turn on PWM control of backlight pin
 | |
|     TCCR1A |= _BV(COM1x1);
 | |
|     // Set the brightness
 | |
|     OCR1x = 0xFFFF >> ((BACKLIGHT_LEVELS - level) * ((BACKLIGHT_LEVELS + 1) / 2));
 | |
|   }
 | |
| 
 | |
|   #ifdef BACKLIGHT_BREATHING
 | |
|     breathing_intensity_default();
 | |
|   #endif
 | |
| }
 | |
| 
 | |
| 
 | |
| #ifdef BACKLIGHT_BREATHING
 | |
| 
 | |
| #define BREATHING_NO_HALT  0
 | |
| #define BREATHING_HALT_OFF 1
 | |
| #define BREATHING_HALT_ON  2
 | |
| 
 | |
| static uint8_t breath_intensity;
 | |
| static uint8_t breath_speed;
 | |
| static uint16_t breathing_index;
 | |
| static uint8_t breathing_halt;
 | |
| 
 | |
| void breathing_enable(void)
 | |
| {
 | |
|     if (get_backlight_level() == 0)
 | |
|     {
 | |
|         breathing_index = 0;
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         // Set breathing_index to be at the midpoint (brightest point)
 | |
|         breathing_index = 0x20 << breath_speed;
 | |
|     }
 | |
| 
 | |
|     breathing_halt = BREATHING_NO_HALT;
 | |
| 
 | |
|     // Enable breathing interrupt
 | |
|     TIMSK1 |= _BV(OCIE1A);
 | |
| }
 | |
| 
 | |
| void breathing_pulse(void)
 | |
| {
 | |
|     if (get_backlight_level() == 0)
 | |
|     {
 | |
|         breathing_index = 0;
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         // Set breathing_index to be at the midpoint + 1 (brightest point)
 | |
|         breathing_index = 0x21 << breath_speed;
 | |
|     }
 | |
| 
 | |
|     breathing_halt = BREATHING_HALT_ON;
 | |
| 
 | |
|     // Enable breathing interrupt
 | |
|     TIMSK1 |= _BV(OCIE1A);
 | |
| }
 | |
| 
 | |
| void breathing_disable(void)
 | |
| {
 | |
|     // Disable breathing interrupt
 | |
|     TIMSK1 &= ~_BV(OCIE1A);
 | |
|     backlight_set(get_backlight_level());
 | |
| }
 | |
| 
 | |
| void breathing_self_disable(void)
 | |
| {
 | |
|     if (get_backlight_level() == 0)
 | |
|     {
 | |
|         breathing_halt = BREATHING_HALT_OFF;
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         breathing_halt = BREATHING_HALT_ON;
 | |
|     }
 | |
| 
 | |
|     //backlight_set(get_backlight_level());
 | |
| }
 | |
| 
 | |
| void breathing_toggle(void)
 | |
| {
 | |
|     if (!is_breathing())
 | |
|     {
 | |
|         if (get_backlight_level() == 0)
 | |
|         {
 | |
|             breathing_index = 0;
 | |
|         }
 | |
|         else
 | |
|         {
 | |
|             // Set breathing_index to be at the midpoint + 1 (brightest point)
 | |
|             breathing_index = 0x21 << breath_speed;
 | |
|         }
 | |
| 
 | |
|         breathing_halt = BREATHING_NO_HALT;
 | |
|     }
 | |
| 
 | |
|     // Toggle breathing interrupt
 | |
|     TIMSK1 ^= _BV(OCIE1A);
 | |
| 
 | |
|     // Restore backlight level
 | |
|     if (!is_breathing())
 | |
|     {
 | |
|         backlight_set(get_backlight_level());
 | |
|     }
 | |
| }
 | |
| 
 | |
| bool is_breathing(void)
 | |
| {
 | |
|     return (TIMSK1 && _BV(OCIE1A));
 | |
| }
 | |
| 
 | |
| void breathing_intensity_default(void)
 | |
| {
 | |
|     //breath_intensity = (uint8_t)((uint16_t)100 * (uint16_t)get_backlight_level() / (uint16_t)BACKLIGHT_LEVELS);
 | |
|     breath_intensity = ((BACKLIGHT_LEVELS - get_backlight_level()) * ((BACKLIGHT_LEVELS + 1) / 2));
 | |
| }
 | |
| 
 | |
| void breathing_intensity_set(uint8_t value)
 | |
| {
 | |
|     breath_intensity = value;
 | |
| }
 | |
| 
 | |
| void breathing_speed_default(void)
 | |
| {
 | |
|     breath_speed = 4;
 | |
| }
 | |
| 
 | |
| void breathing_speed_set(uint8_t value)
 | |
| {
 | |
|     bool is_breathing_now = is_breathing();
 | |
|     uint8_t old_breath_speed = breath_speed;
 | |
| 
 | |
|     if (is_breathing_now)
 | |
|     {
 | |
|         // Disable breathing interrupt
 | |
|         TIMSK1 &= ~_BV(OCIE1A);
 | |
|     }
 | |
| 
 | |
|     breath_speed = value;
 | |
| 
 | |
|     if (is_breathing_now)
 | |
|     {
 | |
|         // Adjust index to account for new speed
 | |
|         breathing_index = (( (uint8_t)( (breathing_index) >> old_breath_speed ) ) & 0x3F) << breath_speed;
 | |
| 
 | |
|         // Enable breathing interrupt
 | |
|         TIMSK1 |= _BV(OCIE1A);
 | |
|     }
 | |
| 
 | |
| }
 | |
| 
 | |
| void breathing_speed_inc(uint8_t value)
 | |
| {
 | |
|     if ((uint16_t)(breath_speed - value) > 10 )
 | |
|     {
 | |
|         breathing_speed_set(0);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         breathing_speed_set(breath_speed - value);
 | |
|     }
 | |
| }
 | |
| 
 | |
| void breathing_speed_dec(uint8_t value)
 | |
| {
 | |
|     if ((uint16_t)(breath_speed + value) > 10 )
 | |
|     {
 | |
|         breathing_speed_set(10);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|         breathing_speed_set(breath_speed + value);
 | |
|     }
 | |
| }
 | |
| 
 | |
| void breathing_defaults(void)
 | |
| {
 | |
|     breathing_intensity_default();
 | |
|     breathing_speed_default();
 | |
|     breathing_halt = BREATHING_NO_HALT;
 | |
| }
 | |
| 
 | |
| /* Breathing Sleep LED brighness(PWM On period) table
 | |
|  * (64[steps] * 4[duration]) / 64[PWM periods/s] = 4 second breath cycle
 | |
|  *
 | |
|  * http://www.wolframalpha.com/input/?i=%28sin%28+x%2F64*pi%29**8+*+255%2C+x%3D0+to+63
 | |
|  * (0..63).each {|x| p ((sin(x/64.0*PI)**8)*255).to_i }
 | |
|  */
 | |
| static const uint8_t breathing_table[64] PROGMEM = {
 | |
|   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   1,   2,   4,   6,  10,
 | |
|  15,  23,  32,  44,  58,  74,  93, 113, 135, 157, 179, 199, 218, 233, 245, 252,
 | |
| 255, 252, 245, 233, 218, 199, 179, 157, 135, 113,  93,  74,  58,  44,  32,  23,
 | |
|  15,  10,   6,   4,   2,   1,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
 | |
| };
 | |
| 
 | |
| ISR(TIMER1_COMPA_vect)
 | |
| {
 | |
|     // OCR1x = (pgm_read_byte(&breathing_table[ ( (uint8_t)( (breathing_index++) >> breath_speed ) ) & 0x3F ] )) * breath_intensity;
 | |
| 
 | |
| 
 | |
|     uint8_t local_index = ( (uint8_t)( (breathing_index++) >> breath_speed ) ) & 0x3F;
 | |
| 
 | |
|     if (((breathing_halt == BREATHING_HALT_ON) && (local_index == 0x20)) || ((breathing_halt == BREATHING_HALT_OFF) && (local_index == 0x3F)))
 | |
|     {
 | |
|         // Disable breathing interrupt
 | |
|         TIMSK1 &= ~_BV(OCIE1A);
 | |
|     }
 | |
| 
 | |
|     OCR1x = (uint16_t)(((uint16_t)pgm_read_byte(&breathing_table[local_index]) * 257)) >> breath_intensity;
 | |
| 
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| #endif // breathing
 | |
| 
 | |
| #else // backlight
 | |
| 
 | |
| __attribute__ ((weak))
 | |
| void backlight_init_ports(void)
 | |
| {
 | |
| 
 | |
| }
 | |
| 
 | |
| __attribute__ ((weak))
 | |
| void backlight_set(uint8_t level)
 | |
| {
 | |
| 
 | |
| }
 | |
| 
 | |
| #endif // backlight
 | |
| 
 | |
| 
 | |
| 
 | |
| __attribute__ ((weak))
 | |
| void led_set_user(uint8_t usb_led) {
 | |
| 
 | |
| }
 | |
| 
 | |
| __attribute__ ((weak))
 | |
| void led_set_kb(uint8_t usb_led) {
 | |
|     led_set_user(usb_led);
 | |
| }
 | |
| 
 | |
| __attribute__ ((weak))
 | |
| void led_init_ports(void)
 | |
| {
 | |
| 
 | |
| }
 | |
| 
 | |
| __attribute__ ((weak))
 | |
| void led_set(uint8_t usb_led)
 | |
| {
 | |
| 
 | |
|   // Example LED Code
 | |
|   //
 | |
|     // // Using PE6 Caps Lock LED
 | |
|     // if (usb_led & (1<<USB_LED_CAPS_LOCK))
 | |
|     // {
 | |
|     //     // Output high.
 | |
|     //     DDRE |= (1<<6);
 | |
|     //     PORTE |= (1<<6);
 | |
|     // }
 | |
|     // else
 | |
|     // {
 | |
|     //     // Output low.
 | |
|     //     DDRE &= ~(1<<6);
 | |
|     //     PORTE &= ~(1<<6);
 | |
|     // }
 | |
| 
 | |
|   led_set_kb(usb_led);
 | |
| }
 | |
| 
 | |
| 
 | |
| //------------------------------------------------------------------------------
 | |
| // Override these functions in your keymap file to play different tunes on
 | |
| // different events such as startup and bootloader jump
 | |
| 
 | |
| __attribute__ ((weak))
 | |
| void startup_user() {}
 | |
| 
 | |
| __attribute__ ((weak))
 | |
| void shutdown_user() {}
 | |
| 
 | |
| __attribute__ ((weak))
 | |
| void music_on_user() {}
 | |
| 
 | |
| __attribute__ ((weak))
 | |
| void audio_on_user() {}
 | |
| 
 | |
| __attribute__ ((weak))
 | |
| void music_scale_user() {}
 | |
| 
 | |
| //------------------------------------------------------------------------------
 | 
