qmk-firmware/keyboards/massdrop/ctrl/keymaps/responsive_pattern/keymap.c
Jeff Epler 9632360caa
Use a macro to compute the size of arrays at compile time (#18044)
* Add ARRAY_SIZE and CEILING utility macros

* Apply a coccinelle patch to use ARRAY_SIZE

* fix up some straggling items

* Fix 'make test:secure'

* Enhance ARRAY_SIZE macro to reject acting on pointers

The previous definition would not produce a diagnostic for
```
int *p;
size_t num_elem = ARRAY_SIZE(p)
```
but the new one will.

* explicitly get definition of ARRAY_SIZE

* Convert to ARRAY_SIZE when const is involved

The following spatch finds additional instances where the array is
const and the division is by the size of the type, not the size of
the first element:
```
@ rule5a using "empty.iso" @
type T;
const T[] E;
@@

- (sizeof(E)/sizeof(T))
+ ARRAY_SIZE(E)

@ rule6a using "empty.iso" @
type T;
const T[] E;
@@

- sizeof(E)/sizeof(T)
+ ARRAY_SIZE(E)
```

* New instances of ARRAY_SIZE added since initial spatch run

* Use `ARRAY_SIZE` in docs (found by grep)

* Manually use ARRAY_SIZE

hs_set is expected to be the same size as uint16_t, though it's made
of two 8-bit integers

* Just like char, sizeof(uint8_t) is guaranteed to be 1

This is at least true on any plausible system where qmk is actually used.

Per my understanding it's universally true, assuming that uint8_t exists:
https://stackoverflow.com/questions/48655310/can-i-assume-that-sizeofuint8-t-1

* Run qmk-format on core C files touched in this branch

Co-authored-by: Stefan Kerkmann <karlk90@pm.me>
2022-08-30 10:20:04 +02:00

765 lines
35 KiB
C

#include QMK_KEYBOARD_H
#include <math.h> // sqrtf, powf
#ifdef CONSOLE_ENABLE
#include <print.h>
#endif
enum ctrl_keycodes {
L_BRI = SAFE_RANGE, //LED Brightness Increase //Working
L_BRD, //LED Brightness Decrease //Working
L_PTN, //LED Pattern Select Next //Working
L_PTP, //LED Pattern Select Previous //Working
L_PSI, //LED Pattern Speed Increase //Working
L_PSD, //LED Pattern Speed Decrease //Working
L_T_MD, //LED Toggle Mode //Working
L_T_ONF, //LED Toggle On / Off //Broken
L_ON, //LED On //Broken
L_OFF, //LED Off //Broken
L_T_BR, //LED Toggle Breath Effect //Working
L_T_PTD, //LED Toggle Scrolling Pattern Direction //Working
U_T_AGCR, //USB Toggle Automatic GCR control //Working
DBG_TOG, //DEBUG Toggle On / Off //
DBG_MTRX, //DEBUG Toggle Matrix Prints //
DBG_KBD, //DEBUG Toggle Keyboard Prints //
DBG_MOU, //DEBUG Toggle Mouse Prints //
MD_BOOT, //Restart into bootloader after hold timeout //Working
L_SP_PR, //LED Splash Pattern Select Previous
L_SP_NE, //LED Splash Pattern Select Next
L_SP_WD, //LED Splash Widen Wavefront width
L_SP_NW, //LED Splash Narrow Wavefront width
L_SP_FA, //LED Splash wave travel speed faster (shorter period)
L_SP_SL, //LED Splash wave travel speed slower (longer period)
L_CP_PR, //LED Color Pattern Select Previous
L_CP_NX, //LEB Color Pattern Select Next
S_RESET // reset all parameters
};
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
[0] = LAYOUT(
KC_ESC, 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_PSCR, KC_SLCK, KC_PAUS, \
KC_GRV, 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, KC_INS, KC_HOME, KC_PGUP, \
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, KC_DEL, KC_END, KC_PGDN, \
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_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, \
KC_LCTL, KC_LGUI, KC_LALT, KC_SPC, KC_RALT, MO(1), KC_APP, KC_RCTL, KC_LEFT, KC_DOWN, KC_RGHT \
),
[1] = LAYOUT(
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, KC_MUTE, _______, _______, \
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, KC_MPLY, KC_MSTP, KC_VOLU, \
L_T_BR, L_PSD, L_BRI, L_PSI, _______, _______, _______, _______, U_T_AGCR,_______, MO(2), _______, _______, _______, KC_MPRV, KC_MNXT, KC_VOLD, \
L_T_PTD, L_PTP, L_BRD, L_PTN, _______, _______, _______, _______, _______, _______, _______, _______, _______, \
_______, L_T_MD, L_T_ONF, _______, _______, MD_BOOT, NK_TOGG, _______, _______, _______, _______, _______, _______, \
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______ \
),
[2] = LAYOUT(
S_RESET, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, \
S_RESET, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, \
L_CP_NX, L_SP_SL, L_SP_WD, L_SP_FA, _______, _______, L_CP_NX, L_SP_SL, L_SP_WD, L_SP_FA, _______, _______, _______, _______, _______, _______, _______, \
L_CP_PR, L_SP_PR, L_SP_NW, L_SP_NE, _______, _______, L_CP_PR, L_SP_PR, L_SP_NW, L_SP_NE, _______, _______, _______, \
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, \
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______ \
)
/*
[X] = LAYOUT(
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, \
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, \
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, \
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, \
_______, _______, _______, _______, _______, _______, NK_TOGG, _______, _______, _______, _______, _______, _______, \
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______ \
),
*/
};
#define DISTANCE_NORAMLIZING_PARAMETER 3
struct {
uint8_t PATTERN_INDEX;
float WAVE_WIDTH;
float WAVE_SPEED;
int COLOR_PATTERN_INDEX;
float TRAVEL_DISTANCE;
} USER_CONFIG = {
.PATTERN_INDEX = 1,
.WAVE_WIDTH = 10, // width of the wave in keycaps
.WAVE_SPEED = 15, // travel how many keycaps per second
.COLOR_PATTERN_INDEX = 0,
.TRAVEL_DISTANCE = 25,
};
#define COLOR_PATTERN_RGB_COUNT 18
static uint8_t COLOR_PATTERNS[][COLOR_PATTERN_RGB_COUNT][3] = {
{ // default rainbow color
{255, 0, 0}, {255, 0, 0}, {255, 127, 0},
{255, 127, 0}, {255, 255, 0}, {255, 255, 0},
{120, 255, 0}, {120, 255, 0}, { 0, 255, 0},
{ 0, 255, 0}, { 0, 255, 120}, { 0, 255, 120},
{ 0, 0, 255}, { 0, 0, 255}, { 75, 0, 130},
{ 75, 0, 130}, { 43, 0, 130}, { 43, 0, 130},
}, { // light rainbow color
{248, 12, 18}, {238, 17, 0}, {255, 51, 17},
{255, 68, 32}, {255, 102, 68}, {255, 153, 51},
{254, 174, 45}, {204, 187, 51}, {208, 195, 16},
{170, 204, 34}, {105, 208, 37}, { 34, 204, 170},
{ 18, 189, 185}, { 17, 170, 187}, { 68, 68, 221},
{ 51, 17, 187}, { 59, 12, 189}, { 68, 34, 153},
}, { // white flat
{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, 255},
{255, 255, 255}, {255, 255, 255}, {255, 255, 255},
{255, 255, 255}, {255, 255, 255}, {255, 255, 255},
}, { // white fade, cos curve
{255, 255, 255}, {255, 255, 255}, {252, 252, 252},
{247, 247, 247}, {240, 240, 240}, {232, 232, 232},
{221, 221, 221}, {209, 209, 209}, {196, 196, 196},
{181, 181, 181}, {164, 164, 164}, {147, 147, 147},
{128, 128, 128}, {108, 108, 108}, { 88, 88, 88},
{ 66, 66, 66}, { 45, 45, 45}, { 23, 23, 23},
},
};
static const uint8_t COLOR_PATTERNS_COUNT = ARRAY_SIZE(COLOR_PATTERNS);
/**
* trimed down version of `ISSI3733_LED_MAP`:
*
* `ISSI3733_LED_MAP` is defined in keyboards/massdrop/ctrl/config_led.h is not directly usable,
* the numbers inside this map could probably be related to the PCB layout instead of
* the actual physical layout,
*
* this `ISSI3733_LED_MAP` is used somewhere in protocol/ but is not globally accessible
* so one is created here
*
* x and y are coordinates of the physical layout
* KC_ESC is (0, 0), gap between function keys and number rows is 1.5
* +y is downwards
* 1 unit is width/height of 1 standard keycap
*/
#define MAX_LED_ID ISSI3733_LED_COUNT
typedef struct led_info_s {
uint16_t id;
uint16_t scan;
float x;
float y;
uint8_t distance_to[MAX_LED_ID + 1];
} led_info_t;
led_info_t led_info[MAX_LED_ID + 1] = {
{ .id = 0 },
{ .id = 1, .x = 0.0, .y = 0.0, .scan = 41 }, // ESC
{ .id = 2, .x = 2.0, .y = 0.0, .scan = 58 }, // F1
{ .id = 3, .x = 3.0, .y = 0.0, .scan = 59 }, // F2
{ .id = 4, .x = 3.5, .y = 0.0, .scan = 60 }, // F3
{ .id = 5, .x = 5.0, .y = 0.0, .scan = 61 }, // F4
{ .id = 6, .x = 6.5, .y = 0.0, .scan = 62 }, // F5
{ .id = 7, .x = 7.5, .y = 0.0, .scan = 63 }, // F6
{ .id = 8, .x = 8.5, .y = 0.0, .scan = 64 }, // F7
{ .id = 9, .x = 9.5, .y = 0.0, .scan = 65 }, // F8
{ .id = 10, .x = 11, .y = 0.0, .scan = 66 }, // F9
{ .id = 11, .x = 12, .y = 0.0, .scan = 67 }, // F10
{ .id = 12, .x = 13, .y = 0.0, .scan = 68 }, // F11
{ .id = 13, .x = 14, .y = 0.0, .scan = 69 }, // F12
{ .id = 14, .x = 15.5, .y = 0.0, .scan = 70 }, // Print
{ .id = 15, .x = 16.5, .y = 0.0, .scan = 71 }, // Scoll Lock
{ .id = 16, .x = 17.5, .y = 0.0, .scan = 72 }, // Pause
{ .id = 17, .x = 0.0, .y = 1.5, .scan = 53 }, // `
{ .id = 18, .x = 1.0, .y = 1.5, .scan = 30 }, // 1
{ .id = 19, .x = 2.0, .y = 1.5, .scan = 31 }, // 2
{ .id = 20, .x = 3.0, .y = 1.5, .scan = 32 }, // 3
{ .id = 21, .x = 3.5, .y = 1.5, .scan = 33 }, // 4
{ .id = 22, .x = 5.0, .y = 1.5, .scan = 34 }, // 5
{ .id = 23, .x = 6.0, .y = 1.5, .scan = 35 }, // 6
{ .id = 24, .x = 7.0, .y = 1.5, .scan = 36 }, // 7
{ .id = 25, .x = 8.0, .y = 1.5, .scan = 37 }, // 8
{ .id = 26, .x = 9.0, .y = 1.5, .scan = 38 }, // 9
{ .id = 27, .x = 10.0, .y = 1.5, .scan = 39 }, // 0
{ .id = 28, .x = 11.0, .y = 1.5, .scan = 45 }, // -
{ .id = 29, .x = 12.0, .y = 1.5, .scan = 46 }, // =
{ .id = 30, .x = 13.5, .y = 1.5, .scan = 42 }, // Backspace
{ .id = 31, .x = 15.5, .y = 1.5, .scan = 73 }, // Insert
{ .id = 32, .x = 16.6, .y = 1.5, .scan = 74 }, // Home
{ .id = 33, .x = 17.5, .y = 1.5, .scan = 75 }, // Page Up
{ .id = 34, .x = 0.2, .y = 2.5, .scan = 43 }, // Tab
{ .id = 35, .x = 1.5, .y = 2.5, .scan = 20 }, // Q
{ .id = 36, .x = 2.5, .y = 2.5, .scan = 26 }, // W
{ .id = 37, .x = 3.5, .y = 2.5, .scan = 8 }, // E
{ .id = 38, .x = 4.5, .y = 2.5, .scan = 21 }, // R
{ .id = 39, .x = 5.5, .y = 2.5, .scan = 23 }, // T
{ .id = 40, .x = 6.5, .y = 2.5, .scan = 28 }, // Y
{ .id = 41, .x = 7.5, .y = 2.5, .scan = 24 }, // U
{ .id = 42, .x = 8.5, .y = 2.5, .scan = 12 }, // I
{ .id = 43, .x = 9.5, .y = 2.5, .scan = 18 }, // O
{ .id = 44, .x = 10.5, .y = 2.5, .scan = 19 }, // P
{ .id = 45, .x = 11.5, .y = 2.5, .scan = 47 }, // [
{ .id = 46, .x = 12.5, .y = 2.5, .scan = 48 }, // ]
{ .id = 47, .x = 13.75, .y = 2.5, .scan = 49 }, /* \ */
{ .id = 48, .x = 15.5, .y = 2.5, .scan = 76 }, // Delete
{ .id = 49, .x = 16.5, .y = 2.5, .scan = 77 }, // End
{ .id = 50, .x = 17.5, .y = 2.5, .scan = 78 }, // Page Down
{ .id = 51, .x = 0.4, .y = 3.5, .scan = 57 }, // Caps Lock
{ .id = 52, .x = 2.5, .y = 3.5, .scan = 4 }, // A
{ .id = 53, .x = 3.5, .y = 3.5, .scan = 22 }, // S
{ .id = 54, .x = 4.5, .y = 3.5, .scan = 7 }, // D
{ .id = 55, .x = 5.5, .y = 3.5, .scan = 9 }, // F
{ .id = 56, .x = 6.5, .y = 3.5, .scan = 10 }, // G
{ .id = 57, .x = 7.5, .y = 3.5, .scan = 11 }, // H
{ .id = 58, .x = 8.5, .y = 3.5, .scan = 13 }, // J
{ .id = 59, .x = 9.5, .y = 3.5, .scan = 14 }, // K
{ .id = 60, .x = 10.5, .y = 3.5, .scan = 15 }, // L
{ .id = 61, .x = 11.5, .y = 3.5, .scan = 51 }, // ;
{ .id = 62, .x = 12.5, .y = 3.5, .scan = 52 }, // '
{ .id = 63, .x = 13.5, .y = 3.5, .scan = 40 }, // Enter
{ .id = 64, .x = 0.5, .y = 4.5, .scan = 225 }, // LSHIFT
{ .id = 65, .x = 2.25, .y = 4.5, .scan = 29 }, // Z
{ .id = 66, .x = 3.25, .y = 4.5, .scan = 27 }, // X
{ .id = 67, .x = 4.25, .y = 4.5, .scan = 6 }, // C
{ .id = 68, .x = 5.25, .y = 4.5, .scan = 25 }, // V
{ .id = 69, .x = 6.25, .y = 4.5, .scan = 5 }, // B
{ .id = 70, .x = 7.25, .y = 4.5, .scan = 17 }, // N
{ .id = 71, .x = 8.25, .y = 4.5, .scan = 16 }, // M
{ .id = 72, .x = 9.25, .y = 4.5, .scan = 54 }, // COMMA
{ .id = 73, .x = 10.25, .y = 4.5, .scan = 55 }, // DOT
{ .id = 74, .x = 11.25, .y = 4.5, .scan = 56 }, // SLASH
{ .id = 75, .x = 13.2, .y = 4.5, .scan = 229 }, // RSHIFT
{ .id = 76, .x = 16.5, .y = 4.5, .scan = 82 }, // UP
{ .id = 77, .x = 0.1, .y = 5.5, .scan = 224 }, // LCTRL
{ .id = 78, .x = 1.25, .y = 5.5, .scan = 227 }, // WIN
{ .id = 79, .x = 2.5, .y = 5.5, .scan = 226 }, // LALT
{ .id = 80, .x = 6.25, .y = 5.5, .scan = 44 }, // SPACE
#define MAX_CACHED_SCAN_CODE 231
{ .id = 81, .x = 10.25, .y = 5.5, .scan = 230 }, // RALT
#define FN_KEY_LED_ID 82
#define FN_KEY_SCAN_CODE 20737
{ .id = 82, .x = 11.5, .y = 5.5, .scan = 20737 }, // FN
{ .id = 83, .x = 12.7, .y = 5.5, .scan = 101 }, // APP
{ .id = 84, .x = 13.75, .y = 5.5, .scan = 228 }, // RCTRL
{ .id = 85, .x = 15.5, .y = 5.5, .scan = 80 }, // LEFT
{ .id = 86, .x = 16.5, .y = 5.5, .scan = 81 }, // DOWN
{ .id = 87, .x = 17.5, .y = 5.5, .scan = 79 }, // RIGHT
#define MAX_LED_ID_WITH_SCANCODE 87
{ .id = 88, .x = 18.5, .y = 6.5, .scan = 255 },
{ .id = 89, .x = 16.917, .y = 6.5, .scan = 255 },
{ .id = 90, .x = 15.333, .y = 6.5, .scan = 255 },
{ .id = 91, .x = 13.75, .y = 6.5, .scan = 255 },
{ .id = 92, .x = 12.167, .y = 6.5, .scan = 255 },
{ .id = 93, .x = 10.583, .y = 6.5, .scan = 255 },
{ .id = 94, .x = 9, .y = 6.5, .scan = 255 },
{ .id = 95, .x = 7.417, .y = 6.5, .scan = 255 },
{ .id = 96, .x = 5.833, .y = 6.5, .scan = 255 },
{ .id = 97, .x = 4.25, .y = 6.5, .scan = 255 },
{ .id = 98, .x = 2.667, .y = 6.5, .scan = 255 },
{ .id = 99, .x = 1.083, .y = 6.5, .scan = 255 },
{ .id = 100, .x = -0.5, .y = 6.5, .scan = 255 },
{ .id = 101, .x = -0.5, .y = 4.75, .scan = 255 },
{ .id = 102, .x = -0.5, .y = 3, .scan = 255 },
{ .id = 103, .x = -0.5, .y = 1.25, .scan = 255 },
{ .id = 104, .x = -0.5, .y = -0.5, .scan = 255 },
{ .id = 105, .x = 1.083, .y = -0.5, .scan = 255 },
{ .id = 106, .x = 2.667, .y = -0.5, .scan = 255 },
{ .id = 107, .x = 4.25, .y = -0.5, .scan = 255 },
{ .id = 108, .x = 5.833, .y = -0.5, .scan = 255 },
{ .id = 109, .x = 7.417, .y = -0.5, .scan = 255 },
{ .id = 110, .x = 9, .y = -0.5, .scan = 255 },
{ .id = 111, .x = 10.583, .y = -0.5, .scan = 255 },
{ .id = 112, .x = 12.167, .y = -0.5, .scan = 255 },
{ .id = 113, .x = 13.75, .y = -0.5, .scan = 255 },
{ .id = 114, .x = 15.333, .y = -0.5, .scan = 255 },
{ .id = 115, .x = 16.917, .y = -0.5, .scan = 255 },
{ .id = 116, .x = 18.5, .y = 1.25, .scan = 255 },
{ .id = 117, .x = 18.5, .y = 3, .scan = 255 },
{ .id = 118, .x = 18.5, .y = 4.75, .scan = 255 },
{ .id = 119, .x = 18.5, .y = 6.5, .scan = 255 },
};
/**
* there are a few variables are used here
* keycode, scancode, led id
*
* scancode relates to actual physical key press
*
* keycode is software key press, or scancode with modifiers (shift, ctrl, alt, etc.),
* keycode with the value less than 255 are usually the same with scan code (I hope so)
*
* the led pattern are running based on led id, because led on the keyboard
* are not limited to keys only
*/
led_info_t* get_led_info_by_scancode(uint16_t scancode){
static bool init = false;
static led_info_t* scancode_to_led_info[MAX_CACHED_SCAN_CODE + 1];
if(!init){
for(int i = 1; i <= MAX_LED_ID_WITH_SCANCODE; ++i){
uint16_t scan = led_info[i].scan;
if(scan <= MAX_CACHED_SCAN_CODE){
scancode_to_led_info[scan] = (led_info + i);
}
}
init = true;
}
if(scancode <= MAX_CACHED_SCAN_CODE){
return scancode_to_led_info[scancode];
} else if(scancode == FN_KEY_SCAN_CODE){ // FN
return (led_info + FN_KEY_LED_ID);
}
return led_info;
}
void init_led_info(void){
for(int i = 1; i <= MAX_LED_ID; ++i){
led_info_t *entry1 = led_info + i;
for(int j = i; j <= MAX_LED_ID; ++j){
led_info_t *entry2 = led_info + j;
/**
* distance is tripled because
* convertion from float to int reduces accuracy
*
*/
uint8_t distance = (uint8_t)sqrtf(
powf(entry1->x - entry2->x, 2.0) +
powf(entry1->y - entry2->y, 2.0)) *
DISTANCE_NORAMLIZING_PARAMETER;
entry1->distance_to[j] = distance;
entry2->distance_to[i] = distance;
}
}
};
// Runs just one time when the keyboard initializes.
void matrix_init_user(void) {
init_led_info();
};
typedef struct keystroke_s {
uint16_t scancode;
uint32_t timer;
bool active;
} keystroke_t;
#define MAX_ACTIVE_KEYSTORKES 10
keystroke_t ACTIVE_KEYSTROKES[MAX_ACTIVE_KEYSTORKES];
void reset_led_for_instruction(int led_instruction_index){
led_instructions[led_instruction_index].id0 = 0;
led_instructions[led_instruction_index].id1 = 0;
led_instructions[led_instruction_index].id2 = 0;
led_instructions[led_instruction_index].id3 = 0;
};
void add_led_to_instruction(int led_instruction_index, int led_id){
if(32 >= led_id && led_id >= 1){
led_instructions[led_instruction_index].id0 += ( 1 << (led_id - 1) );
} else if(64 >= led_id){
led_instructions[led_instruction_index].id1 += ( 1 << (led_id - 33) );
} else if(96 >= led_id){
led_instructions[led_instruction_index].id2 += ( 1 << (led_id - 65) );
} else if(128 >= led_id){
led_instructions[led_instruction_index].id3 += ( 1 << (led_id - 97) );
}
};
void wave_effect(void);
void set_wave_color(int);
// Runs constantly in the background, in a loop.
void matrix_scan_user(void) {
wave_effect();
set_wave_color(USER_CONFIG.PATTERN_INDEX);
};
#define MODS_SHIFT (get_mods() & MOD_BIT(KC_LSHIFT) || get_mods() & MOD_BIT(KC_RSHIFT))
#define MODS_CTRL (get_mods() & MOD_BIT(KC_LCTL) || get_mods() & MOD_BIT(KC_RCTRL))
#define MODS_ALT (get_mods() & MOD_BIT(KC_LALT) || get_mods() & MOD_BIT(KC_RALT))
void register_keystroke(uint16_t keycode){
if(get_led_info_by_scancode(keycode)->id){
uint32_t oldest_keystroke_lifespan = 0;
int8_t oldest_keystroke_index = -1;
bool registered = false;
keystroke_t *keystroke = ACTIVE_KEYSTROKES;
for(int i = 0; i < MAX_ACTIVE_KEYSTORKES; ++i){
if(!keystroke->active){
keystroke->scancode = keycode;
keystroke->timer = timer_read32();
keystroke->active = true;
registered = true;
break;
}
uint32_t lifespan = timer_elapsed32(keystroke->timer);
if(lifespan > oldest_keystroke_lifespan){
oldest_keystroke_index = i;
oldest_keystroke_lifespan = lifespan;
}
++keystroke;
}
// override the oldest keystroke
if(!registered){
keystroke = ACTIVE_KEYSTROKES + oldest_keystroke_index;
keystroke->scancode = keycode;
keystroke->timer = timer_read32();
keystroke->active = true; // presumably active already
}
}
}
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
static uint32_t key_timer;
switch (keycode) {
case L_BRI:
if (record->event.pressed) {
if (LED_GCR_STEP > LED_GCR_MAX - gcr_desired) gcr_desired = LED_GCR_MAX;
else gcr_desired += LED_GCR_STEP;
if (led_animation_breathing) gcr_breathe = gcr_desired;
}
return false;
case L_BRD:
if (record->event.pressed) {
if (LED_GCR_STEP > gcr_desired) gcr_desired = 0;
else gcr_desired -= LED_GCR_STEP;
if (led_animation_breathing) gcr_breathe = gcr_desired;
}
return false;
case L_PTN:
if (record->event.pressed) {
if (led_animation_id == led_setups_count - 1) led_animation_id = 0;
else led_animation_id++;
}
return false;
case L_PTP:
if (record->event.pressed) {
if (led_animation_id == 0) led_animation_id = led_setups_count - 1;
else led_animation_id--;
}
return false;
case L_PSI:
if (record->event.pressed) {
led_animation_speed += ANIMATION_SPEED_STEP;
}
return false;
case L_PSD:
if (record->event.pressed) {
led_animation_speed -= ANIMATION_SPEED_STEP;
if (led_animation_speed < 0) led_animation_speed = 0;
}
return false;
case L_T_MD:
if (record->event.pressed) {
led_lighting_mode++;
if (led_lighting_mode > LED_MODE_MAX_INDEX) led_lighting_mode = LED_MODE_NORMAL;
}
return false;
case L_T_ONF:
if (record->event.pressed) {
led_enabled = !led_enabled;
I2C3733_Control_Set(led_enabled);
}
return false;
case L_ON:
if (record->event.pressed) {
led_enabled = 1;
I2C3733_Control_Set(led_enabled);
}
return false;
case L_OFF:
if (record->event.pressed) {
led_enabled = 0;
I2C3733_Control_Set(led_enabled);
}
return false;
case L_T_BR:
if (record->event.pressed) {
led_animation_breathing = !led_animation_breathing;
if (led_animation_breathing) {
gcr_breathe = gcr_desired;
led_animation_breathe_cur = BREATHE_MIN_STEP;
breathe_dir = 1;
}
}
return false;
case L_T_PTD:
if (record->event.pressed) {
led_animation_direction = !led_animation_direction;
}
return false;
case U_T_AGCR:
if (record->event.pressed && MODS_SHIFT && MODS_CTRL) {
TOGGLE_FLAG_AND_PRINT(usb_gcr_auto, "USB GCR auto mode");
}
return false;
case DBG_TOG:
if (record->event.pressed) {
TOGGLE_FLAG_AND_PRINT(debug_enable, "Debug mode");
}
return false;
case DBG_MTRX:
if (record->event.pressed) {
TOGGLE_FLAG_AND_PRINT(debug_matrix, "Debug matrix");
}
return false;
case DBG_KBD:
if (record->event.pressed) {
TOGGLE_FLAG_AND_PRINT(debug_keyboard, "Debug keyboard");
}
return false;
case DBG_MOU:
if (record->event.pressed) {
TOGGLE_FLAG_AND_PRINT(debug_mouse, "Debug mouse");
}
return false;
case MD_BOOT:
if (record->event.pressed) {
key_timer = timer_read32();
} else {
if (timer_elapsed32(key_timer) >= 500) {
reset_keyboard();
}
}
return false;
case S_RESET:
// reset all parameters
USER_CONFIG.PATTERN_INDEX = 1;
USER_CONFIG.WAVE_WIDTH = 10;
USER_CONFIG.WAVE_SPEED = 15;
USER_CONFIG.COLOR_PATTERN_INDEX = 0;
USER_CONFIG.TRAVEL_DISTANCE = 25;
return false;
case L_SP_PR: // previous dripple pattern
case L_SP_NE: // next dripple pattern
if (record->event.pressed) {
#define PATTERN_COUNT 7
uint8_t incre = keycode == L_SP_PR ? PATTERN_COUNT-1 : 1;
USER_CONFIG.PATTERN_INDEX += incre;
USER_CONFIG.PATTERN_INDEX %= PATTERN_COUNT;
if(USER_CONFIG.PATTERN_INDEX <= 4){
USER_CONFIG.TRAVEL_DISTANCE = 25;
USER_CONFIG.COLOR_PATTERN_INDEX = 0;
USER_CONFIG.WAVE_SPEED = 10;
}
switch(USER_CONFIG.PATTERN_INDEX){
case 0: // None
break;
case 1: // background off, wave on
USER_CONFIG.WAVE_WIDTH = 2;
break;
case 2: // background on, wave off
USER_CONFIG.WAVE_WIDTH = 5;
break;
case 3: // background off, rainbow wave
USER_CONFIG.WAVE_WIDTH = 10;
break;
case 4: // background on, rainbow wave
USER_CONFIG.WAVE_WIDTH = 10;
break;
case 5:
USER_CONFIG.WAVE_WIDTH = 10;
USER_CONFIG.COLOR_PATTERN_INDEX = 2;
USER_CONFIG.TRAVEL_DISTANCE = 0;
USER_CONFIG.WAVE_SPEED = 10;
break;
case 6:
USER_CONFIG.WAVE_WIDTH = 10;
USER_CONFIG.COLOR_PATTERN_INDEX = 3;
USER_CONFIG.TRAVEL_DISTANCE = 2;
USER_CONFIG.WAVE_SPEED = 10;
break;
}
// remove effect after changing pattern
for(int i = 0; i < MAX_ACTIVE_KEYSTORKES; ++i){
ACTIVE_KEYSTROKES[i].active = 0;
}
}
return false;
case L_SP_WD:
case L_SP_NW:
if(record->event.pressed){
short incre = keycode == L_SP_WD ? 1 : -1;
USER_CONFIG.WAVE_WIDTH += incre;
if(USER_CONFIG.WAVE_WIDTH < 1){
USER_CONFIG.WAVE_WIDTH = 1;
}
}
return false;
case L_SP_FA:
case L_SP_SL:
if(record->event.pressed){
short incre = keycode == L_SP_FA ? -1 : 1;
USER_CONFIG.WAVE_SPEED += incre;
if(USER_CONFIG.WAVE_SPEED > 50){
USER_CONFIG.WAVE_SPEED = 50;
} else if(USER_CONFIG.WAVE_SPEED < 1){
USER_CONFIG.WAVE_SPEED = 1;
}
}
return false;
// these are the keys not in range 0x04 - 0x52
case L_CP_PR:
case L_CP_NX:
if(record->event.pressed){
uint8_t incre = keycode == L_CP_PR ? COLOR_PATTERNS_COUNT - 1 : 1;
USER_CONFIG.COLOR_PATTERN_INDEX += incre;
USER_CONFIG.COLOR_PATTERN_INDEX %= COLOR_PATTERNS_COUNT;
set_wave_color(USER_CONFIG.COLOR_PATTERN_INDEX);
}
return false;
default:
if(record->event.pressed){
register_keystroke(keycode);
#ifdef CONSOLE_ENABLE
led_info_t *entry = get_led_info_by_scancode(keycode);
uprintf(("KL: kc: %u, led id: %u, x: %f, y: %f, "
"col: %u, row: %u, pressed: %u, time: %u\n"),
keycode, entry->id, entry->x, entry->y,
record->event.key.col, record->event.key.row,
record->event.pressed, record->event.time);
#endif
}
return true; //Process all other keycodes normally
}
}
led_instruction_t led_instructions[] = {
//LEDs are normally inactive, no processing is performed on them
//Flags are used in matching criteria for an LED to be active and indicate how to color it
//Flags can be found in tmk_core/protocol/arm_atsam/md_rgb_matrix.h (prefixed with LED_FLAG_)
//LED IDs can be found in config_led.h in the keyboard's directory
//Examples are below
//All LEDs use the user's selected pattern (this is the factory default)
{ .flags = LED_FLAG_USE_ROTATE_PATTERN },
//Specific LEDs use the user's selected pattern while all others are off
// { .flags = LED_FLAG_MATCH_ID | LED_FLAG_USE_ROTATE_PATTERN, .id0 = 0xFFFFFFFF, .id1 = 0xAAAAAAAA, .id2 = 0x55555555, .id3 = 0x11111111 },
//Specific LEDs use specified RGB values while all others are off
// { .flags = LED_FLAG_MATCH_ID | LED_FLAG_USE_RGB, .id0 = 0xFF, .id1 = 0x00FF, .id2 = 0x0000FF00, .id3 = 0xFF000000, .r = 75, .g = 150, .b = 225 },
//All LEDs use the user's selected pattern
//On layer 1, all key LEDs (except the top row which keeps active pattern) are red while all edge LEDs are green
//When layer 1 is active, key LEDs use red (id0 32 - 17: 1111 1111 1111 1111 0000 0000 0000 0000 = 0xFFFF0000) (except top row 16 - 1)
//When layer 1 is active, key LEDs use red (id1 64 - 33: 1111 1111 1111 1111 1111 1111 1111 1111 = 0xFFFFFFFF)
//When layer 1 is active, key LEDs use red (id2 87 - 65: 0000 0000 0111 1111 1111 1111 1111 1111 = 0x007FFFFF)
//When layer 1 is active, edge LEDs use green (id2 95 - 88: 1111 1111 1000 0000 0000 0000 0000 0000 = 0xFF800000)
//When layer 1 is active, edge LEDs use green (id3 119 - 96: 0000 0000 1111 1111 1111 1111 1111 1111 = 0x00FFFFFF)
// { .flags = LED_FLAG_USE_ROTATE_PATTERN },
#define WAVE_LED_INSTRUCTION_START 1
{ .flags = LED_FLAG_MATCH_ID | LED_FLAG_USE_RGB, .id0 = 0, .id1 = 0, .id2 = 0, .g = 255 },
{ .flags = LED_FLAG_MATCH_ID | LED_FLAG_USE_RGB, .id0 = 0, .id1 = 0, .id2 = 0, .g = 255 },
{ .flags = LED_FLAG_MATCH_ID | LED_FLAG_USE_RGB, .id0 = 0, .id1 = 0, .id2 = 0, .g = 255 },
{ .flags = LED_FLAG_MATCH_ID | LED_FLAG_USE_RGB, .id0 = 0, .id1 = 0, .id2 = 0, .g = 255 },
{ .flags = LED_FLAG_MATCH_ID | LED_FLAG_USE_RGB, .id0 = 0, .id1 = 0, .id2 = 0, .g = 255 },
{ .flags = LED_FLAG_MATCH_ID | LED_FLAG_USE_RGB, .id0 = 0, .id1 = 0, .id2 = 0, .g = 255 },
{ .flags = LED_FLAG_MATCH_ID | LED_FLAG_USE_RGB, .id0 = 0, .id1 = 0, .id2 = 0, .g = 255 },
{ .flags = LED_FLAG_MATCH_ID | LED_FLAG_USE_RGB, .id0 = 0, .id1 = 0, .id2 = 0, .g = 255 },
{ .flags = LED_FLAG_MATCH_ID | LED_FLAG_USE_RGB, .id0 = 0, .id1 = 0, .id2 = 0, .g = 255 },
{ .flags = LED_FLAG_MATCH_ID | LED_FLAG_USE_RGB, .id0 = 0, .id1 = 0, .id2 = 0, .g = 255 },
{ .flags = LED_FLAG_MATCH_ID | LED_FLAG_USE_RGB, .id0 = 0, .id1 = 0, .id2 = 0, .g = 255 },
{ .flags = LED_FLAG_MATCH_ID | LED_FLAG_USE_RGB, .id0 = 0, .id1 = 0, .id2 = 0, .g = 255 },
{ .flags = LED_FLAG_MATCH_ID | LED_FLAG_USE_RGB, .id0 = 0, .id1 = 0, .id2 = 0, .g = 255 },
{ .flags = LED_FLAG_MATCH_ID | LED_FLAG_USE_RGB, .id0 = 0, .id1 = 0, .id2 = 0, .g = 255 },
{ .flags = LED_FLAG_MATCH_ID | LED_FLAG_USE_RGB, .id0 = 0, .id1 = 0, .id2 = 0, .g = 255 },
{ .flags = LED_FLAG_MATCH_ID | LED_FLAG_USE_RGB, .id0 = 0, .id1 = 0, .id2 = 0, .g = 255 },
{ .flags = LED_FLAG_MATCH_ID | LED_FLAG_USE_RGB, .id0 = 0, .id1 = 0, .id2 = 0, .g = 255 },
{ .flags = LED_FLAG_MATCH_ID | LED_FLAG_USE_RGB, .id0 = 0, .id1 = 0, .id2 = 0, .g = 255 },
#define WAVE_LED_INSTRUCTION_END 18
//All key LEDs use red while edge LEDs use the active pattern
//All key LEDs use red (id0 32 - 1: 1111 1111 1111 1111 1111 1111 1111 1111 = 0xFFFFFFFF)
//All key LEDs use red (id1 64 - 33: 1111 1111 1111 1111 1111 1111 1111 1111 = 0xFFFFFFFF)
//All key LEDs use red (id2 87 - 65: 0000 0000 0111 1111 1111 1111 1111 1111 = 0x007FFFFF)
//Edge uses active pattern (id2 95 - 88: 1111 1111 1000 0000 0000 0000 0000 0000 = 0xFF800000)
//Edge uses active pattern (id3 119 - 96: 0000 0000 1111 1111 1111 1111 1111 1111 = 0x00FFFFFF)
// { .flags = LED_FLAG_MATCH_ID | LED_FLAG_USE_RGB, .id0 = 0xFFFFFFFF, .id1 = 0xFFFFFFFF, .id2 = 0x007FFFFF, .r = 255 },
// { .flags = LED_FLAG_MATCH_ID | LED_FLAG_USE_ROTATE_PATTERN , .id2 = 0xFF800000, .id3 = 0x00FFFFFF },
{ .flags = LED_FLAG_MATCH_ID | LED_FLAG_USE_RGB | LED_FLAG_MATCH_LAYER,
.id1 = 0b00001111001111000000011110011110,
.r = 0, .g = 255, .b = 60, .layer = 2 },
//end must be set to 1 to indicate end of instruction set
{ .end = 1 }
};
void set_wave_color(int color_pattern_index){
for(int i = WAVE_LED_INSTRUCTION_START; i < WAVE_LED_INSTRUCTION_END; ++i){
for(int j = 0; j < COLOR_PATTERN_RGB_COUNT; ++j){
led_instructions[i].r = COLOR_PATTERNS[color_pattern_index][i][0];
led_instructions[i].g = COLOR_PATTERNS[color_pattern_index][i][1];
led_instructions[i].b = COLOR_PATTERNS[color_pattern_index][i][2];
}
}
};
void wave_effect(void){
for(int i = WAVE_LED_INSTRUCTION_START; i < WAVE_LED_INSTRUCTION_END; ++i){
reset_led_for_instruction(i);
}
int wave_led_instruction_span = WAVE_LED_INSTRUCTION_END - WAVE_LED_INSTRUCTION_START;
keystroke_t *keystroke = ACTIVE_KEYSTROKES;
for(int i = 0; i < MAX_ACTIVE_KEYSTORKES; ++i, ++keystroke){
if(!keystroke->active) continue;
bool active = false;
uint16_t keystroke_led_id = get_led_info_by_scancode(keystroke->scancode)->id;
float elapsed_s = timer_elapsed32(keystroke->timer) / 1000.0f;
float travel = elapsed_s * USER_CONFIG.WAVE_SPEED;
for(uint16_t id = 1; id <= MAX_LED_ID; ++id){
float normalized_distance =
led_info[id].distance_to[keystroke_led_id] /
(float)DISTANCE_NORAMLIZING_PARAMETER;
if(travel >= normalized_distance && travel - normalized_distance >= 0 &&
normalized_distance >= travel - USER_CONFIG.WAVE_WIDTH){
int portion = (travel - normalized_distance) *
wave_led_instruction_span / USER_CONFIG.WAVE_WIDTH;
add_led_to_instruction(portion, id);
active = true;
}
}
keystroke->active = active;
}
};