logo

qmk_firmware

custom branch of QMK firmware git clone https://anongit.hacktivis.me/git/qmk_firmware.git

display_oled.c (14031B)


  1. // Copyright 2025 Dasky (@daskygit)
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include "quantum.h"
  4. static uint16_t current_keycode = 0xFF;
  5. static const char *depad_str(const char *depad_str, char depad_char) {
  6. while (*depad_str == depad_char)
  7. ++depad_str;
  8. return depad_str;
  9. }
  10. static void render_spacer(uint8_t char_length) {
  11. static const char PROGMEM spacer_char[] = {8, 8, 8, 8, 8, 8, 8};
  12. if (char_length > 5) {
  13. char_length = 5;
  14. }
  15. for (uint8_t i = 0; i < char_length; i++) {
  16. oled_write_raw_P(spacer_char, sizeof(spacer_char));
  17. oled_advance_char();
  18. }
  19. }
  20. __attribute__((weak)) void render_logo(void) {
  21. static const char PROGMEM mb_logo[] = {
  22. 252, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 31, 31, 31, 31, 31, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 227, 227, 227, 3, 227, 227, 227, 3, 227, 227, 227, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 7, 254, 252, 255, 255, 255, 255, 255, 7, 7, 7, 7, 7, 255, 7, 7, 7, 7, 7, 255, 7, 7, 7, 7, 7, 255, 7, 7, 7, 7, 7, 255, 7, 7, 7, 7, 7, 255, 255, 255, 4, 4, 4, 4, 4, 255,
  23. 7, 7, 7, 7, 7, 255, 7, 7, 7, 7, 7, 255, 255, 255, 255, 255, 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, 0, 0, 0, 224, 224, 224, 0, 238, 238, 238, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255, 65, 65, 65, 65, 65, 255, 255, 255, 255, 255, 255, 255, 65, 65, 65, 65, 65, 255, 255, 255, 255, 255, 255, 255, 65, 65, 65, 65, 65, 255, 255, 255, 65, 65, 65, 65, 65, 255, 127, 127, 127, 127, 127, 255, 65, 65, 65, 65, 65, 255, 255, 255, 255, 255, 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,
  24. 0, 0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 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, 255, 255, 63, 127, 255, 255, 255, 240, 240, 240, 240, 240, 255, 255, 255, 255, 255, 255, 255, 240, 240, 240, 240, 240, 255, 255, 255, 255, 255, 255, 255, 240, 240, 240, 240, 240, 255, 255, 255, 240, 240, 240, 240, 240, 255, 240, 240, 240, 240, 240, 255, 240, 240, 240, 240, 240, 255, 255, 255, 255, 255, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 199, 199, 199, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 192, 224, 127, 63,
  25. };
  26. oled_write_raw_P(mb_logo, sizeof(mb_logo));
  27. }
  28. void render_small_mb_logo(void) {
  29. static const char PROGMEM small_mb_logo[] = {
  30. 112, 112, 112, 0, 112, 112, 112, 0, 112, 112, 112, 0, 112, 112, 112, 0, 112, 112, 112, 0, 0, 119, 119, 119, 0, 112, 112, 112, 0, 112, 112, 112, 119, 119, 119, 0, 0, 0, 0, 0, 119, 119, 119, 0, 0, 0, 0, 0, 119, 119, 119, 0, 0, 119, 119, 119, 0, 112, 112, 112, 0, 119, 119, 119,
  31. };
  32. oled_write_raw_P(small_mb_logo, sizeof(small_mb_logo));
  33. }
  34. static uint8_t last_hue;
  35. static uint8_t last_sat;
  36. static uint8_t last_val;
  37. static uint8_t last_mode;
  38. void render_rgb_info(void) {
  39. last_hue = rgb_matrix_get_hue();
  40. last_sat = rgb_matrix_get_sat();
  41. last_val = rgb_matrix_get_val();
  42. last_mode = rgb_matrix_get_mode();
  43. oled_set_cursor(0, 6);
  44. oled_write("H:", false);
  45. oled_write(depad_str(get_u16_str(last_hue, ' '), ' '), false);
  46. oled_set_cursor(0, 7);
  47. oled_write("S:", false);
  48. oled_write_ln(depad_str(get_u16_str(last_sat, ' '), ' '), false);
  49. oled_set_cursor(0, 8);
  50. oled_write("V:", false);
  51. oled_write_ln(depad_str(get_u16_str(last_val, ' '), ' '), false);
  52. oled_set_cursor(0, 9);
  53. oled_write("M:", false);
  54. oled_write_ln(depad_str(get_u16_str(last_mode, ' '), ' '), false);
  55. }
  56. oled_rotation_t oled_init_kb(oled_rotation_t rotation) {
  57. if (is_keyboard_master()) {
  58. return OLED_ROTATION_270;
  59. }
  60. return rotation;
  61. }
  62. char basic_codes_to_name[57] = {' ', ' ', ' ', ' ', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'R', 'E', 'B', 'T', '_', '-', '=', '[', ']', '\\', '#', ';', '\'', '`', ',', '.', '/'};
  63. const char *keycode_string(uint16_t keycode) {
  64. char *keycode_str;
  65. static char key;
  66. switch (keycode) {
  67. case 0 ... 56:
  68. key = pgm_read_byte(&basic_codes_to_name[keycode]);
  69. return &key;
  70. case KC_CAPS:
  71. keycode_str = "Caps\0";
  72. break;
  73. case KC_SCRL:
  74. keycode_str = "Scrl\0";
  75. break;
  76. case KC_PAUS:
  77. keycode_str = "Pause\0";
  78. break;
  79. case KC_DEL:
  80. keycode_str = "Del\0";
  81. break;
  82. case KC_NUM:
  83. keycode_str = "Num\0";
  84. break;
  85. case KC_MUTE:
  86. keycode_str = "Mute\0";
  87. break;
  88. case KC_VOLU:
  89. keycode_str = "VolUp\0";
  90. break;
  91. case KC_VOLD:
  92. keycode_str = "VolD\0";
  93. break;
  94. case KC_MNXT:
  95. keycode_str = "Next\0";
  96. break;
  97. case KC_MPRV:
  98. keycode_str = "Prev\0";
  99. break;
  100. case KC_MSTP:
  101. keycode_str = "Stop\0";
  102. break;
  103. case KC_MPLY:
  104. keycode_str = "Play\0";
  105. break;
  106. case QK_MODS ... QK_MODS_MAX:
  107. keycode_str = "MOD()\0";
  108. break;
  109. case QK_MOD_TAP ... QK_MOD_TAP_MAX:
  110. keycode_str = "MT()\0";
  111. break;
  112. case QK_LAYER_TAP ... QK_LAYER_TAP_MAX:
  113. keycode_str = "LT()\0";
  114. break;
  115. case QK_LAYER_MOD ... QK_LAYER_MOD_MAX:
  116. keycode_str = "LM()\0";
  117. break;
  118. case QK_TO ... QK_TO_MAX:
  119. keycode_str = "TO()\0";
  120. break;
  121. case QK_MOMENTARY ... QK_MOMENTARY_MAX:
  122. keycode_str = "MO()\0";
  123. break;
  124. case QK_DEF_LAYER ... QK_DEF_LAYER_MAX:
  125. keycode_str = "DF()\0";
  126. break;
  127. case QK_TOGGLE_LAYER ... QK_TOGGLE_LAYER_MAX:
  128. keycode_str = "TG()\0";
  129. break;
  130. case QK_ONE_SHOT_LAYER ... QK_ONE_SHOT_MOD_MAX:
  131. keycode_str = "1SHOT\0";
  132. break;
  133. case QK_LAYER_TAP_TOGGLE ... QK_LAYER_TAP_TOGGLE_MAX:
  134. keycode_str = "TT()\0";
  135. break;
  136. case QK_PERSISTENT_DEF_LAYER ... QK_PERSISTENT_DEF_LAYER_MAX:
  137. keycode_str = "PDF()\0";
  138. break;
  139. case QK_SWAP_HANDS ... QK_SWAP_HANDS_MAX:
  140. keycode_str = "SWAP\0";
  141. break;
  142. case QK_TAP_DANCE ... QK_TAP_DANCE_MAX:
  143. keycode_str = "TD()\0";
  144. break;
  145. case QK_MAGIC ... QK_MAGIC_MAX:
  146. keycode_str = "Magic\0";
  147. break;
  148. case QK_MIDI ... QK_MIDI_MAX:
  149. keycode_str = "Midi\0";
  150. break;
  151. case QK_SEQUENCER ... QK_SEQUENCER_MAX:
  152. keycode_str = "Seq\0";
  153. break;
  154. case QK_JOYSTICK ... QK_JOYSTICK_MAX:
  155. keycode_str = "Joy\0";
  156. break;
  157. case QK_PROGRAMMABLE_BUTTON ... QK_PROGRAMMABLE_BUTTON_MAX:
  158. keycode_str = "Prog\0";
  159. break;
  160. case QK_AUDIO ... QK_AUDIO_MAX:
  161. keycode_str = "Audio\0";
  162. break;
  163. case QK_STENO ... QK_STENO_MAX:
  164. keycode_str = "Steno\0";
  165. break;
  166. case QK_MACRO ... QK_MACRO_MAX:
  167. keycode_str = "Macro\0";
  168. break;
  169. case QK_CONNECTION ... QK_CONNECTION_MAX:
  170. keycode_str = "Conn\0";
  171. break;
  172. case QK_LIGHTING ... QK_LIGHTING_MAX:
  173. keycode_str = "Light\0";
  174. break;
  175. case QK_QUANTUM ... QK_QUANTUM_MAX:
  176. keycode_str = "Quant\0";
  177. break;
  178. case QK_KB ... QK_KB_MAX:
  179. keycode_str = "KB\0";
  180. break;
  181. case QK_USER ... QK_USER_MAX:
  182. keycode_str = "USER\0";
  183. break;
  184. case QK_UNICODEMAP ... QK_UNICODEMAP_PAIR_MAX:
  185. keycode_str = "Uni\0";
  186. break;
  187. default:
  188. keycode_str = "Undef\0";
  189. break;
  190. }
  191. return keycode_str;
  192. }
  193. const char *layer_string(uint32_t layer) {
  194. char *layer_str;
  195. switch (layer) {
  196. case 0:
  197. layer_str = "Zero\0";
  198. break;
  199. case 1:
  200. layer_str = "One\0";
  201. break;
  202. case 2:
  203. layer_str = "Two\0";
  204. break;
  205. case 3:
  206. layer_str = "Three\0";
  207. break;
  208. case 4:
  209. layer_str = "Four\0";
  210. break;
  211. case 5:
  212. layer_str = "Five\0";
  213. break;
  214. case 6:
  215. layer_str = "Six\0";
  216. break;
  217. case 7:
  218. layer_str = "Seven\0";
  219. break;
  220. default:
  221. return get_u16_str(layer, ' ');
  222. }
  223. return layer_str;
  224. }
  225. bool process_detected_host_os_kb(os_variant_t detected_os) {
  226. if (!process_detected_host_os_user(detected_os)) {
  227. return false;
  228. }
  229. oled_set_cursor(0, 10);
  230. switch (detected_os) {
  231. case OS_MACOS:
  232. oled_write_ln("MacOS", false);
  233. case OS_IOS:
  234. oled_write_ln("Apple", false);
  235. break;
  236. case OS_WINDOWS:
  237. oled_write_ln("Win", false);
  238. break;
  239. case OS_LINUX:
  240. oled_write_ln("Linux", false);
  241. break;
  242. case OS_UNSURE:
  243. oled_write_ln("Unkno", false);
  244. break;
  245. }
  246. return true;
  247. }
  248. void keyboard_post_init_kb(void) {
  249. if (!is_keyboard_master()) {
  250. render_logo();
  251. } else {
  252. oled_set_cursor(0, 0);
  253. oled_write("Layer", false);
  254. render_spacer(5);
  255. oled_write_ln(layer_string(get_highest_layer(layer_state)), false);
  256. oled_set_cursor(0, 4);
  257. oled_write_ln("Key", false);
  258. render_spacer(3);
  259. oled_advance_page(false);
  260. oled_write_ln("None", false);
  261. oled_set_cursor(0, 8);
  262. oled_write_ln("OS", false);
  263. render_spacer(2);
  264. oled_advance_page(false);
  265. oled_write_ln("Wait", false);
  266. oled_set_cursor(0, 12);
  267. oled_write_ln("Rate", false);
  268. render_spacer(4);
  269. }
  270. keyboard_post_init_user();
  271. }
  272. layer_state_t layer_state_set_kb(layer_state_t state) {
  273. state = layer_state_set_user(state);
  274. oled_set_cursor(0, 2);
  275. oled_write_ln(layer_string(get_highest_layer(state)), false);
  276. return state;
  277. }
  278. bool process_record_kb(uint16_t keycode, keyrecord_t *record) {
  279. current_keycode = keycode;
  280. return process_record_user(keycode, record);
  281. };
  282. uint16_t loop_rate = 0;
  283. void housekeeping_task_kb(void) {
  284. if (is_keyboard_master()) {
  285. static uint32_t loop_count = 0;
  286. static fast_timer_t loop_time = 0;
  287. loop_count++;
  288. if (timer_elapsed_fast(loop_time) > 1000) {
  289. loop_time = timer_read_fast();
  290. loop_rate = loop_count > UINT16_MAX ? UINT16_MAX : loop_count;
  291. loop_count = 0;
  292. if (is_oled_on()) {
  293. oled_set_cursor(0, 14);
  294. oled_write(depad_str(get_u16_str(loop_rate, ' '), ' '), false);
  295. }
  296. }
  297. }
  298. if (is_oled_on() && last_input_activity_elapsed() > OLED_TIMEOUT) {
  299. oled_off();
  300. }
  301. }
  302. void oled_reinit_slave(void) {
  303. oled_init(OLED_ROTATION_270);
  304. oled_clear();
  305. oled_set_cursor(0, 0);
  306. oled_write_ln("WPM", false);
  307. render_spacer(3);
  308. oled_advance_page(false);
  309. oled_write_ln(depad_str(get_u16_str(get_current_wpm(), ' '), ' '), false);
  310. oled_set_cursor(0, 4);
  311. oled_write_ln("RGB", false);
  312. render_spacer(3);
  313. render_rgb_info();
  314. oled_set_cursor(0, 13);
  315. render_small_mb_logo();
  316. }
  317. bool oled_task_kb(void) {
  318. if (!oled_task_user()) {
  319. return false;
  320. }
  321. static uint16_t last_keycode = 0xFF;
  322. static bool oled_slave_init_done = false;
  323. if (is_keyboard_master()) {
  324. if (last_keycode != current_keycode) {
  325. oled_set_cursor(0, 6);
  326. if (current_keycode < ARRAY_SIZE(basic_codes_to_name)) {
  327. oled_write_char(basic_codes_to_name[current_keycode], false);
  328. oled_advance_page(true);
  329. } else {
  330. oled_write_ln(keycode_string(current_keycode), false);
  331. }
  332. last_keycode = current_keycode;
  333. }
  334. } else {
  335. if (!oled_slave_init_done) {
  336. if (timer_elapsed32(0) > 5000) {
  337. oled_slave_init_done = true;
  338. oled_reinit_slave();
  339. }
  340. } else {
  341. static uint16_t last_wpm = 0;
  342. if (rgb_matrix_get_hue() != last_hue || rgb_matrix_get_sat() != last_sat || rgb_matrix_get_val() != last_val || rgb_matrix_get_mode() != last_mode) {
  343. render_rgb_info();
  344. }
  345. if (last_wpm != get_current_wpm()) {
  346. last_wpm = get_current_wpm();
  347. oled_set_cursor(0, 2);
  348. oled_write_ln(depad_str(get_u16_str(last_wpm, ' '), ' '), false);
  349. }
  350. }
  351. }
  352. return false;
  353. }