You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

181 lines
8.5 KiB

  1. /* Copyright 2022 adpenrose
  2. *
  3. * This program is free software: you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License as published by
  5. * the Free Software Foundation, either version 2 of the License, or
  6. * (at your option) any later version.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU General Public License
  14. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. */
  16. #include QMK_KEYBOARD_H
  17. #include "animation_frames.h"
  18. /* Base layout:
  19. * ,---------------------------------------------------------------------|
  20. * |` |1 |2 |3 |4 |5 |6 |7 |8 |9 |0 |- |= |Backspace| OLED|
  21. * |--------------------------------------------------------------- |
  22. * |Tab |Q |W |E |R |T |Y |U |I |O |P |[ | ] | \ OLED|
  23. * |---------------------------------------------------------------------|
  24. * |Caps |A |S |D |F |G |H |J |K |L |; |' | Enter | ENC |
  25. * |---------------------------------------------------------------------|
  26. * |Shft |Z |X |C |V |B |N |M |, |. |/ |Shift |Up| M0(3) |
  27. * |---------------------------------------------------------------------|
  28. * |Ctrl|GUI |Alt | Space |MO(1) |MO(2)| |Lt |Dn |Rt |
  29. * `---------------------------------------------------------------------|'
  30. */
  31. const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
  32. /* Base */
  33. [0] = LAYOUT(
  34. KC_ESC, KC_1, KC_2, KC_3, KC_4, KC_5, KC_6, KC_7, KC_8, KC_9, KC_0, KC_MINS, KC_EQL, KC_BSPC,
  35. KC_TAB, KC_Q, KC_W, KC_E, KC_R, KC_T, KC_Y, KC_U, KC_I, KC_O, KC_P, KC_LBRC, KC_RBRC, KC_BSLS,
  36. KC_CAPS, KC_A, KC_S, KC_D, KC_F, KC_G, KC_H, KC_J, KC_K, KC_L, KC_SCLN, KC_QUOT, KC_ENT, KC_MUTE,
  37. KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_N, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_RSFT, KC_UP, MO(3),
  38. KC_LCTL, KC_LGUI, KC_LALT, KC_SPC, MO(1), MO(2), KC_LEFT, KC_DOWN, KC_RIGHT
  39. ),
  40. [1] = LAYOUT(
  41. _______, KC_F1, KC_F2, KC_F3, KC_F4, KC_F5, KC_F6, KC_F7, KC_F8, KC_F9, KC_F10, KC_F11, KC_F12, KC_DEL,
  42. _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
  43. QK_BOOT, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, KC_MPLY,
  44. _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
  45. _______, _______, _______, _______, _______, _______, _______, _______, _______
  46. ),
  47. [2] = LAYOUT(
  48. _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
  49. _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
  50. _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, KC_MNXT,
  51. _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
  52. _______, _______, _______, _______, _______, _______, _______, _______, _______
  53. ),
  54. [3] = LAYOUT(
  55. _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
  56. _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
  57. _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
  58. _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
  59. _______, _______, _______, _______, _______, _______, _______, _______, _______
  60. ),
  61. };
  62. /* Encoder */
  63. #if defined(ENCODER_MAP_ENABLE)
  64. const uint16_t PROGMEM encoder_map[][NUM_ENCODERS][NUM_DIRECTIONS] = {
  65. [0] = { ENCODER_CCW_CW(KC_VOLD, KC_VOLU) },
  66. [1] = { ENCODER_CCW_CW(KC_TRNS, KC_TRNS) },
  67. [2] = { ENCODER_CCW_CW(KC_TRNS, KC_TRNS) },
  68. [3] = { ENCODER_CCW_CW(KC_TRNS, KC_TRNS) }
  69. };
  70. #endif
  71. #ifdef OLED_ENABLE
  72. #define IDLE_FRAME_DURATION 200 // Idle animation iteration rate in ms
  73. oled_rotation_t oled_init_user(oled_rotation_t rotation) { return OLED_ROTATION_270; }
  74. uint32_t anim_timer = 0;
  75. uint32_t anim_sleep = 0;
  76. uint8_t current_idle_frame = 0;
  77. bool tap_anim = false;
  78. bool tap_anim_toggle = false;
  79. // Decompress and write a precompressed bitmap frame to the OLED.
  80. // Documentation and python compression script available at:
  81. // https://github.com/nullbitsco/squeez-o
  82. #ifdef USE_OLED_BITMAP_COMPRESSION
  83. static void oled_write_compressed_P(const char* input_block_map, const char* input_block_list) {
  84. uint16_t block_index = 0;
  85. for (uint16_t i=0; i<NUM_OLED_BYTES; i++) {
  86. uint8_t bit = i%8;
  87. uint8_t map_index = i/8;
  88. uint8_t _block_map = (uint8_t)pgm_read_byte_near(input_block_map + map_index);
  89. uint8_t nonzero_byte = (_block_map & (1 << bit));
  90. if (nonzero_byte) {
  91. const char data = (const char)pgm_read_byte_near(input_block_list + block_index++);
  92. oled_write_raw_byte(data, i);
  93. } else {
  94. const char data = (const char)0x00;
  95. oled_write_raw_byte(data, i);
  96. }
  97. }
  98. }
  99. #endif
  100. static void render_anim(void) {
  101. // Idle animation
  102. void animation_phase(void) {
  103. if (!tap_anim) {
  104. current_idle_frame = (current_idle_frame + 1) % NUM_IDLE_FRAMES;
  105. uint8_t idx = abs((NUM_IDLE_FRAMES - 1) - current_idle_frame);
  106. #ifdef USE_OLED_BITMAP_COMPRESSION
  107. oled_write_compressed_P(idle_block_map[idx], idle_frames[idx]);
  108. #else
  109. oled_write_raw_P(idle_frames[idx], NUM_OLED_BYTES);
  110. #endif
  111. }
  112. }
  113. // Idle behaviour
  114. if (get_current_wpm() != 000) { // prevent sleep
  115. oled_on();
  116. if (timer_elapsed32(anim_timer) > IDLE_FRAME_DURATION) {
  117. anim_timer = timer_read32();
  118. animation_phase();
  119. }
  120. anim_sleep = timer_read32();
  121. } else { // Turn off screen when timer threshold elapsed or reset time since last input
  122. if (timer_elapsed32(anim_sleep) > OLED_TIMEOUT) {
  123. oled_off();
  124. } else {
  125. if (timer_elapsed32(anim_timer) > IDLE_FRAME_DURATION) {
  126. anim_timer = timer_read32();
  127. animation_phase();
  128. }
  129. }
  130. }
  131. }
  132. bool oled_task_user(void) {
  133. render_anim();
  134. oled_set_cursor(0, 0);
  135. uint8_t n = get_current_wpm();
  136. char wpm_counter[6];
  137. wpm_counter[5] = '\0';
  138. wpm_counter[4] = '0' + n % 10;
  139. wpm_counter[3] = '0' + (n /= 10) % 10;
  140. wpm_counter[2] = '0' + n / 10 ;
  141. wpm_counter[1] = '0';
  142. wpm_counter[0] = '>';
  143. oled_write_ln(wpm_counter, false);
  144. return false;
  145. }
  146. #endif
  147. // Animate tap
  148. bool process_record_user(uint16_t keycode, keyrecord_t *record) {
  149. #ifdef OLED_ENABLE
  150. // Check if non-mod
  151. if ((keycode >= KC_A && keycode <= KC_0) || (keycode >= KC_TAB && keycode <= KC_SLASH)) {
  152. if (record->event.pressed) {
  153. // Display tap frames
  154. tap_anim_toggle = !tap_anim_toggle;
  155. #ifdef USE_OLED_BITMAP_COMPRESSION
  156. oled_write_compressed_P(tap_block_map[tap_anim_toggle], tap_frames[tap_anim_toggle]);
  157. #else
  158. oled_write_raw_P(tap_frames[tap_anim_toggle], NUM_OLED_BYTES);
  159. #endif
  160. }
  161. }
  162. #endif
  163. return true;
  164. }