// Copyright 2023 QMK // SPDX-License-Identifier: GPL-2.0-or-later #include QMK_KEYBOARD_H // Enable debug console printing // https://docusaurus.qmk.fm/faq_debug #include "print.h" enum layer_names { _COLEMAK = 0, _QWERTY, _FN, }; enum custom_keycodes { COLEMAK = SAFE_RANGE, QWERTY, }; // Each layer gets a name for readability, which is then used in the keymap matrix below. // The underscores don't mean anything - you can have a layer called STUFF or any other name. // Layer names don't all need to be of the same length, obviously, and you can also skip them // entirely and just use numbers. // Keycodes: https://docs.qmk.fm/#/keycodes const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { /* ┌───┬───┬───┬───┬───┬───┐ ┌───┬───┬───┬───┬───┬───┬───┬───┐ │ESC│F1 │F2 │F3 │F4 │F5 │ │F6 │F7 │F8 │F9 │F10│F11│F12│DEL│ ├───┼───┼───┼───┼───┼───┤ ├───┼───┼───┼───┼───┼───┼───┼───┤ │ ` │ 1 │ 2 │ 3 │ 4 │ 5 │ │ 6 │ 7 │ 8 │ 9 │ 0 │ - │ = │BCK│ ├───┼───┼───┼───┼───┼───┤ ├───┼───┼───┼───┼───┼───┼───┼───┤ │TAB│ Q │ W │ F │ P │ G │ │ J │ L │ U │ Y │ ; │ [ │ ] │ \ │ ├───┼───┼───┼───┼───┼───┤ ├───┼───┼───┼───┼───┼───┼───┴───┤ │COM│ A │ R │ S │ T │ D │ │ H │ N │ E │ I │ O │ ' │RETURN │ ├───┼───┼───┼───┼───┼───┤ ├───┼───┼───┼───┼───┼───┼───┬───┤ │SHI│ Z │ X │ C │ V │ B │ │ K │ M │ , │ . │ / │PGU│ ↑ │PGD│ ├───┼───┼───┼───┼───┴───┤ ┌───┼───┼───┼───┼───┼───┼───┼───┼───┤ │CTL│SUP│ALT│FN │ SPACE │ │M1 │M3 │M2 │MEN│HOM│END│ ← │ ↓ │ → │ └───┴───┴───┴───┴───────┘ └───┴───┴───┴───┴───┴───┴───┴───┴───┘ */ [_COLEMAK] = 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_DEL, //|--------+--------+--------+--------+--------+--------| |--------+--------+--------+--------+--------+--------+--------+--------| 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_TAB, KC_Q, KC_W, KC_F, KC_P, KC_G, KC_J, KC_L, KC_U, KC_Y, KC_SCLN, KC_LBRC, KC_RBRC, KC_BSLS, //|--------+--------+--------+--------+--------+--------| |--------+--------+--------+--------+--------+--------+--------+--------| KC_CAPS, KC_A, KC_R, KC_S, KC_T, KC_D, KC_H, KC_N, KC_E, KC_I, KC_O, KC_QUOT, KC_ENT, //|--------+--------+--------+--------+--------+--------| |--------+--------+--------+--------+--------+--------+--------+--------| KC_LSFT, KC_Z, KC_X, KC_C, KC_V, KC_B, KC_K, KC_M, KC_COMM, KC_DOT, KC_SLSH, KC_PGUP, KC_UP, KC_PGDN, //|--------+--------+--------+--------+--------+--------| |--------+--------+--------+--------+--------+--------+--------+--------+--------| KC_LCTL, KC_LGUI, KC_LALT, MO(_FN), KC_SPACE, KC_BTN1, KC_BTN3, KC_BTN2, KC_APP, KC_HOME, KC_END, KC_LEFT, KC_DOWN, KC_RGHT //|--------+--------+--------+--------+--------+--------| |--------+--------+--------+--------+--------+--------+--------+--------+--------| ), /* ┌───┬───┬───┬───┬───┬───┐ ┌───┬───┬───┬───┬───┬───┬───┬───┐ │ESC│F1 │F2 │F3 │F4 │F5 │ │F6 │F7 │F8 │F9 │F10│F11│F12│DEL│ ├───┼───┼───┼───┼───┼───┤ ├───┼───┼───┼───┼───┼───┼───┼───┤ │ ` │ 1 │ 2 │ 3 │ 4 │ 5 │ │ 6 │ 7 │ 8 │ 9 │ 0 │ - │ = │BCK│ ├───┼───┼───┼───┼───┼───┤ ├───┼───┼───┼───┼───┼───┼───┼───┤ │TAB│ Q │ W │ E │ R │ T │ │ Y │ U │ I │ O │ P │ [ │ ] │ \ │ ├───┼───┼───┼───┼───┼───┤ ├───┼───┼───┼───┼───┼───┼───┴───┤ │COM│ A │ S │ D │ F │ G │ │ H │ J │ K │ L │ ; │ ' │RETURN │ ├───┼───┼───┼───┼───┼───┤ ├───┼───┼───┼───┼───┼───┼───┬───┤ │SHI│ Z │ X │ C │ V │ B │ │ N │ M │ , │ . │ / │PGU│ ↑ │PGD│ ├───┼───┼───┼───┼───┴───┤ ┌───┼───┼───┼───┼───┼───┼───┼───┼───┤ │CTL│SUP│ALT│FN │ SPACE │ │M1 │M3 │M2 │MEN│HOM│END│ ← │ ↓ │ → │ └───┴───┴───┴───┴───────┘ └───┴───┴───┴───┴───┴───┴───┴───┴───┘ */ [_QWERTY] = 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_DEL, //|--------+--------+--------+--------+--------+--------| |--------+--------+--------+--------+--------+--------+--------+--------| 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_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_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_PGUP, KC_UP, KC_PGDN, //|--------+--------+--------+--------+--------+--------| |--------+--------+--------+--------+--------+--------+--------+--------+--------| KC_LCTL, KC_LGUI, KC_LALT, MO(_FN), KC_SPACE, KC_BTN1, KC_BTN3, KC_BTN2, KC_APP, KC_HOME, KC_END, KC_LEFT, KC_DOWN, KC_RGHT //|--------+--------+--------+--------+--------+--------| |--------+--------+--------+--------+--------+--------+--------+--------+--------| ), [_FN] = LAYOUT( //|--------+---------+--------+--------+--------+--------+ |--------+--------+--------+--------+--------+--------+--------+--------| _______, KC_MUTE, KC_VOLD, KC_VOLU, KC_BRID, KC_BRIU, KC_MUTE, KC_MPRV, KC_MPLY, KC_MNXT, _______, _______, _______, _______, //|--------+---------+--------+--------+--------+--------+ |--------+--------+--------+--------+--------+--------+--------+--------| _______, _______, _______, _______, _______, _______, _______, KC_P7, KC_P8, KC_P9, KC_PPLS, _______, _______, KC_DEL, //|--------+---------+--------+--------+--------+--------| |--------+--------+--------+--------+--------+--------+--------+--------| _______,TO(_QWERTY),KC_WAKE,_______, DM_PLY1, _______, _______, KC_P4, KC_P5, KC_P6, KC_PAST, _______, _______, _______, //|--------+---------+--------+--------+--------+--------| |--------+--------+--------+--------+--------+--------+-----------------| _______, _______, DM_REC1, KC_SLEP,_______, _______, _______, KC_P1, KC_P2, KC_P3, KC_PMNS, _______, _______, //|--------+---------+--------+--------+--------+--------| |--------+--------+--------+--------+--------+--------+-----------------| _______, _______,_______,TO(_COLEMAK),_______,PB_1, _______, KC_P0, KC_COMM, KC_PDOT, KC_PSLS, _______, _______, _______, //|--------+---------+--------+--------+-----------------| |--------+--------+--------+--------+--------+--------+--------+--------+--------| _______, _______, _______, _______, _______, _______, _______, _______, KC_INS, KC_PSCR, _______, _______, _______, _______ //|--------+---------+--------+--------+-----------------| |--------+--------+--------+--------+--------+--------+--------+--------+--------| ) }; // Micro controller indicator brightness const int indicator_brightness = 7; // Custom composite data type for holding colors typedef struct { int red; int green; int blue; } color_type; // Used for middle mouse button logic bool scrolled = false; typedef struct { color_type color; int cpi; } cpi_type; bool trackball_volume_mode = false; // Trackball cpi. First one is the default This is also the default color cpi_type cpis[] = { { .color = { .red = 0, .green = 255, .blue = 0 }, .cpi = 40000 }, { .color = { .red = 255, .green = 0, .blue = 0 }, .cpi = 20000 } }; int cpi_index = 0; bool cpi_changed = false; void set_trackball_normal_color(void) { // Sets color based on current cpi pimoroni_trackball_set_rgbw( cpis[cpi_index].color.red, cpis[cpi_index].color.green, cpis[cpi_index].color.blue, 0 ); } void keyboard_post_init_user(void) { // Call the post init code. pointing_device_set_cpi(cpis[cpi_index].cpi); debug_enable=true; // LED's called suspend_wakeup_init_user to handle suspention } bool set_scrolling = false; report_mouse_t pointing_device_task_user(report_mouse_t mouse_report) { if (!mouse_report.buttons) { cpi_changed = false; } else { // Only fires on pointing device click, not keyboard mouse buttons // Don't send a mouse button event mouse_report.buttons = 0; if(!cpi_changed){ cpi_changed = true; // Cycle CPI cpi_index++; if (cpi_index == sizeof(cpis) / sizeof(cpis[0])) { cpi_index = 0; } // Set CPI pointing_device_set_cpi(cpis[cpi_index].cpi); // Sets color based on current selected cpi set_trackball_normal_color(); dprintf("CPI: %d\n", cpis[cpi_index].cpi); } } if (set_scrolling) { if (mouse_report.x || mouse_report.y) { // Used for middle mouse button scroll logic scrolled = true; // dprintf("X: %d\nY: %d\n", mouse_report.x, mouse_report.y); } // Convert cursor movement to scroll movement mouse_report.h = mouse_report.x; mouse_report.v = -mouse_report.y; // Prevent cursor movement mouse_report.x = 0; mouse_report.y = 0; } else if(trackball_volume_mode){ if (mouse_report.y) { if (mouse_report.y < 0) { SEND_STRING(SS_TAP(X_VOLU)); } else if (mouse_report.y > 0){ SEND_STRING(SS_TAP(X_VOLD)); } } // Prevent cursor movement mouse_report.x = 0; mouse_report.y = 0; } return mouse_report; } bool process_record_user(uint16_t keycode, keyrecord_t *record) { //dprintf("keycode: %d\n", keycode); switch (keycode) { case KC_BTN3: // Middle mouse button if (record->event.pressed) { // Start scrolling mode set_scrolling = true; pointing_device_set_cpi(8000); pimoroni_trackball_set_rgbw(0, 0, 255, 0); // Don't send pressed to computer, as there's some logic // to check if scrolled. This logic is handled later return false; } else { // Stop scrolling mode set_scrolling = false; // Reset CPI pointing_device_set_cpi(cpis[cpi_index].cpi); set_trackball_normal_color(); // Middle mouse button wasn't sent earlier, // send if not scrolled on mouse button up. // Similar to how ThinkPads handles it if (!scrolled) { SEND_STRING(SS_TAP(X_MS_BTN3)); } else { scrolled = false; } } break; case PB_1: // Programmable button 1 if (record->event.pressed) { SEND_STRING("https://node5.net"); } break; case MO(_FN): // Programmable button 1 if (record->event.pressed) { pimoroni_trackball_set_rgbw(255, 0, 255, 0); trackball_volume_mode = true; } else { set_trackball_normal_color(); trackball_volume_mode = false; } break; } return true; } void suspend_power_down_user(void) { // code will run multiple times while keyboard is suspended // Turn off light when computer is suspended pimoroni_trackball_set_rgbw(0, 0, 0, 0); setrgb(0, 0, 0, (LED_TYPE *)&led[0]); // led 0 rgblight_set(); // Utility functions do not call rgblight_set() automatically, so they need to be called explicitly. } void suspend_wakeup_init_user(void) { // code will run on keyboard wakeup from suspention and initial plugin // Turn on light when computer is woken from sleep set_trackball_normal_color(); setrgb(0, indicator_brightness, 0, (LED_TYPE *)&led[0]); rgblight_set(); } /* uint8_t pointing_device_handle_buttons(uint8_t buttons, bool pressed, pointing_device_buttons_t button) { if (pressed) { buttons |= 1 << (button); if (buttons) { dprintf("buttons: %d\npressed: %d\nbutton: %d\n", buttons, pressed, button); } } else { buttons &= ~(1 << (button)); } return buttons; } */ layer_state_t layer_state_set_user(layer_state_t state) { switch (get_highest_layer(state)) { case _QWERTY: setrgb(indicator_brightness, 0, 0, (LED_TYPE *)&led[0]); break; case _COLEMAK: setrgb(0, indicator_brightness, 0, (LED_TYPE *)&led[0]); break; case _FN: setrgb(0, 0, indicator_brightness, (LED_TYPE *)&led[0]); break; default: // for any other layers, or the default layer setrgb(indicator_brightness, indicator_brightness, indicator_brightness, (LED_TYPE *)&led[0]); break; } rgblight_set(); return state; }