Adding Volt 80 Custom PCB Support (#26158)

* Adding Volt 80 Custom PCB Support

* update license

* lint fix

* requested changes

* requested changes 2

* requested changes 3 because I'm incompetent

* requested changes

* drashna recommends

* Update keyboards/percent_studio_aftermarket/keyboard.json

Co-authored-by: Drashna Jaelre <drashna@live.com>

* Update keyboards/percent_studio_aftermarket/keymaps/default/keymap.c

Co-authored-by: Joel Challis <git@zvecr.com>

* Update keyboards/percent_studio_aftermarket/keyboard.json

Co-authored-by: Joel Challis <git@zvecr.com>

* Update keyboards/percent_studio_aftermarket/percent_studio_aftermarket.c

Co-authored-by: Joel Challis <git@zvecr.com>

* Update keyboards/percent_studio_aftermarket/percent_studio_aftermarket.c

Co-authored-by: Joel Challis <git@zvecr.com>

* Fix JSON formatting by removing extra lines

---------

Co-authored-by: Drashna Jaelre <drashna@live.com>
Co-authored-by: Joel Challis <git@zvecr.com>
This commit is contained in:
Jubakuba
2026-05-26 14:21:19 -06:00
committed by GitHub
parent 3a8ea37a13
commit 3c338996f0
4 changed files with 332 additions and 0 deletions
@@ -0,0 +1,126 @@
{
"manufacturer": "Mike Tihonovich",
"keyboard_name": "percent_studio_aftermarket",
"maintainer": "Jubakuba",
"bootloader": "rp2040",
"diode_direction": "COL2ROW",
"features": {
"bootmagic": true,
"extrakey": true,
"mousekey": true,
"nkro": true,
"rgblight": true
},
"matrix_pins": {
"cols": ["GP0", "GP1", "GP2", "GP3", "GP4", "GP5", "GP6", "GP7", "GP8", "GP9"],
"rows": ["GP10", "GP11", "GP12", "GP13", "GP14", "GP15", "GP26", "GP27", "GP28"]
},
"processor": "RP2040",
"usb": {
"device_version": "1.0.0",
"pid": "0x0004",
"vid": "0x4A4B"
},
"layouts": {
"LAYOUT": {
"layout": [
{"matrix": [0, 0], "x": 1, "y": 0, "label": "Esc"},
{"matrix": [0, 1], "x": 2, "y": 0, "label": "F1"},
{"matrix": [0, 2], "x": 3, "y": 0, "label": "F2"},
{"matrix": [0, 3], "x": 4, "y": 0, "label": "F3"},
{"matrix": [0, 4], "x": 5, "y": 0, "label": "F4"},
{"matrix": [0, 5], "x": 6, "y": 0, "label": "F5"},
{"matrix": [0, 6], "x": 7, "y": 0, "label": "F6"},
{"matrix": [0, 7], "x": 8, "y": 0, "label": "F7"},
{"matrix": [0, 8], "x": 9, "y": 0, "label": "F8"},
{"matrix": [0, 9], "x": 10, "y": 0, "label": "F9"},
{"matrix": [6, 2], "x": 11, "y": 0, "label": "F10"},
{"matrix": [6, 3], "x": 12, "y": 0, "label": "F11"},
{"matrix": [6, 4], "x": 13, "y": 0, "label": "F12"},
{"matrix": [6, 5], "x": 14, "y": 0, "label": "F13"},
{"matrix": [6, 6], "x": 15, "y": 0, "label": "F14"},
{"matrix": [6, 7], "x": 16.5, "y": 0, "label": "Print Screen"},
{"matrix": [6, 8], "x": 17.5, "y": 0, "label": "Scroll Lock"},
{"matrix": [6, 9], "x": 18.5, "y": 0, "label": "Pause"},
{"matrix": [1, 0], "x": 1, "y": 2, "label": "Tilde"},
{"matrix": [1, 1], "x": 2, "y": 2, "label": "1"},
{"matrix": [1, 2], "x": 3, "y": 2, "w": 1.5, "label": "2"},
{"matrix": [1, 3], "x": 4, "y": 2, "label": "3"},
{"matrix": [1, 4], "x": 5, "y": 2, "label": "4"},
{"matrix": [1, 5], "x": 6, "y": 2, "label": "5"},
{"matrix": [1, 6], "x": 7, "y": 2, "label": "6"},
{"matrix": [1, 7], "x": 8, "y": 2, "label": "7"},
{"matrix": [1, 8], "x": 9, "y": 2, "label": "8"},
{"matrix": [1, 9], "x": 10, "y": 2, "label": "9"},
{"matrix": [6, 0], "x": 11, "y": 2, "label": "0"},
{"matrix": [6, 1], "x": 12, "y": 2, "label": "Minus"},
{"matrix": [7, 0], "x": 13, "y": 2, "label": "Equals"},
{"matrix": [7, 1], "x": 14, "y": 2, "w": 2, "label": "Backspace"},
{"matrix": [7, 2], "x": 16.5, "y": 2, "label": "Insert"},
{"matrix": [7, 3], "x": 17.5, "y": 2, "label": "Home"},
{"matrix": [7, 4], "x": 18.5, "y": 2, "label": "Page Up"},
{"matrix": [2, 0], "x": 0, "y": 3, "w": 1.5, "label": "Tab"},
{"matrix": [2, 1], "x": 2.5, "y": 3, "label": "Q"},
{"matrix": [2, 2], "x": 3.5, "y": 3, "label": "W"},
{"matrix": [2, 3], "x": 4.5, "y": 3, "label": "E"},
{"matrix": [2, 4], "x": 5.5, "y": 3, "label": "R"},
{"matrix": [2, 5], "x": 6.5, "y": 3, "label": "T"},
{"matrix": [2, 6], "x": 7.5, "y": 3, "label": "Y"},
{"matrix": [2, 7], "x": 8.5, "y": 3, "label": "U"},
{"matrix": [2, 8], "x": 9.5, "y": 3, "label": "I"},
{"matrix": [2, 9], "x": 10.5, "y": 3, "label": "O"},
{"matrix": [7, 5], "x": 11.5, "y": 3, "label": "P"},
{"matrix": [7, 6], "x": 12.5, "y": 3, "label": "["},
{"matrix": [7, 7], "x": 13.5, "y": 3, "label": "]"},
{"matrix": [7, 8], "x": 14.5, "y": 3, "w": 1.5, "label": "\\"},
{"matrix": [7, 9], "x": 16.5, "y": 3, "label": "Delete"},
{"matrix": [8, 0], "x": 17.5, "y": 3, "label": "End"},
{"matrix": [8, 1], "x": 18.5, "y": 3, "label": "Page Down"},
{"matrix": [3, 0], "x": 1, "y": 4, "w": 1.75, "label": "Caps Lock"},
{"matrix": [3, 1], "x": 2.75, "y": 4, "label": "A"},
{"matrix": [3, 2], "x": 3.75, "y": 4, "label": "S"},
{"matrix": [3, 3], "x": 4.75, "y": 4, "label": "D"},
{"matrix": [3, 4], "x": 5.75, "y": 4, "label": "F"},
{"matrix": [3, 5], "x": 6.75, "y": 4, "label": "G"},
{"matrix": [3, 6], "x": 7.75, "y": 4, "label": "H"},
{"matrix": [3, 7], "x": 8.75, "y": 4, "label": "J"},
{"matrix": [3, 8], "x": 9.75, "y": 4, "label": "K"},
{"matrix": [3, 9], "x": 10.75, "y": 4, "label": "L"},
{"matrix": [8, 2], "x": 11.75, "y": 4, "label": ";"},
{"matrix": [8, 3], "x": 12.75, "y": 4, "label": "'"},
{"matrix": [8, 4], "x": 13.75, "y": 4, "w": 2.25, "label": "Enter"},
{"matrix": [4, 0], "x": 1, "y": 5, "w": 2.25, "label": "Shift"},
{"matrix": [4, 1], "x": 3.25, "y": 5, "label": "Z"},
{"matrix": [4, 2], "x": 4.25, "y": 5, "label": "X"},
{"matrix": [4, 3], "x": 5.25, "y": 5, "label": "C"},
{"matrix": [4, 4], "x": 6.25, "y": 5, "label": "V"},
{"matrix": [4, 5], "x": 7.25, "y": 5, "label": "B"},
{"matrix": [4, 6], "x": 8.25, "y": 5, "label": "N"},
{"matrix": [4, 7], "x": 9.25, "y": 5, "label": "M"},
{"matrix": [4, 8], "x": 10.25, "y": 5, "label": ","},
{"matrix": [4, 9], "x": 11.25, "y": 5, "label": "."},
{"matrix": [8, 5], "x": 12.25, "y": 5, "label": "/"},
{"matrix": [8, 6], "x": 13.25, "y": 5, "w": 2.75, "label": "Right Shift"},
{"matrix": [8, 7], "x": 17.5, "y": 5, "label": "Up"},
{"matrix": [5, 0], "x": 1, "y": 6, "w": 1.5, "label": "Ctrl"},
{"matrix": [5, 1], "x": 2.5, "y": 6, "label": "Win"},
{"matrix": [5, 2], "x": 3.5, "y": 6, "w": 1.5, "label": "Alt"},
{"matrix": [5, 3], "x": 5, "y": 6, "w": 7, "label": "Space"},
{"matrix": [5, 4], "x": 12, "y": 6, "w": 1.5, "label": "Right Alt"},
{"matrix": [5, 5], "x": 13.5, "y": 6, "label": "Right Win"},
{"matrix": [5, 6], "x": 14.5, "y": 6, "w": 1.5, "label": "Right Ctrl"},
{"matrix": [5, 7], "x": 16.5, "y": 6, "label": "Left"},
{"matrix": [5, 8], "x": 17.5, "y": 6, "label": "Down"},
{"matrix": [5, 9], "x": 18.5, "y": 6, "label": "Right"}
]
}
},
"rgblight": {
"led_count": 4,
"max_brightness": 120
},
"ws2812": {
"driver": "vendor",
"pin": "GP29"
}
}
@@ -0,0 +1,47 @@
// Copyright 2023 QMK
// SPDX-License-Identifier: GPL-2.0-or-later
#include QMK_KEYBOARD_H
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
/*
* ┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐ ┌───┬───┬───┐
* │Esc│F1 │F2 │F3 │F4 │F5 │F6 │F7 │F8 │F9 │F10│F11│F12│F13│F14│ │PSc│Scr│Pse│
* ├───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┼───┴───┤ ├───┼───┼───┤
* │ ` │ 1 │ 2 │ 3 │ 4 │ 5 │ 6 │ 7 │ 8 │ 9 │ 0 │ - │ = │ Backsp│ │Ins│Hom│PgU│
* ├───┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─────┤ ├───┼───┼───┤
* │ Tab │ Q │ W │ E │ R │ T │ Y │ U │ I │ O │ P │ [ │ ] │ \ │ │Del│End│PgD│
* ├─────┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴┬──┴─────┤ └───┴───┴───┘
* │ Caps │ A │ S │ D │ F │ G │ H │ J │ K │ L │ ; │ ' │ Enter │
* ├──────┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴─┬─┴────────┤ ┌───┐
* │ Shift │ Z │ X │ C │ V │ B │ N │ M │ , │ . │ / │ Shift │ │ ↑ │
* ├────┬───┼───┴─┬─┴───┴───┴───┴───┴───┴───┴┬──┴───┼───┬──────┤ ┌───┼───┼───┐
* │Ctrl│GUI│ Alt │ │Alt │GUI│ Ctrl │ │ ← │ ↓ │ → │
* └────┴───┴─────┴──────────────────────────┴──────┴───┴──────┘ └───┴───┴───┘
*/
[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, MO(2), MO(1), KC_PSCR, KC_SCRL, 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, KC_RGUI, KC_RCTL, KC_LEFT, KC_DOWN, KC_RGHT
),
[1] = LAYOUT(
QK_BOOT, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______
),
[2] = LAYOUT(
QK_BOOT, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______, _______,
_______, _______, _______, _______, _______, _______, _______, _______, _______, _______
)
};
@@ -0,0 +1,132 @@
/*
Copyright 2026 Jubakuba (Jubakuba@gmail.com)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "quantum.h"
typedef enum {
COLOR_NONE,
COLOR_BACKSPACE,
COLOR_ALPHA,
COLOR_NUM,
COLOR_SYMBOL,
COLOR_SPACE,
COLOR_QUANTUM,
COLOR_OTHER,
} key_type_t;
key_type_t led_history[4] = {COLOR_NONE, COLOR_NONE, COLOR_NONE, COLOR_NONE};
key_type_t get_key_category(uint16_t keycode) {
bool shifted = (get_mods() & (MOD_BIT(KC_LSFT) | MOD_BIT(KC_RSFT)));
switch (keycode) {
case QK_BASIC ... QK_BASIC_MAX:
switch (QK_MODS_GET_BASIC_KEYCODE(keycode)) {
case KC_BSPC:
return COLOR_BACKSPACE;
case KC_A ... KC_Z:
return COLOR_ALPHA;
case KC_SPACE:
return COLOR_SPACE;
case KC_1 ... KC_0:
if (shifted) {
return COLOR_SYMBOL;
}
return COLOR_NUM;
case KC_MINUS ... KC_SLASH:
return COLOR_SYMBOL;
case KC_NO:
case KC_TRNS:
return COLOR_NONE;
default:
return COLOR_OTHER;
}
case QK_MOMENTARY ... QK_MOMENTARY_MAX:
case QK_TOGGLE_LAYER ... QK_TOGGLE_LAYER_MAX:
case QK_DEF_LAYER ... QK_DEF_LAYER_MAX:
case QK_TO ... QK_TO_MAX:
case QK_ONE_SHOT_LAYER ... QK_ONE_SHOT_LAYER_MAX:
case QK_LAYER_TAP_TOGGLE ... QK_LAYER_TAP_TOGGLE_MAX:
case QK_LAYER_MOD ... QK_LAYER_MOD_MAX:
case QK_LAYER_TAP ... QK_LAYER_TAP_MAX:
case QK_MOD_TAP ... QK_MOD_TAP_MAX:
return COLOR_QUANTUM;
default:
return COLOR_OTHER;
}
}
void update_custom_leds(void) {
bool caps_on = host_keyboard_led_state().caps_lock;
for (uint8_t i = 0; i < 4; i++) {
if (i == 0 && caps_on) {
rgblight_sethsv_at(HSV_RED, i);
continue;
}
switch (led_history[i]) {
case COLOR_BACKSPACE:
rgblight_sethsv_at(HSV_RED, i);
break;
case COLOR_ALPHA:
rgblight_sethsv_at(HSV_BLUE, i);
break;
case COLOR_NUM:
rgblight_sethsv_at(HSV_WHITE, i);
break;
case COLOR_SYMBOL:
rgblight_sethsv_at(HSV_YELLOW, i);
break;
case COLOR_OTHER:
rgblight_sethsv_at(HSV_ORANGE, i);
break;
case COLOR_SPACE:
rgblight_sethsv_at(HSV_GREEN, i);
break;
case COLOR_QUANTUM:
rgblight_sethsv_at(HSV_PURPLE, i);
break;
default:
rgblight_sethsv_at(HSV_BLUE, i);
break;
}
}
}
bool process_record_kb(uint16_t keycode, keyrecord_t *record) {
if (record->event.pressed) {
key_type_t new_color = get_key_category(keycode);
if (new_color != COLOR_NONE) {
led_history[0] = led_history[1];
led_history[1] = led_history[2];
led_history[2] = led_history[3];
led_history[3] = new_color;
update_custom_leds();
}
}
return process_record_user(keycode, record);
}
bool led_update_kb(led_t led_state) {
update_custom_leds();
return led_update_user(led_state);
}
@@ -0,0 +1,27 @@
# percent_studio_aftermarket
![percent_studio_aftermarket](https://i.imgur.com/nQAFCH0.png)
*This code is specifically for the aftermarket QMK PCB maintained by Jubakuba that enables QMK for the Volt80 by Percent Studio. This firmware should NOT be flashed on the stock PCB. The PCB needs to be ordered using a PCB provider using the hardware link below. This PCB will fit in the Volt 80 keyboard and work as expected.*
* Keyboard Maintainer: [Mike Tihonovich](https://github.com/Jubakuba)
* Hardware Supported: [Custom PCB](https://github.com/Jubakuba/Volt-80-Kicad)
* Hardware Availability: https://github.com/Jubakuba/Volt-80-Kicad
Make example for this keyboard (after setting up your build environment):
make percent_studio_aftermarket:default
Flashing example for this keyboard:
make percent_studio_aftermarket:default:flash
See the [build environment setup](https://docs.qmk.fm/#/getting_started_build_tools) and the [make instructions](https://docs.qmk.fm/#/getting_started_make_guide) for more information. Brand new to QMK? Start with our [Complete Newbs Guide](https://docs.qmk.fm/#/newbs).
## Bootloader
Enter the bootloader in 3 ways:
* **Bootmagic reset**: Hold down the key at (0,0) in the matrix (usually the top left key or Escape) and plug in the keyboard
* **Physical reset button**: Briefly press the button on the back of the PCB - some may have pads you must short instead
* **Keycode in layout**: Press the key mapped to `QK_BOOT` if it is available