[Keyboard] Add Winry315 keyboard (#15894)

master
Sergey Vlasov 2022-03-08 06:45:30 +03:00 committed by GitHub
parent 86966fce69
commit 249bc3a5c5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 995 additions and 0 deletions

View File

@ -0,0 +1,138 @@
// Copyright 2022 Sergey Vlasov (@sigprof)
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "config_common.h"
// Key matrix size.
#define MATRIX_ROWS 1
#define MATRIX_COLS 24
// Key pins (including encoder press switches).
// The NO_PIN entries are reserved for encoder rotation mappings.
#define DIRECT_PINS \
{ \
{ F4, C7, D4, D5, D1, F5, C6, D6, D3, D2, F6, B6, D7, B4, B5, B2, D0, E6, NO_PIN, NO_PIN, NO_PIN, NO_PIN, NO_PIN, NO_PIN } \
}
// clang-format off
// Encoder pins.
// Encoder numbering (assuming the default board orientation with encoders on
// the top side):
// 0 - left
// 1 - center (with a longer shaft and a larger knob)
// 2 - right
#define ENCODERS_PAD_A { F1, B0, B3 }
#define ENCODERS_PAD_B { F0, B1, B7 }
#define ENCODER_RESOLUTION 4
// Encoder mappings (used for VIA).
#define ENCODERS 3
#define ENCODERS_CW_KEY { { 22, 0 }, { 18, 0 }, { 20, 0 } }
#define ENCODERS_CCW_KEY { { 23, 0 }, { 19, 0 }, { 21, 0 } }
// clang-format on
// RGB LED parameters.
// This PCB uses a single chain of WS2812-compatible addressable RGB LEDs for
// per-key backlight and underglow.
#define RGB_DI_PIN F7
#define RGBLED_NUM 27
#define RGBLIGHT_LIMIT_VAL 150
// RGB Lighting configuration. This mode is used by the vendor firmware, and
// can be chosen if the full RGB Matrix support is not desired for some reason.
#ifdef RGBLIGHT_ENABLE
# define RGBLIGHT_HUE_STEP 8
# define RGBLIGHT_SAT_STEP 8
# define RGBLIGHT_VAL_STEP 8
# define RGBLIGHT_SLEEP
# define RGBLIGHT_EFFECT_BREATHING
# define RGBLIGHT_EFFECT_RAINBOW_MOOD
# define RGBLIGHT_EFFECT_RAINBOW_SWIRL
# define RGBLIGHT_EFFECT_SNAKE
# define RGBLIGHT_EFFECT_KNIGHT
# define RGBLIGHT_EFFECT_CHRISTMAS
# define RGBLIGHT_EFFECT_STATIC_GRADIENT
# define RGBLIGHT_EFFECT_RGB_TEST
# define RGBLIGHT_EFFECT_ALTERNATING
#endif
// RGB Matrix configuration.
#ifdef RGB_MATRIX_ENABLE
# define DRIVER_LED_TOTAL RGBLED_NUM
# define RGB_MATRIX_MAXIMUM_BRIGHTNESS RGBLIGHT_LIMIT_VAL
# define RGB_MATRIX_CENTER \
{ 35, 35 }
# define RGB_DISABLE_WHEN_USB_SUSPENDED
// This option is required for the TYPING_HEATMAP and DIGITAL_RAIN effects,
// both of which are disabled below, so the common support for those effects is
// disabled too.
# undef RGB_MATRIX_FRAMEBUFFER_EFFECTS
// This option is required for reactive effects; disabling this option will
// implicitly disable all of them.
# define RGB_MATRIX_KEYPRESSES
# define ENABLE_RGB_MATRIX_ALPHAS_MODS
# define ENABLE_RGB_MATRIX_GRADIENT_UP_DOWN
# define ENABLE_RGB_MATRIX_GRADIENT_LEFT_RIGHT
# define ENABLE_RGB_MATRIX_BREATHING
# define ENABLE_RGB_MATRIX_BAND_SAT
# define ENABLE_RGB_MATRIX_BAND_VAL
# define ENABLE_RGB_MATRIX_BAND_PINWHEEL_SAT
# define ENABLE_RGB_MATRIX_BAND_PINWHEEL_VAL
# define ENABLE_RGB_MATRIX_BAND_SPIRAL_SAT
# define ENABLE_RGB_MATRIX_BAND_SPIRAL_VAL
# define ENABLE_RGB_MATRIX_CYCLE_ALL
# define ENABLE_RGB_MATRIX_CYCLE_LEFT_RIGHT
# define ENABLE_RGB_MATRIX_CYCLE_UP_DOWN
# define ENABLE_RGB_MATRIX_RAINBOW_MOVING_CHEVRON
# define ENABLE_RGB_MATRIX_CYCLE_OUT_IN
# define ENABLE_RGB_MATRIX_CYCLE_OUT_IN_DUAL
# define ENABLE_RGB_MATRIX_CYCLE_PINWHEEL
# define ENABLE_RGB_MATRIX_CYCLE_SPIRAL
# define ENABLE_RGB_MATRIX_DUAL_BEACON
# define ENABLE_RGB_MATRIX_RAINBOW_BEACON
# define ENABLE_RGB_MATRIX_RAINBOW_PINWHEELS
# define ENABLE_RGB_MATRIX_RAINDROPS
# define ENABLE_RGB_MATRIX_JELLYBEAN_RAINDROPS
# define ENABLE_RGB_MATRIX_HUE_BREATHING
# define ENABLE_RGB_MATRIX_HUE_PENDULUM
# define ENABLE_RGB_MATRIX_HUE_WAVE
# define ENABLE_RGB_MATRIX_PIXEL_RAIN
// The PIXEL_FRACTAL effect does not work properly when the matrix layout is
// different from the physical layout; it also has problems when underglow
// LEDs are present, or when multiple LEDs are associated with the same key.
# undef ENABLE_RGB_MATRIX_PIXEL_FRACTAL
// Framebuffer effects; can be enabled only if RGB_MATRIX_FRAMEBUFFER_EFFECTS
// is defined. Both of these effects currently don't work properly when the
// key matrix does not match the physical layout, so they are disabled.
# undef ENABLE_RGB_MATRIX_TYPING_HEATMAP
# undef ENABLE_RGB_MATRIX_DIGITAL_RAIN
// Reactive effects; can be enabled only if at least one of
// RGB_MATRIX_KEYPRESSES or RGB_MATRIX_KEYRELEASES is defined.
# define ENABLE_RGB_MATRIX_SOLID_REACTIVE_SIMPLE
# define ENABLE_RGB_MATRIX_SOLID_REACTIVE
# define ENABLE_RGB_MATRIX_SOLID_REACTIVE_WIDE
# define ENABLE_RGB_MATRIX_SOLID_REACTIVE_MULTIWIDE
# define ENABLE_RGB_MATRIX_SOLID_REACTIVE_CROSS
# define ENABLE_RGB_MATRIX_SOLID_REACTIVE_MULTICROSS
# define ENABLE_RGB_MATRIX_SOLID_REACTIVE_NEXUS
# define ENABLE_RGB_MATRIX_SOLID_REACTIVE_MULTINEXUS
# define ENABLE_RGB_MATRIX_SPLASH
# define ENABLE_RGB_MATRIX_MULTISPLASH
# define ENABLE_RGB_MATRIX_SOLID_SPLASH
# define ENABLE_RGB_MATRIX_SOLID_MULTISPLASH
#endif
// Debounce reduces chatter (unintended double-presses) - set 0 if debouncing is not needed.
#define DEBOUNCE 5

View File

@ -0,0 +1,104 @@
{
"manufacturer": "Winry",
"keyboard_name": "Winry315",
"maintainer": "sigprof",
"url": "",
"usb": {
"device_version": "0.0.1",
"pid": "0x0315",
"vid": "0xF1F1"
},
"layout_aliases": {
"LAYOUT_all": "LAYOUT_top"
},
"layouts": {
"LAYOUT_top": {
"layout": [
{ "label": "E0", "x": 0.5, "y": 0.25 },
{ "label": "E1", "x": 1.75, "y": 0, "h": 1.5, "w": 1.5 },
{ "label": "E2", "x": 3.5, "y": 0.25 },
{ "label": "0", "x": 0, "y": 1.75 },
{ "label": "1", "x": 1, "y": 1.75 },
{ "label": "2", "x": 2, "y": 1.75 },
{ "label": "3", "x": 3, "y": 1.75 },
{ "label": "4", "x": 4, "y": 1.75 },
{ "label": "5", "x": 0, "y": 2.75 },
{ "label": "6", "x": 1, "y": 2.75 },
{ "label": "7", "x": 2, "y": 2.75 },
{ "label": "8", "x": 3, "y": 2.75 },
{ "label": "9", "x": 4, "y": 2.75 },
{ "label": "10", "x": 0, "y": 3.75 },
{ "label": "11", "x": 1, "y": 3.75 },
{ "label": "12", "x": 2, "y": 3.75 },
{ "label": "13", "x": 3, "y": 3.75 },
{ "label": "14", "x": 4, "y": 3.75 }
]
},
"LAYOUT_left": {
"layout": [
{ "label": "E2", "x": 0.25, "y": 0.5 },
{ "label": "4", "x": 1.75, "y": 0 },
{ "label": "9", "x": 2.75, "y": 0 },
{ "label": "14", "x": 3.75, "y": 0 },
{ "label": "3", "x": 1.75, "y": 1 },
{ "label": "8", "x": 2.75, "y": 1 },
{ "label": "13", "x": 3.75, "y": 1 },
{ "label": "E1", "x": 0, "y": 1.75, "h": 1.5, "w": 1.5 },
{ "label": "2", "x": 1.75, "y": 2 },
{ "label": "7", "x": 2.75, "y": 2 },
{ "label": "12", "x": 3.75, "y": 2 },
{ "label": "1", "x": 1.75, "y": 3 },
{ "label": "6", "x": 2.75, "y": 3 },
{ "label": "11", "x": 3.75, "y": 3 },
{ "label": "E0", "x": 0.25, "y": 3.5 },
{ "label": "0", "x": 1.75, "y": 4 },
{ "label": "5", "x": 2.75, "y": 4 },
{ "label": "10", "x": 3.75, "y": 4 }
]
},
"LAYOUT_right": {
"layout": [
{ "label": "10", "x": 0, "y": 0 },
{ "label": "5", "x": 1, "y": 0 },
{ "label": "0", "x": 2, "y": 0 },
{ "label": "E0", "x": 3.5, "y": 0.5 },
{ "label": "11", "x": 0, "y": 1 },
{ "label": "6", "x": 1, "y": 1 },
{ "label": "1", "x": 2, "y": 1 },
{ "label": "12", "x": 0, "y": 2 },
{ "label": "7", "x": 1, "y": 2 },
{ "label": "2", "x": 2, "y": 2 },
{ "label": "E1", "x": 3.25, "y": 1.75, "h": 1.5, "w": 1.5 },
{ "label": "13", "x": 0, "y": 3 },
{ "label": "8", "x": 1, "y": 3 },
{ "label": "3", "x": 2, "y": 3 },
{ "label": "14", "x": 0, "y": 4 },
{ "label": "9", "x": 1, "y": 4 },
{ "label": "4", "x": 2, "y": 4 },
{ "label": "E2", "x": 3.5, "y": 3.5 }
]
},
"LAYOUT_bottom": {
"layout": [
{ "label": "14", "x": 0, "y": 0 },
{ "label": "13", "x": 1, "y": 0 },
{ "label": "12", "x": 2, "y": 0 },
{ "label": "11", "x": 3, "y": 0 },
{ "label": "10", "x": 4, "y": 0 },
{ "label": "9", "x": 0, "y": 1 },
{ "label": "8", "x": 1, "y": 1 },
{ "label": "7", "x": 2, "y": 1 },
{ "label": "6", "x": 3, "y": 1 },
{ "label": "5", "x": 4, "y": 1 },
{ "label": "4", "x": 0, "y": 2 },
{ "label": "3", "x": 1, "y": 2 },
{ "label": "2", "x": 2, "y": 2 },
{ "label": "1", "x": 3, "y": 2 },
{ "label": "0", "x": 4, "y": 2 },
{ "label": "E2", "x": 0.5, "y": 3.5 },
{ "label": "E1", "x": 1.75, "y": 3.25, "h": 1.5, "w": 1.5 },
{ "label": "E0", "x": 3.5, "y": 3.5 }
]
}
}
}

View File

@ -0,0 +1,79 @@
// Copyright 2022 Sergey Vlasov (@sigprof)
// SPDX-License-Identifier: GPL-2.0-or-later
#include QMK_KEYBOARD_H
// Defines names for use in layer keycodes and the keymap
enum layer_names {
_BASE,
_RGB,
};
// Shorter defines for some QMK keycodes (to keep the keymap aligned)
#define U_LTESC LT(_RGB, KC_ESC)
// clang-format off
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
// Base
[_BASE] = LAYOUT_top(
KC_HOME, KC_MUTE, KC_MPLY,
KC_1, KC_2, KC_3, KC_4, KC_5,
KC_6, KC_7, KC_8, KC_9, KC_0,
U_LTESC, KC_TAB, KC_SPC, KC_BSPC, KC_ENT
),
// RGB configuration
[_RGB] = LAYOUT_top(
RGB_M_P, RGB_M_B, RGB_M_R,
RGB_MOD, RGB_HUI, RGB_SAI, RGB_VAI, RGB_SPI,
RGB_RMOD,RGB_HUD, RGB_SAD, RGB_VAD, RGB_SPD,
KC_TRNS, RGB_TOG, RGB_M_P, RGB_M_B, RGB_M_R
),
};
// clang-format on
bool encoder_update_user(uint8_t index, bool clockwise) {
uint8_t layer = get_highest_layer(layer_state | default_layer_state);
switch (index) {
case 0:
// Left encoder
if (layer == _RGB) {
if (clockwise) {
rgblight_increase_hue();
} else {
rgblight_decrease_hue();
}
} else {
tap_code(clockwise ? KC_PGDN : KC_PGUP);
}
break;
case 1:
// Center encoder
if (layer == _RGB) {
if (clockwise) {
rgblight_increase_sat();
} else {
rgblight_decrease_sat();
}
} else {
tap_code_delay(clockwise ? KC_VOLU : KC_VOLD, 10);
}
break;
case 2:
// Right encoder
if (layer == _RGB) {
if (clockwise) {
rgblight_increase_val();
} else {
rgblight_decrease_val();
}
} else {
tap_code_delay(clockwise ? KC_MNXT : KC_MPRV, 10);
}
break;
}
return false;
}

