spidey3.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. // Copyright 2022 Joshua Diamond josh@windowoffire.com (@spidey3)
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include QMK_KEYBOARD_H
  4. #include "spidey3.h"
  5. #include "version.h"
  6. #include <stdlib.h>
  7. static bool rand_seeded = false;
  8. uint16_t spi_replace_mode = SPI_NORMAL;
  9. bool spi_gflock = false;
  10. #if defined(CONSOLE_ENABLE) && !defined(NO_DEBUG)
  11. static uint32_t matrix_scan_count = 0;
  12. static bool reported_version = false;
  13. # if defined(SPI_DEBUG_SCAN_RATE)
  14. static uint32_t matrix_timer = 0;
  15. # endif
  16. void report_version(void) {
  17. uprintln(QMK_KEYBOARD "/" QMK_KEYMAP " @ " QMK_VERSION " - " QMK_BUILDDATE);
  18. reported_version = true;
  19. }
  20. #endif
  21. void matrix_scan_user(void) {
  22. #if defined(CONSOLE_ENABLE) && !defined(NO_DEBUG)
  23. # if defined(SPI_DEBUG_SCAN_RATE)
  24. matrix_scan_count++;
  25. if (debug_enable) {
  26. uint32_t timer_now = timer_read32();
  27. if (matrix_timer == 0) {
  28. matrix_timer = timer_now;
  29. matrix_scan_count = 0;
  30. } else if (TIMER_DIFF_32(timer_now, matrix_timer) > SPI_SCAN_RATE_INTERVAL * 1000) {
  31. matrix_timer = timer_now;
  32. uprintf("scan rate: %lu/s\n", matrix_scan_count / SPI_SCAN_RATE_INTERVAL);
  33. matrix_scan_count = 0;
  34. if (!reported_version) report_version();
  35. }
  36. }
  37. # else
  38. if (!reported_version) {
  39. matrix_scan_count++;
  40. if (matrix_scan_count > 300) report_version();
  41. }
  42. # endif
  43. #endif
  44. #ifdef RGBLIGHT_ENABLE
  45. matrix_scan_user_rgb();
  46. #endif
  47. }
  48. static uint32_t math_glyph_exceptions(const uint16_t keycode, const bool shifted) {
  49. bool caps = host_keyboard_led_state().caps_lock;
  50. if (shifted != caps) {
  51. switch (keycode) {
  52. // clang-format off
  53. case KC_C: return 0x2102;
  54. case KC_H: return 0x210D;
  55. case KC_N: return 0x2115;
  56. case KC_P: return 0x2119;
  57. case KC_Q: return 0x211A;
  58. case KC_R: return 0x211D;
  59. case KC_Z: return 0x2124;
  60. // clang-format on
  61. }
  62. }
  63. return 0;
  64. }
  65. bool process_record_glyph_replacement(uint16_t keycode, keyrecord_t *record, uint32_t baseAlphaLower, uint32_t baseAlphaUpper, uint32_t zeroGlyph, uint32_t baseNumberOne, uint32_t spaceGlyph, uint32_t (*exceptions)(const uint16_t keycode, const bool shifted), uint8_t temp_mod, uint8_t temp_osm) {
  66. void _register(uint32_t codepoint) {
  67. unicode_input_start();
  68. register_hex32(codepoint);
  69. unicode_input_finish();
  70. }
  71. if ((((temp_mod | temp_osm) & (MOD_MASK_CTRL | MOD_MASK_ALT | MOD_MASK_GUI))) == 0) {
  72. bool shifted = ((temp_mod | temp_osm) & MOD_MASK_SHIFT);
  73. if (exceptions) {
  74. uint32_t res = exceptions(keycode, shifted);
  75. if (res) {
  76. if (record->event.pressed) {
  77. _register(res);
  78. }
  79. return false;
  80. }
  81. }
  82. switch (keycode) {
  83. case KC_A ... KC_Z:
  84. if (record->event.pressed) {
  85. clear_mods();
  86. #ifndef NO_ACTION_ONESHOT
  87. clear_oneshot_mods();
  88. #endif
  89. bool caps = host_keyboard_led_state().caps_lock;
  90. uint32_t base = ((shifted == caps) ? baseAlphaLower : baseAlphaUpper);
  91. _register(base + (keycode - KC_A));
  92. set_mods(temp_mod);
  93. }
  94. return false;
  95. case KC_0:
  96. if (shifted) { // skip shifted numbers, so that we can still use symbols etc.
  97. return true;
  98. }
  99. if (record->event.pressed) {
  100. _register(zeroGlyph);
  101. }
  102. return false;
  103. case KC_1 ... KC_9:
  104. if (shifted) { // skip shifted numbers, so that we can still use symbols etc.
  105. return true;
  106. }
  107. if (record->event.pressed) {
  108. _register(baseNumberOne + (keycode - KC_1));
  109. }
  110. return false;
  111. case KC_SPACE:
  112. if (record->event.pressed) {
  113. _register(spaceGlyph); // em space
  114. }
  115. return false;
  116. }
  117. }
  118. return true;
  119. }
  120. bool process_gflock(uint16_t keycode, keyrecord_t *record) {
  121. if (!spi_gflock) {
  122. return true;
  123. }
  124. if (record->event.pressed) {
  125. register_code16(G(keycode));
  126. } else {
  127. unregister_code16(G(keycode));
  128. }
  129. return false;
  130. }
  131. bool process_record_user(uint16_t keycode, keyrecord_t *record) {
  132. dprintf("key event: kc: %02X, col: %02u, row: %02u, pressed: %u mods: %08b "
  133. #if !defined(NO_ACTION_ONESHOT)
  134. "os: %08b "
  135. #endif
  136. "weak: %08b\n",
  137. keycode, record->event.key.col, record->event.key.row, record->event.pressed, bitrev(get_mods()),
  138. #if !defined(NO_ACTION_ONESHOT)
  139. bitrev(get_oneshot_mods()),
  140. #endif
  141. bitrev(get_weak_mods()));
  142. if (!rand_seeded) {
  143. srand(record->event.time % keycode);
  144. rand_seeded = true;
  145. }
  146. uint8_t mods = get_mods();
  147. #ifndef NO_ACTION_ONESHOT
  148. uint8_t osm = get_oneshot_mods();
  149. #else
  150. uint8_t osm = 0;
  151. #endif
  152. if (record->event.pressed) {
  153. switch (keycode) {
  154. #ifndef NO_DEBUG
  155. // Re-implement this here, but fix the persistence!
  156. case QK_DEBUG_TOGGLE:
  157. if (get_mods() & MOD_MASK_SHIFT) {
  158. debug_enable = 0;
  159. debug_keyboard = 0;
  160. debug_matrix = 0;
  161. } else if (!debug_enable) {
  162. debug_enable = 1;
  163. # if defined(SPI_DEBUG_SCAN_RATE)
  164. matrix_timer = 0;
  165. report_version();
  166. # endif
  167. } else if (!debug_keyboard) {
  168. debug_keyboard = 1;
  169. } else if (!debug_matrix) {
  170. debug_matrix = 1;
  171. } else {
  172. debug_enable = 0;
  173. debug_keyboard = 0;
  174. debug_matrix = 0;
  175. }
  176. uprintf("DEBUG: enable=%u, kb=%u, matrix=%u\n", debug_enable, debug_keyboard, debug_matrix);
  177. eeconfig_update_debug(debug_config.raw);
  178. return false;
  179. #endif
  180. // clang-format off
  181. case CH_SUSP: tap_code16(LGUI(LSFT(KC_L))); return true;
  182. // clang-format on
  183. case SPI_NORMAL ... SPI_MATH:
  184. spi_replace_mode = (spi_replace_mode == keycode) ? SPI_NORMAL : keycode;
  185. break;
  186. case SPI_GFLOCK:
  187. spi_gflock = !spi_gflock;
  188. break;
  189. case SPI_KP_00:
  190. tap_code(KC_KP_0);
  191. #if TAP_CODE_DELAY > 0
  192. wait_ms(TAP_CODE_DELAY);
  193. #endif
  194. register_code(KC_KP_0);
  195. return false;
  196. case KC_PSCR: {
  197. // It's kind of a hack, but we use unicode input mode
  198. // to determine what Print Screen key should do. The
  199. // idea here is to make it consistent across hosts.
  200. switch (get_unicode_input_mode()) {
  201. case UNICODE_MODE_MACOS:
  202. if ((mods | osm) & MOD_MASK_ALT) {
  203. // Window screenshot
  204. clear_mods();
  205. #ifndef NO_ACTION_ONESHOT
  206. clear_oneshot_mods();
  207. #endif
  208. tap_code16(LSFT(LGUI(KC_4)));
  209. wait_ms(100);
  210. tap_code(KC_SPC);
  211. set_mods(mods);
  212. return false;
  213. } else if ((mods | osm) & MOD_MASK_SHIFT) {
  214. // Partial screenshot
  215. tap_code16(LSFT(LGUI(KC_4)));
  216. return false;
  217. } else {
  218. // Full screenshot
  219. tap_code16(LSFT(LGUI(KC_3)));
  220. return false;
  221. }
  222. break;
  223. case UNICODE_MODE_WINDOWS:
  224. case UNICODE_MODE_WINCOMPOSE:
  225. if ((mods | osm) & MOD_MASK_ALT) {
  226. // Window screenshot
  227. // Alt+PrintScreen should work as is
  228. } else if ((mods | osm) & MOD_MASK_SHIFT) {
  229. // Partial screenshot
  230. tap_code16(LGUI(LSFT(KC_S)));
  231. return false;
  232. } else {
  233. // Full screenshot
  234. // PrintScreen should work as is
  235. }
  236. break;
  237. default:
  238. // Note: These are specific to ChromeOS
  239. if ((mods | osm) & MOD_MASK_ALT) {
  240. // Window screenshot
  241. tap_code16(LCTL(LALT(KC_F5)));
  242. return false;
  243. } else if ((mods | osm) & MOD_MASK_SHIFT) {
  244. // Partial screenshot
  245. tap_code16(LCTL(LSFT(KC_F5)));
  246. return false;
  247. } else {
  248. // Full screenshot
  249. // PrintScreen should work as is
  250. }
  251. break;
  252. }
  253. break;
  254. }
  255. }
  256. } else {
  257. switch (keycode) {
  258. case SPI_KP_00:
  259. unregister_code(KC_KP_0);
  260. return false;
  261. }
  262. }
  263. switch (keycode) {
  264. case KC_A ... KC_0:
  265. case KC_SPACE:
  266. switch (spi_replace_mode) {
  267. case SPI_WIDE:
  268. return process_record_glyph_replacement(keycode, record, 0xFF41, 0xFF21, 0xFF10, 0xFF11, 0x2003, NULL, mods, osm);
  269. case SPI_SCRIPT:
  270. return process_record_glyph_replacement(keycode, record, 0x1D4EA, 0x1D4D0, 0x1D7CE, 0x1D7CF, 0x2002, NULL, mods, osm);
  271. case SPI_BLOCKS:
  272. return process_record_glyph_replacement(keycode, record, 0x1F170, 0x1F170, '0', '1', 0x2002, NULL, mods, osm);
  273. case SPI_CIRCLE:
  274. return process_record_glyph_replacement(keycode, record, 0x1F150, 0x1F150, '0', '1', 0x2002, NULL, mods, osm);
  275. case SPI_SQUARE:
  276. return process_record_glyph_replacement(keycode, record, 0x1F130, 0x1F130, '0', '1', 0x2002, NULL, mods, osm);
  277. case SPI_PARENS:
  278. return process_record_glyph_replacement(keycode, record, 0x1F110, 0x1F110, '0', '1', 0x2002, NULL, mods, osm);
  279. case SPI_FRAKTR:
  280. return process_record_glyph_replacement(keycode, record, 0x1D586, 0x1D56C, '0', '1', 0x2002, NULL, mods, osm);
  281. case SPI_BOLD:
  282. return process_record_glyph_replacement(keycode, record, 0x1D41A, 0x1D400, '0', '1', 0x2002, NULL, mods, osm);
  283. case SPI_MATH:
  284. return process_record_glyph_replacement(keycode, record, 0x1D552, 0x1D538, '0', '1', 0x2002, &math_glyph_exceptions, mods, osm);
  285. }
  286. break;
  287. case KC_F1 ... KC_F12:
  288. return process_gflock(keycode, record);
  289. #ifdef SHIFT_BACKSPACE_DELETE
  290. case KC_BSPC: {
  291. static bool delkey_registered;
  292. if (record->event.pressed) {
  293. if ((mods | osm) & MOD_MASK_SHIFT) {
  294. del_mods(MOD_MASK_SHIFT);
  295. # ifndef NO_ACTION_ONESHOT
  296. clear_oneshot_mods();
  297. # endif
  298. register_code(KC_DEL);
  299. delkey_registered = true;
  300. set_mods(mods);
  301. return false;
  302. }
  303. } else { // on release of KC_BSPC
  304. // In case KC_DEL is still being sent even after the release of KC_BSPC
  305. if (delkey_registered) {
  306. unregister_code(KC_DEL);
  307. delkey_registered = false;
  308. return false;
  309. }
  310. }
  311. }
  312. #endif
  313. }
  314. #ifdef RGBLIGHT_ENABLE
  315. return process_record_user_rgb(keycode, record);
  316. #else
  317. return true;
  318. #endif
  319. }
  320. void post_process_record_user(uint16_t keycode, keyrecord_t *record) {
  321. #ifdef RGBLIGHT_ENABLE
  322. post_process_record_user_rgb(keycode, record);
  323. #endif
  324. return;
  325. }
  326. layer_state_t default_layer_state_set_user(layer_state_t state) {
  327. #ifdef RGBLIGHT_ENABLE
  328. return default_layer_state_set_user_rgb(state);
  329. #else
  330. return state;
  331. #endif
  332. }
  333. layer_state_t layer_state_set_user(layer_state_t state) {
  334. #ifdef RGBLIGHT_ENABLE
  335. return layer_state_set_user_rgb(state);
  336. #else
  337. return state;
  338. #endif
  339. }
  340. bool led_update_user(led_t led_state) {
  341. #ifdef RGBLIGHT_ENABLE
  342. return led_update_user_rgb(led_state);
  343. #else
  344. return true;
  345. #endif
  346. }
  347. #if defined(UNICODE_COMMON_ENABLE)
  348. void unicode_input_mode_set_user(uint8_t input_mode) {
  349. # ifdef RGBLIGHT_ENABLE
  350. unicode_input_mode_set_user_rgb(input_mode);
  351. # endif
  352. }
  353. #endif