View File

@ -0,0 +1 @@
# The default keymap for Winry315

View File

@ -0,0 +1,6 @@
// Copyright 2022 Sergey Vlasov (@sigprof)
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#define WINRY315_DEFAULT_ORIENTATION WINRY315_ORIENTATION_LEFT

View File

@ -0,0 +1,81 @@
// Copyright 2022 Sergey Vlasov (@sigprof)
// SPDX-License-Identifier: GPL-2.0-or-later
#include QMK_KEYBOARD_H
// Defines names for use in layer keycodes and the keymap
enum layer_names {
_BASE,
_RGB,
};
// Shorter defines for some QMK keycodes (to keep the keymap aligned)
#define U_LTESC LT(_RGB, KC_ESC)
// clang-format off
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
/* Base */
[_BASE] = LAYOUT_left(
KC_MPLY, U_LTESC, KC_BSPC, KC_PENT,
KC_P7, KC_P8, KC_P9,
KC_MUTE, KC_P4, KC_P5, KC_P6,
KC_P1, KC_P2, KC_P3,
KC_HOME, KC_P0, KC_P0, KC_PDOT
),
/* RGB configuration */
[_RGB] = LAYOUT_left(
RGB_M_R, KC_TRNS, RGB_SPD, RGB_SPI,
RGB_TOG, RGB_HUD, RGB_HUI,
RGB_M_B, RGB_M_P, RGB_SAD, RGB_SAI,
KC_NO, RGB_VAD, RGB_VAI,
RGB_M_P, KC_NLCK, RGB_RMOD,RGB_MOD
),
};
// clang-format on
bool encoder_update_user(uint8_t index, bool clockwise) {
uint8_t layer = get_highest_layer(layer_state | default_layer_state);
switch (index) {
case 0:
// Bottom encoder (left in the default orientation)
if (layer == _RGB) {
if (clockwise) {
rgblight_increase_val();
} else {
rgblight_decrease_val();
}
} else {
tap_code(clockwise ? KC_PGDN : KC_PGUP);
}
break;
case 1:
// Center encoder
if (layer == _RGB) {
if (clockwise) {
rgblight_increase_sat();
} else {
rgblight_decrease_sat();
}
} else {
tap_code_delay(clockwise ? KC_VOLU : KC_VOLD, 10);
}
break;
case 2:
// Top encoder (right in the default orientation)
if (layer == _RGB) {
if (clockwise) {
rgblight_increase_hue();
} else {
rgblight_decrease_hue();
}
} else {
tap_code_delay(clockwise ? KC_MNXT : KC_MPRV, 10);
}
break;
}
return false;
}

View File

@ -0,0 +1,3 @@
# The “Left Numpad” keymap for Winry315
This is a keymap example for the Winry315 board in the “left” orientation (the board is rotated so that the encoders are on the left side, and the keys are in 5 rows of 3 keys). The `LAYOUT_left` macro is used for this orientation, and `WINRY315_DEFAULT_ORIENTATION` is redefined in `config.h` to change the behavior of RGB Matrix effects.

View File

@ -0,0 +1,15 @@
// Copyright 2022 Sergey Vlasov (@sigprof)
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#define DYNAMIC_KEYMAP_LAYER_COUNT 8
// Enable a limited form of RGB Matrix support in VIA (requires redefining the
// effect list in the VIA JSON, which then becomes not 100% compatible with the
// RGBLIGHT firmwares).
#define VIA_QMK_RGBLIGHT_ENABLE
// Enable the workaround for the speed parameter mismatch between RGBLIGHT and
// RGB Matrix, so that the speed slider in VIA behaves in a more useful way.
#define VIA_CUSTOM_LIGHTING_ENABLE

View File

@ -0,0 +1,85 @@
/* Copyright 2020 Neil Brian Ramirez
* Copyright 2021 drashna jael're (@drashna)
* Copyright 2022 Sergey Vlasov (@sigprof)
*
* 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 3 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 "encoder_actions.h"
#if defined(VIA_ENABLE) && defined(ENCODER_ENABLE)
# ifndef ENCODER_TAP_DURATION_MS
# define ENCODER_TAP_DURATION_MS 10
# endif
# define ENCODER_STATE_CW 0x01
# define ENCODER_STATE_CCW 0x02
# ifdef ENCODERS
static uint8_t encoder_state[ENCODERS] = {0};
static uint16_t encoder_timer[ENCODERS] = {0};
static keypos_t encoder_cw[ENCODERS] = ENCODERS_CW_KEY;
static keypos_t encoder_ccw[ENCODERS] = ENCODERS_CCW_KEY;
static void exec_encoder_action(uint8_t index, bool clockwise, bool pressed) {
// clang-format off
keyevent_t encoder_event = (keyevent_t) {
.key = clockwise ? encoder_cw[index] : encoder_ccw[index],
.pressed = pressed,
.time = (timer_read() | 1)
};
// clang-format on
action_exec(encoder_event);
}
# endif
void encoder_action_unregister(void) {
# ifdef ENCODERS
for (int index = 0; index < ENCODERS; ++index) {
if (encoder_state[index] && (timer_elapsed(encoder_timer[index]) >= ENCODER_TAP_DURATION_MS)) {
bool clockwise = !!(encoder_state[index] & ENCODER_STATE_CW);
encoder_state[index] = 0;
exec_encoder_action(index, clockwise, false);
}
}
# endif
}
void encoder_action_register(uint8_t index, bool clockwise) {
# ifdef ENCODERS
if (encoder_state[index]) {
bool was_clockwise = !!(encoder_state[index] & ENCODER_STATE_CW);
encoder_state[index] = 0;
exec_encoder_action(index, was_clockwise, false);
}
encoder_state[index] = clockwise ? ENCODER_STATE_CW : ENCODER_STATE_CCW;
encoder_timer[index] = timer_read();
exec_encoder_action(index, clockwise, true);
# endif
}
void matrix_scan_kb(void) {
encoder_action_unregister();
matrix_scan_user();
}
bool encoder_update_kb(uint8_t index, bool clockwise) {
encoder_action_register(index, clockwise);
// don't return user actions, because they are in the keymap
// encoder_update_user(index, clockwise);
return true;
};
#endif

View File

@ -0,0 +1,21 @@
/* Copyright 2020 Neil Brian Ramirez
*
* 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 3 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"
void encoder_action_unregister(void);
void encoder_action_register(uint8_t index, bool clockwise);

View File

@ -0,0 +1,44 @@
// Copyright 2022 Sergey Vlasov (@sigprof)
// SPDX-License-Identifier: GPL-2.0-or-later
#include QMK_KEYBOARD_H
// clang-format off
#define LAYOUT_via( \
k17, k15, k16, \
k23,k22, k19,k18, k21,k20, \
k00, k01, k02, k03, k04, \
k05, k06, k07, k08, k09, \
k10, k11, k12, k13, k14 \
) { \
{ k00, k01, k02, k03, k04, k05, k06, k07, k08, k09, k10, k11, k12, k13, k14, k15, k16, k17, k18, k19, k20, k21, k22, k23 } \
}
#define U_LTESC LT(1, KC_ESC)
const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
[0] = LAYOUT_via(
KC_HOME, KC_MUTE, KC_MPLY,
KC_PGUP, KC_PGDN, KC_VOLD, KC_VOLU, KC_MPRV, KC_MNXT,
KC_1, KC_2, KC_3, KC_4, KC_5,
KC_6, KC_7, KC_8, KC_9, KC_0,
U_LTESC, KC_TAB, KC_SPC, KC_BSPC, KC_ENT
),
[1] = LAYOUT_via(
RGB_M_P, RGB_M_B, RGB_M_R,
RGB_HUD, RGB_HUI, RGB_SAD, RGB_SAI, RGB_VAD, RGB_VAI,
RGB_MOD, RGB_HUI, RGB_SAI, RGB_VAI, RGB_SPI,
RGB_RMOD,RGB_HUD, RGB_SAD, RGB_VAD, RGB_SPD,
KC_TRNS, RGB_TOG, RGB_M_P, RGB_M_B, RGB_M_R
),
[2 ... 7] = LAYOUT_via(
KC_TRNS, KC_TRNS, KC_TRNS,
KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS,
KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS, KC_TRNS
),
};
// clang-format on

View File

@ -0,0 +1,4 @@
VIA_ENABLE = yes
LTO_ENABLE = yes
SRC += encoder_actions.c

View File

@ -0,0 +1,45 @@
# Winry315
![Winry315](https://i.imgur.com/nWE5mbXh.jpeg)
Winry315 is a macropad with 3 rotary encoders and 15 keys (arranged as 3 rows of 5 keys).
This board may also be known as “YD3xn15mx”, “YD315” or “YD 3x15m”. Boards sold by the [SpiderIsland shop on AliExpress](https://www.aliexpress.com/store/5241107) may have “DEBROGLIE” on the bottom side of the case.
More photos can be found [in this Imgur album](https://imgur.com/a/0xf9pju).
* Keyboard Maintainer: [Sergey Vlasov](https://github.com/sigprof)
* Hardware Supported: Winry315 PCB
* Hardware Availability: [Taobao](https://world.taobao.com/item/657924681898.htm), [AliExpress](https://www.aliexpress.com/item/1005003500083583.html)
Make example for this keyboard (after setting up your build environment):
make winry/winry315:default
Flashing example for this keyboard:
make winry/winry315: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 top left key (not the encoder) and plug in the keyboard. This apparently also works with the vendor VIA firmware.
* Note that the bootmagic key does not change with the board orientation configured using `WINRY315_DEFAULT_ORIENTATION` — the “top left” key position in the default orientation (encoders on the top side) is always used.
* **Physical reset button**: Briefly press the button on the back of the PCB (the acrylic bottom cover should have a hole to access that button).
* **Keycode in layout**: Press the key mapped to `RESET` if it is available (the default keymap does not have that keycode assigned to any key, but you can use that keycode in your custom keymap if you want to have easier access to the bootloader).
## Orientation
Although the normal orientation of this macropad is with the encoders on the “top” side (away from the user), you may prefer using it in a sideways orientation (with the encoders on the left or right side). There are extra layout macros (`LAYOUT_left`, `LAYOUT_right` and even `LAYOUT_bottom` for completeness) which you can use in the keymap; however, just using one of those macros won't change the behavior of RGB Matrix effects. If you want to change the orientation of various RGB Matrix effects too, you can specify the desired orientation in the `config.h` file for your custom keymap by using one of the following defines:
#define WINRY315_DEFAULT_ORIENTATION WINRY315_ORIENTATION_TOP
#define WINRY315_DEFAULT_ORIENTATION WINRY315_ORIENTATION_LEFT
#define WINRY315_DEFAULT_ORIENTATION WINRY315_ORIENTATION_RIGHT
#define WINRY315_DEFAULT_ORIENTATION WINRY315_ORIENTATION_BOTTOM
The VIA firmware changes the orientation for RGB Matrix effects automatically when the “Encoder Side” layout option is changed.
Note that stems of MX switches are not symmetrical with respect to 90° rotation, so you may have some difficulties when putting the keycaps on switches if you choose one of sideways orientations.

View File

@ -0,0 +1,21 @@
# MCU name
MCU = atmega32u4
# Bootloader selection
BOOTLOADER = atmel-dfu
# Build Options
# change yes to no to disable
#
BOOTMAGIC_ENABLE = yes # Enable Bootmagic Lite
MOUSEKEY_ENABLE = yes # Mouse keys
EXTRAKEY_ENABLE = yes # Audio control and System control
CONSOLE_ENABLE = no # Console for debug
COMMAND_ENABLE = no # Commands for debug and configuration
NKRO_ENABLE = no # Enable N-Key Rollover
BACKLIGHT_ENABLE = no # Enable keyboard backlight functionality
RGBLIGHT_ENABLE = no # Enable keyboard RGB underglow
AUDIO_ENABLE = no # Audio output
ENCODER_ENABLE = yes
RGB_MATRIX_ENABLE = yes
RGB_MATRIX_DRIVER = WS2812

View File

@ -0,0 +1,262 @@
// Copyright 2022 Sergey Vlasov (@sigprof)
// SPDX-License-Identifier: GPL-2.0-or-later
#include "winry315.h"
#include "via.h"
#if !defined(WINRY315_DEFAULT_ORIENTATION)
# define WINRY315_DEFAULT_ORIENTATION WINRY315_ORIENTATION_TOP
#endif
#if !defined(VIA_ENABLE) && defined(ENCODER_ENABLE)
# ifndef MEDIA_KEY_DELAY
# define MEDIA_KEY_DELAY 10
# endif
bool encoder_update_kb(uint8_t index, bool clockwise) {
if (!encoder_update_user(index, clockwise)) {
return false;
}
if (index == 0) {
// Left encoder (assuming the default "top" orientation)
if (clockwise) {
tap_code(KC_PGDN);
} else {
tap_code(KC_PGUP);
}
} else if (index == 1) {
// Center encoder
if (clockwise) {
tap_code_delay(KC_VOLU, MEDIA_KEY_DELAY);
} else {
tap_code_delay(KC_VOLD, MEDIA_KEY_DELAY);
}
} else if (index == 2) {
// Right encoder
if (clockwise) {
tap_code_delay(KC_MNXT, MEDIA_KEY_DELAY);
} else {
tap_code_delay(KC_MPRV, MEDIA_KEY_DELAY);
}
}
return true;
}
#endif // !defined(VIA_ENABLE) && defined(ENCODER_ENABLE)
#if defined(RGB_MATRIX_ENABLE)
// LED mapping (assuming the default "top" orientation):
// 0 - right encoder, top right
// 1 - right encoder, top left
// 2 - center encoder, top right
// 3 - center encoder, top left
// 4 - left encoder, top right
// 5 - left encoder, top left
// 6 - row 0, column 0
// 7 - row 1, column 0
// 8 - row 2, column 0
// 9 - row 2, column 1
// 10 - row 1, column 1
// 11 - row 0, column 1
// 12 - row 0, column 2
// 13 - row 1, column 2
// 14 - row 2, column 2
// 15 - row 2, column 3
// 16 - row 1, column 3
// 17 - row 0, column 3
// 18 - row 0, column 4
// 19 - row 1, column 4
// 20 - row 2, column 4
// 21 - underglow, right bottom
// 22 - underglow, left bottom
// 23 - underglow, left middle
// 24 - underglow, left top
// 25 - underglow, right top
// 26 - underglow, right middle
# define X_MM_MIN (-42)
# define X_MM_MAX 42
# define Y_MM_MIN (-40) // actually -35, but adjusted to get height = width
# define Y_MM_MAX 44 // actually 40, but adjusted to get height = width
# define WIDTH_MM (X_MM_MAX - X_MM_MIN)
# define HEIGHT_MM (Y_MM_MAX - Y_MM_MIN)
# define WIDTH_UNITS (35 * 2) // needs to match RGB_MATRIX_CENTER
# define HEIGHT_UNITS (35 * 2) // needs to match RGB_MATRIX_CENTER
// Convert the LED physical coordinates from millimeters with the origin at the
// PCB center to the form expected by the RGB Matrix code.
# define LED(x_mm, y_mm) \
{ ((x_mm - X_MM_MIN) * WIDTH_UNITS + WIDTH_MM / 2) / WIDTH_MM, ((Y_MM_MAX - y_mm) * HEIGHT_UNITS + HEIGHT_MM / 2) / HEIGHT_MM }
// clang-format off
static const led_config_t PROGMEM initial_led_config = {
{
{ 6, 11, 12, 17, 18, 7, 10, 13, 16, 19, 8, 9, 14, 15, 20, 2, 0, 4, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED, NO_LED }
},
{
LED( 35, 36),
LED( 21, 36),
LED( 8, 34),
LED(-8, 34),
LED(-21, 36),
LED(-35, 36),
LED(-38, 5),
LED(-38, -14),
LED(-38, -33),
LED(-19, -33),
LED(-19, -14),
LED(-19, 5),
LED( 0, 5),
LED( 0, -14),
LED( 0, -33),
LED( 19, -33),
LED( 19, -14),
LED( 19, 5),
LED( 38, 5),
LED( 38, -14),
LED( 38, -33),
LED( 28, -35),
LED(-28, -35),
LED(-37, -9),
LED(-42, 40),
LED( 42, 40),
LED( 37, -9)
},
{
1, 1, 1, 1, 1, 1, // encoders (colored as modifiers)
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // regular keys
2, 2, 2, 2, 2, 2 // underglow
}
};
// clang-format on
led_config_t g_led_config;
void keyboard_pre_init_kb(void) {
// To be safe against any possible changes to rgb_matrix_init(),
// g_led_config should be initialized before rgb_matrix_init() is called;
// matrix_init_kb() would be too late, so keyboard_pre_init_kb() is used.
memcpy_P(&g_led_config, &initial_led_config, sizeof(g_led_config));
winry315_set_orientation(WINRY315_DEFAULT_ORIENTATION);
keyboard_pre_init_user();
}
// Encoders have two associated LEDs on this board; supporting more than one
// LED per key requires defining rgb_matrix_map_row_column_to_led_kb() to
// report any extra LEDs.
uint8_t rgb_matrix_map_row_column_to_led_kb(uint8_t row, uint8_t column, uint8_t *led_i) {
if (row == 0) {
switch (column) {
case 15: // center encoder
led_i[0] = 3;
return 1;
case 16: // right encoder
led_i[0] = 1;
return 1;
case 17: // left encoder
led_i[0] = 5;
return 1;
}
}
return 0;
}
# if defined(VIA_ENABLE) && defined(VIA_CUSTOM_LIGHTING_ENABLE)
// VIA supports only 4 discrete values for effect speed; map these to some
// useful speed values for RGB Matrix.
enum speed_values {
RGBLIGHT_SPEED_0 = UINT8_MAX / 16, // not 0 to avoid really slow effects
RGBLIGHT_SPEED_1 = UINT8_MAX / 4,
RGBLIGHT_SPEED_2 = UINT8_MAX / 2, // matches the default value
RGBLIGHT_SPEED_3 = UINT8_MAX / 4 * 3, // UINT8_MAX is really fast
};
static uint8_t speed_from_rgblight(uint8_t rgblight_speed) {
switch (rgblight_speed) {
case 0:
return RGBLIGHT_SPEED_0;
case 1:
return RGBLIGHT_SPEED_1;
case 2:
default:
return RGBLIGHT_SPEED_2;
case 3:
return RGBLIGHT_SPEED_3;
}
}
static uint8_t speed_to_rgblight(uint8_t rgb_matrix_speed) {
if (rgb_matrix_speed < ((RGBLIGHT_SPEED_0 + RGBLIGHT_SPEED_1) / 2)) {
return 0;
} else if (rgb_matrix_speed < ((RGBLIGHT_SPEED_1 + RGBLIGHT_SPEED_2) / 2)) {
return 1;
} else if (rgb_matrix_speed < ((RGBLIGHT_SPEED_2 + RGBLIGHT_SPEED_3) / 2)) {
return 2;
} else {
return 3;
}
}
void raw_hid_receive_kb(uint8_t *data, uint8_t length) {
switch (data[0]) {
case id_lighting_get_value:
if (data[1] == id_qmk_rgblight_effect_speed) {
data[2] = speed_to_rgblight(rgb_matrix_get_speed());
}
break;
case id_lighting_set_value:
if (data[1] == id_qmk_rgblight_effect_speed) {
rgb_matrix_set_speed_noeeprom(speed_from_rgblight(data[2]));
}
break;
}
}
# endif // defined(VIA_ENABLE) && defined(VIA_CUSTOM_LIGHTING_ENABLE)
#endif // defined(RGB_MATRIX_ENABLE)
void winry315_set_orientation(uint8_t orientation) {
(void)orientation;
#if defined(RGB_MATRIX_ENABLE)
for (uint8_t i = 0; i < DRIVER_LED_TOTAL; ++i) {
led_point_t * dst_point = &g_led_config.point[i];
const led_point_t *src_point = &initial_led_config.point[i];
uint8_t x = pgm_read_byte(&src_point->x);
uint8_t y = pgm_read_byte(&src_point->y);
switch (orientation) {
case WINRY315_ORIENTATION_TOP:
default:
dst_point->x = x;
dst_point->y = y;
break;
case WINRY315_ORIENTATION_LEFT:
dst_point->x = y;
dst_point->y = WIDTH_UNITS - x;
break;
case WINRY315_ORIENTATION_RIGHT:
dst_point->x = HEIGHT_UNITS - y;
dst_point->y = x;
break;
case WINRY315_ORIENTATION_BOTTOM:
dst_point->x = WIDTH_UNITS - x;
dst_point->y = HEIGHT_UNITS - y;
break;
}
}
#endif // defined(RGB_MATRIX_ENABLE)
}
#if defined(VIA_ENABLE)
void via_set_layout_options_kb(uint32_t value) {
winry315_set_orientation(value & 0x03);
}
#endif // defined(VIA_ENABLE)

View File

@ -0,0 +1,86 @@
// Copyright 2022 Sergey Vlasov (@sigprof)
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "quantum.h"
// Supported orientations of the board. The enum values must match the layout
// option values used by VIA.
enum winry315_orientation {
WINRY315_ORIENTATION_TOP, // Encoders at the top side (default)
WINRY315_ORIENTATION_LEFT, // Encoders at the left side
WINRY315_ORIENTATION_RIGHT, // Encoders at the right side
WINRY315_ORIENTATION_BOTTOM // Encoders at the bottom side
};
// Set the orientation of the board (changes the RGB Matrix effect behavior to
// match the new orientation).
//
// This function is intended to be used in the `via` keymap, where the board
// orientation is configured dynamically using a VIA layout option. If you are
// making a custom keymap for one specific orientation, it is better to set the
// orientation in config.h (e.g., `#define WINRY315_DEFAULT_ORIENTATION
// WINRY315_ORIENTATION_LEFT`) instead of adding custom code that calls this
// function.
void winry315_set_orientation(uint8_t orientation);
// clang-format off
// This is a shortcut to help you visually see your layout.
//
// The first section contains all of the arguments representing the physical
// layout of the board and position of the keys.
//
// The second converts the arguments into a two-dimensional array which
// represents the switch matrix.
//
// For this board multiple layouts are defined to make it easier to use the
// board in a sideways orientation; the actual PCB supports only a single
// layout (LAYOUT_top).
// Default layout: encoders at the top side (WINRY315_ORIENTATION_TOP).
#define LAYOUT_top( \
k17, k15, k16, \
k00, k01, k02, k03, k04, \
k05, k06, k07, k08, k09, \
k10, k11, k12, k13, k14 \
) { \
{ k00, k01, k02, k03, k04, k05, k06, k07, k08, k09, k10, k11, k12, k13, k14, k15, k16, k17, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO } \
}
// Encoders at the left side (WINRY315_ORIENTATION_LEFT).
#define LAYOUT_left( \
k16, k04, k09, k14, \
k03, k08, k13, \
k15, k02, k07, k12, \
k01, k06, k11, \
k17, k00, k05, k10 \
) { \
{ k00, k01, k02, k03, k04, k05, k06, k07, k08, k09, k10, k11, k12, k13, k14, k15, k16, k17, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO } \
}
// Encoders at the right side (WINRY315_ORIENTATION_RIGHT).
#define LAYOUT_right( \
k10, k05, k00, k17, \
k11, k06, k01, \
k12, k07, k02, k15, \
k13, k08, k03, \
k14, k09, k04, k16 \
) { \
{ k00, k01, k02, k03, k04, k05, k06, k07, k08, k09, k10, k11, k12, k13, k14, k15, k16, k17, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO } \
}
// Encoders at the bottom side (WINRY315_ORIENTATION_BOTTOM).
#define LAYOUT_bottom( \
k14, k13, k12, k11, k10, \
k09, k08, k07, k06, k05, \
k04, k03, k02, k01, k00, \
k16, k15, k17 \
) { \
{ k00, k01, k02, k03, k04, k05, k06, k07, k08, k09, k10, k11, k12, k13, k14, k15, k16, k17, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO, KC_NO } \
}
#define LAYOUT_all LAYOUT_top
// clang-format on